Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / dpdimsave.cxx
blobd200971d50ab2b50dd9045b1b166a71b13543361
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "dpdimsave.hxx"
22 #include "dpgroup.hxx"
23 #include "dpobject.hxx"
24 #include "dputil.hxx"
25 #include "document.hxx"
27 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
29 #include <svl/zforlist.hxx>
30 #include <rtl/math.hxx>
31 #include <algorithm>
33 #include "global.hxx"
34 #include "scresid.hxx"
35 #include "globstr.hrc"
37 using namespace com::sun::star;
39 // ============================================================================
41 ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
42 aGroupName(rName) {}
44 ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
46 void ScDPSaveGroupItem::AddElement( const OUString& rName )
48 aElements.push_back(rName);
51 void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
53 // add all elements of the other group (used for nested grouping)
55 for ( std::vector<OUString>::const_iterator aIter(rGroup.aElements.begin());
56 aIter != rGroup.aElements.end(); ++aIter )
57 aElements.push_back( *aIter );
60 bool ScDPSaveGroupItem::RemoveElement( const OUString& rName )
62 for (std::vector<OUString>::iterator aIter = aElements.begin(); aIter != aElements.end(); ++aIter)
63 if (*aIter == rName) //! ignore case
65 aElements.erase(aIter); // found -> remove
66 return true; // don't have to look further
69 return false; // not found
72 bool ScDPSaveGroupItem::IsEmpty() const
74 return aElements.empty();
77 size_t ScDPSaveGroupItem::GetElementCount() const
79 return aElements.size();
82 const OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
84 return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0;
87 void ScDPSaveGroupItem::Rename( const OUString& rNewName )
89 aGroupName = rNewName;
92 void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const
94 // remove this group's elements from their groups in rDimension
95 // (rDimension must be a different dimension from the one which contains this)
97 for ( std::vector<OUString>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
98 rDimension.RemoveFromGroups( *aIter );
101 void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const
103 maItems.reserve(aElements.size());
104 std::vector<OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end();
105 for (; it != itEnd; ++it)
107 sal_uInt32 nFormat = 0;
108 double fValue;
109 ScDPItemData aData;
110 if (pFormatter->IsNumberFormat(*it, nFormat, fValue))
111 aData.SetValue(fValue);
112 else
113 aData.SetString(*it);
115 maItems.push_back(aData);
119 bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const
121 return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
124 void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
126 ScDPGroupItem aGroup(aGroupName);
127 std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
128 for (; it != itEnd; ++it)
129 aGroup.AddElement(*it);
131 rDataDim.AddItem(aGroup);
134 // ============================================================================
136 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
137 aSourceDim( rSource ),
138 aGroupDimName( rName ),
139 nDatePart( 0 )
143 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
144 aSourceDim( rSource ),
145 aGroupDimName( rName ),
146 aDateInfo( rDateInfo ),
147 nDatePart( nPart )
151 ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
155 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
157 aDateInfo = rInfo;
158 nDatePart = nPart;
161 void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
163 aGroups.push_back( rItem );
166 OUString ScDPSaveGroupDimension::CreateGroupName(const OUString& rPrefix)
168 // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
170 //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
171 //! (only dimensions for the same base)
173 sal_Int32 nAdd = 1; // first try is "Group1"
174 const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
175 while ( nAdd <= nMaxAdd )
177 OUString aGroupName = rPrefix + OUString::number( nAdd );
178 bool bExists = false;
180 // look for existing groups
181 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
182 aIter != aGroups.end() && !bExists; ++aIter )
183 if (aIter->GetGroupName().equals(aGroupName)) //! ignore case
184 bExists = true;
186 if ( !bExists )
187 return aGroupName; // found a new name
189 ++nAdd; // continue with higher number
192 OSL_FAIL("CreateGroupName: no valid name found");
193 return OUString();
196 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const OUString& rGroupName ) const
198 return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
201 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const OUString& rGroupName )
203 for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
204 if (aIter->GetGroupName().equals(rGroupName)) //! ignore case
205 return &*aIter;
207 return NULL; // none found
210 long ScDPSaveGroupDimension::GetGroupCount() const
212 return aGroups.size();
215 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
217 return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
220 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
222 return &aGroups[nIndex];
225 void ScDPSaveGroupDimension::RemoveFromGroups( const OUString& rItemName )
227 // if the item is in any group, remove it from the group,
228 // also remove the group if it is empty afterwards
230 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
231 if ( aIter->RemoveElement( rItemName ) )
233 if ( aIter->IsEmpty() ) // removed last item from the group?
234 aGroups.erase( aIter ); // then remove the group
236 return; // don't have to look further
240 void ScDPSaveGroupDimension::RemoveGroup(const OUString& rGroupName)
242 for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
243 if (aIter->GetGroupName().equals(rGroupName)) //! ignore case
245 aGroups.erase( aIter );
246 return; // don't have to look further
250 bool ScDPSaveGroupDimension::IsEmpty() const
252 return aGroups.empty();
255 bool ScDPSaveGroupDimension::HasOnlyHidden(const ScDPUniqueStringSet& rVisible)
257 // check if there are only groups that don't appear in the list of visible names
259 bool bAllHidden = true;
260 for (ScDPSaveGroupItemVec::const_iterator aIter = aGroups.begin(); aIter != aGroups.end() && bAllHidden; ++aIter)
262 if (rVisible.count(aIter->GetGroupName()) > 0)
263 bAllHidden = false;
265 return bAllHidden;
268 void ScDPSaveGroupDimension::Rename( const OUString& rNewName )
270 aGroupDimName = rNewName;
273 bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const
275 ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
276 for (; it != itEnd; ++it)
278 if (it->HasInGroup(rItem))
279 return true;
281 return false;
284 namespace {
286 inline bool isInteger(double fValue)
288 return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
291 void fillDateGroupDimension(
292 ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, long nSourceDim, long nGroupDim,
293 sal_Int32 nDatePart, SvNumberFormatter* pFormatter)
295 // Auto min/max is only used for "Years" part, but the loop is always
296 // needed.
297 double fSourceMin = 0.0;
298 double fSourceMax = 0.0;
299 bool bFirst = true;
301 const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
302 ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
303 for (; it != itEnd; ++it)
305 const ScDPItemData& rItem = *it;
306 if (rItem.GetType() != ScDPItemData::Value)
307 continue;
309 double fVal = rItem.GetValue();
310 if (bFirst)
312 fSourceMin = fSourceMax = fVal;
313 bFirst = false;
315 else
317 if (fVal < fSourceMin)
318 fSourceMin = fVal;
319 if ( fVal > fSourceMax )
320 fSourceMax = fVal;
324 // For the start/end values, use the same date rounding as in
325 // ScDPNumGroupDimension::GetNumEntries (but not for the list of
326 // available years).
327 if (rDateInfo.mbAutoStart)
328 rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
329 if (rDateInfo.mbAutoEnd)
330 rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
332 //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
334 long nStart = 0, nEnd = 0; // end is inclusive
336 switch (nDatePart)
338 case sheet::DataPilotFieldGroupBy::YEARS:
339 nStart = ScDPUtil::getDatePartValue(
340 fSourceMin, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
341 nEnd = ScDPUtil::getDatePartValue(fSourceMax, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
342 break;
343 case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break;
344 case sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break;
345 case sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break;
346 case sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break;
347 case sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break;
348 case sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break;
349 default:
350 OSL_FAIL("invalid date part");
353 // Now, populate the group items in the cache.
354 rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
356 for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue)
357 rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
359 // add first/last entry (min/max)
360 rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
361 rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
366 void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
368 long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
369 if ( nSourceIndex >= 0 )
371 ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
372 if ( nDatePart )
374 // date grouping
376 aDim.SetDateDimension();
378 else
380 // normal (manual) grouping
382 for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter)
383 aIter->AddToData(aDim);
386 rData.AddGroupDimension( aDim );
390 void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
392 long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
393 if (nSourceDim < 0)
394 return;
396 long nDim = rCache.AppendGroupField();
397 SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
399 if (nDatePart)
401 fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
402 return;
405 rCache.ResetGroupItems(nDim, aDateInfo, 0);
407 ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
408 for (; it != itEnd; ++it)
410 const ScDPSaveGroupItem& rGI = *it;
411 rGI.ConvertElementsToItems(pFormatter);
412 rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
416 const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
418 ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
419 for (; it != itEnd; ++it)
421 const ScDPItemData& rItem = *it;
422 if (!IsInGroup(rItem))
423 // Not in any group. Add as its own group.
424 rCache.SetGroupItem(nDim, rItem);
429 // ============================================================================
431 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rInfo ) :
432 aDimensionName( rName ),
433 aGroupInfo( rInfo ),
434 nDatePart( 0 )
438 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
439 aDimensionName( rName ),
440 aDateInfo( rDateInfo ),
441 nDatePart( nPart )
445 ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
449 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
451 long nSource = rData.GetDimensionIndex( aDimensionName );
452 if ( nSource >= 0 )
454 ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
455 if ( nDatePart )
456 aDim.SetDateDimension();
458 rData.SetNumGroupDimension( nSource, aDim );
462 void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
464 long nDim = rCache.GetDimensionIndex(aDimensionName);
465 if (nDim < 0)
466 return;
468 if (aDateInfo.mbEnable)
470 // Date grouping
471 SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
472 fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
474 else if (aGroupInfo.mbEnable)
476 // Number-range grouping
478 // Look through the source entries for non-integer numbers, minimum
479 // and maximum.
481 // non-integer GroupInfo values count, too
482 aGroupInfo.mbIntegerOnly =
483 (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
484 (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
485 isInteger(aGroupInfo.mfStep);
487 double fSourceMin = 0.0;
488 double fSourceMax = 0.0;
489 bool bFirst = true;
491 const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nDim);
492 ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
493 for (; it != itEnd; ++it)
495 const ScDPItemData& rItem = *it;
496 if (rItem.GetType() != ScDPItemData::Value)
497 continue;
499 double fValue = rItem.GetValue();
500 if (bFirst)
502 fSourceMin = fSourceMax = fValue;
503 bFirst = false;
504 continue;
507 if (fValue < fSourceMin)
508 fSourceMin = fValue;
509 if (fValue > fSourceMax)
510 fSourceMax = fValue;
512 if (aGroupInfo.mbIntegerOnly && !isInteger(fValue))
514 // If any non-integer numbers are involved, the group labels
515 // are shown including their upper limit.
516 aGroupInfo.mbIntegerOnly = false;
520 if (aGroupInfo.mbDateValues)
522 // special handling for dates: always integer, round down limits
523 aGroupInfo.mbIntegerOnly = true;
524 fSourceMin = rtl::math::approxFloor(fSourceMin);
525 fSourceMax = rtl::math::approxFloor(fSourceMax) + 1;
528 if (aGroupInfo.mbAutoStart)
529 aGroupInfo.mfStart = fSourceMin;
530 if (aGroupInfo.mbAutoEnd)
531 aGroupInfo.mfEnd = fSourceMax;
533 //! limit number of entries?
535 long nLoopCount = 0;
536 double fLoop = aGroupInfo.mfStart;
538 rCache.ResetGroupItems(nDim, aGroupInfo, 0);
540 // Use "less than" instead of "less or equal" for the loop - don't
541 // create a group that consists only of the end value. Instead, the
542 // end value is then included in the last group (last group is bigger
543 // than the others). The first group has to be created nonetheless.
544 // GetNumGroupForValue has corresponding logic.
546 bool bFirstGroup = true;
547 while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
549 ScDPItemData aItem;
550 aItem.SetRangeStart(fLoop);
551 rCache.SetGroupItem(nDim, aItem);
552 ++nLoopCount;
553 fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
554 bFirstGroup = false;
556 // ScDPItemData values are compared with approxEqual
559 ScDPItemData aItem;
560 aItem.SetRangeFirst();
561 rCache.SetGroupItem(nDim, aItem);
563 aItem.SetRangeLast();
564 rCache.SetGroupItem(nDim, aItem);
568 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
570 aGroupInfo = rNew;
573 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
575 aDateInfo = rInfo;
576 nDatePart = nPart;
579 // ============================================================================
581 namespace {
583 struct ScDPSaveGroupDimNameFunc
585 OUString maDimName;
586 inline explicit ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
587 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
590 struct ScDPSaveGroupSourceNameFunc
592 OUString maSrcDimName;
593 inline explicit ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
594 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
597 } // namespace
599 // ----------------------------------------------------------------------------
601 ScDPDimensionSaveData::ScDPDimensionSaveData()
605 ScDPDimensionSaveData::~ScDPDimensionSaveData()
609 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
611 return false;
614 void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
616 OSL_ENSURE( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(),
617 "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
618 // ReplaceGroupDimension() adds new or replaces existing
619 ReplaceGroupDimension( rGroupDim );
622 void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
624 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
625 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
626 if( aIt == maGroupDims.end() )
627 maGroupDims.push_back( rGroupDim );
628 else
629 *aIt = rGroupDim;
632 void ScDPDimensionSaveData::RemoveGroupDimension( const OUString& rGroupDimName )
634 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
635 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
636 if( aIt != maGroupDims.end() )
637 maGroupDims.erase( aIt );
640 void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
642 OSL_ENSURE( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
643 "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
644 // ReplaceNumGroupDimension() adds new or replaces existing
645 ReplaceNumGroupDimension( rGroupDim );
648 void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
650 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
651 if( aIt == maNumGroupDims.end() )
652 maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
653 else
654 aIt->second = rGroupDim;
657 void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString& rGroupDimName )
659 maNumGroupDims.erase( rGroupDimName );
662 void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
664 // rData is assumed to be empty
665 // AddToData also handles date grouping
667 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
668 aIt->AddToData( rData );
670 for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
671 aIt->second.AddToData( rData );
674 namespace {
676 class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void>
678 ScDPCache& mrCache;
679 public:
680 AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {}
681 void operator() (const ScDPSaveGroupDimension& rDim)
683 rDim.AddToCache(mrCache);
689 void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const
691 std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache));
692 ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end();
693 for (; it != itEnd; ++it)
694 it->second.AddToCache(rCache);
697 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const OUString& rBaseDimName ) const
699 return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
702 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const OUString& rGroupDimName ) const
704 return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
707 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const OUString& rBaseDimName ) const
709 return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
712 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const OUString& rGroupDimName ) const
714 return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
717 const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const OUString& rGroupDimName ) const
719 return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
722 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const OUString& rBaseDimName )
724 ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
725 return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
728 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const OUString& rGroupDimName )
730 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
731 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
732 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
735 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const OUString& rBaseDimName )
737 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
738 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
739 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
742 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const OUString& rGroupDimName )
744 // find the group dimension with the passed name
745 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
746 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
747 // find next group dimension based on the same source dimension name
748 if( aIt != maGroupDims.end() )
749 aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
750 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
753 ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const OUString& rGroupDimName )
755 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
756 return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
759 bool ScDPDimensionSaveData::HasGroupDimensions() const
761 return !maGroupDims.empty() || !maNumGroupDims.empty();
764 sal_Int32 ScDPDimensionSaveData::CollectDateParts( const OUString& rBaseDimName ) const
766 sal_Int32 nParts = 0;
767 // start with part of numeric group
768 if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
769 nParts |= pNumDim->GetDatePart();
770 // collect parts from all matching group dimensions
771 for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
772 nParts |= pGroupDim->GetDatePart();
774 return nParts;
777 OUString ScDPDimensionSaveData::CreateGroupDimName(
778 const OUString& rSourceName, const ScDPObject& rObject, bool bAllowSource,
779 const std::vector<OUString>* pDeletedNames )
781 // create a name for the new dimension by appending a number to the original
782 // dimension's name
784 bool bUseSource = bAllowSource; // if set, try the unchanged original name first
786 sal_Int32 nAdd = 2; // first try is "Name2"
787 const sal_Int32 nMaxAdd = 1000; // limit the loop
788 while ( nAdd <= nMaxAdd )
790 OUString aDimName( rSourceName );
791 if ( !bUseSource )
792 aDimName += OUString::number(nAdd);
793 bool bExists = false;
795 // look for existing group dimensions
796 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
797 if( aIt->GetGroupDimName() == aDimName ) //! ignore case
798 bExists = true;
800 // look for base dimensions that happen to have that name
801 if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
803 if ( pDeletedNames &&
804 std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
806 // allow the name anyway if the name is in pDeletedNames
808 else
809 bExists = true;
812 if ( !bExists )
813 return aDimName; // found a new name
815 if ( bUseSource )
816 bUseSource = false;
817 else
818 ++nAdd; // continue with higher number
820 OSL_FAIL("CreateGroupDimName: no valid name found");
821 return OUString();
824 namespace
826 static const sal_uInt16 nDatePartIds[] =
828 STR_DPFIELD_GROUP_BY_SECONDS,
829 STR_DPFIELD_GROUP_BY_MINUTES,
830 STR_DPFIELD_GROUP_BY_HOURS,
831 STR_DPFIELD_GROUP_BY_DAYS,
832 STR_DPFIELD_GROUP_BY_MONTHS,
833 STR_DPFIELD_GROUP_BY_QUARTERS,
834 STR_DPFIELD_GROUP_BY_YEARS
838 OUString ScDPDimensionSaveData::CreateDateGroupDimName(
839 sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource,
840 const std::vector<OUString>* pDeletedNames )
842 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
843 OUString aPartName;
844 switch( nDatePart )
846 case SECONDS: aPartName = ScGlobal::GetRscString( nDatePartIds[0] ); break;
847 case MINUTES: aPartName = ScGlobal::GetRscString( nDatePartIds[1] ); break;
848 case HOURS: aPartName = ScGlobal::GetRscString( nDatePartIds[2] ); break;
849 case DAYS: aPartName = ScGlobal::GetRscString( nDatePartIds[3] ); break;
850 case MONTHS: aPartName = ScGlobal::GetRscString( nDatePartIds[4] ); break;
851 case QUARTERS: aPartName = ScGlobal::GetRscString( nDatePartIds[5] ); break;
852 case YEARS: aPartName = ScGlobal::GetRscString( nDatePartIds[6] ); break;
854 OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
855 return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
858 // ============================================================================
860 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */