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 12 : ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
39 12 : aGroupName(rName) {}
40 :
41 52 : ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
42 :
43 34 : void ScDPSaveGroupItem::AddElement( const OUString& rName )
44 : {
45 34 : aElements.push_back(rName);
46 34 : }
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) //! 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 6 : size_t ScDPSaveGroupItem::GetElementCount() const
75 : {
76 6 : return aElements.size();
77 : }
78 :
79 12 : const OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
80 : {
81 12 : 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 14 : void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const
99 : {
100 14 : maItems.reserve(aElements.size());
101 14 : std::vector<OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end();
102 54 : for (; it != itEnd; ++it)
103 : {
104 40 : sal_uInt32 nFormat = 0;
105 : double fValue;
106 40 : ScDPItemData aData;
107 40 : if (pFormatter->IsNumberFormat(*it, nFormat, fValue))
108 10 : aData.SetValue(fValue);
109 : else
110 30 : aData.SetString(*it);
111 :
112 40 : maItems.push_back(aData);
113 40 : }
114 14 : }
115 :
116 70 : bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const
117 : {
118 70 : return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
119 : }
120 :
121 14 : void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
122 : {
123 14 : ScDPGroupItem aGroup(aGroupName);
124 14 : std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
125 60 : for (; it != itEnd; ++it)
126 46 : aGroup.AddElement(*it);
127 :
128 14 : rDataDim.AddItem(aGroup);
129 14 : }
130 :
131 18 : ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
132 : aSourceDim( rSource ),
133 : aGroupDimName( rName ),
134 18 : nDatePart( 0 )
135 : {
136 18 : }
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 64 : ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
147 : {
148 64 : }
149 :
150 8 : void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
151 : {
152 8 : aDateInfo = rInfo;
153 8 : nDatePart = nPart;
154 8 : }
155 :
156 12 : void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
157 : {
158 12 : aGroups.push_back( rItem );
159 12 : }
160 :
161 12 : 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 : //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
166 : //! (only dimensions for the same base)
167 :
168 12 : sal_Int32 nAdd = 1; // first try is "Group1"
169 12 : const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
170 26 : while ( nAdd <= nMaxAdd )
171 : {
172 14 : OUString aGroupName = rPrefix + OUString::number( nAdd );
173 14 : bool bExists = false;
174 :
175 : // look for existing groups
176 54 : for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
177 54 : aIter != aGroups.end() && !bExists; ++aIter )
178 4 : if (aIter->GetGroupName().equals(aGroupName)) //! ignore case
179 2 : bExists = true;
180 :
181 14 : if ( !bExists )
182 12 : return aGroupName; // found a new name
183 :
184 2 : ++nAdd; // continue with higher number
185 2 : }
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)) //! ignore case
200 0 : return &*aIter;
201 :
202 0 : return NULL; // none found
203 : }
204 :
205 6 : long ScDPSaveGroupDimension::GetGroupCount() const
206 : {
207 6 : return aGroups.size();
208 : }
209 :
210 6 : const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
211 : {
212 6 : return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
213 : }
214 :
215 6 : ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
216 : {
217 6 : 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)) //! 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 62 : bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const
269 : {
270 62 : ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
271 92 : for (; it != itEnd; ++it)
272 : {
273 70 : if (it->HasInGroup(rItem))
274 40 : return true;
275 : }
276 22 : return false;
277 : }
278 :
279 : namespace {
280 :
281 72 : inline bool isInteger(double fValue)
282 : {
283 72 : return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
284 : }
285 :
286 20 : 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 20 : double fSourceMin = 0.0;
293 20 : double fSourceMax = 0.0;
294 20 : bool bFirst = true;
295 :
296 20 : const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
297 20 : ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
298 716 : for (; it != itEnd; ++it)
299 : {
300 696 : const ScDPItemData& rItem = *it;
301 696 : if (rItem.GetType() != ScDPItemData::Value)
302 0 : continue;
303 :
304 696 : double fVal = rItem.GetValue();
305 696 : if (bFirst)
306 : {
307 20 : fSourceMin = fSourceMax = fVal;
308 20 : bFirst = false;
309 : }
310 : else
311 : {
312 676 : if (fVal < fSourceMin)
313 0 : fSourceMin = fVal;
314 676 : if ( fVal > fSourceMax )
315 676 : 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 20 : if (rDateInfo.mbAutoStart)
323 12 : rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
324 20 : if (rDateInfo.mbAutoEnd)
325 20 : rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
326 :
327 : //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
328 :
329 20 : long nStart = 0, nEnd = 0; // end is inclusive
330 :
331 20 : switch (nDatePart)
332 : {
333 : case sheet::DataPilotFieldGroupBy::YEARS:
334 : nStart = ScDPUtil::getDatePartValue(
335 6 : fSourceMin, NULL, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
336 6 : nEnd = ScDPUtil::getDatePartValue(fSourceMax, NULL, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
337 6 : break;
338 4 : case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break;
339 6 : case sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break;
340 4 : 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 20 : rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
350 :
351 1584 : for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue)
352 1564 : rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
353 :
354 : // add first/last entry (min/max)
355 20 : rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
356 20 : rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
357 20 : }
358 :
359 : }
360 :
361 24 : void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
362 : {
363 24 : long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
364 24 : if ( nSourceIndex >= 0 )
365 : {
366 24 : ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
367 24 : if ( nDatePart )
368 : {
369 : // date grouping
370 :
371 12 : aDim.SetDateDimension();
372 : }
373 : else
374 : {
375 : // normal (manual) grouping
376 :
377 26 : for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter)
378 14 : aIter->AddToData(aDim);
379 : }
380 :
381 24 : rData.AddGroupDimension( aDim );
382 : }
383 24 : }
384 :
385 24 : void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
386 : {
387 24 : long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
388 24 : if (nSourceDim < 0)
389 0 : return;
390 :
391 24 : long nDim = rCache.AppendGroupField();
392 24 : SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
393 :
394 24 : if (nDatePart)
395 : {
396 12 : fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
397 12 : return;
398 : }
399 :
400 12 : rCache.ResetGroupItems(nDim, aDateInfo, 0);
401 : {
402 12 : ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
403 26 : for (; it != itEnd; ++it)
404 : {
405 14 : const ScDPSaveGroupItem& rGI = *it;
406 14 : rGI.ConvertElementsToItems(pFormatter);
407 14 : rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
408 : }
409 : }
410 :
411 12 : const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
412 : {
413 12 : ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
414 74 : for (; it != itEnd; ++it)
415 : {
416 62 : const ScDPItemData& rItem = *it;
417 62 : if (!IsInGroup(rItem))
418 : // Not in any group. Add as its own group.
419 22 : rCache.SetGroupItem(nDim, rItem);
420 : }
421 : }
422 : }
423 :
424 6 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rInfo ) :
425 : aDimensionName( rName ),
426 : aGroupInfo( rInfo ),
427 6 : nDatePart( 0 )
428 : {
429 6 : }
430 :
431 2 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
432 : aDimensionName( rName ),
433 : aDateInfo( rDateInfo ),
434 2 : nDatePart( nPart )
435 : {
436 2 : }
437 :
438 32 : ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
439 : {
440 32 : }
441 :
442 10 : void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
443 : {
444 10 : long nSource = rData.GetDimensionIndex( aDimensionName );
445 10 : if ( nSource >= 0 )
446 : {
447 10 : ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
448 10 : if ( nDatePart )
449 8 : aDim.SetDateDimension();
450 :
451 10 : rData.SetNumGroupDimension( nSource, aDim );
452 : }
453 10 : }
454 :
455 12 : void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
456 : {
457 12 : long nDim = rCache.GetDimensionIndex(aDimensionName);
458 12 : if (nDim < 0)
459 12 : return;
460 :
461 12 : if (aDateInfo.mbEnable)
462 : {
463 : // Date grouping
464 8 : SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
465 8 : fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
466 : }
467 4 : 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 4 : (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
477 12 : (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
478 8 : isInteger(aGroupInfo.mfStep);
479 :
480 4 : double fSourceMin = 0.0;
481 4 : double fSourceMax = 0.0;
482 4 : bool bFirst = true;
483 :
484 4 : const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nDim);
485 4 : ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
486 68 : for (; it != itEnd; ++it)
487 : {
488 64 : const ScDPItemData& rItem = *it;
489 64 : if (rItem.GetType() != ScDPItemData::Value)
490 0 : continue;
491 :
492 64 : double fValue = rItem.GetValue();
493 64 : if (bFirst)
494 : {
495 4 : fSourceMin = fSourceMax = fValue;
496 4 : bFirst = false;
497 4 : continue;
498 : }
499 :
500 60 : if (fValue < fSourceMin)
501 0 : fSourceMin = fValue;
502 60 : if (fValue > fSourceMax)
503 60 : fSourceMax = fValue;
504 :
505 60 : 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 4 : 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 4 : if (aGroupInfo.mbAutoStart)
522 0 : aGroupInfo.mfStart = fSourceMin;
523 4 : if (aGroupInfo.mbAutoEnd)
524 0 : aGroupInfo.mfEnd = fSourceMax;
525 :
526 : //! limit number of entries?
527 :
528 4 : long nLoopCount = 0;
529 4 : double fLoop = aGroupInfo.mfStart;
530 :
531 4 : 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 4 : bool bFirstGroup = true;
540 20 : while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
541 : {
542 12 : ScDPItemData aItem;
543 12 : aItem.SetRangeStart(fLoop);
544 12 : rCache.SetGroupItem(nDim, aItem);
545 12 : ++nLoopCount;
546 12 : fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
547 12 : bFirstGroup = false;
548 :
549 : // ScDPItemData values are compared with approxEqual
550 12 : }
551 :
552 4 : ScDPItemData aItem;
553 4 : aItem.SetRangeFirst();
554 4 : rCache.SetGroupItem(nDim, aItem);
555 :
556 4 : aItem.SetRangeLast();
557 4 : rCache.SetGroupItem(nDim, aItem);
558 : }
559 : }
560 :
561 0 : void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
562 : {
563 0 : aGroupInfo = rNew;
564 0 : }
565 :
566 4 : void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
567 : {
568 4 : aDateInfo = rInfo;
569 4 : nDatePart = nPart;
570 4 : }
571 :
572 : namespace {
573 :
574 522 : struct ScDPSaveGroupDimNameFunc
575 : {
576 : OUString maDimName;
577 58 : inline explicit ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
578 26 : inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
579 : };
580 :
581 144 : struct ScDPSaveGroupSourceNameFunc
582 : {
583 : OUString maSrcDimName;
584 16 : inline explicit ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
585 6 : inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
586 : };
587 :
588 : } // namespace
589 :
590 18 : ScDPDimensionSaveData::ScDPDimensionSaveData()
591 : {
592 18 : }
593 :
594 42 : ScDPDimensionSaveData::~ScDPDimensionSaveData()
595 : {
596 42 : }
597 :
598 0 : bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
599 : {
600 0 : return false;
601 : }
602 :
603 18 : void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
604 : {
605 : OSL_ENSURE( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(),
606 : "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
607 : // ReplaceGroupDimension() adds new or replaces existing
608 18 : ReplaceGroupDimension( rGroupDim );
609 18 : }
610 :
611 18 : void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
612 : {
613 : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
614 18 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
615 18 : if( aIt == maGroupDims.end() )
616 18 : maGroupDims.push_back( rGroupDim );
617 : else
618 0 : *aIt = rGroupDim;
619 18 : }
620 :
621 4 : void ScDPDimensionSaveData::RemoveGroupDimension( const OUString& rGroupDimName )
622 : {
623 : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
624 4 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
625 4 : if( aIt != maGroupDims.end() )
626 4 : maGroupDims.erase( aIt );
627 4 : }
628 :
629 8 : 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 8 : ReplaceNumGroupDimension( rGroupDim );
635 8 : }
636 :
637 8 : void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
638 : {
639 8 : ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
640 8 : if( aIt == maNumGroupDims.end() )
641 8 : maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
642 : else
643 0 : aIt->second = rGroupDim;
644 8 : }
645 :
646 2 : void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString& rGroupDimName )
647 : {
648 2 : maNumGroupDims.erase( rGroupDimName );
649 2 : }
650 :
651 22 : void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
652 : {
653 : // rData is assumed to be empty
654 : // AddToData also handles date grouping
655 :
656 46 : for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
657 24 : aIt->AddToData( rData );
658 :
659 32 : for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
660 10 : aIt->second.AddToData( rData );
661 22 : }
662 :
663 : namespace {
664 :
665 : class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void>
666 : {
667 : ScDPCache& mrCache;
668 : public:
669 24 : AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {}
670 24 : void operator() (const ScDPSaveGroupDimension& rDim)
671 : {
672 24 : rDim.AddToCache(mrCache);
673 24 : }
674 : };
675 :
676 : }
677 :
678 24 : void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const
679 : {
680 24 : std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache));
681 24 : ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end();
682 36 : for (; it != itEnd; ++it)
683 12 : it->second.AddToCache(rCache);
684 24 : }
685 :
686 6 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const OUString& rBaseDimName ) const
687 : {
688 6 : return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
689 : }
690 :
691 26 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const OUString& rGroupDimName ) const
692 : {
693 26 : 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 6 : const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const OUString& rGroupDimName ) const
707 : {
708 6 : return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
709 : }
710 :
711 16 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const OUString& rBaseDimName )
712 : {
713 16 : ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
714 16 : return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
715 : }
716 :
717 26 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const OUString& rGroupDimName )
718 : {
719 : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
720 26 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
721 26 : return (aIt == maGroupDims.end()) ? 0 : &*aIt;
722 : }
723 :
724 16 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const OUString& rBaseDimName )
725 : {
726 : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
727 16 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
728 16 : return (aIt == maGroupDims.end()) ? 0 : &*aIt;
729 : }
730 :
731 10 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const OUString& rGroupDimName )
732 : {
733 : // find the group dimension with the passed name
734 : ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
735 10 : maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
736 : // find next group dimension based on the same source dimension name
737 10 : if( aIt != maGroupDims.end() )
738 0 : aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
739 10 : return (aIt == maGroupDims.end()) ? 0 : &*aIt;
740 : }
741 :
742 6 : ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const OUString& rGroupDimName )
743 : {
744 6 : ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
745 6 : return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
746 : }
747 :
748 16 : bool ScDPDimensionSaveData::HasGroupDimensions() const
749 : {
750 16 : 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 14 : 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 14 : bool bUseSource = bAllowSource; // if set, try the unchanged original name first
774 :
775 14 : sal_Int32 nAdd = 2; // first try is "Name2"
776 14 : const sal_Int32 nMaxAdd = 1000; // limit the loop
777 28 : while ( nAdd <= nMaxAdd )
778 : {
779 14 : OUString aDimName( rSourceName );
780 14 : if ( !bUseSource )
781 10 : aDimName += OUString::number(nAdd);
782 14 : bool bExists = false;
783 :
784 : // look for existing group dimensions
785 16 : for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
786 2 : if( aIt->GetGroupDimName() == aDimName ) //! ignore case
787 0 : bExists = true;
788 :
789 : // look for base dimensions that happen to have that name
790 14 : 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 14 : if ( !bExists )
802 14 : 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 4 : 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 4 : OUString aPartName;
833 4 : 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 2 : case QUARTERS: aPartName = ScGlobal::GetRscString( nDatePartIds[5] ); break;
841 2 : case YEARS: aPartName = ScGlobal::GetRscString( nDatePartIds[6] ); break;
842 : }
843 : OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
844 4 : return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
845 228 : }
846 :
847 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|