fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / dpdimsave.cxx
blobffa721dbe0e9ec581209b3d012a3206896c05298
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 .
20 #include "dpdimsave.hxx"
21 #include "dpgroup.hxx"
22 #include "dpobject.hxx"
23 #include "dputil.hxx"
24 #include "document.hxx"
26 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
28 #include <svl/zforlist.hxx>
29 #include <rtl/math.hxx>
30 #include <algorithm>
32 #include "global.hxx"
33 #include "scresid.hxx"
34 #include "globstr.hrc"
36 using namespace com::sun::star;
38 ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
39 aGroupName(rName) {}
41 ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
43 void ScDPSaveGroupItem::AddElement( const OUString& rName )
45 aElements.push_back(rName);
48 void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
50 // add all elements of the other group (used for nested grouping)
52 for ( std::vector<OUString>::const_iterator aIter(rGroup.aElements.begin());
53 aIter != rGroup.aElements.end(); ++aIter )
54 aElements.push_back( *aIter );
57 bool ScDPSaveGroupItem::RemoveElement( const OUString& rName )
59 for (std::vector<OUString>::iterator aIter = aElements.begin(); aIter != aElements.end(); ++aIter)
60 if (*aIter == rName) //TODO: ignore case
62 aElements.erase(aIter); // found -> remove
63 return true; // don't have to look further
66 return false; // not found
69 bool ScDPSaveGroupItem::IsEmpty() const
71 return aElements.empty();
74 size_t ScDPSaveGroupItem::GetElementCount() const
76 return aElements.size();
79 const OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
81 return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0;
84 void ScDPSaveGroupItem::Rename( const OUString& rNewName )
86 aGroupName = rNewName;
89 void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const
91 // remove this group's elements from their groups in rDimension
92 // (rDimension must be a different dimension from the one which contains this)
94 for ( std::vector<OUString>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
95 rDimension.RemoveFromGroups( *aIter );
98 void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const
100 maItems.reserve(aElements.size());
101 std::vector<OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end();
102 for (; it != itEnd; ++it)
104 sal_uInt32 nFormat = 0;
105 double fValue;
106 ScDPItemData aData;
107 if (pFormatter->IsNumberFormat(*it, nFormat, fValue))
108 aData.SetValue(fValue);
109 else
110 aData.SetString(*it);
112 maItems.push_back(aData);
116 bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const
118 return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
121 void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
123 ScDPGroupItem aGroup(aGroupName);
124 std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
125 for (; it != itEnd; ++it)
126 aGroup.AddElement(*it);
128 rDataDim.AddItem(aGroup);
131 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
132 aSourceDim( rSource ),
133 aGroupDimName( rName ),
134 nDatePart( 0 )
138 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
139 aSourceDim( rSource ),
140 aGroupDimName( rName ),
141 aDateInfo( rDateInfo ),
142 nDatePart( nPart )
146 ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
150 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
152 aDateInfo = rInfo;
153 nDatePart = nPart;
156 void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
158 aGroups.push_back( rItem );
161 OUString ScDPSaveGroupDimension::CreateGroupName(const OUString& rPrefix)
163 // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
165 //TODO: look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
166 //TODO: (only dimensions for the same base)
168 sal_Int32 nAdd = 1; // first try is "Group1"
169 const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
170 while ( nAdd <= nMaxAdd )
172 OUString aGroupName = rPrefix + OUString::number( nAdd );
173 bool bExists = false;
175 // look for existing groups
176 for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
177 aIter != aGroups.end() && !bExists; ++aIter )
178 if (aIter->GetGroupName().equals(aGroupName)) //TODO: ignore case
179 bExists = true;
181 if ( !bExists )
182 return aGroupName; // found a new name
184 ++nAdd; // continue with higher number
187 OSL_FAIL("CreateGroupName: no valid name found");
188 return OUString();
191 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const OUString& rGroupName ) const
193 return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
196 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const OUString& rGroupName )
198 for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
199 if (aIter->GetGroupName().equals(rGroupName)) //TODO: ignore case
200 return &*aIter;
202 return NULL; // none found
205 long ScDPSaveGroupDimension::GetGroupCount() const
207 return aGroups.size();
210 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
212 return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
215 ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
217 return &aGroups[nIndex];
220 void ScDPSaveGroupDimension::RemoveFromGroups( const OUString& rItemName )
222 // if the item is in any group, remove it from the group,
223 // also remove the group if it is empty afterwards
225 for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
226 if ( aIter->RemoveElement( rItemName ) )
228 if ( aIter->IsEmpty() ) // removed last item from the group?
229 aGroups.erase( aIter ); // then remove the group
231 return; // don't have to look further
235 void ScDPSaveGroupDimension::RemoveGroup(const OUString& rGroupName)
237 for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
238 if (aIter->GetGroupName().equals(rGroupName)) //TODO: ignore case
240 aGroups.erase( aIter );
241 return; // don't have to look further
245 bool ScDPSaveGroupDimension::IsEmpty() const
247 return aGroups.empty();
250 bool ScDPSaveGroupDimension::HasOnlyHidden(const ScDPUniqueStringSet& rVisible)
252 // check if there are only groups that don't appear in the list of visible names
254 bool bAllHidden = true;
255 for (ScDPSaveGroupItemVec::const_iterator aIter = aGroups.begin(); aIter != aGroups.end() && bAllHidden; ++aIter)
257 if (rVisible.count(aIter->GetGroupName()) > 0)
258 bAllHidden = false;
260 return bAllHidden;
263 void ScDPSaveGroupDimension::Rename( const OUString& rNewName )
265 aGroupDimName = rNewName;
268 bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const
270 ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
271 for (; it != itEnd; ++it)
273 if (it->HasInGroup(rItem))
274 return true;
276 return false;
279 namespace {
281 inline bool isInteger(double fValue)
283 return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
286 void fillDateGroupDimension(
287 ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, long nSourceDim, long nGroupDim,
288 sal_Int32 nDatePart, SvNumberFormatter* pFormatter)
290 // Auto min/max is only used for "Years" part, but the loop is always
291 // needed.
292 double fSourceMin = 0.0;
293 double fSourceMax = 0.0;
294 bool bFirst = true;
296 const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
297 ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
298 for (; it != itEnd; ++it)
300 const ScDPItemData& rItem = *it;
301 if (rItem.GetType() != ScDPItemData::Value)
302 continue;
304 double fVal = rItem.GetValue();
305 if (bFirst)
307 fSourceMin = fSourceMax = fVal;
308 bFirst = false;
310 else
312 if (fVal < fSourceMin)
313 fSourceMin = fVal;
314 if ( fVal > fSourceMax )
315 fSourceMax = fVal;
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 if (rDateInfo.mbAutoStart)
323 rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
324 if (rDateInfo.mbAutoEnd)
325 rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
327 //TODO: if not automatic, limit fSourceMin/fSourceMax for list of year values?
329 long nStart = 0, nEnd = 0; // end is inclusive
331 switch (nDatePart)
333 case sheet::DataPilotFieldGroupBy::YEARS:
334 nStart = ScDPUtil::getDatePartValue(
335 fSourceMin, NULL, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
336 nEnd = ScDPUtil::getDatePartValue(fSourceMax, NULL, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
337 break;
338 case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break;
339 case sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break;
340 case sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break;
341 case sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break;
342 case sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break;
343 case sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break;
344 default:
345 OSL_FAIL("invalid date part");
348 // Now, populate the group items in the cache.
349 rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
351 for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue)
352 rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
354 // add first/last entry (min/max)
355 rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
356 rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
361 void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
363 long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
364 if ( nSourceIndex >= 0 )
366 ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
367 if ( nDatePart )
369 // date grouping
371 aDim.SetDateDimension();
373 else
375 // normal (manual) grouping
377 for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter)
378 aIter->AddToData(aDim);
381 rData.AddGroupDimension( aDim );
385 void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
387 long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
388 if (nSourceDim < 0)
389 return;
391 long nDim = rCache.AppendGroupField();
392 SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
394 if (nDatePart)
396 fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
397 return;
400 rCache.ResetGroupItems(nDim, aDateInfo, 0);
402 ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
403 for (; it != itEnd; ++it)
405 const ScDPSaveGroupItem& rGI = *it;
406 rGI.ConvertElementsToItems(pFormatter);
407 rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
411 const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
413 ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
414 for (; it != itEnd; ++it)
416 const ScDPItemData& rItem = *it;
417 if (!IsInGroup(rItem))
418 // Not in any group. Add as its own group.
419 rCache.SetGroupItem(nDim, rItem);
424 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rInfo ) :
425 aDimensionName( rName ),
426 aGroupInfo( rInfo ),
427 nDatePart( 0 )
431 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
432 aDimensionName( rName ),
433 aDateInfo( rDateInfo ),
434 nDatePart( nPart )
438 ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
442 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
444 long nSource = rData.GetDimensionIndex( aDimensionName );
445 if ( nSource >= 0 )
447 ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
448 if ( nDatePart )
449 aDim.SetDateDimension();
451 rData.SetNumGroupDimension( nSource, aDim );
455 void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
457 long nDim = rCache.GetDimensionIndex(aDimensionName);
458 if (nDim < 0)
459 return;
461 if (aDateInfo.mbEnable)
463 // Date grouping
464 SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
465 fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
467 else if (aGroupInfo.mbEnable)
469 // Number-range grouping
471 // Look through the source entries for non-integer numbers, minimum
472 // and maximum.
474 // non-integer GroupInfo values count, too
475 aGroupInfo.mbIntegerOnly =
476 (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
477 (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
478 isInteger(aGroupInfo.mfStep);
480 double fSourceMin = 0.0;
481 double fSourceMax = 0.0;
482 bool bFirst = true;
484 const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nDim);
485 ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
486 for (; it != itEnd; ++it)
488 const ScDPItemData& rItem = *it;
489 if (rItem.GetType() != ScDPItemData::Value)
490 continue;
492 double fValue = rItem.GetValue();
493 if (bFirst)
495 fSourceMin = fSourceMax = fValue;
496 bFirst = false;
497 continue;
500 if (fValue < fSourceMin)
501 fSourceMin = fValue;
502 if (fValue > fSourceMax)
503 fSourceMax = fValue;
505 if (aGroupInfo.mbIntegerOnly && !isInteger(fValue))
507 // If any non-integer numbers are involved, the group labels
508 // are shown including their upper limit.
509 aGroupInfo.mbIntegerOnly = false;
513 if (aGroupInfo.mbDateValues)
515 // special handling for dates: always integer, round down limits
516 aGroupInfo.mbIntegerOnly = true;
517 fSourceMin = rtl::math::approxFloor(fSourceMin);
518 fSourceMax = rtl::math::approxFloor(fSourceMax) + 1;
521 if (aGroupInfo.mbAutoStart)
522 aGroupInfo.mfStart = fSourceMin;
523 if (aGroupInfo.mbAutoEnd)
524 aGroupInfo.mfEnd = fSourceMax;
526 //TODO: limit number of entries?
528 long nLoopCount = 0;
529 double fLoop = aGroupInfo.mfStart;
531 rCache.ResetGroupItems(nDim, aGroupInfo, 0);
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.
539 bool bFirstGroup = true;
540 while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
542 ScDPItemData aItem;
543 aItem.SetRangeStart(fLoop);
544 rCache.SetGroupItem(nDim, aItem);
545 ++nLoopCount;
546 fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
547 bFirstGroup = false;
549 // ScDPItemData values are compared with approxEqual
552 ScDPItemData aItem;
553 aItem.SetRangeFirst();
554 rCache.SetGroupItem(nDim, aItem);
556 aItem.SetRangeLast();
557 rCache.SetGroupItem(nDim, aItem);
561 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
563 aGroupInfo = rNew;
566 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
568 aDateInfo = rInfo;
569 nDatePart = nPart;
572 namespace {
574 struct ScDPSaveGroupDimNameFunc
576 OUString maDimName;
577 inline explicit ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
578 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
581 struct ScDPSaveGroupSourceNameFunc
583 OUString maSrcDimName;
584 inline explicit ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
585 inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
588 } // namespace
590 ScDPDimensionSaveData::ScDPDimensionSaveData()
594 ScDPDimensionSaveData::~ScDPDimensionSaveData()
598 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
600 return false;
603 void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
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 ReplaceGroupDimension( rGroupDim );
611 void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
613 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
614 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
615 if( aIt == maGroupDims.end() )
616 maGroupDims.push_back( rGroupDim );
617 else
618 *aIt = rGroupDim;
621 void ScDPDimensionSaveData::RemoveGroupDimension( const OUString& rGroupDimName )
623 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
624 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
625 if( aIt != maGroupDims.end() )
626 maGroupDims.erase( aIt );
629 void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
631 OSL_ENSURE( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
632 "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
633 // ReplaceNumGroupDimension() adds new or replaces existing
634 ReplaceNumGroupDimension( rGroupDim );
637 void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
639 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
640 if( aIt == maNumGroupDims.end() )
641 maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
642 else
643 aIt->second = rGroupDim;
646 void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString& rGroupDimName )
648 maNumGroupDims.erase( rGroupDimName );
651 void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
653 // rData is assumed to be empty
654 // AddToData also handles date grouping
656 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
657 aIt->AddToData( rData );
659 for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
660 aIt->second.AddToData( rData );
663 namespace {
665 class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void>
667 ScDPCache& mrCache;
668 public:
669 AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {}
670 void operator() (const ScDPSaveGroupDimension& rDim)
672 rDim.AddToCache(mrCache);
678 void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const
680 std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache));
681 ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end();
682 for (; it != itEnd; ++it)
683 it->second.AddToCache(rCache);
686 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const OUString& rBaseDimName ) const
688 return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
691 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const OUString& rGroupDimName ) const
693 return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
696 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const OUString& rBaseDimName ) const
698 return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
701 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const OUString& rGroupDimName ) const
703 return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
706 const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const OUString& rGroupDimName ) const
708 return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
711 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const OUString& rBaseDimName )
713 ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
714 return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
717 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const OUString& rGroupDimName )
719 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
720 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
721 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
724 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const OUString& rBaseDimName )
726 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
727 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
728 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
731 ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const OUString& rGroupDimName )
733 // find the group dimension with the passed name
734 ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
735 maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
736 // find next group dimension based on the same source dimension name
737 if( aIt != maGroupDims.end() )
738 aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
739 return (aIt == maGroupDims.end()) ? 0 : &*aIt;
742 ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const OUString& rGroupDimName )
744 ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
745 return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
748 bool ScDPDimensionSaveData::HasGroupDimensions() const
750 return !maGroupDims.empty() || !maNumGroupDims.empty();
753 sal_Int32 ScDPDimensionSaveData::CollectDateParts( const OUString& rBaseDimName ) const
755 sal_Int32 nParts = 0;
756 // start with part of numeric group
757 if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
758 nParts |= pNumDim->GetDatePart();
759 // collect parts from all matching group dimensions
760 for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
761 nParts |= pGroupDim->GetDatePart();
763 return nParts;
766 OUString ScDPDimensionSaveData::CreateGroupDimName(
767 const OUString& rSourceName, const ScDPObject& rObject, bool bAllowSource,
768 const std::vector<OUString>* pDeletedNames )
770 // create a name for the new dimension by appending a number to the original
771 // dimension's name
773 bool bUseSource = bAllowSource; // if set, try the unchanged original name first
775 sal_Int32 nAdd = 2; // first try is "Name2"
776 const sal_Int32 nMaxAdd = 1000; // limit the loop
777 while ( nAdd <= nMaxAdd )
779 OUString aDimName( rSourceName );
780 if ( !bUseSource )
781 aDimName += OUString::number(nAdd);
782 bool bExists = false;
784 // look for existing group dimensions
785 for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
786 if( aIt->GetGroupDimName() == aDimName ) //TODO: ignore case
787 bExists = true;
789 // look for base dimensions that happen to have that name
790 if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
792 if ( pDeletedNames &&
793 std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
795 // allow the name anyway if the name is in pDeletedNames
797 else
798 bExists = true;
801 if ( !bExists )
802 return aDimName; // found a new name
804 if ( bUseSource )
805 bUseSource = false;
806 else
807 ++nAdd; // continue with higher number
809 OSL_FAIL("CreateGroupDimName: no valid name found");
810 return OUString();
813 namespace
815 static const sal_uInt16 nDatePartIds[] =
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
827 OUString ScDPDimensionSaveData::CreateDateGroupDimName(
828 sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource,
829 const std::vector<OUString>* pDeletedNames )
831 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
832 OUString aPartName;
833 switch( nDatePart )
835 case SECONDS: aPartName = ScGlobal::GetRscString( nDatePartIds[0] ); break;
836 case MINUTES: aPartName = ScGlobal::GetRscString( nDatePartIds[1] ); break;
837 case HOURS: aPartName = ScGlobal::GetRscString( nDatePartIds[2] ); break;
838 case DAYS: aPartName = ScGlobal::GetRscString( nDatePartIds[3] ); break;
839 case MONTHS: aPartName = ScGlobal::GetRscString( nDatePartIds[4] ); break;
840 case QUARTERS: aPartName = ScGlobal::GetRscString( nDatePartIds[5] ); break;
841 case YEARS: aPartName = ScGlobal::GetRscString( nDatePartIds[6] ); break;
843 OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
844 return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
847 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */