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