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