Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "dpdimsave.hxx"
31 : : #include "dpgroup.hxx"
32 : : #include "dpobject.hxx"
33 : : #include "dputil.hxx"
34 : : #include "document.hxx"
35 : :
36 : : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
37 : :
38 : : #include <svl/zforlist.hxx>
39 : : #include <rtl/math.hxx>
40 : : #include <algorithm>
41 : :
42 : : using namespace com::sun::star;
43 : :
44 : : // ============================================================================
45 : :
46 : 11 : ScDPSaveGroupItem::ScDPSaveGroupItem( const rtl::OUString& rName ) :
47 [ + - ][ + - ]: 11 : aGroupName(rName) {}
48 : :
49 : 38 : ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
50 : :
51 : 34 : void ScDPSaveGroupItem::AddElement( const rtl::OUString& rName )
52 : : {
53 : 34 : aElements.push_back(rName);
54 : 34 : }
55 : :
56 : 0 : void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
57 : : {
58 : : // add all elements of the other group (used for nested grouping)
59 : :
60 [ # # ][ # # ]: 0 : for ( std::vector<rtl::OUString>::const_iterator aIter(rGroup.aElements.begin());
61 : 0 : aIter != rGroup.aElements.end(); ++aIter )
62 [ # # ]: 0 : aElements.push_back( *aIter );
63 : 0 : }
64 : :
65 : 0 : bool ScDPSaveGroupItem::RemoveElement( const rtl::OUString& rName )
66 : : {
67 [ # # ][ # # ]: 0 : for (std::vector<rtl::OUString>::iterator aIter = aElements.begin(); aIter != aElements.end(); ++aIter)
68 [ # # ]: 0 : if (*aIter == rName) //! ignore case
69 : : {
70 [ # # ]: 0 : aElements.erase(aIter); // found -> remove
71 : 0 : return true; // don't have to look further
72 : : }
73 : :
74 : 0 : return false; // not found
75 : : }
76 : :
77 : 0 : bool ScDPSaveGroupItem::IsEmpty() const
78 : : {
79 : 0 : return aElements.empty();
80 : : }
81 : :
82 : 3 : size_t ScDPSaveGroupItem::GetElementCount() const
83 : : {
84 : 3 : return aElements.size();
85 : : }
86 : :
87 : 6 : const rtl::OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
88 : : {
89 [ + - ]: 6 : return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0;
90 : : }
91 : :
92 : 0 : void ScDPSaveGroupItem::Rename( const rtl::OUString& rNewName )
93 : : {
94 : 0 : aGroupName = rNewName;
95 : 0 : }
96 : :
97 : 0 : void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const
98 : : {
99 : : // remove this group's elements from their groups in rDimension
100 : : // (rDimension must be a different dimension from the one which contains this)
101 : :
102 [ # # ][ # # ]: 0 : for ( std::vector<rtl::OUString>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
[ # # ]
103 [ # # ]: 0 : rDimension.RemoveFromGroups( *aIter );
104 : 0 : }
105 : :
106 : 14 : void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const
107 : : {
108 [ + - ]: 14 : maItems.reserve(aElements.size());
109 : 14 : std::vector<rtl::OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end();
110 [ + - ][ + + ]: 57 : for (; it != itEnd; ++it)
111 : : {
112 : 43 : sal_uInt32 nFormat = 0;
113 : : double fValue;
114 [ + - ]: 43 : ScDPItemData aData;
115 [ + - ][ + - ]: 43 : if (pFormatter->IsNumberFormat(*it, nFormat, fValue))
[ + - ][ + + ]
116 [ + - ]: 10 : aData.SetValue(fValue);
117 : : else
118 [ + - ]: 33 : aData.SetString(*it);
119 : :
120 [ + - ]: 43 : maItems.push_back(aData);
121 [ + - ]: 43 : }
122 : 14 : }
123 : :
124 : 76 : bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const
125 : : {
126 [ + - ][ + - ]: 76 : return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
127 : : }
128 : :
129 : 14 : void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
130 : : {
131 [ + - ][ + - ]: 14 : ScDPGroupItem aGroup(aGroupName);
[ + - ]
132 [ + - ][ + - ]: 14 : std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
133 [ + - ][ + - ]: 66 : for (; it != itEnd; ++it)
[ + + ]
134 [ + - ][ + - ]: 52 : aGroup.AddElement(*it);
135 : :
136 [ + - ][ + - ]: 14 : rDataDim.AddItem(aGroup);
137 : 14 : }
138 : :
139 : : // ============================================================================
140 : :
141 : 14 : ScDPSaveGroupDimension::ScDPSaveGroupDimension( const rtl::OUString& rSource, const rtl::OUString& rName ) :
142 : : aSourceDim( rSource ),
143 : : aGroupDimName( rName ),
144 [ + - ][ + - ]: 14 : nDatePart( 0 )
145 : : {
146 : 14 : }
147 : :
148 : 0 : ScDPSaveGroupDimension::ScDPSaveGroupDimension( const rtl::OUString& rSource, const rtl::OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
149 : : aSourceDim( rSource ),
150 : : aGroupDimName( rName ),
151 : : aDateInfo( rDateInfo ),
152 [ # # ][ # # ]: 0 : nDatePart( nPart )
153 : : {
154 : 0 : }
155 : :
156 : 36 : ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
157 : : {
158 : 36 : }
159 : :
160 : 6 : void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
161 : : {
162 : 6 : aDateInfo = rInfo;
163 : 6 : nDatePart = nPart;
164 : 6 : }
165 : :
166 : 11 : void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
167 : : {
168 : 11 : aGroups.push_back( rItem );
169 : 11 : }
170 : :
171 : 11 : rtl::OUString ScDPSaveGroupDimension::CreateGroupName(const rtl::OUString& rPrefix)
172 : : {
173 : : // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
174 : :
175 : : //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
176 : : //! (only dimensions for the same base)
177 : :
178 : 11 : sal_Int32 nAdd = 1; // first try is "Group1"
179 : 11 : const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
180 [ + - ]: 14 : while ( nAdd <= nMaxAdd )
181 : : {
182 [ + - ]: 14 : String aGroupName( rPrefix );
183 [ + - ][ + - ]: 14 : aGroupName.Append( String::CreateFromInt32( nAdd ) );
[ + - ]
184 : 14 : bool bExists = false;
185 : :
186 : : // look for existing groups
187 [ + - ][ + - ]: 60 : for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
[ + + ][ + - ]
[ + + ]
188 [ + - ][ + - ]: 40 : aIter != aGroups.end() && !bExists; ++aIter )
[ # # ]
189 [ + - ][ + - ]: 6 : if (aIter->GetGroupName().equals(aGroupName)) //! ignore case
[ + + ]
190 : 3 : bExists = true;
191 : :
192 [ + + ]: 14 : if ( !bExists )
193 [ + - ]: 11 : return aGroupName; // found a new name
194 : :
195 [ + + ]: 17 : ++nAdd; // continue with higher number
196 [ + - ]: 14 : }
197 : :
198 : : OSL_FAIL("CreateGroupName: no valid name found");
199 : 11 : return rtl::OUString();
200 : : }
201 : :
202 : 0 : const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const rtl::OUString& rGroupName ) const
203 : : {
204 : 0 : return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
205 : : }
206 : :
207 : 0 : ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const rtl::OUString& rGroupName )
208 : : {
209 [ # # ][ # # ]: 0 : for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
[ # # ]
210 [ # # ][ # # ]: 0 : if (aIter->GetGroupName().equals(rGroupName)) //! ignore case
211 [ # # ]: 0 : return &*aIter;
212 : :
213 : 0 : return NULL; // none found
214 : : }
215 : :
216 : 3 : long ScDPSaveGroupDimension::GetGroupCount() const
217 : : {
218 : 3 : return aGroups.size();
219 : : }
220 : :
221 : 3 : const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
222 : : {
223 : 3 : return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
224 : : }
225 : :
226 : 3 : ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
227 : : {
228 : 3 : return &aGroups[nIndex];
229 : : }
230 : :
231 : 0 : void ScDPSaveGroupDimension::RemoveFromGroups( const rtl::OUString& rItemName )
232 : : {
233 : : // if the item is in any group, remove it from the group,
234 : : // also remove the group if it is empty afterwards
235 : :
236 [ # # ][ # # ]: 0 : for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
[ # # ]
237 [ # # ][ # # ]: 0 : if ( aIter->RemoveElement( rItemName ) )
[ # # ]
238 : : {
239 [ # # ][ # # ]: 0 : if ( aIter->IsEmpty() ) // removed last item from the group?
[ # # ]
240 [ # # ]: 0 : aGroups.erase( aIter ); // then remove the group
241 : :
242 : 0 : return; // don't have to look further
243 : : }
244 : : }
245 : :
246 : 0 : void ScDPSaveGroupDimension::RemoveGroup(const rtl::OUString& rGroupName)
247 : : {
248 [ # # ][ # # ]: 0 : for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
[ # # ]
249 [ # # ][ # # ]: 0 : if (aIter->GetGroupName().equals(rGroupName)) //! ignore case
250 : : {
251 [ # # ]: 0 : aGroups.erase( aIter );
252 : 0 : return; // don't have to look further
253 : : }
254 : : }
255 : :
256 : 0 : bool ScDPSaveGroupDimension::IsEmpty() const
257 : : {
258 : 0 : return aGroups.empty();
259 : : }
260 : :
261 : 0 : bool ScDPSaveGroupDimension::HasOnlyHidden(const ScDPUniqueStringSet& rVisible)
262 : : {
263 : : // check if there are only groups that don't appear in the list of visible names
264 : :
265 : 0 : bool bAllHidden = true;
266 [ # # ][ # # ]: 0 : for (ScDPSaveGroupItemVec::const_iterator aIter = aGroups.begin(); aIter != aGroups.end() && bAllHidden; ++aIter)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # # ]
267 : : {
268 [ # # ][ # # ]: 0 : if (rVisible.count(aIter->GetGroupName()) > 0)
[ # # ]
269 : 0 : bAllHidden = false;
270 : : }
271 : 0 : return bAllHidden;
272 : : }
273 : :
274 : 0 : void ScDPSaveGroupDimension::Rename( const rtl::OUString& rNewName )
275 : : {
276 : 0 : aGroupDimName = rNewName;
277 : 0 : }
278 : :
279 : 64 : bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const
280 : : {
281 : 64 : ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
282 [ + - ][ + - ]: 97 : for (; it != itEnd; ++it)
[ + + ]
283 : : {
284 [ + - ][ + - ]: 76 : if (it->HasInGroup(rItem))
[ + + ]
285 : 43 : return true;
286 : : }
287 : 64 : return false;
288 : : }
289 : :
290 : : namespace {
291 : :
292 : 54 : inline bool isInteger(double fValue)
293 : : {
294 : 54 : return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
295 : : }
296 : :
297 : 9 : void fillDateGroupDimension(
298 : : ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, long nSourceDim, long nGroupDim,
299 : : sal_Int32 nDatePart, SvNumberFormatter* pFormatter)
300 : : {
301 : : // Auto min/max is only used for "Years" part, but the loop is always
302 : : // needed.
303 : 9 : double fSourceMin = 0.0;
304 : 9 : double fSourceMax = 0.0;
305 : 9 : bool bFirst = true;
306 : :
307 [ + - ]: 9 : const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
308 : 9 : ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
309 [ + - ][ + - ]: 81 : for (; it != itEnd; ++it)
[ + + ]
310 : : {
311 [ + - ]: 72 : const ScDPItemData& rItem = *it;
312 [ + - ][ - + ]: 72 : if (rItem.GetType() != ScDPItemData::Value)
313 : 0 : continue;
314 : :
315 [ + - ]: 72 : double fVal = rItem.GetValue();
316 [ + + ]: 72 : if (bFirst)
317 : : {
318 : 9 : fSourceMin = fSourceMax = fVal;
319 : 9 : bFirst = false;
320 : : }
321 : : else
322 : : {
323 [ - + ]: 63 : if (fVal < fSourceMin)
324 : 0 : fSourceMin = fVal;
325 [ + - ]: 63 : if ( fVal > fSourceMax )
326 : 63 : fSourceMax = fVal;
327 : : }
328 : : }
329 : :
330 : : // For the start/end values, use the same date rounding as in
331 : : // ScDPNumGroupDimension::GetNumEntries (but not for the list of
332 : : // available years).
333 [ + - ]: 9 : if (rDateInfo.mbAutoStart)
334 : 9 : rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
335 [ + - ]: 9 : if (rDateInfo.mbAutoEnd)
336 : 9 : rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
337 : :
338 : : //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
339 : :
340 : 9 : long nStart = 0, nEnd = 0; // end is inclusive
341 : :
342 [ + + + - : 9 : switch (nDatePart)
- - - - ]
343 : : {
344 : : case sheet::DataPilotFieldGroupBy::YEARS:
345 : : nStart = ScDPUtil::getDatePartValue(
346 [ + - ]: 3 : fSourceMin, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
347 [ + - ]: 3 : nEnd = ScDPUtil::getDatePartValue(fSourceMax, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
348 : 3 : break;
349 : 3 : case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break;
350 : 3 : case sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break;
351 : 0 : case sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break;
352 : 0 : case sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break;
353 : 0 : case sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break;
354 : 0 : case sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break;
355 : : default:
356 : : OSL_FAIL("invalid date part");
357 : : }
358 : :
359 : : // Now, populate the group items in the cache.
360 [ + - ]: 9 : rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
361 : :
362 [ + + ]: 63 : for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue)
363 [ + - ][ + - ]: 54 : rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
[ + - ]
364 : :
365 : : // add first/last entry (min/max)
366 [ + - ][ + - ]: 9 : rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
[ + - ]
367 [ + - ][ + - ]: 9 : rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
[ + - ]
368 : 9 : }
369 : :
370 : : }
371 : :
372 : 23 : void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
373 : : {
374 : 23 : long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
375 [ + - ]: 23 : if ( nSourceIndex >= 0 )
376 : : {
377 [ + - ][ + - ]: 23 : ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
[ + - ]
378 [ + + ]: 23 : if ( nDatePart )
379 : : {
380 : : // date grouping
381 : :
382 [ + - ]: 12 : aDim.SetDateDimension();
383 : : }
384 : : else
385 : : {
386 : : // normal (manual) grouping
387 : :
388 [ + - ][ + - ]: 25 : for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter)
[ + + ]
389 [ + - ][ + - ]: 14 : aIter->AddToData(aDim);
390 : : }
391 : :
392 [ + - ][ + - ]: 23 : rData.AddGroupDimension( aDim );
393 : : }
394 : 23 : }
395 : :
396 : 17 : void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
397 : : {
398 : 17 : long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
399 [ - + ]: 17 : if (nSourceDim < 0)
400 : 0 : return;
401 : :
402 : 17 : long nDim = rCache.AppendGroupField();
403 : 17 : SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
404 : :
405 [ + + ]: 17 : if (nDatePart)
406 : : {
407 : 6 : fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
408 : 6 : return;
409 : : }
410 : :
411 : 11 : rCache.ResetGroupItems(nDim, aDateInfo, 0);
412 : : {
413 : 11 : ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
414 [ + - ][ + - ]: 25 : for (; it != itEnd; ++it)
[ + + ]
415 : : {
416 [ + - ]: 14 : const ScDPSaveGroupItem& rGI = *it;
417 [ + - ]: 14 : rGI.ConvertElementsToItems(pFormatter);
418 [ + - ][ + - ]: 14 : rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
[ + - ]
419 : : }
420 : : }
421 : :
422 : 11 : const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
423 : : {
424 : 11 : ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
425 [ + - ][ + - ]: 81 : for (; it != itEnd; ++it)
[ + + ]
426 : : {
427 [ + - ]: 64 : const ScDPItemData& rItem = *it;
428 [ + - ][ + + ]: 64 : if (!IsInGroup(rItem))
429 : : // Not in any group. Add as its own group.
430 [ + - ]: 21 : rCache.SetGroupItem(nDim, rItem);
431 : : }
432 : : }
433 : : }
434 : :
435 : : // ============================================================================
436 : :
437 : 3 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const rtl::OUString& rName, const ScDPNumGroupInfo& rInfo ) :
438 : : aDimensionName( rName ),
439 : : aGroupInfo( rInfo ),
440 [ + - ][ + - ]: 3 : nDatePart( 0 )
441 : : {
442 : 3 : }
443 : :
444 : 3 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const rtl::OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
445 : : aDimensionName( rName ),
446 : : aDateInfo( rDateInfo ),
447 [ + - ][ + - ]: 3 : nDatePart( nPart )
448 : : {
449 : 3 : }
450 : :
451 : 18 : ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
452 : : {
453 : 18 : }
454 : :
455 : 9 : void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
456 : : {
457 : 9 : long nSource = rData.GetDimensionIndex( aDimensionName );
458 [ + - ]: 9 : if ( nSource >= 0 )
459 : : {
460 [ + - ]: 9 : ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
461 [ + + ]: 9 : if ( nDatePart )
462 [ + - ]: 6 : aDim.SetDateDimension();
463 : :
464 [ + - ][ + - ]: 9 : rData.SetNumGroupDimension( nSource, aDim );
465 : : }
466 : 9 : }
467 : :
468 : 6 : void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
469 : : {
470 : 6 : long nDim = rCache.GetDimensionIndex(aDimensionName);
471 [ - + ]: 6 : if (nDim < 0)
472 : 6 : return;
473 : :
474 [ + + ]: 6 : if (aDateInfo.mbEnable)
475 : : {
476 : : // Date grouping
477 : 3 : SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
478 : 3 : fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
479 : : }
480 [ + - ]: 3 : else if (aGroupInfo.mbEnable)
481 : : {
482 : : // Number-range grouping
483 : :
484 : : // Look through the source entries for non-integer numbers, minimum
485 : : // and maximum.
486 : :
487 : : // non-integer GroupInfo values count, too
488 : : aGroupInfo.mbIntegerOnly =
489 : 3 : (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
490 : 3 : (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
491 [ + - + - ]: 9 : isInteger(aGroupInfo.mfStep);
[ + - + - ]
[ + - ]
492 : :
493 : 3 : double fSourceMin = 0.0;
494 : 3 : double fSourceMax = 0.0;
495 : 3 : bool bFirst = true;
496 : :
497 [ + - ]: 3 : const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nDim);
498 : 3 : ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
499 [ + - ][ + - ]: 51 : for (; it != itEnd; ++it)
[ + + ]
500 : : {
501 [ + - ]: 48 : const ScDPItemData& rItem = *it;
502 [ + - ][ - + ]: 48 : if (rItem.GetType() != ScDPItemData::Value)
503 : 0 : continue;
504 : :
505 [ + - ]: 48 : double fValue = rItem.GetValue();
506 [ + + ]: 48 : if (bFirst)
507 : : {
508 : 3 : fSourceMin = fSourceMax = fValue;
509 : 3 : bFirst = false;
510 : 3 : continue;
511 : : }
512 : :
513 [ - + ]: 45 : if (fValue < fSourceMin)
514 : 0 : fSourceMin = fValue;
515 [ + - ]: 45 : if (fValue > fSourceMax)
516 : 45 : fSourceMax = fValue;
517 : :
518 [ + - ][ - + ]: 45 : if (aGroupInfo.mbIntegerOnly && !isInteger(fValue))
[ - + ]
519 : : {
520 : : // If any non-integer numbers are involved, the group labels
521 : : // are shown including their upper limit.
522 : 0 : aGroupInfo.mbIntegerOnly = false;
523 : : }
524 : : }
525 : :
526 [ - + ]: 3 : if (aGroupInfo.mbDateValues)
527 : : {
528 : : // special handling for dates: always integer, round down limits
529 : 0 : aGroupInfo.mbIntegerOnly = true;
530 : 0 : fSourceMin = rtl::math::approxFloor(fSourceMin);
531 : 0 : fSourceMax = rtl::math::approxFloor(fSourceMax) + 1;
532 : : }
533 : :
534 [ - + ]: 3 : if (aGroupInfo.mbAutoStart)
535 : 0 : aGroupInfo.mfStart = fSourceMin;
536 [ - + ]: 3 : if (aGroupInfo.mbAutoEnd)
537 : 0 : aGroupInfo.mfEnd = fSourceMax;
538 : :
539 : : //! limit number of entries?
540 : :
541 : 3 : long nLoopCount = 0;
542 : 3 : double fLoop = aGroupInfo.mfStart;
543 : :
544 [ + - ]: 3 : rCache.ResetGroupItems(nDim, aGroupInfo, 0);
545 : :
546 : : // Use "less than" instead of "less or equal" for the loop - don't
547 : : // create a group that consists only of the end value. Instead, the
548 : : // end value is then included in the last group (last group is bigger
549 : : // than the others). The first group has to be created nonetheless.
550 : : // GetNumGroupForValue has corresponding logic.
551 : :
552 : 3 : bool bFirstGroup = true;
553 [ + + ][ + + ]: 12 : while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
[ + - ][ + + ]
554 : : {
555 [ + - ]: 9 : ScDPItemData aItem;
556 [ + - ]: 9 : aItem.SetRangeStart(fLoop);
557 [ + - ]: 9 : rCache.SetGroupItem(nDim, aItem);
558 : 9 : ++nLoopCount;
559 : 9 : fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
560 : 9 : bFirstGroup = false;
561 : :
562 : : // ScDPItemData values are compared with approxEqual
563 [ + - ]: 9 : }
564 : :
565 [ + - ]: 3 : ScDPItemData aItem;
566 [ + - ]: 3 : aItem.SetRangeFirst();
567 [ + - ]: 3 : rCache.SetGroupItem(nDim, aItem);
568 : :
569 [ + - ]: 3 : aItem.SetRangeLast();
570 [ + - ][ + - ]: 3 : rCache.SetGroupItem(nDim, aItem);
571 : : }
572 : : }
573 : :
574 : 0 : void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
575 : : {
576 : 0 : aGroupInfo = rNew;
577 : 0 : }
578 : :
579 : 0 : void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
580 : : {
581 : 0 : aDateInfo = rInfo;
582 : 0 : nDatePart = nPart;
583 : 0 : }
584 : :
585 : : // ============================================================================
586 : :
587 : : namespace {
588 : :
589 : 99 : struct ScDPSaveGroupDimNameFunc
590 : : {
591 : : rtl::OUString maDimName;
592 : 33 : inline explicit ScDPSaveGroupDimNameFunc( const rtl::OUString& rDimName ) : maDimName( rDimName ) {}
593 : 12 : inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
594 : : };
595 : :
596 : 24 : struct ScDPSaveGroupSourceNameFunc
597 : : {
598 : : rtl::OUString maSrcDimName;
599 : 8 : inline explicit ScDPSaveGroupSourceNameFunc( const rtl::OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
600 : 3 : inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
601 : : };
602 : :
603 : : } // namespace
604 : :
605 : : // ----------------------------------------------------------------------------
606 : :
607 [ + - ]: 14 : ScDPDimensionSaveData::ScDPDimensionSaveData()
608 : : {
609 : 14 : }
610 : :
611 : 19 : ScDPDimensionSaveData::~ScDPDimensionSaveData()
612 : : {
613 : 19 : }
614 : :
615 : 0 : bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
616 : : {
617 : 0 : return false;
618 : : }
619 : :
620 : 14 : void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
621 : : {
622 : : OSL_ENSURE( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(),
623 : : "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
624 : : // ReplaceGroupDimension() adds new or replaces existing
625 : 14 : ReplaceGroupDimension( rGroupDim );
626 : 14 : }
627 : :
628 : 14 : void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
629 : : {
630 : : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
631 [ + - ]: 14 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
632 [ + - ][ + - ]: 14 : if( aIt == maGroupDims.end() )
633 [ + - ]: 14 : maGroupDims.push_back( rGroupDim );
634 : : else
635 [ # # ][ # # ]: 0 : *aIt = rGroupDim;
636 : 14 : }
637 : :
638 : 0 : void ScDPDimensionSaveData::RemoveGroupDimension( const rtl::OUString& rGroupDimName )
639 : : {
640 : : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
641 [ # # ]: 0 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
642 [ # # ][ # # ]: 0 : if( aIt != maGroupDims.end() )
643 [ # # ]: 0 : maGroupDims.erase( aIt );
644 : 0 : }
645 : :
646 : 6 : void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
647 : : {
648 : : OSL_ENSURE( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
649 : : "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
650 : : // ReplaceNumGroupDimension() adds new or replaces existing
651 : 6 : ReplaceNumGroupDimension( rGroupDim );
652 : 6 : }
653 : :
654 : 6 : void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
655 : : {
656 [ + - ]: 6 : ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
657 [ + - ]: 6 : if( aIt == maNumGroupDims.end() )
658 [ + - ][ + - ]: 6 : maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
[ + - ]
659 : : else
660 [ # # ]: 0 : aIt->second = rGroupDim;
661 : 6 : }
662 : :
663 : 0 : void ScDPDimensionSaveData::RemoveNumGroupDimension( const rtl::OUString& rGroupDimName )
664 : : {
665 : 0 : maNumGroupDims.erase( rGroupDimName );
666 : 0 : }
667 : :
668 : 20 : void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
669 : : {
670 : : // rData is assumed to be empty
671 : : // AddToData also handles date grouping
672 : :
673 [ + - ][ + - ]: 43 : for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
[ + + ]
674 [ + - ][ + - ]: 23 : aIt->AddToData( rData );
675 : :
676 [ + + ]: 29 : for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
677 [ + - ]: 9 : aIt->second.AddToData( rData );
678 : 20 : }
679 : :
680 : : namespace {
681 : :
682 : : class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void>
683 : : {
684 : : ScDPCache& mrCache;
685 : : public:
686 : 17 : AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {}
687 : 17 : void operator() (const ScDPSaveGroupDimension& rDim)
688 : : {
689 : 17 : rDim.AddToCache(mrCache);
690 : 17 : }
691 : : };
692 : :
693 : : }
694 : :
695 : 17 : void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const
696 : : {
697 [ + - ]: 17 : std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache));
698 : 17 : ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end();
699 [ + + ]: 23 : for (; it != itEnd; ++it)
700 [ + - ]: 6 : it->second.AddToCache(rCache);
701 : 17 : }
702 : :
703 : 0 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const rtl::OUString& rBaseDimName ) const
704 : : {
705 : 0 : return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
706 : : }
707 : :
708 : 14 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const rtl::OUString& rGroupDimName ) const
709 : : {
710 : 14 : return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
711 : : }
712 : :
713 : 0 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const rtl::OUString& rBaseDimName ) const
714 : : {
715 : 0 : return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
716 : : }
717 : :
718 : 0 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const rtl::OUString& rGroupDimName ) const
719 : : {
720 : 0 : return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
721 : : }
722 : :
723 : 3 : const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const rtl::OUString& rGroupDimName ) const
724 : : {
725 : 3 : return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
726 : : }
727 : :
728 : 8 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const rtl::OUString& rBaseDimName )
729 : : {
730 : 8 : ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
731 [ + + ]: 8 : return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
732 : : }
733 : :
734 : 14 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const rtl::OUString& rGroupDimName )
735 : : {
736 : : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
737 [ + - ]: 14 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
738 [ + + ][ + - ]: 14 : return (aIt == maGroupDims.end()) ? 0 : &*aIt;
[ + - ]
739 : : }
740 : :
741 : 8 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const rtl::OUString& rBaseDimName )
742 : : {
743 : : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
744 [ + - ]: 8 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
745 [ + + ][ + - ]: 8 : return (aIt == maGroupDims.end()) ? 0 : &*aIt;
[ + - ]
746 : : }
747 : :
748 : 5 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const rtl::OUString& rGroupDimName )
749 : : {
750 : : // find the group dimension with the passed name
751 : : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
752 [ + - ]: 5 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
753 : : // find next group dimension based on the same source dimension name
754 [ - + ][ + - ]: 5 : if( aIt != maGroupDims.end() )
755 [ # # ][ # # ]: 0 : aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
[ # # ]
756 [ + - ][ + - ]: 5 : return (aIt == maGroupDims.end()) ? 0 : &*aIt;
[ # # ]
757 : : }
758 : :
759 : 3 : ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const rtl::OUString& rGroupDimName )
760 : : {
761 [ + - ]: 3 : ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
762 [ + - ]: 3 : return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
763 : : }
764 : :
765 : 14 : bool ScDPDimensionSaveData::HasGroupDimensions() const
766 : : {
767 [ - + ][ # # ]: 14 : return !maGroupDims.empty() || !maNumGroupDims.empty();
768 : : }
769 : :
770 : 0 : sal_Int32 ScDPDimensionSaveData::CollectDateParts( const rtl::OUString& rBaseDimName ) const
771 : : {
772 : 0 : sal_Int32 nParts = 0;
773 : : // start with part of numeric group
774 [ # # ]: 0 : if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
775 : 0 : nParts |= pNumDim->GetDatePart();
776 : : // collect parts from all matching group dimensions
777 [ # # ]: 0 : for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
778 : 0 : nParts |= pGroupDim->GetDatePart();
779 : :
780 : 0 : return nParts;
781 : : }
782 : :
783 : 14 : rtl::OUString ScDPDimensionSaveData::CreateGroupDimName(
784 : : const rtl::OUString& rSourceName, const ScDPObject& rObject, bool bAllowSource,
785 : : const std::vector<rtl::OUString>* pDeletedNames )
786 : : {
787 : : // create a name for the new dimension by appending a number to the original
788 : : // dimension's name
789 : :
790 : 14 : bool bUseSource = bAllowSource; // if set, try the unchanged original name first
791 : :
792 : 14 : sal_Int32 nAdd = 2; // first try is "Name2"
793 : 14 : const sal_Int32 nMaxAdd = 1000; // limit the loop
794 [ + - ]: 14 : while ( nAdd <= nMaxAdd )
795 : : {
796 : 14 : rtl::OUString aDimName( rSourceName );
797 [ + + ]: 14 : if ( !bUseSource )
798 : 8 : aDimName += rtl::OUString::valueOf(static_cast<sal_Int32>(nAdd));
799 : 14 : bool bExists = false;
800 : :
801 : : // look for existing group dimensions
802 [ + - ][ + - ]: 17 : for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ]
803 [ + - ][ - + ]: 3 : if( aIt->GetGroupDimName() == aDimName ) //! ignore case
804 : 0 : bExists = true;
805 : :
806 : : // look for base dimensions that happen to have that name
807 [ + - ][ + - ]: 14 : if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
[ - + ][ - + ]
808 : : {
809 [ # # ][ # # ]: 0 : if ( pDeletedNames &&
[ # # ]
810 [ # # ][ # # ]: 0 : std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
[ # # ][ # # ]
[ # # # # ]
811 : : {
812 : : // allow the name anyway if the name is in pDeletedNames
813 : : }
814 : : else
815 : 0 : bExists = true;
816 : : }
817 : :
818 [ + - ]: 14 : if ( !bExists )
819 : 14 : return aDimName; // found a new name
820 : :
821 [ # # ]: 0 : if ( bUseSource )
822 : 0 : bUseSource = false;
823 : : else
824 : 0 : ++nAdd; // continue with higher number
825 [ - + ]: 14 : }
826 : : OSL_FAIL("CreateGroupDimName: no valid name found");
827 : 14 : return rtl::OUString();
828 : : }
829 : :
830 : 6 : rtl::OUString ScDPDimensionSaveData::CreateDateGroupDimName(
831 : : sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource,
832 : : const std::vector<rtl::OUString>* pDeletedNames )
833 : : {
834 : : using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
835 : 6 : rtl::OUString aPartName;
836 [ - - - - : 6 : switch( nDatePart )
- + + - ]
837 : : {
838 : : //! use translated strings from globstr.src
839 : 0 : case SECONDS: aPartName = rtl::OUString::createFromAscii( "Seconds" ); break;
840 : 0 : case MINUTES: aPartName = rtl::OUString::createFromAscii( "Minutes" ); break;
841 : 0 : case HOURS: aPartName = rtl::OUString::createFromAscii( "Hours" ); break;
842 : 0 : case DAYS: aPartName = rtl::OUString::createFromAscii( "Days" ); break;
843 : 0 : case MONTHS: aPartName = rtl::OUString::createFromAscii( "Months" ); break;
844 : 3 : case QUARTERS: aPartName = rtl::OUString::createFromAscii( "Quarters" ); break;
845 : 3 : case YEARS: aPartName = rtl::OUString::createFromAscii( "Years" ); break;
846 : : }
847 : : OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
848 [ + - ]: 6 : return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
849 [ + - ][ + - ]: 153 : }
850 : :
851 : : // ============================================================================
852 : :
853 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|