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 <svl/zforlist.hxx>
31 #include <osl/diagnose.h>
32 #include <rtl/math.hxx>
33 #include <algorithm>
34 
35 #include <globstr.hrc>
36 #include <scresid.hxx>
37 
38 using namespace com::sun::star;
39 
40 ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
41  aGroupName(rName) {}
42 
44 
45 void ScDPSaveGroupItem::AddElement( const OUString& rName )
46 {
47  aElements.push_back(rName);
48 }
49 
51 {
52  // add all elements of the other group (used for nested grouping)
53  aElements.insert( aElements.end(), rGroup.aElements.begin(), rGroup.aElements.end() );
54 }
55 
56 bool ScDPSaveGroupItem::RemoveElement( const OUString& rName )
57 {
58  auto it = std::find(aElements.begin(), aElements.end(), rName); //TODO: ignore case
59  if (it != aElements.end())
60  {
61  aElements.erase(it);
62  return true;
63  }
64  return false; // not found
65 }
66 
68 {
69  return aElements.empty();
70 }
71 
73 {
74  return aElements.size();
75 }
76 
77 const OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
78 {
79  return (nIndex < aElements.size()) ? &aElements[ nIndex ] : nullptr;
80 }
81 
82 void ScDPSaveGroupItem::Rename( const OUString& rNewName )
83 {
84  aGroupName = rNewName;
85 }
86 
88 {
89  // remove this group's elements from their groups in rDimension
90  // (rDimension must be a different dimension from the one which contains this)
91 
92  for ( const auto& rElement : aElements )
93  rDimension.RemoveFromGroups( rElement );
94 }
95 
97 {
98  maItems.reserve(aElements.size());
99  for (const auto& rElement : aElements)
100  {
101  sal_uInt32 nFormat = 0;
102  double fValue;
104  if (pFormatter->IsNumberFormat(rElement, nFormat, fValue))
105  aData.SetValue(fValue);
106  else
107  aData.SetString(rElement);
108 
109  maItems.push_back(aData);
110  }
111 }
112 
114 {
115  return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
116 }
117 
119 {
120  ScDPGroupItem aGroup(aGroupName);
121  for (const auto& rItem : maItems)
122  aGroup.AddElement(rItem);
123 
124  rDataDim.AddItem(aGroup);
125 }
126 
127 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
128  aSourceDim( rSource ),
129  aGroupDimName( rName ),
130  nDatePart( 0 )
131 {
132 }
133 
134 ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
135  aSourceDim( rSource ),
136  aGroupDimName( rName ),
137  aDateInfo( rDateInfo ),
138  nDatePart( nPart )
139 {
140 }
141 
142 void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
143 {
144  aDateInfo = rInfo;
145  nDatePart = nPart;
146 }
147 
149 {
150  aGroups.push_back( rItem );
151 }
152 
153 OUString ScDPSaveGroupDimension::CreateGroupName(std::u16string_view rPrefix)
154 {
155  // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
156 
157  //TODO: look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
158  //TODO: (only dimensions for the same base)
159 
160  sal_Int32 nAdd = 1; // first try is "Group1"
161  const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
162  while ( nAdd <= nMaxAdd )
163  {
164  OUString aGroupName = rPrefix + OUString::number( nAdd );
165 
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
170  });
171 
172  if ( !bExists )
173  return aGroupName; // found a new name
174 
175  ++nAdd; // continue with higher number
176  }
177 
178  OSL_FAIL("CreateGroupName: no valid name found");
179  return OUString();
180 }
181 
182 const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const OUString& rGroupName ) const
183 {
184  return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
185 }
186 
188 {
189  auto aIter = std::find_if(aGroups.begin(), aGroups.end(),
190  [&rGroupName](const ScDPSaveGroupItem& rGroup) {
191  return rGroup.GetGroupName() == rGroupName; //TODO: ignore case
192  });
193  if (aIter != aGroups.end())
194  return &*aIter;
195 
196  return nullptr; // none found
197 }
198 
200 {
201  return aGroups.size();
202 }
203 
205 {
206  return aGroups[nIndex];
207 }
208 
209 
210 void ScDPSaveGroupDimension::RemoveFromGroups( const OUString& rItemName )
211 {
212  // if the item is in any group, remove it from the group,
213  // also remove the group if it is empty afterwards
214 
215  for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
216  if ( aIter->RemoveElement( rItemName ) )
217  {
218  if ( aIter->IsEmpty() ) // removed last item from the group?
219  aGroups.erase( aIter ); // then remove the group
220 
221  return; // don't have to look further
222  }
223 }
224 
225 void ScDPSaveGroupDimension::RemoveGroup(const OUString& rGroupName)
226 {
227  auto aIter = std::find_if(aGroups.begin(), aGroups.end(),
228  [&rGroupName](const ScDPSaveGroupItem& rGroup) {
229  return rGroup.GetGroupName() == rGroupName; //TODO: ignore case
230  });
231  if (aIter != aGroups.end())
232  aGroups.erase( aIter );
233 }
234 
236 {
237  return aGroups.empty();
238 }
239 
241 {
242  // check if there are only groups that don't appear in the list of visible names
243 
244  return std::none_of(aGroups.begin(), aGroups.end(),
245  [&rVisible](const ScDPSaveGroupItem& rGroup) { return rVisible.count(rGroup.GetGroupName()) > 0; });
246 }
247 
248 void ScDPSaveGroupDimension::Rename( const OUString& rNewName )
249 {
250  aGroupDimName = rNewName;
251 }
252 
254 {
255  return std::any_of(aGroups.begin(), aGroups.end(),
256  [&rItem](const ScDPSaveGroupItem& rGroup) { return rGroup.HasInGroup(rItem); });
257 }
258 
259 namespace {
260 
261 bool isInteger(double fValue)
262 {
263  return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
264 }
265 
266 void fillDateGroupDimension(
267  ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, tools::Long nSourceDim, tools::Long nGroupDim,
268  sal_Int32 nDatePart, const SvNumberFormatter* pFormatter)
269 {
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;
275 
276  const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nSourceDim);
277  for (const ScDPItemData& rItem : rItems)
278  {
279  if (rItem.GetType() != ScDPItemData::Value)
280  continue;
281 
282  double fVal = rItem.GetValue();
283  if (bFirst)
284  {
285  fSourceMin = fSourceMax = fVal;
286  bFirst = false;
287  }
288  else
289  {
290  if (fVal < fSourceMin)
291  fSourceMin = fVal;
292  if ( fVal > fSourceMax )
293  fSourceMax = fVal;
294  }
295  }
296 
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;
304 
305  //TODO: if not automatic, limit fSourceMin/fSourceMax for list of year values?
306 
307  tools::Long nStart = 0, nEnd = 0; // end is inclusive
308 
309  switch (nDatePart)
310  {
311  case sheet::DataPilotFieldGroupBy::YEARS:
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");
324  }
325 
326  // Now, populate the group items in the cache.
327  rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
328 
329  for (tools::Long nValue = nStart; nValue <= nEnd; ++nValue)
330  rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
331 
332  // add first/last entry (min/max)
333  rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
334  rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
335 }
336 
337 }
338 
340 {
341  tools::Long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
342  if ( nSourceIndex < 0 )
343  return;
344 
345  ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
346  if ( nDatePart )
347  {
348  // date grouping
349 
350  aDim.SetDateDimension();
351  }
352  else
353  {
354  // normal (manual) grouping
355 
356  for (const auto& rGroup : aGroups)
357  rGroup.AddToData(aDim);
358  }
359 
360  rData.AddGroupDimension( aDim );
361 }
362 
364 {
365  tools::Long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
366  if (nSourceDim < 0)
367  return;
368 
369  tools::Long nDim = rCache.AppendGroupField();
370  SvNumberFormatter* pFormatter = rCache.GetDoc().GetFormatTable();
371 
372  if (nDatePart)
373  {
374  fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
375  return;
376  }
377 
378  rCache.ResetGroupItems(nDim, aDateInfo, 0);
379  for (const ScDPSaveGroupItem& rGI : aGroups)
380  {
381  rGI.ConvertElementsToItems(pFormatter);
382  rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
383  }
384 
385  const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nSourceDim);
386  for (const ScDPItemData& rItem : rItems)
387  {
388  if (!IsInGroup(rItem))
389  // Not in any group. Add as its own group.
390  rCache.SetGroupItem(nDim, rItem);
391  }
392 }
393 
395  aDimensionName( rName ),
396  aGroupInfo( rInfo ),
397  nDatePart( 0 )
398 {
399 }
400 
401 ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
402  aDimensionName( rName ),
403  aDateInfo( rDateInfo ),
404  nDatePart( nPart )
405 {
406 }
407 
409 {
410  tools::Long nSource = rData.GetDimensionIndex( aDimensionName );
411  if ( nSource >= 0 )
412  {
413  ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
414  if ( nDatePart )
415  aDim.SetDateDimension();
416 
417  rData.SetNumGroupDimension( nSource, aDim );
418  }
419 }
420 
422 {
424  if (nDim < 0)
425  return;
426 
427  if (aDateInfo.mbEnable)
428  {
429  // Date grouping
430  SvNumberFormatter* pFormatter = rCache.GetDoc().GetFormatTable();
431  fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
432  }
433  else if (aGroupInfo.mbEnable)
434  {
435  // Number-range grouping
436 
437  // Look through the source entries for non-integer numbers, minimum
438  // and maximum.
439 
440  // non-integer GroupInfo values count, too
442  (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
443  (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
444  isInteger(aGroupInfo.mfStep);
445 
446  double fSourceMin = 0.0;
447  double fSourceMax = 0.0;
448  bool bFirst = true;
449 
450  const ScDPCache::ScDPItemDataVec& rItems = rCache.GetDimMemberValues(nDim);
451  for (const ScDPItemData& rItem : rItems)
452  {
453  if (rItem.GetType() != ScDPItemData::Value)
454  continue;
455 
456  double fValue = rItem.GetValue();
457  if (bFirst)
458  {
459  fSourceMin = fSourceMax = fValue;
460  bFirst = false;
461  continue;
462  }
463 
464  if (fValue < fSourceMin)
465  fSourceMin = fValue;
466  if (fValue > fSourceMax)
467  fSourceMax = fValue;
468 
469  if (aGroupInfo.mbIntegerOnly && !isInteger(fValue))
470  {
471  // If any non-integer numbers are involved, the group labels
472  // are shown including their upper limit.
473  aGroupInfo.mbIntegerOnly = false;
474  }
475  }
476 
478  {
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;
483  }
484 
486  aGroupInfo.mfStart = fSourceMin;
487  if (aGroupInfo.mbAutoEnd)
488  aGroupInfo.mfEnd = fSourceMax;
489 
490  //TODO: limit number of entries?
491 
492  tools::Long nLoopCount = 0;
493  double fLoop = aGroupInfo.mfStart;
494 
495  rCache.ResetGroupItems(nDim, aGroupInfo, 0);
496 
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.
502 
503  bool bFirstGroup = true;
504  while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
505  {
506  ScDPItemData aItem;
507  aItem.SetRangeStart(fLoop);
508  rCache.SetGroupItem(nDim, aItem);
509  ++nLoopCount;
510  fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
511  bFirstGroup = false;
512 
513  // ScDPItemData values are compared with approxEqual
514  }
515 
516  ScDPItemData aItem;
517  aItem.SetRangeFirst();
518  rCache.SetGroupItem(nDim, aItem);
519 
520  aItem.SetRangeLast();
521  rCache.SetGroupItem(nDim, aItem);
522  }
523 }
524 
526 {
527  aGroupInfo = rNew;
528 }
529 
530 void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
531 {
532  aDateInfo = rInfo;
533  nDatePart = nPart;
534 }
535 
536 namespace {
537 
538 struct ScDPSaveGroupDimNameFunc
539 {
540  OUString maDimName;
541  explicit ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
542  bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
543 };
544 
545 struct ScDPSaveGroupSourceNameFunc
546 {
547  OUString maSrcDimName;
548  explicit ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
549  bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
550 };
551 
552 } // namespace
553 
555 {
556 }
557 
559 {
560  return false;
561 }
562 
564 {
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 );
569 }
570 
572 {
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;
579 }
580 
581 void ScDPDimensionSaveData::RemoveGroupDimension( const OUString& rGroupDimName )
582 {
583  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
584  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
585  if( aIt != maGroupDims.end() )
586  maGroupDims.erase( aIt );
587 }
588 
590 {
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 );
595 }
596 
598 {
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;
604 }
605 
606 void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString& rGroupDimName )
607 {
608  maNumGroupDims.erase( rGroupDimName );
609 }
610 
612 {
613  // rData is assumed to be empty
614  // AddToData also handles date grouping
615 
616  for( const auto& rGroupDim : maGroupDims )
617  rGroupDim.AddToData( rData );
618 
619  for( const auto& rEntry : maNumGroupDims )
620  rEntry.second.AddToData( rData );
621 }
622 
624 {
625  for (const auto& rEntry : maGroupDims)
626  rEntry.AddToCache(rCache);
627  for (const auto& rEntry : maNumGroupDims)
628  rEntry.second.AddToCache(rCache);
629 }
630 
631 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const OUString& rBaseDimName ) const
632 {
633  return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
634 }
635 
636 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const OUString& rGroupDimName ) const
637 {
638  return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
639 }
640 
641 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const OUString& rBaseDimName ) const
642 {
643  return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
644 }
645 
646 const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const OUString& rGroupDimName ) const
647 {
648  return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
649 }
650 
651 const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const OUString& rGroupDimName ) const
652 {
653  return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
654 }
655 
657 {
658  ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
659  return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
660 }
661 
663 {
664  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
665  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
666  return (aIt == maGroupDims.end()) ? nullptr : &*aIt;
667 }
668 
670 {
671  ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
672  maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
673  return (aIt == maGroupDims.end()) ? nullptr : &*aIt;
674 }
675 
677 {
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;
685 }
686 
688 {
689  ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
690  return (aIt == maNumGroupDims.end()) ? nullptr : &aIt->second;
691 }
692 
694 {
695  return !maGroupDims.empty() || !maNumGroupDims.empty();
696 }
697 
698 sal_Int32 ScDPDimensionSaveData::CollectDateParts( const OUString& rBaseDimName ) const
699 {
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();
707 
708  return nParts;
709 }
710 
712  const OUString& rSourceName, const ScDPObject& rObject, bool bAllowSource,
713  const std::vector<OUString>* pDeletedNames )
714 {
715  // create a name for the new dimension by appending a number to the original
716  // dimension's name
717 
718  bool bUseSource = bAllowSource; // if set, try the unchanged original name first
719 
720  sal_Int32 nAdd = 2; // first try is "Name2"
721  const sal_Int32 nMaxAdd = 1000; // limit the loop
722  while ( nAdd <= nMaxAdd )
723  {
724  OUString aDimName( rSourceName );
725  if ( !bUseSource )
726  aDimName += OUString::number(nAdd);
727 
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
732  });
733 
734  // look for base dimensions that happen to have that name
735  if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
736  {
737  if ( pDeletedNames &&
738  std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
739  {
740  // allow the name anyway if the name is in pDeletedNames
741  }
742  else
743  bExists = true;
744  }
745 
746  if ( !bExists )
747  return aDimName; // found a new name
748 
749  if ( bUseSource )
750  bUseSource = false;
751  else
752  ++nAdd; // continue with higher number
753  }
754  OSL_FAIL("CreateGroupDimName: no valid name found");
755  return OUString();
756 }
757 
758 namespace
759 {
760  const TranslateId aDatePartIds[] =
761  {
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
769  };
770 }
771 
773  sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource,
774  const std::vector<OUString>* pDeletedNames )
775 {
776  using namespace css::sheet::DataPilotFieldGroupBy;
777  OUString aPartName;
778  switch( nDatePart )
779  {
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;
787  }
788  OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
789  return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
790 }
791 
792 /* 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:253
bool IsDimNameInUse(std::u16string_view rName) const
Definition: dpobject.cxx:1174
void AddToData(ScDPGroupTableData &rData) const
Definition: dpdimsave.cxx:408
void ReplaceNumGroupDimension(const ScDPSaveNumGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:597
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:89
void Rename(const OUString &rNewName)
Definition: dpdimsave.cxx:82
void AddGroupDimension(const ScDPGroupDimension &rGroup)
Definition: dpgroup.cxx:480
bool HasGroupDimensions() const
Definition: dpdimsave.cxx:693
ScDPSaveGroupItemVec aGroups
Definition: dpdimsave.hxx:94
void AddNumGroupDimension(const ScDPSaveNumGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:589
bool RemoveElement(const OUString &rName)
Definition: dpdimsave.cxx:56
const ScDPSaveGroupDimension * GetGroupDimForBase(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:631
SCROW SetGroupItem(tools::Long nDim, const ScDPItemData &rData)
Definition: dpcache.cxx:1289
ScDocument & GetDoc() const
Definition: dpcache.cxx:880
ScDPSaveGroupItem(const OUString &rName)
Definition: dpdimsave.cxx:40
long Long
void AddGroupDimension(const ScDPSaveGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:563
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:581
void AddToData(ScDPGroupTableData &rData) const
Definition: dpdimsave.cxx:339
ScDPNumGroupInfo aDateInfo
Definition: dpdimsave.hxx:95
const ScDPItemDataVec & GetDimMemberValues(SCCOL nDim) const
Definition: dpcache.cxx:1047
void RemoveNumGroupDimension(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:606
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:1082
OUString CreateGroupDimName(const OUString &rSourceName, const ScDPObject &rObject, bool bAllowSource, const ::std::vector< OUString > *pDeletedNames)
Definition: dpdimsave.cxx:711
void SetNumGroupDimension(sal_Int32 nIndex, const ScDPNumGroupDimension &rGroup)
Definition: dpgroup.cxx:487
const ScDPSaveGroupDimension * GetNamedGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:636
ScDPSaveGroupDimension * GetGroupDimAccForBase(const OUString &rBaseDimName)
Definition: dpdimsave.cxx:656
tools::Long AppendGroupField()
Definition: dpcache.cxx:1261
ScDPSaveGroupDimension * GetNextNamedGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:676
ScDPNumGroupInfo aDateInfo
Definition: dpdimsave.hxx:139
ScDPSaveGroupDimVec maGroupDims
Definition: dpdimsave.hxx:214
void AddElementsFromGroup(const ScDPSaveGroupItem &rGroup)
Definition: dpdimsave.cxx:50
void ReplaceGroupDimension(const ScDPSaveGroupDimension &rGroupDim)
Definition: dpdimsave.cxx:571
void SetDateDimension()
Definition: dpgroup.cxx:418
void SetGroupInfo(const ScDPNumGroupInfo &rNew)
Definition: dpdimsave.cxx:525
size_t GetElementCount() const
Definition: dpdimsave.cxx:72
constexpr OUStringLiteral aData
ScDPSaveGroupDimension * GetNamedGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:662
tools::Long GetGroupCount() const
Definition: dpdimsave.cxx:199
OUString aSourceDim
always the real source from the original data
Definition: dpdimsave.hxx:92
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:441
const ScDPSaveGroupItem & GetGroupByIndex(tools::Long nIndex) const
Definition: dpdimsave.cxx:204
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:67
const OUString * GetElementByIndex(size_t nIndex) const
Definition: dpdimsave.cxx:77
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:225
const OUString & GetDimensionName() const
Definition: dpdimsave.hxx:149
const ScDPSaveGroupDimension * GetNextNamedGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:646
void ResetGroupItems(tools::Long nDim, const ScDPNumGroupInfo &rNumInfo, sal_Int32 nGroupType)
Definition: dpcache.cxx:1267
ScDPSaveNumGroupDimension * GetNumGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:687
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:669
sal_Int32 GetDimensionIndex(std::u16string_view rName)
Definition: dpgroup.cxx:497
const ScDPSaveGroupDimension * GetFirstNamedGroupDim(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:641
ScDPSaveNumGroupDimMap maNumGroupDims
Definition: dpdimsave.hxx:215
ScDPSaveNumGroupDimension(const OUString &rName, const ScDPNumGroupInfo &rInfo)
Definition: dpdimsave.cxx:394
void AddItem(const ScDPGroupItem &rItem)
Definition: dpgroup.cxx:365
bool HasOnlyHidden(const ScDPUniqueStringSet &rVisible)
Definition: dpdimsave.cxx:240
void RemoveElementsFromGroups(ScDPSaveGroupDimension &rDimension) const
remove this group's elements from their groups in rDimension (rDimension must be a different dimensio...
Definition: dpdimsave.cxx:87
static const sal_Int32 DateLast
Definition: dpitemdata.hxx:36
void AddToCache(ScDPCache &rCache) const
Definition: dpdimsave.cxx:421
void SetRangeFirst()
Definition: dpitemdata.cxx:167
void AddToData(ScDPGroupDimension &rDataDim) const
Definition: dpdimsave.cxx:118
ScDPSaveGroupItem * GetNamedGroupAcc(const OUString &rGroupName)
Definition: dpdimsave.cxx:187
std::unordered_set< OUString > ScDPUniqueStringSet
Definition: dptypes.hxx:16
void RemoveFromGroups(const OUString &rItemName)
Definition: dpdimsave.cxx:210
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:248
void AddElement(const OUString &rName)
Definition: dpdimsave.cxx:45
const ScDPSaveGroupItem * GetNamedGroup(const OUString &rGroupName) const
Definition: dpdimsave.cxx:182
void SetDateInfo(const ScDPNumGroupInfo &rInfo, sal_Int32 nPart)
Definition: dpdimsave.cxx:530
sal_Int32 CollectDateParts(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:698
bool operator==(const ScDPDimensionSaveData &r) const
Definition: dpdimsave.cxx:558
void WriteToData(ScDPGroupTableData &rData) const
Definition: dpdimsave.cxx:611
void AddToCache(ScDPCache &rCache) const
Definition: dpdimsave.cxx:363
OUString CreateDateGroupDimName(sal_Int32 nDatePart, const ScDPObject &rObject, bool bAllowSource, const ::std::vector< OUString > *pDeletedNames)
Definition: dpdimsave.cxx:772
void ConvertElementsToItems(SvNumberFormatter *pFormatter) const
Definition: dpdimsave.cxx:96
void WriteToCache(ScDPCache &rCache) const
Definition: dpdimsave.cxx:623
const ScDPSaveNumGroupDimension * GetNumGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:651
bool HasInGroup(const ScDPItemData &rItem) const
Definition: dpdimsave.cxx:113
ScDPSaveGroupDimension(const OUString &rSource, const OUString &rName)
Definition: dpdimsave.cxx:127
void AddGroupItem(const ScDPSaveGroupItem &rItem)
Definition: dpdimsave.cxx:148
void SetDateInfo(const ScDPNumGroupInfo &rInfo, sal_Int32 nPart)
Definition: dpdimsave.cxx:142
OUString CreateGroupName(std::u16string_view rPrefix)
Definition: dpdimsave.cxx:153
sal_Int16 nValue
bool IsEmpty() const
Definition: dpdimsave.cxx:235
void SetRangeStart(double fVal)
Definition: dpitemdata.cxx:160