1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <dpcache.hxx>
21 #include <dpdimsave.hxx>
22 #include <dpgroup.hxx>
23 #include <dpobject.hxx>
25 #include <document.hxx>
27 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
29 #include <svl/numformat.hxx>
30 #include <osl/diagnose.h>
31 #include <rtl/math.hxx>
34 #include <globstr.hrc>
35 #include <scresid.hxx>
38 using namespace com::sun::star
;
40 ScDPSaveGroupItem::ScDPSaveGroupItem( OUString aName
) :
41 aGroupName(std::move(aName
)) {}
43 ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
45 void ScDPSaveGroupItem::AddElement( const OUString
& rName
)
47 aElements
.push_back(rName
);
50 void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem
& rGroup
)
52 // add all elements of the other group (used for nested grouping)
53 aElements
.insert( aElements
.end(), rGroup
.aElements
.begin(), rGroup
.aElements
.end() );
56 bool ScDPSaveGroupItem::RemoveElement( const OUString
& rName
)
58 auto it
= std::find(aElements
.begin(), aElements
.end(), rName
); //TODO: ignore case
59 if (it
!= aElements
.end())
64 return false; // not found
67 bool ScDPSaveGroupItem::IsEmpty() const
69 return aElements
.empty();
72 size_t ScDPSaveGroupItem::GetElementCount() const
74 return aElements
.size();
77 const OUString
* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex
) const
79 return (nIndex
< aElements
.size()) ? &aElements
[ nIndex
] : nullptr;
82 void ScDPSaveGroupItem::Rename( const OUString
& rNewName
)
84 aGroupName
= rNewName
;
87 void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension
& rDimension
) const
89 // remove this group's elements from their groups in rDimension
90 // (rDimension must be a different dimension from the one which contains this)
92 for ( const auto& rElement
: aElements
)
93 rDimension
.RemoveFromGroups( rElement
);
96 void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter
* pFormatter
) const
98 maItems
.reserve(aElements
.size());
99 for (const auto& rElement
: aElements
)
101 sal_uInt32 nFormat
= 0;
104 if (pFormatter
->IsNumberFormat(rElement
, nFormat
, fValue
))
105 aData
.SetValue(fValue
);
107 aData
.SetString(rElement
);
109 maItems
.push_back(aData
);
113 bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData
& rItem
) const
115 return std::find(maItems
.begin(), maItems
.end(), rItem
) != maItems
.end();
118 void ScDPSaveGroupItem::AddToData(ScDPGroupDimension
& rDataDim
) const
120 ScDPGroupItem
aGroup(aGroupName
);
121 for (const auto& rItem
: maItems
)
122 aGroup
.AddElement(rItem
);
124 rDataDim
.AddItem(aGroup
);
127 ScDPSaveGroupDimension::ScDPSaveGroupDimension( OUString aSource
, OUString aName
) :
128 aSourceDim(std::move( aSource
)),
129 aGroupDimName(std::move( aName
)),
134 ScDPSaveGroupDimension::ScDPSaveGroupDimension( OUString aSource
, OUString aName
, const ScDPNumGroupInfo
& rDateInfo
, sal_Int32 nPart
) :
135 aSourceDim(std::move( aSource
)),
136 aGroupDimName(std::move( aName
)),
137 aDateInfo( rDateInfo
),
142 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo
& rInfo
, sal_Int32 nPart
)
148 void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem
& rItem
)
150 aGroups
.push_back( rItem
);
153 OUString
ScDPSaveGroupDimension::CreateGroupName(std::u16string_view rPrefix
)
155 // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
157 //TODO: look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
158 //TODO: (only dimensions for the same base)
160 sal_Int32 nAdd
= 1; // first try is "Group1"
161 const sal_Int32 nMaxAdd
= nAdd
+ aGroups
.size(); // limit the loop
162 while ( nAdd
<= nMaxAdd
)
164 OUString aGroupName
= rPrefix
+ OUString::number( nAdd
);
166 // look for existing groups
167 bool bExists
= std::any_of(aGroups
.begin(), aGroups
.end(),
168 [&aGroupName
](const ScDPSaveGroupItem
& rGroup
) {
169 return rGroup
.GetGroupName() == aGroupName
; //TODO: ignore case
173 return aGroupName
; // found a new name
175 ++nAdd
; // continue with higher number
178 OSL_FAIL("CreateGroupName: no valid name found");
182 const ScDPSaveGroupItem
* ScDPSaveGroupDimension::GetNamedGroup( const OUString
& rGroupName
) const
184 return const_cast< ScDPSaveGroupDimension
* >( this )->GetNamedGroupAcc( rGroupName
);
187 ScDPSaveGroupItem
* ScDPSaveGroupDimension::GetNamedGroupAcc( const OUString
& rGroupName
)
189 auto aIter
= std::find_if(aGroups
.begin(), aGroups
.end(),
190 [&rGroupName
](const ScDPSaveGroupItem
& rGroup
) {
191 return rGroup
.GetGroupName() == rGroupName
; //TODO: ignore case
193 if (aIter
!= aGroups
.end())
196 return nullptr; // none found
199 tools::Long
ScDPSaveGroupDimension::GetGroupCount() const
201 return aGroups
.size();
204 const ScDPSaveGroupItem
& ScDPSaveGroupDimension::GetGroupByIndex( tools::Long nIndex
) const
206 return aGroups
[nIndex
];
210 void ScDPSaveGroupDimension::RemoveFromGroups( const OUString
& rItemName
)
212 // if the item is in any group, remove it from the group,
213 // also remove the group if it is empty afterwards
215 for ( ScDPSaveGroupItemVec::iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
216 if ( aIter
->RemoveElement( rItemName
) )
218 if ( aIter
->IsEmpty() ) // removed last item from the group?
219 aGroups
.erase( aIter
); // then remove the group
221 return; // don't have to look further
225 void ScDPSaveGroupDimension::RemoveGroup(const OUString
& rGroupName
)
227 auto aIter
= std::find_if(aGroups
.begin(), aGroups
.end(),
228 [&rGroupName
](const ScDPSaveGroupItem
& rGroup
) {
229 return rGroup
.GetGroupName() == rGroupName
; //TODO: ignore case
231 if (aIter
!= aGroups
.end())
232 aGroups
.erase( aIter
);
235 bool ScDPSaveGroupDimension::IsEmpty() const
237 return aGroups
.empty();
240 bool ScDPSaveGroupDimension::HasOnlyHidden(const ScDPUniqueStringSet
& rVisible
)
242 // check if there are only groups that don't appear in the list of visible names
244 return std::none_of(aGroups
.begin(), aGroups
.end(),
245 [&rVisible
](const ScDPSaveGroupItem
& rGroup
) { return rVisible
.count(rGroup
.GetGroupName()) > 0; });
248 void ScDPSaveGroupDimension::Rename( const OUString
& rNewName
)
250 aGroupDimName
= rNewName
;
253 bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData
& rItem
) const
255 return std::any_of(aGroups
.begin(), aGroups
.end(),
256 [&rItem
](const ScDPSaveGroupItem
& rGroup
) { return rGroup
.HasInGroup(rItem
); });
261 bool isInteger(double fValue
)
263 return rtl::math::approxEqual(fValue
, rtl::math::approxFloor(fValue
));
266 void fillDateGroupDimension(
267 ScDPCache
& rCache
, ScDPNumGroupInfo
& rDateInfo
, tools::Long nSourceDim
, tools::Long nGroupDim
,
268 sal_Int32 nDatePart
, const SvNumberFormatter
* pFormatter
)
270 // Auto min/max is only used for "Years" part, but the loop is always
272 double fSourceMin
= 0.0;
273 double fSourceMax
= 0.0;
276 const ScDPCache::ScDPItemDataVec
& rItems
= rCache
.GetDimMemberValues(nSourceDim
);
277 for (const ScDPItemData
& rItem
: rItems
)
279 if (rItem
.GetType() != ScDPItemData::Value
)
282 double fVal
= rItem
.GetValue();
285 fSourceMin
= fSourceMax
= fVal
;
290 if (fVal
< fSourceMin
)
292 if ( fVal
> fSourceMax
)
297 // For the start/end values, use the same date rounding as in
298 // ScDPNumGroupDimension::GetNumEntries (but not for the list of
300 if (rDateInfo
.mbAutoStart
)
301 rDateInfo
.mfStart
= rtl::math::approxFloor(fSourceMin
);
302 if (rDateInfo
.mbAutoEnd
)
303 rDateInfo
.mfEnd
= rtl::math::approxFloor(fSourceMax
) + 1;
305 //TODO: if not automatic, limit fSourceMin/fSourceMax for list of year values?
307 tools::Long nStart
= 0, nEnd
= 0; // end is inclusive
311 case sheet::DataPilotFieldGroupBy::YEARS
:
312 nStart
= ScDPUtil::getDatePartValue(
313 fSourceMin
, nullptr, sheet::DataPilotFieldGroupBy::YEARS
, pFormatter
);
314 nEnd
= ScDPUtil::getDatePartValue(fSourceMax
, nullptr, sheet::DataPilotFieldGroupBy::YEARS
, pFormatter
);
316 case sheet::DataPilotFieldGroupBy::QUARTERS
: nStart
= 1; nEnd
= 4; break;
317 case sheet::DataPilotFieldGroupBy::MONTHS
: nStart
= 1; nEnd
= 12; break;
318 case sheet::DataPilotFieldGroupBy::DAYS
: nStart
= 1; nEnd
= 366; break;
319 case sheet::DataPilotFieldGroupBy::HOURS
: nStart
= 0; nEnd
= 23; break;
320 case sheet::DataPilotFieldGroupBy::MINUTES
: nStart
= 0; nEnd
= 59; break;
321 case sheet::DataPilotFieldGroupBy::SECONDS
: nStart
= 0; nEnd
= 59; break;
323 OSL_FAIL("invalid date part");
326 // Now, populate the group items in the cache.
327 rCache
.ResetGroupItems(nGroupDim
, rDateInfo
, nDatePart
);
329 for (tools::Long nValue
= nStart
; nValue
<= nEnd
; ++nValue
)
330 rCache
.SetGroupItem(nGroupDim
, ScDPItemData(nDatePart
, nValue
));
332 // add first/last entry (min/max)
333 rCache
.SetGroupItem(nGroupDim
, ScDPItemData(nDatePart
, ScDPItemData::DateFirst
));
334 rCache
.SetGroupItem(nGroupDim
, ScDPItemData(nDatePart
, ScDPItemData::DateLast
));
339 void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData
& rData
) const
341 tools::Long nSourceIndex
= rData
.GetDimensionIndex( aSourceDim
);
342 if ( nSourceIndex
< 0 )
345 ScDPGroupDimension
aDim( nSourceIndex
, aGroupDimName
);
350 aDim
.SetDateDimension();
354 // normal (manual) grouping
356 for (const auto& rGroup
: aGroups
)
357 rGroup
.AddToData(aDim
);
360 rData
.AddGroupDimension( aDim
);
363 void ScDPSaveGroupDimension::AddToCache(ScDPCache
& rCache
) const
365 tools::Long nSourceDim
= rCache
.GetDimensionIndex(aSourceDim
);
369 tools::Long nDim
= rCache
.AppendGroupField();
370 SvNumberFormatter
* pFormatter
= rCache
.GetDoc().GetFormatTable();
374 fillDateGroupDimension(rCache
, aDateInfo
, nSourceDim
, nDim
, nDatePart
, pFormatter
);
378 rCache
.ResetGroupItems(nDim
, aDateInfo
, 0);
379 for (const ScDPSaveGroupItem
& rGI
: aGroups
)
381 rGI
.ConvertElementsToItems(pFormatter
);
382 rCache
.SetGroupItem(nDim
, ScDPItemData(rGI
.GetGroupName()));
385 const ScDPCache::ScDPItemDataVec
& rItems
= rCache
.GetDimMemberValues(nSourceDim
);
386 for (const ScDPItemData
& rItem
: rItems
)
388 if (!IsInGroup(rItem
))
389 // Not in any group. Add as its own group.
390 rCache
.SetGroupItem(nDim
, rItem
);
394 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( OUString aName
, const ScDPNumGroupInfo
& rInfo
) :
395 aDimensionName(std::move( aName
)),
401 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( OUString aName
, const ScDPNumGroupInfo
& rDateInfo
, sal_Int32 nPart
) :
402 aDimensionName(std::move( aName
)),
403 aDateInfo( rDateInfo
),
408 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData
& rData
) const
410 tools::Long nSource
= rData
.GetDimensionIndex( aDimensionName
);
413 ScDPNumGroupDimension
aDim( aGroupInfo
); // aGroupInfo: value grouping
415 aDim
.SetDateDimension();
417 rData
.SetNumGroupDimension( nSource
, aDim
);
421 void ScDPSaveNumGroupDimension::AddToCache(ScDPCache
& rCache
) const
423 tools::Long nDim
= rCache
.GetDimensionIndex(aDimensionName
);
427 if (aDateInfo
.mbEnable
)
430 SvNumberFormatter
* pFormatter
= rCache
.GetDoc().GetFormatTable();
431 fillDateGroupDimension(rCache
, aDateInfo
, nDim
, nDim
, nDatePart
, pFormatter
);
433 else if (aGroupInfo
.mbEnable
)
435 // Number-range grouping
437 // Look through the source entries for non-integer numbers, minimum
440 // non-integer GroupInfo values count, too
441 aGroupInfo
.mbIntegerOnly
=
442 (aGroupInfo
.mbAutoStart
|| isInteger(aGroupInfo
.mfStart
)) &&
443 (aGroupInfo
.mbAutoEnd
|| isInteger(aGroupInfo
.mfEnd
)) &&
444 isInteger(aGroupInfo
.mfStep
);
446 double fSourceMin
= 0.0;
447 double fSourceMax
= 0.0;
450 const ScDPCache::ScDPItemDataVec
& rItems
= rCache
.GetDimMemberValues(nDim
);
451 for (const ScDPItemData
& rItem
: rItems
)
453 if (rItem
.GetType() != ScDPItemData::Value
)
456 double fValue
= rItem
.GetValue();
459 fSourceMin
= fSourceMax
= fValue
;
464 if (fValue
< fSourceMin
)
466 if (fValue
> fSourceMax
)
469 if (aGroupInfo
.mbIntegerOnly
&& !isInteger(fValue
))
471 // If any non-integer numbers are involved, the group labels
472 // are shown including their upper limit.
473 aGroupInfo
.mbIntegerOnly
= false;
477 if (aGroupInfo
.mbDateValues
)
479 // special handling for dates: always integer, round down limits
480 aGroupInfo
.mbIntegerOnly
= true;
481 fSourceMin
= rtl::math::approxFloor(fSourceMin
);
482 fSourceMax
= rtl::math::approxFloor(fSourceMax
) + 1;
485 if (aGroupInfo
.mbAutoStart
)
486 aGroupInfo
.mfStart
= fSourceMin
;
487 if (aGroupInfo
.mbAutoEnd
)
488 aGroupInfo
.mfEnd
= fSourceMax
;
490 //TODO: limit number of entries?
492 tools::Long nLoopCount
= 0;
493 double fLoop
= aGroupInfo
.mfStart
;
495 rCache
.ResetGroupItems(nDim
, aGroupInfo
, 0);
497 // Use "less than" instead of "less or equal" for the loop - don't
498 // create a group that consists only of the end value. Instead, the
499 // end value is then included in the last group (last group is bigger
500 // than the others). The first group has to be created nonetheless.
501 // GetNumGroupForValue has corresponding logic.
503 bool bFirstGroup
= true;
504 while (bFirstGroup
|| (fLoop
< aGroupInfo
.mfEnd
&& !rtl::math::approxEqual(fLoop
, aGroupInfo
.mfEnd
)))
507 aItem
.SetRangeStart(fLoop
);
508 rCache
.SetGroupItem(nDim
, aItem
);
510 fLoop
= aGroupInfo
.mfStart
+ nLoopCount
* aGroupInfo
.mfStep
;
513 // ScDPItemData values are compared with approxEqual
517 aItem
.SetRangeFirst();
518 rCache
.SetGroupItem(nDim
, aItem
);
520 aItem
.SetRangeLast();
521 rCache
.SetGroupItem(nDim
, aItem
);
525 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo
& rNew
)
530 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo
& rInfo
, sal_Int32 nPart
)
538 struct ScDPSaveGroupDimNameFunc
541 explicit ScDPSaveGroupDimNameFunc( OUString aDimName
) : maDimName(std::move( aDimName
)) {}
542 bool operator()( const ScDPSaveGroupDimension
& rGroupDim
) const { return rGroupDim
.GetGroupDimName() == maDimName
; }
545 struct ScDPSaveGroupSourceNameFunc
547 OUString maSrcDimName
;
548 explicit ScDPSaveGroupSourceNameFunc( OUString aSrcDimName
) : maSrcDimName(std::move( aSrcDimName
)) {}
549 bool operator()( const ScDPSaveGroupDimension
& rGroupDim
) const { return rGroupDim
.GetSourceDimName() == maSrcDimName
; }
554 ScDPDimensionSaveData::ScDPDimensionSaveData()
558 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData
& ) const
563 void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension
& rGroupDim
)
565 OSL_ENSURE( ::std::none_of( maGroupDims
.begin(), maGroupDims
.end(), ScDPSaveGroupDimNameFunc( rGroupDim
.GetGroupDimName() ) ),
566 "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
567 // ReplaceGroupDimension() adds new or replaces existing
568 ReplaceGroupDimension( rGroupDim
);
571 void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension
& rGroupDim
)
573 ScDPSaveGroupDimVec::iterator aIt
= ::std::find_if(
574 maGroupDims
.begin(), maGroupDims
.end(), ScDPSaveGroupDimNameFunc( rGroupDim
.GetGroupDimName() ) );
575 if( aIt
== maGroupDims
.end() )
576 maGroupDims
.push_back( rGroupDim
);
581 void ScDPDimensionSaveData::RemoveGroupDimension( const OUString
& rGroupDimName
)
583 ScDPSaveGroupDimVec::iterator aIt
= ::std::find_if(
584 maGroupDims
.begin(), maGroupDims
.end(), ScDPSaveGroupDimNameFunc( rGroupDimName
) );
585 if( aIt
!= maGroupDims
.end() )
586 maGroupDims
.erase( aIt
);
589 void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension
& rGroupDim
)
591 OSL_ENSURE( maNumGroupDims
.count( rGroupDim
.GetDimensionName() ) == 0,
592 "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
593 // ReplaceNumGroupDimension() adds new or replaces existing
594 ReplaceNumGroupDimension( rGroupDim
);
597 void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension
& rGroupDim
)
599 ScDPSaveNumGroupDimMap::iterator aIt
= maNumGroupDims
.find( rGroupDim
.GetDimensionName() );
600 if( aIt
== maNumGroupDims
.end() )
601 maNumGroupDims
.emplace( rGroupDim
.GetDimensionName(), rGroupDim
);
603 aIt
->second
= rGroupDim
;
606 void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString
& rGroupDimName
)
608 maNumGroupDims
.erase( rGroupDimName
);
611 void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData
& rData
) const
613 // rData is assumed to be empty
614 // AddToData also handles date grouping
616 for( const auto& rGroupDim
: maGroupDims
)
617 rGroupDim
.AddToData( rData
);
619 for( const auto& rEntry
: maNumGroupDims
)
620 rEntry
.second
.AddToData( rData
);
623 void ScDPDimensionSaveData::WriteToCache(ScDPCache
& rCache
) const
625 for (const auto& rEntry
: maGroupDims
)
626 rEntry
.AddToCache(rCache
);
627 for (const auto& rEntry
: maNumGroupDims
)
628 rEntry
.second
.AddToCache(rCache
);
631 const ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetGroupDimForBase( const OUString
& rBaseDimName
) const
633 return const_cast< ScDPDimensionSaveData
* >( this )->GetGroupDimAccForBase( rBaseDimName
);
636 const ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetNamedGroupDim( const OUString
& rGroupDimName
) const
638 return const_cast< ScDPDimensionSaveData
* >( this )->GetNamedGroupDimAcc( rGroupDimName
);
641 const ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetFirstNamedGroupDim( const OUString
& rBaseDimName
) const
643 return const_cast< ScDPDimensionSaveData
* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName
);
646 const ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetNextNamedGroupDim( const OUString
& rGroupDimName
) const
648 return const_cast< ScDPDimensionSaveData
* >( this )->GetNextNamedGroupDimAcc( rGroupDimName
);
651 const ScDPSaveNumGroupDimension
* ScDPDimensionSaveData::GetNumGroupDim( const OUString
& rGroupDimName
) const
653 return const_cast< ScDPDimensionSaveData
* >( this )->GetNumGroupDimAcc( rGroupDimName
);
656 ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetGroupDimAccForBase( const OUString
& rBaseDimName
)
658 ScDPSaveGroupDimension
* pGroupDim
= GetFirstNamedGroupDimAcc( rBaseDimName
);
659 return pGroupDim
? pGroupDim
: GetNextNamedGroupDimAcc( rBaseDimName
);
662 ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetNamedGroupDimAcc( const OUString
& rGroupDimName
)
664 ScDPSaveGroupDimVec::iterator aIt
= ::std::find_if(
665 maGroupDims
.begin(), maGroupDims
.end(), ScDPSaveGroupDimNameFunc( rGroupDimName
) );
666 return (aIt
== maGroupDims
.end()) ? nullptr : &*aIt
;
669 ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const OUString
& rBaseDimName
)
671 ScDPSaveGroupDimVec::iterator aIt
= ::std::find_if(
672 maGroupDims
.begin(), maGroupDims
.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName
) );
673 return (aIt
== maGroupDims
.end()) ? nullptr : &*aIt
;
676 ScDPSaveGroupDimension
* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const OUString
& rGroupDimName
)
678 // find the group dimension with the passed name
679 ScDPSaveGroupDimVec::iterator aIt
= ::std::find_if(
680 maGroupDims
.begin(), maGroupDims
.end(), ScDPSaveGroupDimNameFunc( rGroupDimName
) );
681 // find next group dimension based on the same source dimension name
682 if( aIt
!= maGroupDims
.end() )
683 aIt
= ::std::find_if( aIt
+ 1, maGroupDims
.end(), ScDPSaveGroupSourceNameFunc( aIt
->GetSourceDimName() ) );
684 return (aIt
== maGroupDims
.end()) ? nullptr : &*aIt
;
687 ScDPSaveNumGroupDimension
* ScDPDimensionSaveData::GetNumGroupDimAcc( const OUString
& rGroupDimName
)
689 ScDPSaveNumGroupDimMap::iterator aIt
= maNumGroupDims
.find( rGroupDimName
);
690 return (aIt
== maNumGroupDims
.end()) ? nullptr : &aIt
->second
;
693 bool ScDPDimensionSaveData::HasGroupDimensions() const
695 return !maGroupDims
.empty() || !maNumGroupDims
.empty();
698 sal_Int32
ScDPDimensionSaveData::CollectDateParts( const OUString
& rBaseDimName
) const
700 sal_Int32 nParts
= 0;
701 // start with part of numeric group
702 if( const ScDPSaveNumGroupDimension
* pNumDim
= GetNumGroupDim( rBaseDimName
) )
703 nParts
|= pNumDim
->GetDatePart();
704 // collect parts from all matching group dimensions
705 for( const ScDPSaveGroupDimension
* pGroupDim
= GetFirstNamedGroupDim( rBaseDimName
); pGroupDim
; pGroupDim
= GetNextNamedGroupDim( pGroupDim
->GetGroupDimName() ) )
706 nParts
|= pGroupDim
->GetDatePart();
711 OUString
ScDPDimensionSaveData::CreateGroupDimName(
712 const OUString
& rSourceName
, const ScDPObject
& rObject
, bool bAllowSource
,
713 const std::vector
<OUString
>* pDeletedNames
)
715 // create a name for the new dimension by appending a number to the original
718 bool bUseSource
= bAllowSource
; // if set, try the unchanged original name first
720 sal_Int32 nAdd
= 2; // first try is "Name2"
721 const sal_Int32 nMaxAdd
= 1000; // limit the loop
722 while ( nAdd
<= nMaxAdd
)
724 OUString
aDimName( rSourceName
);
726 aDimName
+= OUString::number(nAdd
);
728 // look for existing group dimensions
729 bool bExists
= std::any_of(maGroupDims
.begin(), maGroupDims
.end(),
730 [&aDimName
](const ScDPSaveGroupDimension
& rDim
) {
731 return rDim
.GetGroupDimName() == aDimName
; //TODO: ignore case
734 // look for base dimensions that happen to have that name
735 if ( !bExists
&& rObject
.IsDimNameInUse( aDimName
) )
737 if ( pDeletedNames
&&
738 std::find( pDeletedNames
->begin(), pDeletedNames
->end(), aDimName
) != pDeletedNames
->end() )
740 // allow the name anyway if the name is in pDeletedNames
747 return aDimName
; // found a new name
752 ++nAdd
; // continue with higher number
754 OSL_FAIL("CreateGroupDimName: no valid name found");
760 const TranslateId aDatePartIds
[] =
762 STR_DPFIELD_GROUP_BY_SECONDS
,
763 STR_DPFIELD_GROUP_BY_MINUTES
,
764 STR_DPFIELD_GROUP_BY_HOURS
,
765 STR_DPFIELD_GROUP_BY_DAYS
,
766 STR_DPFIELD_GROUP_BY_MONTHS
,
767 STR_DPFIELD_GROUP_BY_QUARTERS
,
768 STR_DPFIELD_GROUP_BY_YEARS
772 OUString
ScDPDimensionSaveData::CreateDateGroupDimName(
773 sal_Int32 nDatePart
, const ScDPObject
& rObject
, bool bAllowSource
,
774 const std::vector
<OUString
>* pDeletedNames
)
776 using namespace css::sheet::DataPilotFieldGroupBy
;
780 case SECONDS
: aPartName
= ScResId(aDatePartIds
[0]); break;
781 case MINUTES
: aPartName
= ScResId(aDatePartIds
[1]); break;
782 case HOURS
: aPartName
= ScResId(aDatePartIds
[2]); break;
783 case DAYS
: aPartName
= ScResId(aDatePartIds
[3]); break;
784 case MONTHS
: aPartName
= ScResId(aDatePartIds
[4]); break;
785 case QUARTERS
: aPartName
= ScResId(aDatePartIds
[5]); break;
786 case YEARS
: aPartName
= ScResId(aDatePartIds
[6]); break;
788 OSL_ENSURE(!aPartName
.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
789 return CreateGroupDimName( aPartName
, rObject
, bAllowSource
, pDeletedNames
);
792 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */