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