Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "dpgroup.hxx"
30 : :
31 : : #include "global.hxx"
32 : : #include "document.hxx"
33 : : #include "dpcachetable.hxx"
34 : : #include "dptabsrc.hxx"
35 : : #include "dptabres.hxx"
36 : : #include "dpobject.hxx"
37 : : #include "dpglobal.hxx"
38 : : #include "dputil.hxx"
39 : :
40 : : #include <rtl/math.hxx>
41 : :
42 : : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
43 : : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
44 : : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
45 : :
46 : : #include <vector>
47 : : #include <boost/unordered_map.hpp>
48 : : #include <boost/unordered_set.hpp>
49 : :
50 : : using namespace ::com::sun::star;
51 : : using ::com::sun::star::uno::Any;
52 : : using ::com::sun::star::uno::Reference;
53 : : using ::com::sun::star::uno::Sequence;
54 : : using ::com::sun::star::uno::UNO_QUERY;
55 : : using ::com::sun::star::uno::UNO_QUERY_THROW;
56 : : using ::rtl::OUString;
57 : : using ::rtl::OUStringHash;
58 : :
59 : : using ::std::vector;
60 : : using ::boost::shared_ptr;
61 : :
62 : : #define D_TIMEFACTOR 86400.0
63 : :
64 : : const sal_uInt16 SC_DP_LEAPYEAR = 1648; // arbitrary leap year for date calculations
65 : :
66 : : class ScDPGroupNumFilter : public ScDPCacheTable::FilterBase
67 : : {
68 : : public:
69 : : ScDPGroupNumFilter(const ScDPItemData& rValue, const ScDPNumGroupInfo& rInfo);
70 [ # # ][ # # ]: 0 : virtual ~ScDPGroupNumFilter() {}
71 : : virtual bool match(const ScDPItemData &rCellData) const;
72 : : private:
73 : : ScDPItemData maValue;
74 : : ScDPNumGroupInfo maNumInfo;
75 : : };
76 : :
77 : 0 : ScDPGroupNumFilter::ScDPGroupNumFilter(const ScDPItemData& rValue, const ScDPNumGroupInfo& rInfo) :
78 [ # # ][ # # ]: 0 : maValue(rValue), maNumInfo(rInfo) {}
79 : :
80 : 0 : bool ScDPGroupNumFilter::match(const ScDPItemData& rCellData) const
81 : : {
82 [ # # ]: 0 : if (rCellData.GetType() != ScDPItemData::Value)
83 : 0 : return false;
84 : :
85 : 0 : double fVal = maValue.GetValue();
86 [ # # ]: 0 : if (rtl::math::isInf(fVal))
87 : : {
88 [ # # ]: 0 : if (rtl::math::isSignBitSet(fVal))
89 : : {
90 : : // Less than the min value.
91 : 0 : return rCellData.GetValue() < maNumInfo.mfStart;
92 : : }
93 : :
94 : : // Greater than the max value.
95 : 0 : return maNumInfo.mfEnd < rCellData.GetValue();
96 : : }
97 : :
98 : 0 : double low = fVal;
99 : 0 : double high = low + maNumInfo.mfStep;
100 [ # # ]: 0 : if (maNumInfo.mbIntegerOnly)
101 : 0 : high += 1.0;
102 : :
103 [ # # ][ # # ]: 0 : return low <= rCellData.GetValue() && rCellData.GetValue() < high;
104 : : }
105 : :
106 : : class ScDPGroupDateFilter : public ScDPCacheTable::FilterBase
107 : : {
108 : : public:
109 [ # # ][ # # ]: 0 : virtual ~ScDPGroupDateFilter() {}
110 : : ScDPGroupDateFilter(
111 : : const ScDPItemData& rValue, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo);
112 : :
113 : : virtual bool match(const ScDPItemData & rCellData) const;
114 : :
115 : : private:
116 : : ScDPGroupDateFilter(); // disabled
117 : :
118 : : ScDPItemData maValue;
119 : : Date maNullDate;
120 : : ScDPNumGroupInfo maNumInfo;
121 : : };
122 : :
123 : : // ----------------------------------------------------------------------------
124 : :
125 : 0 : ScDPGroupDateFilter::ScDPGroupDateFilter(
126 : : const ScDPItemData& rItem, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo) :
127 : : maValue(rItem),
128 : : maNullDate(rNullDate),
129 [ # # ][ # # ]: 0 : maNumInfo(rNumInfo)
130 : : {
131 : 0 : }
132 : :
133 : 0 : bool ScDPGroupDateFilter::match( const ScDPItemData & rCellData ) const
134 : : {
135 : : using namespace ::com::sun::star::sheet;
136 : : using ::rtl::math::approxFloor;
137 : : using ::rtl::math::approxEqual;
138 : :
139 [ # # ][ # # ]: 0 : if ( !rCellData.IsValue() )
140 : 0 : return false;
141 : :
142 [ # # ][ # # ]: 0 : if (maValue.GetType() != ScDPItemData::GroupValue)
143 : 0 : return false;
144 : :
145 [ # # ]: 0 : sal_Int32 nGroupType = maValue.GetGroupValue().mnGroupType;
146 [ # # ]: 0 : sal_Int32 nValue = maValue.GetGroupValue().mnValue;
147 : :
148 : : // Start and end dates are inclusive. (An end date without a time value
149 : : // is included, while an end date with a time value is not.)
150 : :
151 [ # # ][ # # ]: 0 : if ( rCellData.GetValue() < maNumInfo.mfStart && !approxEqual(rCellData.GetValue(), maNumInfo.mfStart) )
[ # # ][ # # ]
[ # # ]
152 : : {
153 : 0 : return nValue == ScDPItemData::DateFirst;
154 : : }
155 : :
156 [ # # ][ # # ]: 0 : if ( rCellData.GetValue() > maNumInfo.mfEnd && !approxEqual(rCellData.GetValue(), maNumInfo.mfEnd) )
[ # # ][ # # ]
[ # # ]
157 : : {
158 : 0 : return nValue == ScDPItemData::DateLast;
159 : : }
160 : :
161 : :
162 [ # # ][ # # ]: 0 : if (nGroupType == DataPilotFieldGroupBy::HOURS || nGroupType == DataPilotFieldGroupBy::MINUTES ||
[ # # ]
163 : : nGroupType == DataPilotFieldGroupBy::SECONDS)
164 : : {
165 : : // handle time
166 : : // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
167 : :
168 [ # # ][ # # ]: 0 : double time = rCellData.GetValue() - approxFloor(rCellData.GetValue());
169 : 0 : long seconds = static_cast<long>(approxFloor(time*D_TIMEFACTOR + 0.5));
170 : :
171 [ # # # # ]: 0 : switch (nGroupType)
172 : : {
173 : : case DataPilotFieldGroupBy::HOURS:
174 : : {
175 : 0 : sal_Int32 hrs = seconds / 3600;
176 : 0 : return hrs == nValue;
177 : : }
178 : : case DataPilotFieldGroupBy::MINUTES:
179 : : {
180 : 0 : sal_Int32 minutes = (seconds % 3600) / 60;
181 : 0 : return minutes == nValue;
182 : : }
183 : : case DataPilotFieldGroupBy::SECONDS:
184 : : {
185 : 0 : sal_Int32 sec = seconds % 60;
186 : 0 : return sec == nValue;
187 : : }
188 : : default:
189 : : OSL_FAIL("invalid time part");
190 : : }
191 : 0 : return false;
192 : : }
193 : :
194 [ # # ][ # # ]: 0 : Date date = maNullDate + static_cast<long>(approxFloor(rCellData.GetValue()));
195 [ # # # # : 0 : switch (nGroupType)
# ]
196 : : {
197 : : case DataPilotFieldGroupBy::YEARS:
198 : : {
199 : 0 : sal_Int32 year = static_cast<sal_Int32>(date.GetYear());
200 : 0 : return year == nValue;
201 : : }
202 : : case DataPilotFieldGroupBy::QUARTERS:
203 : : {
204 : 0 : sal_Int32 qtr = 1 + (static_cast<sal_Int32>(date.GetMonth()) - 1) / 3;
205 : 0 : return qtr == nValue;
206 : : }
207 : : case DataPilotFieldGroupBy::MONTHS:
208 : : {
209 : 0 : sal_Int32 month = static_cast<sal_Int32>(date.GetMonth());
210 : 0 : return month == nValue;
211 : : }
212 : : case DataPilotFieldGroupBy::DAYS:
213 : : {
214 : 0 : Date yearStart(1, 1, date.GetYear());
215 [ # # ]: 0 : sal_Int32 days = (date - yearStart) + 1; // Jan 01 has value 1
216 [ # # ][ # # ]: 0 : if (days >= 60 && !date.IsLeapYear())
[ # # ][ # # ]
217 : : {
218 : : // This is not a leap year. Adjust the value accordingly.
219 : 0 : ++days;
220 : : }
221 : 0 : return days == nValue;
222 : : }
223 : : default:
224 : : OSL_FAIL("invalid date part");
225 : : }
226 : :
227 : 0 : return false;
228 : : }
229 : :
230 : : namespace {
231 : :
232 : 108 : bool isDateInGroup(const ScDPItemData& rGroupItem, const ScDPItemData& rChildItem)
233 : : {
234 [ + - ][ - + ]: 108 : if (rGroupItem.GetType() != ScDPItemData::GroupValue || rChildItem.GetType() != ScDPItemData::GroupValue)
[ - + ]
235 : 0 : return false;
236 : :
237 : 108 : sal_Int32 nGroupPart = rGroupItem.GetGroupValue().mnGroupType;
238 : 108 : sal_Int32 nGroupValue = rGroupItem.GetGroupValue().mnValue;
239 : 108 : sal_Int32 nChildPart = rChildItem.GetGroupValue().mnGroupType;
240 : 108 : sal_Int32 nChildValue = rChildItem.GetGroupValue().mnValue;
241 : :
242 [ + - ][ + - ]: 108 : if (nGroupValue == ScDPItemData::DateFirst || nGroupValue == ScDPItemData::DateLast ||
[ - + ][ + - ]
243 : : nChildValue == ScDPItemData::DateFirst || nChildValue == ScDPItemData::DateLast)
244 : : {
245 : : // first/last entry matches only itself
246 : 0 : return nGroupValue == nChildValue;
247 : : }
248 : :
249 [ + - + ]: 108 : switch (nChildPart) // inner part
250 : : {
251 : : case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
252 : : // a month is only contained in its quarter
253 [ + + ]: 84 : if (nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS)
254 : : // months and quarters are both 1-based
255 : 42 : return (nGroupValue - 1 == (nChildValue - 1) / 3);
256 : :
257 : : case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
258 : : // a day is only contained in its quarter or month
259 [ + - ][ - + ]: 42 : if (nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS ||
260 : : nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS)
261 : : {
262 : 0 : Date aDate(1, 1, SC_DP_LEAPYEAR);
263 [ # # ]: 0 : aDate += (nChildValue - 1); // days are 1-based
264 : 0 : sal_Int32 nCompare = aDate.GetMonth();
265 [ # # ]: 0 : if (nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS)
266 : 0 : nCompare = ( ( nCompare - 1 ) / 3 ) + 1; // get quarter from date
267 : :
268 : 0 : return nGroupValue == nCompare;
269 : : }
270 : 42 : break;
271 : : default:
272 : : ;
273 : : }
274 : :
275 : 108 : return true;
276 : : }
277 : :
278 : : }
279 : :
280 : 14 : ScDPGroupItem::ScDPGroupItem( const ScDPItemData& rName ) :
281 [ + - ]: 14 : aGroupName( rName )
282 : : {
283 : 14 : }
284 : :
285 : 59 : ScDPGroupItem::~ScDPGroupItem()
286 : : {
287 : 59 : }
288 : :
289 : 52 : void ScDPGroupItem::AddElement( const ScDPItemData& rName )
290 : : {
291 : 52 : aElements.push_back( rName );
292 : 52 : }
293 : :
294 : 155 : bool ScDPGroupItem::HasElement( const ScDPItemData& rData ) const
295 : : {
296 [ + - ][ + - ]: 516 : for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
[ + + ]
297 [ + - ][ + - ]: 450 : if ( aIter->IsCaseInsEqual( rData ) )
[ + + ]
298 : 89 : return true;
299 : :
300 : 155 : return false;
301 : : }
302 : :
303 : 0 : bool ScDPGroupItem::HasCommonElement( const ScDPGroupItem& rOther ) const
304 : : {
305 [ # # ][ # # ]: 0 : for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
[ # # ]
306 [ # # ][ # # ]: 0 : if ( rOther.HasElement( *aIter ) )
[ # # ]
307 : 0 : return true;
308 : :
309 : 0 : return false;
310 : : }
311 : :
312 : 0 : void ScDPGroupItem::FillGroupFilter( ScDPCacheTable::GroupFilter& rFilter ) const
313 : : {
314 : 0 : ScDPItemDataVec::const_iterator itrEnd = aElements.end();
315 [ # # ][ # # ]: 0 : for (ScDPItemDataVec::const_iterator itr = aElements.begin(); itr != itrEnd; ++itr)
[ # # ]
316 [ # # ][ # # ]: 0 : rFilter.addMatchItem(*itr);
317 : 0 : }
318 : :
319 : : // -----------------------------------------------------------------------
320 : :
321 : 23 : ScDPGroupDimension::ScDPGroupDimension( long nSource, const String& rNewName ) :
322 : : nSourceDim( nSource ),
323 : : nGroupDim( -1 ),
324 : : aGroupName( rNewName ),
325 [ + - ][ + - ]: 23 : mbDateDimension(false)
326 : : {
327 : 23 : }
328 : :
329 : 75 : ScDPGroupDimension::~ScDPGroupDimension()
330 : : {
331 : 75 : maMemberEntries.clear();
332 : 75 : }
333 : :
334 : 52 : ScDPGroupDimension::ScDPGroupDimension( const ScDPGroupDimension& rOther ) :
335 : : nSourceDim( rOther.nSourceDim ),
336 : : nGroupDim( rOther.nGroupDim ),
337 : : aGroupName( rOther.aGroupName ),
338 : : aItems( rOther.aItems ),
339 [ + - ][ + - ]: 52 : mbDateDimension(rOther.mbDateDimension)
340 : : {
341 : 52 : }
342 : :
343 : 0 : ScDPGroupDimension& ScDPGroupDimension::operator=( const ScDPGroupDimension& rOther )
344 : : {
345 : 0 : nSourceDim = rOther.nSourceDim;
346 : 0 : nGroupDim = rOther.nGroupDim;
347 : 0 : aGroupName = rOther.aGroupName;
348 : 0 : aItems = rOther.aItems;
349 : 0 : mbDateDimension = rOther.mbDateDimension;
350 : 0 : return *this;
351 : : }
352 : :
353 : 14 : void ScDPGroupDimension::AddItem( const ScDPGroupItem& rItem )
354 : : {
355 : 14 : aItems.push_back( rItem );
356 : 14 : }
357 : :
358 : 23 : void ScDPGroupDimension::SetGroupDim( long nDim )
359 : : {
360 : 23 : nGroupDim = nDim;
361 : 23 : }
362 : :
363 : 118 : const std::vector<SCROW>& ScDPGroupDimension::GetColumnEntries(
364 : : const ScDPCacheTable& rCacheTable) const
365 : : {
366 [ + + ]: 118 : if (!maMemberEntries.empty())
367 : 95 : return maMemberEntries;
368 : :
369 : 23 : rCacheTable.getCache()->GetGroupDimMemberIds(nGroupDim, maMemberEntries);
370 : 118 : return maMemberEntries;
371 : : }
372 : :
373 : :
374 : :
375 : 131 : const ScDPGroupItem* ScDPGroupDimension::GetGroupForData( const ScDPItemData& rData ) const
376 : : {
377 [ + - ][ + + ]: 197 : for (ScDPGroupItemVec::const_iterator aIter = aItems.begin(); aIter != aItems.end(); ++aIter)
378 [ + - ][ + + ]: 155 : if (aIter->HasElement(rData))
379 : 89 : return &*aIter;
380 : :
381 : 131 : return NULL;
382 : : }
383 : :
384 : 0 : const ScDPGroupItem* ScDPGroupDimension::GetGroupForName( const ScDPItemData& rName ) const
385 : : {
386 [ # # ][ # # ]: 0 : for ( ScDPGroupItemVec::const_iterator aIter(aItems.begin()); aIter != aItems.end(); ++aIter )
387 [ # # ][ # # ]: 0 : if ( aIter->GetName().IsCaseInsEqual( rName ) )
388 : 0 : return &*aIter;
389 : :
390 : 0 : return NULL;
391 : : }
392 : :
393 : 0 : const ScDPGroupItem* ScDPGroupDimension::GetGroupByIndex( size_t nIndex ) const
394 : : {
395 [ # # ]: 0 : if (nIndex >= aItems.size())
396 : 0 : return NULL;
397 : :
398 : 0 : return &aItems[nIndex];
399 : : }
400 : :
401 : 0 : void ScDPGroupDimension::DisposeData()
402 : : {
403 : 0 : maMemberEntries.clear();
404 : 0 : }
405 : :
406 : 12 : void ScDPGroupDimension::SetDateDimension()
407 : : {
408 : 12 : mbDateDimension = true;
409 : 12 : }
410 : :
411 : 359 : bool ScDPGroupDimension::IsDateDimension() const
412 : : {
413 : 359 : return mbDateDimension;
414 : : }
415 : :
416 : : // -----------------------------------------------------------------------
417 : :
418 : 55 : ScDPNumGroupDimension::ScDPNumGroupDimension() : mbDateDimension(false) {}
419 : :
420 : 9 : ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) :
421 : 9 : aGroupInfo(rInfo), mbDateDimension(false) {}
422 : :
423 : 0 : ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) :
424 : 0 : aGroupInfo(rOther.aGroupInfo), mbDateDimension(rOther.mbDateDimension) {}
425 : :
426 : 9 : ScDPNumGroupDimension& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimension& rOther )
427 : : {
428 : 9 : aGroupInfo = rOther.aGroupInfo;
429 : 9 : mbDateDimension = rOther.mbDateDimension;
430 : 9 : return *this;
431 : : }
432 : :
433 : 0 : void ScDPNumGroupDimension::DisposeData()
434 : : {
435 : 0 : aGroupInfo = ScDPNumGroupInfo();
436 : 0 : maMemberEntries.clear();
437 : 0 : }
438 : :
439 : 137 : bool ScDPNumGroupDimension::IsDateDimension() const
440 : : {
441 : 137 : return mbDateDimension;
442 : : }
443 : :
444 : 64 : ScDPNumGroupDimension::~ScDPNumGroupDimension()
445 : : {
446 : 64 : }
447 : :
448 : 6 : void ScDPNumGroupDimension::SetDateDimension()
449 : : {
450 : 6 : aGroupInfo.mbEnable = true; //! or query both?
451 : 6 : mbDateDimension = true;
452 : 6 : }
453 : :
454 : 108 : const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries(
455 : : SCCOL nSourceDim, const ScDPCache* pCache) const
456 : : {
457 [ + + ]: 108 : if (!maMemberEntries.empty())
458 : 99 : return maMemberEntries;
459 : :
460 : 9 : pCache->GetGroupDimMemberIds(nSourceDim, maMemberEntries);
461 : 108 : return maMemberEntries;
462 : : }
463 : :
464 : 20 : ScDPGroupTableData::ScDPGroupTableData( const shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ) :
465 : : ScDPTableData(pDocument),
466 : : pSourceData( pSource ),
467 [ + - ][ + - ]: 20 : pDoc( pDocument )
[ + - ]
468 : : {
469 : : OSL_ENSURE( pSource, "ScDPGroupTableData: pSource can't be NULL" );
470 : :
471 [ + - ]: 20 : CreateCacheTable();
472 [ + - ]: 20 : nSourceCount = pSource->GetColumnCount(); // real columns, excluding data layout
473 [ + - ][ + - ]: 75 : pNumGroups = new ScDPNumGroupDimension[nSourceCount];
[ + + # #
# # ]
474 : 20 : }
475 : :
476 [ + - ][ + - ]: 20 : ScDPGroupTableData::~ScDPGroupTableData()
477 : : {
478 [ + - ][ + + ]: 75 : delete[] pNumGroups;
[ + - ]
479 [ - + ]: 40 : }
480 : :
481 : 6 : boost::shared_ptr<ScDPTableData> ScDPGroupTableData::GetSourceTableData()
482 : : {
483 : 6 : return pSourceData;
484 : : }
485 : :
486 : 23 : void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
487 : : {
488 [ + - ]: 23 : ScDPGroupDimension aNewGroup( rGroup );
489 [ + - ]: 23 : aNewGroup.SetGroupDim( GetColumnCount() ); // new dimension will be at the end
490 [ + - ]: 23 : aGroups.push_back( aNewGroup );
491 [ + - ]: 23 : aGroupNames.insert(aNewGroup.GetName());
492 : 23 : }
493 : :
494 : 9 : void ScDPGroupTableData::SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup )
495 : : {
496 [ + - ]: 9 : if ( nIndex < nSourceCount )
497 : : {
498 : 9 : pNumGroups[nIndex] = rGroup;
499 : :
500 : : // automatic minimum / maximum is handled in GetNumEntries
501 : : }
502 : 9 : }
503 : :
504 : 32 : long ScDPGroupTableData::GetDimensionIndex( const rtl::OUString& rName )
505 : : {
506 [ + - ]: 32 : for (long i = 0; i < nSourceCount; ++i) // nSourceCount excludes data layout
507 [ + - ]: 32 : if (pSourceData->getDimensionName(i).equals(rName)) //! ignore case?
508 : 32 : return i;
509 : 32 : return -1; // none
510 : : }
511 : :
512 : 8490 : long ScDPGroupTableData::GetColumnCount()
513 : : {
514 : 8490 : return nSourceCount + aGroups.size();
515 : : }
516 : :
517 : 441 : bool ScDPGroupTableData::IsNumGroupDimension( long nDimension ) const
518 : : {
519 [ + - ][ + + ]: 441 : return ( nDimension < nSourceCount && pNumGroups[nDimension].GetInfo().mbEnable );
520 : : }
521 : :
522 : 54 : void ScDPGroupTableData::GetNumGroupInfo(long nDimension, ScDPNumGroupInfo& rInfo)
523 : : {
524 [ + - ]: 54 : if ( nDimension < nSourceCount )
525 : 54 : rInfo = pNumGroups[nDimension].GetInfo();
526 : 54 : }
527 : 52 : long ScDPGroupTableData::GetMembersCount( long nDim )
528 : : {
529 : 52 : const std::vector< SCROW >& members = GetColumnEntries( nDim );
530 : 52 : return members.size();
531 : : }
532 : 355 : const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( long nColumn )
533 : : {
534 [ + + ]: 355 : if ( nColumn >= nSourceCount )
535 : : {
536 [ - + ]: 118 : if ( getIsDataLayoutDimension( nColumn) ) // data layout dimension?
537 : 0 : nColumn = nSourceCount; // index of data layout in source data
538 : : else
539 : : {
540 : 118 : const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
541 : 118 : return rGroupDim.GetColumnEntries( GetCacheTable() );
542 : : }
543 : : }
544 : :
545 [ + + ]: 237 : if ( IsNumGroupDimension( nColumn ) )
546 : : {
547 : : // dimension number is unchanged for numerical groups
548 : : return pNumGroups[nColumn].GetNumEntries(
549 : 108 : static_cast<SCCOL>(nColumn), GetCacheTable().getCache());
550 : : }
551 : :
552 : 355 : return pSourceData->GetColumnEntries( nColumn );
553 : : }
554 : :
555 : 1540 : const ScDPItemData* ScDPGroupTableData::GetMemberById( long nDim, long nId )
556 : : {
557 : 1540 : return pSourceData->GetMemberById( nDim, nId );
558 : : }
559 : :
560 : 3308 : rtl::OUString ScDPGroupTableData::getDimensionName(long nColumn)
561 : : {
562 [ + + ]: 3308 : if ( nColumn >= nSourceCount )
563 : : {
564 [ + + ]: 810 : if ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
565 : 260 : nColumn = nSourceCount; // index of data layout in source data
566 : : else
567 : 550 : return aGroups[nColumn - nSourceCount].GetName();
568 : : }
569 : :
570 : 3308 : return pSourceData->getDimensionName( nColumn );
571 : : }
572 : :
573 : 1678 : sal_Bool ScDPGroupTableData::getIsDataLayoutDimension(long nColumn)
574 : : {
575 : : // position of data layout dimension is moved from source data
576 : 1678 : return ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ); // data layout dimension?
577 : : }
578 : :
579 : 522 : sal_Bool ScDPGroupTableData::IsDateDimension(long nDim)
580 : : {
581 [ + + ]: 522 : if ( nDim >= nSourceCount )
582 : : {
583 [ + + ]: 240 : if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
584 : 102 : nDim = nSourceCount; // index of data layout in source data
585 : : else
586 : 138 : nDim = aGroups[nDim - nSourceCount].GetSourceDim(); // look at original dimension
587 : : }
588 : :
589 : 522 : return pSourceData->IsDateDimension( nDim );
590 : : }
591 : :
592 : 20 : sal_uLong ScDPGroupTableData::GetNumberFormat(long nDim)
593 : : {
594 [ - + ]: 20 : if ( nDim >= nSourceCount )
595 : : {
596 [ # # ]: 0 : if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
597 : 0 : nDim = nSourceCount; // index of data layout in source data
598 : : else
599 : 0 : nDim = aGroups[nDim - nSourceCount].GetSourceDim(); // look at original dimension
600 : : }
601 : :
602 : 20 : return pSourceData->GetNumberFormat( nDim );
603 : : }
604 : :
605 : 0 : void ScDPGroupTableData::DisposeData()
606 : : {
607 [ # # ][ # # ]: 0 : for ( ScDPGroupDimensionVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
608 : 0 : aIter->DisposeData();
609 : :
610 [ # # ]: 0 : for ( long i=0; i<nSourceCount; i++ )
611 : 0 : pNumGroups[i].DisposeData();
612 : :
613 : 0 : pSourceData->DisposeData();
614 : 0 : }
615 : :
616 : 80 : void ScDPGroupTableData::SetEmptyFlags( sal_Bool bIgnoreEmptyRows, sal_Bool bRepeatIfEmpty )
617 : : {
618 : 80 : pSourceData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
619 : 80 : }
620 : :
621 : 367 : bool ScDPGroupTableData::IsRepeatIfEmpty()
622 : : {
623 : 367 : return pSourceData->IsRepeatIfEmpty();
624 : : }
625 : :
626 : 20 : void ScDPGroupTableData::CreateCacheTable()
627 : : {
628 : 20 : pSourceData->CreateCacheTable();
629 : 20 : }
630 : :
631 : 0 : void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPCacheTable::Criterion>& rCriteria)
632 : : {
633 : : typedef boost::unordered_map<long, const ScDPGroupDimension*> GroupFieldMapType;
634 [ # # ]: 0 : GroupFieldMapType aGroupFieldIds;
635 : : {
636 [ # # ][ # # ]: 0 : ScDPGroupDimensionVec::const_iterator itr = aGroups.begin(), itrEnd = aGroups.end();
637 [ # # ][ # # ]: 0 : for (; itr != itrEnd; ++itr)
638 [ # # ]: 0 : aGroupFieldIds.insert( boost::unordered_map<long, const ScDPGroupDimension*>::value_type(itr->GetGroupDim(), &(*itr)) );
639 : : }
640 : :
641 [ # # ]: 0 : vector<ScDPCacheTable::Criterion> aNewCriteria;
642 [ # # ]: 0 : aNewCriteria.reserve(rCriteria.size() + aGroups.size());
643 : :
644 : : // Go through all the filtered field names and process them appropriately.
645 : :
646 [ # # ][ # # ]: 0 : const ScDPCache* pCache = GetCacheTable().getCache();
647 [ # # ]: 0 : vector<ScDPCacheTable::Criterion>::const_iterator itrEnd = rCriteria.end();
648 [ # # ]: 0 : GroupFieldMapType::const_iterator itrGrpEnd = aGroupFieldIds.end();
649 [ # # ][ # # ]: 0 : for (vector<ScDPCacheTable::Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
[ # # ][ # # ]
650 : : {
651 [ # # ][ # # ]: 0 : ScDPCacheTable::SingleFilter* pFilter = dynamic_cast<ScDPCacheTable::SingleFilter*>(itr->mpFilter.get());
652 [ # # ]: 0 : if (!pFilter)
653 : : // We expect this to be a single filter.
654 : 0 : continue;
655 : :
656 [ # # ][ # # ]: 0 : GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(itr->mnFieldIndex);
657 [ # # ]: 0 : if (itrGrp == itrGrpEnd)
658 : : {
659 [ # # ][ # # ]: 0 : if (IsNumGroupDimension(itr->mnFieldIndex))
660 : : {
661 : : // internal number group field
662 [ # # ]: 0 : ScDPCacheTable::Criterion aCri;
663 [ # # ]: 0 : aCri.mnFieldIndex = itr->mnFieldIndex;
664 [ # # ]: 0 : const ScDPNumGroupDimension& rNumGrpDim = pNumGroups[itr->mnFieldIndex];
665 [ # # ][ # # ]: 0 : const ScDPNumGroupInfo* pNumInfo = pCache->GetNumGroupInfo(itr->mnFieldIndex);
666 : :
667 [ # # ]: 0 : if (pNumInfo)
668 : : {
669 [ # # ][ # # ]: 0 : if (rNumGrpDim.IsDateDimension())
670 : : {
671 : : // grouped by dates.
672 : : aCri.mpFilter.reset(
673 : : new ScDPGroupDateFilter(
674 [ # # ][ # # ]: 0 : pFilter->getMatchValue(), *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
[ # # ][ # # ]
[ # # ][ # # ]
675 : : }
676 : : else
677 : : {
678 : : // This dimension is grouped by numeric ranges.
679 : : aCri.mpFilter.reset(
680 [ # # ][ # # ]: 0 : new ScDPGroupNumFilter(pFilter->getMatchValue(), *pNumInfo));
[ # # ][ # # ]
681 : : }
682 : : }
683 : :
684 [ # # ][ # # ]: 0 : aNewCriteria.push_back(aCri);
685 : : }
686 : : else
687 : : {
688 : : // This is a regular source field.
689 [ # # ][ # # ]: 0 : aNewCriteria.push_back(*itr);
690 : : }
691 : : }
692 : : else
693 : : {
694 : : // This is an ordinary group field or external number group field.
695 : :
696 [ # # ]: 0 : const ScDPGroupDimension* pGrpDim = itrGrp->second;
697 : 0 : long nSrcDim = pGrpDim->GetSourceDim();
698 : 0 : long nGrpDim = pGrpDim->GetGroupDim();
699 [ # # ]: 0 : const ScDPNumGroupInfo* pNumInfo = pCache->GetNumGroupInfo(nGrpDim);
700 : :
701 [ # # ][ # # ]: 0 : if (pGrpDim->IsDateDimension() && pNumInfo)
[ # # ]
702 : : {
703 : : // external number group
704 [ # # ]: 0 : ScDPCacheTable::Criterion aCri;
705 : 0 : aCri.mnFieldIndex = nSrcDim; // use the source dimension, not the group dimension.
706 : : aCri.mpFilter.reset(
707 : : new ScDPGroupDateFilter(
708 [ # # ][ # # ]: 0 : pFilter->getMatchValue(), *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
[ # # ][ # # ]
[ # # ][ # # ]
709 : :
710 [ # # ][ # # ]: 0 : aNewCriteria.push_back(aCri);
711 : : }
712 : : else
713 : : {
714 : : // normal group
715 : :
716 : : // Note that each group dimension may have multiple group names!
717 : 0 : size_t nGroupItemCount = pGrpDim->GetItemCount();
718 [ # # ]: 0 : for (size_t i = 0; i < nGroupItemCount; ++i)
719 : : {
720 [ # # ]: 0 : const ScDPGroupItem* pGrpItem = pGrpDim->GetGroupByIndex(i);
721 [ # # ][ # # ]: 0 : ScDPItemData aName = pFilter->getMatchValue();
722 : :
723 [ # # ][ # # ]: 0 : if (!pGrpItem || !pGrpItem->GetName().IsCaseInsEqual(aName))
[ # # ][ # # ]
724 : 0 : continue;
725 : :
726 [ # # ]: 0 : ScDPCacheTable::Criterion aCri;
727 : 0 : aCri.mnFieldIndex = nSrcDim;
728 [ # # ][ # # ]: 0 : aCri.mpFilter.reset(new ScDPCacheTable::GroupFilter());
[ # # ]
729 : : ScDPCacheTable::GroupFilter* pGrpFilter =
730 : 0 : static_cast<ScDPCacheTable::GroupFilter*>(aCri.mpFilter.get());
731 : :
732 [ # # ]: 0 : pGrpItem->FillGroupFilter(*pGrpFilter);
733 [ # # ]: 0 : aNewCriteria.push_back(aCri);
734 [ # # ][ # # ]: 0 : }
[ # # ]
735 : : }
736 : : }
737 : : }
738 [ # # ]: 0 : rCriteria.swap(aNewCriteria);
739 : 0 : }
740 : :
741 : 0 : void ScDPGroupTableData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rCatDims)
742 : : {
743 [ # # ]: 0 : vector<ScDPCacheTable::Criterion> aNewCriteria(rCriteria);
744 [ # # ]: 0 : ModifyFilterCriteria(aNewCriteria);
745 [ # # ]: 0 : pSourceData->FilterCacheTable(aNewCriteria, rCatDims);
746 : 0 : }
747 : :
748 : 0 : void ScDPGroupTableData::GetDrillDownData(const vector<ScDPCacheTable::Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
749 : : {
750 [ # # ]: 0 : vector<ScDPCacheTable::Criterion> aNewCriteria(rCriteria);
751 [ # # ]: 0 : ModifyFilterCriteria(aNewCriteria);
752 [ # # ]: 0 : pSourceData->GetDrillDownData(aNewCriteria, rCatDims, rData);
753 : 0 : }
754 : :
755 : 20 : void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
756 : : {
757 : : // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods
758 : : // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called
759 : : // with original rInfo, containing dimension indexes of the grouped data.
760 : :
761 : 20 : const ScDPCacheTable& rCacheTable = pSourceData->GetCacheTable();
762 : 20 : sal_Int32 nRowSize = rCacheTable.getRowSize();
763 [ + + ]: 189 : for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
764 : : {
765 [ + - ][ - + ]: 169 : if (!rCacheTable.isRowActive(nRow))
766 : 0 : continue;
767 : :
768 [ + - ]: 169 : CalcRowData aData;
769 [ + - ]: 169 : FillRowDataFromCacheTable(nRow, rCacheTable, rInfo, aData);
770 : :
771 [ + + ]: 169 : if ( !rInfo.aColLevelDims.empty() )
772 [ + - ]: 25 : FillGroupValues(aData.aColData, rInfo.aColLevelDims);
773 [ + - ]: 169 : if ( !rInfo.aRowLevelDims.empty() )
774 [ + - ]: 169 : FillGroupValues(aData.aRowData, rInfo.aRowLevelDims);
775 [ + + ]: 169 : if ( !rInfo.aPageDims.empty() )
776 [ + - ]: 10 : FillGroupValues(aData.aPageData, rInfo.aPageDims);
777 : :
778 [ + - ]: 169 : ProcessRowData(rInfo, aData, bAutoShow);
779 : 169 : }
780 : 20 : }
781 : :
782 : 717 : const ScDPCacheTable& ScDPGroupTableData::GetCacheTable() const
783 : : {
784 : 717 : return pSourceData->GetCacheTable();
785 : : }
786 : :
787 : 20 : void ScDPGroupTableData::ReloadCacheTable()
788 : : {
789 : 20 : pSourceData->ReloadCacheTable();
790 : 20 : }
791 : :
792 : 204 : void ScDPGroupTableData::FillGroupValues(vector<SCROW>& rItems, const vector<long>& rDims)
793 : : {
794 : 204 : long nGroupedColumns = aGroups.size();
795 : :
796 [ + - ][ + - ]: 204 : const ScDPCache* pCache = GetCacheTable().getCache();
797 : 204 : vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
798 [ + - ][ + - ]: 571 : for (size_t i = 0; it != itEnd; ++it, ++i)
[ + + ]
799 : : {
800 [ + - ]: 367 : long nColumn = *it;
801 : 367 : bool bDateDim = false;
802 : :
803 : 367 : long nSourceDim = nColumn;
804 [ + + ][ + - ]: 367 : if ( nColumn >= nSourceCount && nColumn < nSourceCount + nGroupedColumns )
805 : : {
806 : 163 : const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
807 : 163 : nSourceDim= rGroupDim.GetSourceDim();
808 : 163 : bDateDim = rGroupDim.IsDateDimension();
809 [ + + ]: 163 : if (!bDateDim) // date is handled below
810 : : {
811 [ + - ][ + - ]: 67 : const ScDPItemData& rItem = *GetMemberById(nSourceDim, rItems[i]);
812 [ + - ]: 67 : const ScDPGroupItem* pGroupItem = rGroupDim.GetGroupForData(rItem);
813 [ + + ]: 67 : if (pGroupItem)
814 : : {
815 [ + - ]: 46 : rItems[i] =
816 [ + - ]: 46 : pCache->GetIdByItemData(nColumn, pGroupItem->GetName());
817 : : }
818 : : else
819 [ + - ][ + - ]: 21 : rItems[i] = pCache->GetIdByItemData(nColumn, rItem);
820 : 163 : }
821 : : }
822 [ + + ]: 204 : else if ( IsNumGroupDimension( nColumn ) )
823 : : {
824 [ + - ]: 102 : bDateDim = pNumGroups[nColumn].IsDateDimension();
825 [ + + ]: 102 : if (!bDateDim) // date is handled below
826 : : {
827 [ + - ][ + - ]: 54 : const ScDPItemData* pData = pCache->GetItemDataById(nSourceDim, rItems[i]);
828 [ + - ][ + - ]: 54 : if (pData->GetType() == ScDPItemData::Value)
829 : : {
830 [ + - ]: 54 : ScDPNumGroupInfo aNumInfo;
831 : 54 : GetNumGroupInfo(nColumn, aNumInfo);
832 [ + - ][ + - ]: 54 : double fGroupValue = ScDPUtil::getNumGroupStartValue(pData->GetValue(), aNumInfo);
833 [ + - ]: 54 : ScDPItemData aItemData;
834 [ + - ]: 54 : aItemData.SetRangeStart(fGroupValue);
835 [ + - ][ + - ]: 54 : rItems[i] = pCache->GetIdByItemData(nSourceDim, aItemData);
[ + - ]
836 : : }
837 : : // else (textual) keep original value
838 : : }
839 : : }
840 : :
841 [ + - ]: 367 : const ScDPNumGroupInfo* pNumInfo = pCache->GetNumGroupInfo(nColumn);
842 : :
843 [ + + ][ + - ]: 367 : if (bDateDim && pNumInfo)
844 : : {
845 : : // This is a date group dimension.
846 [ + - ]: 144 : sal_Int32 nDatePart = pCache->GetGroupType(nColumn);
847 [ + - ][ + - ]: 144 : const ScDPItemData* pData = pCache->GetItemDataById(nSourceDim, rItems[i]);
848 [ + - ][ + - ]: 144 : if (pData->GetType() == ScDPItemData::Value)
849 : : {
850 [ + - ]: 144 : SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
851 : : sal_Int32 nPartValue = ScDPUtil::getDatePartValue(
852 [ + - ][ + - ]: 144 : pData->GetValue(), *pNumInfo, nDatePart, pFormatter);
853 : : rtl::OUString aName = ScDPUtil::getDateGroupName(
854 [ + - ]: 144 : nDatePart, nPartValue, pFormatter, pNumInfo->mfStart, pNumInfo->mfEnd);
855 : :
856 [ + - ]: 144 : ScDPItemData aItem(nDatePart, nPartValue);
857 [ + - ][ + - ]: 144 : rItems[i] = pCache->GetIdByItemData(nColumn, aItem);
[ + - ]
858 : : }
859 : : }
860 : : }
861 : 204 : }
862 : :
863 : 180 : sal_Bool ScDPGroupTableData::IsBaseForGroup(long nDim) const
864 : : {
865 [ + - ][ + + ]: 304 : for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
866 : : {
867 : 231 : const ScDPGroupDimension& rDim = *aIter;
868 [ + + ]: 231 : if ( rDim.GetSourceDim() == nDim )
869 : 107 : return sal_True;
870 : : }
871 : :
872 : 180 : return false;
873 : : }
874 : :
875 : 352 : long ScDPGroupTableData::GetGroupBase(long nGroupDim) const
876 : : {
877 [ + - ][ + + ]: 584 : for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
878 : : {
879 : 469 : const ScDPGroupDimension& rDim = *aIter;
880 [ + + ]: 469 : if ( rDim.GetGroupDim() == nGroupDim )
881 : 237 : return rDim.GetSourceDim();
882 : : }
883 : :
884 : 352 : return -1; // none
885 : : }
886 : :
887 : 35 : sal_Bool ScDPGroupTableData::IsNumOrDateGroup(long nDimension) const
888 : : {
889 : : // Virtual method from ScDPTableData, used in result data to force text labels.
890 : :
891 [ + - ]: 35 : if ( nDimension < nSourceCount )
892 : : {
893 : 35 : return pNumGroups[nDimension].GetInfo().mbEnable ||
894 [ - + ][ + - ]: 35 : pNumGroups[nDimension].IsDateDimension();
895 : : }
896 : :
897 [ # # ][ # # ]: 0 : for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
898 : : {
899 : 0 : const ScDPGroupDimension& rDim = *aIter;
900 [ # # ]: 0 : if ( rDim.GetGroupDim() == nDimension )
901 : 0 : return rDim.IsDateDimension();
902 : : }
903 : :
904 : 35 : return false;
905 : : }
906 : :
907 : 148 : sal_Bool ScDPGroupTableData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
908 : : const ScDPItemData& rBaseData, long nBaseIndex ) const
909 : : {
910 [ + - ][ + - ]: 190 : for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
911 : : {
912 : 190 : const ScDPGroupDimension& rDim = *aIter;
913 [ + - ][ + + ]: 190 : if ( rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex )
[ + + ]
914 : : {
915 [ + + ]: 148 : if (rDim.IsDateDimension())
916 : : {
917 [ + - ]: 84 : return isDateInGroup(rGroupData, rBaseData);
918 : : }
919 : : else
920 : : {
921 : : // If the item is in a group, only that group is valid.
922 : : // If the item is not in any group, its own name is valid.
923 : :
924 [ + - ]: 64 : const ScDPGroupItem* pGroup = rDim.GetGroupForData( rBaseData );
925 [ + - ]: 43 : return pGroup ? pGroup->GetName().IsCaseInsEqual( rGroupData ) :
926 [ + + ][ + - ]: 107 : rGroupData.IsCaseInsEqual( rBaseData );
927 : : }
928 : : }
929 : : }
930 : :
931 : : OSL_FAIL("IsInGroup: no group dimension found");
932 : 148 : return true;
933 : : }
934 : :
935 : 24 : sal_Bool ScDPGroupTableData::HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex,
936 : : const ScDPItemData& rSecondData, long nSecondIndex ) const
937 : : {
938 : 24 : const ScDPGroupDimension* pFirstDim = NULL;
939 : 24 : const ScDPGroupDimension* pSecondDim = NULL;
940 [ + - ][ + + ]: 72 : for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
941 : : {
942 : 48 : const ScDPGroupDimension* pDim = &(*aIter);
943 [ + + ]: 48 : if ( pDim->GetGroupDim() == nFirstIndex )
944 : 24 : pFirstDim = pDim;
945 [ + - ]: 24 : else if ( pDim->GetGroupDim() == nSecondIndex )
946 : 24 : pSecondDim = pDim;
947 : : }
948 [ + - ][ + - ]: 24 : if ( pFirstDim && pSecondDim )
949 : : {
950 : 24 : bool bFirstDate = pFirstDim->IsDateDimension();
951 : 24 : bool bSecondDate = pSecondDim->IsDateDimension();
952 [ # # ][ - + ]: 24 : if (bFirstDate || bSecondDate)
953 : : {
954 : : // If one is a date group dimension, the other one must be, too.
955 [ + - ][ - + ]: 24 : if (!bFirstDate || !bSecondDate)
956 : : {
957 : : OSL_FAIL( "mix of date and non-date groups" );
958 : 0 : return true;
959 : : }
960 : :
961 : 24 : return isDateInGroup(rFirstData, rSecondData);
962 : : }
963 : :
964 : 0 : const ScDPGroupItem* pFirstItem = pFirstDim->GetGroupForName( rFirstData );
965 : 0 : const ScDPGroupItem* pSecondItem = pSecondDim->GetGroupForName( rSecondData );
966 [ # # ][ # # ]: 0 : if ( pFirstItem && pSecondItem )
967 : : {
968 : : // two existing groups -> sal_True if they have a common element
969 : 0 : return pFirstItem->HasCommonElement( *pSecondItem );
970 : : }
971 [ # # ]: 0 : else if ( pFirstItem )
972 : : {
973 : : // "automatic" group contains only its own name
974 : 0 : return pFirstItem->HasElement( rSecondData );
975 : : }
976 [ # # ]: 0 : else if ( pSecondItem )
977 : : {
978 : : // "automatic" group contains only its own name
979 : 0 : return pSecondItem->HasElement( rFirstData );
980 : : }
981 : : else
982 : : {
983 : : // no groups -> sal_True if equal
984 : 0 : return rFirstData.IsCaseInsEqual( rSecondData );
985 : : }
986 : : }
987 : :
988 : : OSL_FAIL("HasCommonElement: no group dimension found");
989 : 24 : return true;
990 : : }
991 : :
992 : 367 : long ScDPGroupTableData::GetSourceDim( long nDim )
993 : : {
994 [ - + ]: 367 : if ( getIsDataLayoutDimension( nDim ) )
995 : 0 : return nSourceCount;
996 [ + + ][ + - ]: 367 : if ( nDim >= nSourceCount && nDim < nSourceCount +(long) aGroups.size() )
[ + + ]
997 : : {
998 : 163 : const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
999 : 163 : return rGroupDim.GetSourceDim();
1000 : : }
1001 : 367 : return nDim;
1002 : : }
1003 : :
1004 : 427 : long ScDPGroupTableData::Compare(long nDim, long nDataId1, long nDataId2)
1005 : : {
1006 [ - + ]: 427 : if ( getIsDataLayoutDimension(nDim) )
1007 : 0 : return 0;
1008 : 427 : return ScDPItemData::Compare( *GetMemberById(nDim, nDataId1),*GetMemberById(nDim, nDataId2) );
1009 [ + - ][ + - ]: 153 : }
1010 : :
1011 : : #if DEBUG_PIVOT_TABLE
1012 : : #include <iostream>
1013 : : using std::cout;
1014 : : using std::endl;
1015 : :
1016 : : void ScDPGroupTableData::Dump() const
1017 : : {
1018 : : cout << "--- ScDPGroupTableData" << endl;
1019 : : for (long i = 0; i < nSourceCount; ++i)
1020 : : {
1021 : : cout << "* dimension: " << i << endl;
1022 : : const ScDPNumGroupDimension& rGrp = pNumGroups[i];
1023 : : rGrp.GetInfo().Dump();
1024 : : }
1025 : : cout << "---" << endl;
1026 : : }
1027 : : #endif
1028 : :
1029 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|