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