tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / data / dpdimsave.cxx
blob63811dc1f713bcee03b6b2c2e40c60aa7af26d4b
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 <dpcache.hxx>
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/numformat.hxx>
30 #include <osl/diagnose.h>
31 #include <rtl/math.hxx>
32 #include <algorithm>
34 #include <globstr.hrc>
35 #include <scresid.hxx>
36 #include <utility>
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())
61 aElements.erase(it);
62 return true;
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;
102 double fValue;
103 ScDPItemData aData;
104 if (pFormatter->IsNumberFormat(rElement, nFormat, fValue))
105 aData.SetValue(fValue);
106 else
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 )),
130 nDatePart( 0 )
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 ),
138 nDatePart( nPart )
142 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
144 aDateInfo = rInfo;
145 nDatePart = 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
172 if ( !bExists )
173 return aGroupName; // found a new name
175 ++nAdd; // continue with higher number
178 OSL_FAIL("CreateGroupName: no valid name found");
179 return OUString();
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())
194 return &*aIter;
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); });
259 namespace {
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
271 // needed.
272 double fSourceMin = 0.0;
273 double fSourceMax = 0.0;
274 bool bFirst = true;
276 const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nSourceDim);
277 for (const ScDPItemData& rItem : rItems)
279 if (rItem.GetType() != ScDPItemData::Value)
280 continue;
282 double fVal = rItem.GetValue();
283 if (bFirst)
285 fSourceMin = fSourceMax = fVal;
286 bFirst = false;
288 else
290 if (fVal < fSourceMin)
291 fSourceMin = fVal;
292 if ( fVal > fSourceMax )
293 fSourceMax = fVal;
297 // For the start/end values, use the same date rounding as in
298 // ScDPNumGroupDimension::GetNumEntries (but not for the list of
299 // available years).
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
309 switch (nDatePart)
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);
315 break;
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;
322 default:
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 )
343 return;
345 ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
346 if ( nDatePart )
348 // date grouping
350 aDim.SetDateDimension();
352 else
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);
366 if (nSourceDim < 0)
367 return;
369 tools::Long nDim = rCache.AppendGroupField();
370 SvNumberFormatter* pFormatter = rCache.GetDoc().GetFormatTable();
372 if (nDatePart)
374 fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
375 return;
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 )),
396 aGroupInfo( rInfo ),
397 nDatePart( 0 )
401 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( OUString aName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
402 aDimensionName(std::move( aName )),
403 aDateInfo( rDateInfo ),
404 nDatePart( nPart )
408 void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
410 tools::Long nSource = rData.GetDimensionIndex( aDimensionName );
411 if ( nSource >= 0 )
413 ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
414 if ( nDatePart )
415 aDim.SetDateDimension();
417 rData.SetNumGroupDimension( nSource, aDim );
421 void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
423 tools::Long nDim = rCache.GetDimensionIndex(aDimensionName);
424 if (nDim < 0)
425 return;
427 if (aDateInfo.mbEnable)
429 // Date grouping
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
438 // and maximum.
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;
448 bool bFirst = true;
450 const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nDim);
451 for (const ScDPItemData& rItem : rItems)
453 if (rItem.GetType() != ScDPItemData::Value)
454 continue;
456 double fValue = rItem.GetValue();
457 if (bFirst)
459 fSourceMin = fSourceMax = fValue;
460 bFirst = false;
461 continue;
464 if (fValue < fSourceMin)
465 fSourceMin = fValue;
466 if (fValue > fSourceMax)
467 fSourceMax = fValue;
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)))
506 ScDPItemData aItem;
507 aItem.SetRangeStart(fLoop);
508 rCache.SetGroupItem(nDim, aItem);
509 ++nLoopCount;
510 fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
511 bFirstGroup = false;
513 // ScDPItemData values are compared with approxEqual
516 ScDPItemData aItem;
517 aItem.SetRangeFirst();
518 rCache.SetGroupItem(nDim, aItem);
520 aItem.SetRangeLast();
521 rCache.SetGroupItem(nDim, aItem);
525 void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
527 aGroupInfo = rNew;
530 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
532 aDateInfo = rInfo;
533 nDatePart = nPart;
536 namespace {
538 struct ScDPSaveGroupDimNameFunc
540 OUString maDimName;
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; }
552 } // namespace
554 ScDPDimensionSaveData::ScDPDimensionSaveData()
558 bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
560 return false;
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 );
577 else
578 *aIt = 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 );
602 else
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();
708 return nParts;
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
716 // dimension's name
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 );
725 if ( !bUseSource )
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
742 else
743 bExists = true;
746 if ( !bExists )
747 return aDimName; // found a new name
749 if ( bUseSource )
750 bUseSource = false;
751 else
752 ++nAdd; // continue with higher number
754 OSL_FAIL("CreateGroupDimName: no valid name found");
755 return OUString();
758 namespace
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;
777 OUString aPartName;
778 switch( nDatePart )
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: */