LibreOffice Module sc (master)  1
dpdimsave.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <dpcache.hxx>
21 #include <dpdimsave.hxx>
22 #include <dpgroup.hxx>
23 #include <dpobject.hxx>
24 #include <dputil.hxx>
25 #include <document.hxx>
26 
27 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
28 
29 #include <svl/numformat.hxx>
30 #include <osl/diagnose.h>
31 #include <rtl/math.hxx>
32 #include <algorithm>
33 
34 #include <globstr.hrc>
35 #include <scresid.hxx>
36 
37 using namespace com::sun::star;
38 
39 ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
40  aGroupName(rName) {}
41 
43 
44 void ScDPSaveGroupItem::AddElement( const OUString& rName )
45 {
46  aElements.push_back(rName);
47 }
48 
50 {
51  // add all elements of the other group (used for nested grouping)
52  aElements.insert( aElements.end(), rGroup.aElements.begin(), rGroup.aElements.end() );
53 }
54 
55 bool ScDPSaveGroupItem::RemoveElement( const OUString& rName )
56 {
57  auto it = std::find(aElements.begin(), aElements.end(), rName); //TODO: ignore case
58  if (it != aElements.end())
59  {
60  aElements.erase(it);
61  return true;
62  }
63  return false; // not found
64 }
65 
67 {
68  return aElements.empty();
69 }
70 
72 {
73  return aElements.size();
74 }
75 
76 const OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
77 {
78  return (nIndex < aElements.size()) ? &aElements[ nIndex ] : nullptr;
79 }
80 
81 void ScDPSaveGroupItem::Rename( const OUString& rNewName )
82 {
83  aGroupName = rNewName;
84 }
85 
87 {
88  // remove this group's elements from their groups in rDimension
89  // (rDimension must be a different dimension from the one which contains this)
90 
91  for ( const auto& rElement : aElements )
92  rDimension.RemoveFromGroups( rElement );
93 }
94 
96 {
97  maItems.reserve(aElements.size());
98  for (const auto& rElement : aElements)
99  {
100  sal_uInt32 nFormat = 0;
101  double fValue;
103  if (pFormatter->IsNumberFormat(rElement, nFormat, fValue))
104  aData.SetValue(fValue);
105  else
106  aData.SetString(rElement);
107 
108  maItems.push_back(aData);
109  }
110 }
111 
113 {
114  return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
115 }
116 
118 {
119  ScDPGroupItem aGroup(aGroupName);
120  for (const auto& rItem : maItems)
121  aGroup.AddElement(rItem);
122 
123  rDataDim.AddItem(aGroup);
124 }
125 
126 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
127  aSourceDim( rSource ),
128  aGroupDimName( rName ),
129  nDatePart( 0 )
130 {
131 }
132 
133 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
134  aSourceDim( rSource ),
135  aGroupDimName( rName ),
136  aDateInfo( rDateInfo ),
137  nDatePart( nPart )
138 {
139 }
140 
141 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
142 {
143  aDateInfo = rInfo;
144  nDatePart = nPart;
145 }
146 
148 {
149  aGroups.push_back( rItem );
150 }
151 
152 OUString ScDPSaveGroupDimension::CreateGroupName(std::u16string_view rPrefix)
153 {
154  // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
155 
156  //TODO: look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
157  //TODO: (only dimensions for the same base)
158 
159  sal_Int32 nAdd = 1; // first try is "Group1"
160  const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
161  while ( nAdd <= nMaxAdd )
162  {
163  OUString aGroupName = rPrefix + OUString::number( nAdd );
164 
165  // look for existing groups
166  bool bExists = std::any_of(aGroups.begin(), aGroups.end(),
167  [&aGroupName](const ScDPSaveGroupItem& rGroup) {
168  return rGroup.GetGroupName() == aGroupName; //TODO: ignore case
169  });
170 
171  if ( !bExists )
172  return aGroupName; // found a new name
173 
174  ++nAdd; // continue with higher number
175  }
176 
177  OSL_FAIL("CreateGroupName: no valid name found");
178  return OUString();
179 }
180 
181 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const OUString& rGroupName ) const
182 {
183  return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
184 }
185 
187 {
188  auto aIter = std::find_if(aGroups.begin(), aGroups.end(),
189  [&rGroupName](const ScDPSaveGroupItem& rGroup) {
190  return rGroup.GetGroupName() == rGroupName; //TODO: ignore case
191  });
192  if (aIter != aGroups.end())
193  return &*aIter;
194 
195  return nullptr; // none found
196 }
197 
199 {
200  return aGroups.size();
201 }
202 
204 {
205  return aGroups[nIndex];
206 }
207 
208 
209 void ScDPSaveGroupDimension::RemoveFromGroups( const OUString& rItemName )
210 {
211  // if the item is in any group, remove it from the group,
212  // also remove the group if it is empty afterwards
213 
214  for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
215  if ( aIter->RemoveElement( rItemName ) )
216  {
217  if ( aIter->IsEmpty() ) // removed last item from the group?
218  aGroups.erase( aIter ); // then remove the group
219 
220  return; // don't have to look further
221  }
222 }
223 
224 void ScDPSaveGroupDimension::RemoveGroup(const OUString& rGroupName)
225 {
226  auto aIter = std::find_if(aGroups.begin(), aGroups.end(),
227  [&rGroupName](const ScDPSaveGroupItem& rGroup) {
228  return rGroup.GetGroupName() == rGroupName; //TODO: ignore case
229  });
230  if (aIter != aGroups.end())
231  aGroups.erase( aIter );
232 }
233 
235 {
236  return aGroups.empty();
237 }
238 
240 {
241  // check if there are only groups that don't appear in the list of visible names
242 
243  return std::none_of(aGroups.begin(), aGroups.end(),
244  [&rVisible](const ScDPSaveGroupItem& rGroup) { return rVisible.count(rGroup.GetGroupName()) > 0; });
245 }
246 
247 void ScDPSaveGroupDimension::Rename( const OUString& rNewName )
248 {
249  aGroupDimName = rNewName;
250 }
251 
253 {
254  return std::any_of(aGroups.begin(), aGroups.end(),
255  [&rItem](const ScDPSaveGroupItem& rGroup) { return rGroup.HasInGroup(rItem); });
256 }
257 
258 namespace {
259 
260 bool isInteger(double fValue)
261 {
262  return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
263 }
264 
265 void fillDateGroupDimension(
266  ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, tools::Long nSourceDim, tools::Long nGroupDim,
267  sal_Int32 nDatePart, const SvNumberFormatter* pFormatter)
268 {
269  // Auto min/max is only used for "Years" part, but the loop is always
270  // needed.
271  double fSourceMin = 0.0;
272  double fSourceMax = 0.0;
273  bool bFirst = true;
274 
275  const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nSourceDim);
276  for (const ScDPItemData& rItem : rItems)
277  {
278  if (rItem.GetType() != ScDPItemData::Value)
279  continue;
280 
281  double fVal = rItem.GetValue();
282  if (bFirst)
283  {
284  fSourceMin = fSourceMax = fVal;
285  bFirst = false;
286  }
287  else
288  {
289  if (fVal < fSourceMin)
290  fSourceMin = fVal;
291  if ( fVal > fSourceMax )
292  fSourceMax = fVal;
293  }
294  }
295 
296  // For the start/end values, use the same date rounding as in
297  // ScDPNumGroupDimension::GetNumEntries (but not for the list of
298  // available years).
299  if (rDateInfo.mbAutoStart)
300  rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
301  if (rDateInfo.mbAutoEnd)
302  rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
303 
304  //TODO: if not automatic, limit fSourceMin/fSourceMax for list of year values?
305 
306  tools::Long nStart = 0, nEnd = 0; // end is inclusive
307 
308  switch (nDatePart)
309  {
310  case sheet::DataPilotFieldGroupBy::YEARS:
312  fSourceMin, nullptr, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
313  nEnd = ScDPUtil::getDatePartValue(fSourceMax, nullptr, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
314  break;
315  case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break;
316  case sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break;
317  case sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break;
318  case sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break;
319  case sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break;
320  case sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break;
321  default:
322  OSL_FAIL("invalid date part");
323  }
324 
325  // Now, populate the group items in the cache.
326  rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
327 
328  for (tools::Long nValue = nStart; nValue <= nEnd; ++nValue)
329  rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
330 
331  // add first/last entry (min/max)
332  rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
333  rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
334 }
335 
336 }
337 
339 {
340  tools::Long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
341  if ( nSourceIndex < 0 )
342  return;
343 
344  ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
345  if ( nDatePart )
346  {
347  // date grouping
348 
349  aDim.SetDateDimension();
350  }
351  else
352  {
353  // normal (manual) grouping
354 
355  for (const auto& rGroup : aGroups)
356  rGroup.AddToData(aDim);
357  }
358 
359  rData.AddGroupDimension( aDim );
360 }
361 
363 {
364  tools::Long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
365  if (nSourceDim < 0)
366  return;
367 
368  tools::Long nDim = rCache.AppendGroupField();
369  SvNumberFormatter* pFormatter = rCache.GetDoc().GetFormatTable();
370 
371  if (nDatePart)
372  {
373  fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
374  return;
375  }
376 
377  rCache.ResetGroupItems(nDim, aDateInfo, 0);
378  for (const ScDPSaveGroupItem& rGI : aGroups)
379  {
380  rGI.ConvertElementsToItems(pFormatter);
381  rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
382  }
383 
384  const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nSourceDim);
385  for (const ScDPItemData& rItem : rItems)
386  {
387  if (!IsInGroup(rItem))
388  // Not in any group. Add as its own group.
389  rCache.SetGroupItem(nDim, rItem);
390  }
391 }
392 
394  aDimensionName( rName ),
395  aGroupInfo( rInfo ),
396  nDatePart( 0 )
397 {
398 }
399 
400 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
401  aDimensionName( rName ),
402  aDateInfo( rDateInfo ),
403  nDatePart( nPart )
404 {
405 }
406 
408 {
409  tools::Long nSource = rData.GetDimensionIndex( aDimensionName );
410  if ( nSource >= 0 )
411  {
412  ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
413  if ( nDatePart )
414  aDim.SetDateDimension();
415 
416  rData.SetNumGroupDimension( nSource, aDim );
417  }
418 }
419 
421 {
423  if (nDim < 0)
424  return;
425 
426  if (aDateInfo.mbEnable)
427  {
428  // Date grouping
429  SvNumberFormatter* pFormatter = rCache.GetDoc().GetFormatTable();
430  fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
431  }
432  else if (aGroupInfo.mbEnable)
433  {
434  // Number-range grouping
435 
436  // Look through the source entries for non-integer numbers, minimum
437  // and maximum.
438 
439  // non-integer GroupInfo values count, too
441  (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
442  (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
443  isInteger(aGroupInfo.mfStep);
444 
445  double fSourceMin = 0.0;
446  double fSourceMax = 0.0;
447  bool bFirst = true;
448 
449  const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nDim);
450  for (const ScDPItemData& rItem : rItems)
451  {
452  if (rItem.GetType() != ScDPItemData::Value)
453  continue;
454 
455  double fValue = rItem.GetValue();
456  if (bFirst)
457  {
458  fSourceMin = fSourceMax = fValue;
459  bFirst = false;
460  continue;
461  }
462 
463  if (fValue < fSourceMin)
464  fSourceMin = fValue;
465  if (fValue > fSourceMax)
466  fSourceMax = fValue;
467 
468  if (aGroupInfo.mbIntegerOnly && !isInteger(fValue))
469  {
470  // If any non-integer numbers are involved, the group labels
471  // are shown including their upper limit.
472  aGroupInfo.mbIntegerOnly = false;
473  }
474  }
475 
477  {
478  // special handling for dates: always integer, round down limits
479  aGroupInfo.mbIntegerOnly = true;
480  fSourceMin = rtl::math::approxFloor(fSourceMin);
481  fSourceMax = rtl::math::approxFloor(fSourceMax) + 1;
482  }
483 
485  aGroupInfo.mfStart = fSourceMin;
486  if (aGroupInfo.mbAutoEnd)
487  aGroupInfo.mfEnd = fSourceMax;
488 
489  //TODO: limit number of entries?
490 
491  tools::Long nLoopCount = 0;
492  double fLoop = aGroupInfo.mfStart;
493 
494  rCache.ResetGroupItems(nDim, aGroupInfo, 0);
495 
496  // Use "less than" instead of "less or equal" for the loop - don't
497  // create a group that consists only of the end value. Instead, the
498  // end value is then included in the last group (last group is bigger
499  // than the others). The first group has to be created nonetheless.
500  // GetNumGroupForValue has corresponding logic.
501 
502  bool bFirstGroup = true;
503  while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
504  {
505  ScDPItemData aItem;
506  aItem.SetRangeStart(fLoop);
507  rCache.SetGroupItem(nDim, aItem);
508  ++nLoopCount;
509  fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
510  bFirstGroup = false;
511 
512  // ScDPItemData values are compared with approxEqual
513  }
514 
515  ScDPItemData aItem;
516  aItem.SetRangeFirst();
517  rCache.SetGroupItem(nDim, aItem);
518 
519  aItem.SetRangeLast();
520  rCache.SetGroupItem(nDim, aItem);
521  }
522 }
523 
525 {
526  aGroupInfo = rNew;
527 }
528 
529 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
530 {
531  aDateInfo = rInfo;
532  nDatePart = nPart;
533 }
534 
535 namespace {
536 
537 struct ScDPSaveGroupDimNameFunc
538 {
539  OUString maDimName;
540  explicit ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
541  bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
542 };
543 
544 struct ScDPSaveGroupSourceNameFunc
545 {
546  OUString maSrcDimName;
547  explicit ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
548  bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
549 };
550 
551 } // namespace
552 
554 {
555 }
556 
558 {
559  return false;
560 }
561 
563 {
564  OSL_ENSURE( ::std::none_of( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ),
565  "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
566  // ReplaceGroupDimension() adds new or replaces existing
567  ReplaceGroupDimension( rGroupDim );
568 }
569 
571 {
572  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
573  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
574  if( aIt == maGroupDims.end() )
575  maGroupDims.push_back( rGroupDim );
576  else
577  *aIt = rGroupDim;
578 }
579 
580 void ScDPDimensionSaveData::RemoveGroupDimension( const OUString& rGroupDimName )
581 {
582  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
583  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
584  if( aIt != maGroupDims.end() )
585  maGroupDims.erase( aIt );
586 }
587 
589 {
590  OSL_ENSURE( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
591  "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
592  // ReplaceNumGroupDimension() adds new or replaces existing
593  ReplaceNumGroupDimension( rGroupDim );
594 }
595 
597 {
598  ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
599  if( aIt == maNumGroupDims.end() )
600  maNumGroupDims.emplace( rGroupDim.GetDimensionName(), rGroupDim );
601  else
602  aIt->second = rGroupDim;
603 }
604 
605 void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString& rGroupDimName )
606 {
607  maNumGroupDims.erase( rGroupDimName );
608 }
609 
611 {
612  // rData is assumed to be empty
613  // AddToData also handles date grouping
614 
615  for( const auto& rGroupDim : maGroupDims )
616  rGroupDim.AddToData( rData );
617 
618  for( const auto& rEntry : maNumGroupDims )
619  rEntry.second.AddToData( rData );
620 }
621 
623 {
624  for (const auto& rEntry : maGroupDims)
625  rEntry.AddToCache(rCache);
626  for (const auto& rEntry : maNumGroupDims)
627  rEntry.second.AddToCache(rCache);
628 }
629 
630 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const OUString& rBaseDimName ) const
631 {
632  return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
633 }
634 
635 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const OUString& rGroupDimName ) const
636 {
637  return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
638 }
639 
640 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const OUString& rBaseDimName ) const
641 {
642  return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
643 }
644 
645 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const OUString& rGroupDimName ) const
646 {
647  return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
648 }
649 
650 const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const OUString& rGroupDimName ) const
651 {
652  return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
653 }
654 
656 {
657  ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
658  return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
659 }
660 
662 {
663  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
664  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
665  return (aIt == maGroupDims.end()) ? nullptr : &*aIt;
666 }
667 
669 {
670  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
671  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
672  return (aIt == maGroupDims.end()) ? nullptr : &*aIt;
673 }
674 
676 {
677  // find the group dimension with the passed name
678  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
679  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
680  // find next group dimension based on the same source dimension name
681  if( aIt != maGroupDims.end() )
682  aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
683  return (aIt == maGroupDims.end()) ? nullptr : &*aIt;
684 }
685 
687 {
688  ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
689  return (aIt == maNumGroupDims.end()) ? nullptr : &aIt->second;
690 }
691 
693 {
694  return !maGroupDims.empty() || !maNumGroupDims.empty();
695 }
696 
697 sal_Int32 ScDPDimensionSaveData::CollectDateParts( const OUString& rBaseDimName ) const
698 {
699  sal_Int32 nParts = 0;
700  // start with part of numeric group
701  if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
702  nParts |= pNumDim->GetDatePart();
703  // collect parts from all matching group dimensions
704  for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
705  nParts |= pGroupDim->GetDatePart();
706 
707  return nParts;
708 }
709 
711  const OUString& rSourceName, const ScDPObject& rObject, bool bAllowSource,
712  const std::vector<OUString>* pDeletedNames )
713 {
714  // create a name for the new dimension by appending a number to the original
715  // dimension's name
716 
717  bool bUseSource = bAllowSource; // if set, try the unchanged original name first
718 
719  sal_Int32 nAdd = 2; // first try is "Name2"
720  const sal_Int32 nMaxAdd = 1000; // limit the loop
721  while ( nAdd <= nMaxAdd )
722  {
723  OUString aDimName( rSourceName );
724  if ( !bUseSource )
725  aDimName += OUString::number(nAdd);
726 
727  // look for existing group dimensions
728  bool bExists = std::any_of(maGroupDims.begin(), maGroupDims.end(),
729  [&aDimName](const ScDPSaveGroupDimension& rDim) {
730  return rDim.GetGroupDimName() == aDimName; //TODO: ignore case
731  });
732 
733  // look for base dimensions that happen to have that name
734  if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
735  {
736  if ( pDeletedNames &&
737  std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
738  {
739  // allow the name anyway if the name is in pDeletedNames
740  }
741  else
742  bExists = true;
743  }
744 
745  if ( !bExists )
746  return aDimName; // found a new name
747 
748  if ( bUseSource )
749  bUseSource = false;
750  else
751  ++nAdd; // continue with higher number
752  }
753  OSL_FAIL("CreateGroupDimName: no valid name found");
754  return OUString();
755 }
756 
757 namespace
758 {
759  const TranslateId aDatePartIds[] =
760  {
761  STR_DPFIELD_GROUP_BY_SECONDS,
762  STR_DPFIELD_GROUP_BY_MINUTES,
763  STR_DPFIELD_GROUP_BY_HOURS,
764  STR_DPFIELD_GROUP_BY_DAYS,
765  STR_DPFIELD_GROUP_BY_MONTHS,
766  STR_DPFIELD_GROUP_BY_QUARTERS,
767  STR_DPFIELD_GROUP_BY_YEARS
768  };
769 }
770 
772  sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource,
773  const std::vector<OUString>* pDeletedNames )
774 {
775  using namespace css::sheet::DataPilotFieldGroupBy;
776  OUString aPartName;
777  switch( nDatePart )
778  {
779  case SECONDS: aPartName = ScResId(aDatePartIds[0]); break;
780  case MINUTES: aPartName = ScResId(aDatePartIds[1]); break;
781  case HOURS: aPartName = ScResId(aDatePartIds[2]); break;
782  case DAYS: aPartName = ScResId(aDatePartIds[3]); break;
783  case MONTHS: aPartName = ScResId(aDatePartIds[4]); break;
784  case QUARTERS: aPartName = ScResId(aDatePartIds[5]); break;
785  case YEARS: aPartName = ScResId(aDatePartIds[6]); break;
786  }
787  OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
788  return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
789 }
790 
791 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetValue(double fVal)
Definition: dpitemdata.cxx:153
const OUString & GetGroupDimName() const
Definition: dpdimsave.hxx:107
bool IsInGroup(const ScDPItemData &rItem) const
Definition: dpdimsave.cxx:252
bool IsDimNameInUse(std::u16string_view rName) const
Definition: dpobject.cxx:1173
void AddToData(ScDPGroupTableData &rData) const
Definition: dpdimsave.cxx:407
void ReplaceNumGroupDimension(const ScDPSaveNumGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:596
void SetRangeLast()
Definition: dpitemdata.cxx:174
This class has to do with handling exclusively grouped dimensions? TODO: Find out what this class doe...
Definition: dpdimsave.hxx:163
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
void Rename(const OUString &rNewName)
Definition: dpdimsave.cxx:81
void AddGroupDimension(const ScDPGroupDimension &rGroup)
Definition: dpgroup.cxx:480
bool HasGroupDimensions() const
Definition: dpdimsave.cxx:692
ScDPSaveGroupItemVec aGroups
Definition: dpdimsave.hxx:94
void AddNumGroupDimension(const ScDPSaveNumGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:588
bool RemoveElement(const OUString &rName)
Definition: dpdimsave.cxx:55
const ScDPSaveGroupDimension * GetGroupDimForBase(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:630
SCROW SetGroupItem(tools::Long nDim, const ScDPItemData &rData)
Definition: dpcache.cxx:1292
ScDocument & GetDoc() const
Definition: dpcache.cxx:883
ScDPSaveGroupItem(const OUString &rName)
Definition: dpdimsave.cxx:39
long Long
void AddGroupDimension(const ScDPSaveGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:562
Classes to save Data Pilot settings that create new dimensions (fields).
Definition: dpdimsave.hxx:46
void SetString(const OUString &rS)
Definition: dpitemdata.cxx:137
const OUString & GetSourceDimName() const
Definition: dpdimsave.hxx:108
void RemoveGroupDimension(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:580
void AddToData(ScDPGroupTableData &rData) const
Definition: dpdimsave.cxx:338
ScDPNumGroupInfo aDateInfo
Definition: dpdimsave.hxx:95
const ScDPItemDataVec & GetDimMemberValues(SCCOL nDim) const
Definition: dpcache.cxx:1050
void RemoveNumGroupDimension(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:605
This class represents the cached data part of the datapilot cache table implementation.
Definition: dpcache.hxx:47
std::vector< ScDPItemData > maItems
items converted from the strings.
Definition: dpdimsave.hxx:50
SCCOL GetDimensionIndex(std::u16string_view sName) const
Definition: dpcache.cxx:1085
OUString CreateGroupDimName(const OUString &rSourceName, const ScDPObject &rObject, bool bAllowSource, const ::std::vector< OUString > *pDeletedNames)
Definition: dpdimsave.cxx:710
void SetNumGroupDimension(sal_Int32 nIndex, const ScDPNumGroupDimension &rGroup)
Definition: dpgroup.cxx:487
const ScDPSaveGroupDimension * GetNamedGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:635
ScDPSaveGroupDimension * GetGroupDimAccForBase(const OUString &rBaseDimName)
Definition: dpdimsave.cxx:655
tools::Long AppendGroupField()
Definition: dpcache.cxx:1264
ScDPSaveGroupDimension * GetNextNamedGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:675
ScDPNumGroupInfo aDateInfo
Definition: dpdimsave.hxx:139
ScDPSaveGroupDimVec maGroupDims
Definition: dpdimsave.hxx:214
void AddElementsFromGroup(const ScDPSaveGroupItem &rGroup)
Definition: dpdimsave.cxx:49
void ReplaceGroupDimension(const ScDPSaveGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:570
void SetDateDimension()
Definition: dpgroup.cxx:418
void SetGroupInfo(const ScDPNumGroupInfo &rNew)
Definition: dpdimsave.cxx:524
size_t GetElementCount() const
Definition: dpdimsave.cxx:71
constexpr OUStringLiteral aData
ScDPSaveGroupDimension * GetNamedGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:661
tools::Long GetGroupCount() const
Definition: dpdimsave.cxx:198
OUString aSourceDim
always the real source from the original data
Definition: dpdimsave.hxx:92
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:457
const ScDPSaveGroupItem & GetGroupByIndex(tools::Long nIndex) const
Definition: dpdimsave.cxx:203
When assigning a string value, you can also assign an interned string whose life-cycle is managed by ...
Definition: dpitemdata.hxx:28
void AddElement(const ScDPItemData &rName)
Definition: dpgroup.cxx:310
bool IsEmpty() const
Definition: dpdimsave.cxx:66
const OUString * GetElementByIndex(size_t nIndex) const
Definition: dpdimsave.cxx:76
Represents a group dimension that introduces a new hierarchy for an existing dimension.
Definition: dpdimsave.hxx:135
void RemoveGroup(const OUString &rGroupName)
Definition: dpdimsave.cxx:224
const OUString & GetDimensionName() const
Definition: dpdimsave.hxx:149
const ScDPSaveGroupDimension * GetNextNamedGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:645
void ResetGroupItems(tools::Long nDim, const ScDPNumGroupInfo &rNumInfo, sal_Int32 nGroupType)
Definition: dpcache.cxx:1270
ScDPSaveNumGroupDimension * GetNumGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:686
ScDPNumGroupInfo aGroupInfo
Definition: dpdimsave.hxx:138
std::vector< ScDPItemData > ScDPItemDataVec
Definition: dpcache.hxx:52
OUString aGroupName
name of group
Definition: dpdimsave.hxx:48
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
ScDPSaveGroupDimension * GetFirstNamedGroupDimAcc(const OUString &rBaseDimName)
Definition: dpdimsave.cxx:668
sal_Int32 GetDimensionIndex(std::u16string_view rName)
Definition: dpgroup.cxx:497
const ScDPSaveGroupDimension * GetFirstNamedGroupDim(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:640
ScDPSaveNumGroupDimMap maNumGroupDims
Definition: dpdimsave.hxx:215
ScDPSaveNumGroupDimension(const OUString &rName, const ScDPNumGroupInfo &rInfo)
Definition: dpdimsave.cxx:393
void AddItem(const ScDPGroupItem &rItem)
Definition: dpgroup.cxx:365
bool HasOnlyHidden(const ScDPUniqueStringSet &rVisible)
Definition: dpdimsave.cxx:239
void RemoveElementsFromGroups(ScDPSaveGroupDimension &rDimension) const
remove this group's elements from their groups in rDimension (rDimension must be a different dimensio...
Definition: dpdimsave.cxx:86
static const sal_Int32 DateLast
Definition: dpitemdata.hxx:36
void AddToCache(ScDPCache &rCache) const
Definition: dpdimsave.cxx:420
void SetRangeFirst()
Definition: dpitemdata.cxx:167
void AddToData(ScDPGroupDimension &rDataDim) const
Definition: dpdimsave.cxx:117
ScDPSaveGroupItem * GetNamedGroupAcc(const OUString &rGroupName)
Definition: dpdimsave.cxx:186
std::unordered_set< OUString > ScDPUniqueStringSet
Definition: dptypes.hxx:16
void RemoveFromGroups(const OUString &rItemName)
Definition: dpdimsave.cxx:209
static const sal_Int32 DateFirst
Definition: dpitemdata.hxx:35
std::vector< OUString > aElements
names of items in original dimension
Definition: dpdimsave.hxx:49
Represents a new group dimension whose dimension ID is higher than the highest source dimension ID...
Definition: dpdimsave.hxx:90
static sal_Int32 getDatePartValue(double fValue, const ScDPNumGroupInfo *pInfo, sal_Int32 nDatePart, const SvNumberFormatter *pFormatter)
Definition: dputil.cxx:287
void Rename(const OUString &rNewName)
Definition: dpdimsave.cxx:247
void AddElement(const OUString &rName)
Definition: dpdimsave.cxx:44
const ScDPSaveGroupItem * GetNamedGroup(const OUString &rGroupName) const
Definition: dpdimsave.cxx:181
void SetDateInfo(const ScDPNumGroupInfo &rInfo, sal_Int32 nPart)
Definition: dpdimsave.cxx:529
sal_Int32 CollectDateParts(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:697
bool operator==(const ScDPDimensionSaveData &r) const
Definition: dpdimsave.cxx:557
void WriteToData(ScDPGroupTableData &rData) const
Definition: dpdimsave.cxx:610
void AddToCache(ScDPCache &rCache) const
Definition: dpdimsave.cxx:362
OUString CreateDateGroupDimName(sal_Int32 nDatePart, const ScDPObject &rObject, bool bAllowSource, const ::std::vector< OUString > *pDeletedNames)
Definition: dpdimsave.cxx:771
void ConvertElementsToItems(SvNumberFormatter *pFormatter) const
Definition: dpdimsave.cxx:95
void WriteToCache(ScDPCache &rCache) const
Definition: dpdimsave.cxx:622
const ScDPSaveNumGroupDimension * GetNumGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:650
bool HasInGroup(const ScDPItemData &rItem) const
Definition: dpdimsave.cxx:112
ScDPSaveGroupDimension(const OUString &rSource, const OUString &rName)
Definition: dpdimsave.cxx:126
void AddGroupItem(const ScDPSaveGroupItem &rItem)
Definition: dpdimsave.cxx:147
void SetDateInfo(const ScDPNumGroupInfo &rInfo, sal_Int32 nPart)
Definition: dpdimsave.cxx:141
OUString CreateGroupName(std::u16string_view rPrefix)
Definition: dpdimsave.cxx:152
sal_Int16 nValue
bool IsEmpty() const
Definition: dpdimsave.cxx:234
void SetRangeStart(double fVal)
Definition: dpitemdata.cxx:160