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 : #include "dptabres.hxx"
21 :
22 : #include "dptabdat.hxx"
23 : #include "dptabsrc.hxx"
24 : #include "global.hxx"
25 : #include "subtotal.hxx"
26 : #include "globstr.hrc"
27 : #include "datauno.hxx" // ScDataUnoConversion
28 : #include "dpitemdata.hxx"
29 :
30 : #include "document.hxx" // for DumpState only!
31 : #include "stlalgorithm.hxx"
32 : #include "dpresfilter.hxx"
33 :
34 : #include <osl/diagnose.h>
35 : #include <rtl/math.hxx>
36 : #include <rtl/strbuf.hxx>
37 :
38 : #include <math.h>
39 : #include <float.h> //! Test !!!
40 : #include <algorithm>
41 : #include <boost/unordered_map.hpp>
42 : #include <boost/scoped_ptr.hpp>
43 :
44 : #include <com/sun/star/sheet/DataResultFlags.hpp>
45 : #include <com/sun/star/sheet/MemberResultFlags.hpp>
46 : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
47 : #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
48 : #include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
49 : #include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
50 : #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
51 : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
52 :
53 : using namespace com::sun::star;
54 : using ::std::vector;
55 : using ::std::pair;
56 : using ::com::sun::star::uno::Sequence;
57 :
58 : namespace {
59 :
60 : sal_uInt16 nFuncStrIds[12] = // passend zum enum ScSubTotalFunc
61 : {
62 : 0, // SUBTOTAL_FUNC_NONE
63 : STR_FUN_TEXT_AVG, // SUBTOTAL_FUNC_AVE
64 : STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT
65 : STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT2
66 : STR_FUN_TEXT_MAX, // SUBTOTAL_FUNC_MAX
67 : STR_FUN_TEXT_MIN, // SUBTOTAL_FUNC_MIN
68 : STR_FUN_TEXT_PRODUCT, // SUBTOTAL_FUNC_PROD
69 : STR_FUN_TEXT_STDDEV, // SUBTOTAL_FUNC_STD
70 : STR_FUN_TEXT_STDDEV, // SUBTOTAL_FUNC_STDP
71 : STR_FUN_TEXT_SUM, // SUBTOTAL_FUNC_SUM
72 : STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VAR
73 : STR_FUN_TEXT_VAR // SUBTOTAL_FUNC_VARP
74 : };
75 :
76 63 : bool lcl_SearchMember( const std::vector <ScDPResultMember *>& list, SCROW nOrder, SCROW& rIndex)
77 : {
78 63 : rIndex = list.size();
79 63 : bool bFound = false;
80 63 : SCROW nLo = 0;
81 63 : SCROW nHi = list.size() - 1;
82 : SCROW nIndex;
83 150 : while (nLo <= nHi)
84 : {
85 24 : nIndex = (nLo + nHi) / 2;
86 24 : if ( list[nIndex]->GetOrder() < nOrder )
87 24 : nLo = nIndex + 1;
88 : else
89 : {
90 0 : nHi = nIndex - 1;
91 0 : if ( list[nIndex]->GetOrder() == nOrder )
92 : {
93 0 : bFound = true;
94 0 : nLo = nIndex;
95 : }
96 : }
97 : }
98 63 : rIndex = nLo;
99 63 : return bFound;
100 : }
101 :
102 : class FilterStack
103 : {
104 : std::vector<ScDPResultFilter>& mrFilters;
105 : public:
106 1736 : FilterStack(std::vector<ScDPResultFilter>& rFilters) : mrFilters(rFilters) {}
107 :
108 364 : void pushDimName(const OUString& rName, bool bDataLayout)
109 : {
110 364 : mrFilters.push_back(ScDPResultFilter(rName, bDataLayout));
111 364 : }
112 :
113 1372 : void pushDimValue(const ScDPItemData& rValue)
114 : {
115 1372 : ScDPResultFilter& rFilter = mrFilters.back();
116 1372 : rFilter.maValue = rValue;
117 1372 : rFilter.mbHasValue = true;
118 1372 : }
119 :
120 1736 : ~FilterStack()
121 : {
122 1736 : ScDPResultFilter& rFilter = mrFilters.back();
123 1736 : if (rFilter.mbHasValue)
124 1372 : rFilter.mbHasValue = false;
125 : else
126 364 : mrFilters.pop_back();
127 1736 : }
128 : };
129 :
130 : }
131 :
132 : //
133 : // function objects for sorting of the column and row members:
134 : //
135 :
136 : class ScDPRowMembersOrder
137 : {
138 : ScDPResultDimension& rDimension;
139 : long nMeasure;
140 : bool bAscending;
141 :
142 : public:
143 0 : ScDPRowMembersOrder( ScDPResultDimension& rDim, long nM, bool bAsc ) :
144 : rDimension(rDim),
145 : nMeasure(nM),
146 0 : bAscending(bAsc)
147 0 : {}
148 0 : ~ScDPRowMembersOrder() {}
149 :
150 : bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
151 : };
152 :
153 : class ScDPColMembersOrder
154 : {
155 : ScDPDataDimension& rDimension;
156 : long nMeasure;
157 : bool bAscending;
158 :
159 : public:
160 0 : ScDPColMembersOrder( ScDPDataDimension& rDim, long nM, bool bAsc ) :
161 : rDimension(rDim),
162 : nMeasure(nM),
163 0 : bAscending(bAsc)
164 0 : {}
165 0 : ~ScDPColMembersOrder() {}
166 :
167 : bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
168 : };
169 :
170 0 : static bool lcl_IsLess( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure, bool bAscending )
171 : {
172 : // members can be NULL if used for rows
173 :
174 0 : ScDPSubTotalState aEmptyState;
175 0 : const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : NULL;
176 0 : const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : NULL;
177 :
178 0 : bool bError1 = pAgg1 && pAgg1->HasError();
179 0 : bool bError2 = pAgg2 && pAgg2->HasError();
180 0 : if ( bError1 )
181 0 : return false; // errors are always sorted at the end
182 0 : else if ( bError2 )
183 0 : return true; // errors are always sorted at the end
184 : else
185 : {
186 0 : double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0; // no data is sorted as 0
187 0 : double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;
188 :
189 : // compare values
190 : // don't have to check approxEqual, as this is the only sort criterion
191 :
192 0 : return bAscending ? ( fVal1 < fVal2 ) : ( fVal1 > fVal2 );
193 : }
194 : }
195 :
196 0 : static bool lcl_IsEqual( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure )
197 : {
198 : // members can be NULL if used for rows
199 :
200 0 : ScDPSubTotalState aEmptyState;
201 0 : const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : NULL;
202 0 : const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : NULL;
203 :
204 0 : bool bError1 = pAgg1 && pAgg1->HasError();
205 0 : bool bError2 = pAgg2 && pAgg2->HasError();
206 0 : if ( bError1 )
207 : {
208 0 : if ( bError2 )
209 0 : return true; // equal
210 : else
211 0 : return false;
212 : }
213 0 : else if ( bError2 )
214 0 : return false;
215 : else
216 : {
217 0 : double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0; // no data is sorted as 0
218 0 : double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;
219 :
220 : // compare values
221 : // this is used to find equal data at the end of the AutoShow range, so approxEqual must be used
222 :
223 0 : return rtl::math::approxEqual( fVal1, fVal2 );
224 : }
225 : }
226 :
227 0 : bool ScDPRowMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
228 : {
229 0 : const ScDPResultMember* pMember1 = rDimension.GetMember(nIndex1);
230 0 : const ScDPResultMember* pMember2 = rDimension.GetMember(nIndex2);
231 :
232 : // make the hide item to the largest order.
233 0 : if ( !pMember1->IsVisible() || !pMember2->IsVisible() )
234 0 : return pMember1->IsVisible();
235 0 : const ScDPDataMember* pDataMember1 = pMember1->GetDataRoot() ;
236 0 : const ScDPDataMember* pDataMember2 = pMember2->GetDataRoot();
237 : // GetDataRoot can be NULL if there was no data.
238 : // IsVisible == false can happen after AutoShow.
239 0 : return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
240 : }
241 :
242 0 : bool ScDPColMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
243 : {
244 0 : const ScDPDataMember* pDataMember1 = rDimension.GetMember(nIndex1);
245 0 : const ScDPDataMember* pDataMember2 = rDimension.GetMember(nIndex2);
246 0 : bool bHide1 = pDataMember1 && !pDataMember1->IsVisible();
247 0 : bool bHide2 = pDataMember2 && !pDataMember2->IsVisible();
248 0 : if ( bHide1 || bHide2 )
249 0 : return !bHide1;
250 0 : return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
251 : }
252 :
253 709 : ScDPInitState::Member::Member(long nSrcIndex, SCROW nNameIndex) :
254 709 : mnSrcIndex(nSrcIndex), mnNameIndex(nNameIndex) {}
255 :
256 709 : void ScDPInitState::AddMember( long nSourceIndex, SCROW nMember )
257 : {
258 709 : maMembers.push_back(Member(nSourceIndex, nMember));
259 709 : }
260 :
261 709 : void ScDPInitState::RemoveMember()
262 : {
263 : OSL_ENSURE(!maMembers.empty(), "ScDPInitState::RemoveMember: Attempt to remmove member while empty.");
264 709 : if (!maMembers.empty())
265 709 : maMembers.pop_back();
266 709 : }
267 :
268 : namespace {
269 :
270 : #if DEBUG_PIVOT_TABLE
271 : void lcl_DumpRow(
272 : const OUString& rType, const OUString& rName, const ScDPAggData* pAggData,
273 : ScDocument* pDoc, ScAddress& rPos )
274 : {
275 : SCCOL nCol = rPos.Col();
276 : SCROW nRow = rPos.Row();
277 : SCTAB nTab = rPos.Tab();
278 : pDoc->SetString( nCol++, nRow, nTab, rType );
279 : pDoc->SetString( nCol++, nRow, nTab, rName );
280 : while ( pAggData )
281 : {
282 : pDoc->SetValue( nCol++, nRow, nTab, pAggData->GetResult() );
283 : pAggData = pAggData->GetExistingChild();
284 : }
285 : rPos.SetRow( nRow + 1 );
286 : }
287 :
288 : void lcl_Indent( ScDocument* pDoc, SCROW nStartRow, const ScAddress& rPos )
289 : {
290 : SCCOL nCol = rPos.Col();
291 : SCTAB nTab = rPos.Tab();
292 :
293 : OUString aString;
294 : for (SCROW nRow = nStartRow; nRow < rPos.Row(); nRow++)
295 : {
296 : aString = pDoc->GetString(nCol, nRow, nTab);
297 : if (!aString.isEmpty())
298 : {
299 : aString = " " + aString;
300 : pDoc->SetString( nCol, nRow, nTab, aString );
301 : }
302 : }
303 : }
304 : #endif
305 :
306 : }
307 :
308 78 : ScDPRunningTotalState::ScDPRunningTotalState( ScDPResultMember* pColRoot, ScDPResultMember* pRowRoot ) :
309 78 : pColResRoot(pColRoot), pRowResRoot(pRowRoot)
310 : {
311 : // These arrays should never be empty as the terminating value must be present at all times.
312 78 : maColVisible.push_back(-1);
313 78 : maColSorted.push_back(-1);
314 78 : maRowVisible.push_back(-1);
315 78 : maRowSorted.push_back(-1);
316 78 : }
317 :
318 20 : const ScDPRunningTotalState::IndexArray& ScDPRunningTotalState::GetColVisible() const
319 : {
320 20 : return maColVisible;
321 : }
322 :
323 20 : const ScDPRunningTotalState::IndexArray& ScDPRunningTotalState::GetColSorted() const
324 : {
325 20 : return maColSorted;
326 : }
327 :
328 20 : const ScDPRunningTotalState::IndexArray& ScDPRunningTotalState::GetRowVisible() const
329 : {
330 20 : return maRowVisible;
331 : }
332 :
333 20 : const ScDPRunningTotalState::IndexArray& ScDPRunningTotalState::GetRowSorted() const
334 : {
335 20 : return maRowSorted;
336 : }
337 :
338 1178 : void ScDPRunningTotalState::AddColIndex( long nVisible, long nSorted )
339 : {
340 1178 : maColVisible.back() = nVisible;
341 1178 : maColVisible.push_back(-1);
342 :
343 1178 : maColSorted.back() = nSorted;
344 1178 : maColSorted.push_back(-1);
345 1178 : }
346 :
347 329 : void ScDPRunningTotalState::AddRowIndex( long nVisible, long nSorted )
348 : {
349 329 : maRowVisible.back() = nVisible;
350 329 : maRowVisible.push_back(-1);
351 :
352 329 : maRowSorted.back() = nSorted;
353 329 : maRowSorted.push_back(-1);
354 329 : }
355 :
356 1178 : void ScDPRunningTotalState::RemoveColIndex()
357 : {
358 : OSL_ENSURE(!maColVisible.empty() && !maColSorted.empty(), "ScDPRunningTotalState::RemoveColIndex: array is already empty!");
359 1178 : if (maColVisible.size() >= 2)
360 : {
361 1178 : maColVisible.pop_back();
362 1178 : maColVisible.back() = -1;
363 : }
364 :
365 1178 : if (maColSorted.size() >= 2)
366 : {
367 1178 : maColSorted.pop_back();
368 1178 : maColSorted.back() = -1;
369 : }
370 1178 : }
371 :
372 329 : void ScDPRunningTotalState::RemoveRowIndex()
373 : {
374 : OSL_ENSURE(!maRowVisible.empty() && !maRowSorted.empty(), "ScDPRunningTotalState::RemoveRowIndex: array is already empty!");
375 329 : if (maRowVisible.size() >= 2)
376 : {
377 329 : maRowVisible.pop_back();
378 329 : maRowVisible.back() = -1;
379 : }
380 :
381 329 : if (maRowSorted.size() >= 2)
382 : {
383 329 : maRowSorted.pop_back();
384 329 : maRowSorted.back() = -1;
385 : }
386 329 : }
387 :
388 : // -----------------------------------------------------------------------
389 :
390 12 : ScDPRelativePos::ScDPRelativePos( long nBase, long nDir ) :
391 : nBasePos( nBase ),
392 12 : nDirection( nDir )
393 : {
394 12 : }
395 :
396 : // -----------------------------------------------------------------------
397 :
398 1600 : void ScDPAggData::Update( const ScDPValue& rNext, ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
399 : {
400 1600 : if (nCount<0) // error?
401 0 : return; // nothing more...
402 :
403 1600 : if (rNext.meType == ScDPValue::Empty)
404 4 : return;
405 :
406 1596 : if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
407 0 : rSubState.eColForce != rSubState.eRowForce )
408 0 : return;
409 1596 : if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
410 1596 : if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;
411 :
412 1596 : if ( eFunc == SUBTOTAL_FUNC_NONE )
413 0 : return;
414 :
415 1596 : if ( eFunc != SUBTOTAL_FUNC_CNT2 ) // CNT2 counts everything, incl. strings and errors
416 : {
417 1516 : if (rNext.meType == ScDPValue::Error)
418 : {
419 0 : nCount = -1; // -1 for error (not for CNT2)
420 0 : return;
421 : }
422 1516 : if (rNext.meType == ScDPValue::String)
423 0 : return; // ignore
424 : }
425 :
426 1596 : ++nCount; // for all functions
427 :
428 1596 : switch (eFunc)
429 : {
430 : case SUBTOTAL_FUNC_SUM:
431 : case SUBTOTAL_FUNC_AVE:
432 1516 : if ( !SubTotal::SafePlus( fVal, rNext.mfValue ) )
433 0 : nCount = -1; // -1 for error
434 1516 : break;
435 : case SUBTOTAL_FUNC_PROD:
436 0 : if ( nCount == 1 ) // copy first value (fVal is initialized to 0)
437 0 : fVal = rNext.mfValue;
438 0 : else if ( !SubTotal::SafeMult( fVal, rNext.mfValue ) )
439 0 : nCount = -1; // -1 for error
440 0 : break;
441 : case SUBTOTAL_FUNC_CNT:
442 : case SUBTOTAL_FUNC_CNT2:
443 : // nothing more than incrementing nCount
444 80 : break;
445 : case SUBTOTAL_FUNC_MAX:
446 0 : if ( nCount == 1 || rNext.mfValue > fVal )
447 0 : fVal = rNext.mfValue;
448 0 : break;
449 : case SUBTOTAL_FUNC_MIN:
450 0 : if ( nCount == 1 || rNext.mfValue < fVal )
451 0 : fVal = rNext.mfValue;
452 0 : break;
453 : case SUBTOTAL_FUNC_STD:
454 : case SUBTOTAL_FUNC_STDP:
455 : case SUBTOTAL_FUNC_VAR:
456 : case SUBTOTAL_FUNC_VARP:
457 : {
458 : // fAux is used to sum up squares
459 0 : if ( !SubTotal::SafePlus( fVal, rNext.mfValue ) )
460 0 : nCount = -1; // -1 for error
461 0 : double fAdd = rNext.mfValue;
462 0 : if ( !SubTotal::SafeMult( fAdd, rNext.mfValue ) ||
463 0 : !SubTotal::SafePlus( fAux, fAdd ) )
464 0 : nCount = -1; // -1 for error
465 : }
466 0 : break;
467 : default:
468 : OSL_FAIL("invalid function");
469 : }
470 : }
471 :
472 1813 : void ScDPAggData::Calculate( ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
473 : {
474 : // calculate the original result
475 : // (without reference value, used as the basis for reference value calculation)
476 :
477 : // called several times at the cross-section of several subtotals - don't calculate twice then
478 1813 : if ( IsCalculated() )
479 0 : return;
480 :
481 1813 : if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
482 1813 : if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;
483 :
484 1813 : if ( eFunc == SUBTOTAL_FUNC_NONE ) // this happens when there is no data dimension
485 : {
486 77 : nCount = SC_DPAGG_RESULT_EMPTY; // make sure there's a valid state for HasData etc.
487 77 : return;
488 : }
489 :
490 : // check the error conditions for the selected function
491 :
492 1736 : bool bError = false;
493 1736 : switch (eFunc)
494 : {
495 : case SUBTOTAL_FUNC_SUM:
496 : case SUBTOTAL_FUNC_PROD:
497 : case SUBTOTAL_FUNC_CNT:
498 : case SUBTOTAL_FUNC_CNT2:
499 1736 : bError = ( nCount < 0 ); // only real errors
500 1736 : break;
501 :
502 : case SUBTOTAL_FUNC_AVE:
503 : case SUBTOTAL_FUNC_MAX:
504 : case SUBTOTAL_FUNC_MIN:
505 : case SUBTOTAL_FUNC_STDP:
506 : case SUBTOTAL_FUNC_VARP:
507 0 : bError = ( nCount <= 0 ); // no data is an error
508 0 : break;
509 :
510 : case SUBTOTAL_FUNC_STD:
511 : case SUBTOTAL_FUNC_VAR:
512 0 : bError = ( nCount < 2 ); // need at least 2 values
513 0 : break;
514 :
515 : default:
516 : OSL_FAIL("invalid function");
517 : }
518 :
519 : // calculate the selected function
520 :
521 1736 : double fResult = 0.0;
522 1736 : if ( !bError )
523 : {
524 1736 : switch (eFunc)
525 : {
526 : case SUBTOTAL_FUNC_MAX:
527 : case SUBTOTAL_FUNC_MIN:
528 : case SUBTOTAL_FUNC_SUM:
529 : case SUBTOTAL_FUNC_PROD:
530 : // different error conditions are handled above
531 1725 : fResult = fVal;
532 1725 : break;
533 :
534 : case SUBTOTAL_FUNC_CNT:
535 : case SUBTOTAL_FUNC_CNT2:
536 11 : fResult = nCount;
537 11 : break;
538 :
539 : case SUBTOTAL_FUNC_AVE:
540 0 : if ( nCount > 0 )
541 0 : fResult = fVal / (double) nCount;
542 0 : break;
543 :
544 : //! use safe mul for fVal * fVal
545 :
546 : case SUBTOTAL_FUNC_STD:
547 0 : if ( nCount >= 2 )
548 0 : fResult = sqrt((fAux - fVal*fVal/(double)(nCount)) / (double)(nCount-1));
549 0 : break;
550 : case SUBTOTAL_FUNC_VAR:
551 0 : if ( nCount >= 2 )
552 0 : fResult = (fAux - fVal*fVal/(double)(nCount)) / (double)(nCount-1);
553 0 : break;
554 : case SUBTOTAL_FUNC_STDP:
555 0 : if ( nCount > 0 )
556 0 : fResult = sqrt((fAux - fVal*fVal/(double)(nCount)) / (double)nCount);
557 0 : break;
558 : case SUBTOTAL_FUNC_VARP:
559 0 : if ( nCount > 0 )
560 0 : fResult = (fAux - fVal*fVal/(double)(nCount)) / (double)nCount;
561 0 : break;
562 : default:
563 : OSL_FAIL("invalid function");
564 : }
565 : }
566 :
567 1736 : bool bEmpty = ( nCount == 0 ); // no data
568 :
569 : // store the result
570 : // Empty is checked first, so empty results are shown empty even for "average" etc.
571 : // If these results should be treated as errors in reference value calculations,
572 : // a separate state value (EMPTY_ERROR) is needed.
573 : // Now, for compatibility, empty "average" results are counted as 0.
574 :
575 1736 : if ( bEmpty )
576 894 : nCount = SC_DPAGG_RESULT_EMPTY;
577 842 : else if ( bError )
578 0 : nCount = SC_DPAGG_RESULT_ERROR;
579 : else
580 842 : nCount = SC_DPAGG_RESULT_VALID;
581 :
582 1736 : if ( bEmpty || bError )
583 894 : fResult = 0.0; // default, in case the state is later modified
584 :
585 1736 : fVal = fResult; // used directly from now on
586 1736 : fAux = 0.0; // used for running total or original result of reference value
587 : }
588 :
589 1828 : bool ScDPAggData::IsCalculated() const
590 : {
591 1828 : return ( nCount <= SC_DPAGG_RESULT_EMPTY );
592 : }
593 :
594 719 : double ScDPAggData::GetResult() const
595 : {
596 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
597 :
598 719 : return fVal; // use calculated value
599 : }
600 :
601 685 : bool ScDPAggData::HasError() const
602 : {
603 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
604 :
605 685 : return ( nCount == SC_DPAGG_RESULT_ERROR );
606 : }
607 :
608 1304 : bool ScDPAggData::HasData() const
609 : {
610 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
611 :
612 1304 : return ( nCount != SC_DPAGG_RESULT_EMPTY ); // values or error
613 : }
614 :
615 19 : void ScDPAggData::SetResult( double fNew )
616 : {
617 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
618 :
619 19 : fVal = fNew; // don't reset error flag
620 19 : }
621 :
622 0 : void ScDPAggData::SetError()
623 : {
624 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
625 :
626 0 : nCount = SC_DPAGG_RESULT_ERROR;
627 0 : }
628 :
629 20 : void ScDPAggData::SetEmpty( bool bSet )
630 : {
631 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
632 :
633 20 : if ( bSet )
634 6 : nCount = SC_DPAGG_RESULT_EMPTY;
635 : else
636 14 : nCount = SC_DPAGG_RESULT_VALID;
637 20 : }
638 :
639 19 : double ScDPAggData::GetAuxiliary() const
640 : {
641 : // after Calculate, fAux is used as auxiliary value for running totals and reference values
642 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
643 :
644 19 : return fAux;
645 : }
646 :
647 26 : void ScDPAggData::SetAuxiliary( double fNew )
648 : {
649 : // after Calculate, fAux is used as auxiliary value for running totals and reference values
650 : OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
651 :
652 26 : fAux = fNew;
653 26 : }
654 :
655 1638 : ScDPAggData* ScDPAggData::GetChild()
656 : {
657 1638 : if (!pChild)
658 1031 : pChild = new ScDPAggData;
659 1638 : return pChild;
660 : }
661 :
662 41 : void ScDPAggData::Reset()
663 : {
664 41 : fVal = 0.0;
665 41 : fAux = 0.0;
666 41 : nCount = SC_DPAGG_EMPTY;
667 41 : delete pChild;
668 41 : pChild = NULL;
669 41 : }
670 :
671 : #if DEBUG_PIVOT_TABLE
672 : void ScDPAggData::Dump(int nIndent) const
673 : {
674 : std::string aIndent(nIndent*2, ' ');
675 : std::cout << aIndent << "* ";
676 : if (IsCalculated())
677 : std::cout << GetResult();
678 : else
679 : std::cout << "not calculated";
680 :
681 : std::cout << " [val=" << fVal << "; aux=" << fAux << "; count=" << nCount << "]" << std::endl;
682 : }
683 : #endif
684 :
685 : // -----------------------------------------------------------------------
686 :
687 78 : ScDPRowTotals::ScDPRowTotals() :
688 78 : bIsInColRoot( false )
689 : {
690 78 : }
691 :
692 78 : ScDPRowTotals::~ScDPRowTotals()
693 : {
694 78 : }
695 :
696 15 : static ScDPAggData* lcl_GetChildTotal( ScDPAggData* pFirst, long nMeasure )
697 : {
698 : OSL_ENSURE( nMeasure >= 0, "GetColTotal: no measure" );
699 :
700 15 : ScDPAggData* pAgg = pFirst;
701 15 : long nSkip = nMeasure;
702 :
703 : // subtotal settings are ignored - colum/row totals exist once per measure
704 :
705 15 : for ( long nPos=0; nPos<nSkip; nPos++ )
706 0 : pAgg = pAgg->GetChild(); // column total is constructed empty - children need to be created
707 :
708 15 : if ( !pAgg->IsCalculated() )
709 : {
710 : // for first use, simulate an empty calculation
711 3 : ScDPSubTotalState aEmptyState;
712 3 : pAgg->Calculate( SUBTOTAL_FUNC_SUM, aEmptyState );
713 : }
714 :
715 15 : return pAgg;
716 : }
717 :
718 5 : ScDPAggData* ScDPRowTotals::GetRowTotal( long nMeasure )
719 : {
720 5 : return lcl_GetChildTotal( &aRowTotal, nMeasure );
721 : }
722 :
723 5 : ScDPAggData* ScDPRowTotals::GetGrandTotal( long nMeasure )
724 : {
725 5 : return lcl_GetChildTotal( &aGrandTotal, nMeasure );
726 : }
727 :
728 : // -----------------------------------------------------------------------
729 :
730 101 : static ScSubTotalFunc lcl_GetForceFunc( const ScDPLevel* pLevel, long nFuncNo )
731 : {
732 101 : ScSubTotalFunc eRet = SUBTOTAL_FUNC_NONE;
733 101 : if ( pLevel )
734 : {
735 : //! direct access via ScDPLevel
736 :
737 0 : uno::Sequence<sheet::GeneralFunction> aSeq = pLevel->getSubTotals();
738 0 : long nSequence = aSeq.getLength();
739 0 : if ( nSequence && aSeq[0] != sheet::GeneralFunction_AUTO )
740 : {
741 : // For manual subtotals, "automatic" is added as first function.
742 : // ScDPResultMember::GetSubTotalCount adds to the count, here NONE has to be
743 : // returned as the first function then.
744 :
745 0 : --nFuncNo; // keep NONE for first (check below), move the other entries
746 : }
747 :
748 0 : if ( nFuncNo >= 0 && nFuncNo < nSequence )
749 : {
750 0 : sheet::GeneralFunction eUser = aSeq.getConstArray()[nFuncNo];
751 0 : if (eUser != sheet::GeneralFunction_AUTO)
752 0 : eRet = ScDataUnoConversion::GeneralToSubTotal( eUser );
753 0 : }
754 : }
755 101 : return eRet;
756 : }
757 :
758 : // -----------------------------------------------------------------------
759 :
760 78 : ScDPResultData::ScDPResultData( ScDPSource& rSrc ) :
761 : mrSource(rSrc),
762 : bLateInit( false ),
763 : bDataAtCol( false ),
764 78 : bDataAtRow( false )
765 : {
766 78 : }
767 :
768 156 : ScDPResultData::~ScDPResultData()
769 : {
770 78 : std::for_each(maDimMembers.begin(), maDimMembers.end(), ScDeleteObjectByPtr<ResultMembers>());
771 78 : }
772 :
773 78 : void ScDPResultData::SetMeasureData(
774 : std::vector<ScSubTotalFunc>& rFunctions, std::vector<sheet::DataPilotFieldReference>& rRefs,
775 : std::vector<sal_uInt16>& rRefOrient, std::vector<OUString>& rNames )
776 : {
777 : // We need to have at least one measure data at all times.
778 :
779 78 : maMeasureFuncs.swap(rFunctions);
780 78 : if (maMeasureFuncs.empty())
781 10 : maMeasureFuncs.push_back(SUBTOTAL_FUNC_NONE);
782 :
783 78 : maMeasureRefs.swap(rRefs);
784 78 : if (maMeasureRefs.empty())
785 10 : maMeasureRefs.push_back(sheet::DataPilotFieldReference()); // default ctor is ok.
786 :
787 78 : maMeasureRefOrients.swap(rRefOrient);
788 78 : if (maMeasureRefOrients.empty())
789 10 : maMeasureRefOrients.push_back(sheet::DataPilotFieldOrientation_HIDDEN);
790 :
791 78 : maMeasureNames.swap(rNames);
792 78 : if (maMeasureNames.empty())
793 10 : maMeasureNames.push_back(ScGlobal::GetRscString(STR_EMPTYDATA));
794 78 : }
795 :
796 78 : void ScDPResultData::SetDataLayoutOrientation( sal_uInt16 nOrient )
797 : {
798 78 : bDataAtCol = ( nOrient == sheet::DataPilotFieldOrientation_COLUMN );
799 78 : bDataAtRow = ( nOrient == sheet::DataPilotFieldOrientation_ROW );
800 78 : }
801 :
802 78 : void ScDPResultData::SetLateInit( bool bSet )
803 : {
804 78 : bLateInit = bSet;
805 78 : }
806 :
807 1322 : long ScDPResultData::GetColStartMeasure() const
808 : {
809 1322 : if (maMeasureFuncs.size() == 1)
810 1269 : return 0;
811 :
812 53 : return bDataAtCol ? SC_DPMEASURE_ALL : SC_DPMEASURE_ANY;
813 : }
814 :
815 441 : long ScDPResultData::GetRowStartMeasure() const
816 : {
817 441 : if (maMeasureFuncs.size() == 1)
818 405 : return 0;
819 :
820 36 : return bDataAtRow ? SC_DPMEASURE_ALL : SC_DPMEASURE_ANY;
821 : }
822 :
823 3498 : ScSubTotalFunc ScDPResultData::GetMeasureFunction(long nMeasure) const
824 : {
825 : OSL_ENSURE((size_t) nMeasure < maMeasureFuncs.size(), "bumm");
826 3498 : return maMeasureFuncs[nMeasure];
827 : }
828 :
829 3404 : const sheet::DataPilotFieldReference& ScDPResultData::GetMeasureRefVal(long nMeasure) const
830 : {
831 : OSL_ENSURE((size_t) nMeasure < maMeasureRefs.size(), "bumm");
832 3404 : return maMeasureRefs[nMeasure];
833 : }
834 :
835 20 : sal_uInt16 ScDPResultData::GetMeasureRefOrient(long nMeasure) const
836 : {
837 : OSL_ENSURE((size_t) nMeasure < maMeasureRefOrients.size(), "bumm");
838 20 : return maMeasureRefOrients[nMeasure];
839 : }
840 :
841 187 : OUString ScDPResultData::GetMeasureString(long nMeasure, bool bForce, ScSubTotalFunc eForceFunc, bool& rbTotalResult) const
842 : {
843 : // with bForce==true, return function instead of "result" for single measure
844 : // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
845 187 : rbTotalResult = false;
846 187 : if ( nMeasure < 0 || (maMeasureFuncs.size() == 1 && !bForce && eForceFunc == SUBTOTAL_FUNC_NONE) )
847 : {
848 : // for user-specified subtotal function with all measures,
849 : // display only function name
850 99 : if ( eForceFunc != SUBTOTAL_FUNC_NONE )
851 0 : return ScGlobal::GetRscString(nFuncStrIds[eForceFunc]);
852 :
853 99 : rbTotalResult = true;
854 99 : return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS);
855 : }
856 : else
857 : {
858 : OSL_ENSURE((size_t) nMeasure < maMeasureFuncs.size(), "bumm");
859 88 : const ScDPDimension* pDataDim = mrSource.GetDataDimension(nMeasure);
860 88 : if (pDataDim)
861 : {
862 78 : const OUString* pLayoutName = pDataDim->GetLayoutName();
863 78 : if (pLayoutName)
864 0 : return *pLayoutName;
865 : }
866 88 : OUStringBuffer aRet;
867 : ScSubTotalFunc eFunc = ( eForceFunc == SUBTOTAL_FUNC_NONE ) ?
868 88 : GetMeasureFunction(nMeasure) : eForceFunc;
869 88 : sal_uInt16 nId = nFuncStrIds[eFunc];
870 88 : if (nId)
871 : {
872 78 : aRet.append(ScGlobal::GetRscString(nId)); // function name
873 78 : aRet.appendAscii(RTL_CONSTASCII_STRINGPARAM(" - "));
874 : }
875 88 : aRet.append(maMeasureNames[nMeasure]); // field name
876 :
877 88 : return aRet.makeStringAndClear();
878 : }
879 : }
880 :
881 16 : OUString ScDPResultData::GetMeasureDimensionName(long nMeasure) const
882 : {
883 16 : if ( nMeasure < 0 )
884 : {
885 : OSL_FAIL("GetMeasureDimensionName: negative");
886 0 : return OUString("***");
887 : }
888 :
889 16 : return mrSource.GetDataDimName(nMeasure);
890 : }
891 :
892 199 : bool ScDPResultData::IsBaseForGroup( long nDim ) const
893 : {
894 199 : return mrSource.GetData()->IsBaseForGroup(nDim);
895 : }
896 :
897 266 : long ScDPResultData::GetGroupBase( long nGroupDim ) const
898 : {
899 266 : return mrSource.GetData()->GetGroupBase(nGroupDim);
900 : }
901 :
902 332 : bool ScDPResultData::IsNumOrDateGroup( long nDim ) const
903 : {
904 332 : return mrSource.GetData()->IsNumOrDateGroup(nDim);
905 : }
906 :
907 59 : bool ScDPResultData::IsInGroup( SCROW nGroupDataId, long nGroupIndex,
908 : const ScDPItemData& rBaseData, long nBaseIndex ) const
909 : {
910 59 : const ScDPItemData* pGroupData = mrSource.GetItemDataById(nGroupIndex , nGroupDataId);
911 59 : if ( pGroupData )
912 59 : return mrSource.GetData()->IsInGroup(*pGroupData, nGroupIndex, rBaseData, nBaseIndex);
913 : else
914 0 : return false;
915 : }
916 :
917 8 : bool ScDPResultData::HasCommonElement( SCROW nFirstDataId, long nFirstIndex,
918 : const ScDPItemData& rSecondData, long nSecondIndex ) const
919 : {
920 8 : const ScDPItemData* pFirstData = mrSource.GetItemDataById(nFirstIndex , nFirstDataId);
921 8 : if ( pFirstData )
922 8 : return mrSource.GetData()->HasCommonElement(*pFirstData, nFirstIndex, rSecondData, nSecondIndex);
923 : else
924 0 : return false;
925 : }
926 :
927 720 : const ScDPSource& ScDPResultData::GetSource() const
928 : {
929 720 : return mrSource;
930 : }
931 :
932 693 : ResultMembers* ScDPResultData::GetDimResultMembers(long nDim, ScDPDimension* pDim, ScDPLevel* pLevel) const
933 : {
934 693 : if (nDim < static_cast<long>(maDimMembers.size()) && maDimMembers[nDim])
935 551 : return maDimMembers[nDim];
936 :
937 142 : maDimMembers.resize(nDim+1, NULL);
938 :
939 142 : ResultMembers* pResultMembers = new ResultMembers();
940 : // global order is used to initialize aMembers, so it doesn't have to be looked at later
941 142 : const ScMemberSortOrder& rGlobalOrder = pLevel->GetGlobalOrder();
942 :
943 142 : ScDPMembers* pMembers = pLevel->GetMembersObject();
944 142 : long nMembCount = pMembers->getCount();
945 795 : for (long i = 0; i < nMembCount; ++i)
946 : {
947 653 : long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
948 653 : ScDPMember* pMember = pMembers->getByIndex(nSorted);
949 653 : if (!pResultMembers->FindMember(pMember->GetItemDataId()))
950 : {
951 653 : ScDPParentDimData* pNew = new ScDPParentDimData(i, pDim, pLevel, pMember);
952 653 : pResultMembers->InsertMember(pNew);
953 : }
954 : }
955 :
956 142 : maDimMembers[nDim] = pResultMembers;
957 142 : return maDimMembers[nDim];
958 : }
959 :
960 : // -----------------------------------------------------------------------
961 :
962 :
963 601 : ScDPResultMember::ScDPResultMember(
964 : const ScDPResultData* pData, const ScDPParentDimData& rParentDimData, bool bForceSub ) :
965 : pResultData( pData ),
966 : aParentDimData( rParentDimData ),
967 : pChildDimension( NULL ),
968 : pDataRoot( NULL ),
969 : bHasElements( false ),
970 : bForceSubTotal( bForceSub ),
971 : bHasHiddenDetails( false ),
972 : bInitialized( false ),
973 : bAutoHidden( false ),
974 601 : nMemberStep( 1 )
975 : {
976 : // pParentLevel/pMemberDesc is 0 for root members
977 601 : }
978 :
979 156 : ScDPResultMember::ScDPResultMember(
980 : const ScDPResultData* pData, bool bForceSub ) :
981 : pResultData( pData ),
982 : pChildDimension( NULL ),
983 : pDataRoot( NULL ),
984 : bHasElements( false ),
985 : bForceSubTotal( bForceSub ),
986 : bHasHiddenDetails( false ),
987 : bInitialized( false ),
988 : bAutoHidden( false ),
989 156 : nMemberStep( 1 )
990 : {
991 156 : }
992 1514 : ScDPResultMember::~ScDPResultMember()
993 : {
994 757 : delete pChildDimension;
995 757 : delete pDataRoot;
996 757 : }
997 :
998 12 : OUString ScDPResultMember::GetName() const
999 : {
1000 12 : const ScDPMember* pMemberDesc = GetDPMember();
1001 12 : if (pMemberDesc)
1002 12 : return pMemberDesc->GetNameStr();
1003 : else
1004 0 : return ScGlobal::GetRscString(STR_PIVOT_TOTAL); // root member
1005 : }
1006 :
1007 5941 : void ScDPResultMember::FillItemData( ScDPItemData& rData ) const
1008 : {
1009 5941 : const ScDPMember* pMemberDesc = GetDPMember();
1010 5941 : if (pMemberDesc)
1011 5836 : pMemberDesc->FillItemData( rData );
1012 : else
1013 105 : rData.SetString( ScGlobal::GetRscString(STR_PIVOT_TOTAL) ); // root member
1014 5941 : }
1015 :
1016 3245 : bool ScDPResultMember::IsNamedItem( SCROW nIndex ) const
1017 : {
1018 : //! store ScDPMember pointer instead of ScDPMember ???
1019 3245 : const ScDPMember* pMemberDesc = GetDPMember();
1020 3245 : if (pMemberDesc)
1021 3245 : return pMemberDesc->IsNamedItem(nIndex);
1022 0 : return false;
1023 : }
1024 :
1025 671 : bool ScDPResultMember::IsValidEntry( const vector< SCROW >& aMembers ) const
1026 : {
1027 671 : if ( !IsValid() )
1028 5 : return false;
1029 :
1030 666 : const ScDPResultDimension* pChildDim = GetChildDimension();
1031 666 : if (pChildDim)
1032 : {
1033 96 : if (aMembers.size() < 2)
1034 0 : return false;
1035 :
1036 96 : vector<SCROW>::const_iterator itr = aMembers.begin();
1037 96 : vector<SCROW> aChildMembers(++itr, aMembers.end());
1038 96 : return pChildDim->IsValidEntry(aChildMembers);
1039 : }
1040 : else
1041 570 : return true;
1042 : }
1043 :
1044 172 : void ScDPResultMember::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
1045 : size_t nPos, ScDPInitState& rInitState ,
1046 : bool bInitChild )
1047 : {
1048 : // with LateInit, initialize only those members that have data
1049 172 : if ( pResultData->IsLateInit() )
1050 148 : return;
1051 :
1052 24 : bInitialized = true;
1053 :
1054 24 : if (nPos >= ppDim.size())
1055 20 : return;
1056 :
1057 : // skip child dimension if details are not shown
1058 4 : if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1059 : {
1060 : // Show DataLayout dimention
1061 0 : nMemberStep = 1;
1062 0 : while ( nPos < ppDim.size() )
1063 : {
1064 0 : if ( ppDim[nPos] ->getIsDataLayoutDimension() )
1065 : {
1066 0 : if ( !pChildDimension )
1067 0 : pChildDimension = new ScDPResultDimension( pResultData );
1068 0 : pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState , false );
1069 0 : return;
1070 : }
1071 : else
1072 : { //find next dim
1073 0 : nPos ++;
1074 0 : nMemberStep ++;
1075 : }
1076 : }
1077 0 : bHasHiddenDetails = true; // only if there is a next dimension
1078 0 : return;
1079 : }
1080 :
1081 4 : if ( bInitChild )
1082 : {
1083 4 : pChildDimension = new ScDPResultDimension( pResultData );
1084 4 : pChildDimension->InitFrom(ppDim, ppLev, nPos, rInitState, true);
1085 : }
1086 : }
1087 :
1088 1521 : void ScDPResultMember::LateInitFrom(
1089 : LateInitParams& rParams, const vector<SCROW>& pItemData, size_t nPos, ScDPInitState& rInitState)
1090 : {
1091 : // without LateInit, everything has already been initialized
1092 1521 : if ( !pResultData->IsLateInit() )
1093 32 : return;
1094 :
1095 1489 : bInitialized = true;
1096 :
1097 1489 : if ( rParams.IsEnd( nPos ) /*nPos >= ppDim.size()*/)
1098 : // No next dimension. Bail out.
1099 834 : return;
1100 :
1101 : // skip child dimension if details are not shown
1102 655 : if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1103 : {
1104 : // Show DataLayout dimention
1105 0 : nMemberStep = 1;
1106 0 : while ( !rParams.IsEnd( nPos ) )
1107 : {
1108 0 : if ( rParams.GetDim( nPos ) ->getIsDataLayoutDimension() )
1109 : {
1110 0 : if ( !pChildDimension )
1111 0 : pChildDimension = new ScDPResultDimension( pResultData );
1112 :
1113 : // #i111462# reset InitChild flag only for this child dimension's LateInitFrom call,
1114 : // not for following members of parent dimensions
1115 0 : bool bWasInitChild = rParams.GetInitChild();
1116 0 : rParams.SetInitChild( false );
1117 0 : pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
1118 0 : rParams.SetInitChild( bWasInitChild );
1119 0 : return;
1120 : }
1121 : else
1122 : { //find next dim
1123 0 : nPos ++;
1124 0 : nMemberStep ++;
1125 : }
1126 : }
1127 0 : bHasHiddenDetails = true; // only if there is a next dimension
1128 0 : return;
1129 : }
1130 :
1131 : // LateInitFrom is called several times...
1132 655 : if ( rParams.GetInitChild() )
1133 : {
1134 655 : if ( !pChildDimension )
1135 163 : pChildDimension = new ScDPResultDimension( pResultData );
1136 655 : pChildDimension->LateInitFrom( rParams, pItemData, nPos, rInitState );
1137 : }
1138 : }
1139 :
1140 2445 : bool ScDPResultMember::IsSubTotalInTitle(long nMeasure) const
1141 : {
1142 2445 : bool bRet = false;
1143 3231 : if ( pChildDimension && /*pParentLevel*/GetParentLevel() &&
1144 2643 : /*pParentLevel*/GetParentLevel()->IsOutlineLayout() && /*pParentLevel*/GetParentLevel()->IsSubtotalsAtTop() )
1145 : {
1146 : long nUserSubStart;
1147 0 : long nSubTotals = GetSubTotalCount( &nUserSubStart );
1148 0 : nSubTotals -= nUserSubStart; // visible count
1149 0 : if ( nSubTotals )
1150 : {
1151 0 : if ( nMeasure == SC_DPMEASURE_ALL )
1152 0 : nSubTotals *= pResultData->GetMeasureCount(); // number of subtotals that will be inserted
1153 :
1154 : // only a single subtotal row will be shown in the outline title row
1155 0 : if ( nSubTotals == 1 )
1156 0 : bRet = true;
1157 : }
1158 : }
1159 2445 : return bRet;
1160 : }
1161 :
1162 5570 : long ScDPResultMember::GetSize(long nMeasure) const
1163 : {
1164 5570 : if ( !IsVisible() )
1165 982 : return 0;
1166 4588 : const ScDPLevel* pParentLevel = GetParentLevel();
1167 4588 : long nExtraSpace = 0;
1168 4588 : if ( pParentLevel && pParentLevel->IsAddEmpty() )
1169 0 : ++nExtraSpace;
1170 :
1171 4588 : if ( pChildDimension )
1172 : {
1173 : // outline layout takes up an extra row for the title only if subtotals aren't shown in that row
1174 1126 : if ( pParentLevel && pParentLevel->IsOutlineLayout() && !IsSubTotalInTitle( nMeasure ) )
1175 0 : ++nExtraSpace;
1176 :
1177 1126 : long nSize = pChildDimension->GetSize(nMeasure);
1178 : long nUserSubStart;
1179 1126 : long nUserSubCount = GetSubTotalCount( &nUserSubStart );
1180 1126 : nUserSubCount -= nUserSubStart; // for output size, use visible count
1181 1126 : if ( nUserSubCount )
1182 : {
1183 578 : if ( nMeasure == SC_DPMEASURE_ALL )
1184 4 : nSize += pResultData->GetMeasureCount() * nUserSubCount;
1185 : else
1186 574 : nSize += nUserSubCount;
1187 : }
1188 1126 : return nSize + nExtraSpace;
1189 : }
1190 : else
1191 : {
1192 3462 : if ( nMeasure == SC_DPMEASURE_ALL )
1193 0 : return pResultData->GetMeasureCount() + nExtraSpace;
1194 : else
1195 3462 : return 1 + nExtraSpace;
1196 : }
1197 : }
1198 :
1199 11333 : bool ScDPResultMember::IsVisible() const
1200 : {
1201 11333 : if (!bInitialized)
1202 1418 : return false;
1203 :
1204 9915 : if (!IsValid())
1205 9 : return false;
1206 :
1207 9906 : if (bHasElements)
1208 9906 : return true;
1209 :
1210 : // not initialized -> shouldn't be there at all
1211 : // (allocated only to preserve ordering)
1212 0 : const ScDPLevel* pParentLevel = GetParentLevel();
1213 :
1214 0 : return (pParentLevel && pParentLevel->getShowEmpty());
1215 : }
1216 :
1217 15978 : bool ScDPResultMember::IsValid() const
1218 : {
1219 : // non-Valid members are left out of calculation
1220 :
1221 : // was member set no invisible at the DataPilotSource?
1222 15978 : const ScDPMember* pMemberDesc = GetDPMember();
1223 15978 : if ( pMemberDesc && !pMemberDesc->isVisible() )
1224 15 : return false;
1225 :
1226 15963 : if ( bAutoHidden )
1227 0 : return false;
1228 :
1229 15963 : return true;
1230 : }
1231 :
1232 4 : bool ScDPResultMember::HasHiddenDetails() const
1233 : {
1234 : // bHasHiddenDetails is set only if the "show details" flag is off,
1235 : // and there was a child dimension to skip
1236 :
1237 4 : return bHasHiddenDetails;
1238 : }
1239 :
1240 9365 : long ScDPResultMember::GetSubTotalCount( long* pUserSubStart ) const
1241 : {
1242 9365 : if ( pUserSubStart )
1243 3571 : *pUserSubStart = 0; // default
1244 :
1245 9365 : const ScDPLevel* pParentLevel = GetParentLevel();
1246 :
1247 9365 : if ( bForceSubTotal ) // set if needed for root members
1248 1909 : return 1; // grand total is always "automatic"
1249 7456 : else if ( pParentLevel )
1250 : {
1251 : //! direct access via ScDPLevel
1252 :
1253 6819 : uno::Sequence<sheet::GeneralFunction> aSeq = pParentLevel->getSubTotals();
1254 6819 : long nSequence = aSeq.getLength();
1255 6819 : if ( nSequence && aSeq[0] != sheet::GeneralFunction_AUTO )
1256 : {
1257 : // For manual subtotals, always add "automatic" as first function
1258 : // (used for calculation, but not for display, needed for sorting, see lcl_GetForceFunc)
1259 :
1260 0 : ++nSequence;
1261 0 : if ( pUserSubStart )
1262 0 : *pUserSubStart = 1; // visible subtotals start at 1
1263 : }
1264 6819 : return nSequence;
1265 : }
1266 : else
1267 637 : return 0;
1268 : }
1269 :
1270 1080 : void ScDPResultMember::ProcessData( const vector< SCROW >& aChildMembers, const ScDPResultDimension* pDataDim,
1271 : const vector< SCROW >& aDataMembers, const vector<ScDPValue>& aValues )
1272 : {
1273 1080 : SetHasElements();
1274 :
1275 1080 : if (pChildDimension)
1276 456 : pChildDimension->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
1277 :
1278 1080 : if ( !pDataRoot )
1279 : {
1280 600 : pDataRoot = new ScDPDataMember( pResultData, NULL );
1281 600 : if ( pDataDim )
1282 245 : pDataRoot->InitFrom( pDataDim ); // recursive
1283 : }
1284 :
1285 1080 : ScDPSubTotalState aSubState; // initial state
1286 :
1287 1080 : long nUserSubCount = GetSubTotalCount();
1288 :
1289 : // Calculate at least automatic if no subtotals are selected,
1290 : // show only own values if there's no child dimension (innermost).
1291 1080 : if ( !nUserSubCount || !pChildDimension )
1292 738 : nUserSubCount = 1;
1293 :
1294 1080 : const ScDPLevel* pParentLevel = GetParentLevel();
1295 :
1296 2160 : for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
1297 : {
1298 : // #i68338# if nUserSubCount is 1 (automatic only), don't set nRowSubTotalFunc
1299 1080 : if ( pChildDimension && nUserSubCount > 1 )
1300 : {
1301 0 : aSubState.nRowSubTotalFunc = nUserPos;
1302 0 : aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
1303 : }
1304 :
1305 1080 : pDataRoot->ProcessData( aDataMembers, aValues, aSubState );
1306 : }
1307 1080 : }
1308 :
1309 : /**
1310 : * Parse subtotal string and replace all occurrences of '?' with the caption
1311 : * string. Do ensure that escaped characters are not translated.
1312 : */
1313 0 : static String lcl_parseSubtotalName(const String& rSubStr, const String& rCaption)
1314 : {
1315 0 : String aNewStr;
1316 0 : xub_StrLen n = rSubStr.Len();
1317 0 : bool bEscaped = false;
1318 0 : for (xub_StrLen i = 0; i < n; ++i)
1319 : {
1320 0 : sal_Unicode c = rSubStr.GetChar(i);
1321 0 : if (!bEscaped && c == sal_Unicode('\\'))
1322 : {
1323 0 : bEscaped = true;
1324 0 : continue;
1325 : }
1326 :
1327 0 : if (!bEscaped && c == sal_Unicode('?'))
1328 0 : aNewStr.Append(rCaption);
1329 : else
1330 0 : aNewStr.Append(c);
1331 0 : bEscaped = false;
1332 : }
1333 0 : return aNewStr;
1334 : }
1335 :
1336 635 : void ScDPResultMember::FillMemberResults(
1337 : uno::Sequence<sheet::MemberResult>* pSequences, long& rPos, long nMeasure, bool bRoot,
1338 : const OUString* pMemberName, const OUString* pMemberCaption )
1339 : {
1340 : // IsVisible() test is in ScDPResultDimension::FillMemberResults
1341 : // (not on data layout dimension)
1342 :
1343 635 : if (!pSequences->getLength())
1344 : // empty sequence. Bail out.
1345 635 : return;
1346 :
1347 635 : long nSize = GetSize(nMeasure);
1348 635 : sheet::MemberResult* pArray = pSequences->getArray();
1349 : OSL_ENSURE( rPos+nSize <= pSequences->getLength(), "bumm" );
1350 :
1351 635 : bool bIsNumeric = false;
1352 635 : OUString aName;
1353 635 : if ( pMemberName ) // if pMemberName != NULL, use instead of real member name
1354 : {
1355 14 : aName = *pMemberName;
1356 : }
1357 : else
1358 : {
1359 621 : ScDPItemData aItemData;
1360 621 : FillItemData( aItemData );
1361 621 : if (aParentDimData.mpParentDim)
1362 : {
1363 516 : long nDim = aParentDimData.mpParentDim->GetDimension();
1364 516 : aName = pResultData->GetSource().GetData()->GetFormattedString(nDim, aItemData);
1365 : }
1366 : else
1367 : {
1368 105 : long nDim = -1;
1369 105 : const ScDPMember* pMem = GetDPMember();
1370 105 : if (pMem)
1371 0 : nDim = pMem->GetDim();
1372 105 : aName = pResultData->GetSource().GetData()->GetFormattedString(nDim, aItemData);
1373 : }
1374 :
1375 621 : ScDPItemData::Type eType = aItemData.GetType();
1376 621 : bIsNumeric = eType == ScDPItemData::Value || ScDPItemData::GroupValue;
1377 : }
1378 :
1379 635 : const ScDPDimension* pParentDim = GetParentDim();
1380 635 : if ( bIsNumeric && pParentDim && pResultData->IsNumOrDateGroup( pParentDim->GetDimension() ) )
1381 : {
1382 : // Numeric group dimensions use numeric entries for proper sorting,
1383 : // but the group titles must be output as text.
1384 0 : bIsNumeric = false;
1385 : }
1386 :
1387 1270 : OUString aCaption = aName;
1388 635 : const ScDPMember* pMemberDesc = GetDPMember();
1389 635 : if (pMemberDesc)
1390 : {
1391 530 : const OUString* pLayoutName = pMemberDesc->GetLayoutName();
1392 530 : if (pLayoutName)
1393 : {
1394 0 : aCaption = *pLayoutName;
1395 0 : bIsNumeric = false; // layout name is always non-numeric.
1396 : }
1397 : }
1398 :
1399 635 : if ( pMemberCaption ) // use pMemberCaption if != NULL
1400 14 : aCaption = *pMemberCaption;
1401 635 : if (aCaption.isEmpty())
1402 1 : aCaption = ScGlobal::GetRscString(STR_EMPTYDATA);
1403 :
1404 635 : if (bIsNumeric)
1405 332 : pArray[rPos].Flags |= sheet::MemberResultFlags::NUMERIC;
1406 : else
1407 303 : pArray[rPos].Flags &= ~sheet::MemberResultFlags::NUMERIC;
1408 :
1409 635 : if ( nSize && !bRoot ) // root is overwritten by first dimension
1410 : {
1411 530 : pArray[rPos].Name = aName;
1412 530 : pArray[rPos].Caption = aCaption;
1413 530 : pArray[rPos].Flags |= sheet::MemberResultFlags::HASMEMBER;
1414 :
1415 : // set "continue" flag (removed for subtotals later)
1416 556 : for (long i=1; i<nSize; i++)
1417 26 : pArray[rPos+i].Flags |= sheet::MemberResultFlags::CONTINUE;
1418 : }
1419 :
1420 635 : const ScDPLevel* pParentLevel = GetParentLevel();
1421 635 : long nExtraSpace = 0;
1422 635 : if ( pParentLevel && pParentLevel->IsAddEmpty() )
1423 0 : ++nExtraSpace;
1424 :
1425 635 : bool bTitleLine = false;
1426 635 : if ( pParentLevel && pParentLevel->IsOutlineLayout() )
1427 0 : bTitleLine = true;
1428 :
1429 : // if the subtotals are shown at the top (title row) in outline layout,
1430 : // no extra row for the subtotals is needed
1431 635 : bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
1432 :
1433 635 : bool bHasChild = ( pChildDimension != NULL );
1434 635 : if (bHasChild)
1435 : {
1436 164 : if ( bTitleLine ) // in tabular layout the title is on a separate row
1437 0 : ++rPos; // -> fill child dimension one row below
1438 :
1439 164 : if (bRoot) // same sequence for root member
1440 105 : pChildDimension->FillMemberResults( pSequences, rPos, nMeasure );
1441 : else
1442 59 : pChildDimension->FillMemberResults( pSequences + nMemberStep/*1*/, rPos, nMeasure );
1443 :
1444 164 : if ( bTitleLine ) // title row is included in GetSize, so the following
1445 0 : --rPos; // positions are calculated with the normal values
1446 : }
1447 :
1448 635 : rPos += nSize;
1449 :
1450 : long nUserSubStart;
1451 635 : long nUserSubCount = GetSubTotalCount(&nUserSubStart);
1452 635 : if ( nUserSubCount && pChildDimension && !bSubTotalInTitle )
1453 : {
1454 100 : long nMemberMeasure = nMeasure;
1455 100 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1456 :
1457 100 : rPos -= nSubSize * (nUserSubCount - nUserSubStart); // GetSize includes space for SubTotal
1458 100 : rPos -= nExtraSpace; // GetSize includes the empty line
1459 :
1460 200 : for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
1461 : {
1462 201 : for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
1463 : {
1464 101 : if ( nMeasure == SC_DPMEASURE_ALL )
1465 2 : nMemberMeasure = nSubCount;
1466 :
1467 101 : ScSubTotalFunc eForce = SUBTOTAL_FUNC_NONE;
1468 101 : if (bHasChild)
1469 101 : eForce = lcl_GetForceFunc( pParentLevel, nUserPos );
1470 :
1471 101 : bool bTotalResult = false;
1472 101 : OUString aSubStr = aCaption + " " + pResultData->GetMeasureString(nMemberMeasure, false, eForce, bTotalResult);
1473 :
1474 101 : if (bTotalResult)
1475 : {
1476 99 : if (pMemberDesc)
1477 : {
1478 : // single data field layout.
1479 0 : const OUString* pSubtotalName = pParentDim->GetSubtotalName();
1480 0 : if (pSubtotalName)
1481 0 : aSubStr = lcl_parseSubtotalName(*pSubtotalName, aCaption);
1482 0 : pArray[rPos].Flags &= ~sheet::MemberResultFlags::GRANDTOTAL;
1483 : }
1484 : else
1485 : {
1486 : // root member - subtotal (grand total?) for multi-data field layout.
1487 99 : const OUString* pGrandTotalName = pResultData->GetSource().GetGrandTotalName();
1488 99 : if (pGrandTotalName)
1489 0 : aSubStr = *pGrandTotalName;
1490 99 : pArray[rPos].Flags |= sheet::MemberResultFlags::GRANDTOTAL;
1491 : }
1492 : }
1493 :
1494 101 : pArray[rPos].Name = aName;
1495 101 : pArray[rPos].Caption = aSubStr;
1496 101 : pArray[rPos].Flags = ( pArray[rPos].Flags |
1497 101 : ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL) ) &
1498 101 : ~sheet::MemberResultFlags::CONTINUE;
1499 :
1500 101 : if ( nMeasure == SC_DPMEASURE_ALL )
1501 : {
1502 : // data layout dimension is (direct/indirect) child of this.
1503 : // data layout dimension must have name for all entries.
1504 :
1505 2 : uno::Sequence<sheet::MemberResult>* pLayoutSeq = pSequences;
1506 2 : if (!bRoot)
1507 0 : ++pLayoutSeq;
1508 2 : ScDPResultDimension* pLayoutDim = pChildDimension;
1509 6 : while ( pLayoutDim && !pLayoutDim->IsDataLayout() )
1510 : {
1511 2 : pLayoutDim = pLayoutDim->GetFirstChildDimension();
1512 2 : ++pLayoutSeq;
1513 : }
1514 2 : if ( pLayoutDim )
1515 : {
1516 2 : sheet::MemberResult* pLayoutArray = pLayoutSeq->getArray();
1517 2 : pLayoutArray[rPos].Name = pResultData->GetMeasureDimensionName(nMemberMeasure);
1518 : }
1519 : }
1520 :
1521 101 : rPos += 1;
1522 101 : }
1523 : }
1524 :
1525 100 : rPos += nExtraSpace; // add again (subtracted above)
1526 635 : }
1527 : }
1528 :
1529 407 : void ScDPResultMember::FillDataResults(
1530 : const ScDPResultMember* pRefMember,
1531 : ScDPResultFilterContext& rFilterCxt, uno::Sequence<uno::Sequence<sheet::DataResult> >& rSequence,
1532 : long nMeasure) const
1533 : {
1534 407 : boost::scoped_ptr<FilterStack> pFilterStack;
1535 407 : const ScDPMember* pDPMember = GetDPMember();
1536 407 : if (pDPMember)
1537 : {
1538 : // Root result has no corresponding DP member. Only take the non-root results.
1539 329 : ScDPItemData aItem;
1540 329 : pDPMember->FillItemData(aItem);
1541 329 : pFilterStack.reset(new FilterStack(rFilterCxt.maFilters));
1542 329 : pFilterStack->pushDimValue(aItem);
1543 : }
1544 :
1545 : // IsVisible() test is in ScDPResultDimension::FillDataResults
1546 : // (not on data layout dimension)
1547 407 : const ScDPLevel* pParentLevel = GetParentLevel();
1548 407 : long nStartRow = rFilterCxt.mnRow;
1549 :
1550 407 : long nExtraSpace = 0;
1551 407 : if ( pParentLevel && pParentLevel->IsAddEmpty() )
1552 0 : ++nExtraSpace;
1553 :
1554 407 : bool bTitleLine = false;
1555 407 : if ( pParentLevel && pParentLevel->IsOutlineLayout() )
1556 0 : bTitleLine = true;
1557 :
1558 407 : bool bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
1559 :
1560 407 : bool bHasChild = ( pChildDimension != NULL );
1561 407 : if (bHasChild)
1562 : {
1563 107 : if ( bTitleLine ) // in tabular layout the title is on a separate row
1564 0 : ++rFilterCxt.mnRow; // -> fill child dimension one row below
1565 :
1566 107 : long nOldRow = rFilterCxt.mnRow;
1567 107 : pChildDimension->FillDataResults(pRefMember, rFilterCxt, rSequence, nMeasure);
1568 107 : rFilterCxt.mnRow = nOldRow; // Revert to the original row before the call.
1569 :
1570 107 : rFilterCxt.mnRow += GetSize( nMeasure );
1571 :
1572 107 : if ( bTitleLine ) // title row is included in GetSize, so the following
1573 0 : --rFilterCxt.mnRow; // positions are calculated with the normal values
1574 : }
1575 :
1576 : long nUserSubStart;
1577 407 : long nUserSubCount = GetSubTotalCount(&nUserSubStart);
1578 407 : if ( nUserSubCount || !bHasChild )
1579 : {
1580 : // Calculate at least automatic if no subtotals are selected,
1581 : // show only own values if there's no child dimension (innermost).
1582 360 : if ( !nUserSubCount || !bHasChild )
1583 : {
1584 300 : nUserSubCount = 1;
1585 300 : nUserSubStart = 0;
1586 : }
1587 :
1588 360 : long nMemberMeasure = nMeasure;
1589 360 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1590 360 : if (bHasChild)
1591 : {
1592 60 : rFilterCxt.mnRow -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
1593 60 : rFilterCxt.mnRow -= nExtraSpace; // GetSize includes the empty line
1594 : }
1595 :
1596 360 : long nMoveSubTotal = 0;
1597 360 : if ( bSubTotalInTitle )
1598 : {
1599 0 : nMoveSubTotal = rFilterCxt.mnRow - nStartRow; // force to first (title) row
1600 0 : rFilterCxt.mnRow = nStartRow;
1601 : }
1602 :
1603 360 : if ( pDataRoot )
1604 : {
1605 359 : ScDPSubTotalState aSubState; // initial state
1606 :
1607 718 : for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
1608 : {
1609 359 : if ( bHasChild && nUserSubCount > 1 )
1610 : {
1611 0 : aSubState.nRowSubTotalFunc = nUserPos;
1612 0 : aSubState.eRowForce = lcl_GetForceFunc( /*pParentLevel*/GetParentLevel() , nUserPos );
1613 : }
1614 :
1615 719 : for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
1616 : {
1617 360 : if ( nMeasure == SC_DPMEASURE_ALL )
1618 2 : nMemberMeasure = nSubCount;
1619 358 : else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
1620 3 : nMemberMeasure = SC_DPMEASURE_ALL;
1621 :
1622 : OSL_ENSURE( rFilterCxt.mnRow < rSequence.getLength(), "bumm" );
1623 360 : uno::Sequence<sheet::DataResult>& rSubSeq = rSequence.getArray()[rFilterCxt.mnRow];
1624 360 : rFilterCxt.mnCol = 0;
1625 360 : if (pRefMember->IsVisible())
1626 360 : pDataRoot->FillDataRow(pRefMember, rFilterCxt, rSubSeq, nMemberMeasure, bHasChild, aSubState);
1627 :
1628 360 : rFilterCxt.mnRow += 1;
1629 : }
1630 : }
1631 : }
1632 : else
1633 1 : rFilterCxt.mnRow += nSubSize * ( nUserSubCount - nUserSubStart ); // empty rows occur when ShowEmpty is true
1634 :
1635 : // add extra space again if subtracted from GetSize above,
1636 : // add to own size if no children
1637 360 : rFilterCxt.mnRow += nExtraSpace;
1638 360 : rFilterCxt.mnRow += nMoveSubTotal;
1639 407 : }
1640 407 : }
1641 :
1642 413 : void ScDPResultMember::UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const
1643 : {
1644 : // IsVisible() test is in ScDPResultDimension::FillDataResults
1645 : // (not on data layout dimension)
1646 :
1647 413 : bool bHasChild = ( pChildDimension != NULL );
1648 :
1649 413 : long nUserSubCount = GetSubTotalCount();
1650 :
1651 : // process subtotals even if not shown
1652 :
1653 : // Calculate at least automatic if no subtotals are selected,
1654 : // show only own values if there's no child dimension (innermost).
1655 413 : if (!nUserSubCount || !bHasChild)
1656 352 : nUserSubCount = 1;
1657 :
1658 413 : long nMemberMeasure = nMeasure;
1659 413 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1660 :
1661 413 : if (pDataRoot)
1662 : {
1663 412 : ScDPSubTotalState aSubState; // initial state
1664 :
1665 824 : for (long nUserPos = 0; nUserPos < nUserSubCount; ++nUserPos) // including hidden "automatic"
1666 : {
1667 412 : if (bHasChild && nUserSubCount > 1)
1668 : {
1669 0 : aSubState.nRowSubTotalFunc = nUserPos;
1670 0 : aSubState.eRowForce = lcl_GetForceFunc(GetParentLevel(), nUserPos);
1671 : }
1672 :
1673 831 : for (long nSubCount = 0; nSubCount < nSubSize; ++nSubCount)
1674 : {
1675 419 : if (nMeasure == SC_DPMEASURE_ALL)
1676 14 : nMemberMeasure = nSubCount;
1677 405 : else if (pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL)
1678 3 : nMemberMeasure = SC_DPMEASURE_ALL;
1679 :
1680 419 : pDataRoot->UpdateDataRow(pRefMember, nMemberMeasure, bHasChild, aSubState);
1681 : }
1682 : }
1683 : }
1684 :
1685 413 : if (bHasChild) // child dimension must be processed last, so the column total is known
1686 : {
1687 108 : pChildDimension->UpdateDataResults( pRefMember, nMeasure );
1688 : }
1689 413 : }
1690 :
1691 401 : void ScDPResultMember::SortMembers( ScDPResultMember* pRefMember )
1692 : {
1693 401 : bool bHasChild = ( pChildDimension != NULL );
1694 401 : if (bHasChild)
1695 107 : pChildDimension->SortMembers( pRefMember ); // sorting is done at the dimension
1696 :
1697 401 : if ( IsRoot() && pDataRoot )
1698 : {
1699 : // use the row root member to sort columns
1700 : // sub total count is always 1
1701 :
1702 77 : pDataRoot->SortMembers( pRefMember );
1703 : }
1704 401 : }
1705 :
1706 6 : void ScDPResultMember::DoAutoShow( ScDPResultMember* pRefMember )
1707 : {
1708 6 : bool bHasChild = ( pChildDimension != NULL );
1709 6 : if (bHasChild)
1710 1 : pChildDimension->DoAutoShow( pRefMember ); // sorting is done at the dimension
1711 :
1712 6 : if ( IsRoot()&& pDataRoot )
1713 : {
1714 : // use the row root member to sort columns
1715 : // sub total count is always 1
1716 :
1717 1 : pDataRoot->DoAutoShow( pRefMember );
1718 : }
1719 6 : }
1720 :
1721 12 : void ScDPResultMember::ResetResults()
1722 : {
1723 12 : if (pDataRoot)
1724 11 : pDataRoot->ResetResults();
1725 :
1726 12 : if (pChildDimension)
1727 2 : pChildDimension->ResetResults();
1728 12 : }
1729 :
1730 407 : void ScDPResultMember::UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
1731 : ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
1732 : {
1733 : // IsVisible() test is in ScDPResultDimension::FillDataResults
1734 : // (not on data layout dimension)
1735 :
1736 407 : rTotals.SetInColRoot( IsRoot() );
1737 :
1738 407 : bool bHasChild = ( pChildDimension != NULL );
1739 :
1740 407 : long nUserSubCount = GetSubTotalCount();
1741 : //if ( nUserSubCount || !bHasChild )
1742 : {
1743 : // Calculate at least automatic if no subtotals are selected,
1744 : // show only own values if there's no child dimension (innermost).
1745 407 : if ( !nUserSubCount || !bHasChild )
1746 347 : nUserSubCount = 1;
1747 :
1748 407 : long nMemberMeasure = nMeasure;
1749 407 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
1750 :
1751 407 : if ( pDataRoot )
1752 : {
1753 406 : ScDPSubTotalState aSubState; // initial state
1754 :
1755 812 : for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
1756 : {
1757 406 : if ( bHasChild && nUserSubCount > 1 )
1758 : {
1759 0 : aSubState.nRowSubTotalFunc = nUserPos;
1760 0 : aSubState.eRowForce = lcl_GetForceFunc(GetParentLevel(), nUserPos);
1761 : }
1762 :
1763 819 : for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
1764 : {
1765 413 : if ( nMeasure == SC_DPMEASURE_ALL )
1766 14 : nMemberMeasure = nSubCount;
1767 399 : else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
1768 3 : nMemberMeasure = SC_DPMEASURE_ALL;
1769 :
1770 413 : if (pRefMember->IsVisible())
1771 : pDataRoot->UpdateRunningTotals(
1772 413 : pRefMember, nMemberMeasure, bHasChild, aSubState, rRunning, rTotals, *this);
1773 : }
1774 : }
1775 : }
1776 : }
1777 :
1778 407 : if (bHasChild) // child dimension must be processed last, so the column total is known
1779 : {
1780 107 : pChildDimension->UpdateRunningTotals( pRefMember, nMeasure, rRunning, rTotals );
1781 : }
1782 407 : }
1783 :
1784 : #if DEBUG_PIVOT_TABLE
1785 : void ScDPResultMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
1786 : {
1787 : lcl_DumpRow( OUString("ScDPResultMember"), GetName(), NULL, pDoc, rPos );
1788 : SCROW nStartRow = rPos.Row();
1789 :
1790 : if (pDataRoot)
1791 : pDataRoot->DumpState( pRefMember, pDoc, rPos );
1792 :
1793 : if (pChildDimension)
1794 : pChildDimension->DumpState( pRefMember, pDoc, rPos );
1795 :
1796 : lcl_Indent( pDoc, nStartRow, rPos );
1797 : }
1798 :
1799 : void ScDPResultMember::Dump(int nIndent) const
1800 : {
1801 : std::string aIndent(nIndent*2, ' ');
1802 : std::cout << aIndent << "-- result member '" << GetName() << "'" << std::endl;
1803 :
1804 : std::cout << aIndent << " column totals" << std::endl;
1805 : for (const ScDPAggData* p = &aColTotal; p; p = p->GetExistingChild())
1806 : p->Dump(nIndent+1);
1807 :
1808 : if (pChildDimension)
1809 : pChildDimension->Dump(nIndent+1);
1810 :
1811 : if (pDataRoot)
1812 : {
1813 : std::cout << aIndent << " data root" << std::endl;
1814 : pDataRoot->Dump(nIndent+1);
1815 : }
1816 : }
1817 : #endif
1818 :
1819 5 : ScDPAggData* ScDPResultMember::GetColTotal( long nMeasure ) const
1820 : {
1821 5 : return lcl_GetChildTotal( const_cast<ScDPAggData*>(&aColTotal), nMeasure );
1822 : }
1823 :
1824 5586 : void ScDPResultMember::FillVisibilityData(ScDPResultVisibilityData& rData) const
1825 : {
1826 5586 : if (pChildDimension)
1827 1596 : pChildDimension->FillVisibilityData(rData);
1828 5586 : }
1829 :
1830 : // -----------------------------------------------------------------------
1831 :
1832 1958 : ScDPDataMember::ScDPDataMember( const ScDPResultData* pData, const ScDPResultMember* pRes ) :
1833 : pResultData( pData ),
1834 : pResultMember( pRes ),
1835 1958 : pChildDimension( NULL )
1836 : {
1837 : // pResultMember is 0 for root members
1838 1958 : }
1839 :
1840 3916 : ScDPDataMember::~ScDPDataMember()
1841 : {
1842 1958 : delete pChildDimension;
1843 1958 : }
1844 :
1845 0 : OUString ScDPDataMember::GetName() const
1846 : {
1847 0 : if (pResultMember)
1848 0 : return pResultMember->GetName();
1849 : else
1850 0 : return EMPTY_OUSTRING;
1851 : }
1852 :
1853 0 : bool ScDPDataMember::IsVisible() const
1854 : {
1855 0 : if (pResultMember)
1856 0 : return pResultMember->IsVisible();
1857 : else
1858 0 : return false;
1859 : }
1860 :
1861 1330 : bool ScDPDataMember::IsNamedItem( SCROW nRow ) const
1862 : {
1863 1330 : if (pResultMember)
1864 1330 : return pResultMember->IsNamedItem(nRow);
1865 : else
1866 0 : return false;
1867 : }
1868 :
1869 0 : bool ScDPDataMember::HasHiddenDetails() const
1870 : {
1871 0 : if (pResultMember)
1872 0 : return pResultMember->HasHiddenDetails();
1873 : else
1874 0 : return false;
1875 : }
1876 :
1877 296 : void ScDPDataMember::InitFrom( const ScDPResultDimension* pDim )
1878 : {
1879 296 : if ( !pChildDimension )
1880 296 : pChildDimension = new ScDPDataDimension(pResultData);
1881 296 : pChildDimension->InitFrom(pDim);
1882 296 : }
1883 :
1884 : const long SC_SUBTOTALPOS_AUTO = -1; // default
1885 : const long SC_SUBTOTALPOS_SKIP = -2; // don't use
1886 :
1887 7658 : static long lcl_GetSubTotalPos( const ScDPSubTotalState& rSubState )
1888 : {
1889 7658 : if ( rSubState.nColSubTotalFunc >= 0 && rSubState.nRowSubTotalFunc >= 0 &&
1890 0 : rSubState.nColSubTotalFunc != rSubState.nRowSubTotalFunc )
1891 : {
1892 : // #i68338# don't return the same index for different combinations (leading to repeated updates),
1893 : // return a "don't use" value instead
1894 :
1895 0 : return SC_SUBTOTALPOS_SKIP;
1896 : }
1897 :
1898 7658 : long nRet = SC_SUBTOTALPOS_AUTO;
1899 7658 : if ( rSubState.nColSubTotalFunc >= 0 ) nRet = rSubState.nColSubTotalFunc;
1900 7658 : if ( rSubState.nRowSubTotalFunc >= 0 ) nRet = rSubState.nRowSubTotalFunc;
1901 7658 : return nRet;
1902 : }
1903 :
1904 1576 : void ScDPDataMember::UpdateValues( const vector<ScDPValue>& aValues, const ScDPSubTotalState& rSubState )
1905 : {
1906 : //! find out how many and which subtotals are used
1907 :
1908 1576 : ScDPAggData* pAgg = &aAggregate;
1909 :
1910 1576 : long nSubPos = lcl_GetSubTotalPos(rSubState);
1911 1576 : if (nSubPos == SC_SUBTOTALPOS_SKIP)
1912 1576 : return;
1913 1576 : if (nSubPos > 0)
1914 : {
1915 0 : long nSkip = nSubPos * pResultData->GetMeasureCount();
1916 0 : for (long i=0; i<nSkip; i++)
1917 0 : pAgg = pAgg->GetChild(); // created if not there
1918 : }
1919 :
1920 1576 : size_t nCount = aValues.size();
1921 3176 : for (size_t nPos = 0; nPos < nCount; ++nPos)
1922 : {
1923 1600 : pAgg->Update(aValues[nPos], pResultData->GetMeasureFunction(nPos), rSubState);
1924 1600 : pAgg = pAgg->GetChild();
1925 : }
1926 : }
1927 :
1928 1576 : void ScDPDataMember::ProcessData( const vector< SCROW >& aChildMembers, const vector<ScDPValue>& aValues,
1929 : const ScDPSubTotalState& rSubState )
1930 : {
1931 1576 : if ( pResultData->IsLateInit() && !pChildDimension && pResultMember && pResultMember->GetChildDimension() )
1932 : {
1933 : // if this DataMember doesn't have a child dimension because the ResultMember's
1934 : // child dimension wasn't there yet during this DataMembers's creation,
1935 : // create the child dimension now
1936 51 : InitFrom( pResultMember->GetChildDimension() );
1937 : }
1938 :
1939 1576 : long nUserSubCount = pResultMember ? pResultMember->GetSubTotalCount() : 0;
1940 :
1941 : // Calculate at least automatic if no subtotals are selected,
1942 : // show only own values if there's no child dimension (innermost).
1943 1576 : if ( !nUserSubCount || !pChildDimension )
1944 1576 : nUserSubCount = 1;
1945 :
1946 1576 : ScDPSubTotalState aLocalSubState = rSubState; // keep row state, modify column
1947 3152 : for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
1948 : {
1949 1576 : if ( pChildDimension && nUserSubCount > 1 )
1950 : {
1951 0 : const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
1952 0 : aLocalSubState.nColSubTotalFunc = nUserPos;
1953 0 : aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
1954 : }
1955 :
1956 1576 : UpdateValues( aValues, aLocalSubState );
1957 : }
1958 :
1959 1576 : if (pChildDimension)
1960 496 : pChildDimension->ProcessData( aChildMembers, aValues, rSubState ); // with unmodified subtotal state
1961 1576 : }
1962 :
1963 1304 : bool ScDPDataMember::HasData( long nMeasure, const ScDPSubTotalState& rSubState ) const
1964 : {
1965 1304 : if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
1966 0 : rSubState.eColForce != rSubState.eRowForce )
1967 0 : return false;
1968 :
1969 : // HasData can be different between measures!
1970 :
1971 1304 : const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
1972 1304 : if (!pAgg)
1973 0 : return false; //! error?
1974 :
1975 1304 : return pAgg->HasData();
1976 : }
1977 :
1978 680 : bool ScDPDataMember::HasError( long nMeasure, const ScDPSubTotalState& rSubState ) const
1979 : {
1980 680 : const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
1981 680 : if (!pAgg)
1982 0 : return true;
1983 :
1984 680 : return pAgg->HasError();
1985 : }
1986 :
1987 680 : double ScDPDataMember::GetAggregate( long nMeasure, const ScDPSubTotalState& rSubState ) const
1988 : {
1989 680 : const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
1990 680 : if (!pAgg)
1991 0 : return DBL_MAX; //! error?
1992 :
1993 680 : return pAgg->GetResult();
1994 : }
1995 :
1996 3408 : ScDPAggData* ScDPDataMember::GetAggData( long nMeasure, const ScDPSubTotalState& rSubState )
1997 : {
1998 : OSL_ENSURE( nMeasure >= 0, "GetAggData: no measure" );
1999 :
2000 3408 : ScDPAggData* pAgg = &aAggregate;
2001 3408 : long nSkip = nMeasure;
2002 3408 : long nSubPos = lcl_GetSubTotalPos(rSubState);
2003 3408 : if (nSubPos == SC_SUBTOTALPOS_SKIP)
2004 0 : return NULL;
2005 3408 : if (nSubPos > 0)
2006 0 : nSkip += nSubPos * pResultData->GetMeasureCount();
2007 :
2008 3446 : for ( long nPos=0; nPos<nSkip; nPos++ )
2009 38 : pAgg = pAgg->GetChild(); //! need to create children here?
2010 :
2011 3408 : return pAgg;
2012 : }
2013 :
2014 2674 : const ScDPAggData* ScDPDataMember::GetConstAggData( long nMeasure, const ScDPSubTotalState& rSubState ) const
2015 : {
2016 : OSL_ENSURE( nMeasure >= 0, "GetConstAggData: no measure" );
2017 :
2018 2674 : const ScDPAggData* pAgg = &aAggregate;
2019 2674 : long nSkip = nMeasure;
2020 2674 : long nSubPos = lcl_GetSubTotalPos(rSubState);
2021 2674 : if (nSubPos == SC_SUBTOTALPOS_SKIP)
2022 0 : return NULL;
2023 2674 : if (nSubPos > 0)
2024 0 : nSkip += nSubPos * pResultData->GetMeasureCount();
2025 :
2026 2704 : for ( long nPos=0; nPos<nSkip; nPos++ )
2027 : {
2028 30 : pAgg = pAgg->GetExistingChild();
2029 30 : if (!pAgg)
2030 0 : return NULL;
2031 : }
2032 :
2033 2674 : return pAgg;
2034 : }
2035 :
2036 1403 : void ScDPDataMember::FillDataRow(
2037 : const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
2038 : uno::Sequence<sheet::DataResult>& rSequence, long nMeasure, bool bIsSubTotalRow,
2039 : const ScDPSubTotalState& rSubState) const
2040 : {
2041 1403 : boost::scoped_ptr<FilterStack> pFilterStack;
2042 1403 : if (pResultMember)
2043 : {
2044 : // Topmost data member (pResultMember=NULL) doesn't need to be handled
2045 : // since its immediate parent result member is linked to the same
2046 : // dimension member.
2047 1043 : ScDPItemData aItem;
2048 1043 : const ScDPMember* pDPMember = pResultMember->GetDPMember();
2049 1043 : if (pDPMember)
2050 1043 : pDPMember->FillItemData(aItem);
2051 1043 : pFilterStack.reset(new FilterStack(rFilterCxt.maFilters));
2052 1043 : pFilterStack->pushDimValue(aItem);
2053 : }
2054 :
2055 : OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2056 :
2057 1403 : long nStartCol = rFilterCxt.mnCol;
2058 :
2059 1403 : const ScDPDataDimension* pDataChild = GetChildDimension();
2060 1403 : const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2061 :
2062 1403 : const ScDPLevel* pRefParentLevel = const_cast<ScDPResultMember*>(pRefMember)->GetParentLevel();
2063 :
2064 1403 : long nExtraSpace = 0;
2065 1403 : if ( pRefParentLevel && pRefParentLevel->IsAddEmpty() )
2066 0 : ++nExtraSpace;
2067 :
2068 1403 : bool bTitleLine = false;
2069 1403 : if ( pRefParentLevel && pRefParentLevel->IsOutlineLayout() )
2070 0 : bTitleLine = true;
2071 :
2072 1403 : bool bSubTotalInTitle = pRefMember->IsSubTotalInTitle( nMeasure );
2073 :
2074 : // leave space for children even if the DataMember hasn't been initialized
2075 : // (pDataChild is null then, this happens when no values for it are in this row)
2076 1403 : bool bHasChild = ( pRefChild != NULL );
2077 :
2078 1403 : if ( bHasChild )
2079 : {
2080 317 : if ( bTitleLine ) // in tabular layout the title is on a separate column
2081 0 : ++rFilterCxt.mnCol; // -> fill child dimension one column below
2082 :
2083 317 : if ( pDataChild )
2084 : {
2085 257 : long nOldCol = rFilterCxt.mnCol;
2086 257 : pDataChild->FillDataRow(pRefChild, rFilterCxt, rSequence, nMeasure, bIsSubTotalRow, rSubState);
2087 257 : rFilterCxt.mnCol = nOldCol; // Revert to the old column value before the call.
2088 : }
2089 317 : rFilterCxt.mnCol += (sal_uInt16)pRefMember->GetSize( nMeasure );
2090 :
2091 317 : if ( bTitleLine ) // title column is included in GetSize, so the following
2092 0 : --rFilterCxt.mnCol; // positions are calculated with the normal values
2093 : }
2094 :
2095 : long nUserSubStart;
2096 1403 : long nUserSubCount = pRefMember->GetSubTotalCount(&nUserSubStart);
2097 1403 : if ( nUserSubCount || !bHasChild )
2098 : {
2099 : // Calculate at least automatic if no subtotals are selected,
2100 : // show only own values if there's no child dimension (innermost).
2101 1304 : if ( !nUserSubCount || !bHasChild )
2102 : {
2103 1086 : nUserSubCount = 1;
2104 1086 : nUserSubStart = 0;
2105 : }
2106 :
2107 1304 : ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
2108 :
2109 1304 : long nMemberMeasure = nMeasure;
2110 1304 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
2111 1304 : if (bHasChild)
2112 : {
2113 218 : rFilterCxt.mnCol -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
2114 218 : rFilterCxt.mnCol -= nExtraSpace; // GetSize includes the empty line
2115 : }
2116 :
2117 1304 : long nMoveSubTotal = 0;
2118 1304 : if ( bSubTotalInTitle )
2119 : {
2120 0 : nMoveSubTotal = rFilterCxt.mnCol - nStartCol; // force to first (title) column
2121 0 : rFilterCxt.mnCol = nStartCol;
2122 : }
2123 :
2124 2608 : for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
2125 : {
2126 1304 : if ( pChildDimension && nUserSubCount > 1 )
2127 : {
2128 0 : const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
2129 0 : aLocalSubState.nColSubTotalFunc = nUserPos;
2130 0 : aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
2131 : }
2132 :
2133 2608 : for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
2134 : {
2135 1304 : if ( nMeasure == SC_DPMEASURE_ALL )
2136 0 : nMemberMeasure = nSubCount;
2137 :
2138 : OSL_ENSURE( rFilterCxt.mnCol < rSequence.getLength(), "bumm" );
2139 1304 : sheet::DataResult& rRes = rSequence.getArray()[rFilterCxt.mnCol];
2140 :
2141 1304 : if ( HasData( nMemberMeasure, aLocalSubState ) )
2142 : {
2143 680 : if ( HasError( nMemberMeasure, aLocalSubState ) )
2144 : {
2145 0 : rRes.Value = 0;
2146 0 : rRes.Flags |= sheet::DataResultFlags::ERROR;
2147 : }
2148 : else
2149 : {
2150 680 : rRes.Value = GetAggregate( nMemberMeasure, aLocalSubState );
2151 680 : rRes.Flags |= sheet::DataResultFlags::HASDATA;
2152 : }
2153 : }
2154 :
2155 1304 : if ( bHasChild || bIsSubTotalRow )
2156 416 : rRes.Flags |= sheet::DataResultFlags::SUBTOTAL;
2157 :
2158 1304 : rFilterCxt.maFilterSet.add(rFilterCxt.maFilters, rFilterCxt.mnCol, rFilterCxt.mnRow, rRes.Value);
2159 1304 : rFilterCxt.mnCol += 1;
2160 : }
2161 : }
2162 :
2163 : // add extra space again if subtracted from GetSize above,
2164 : // add to own size if no children
2165 1304 : rFilterCxt.mnCol += nExtraSpace;
2166 1304 : rFilterCxt.mnCol += nMoveSubTotal;
2167 1403 : }
2168 1403 : }
2169 :
2170 1807 : void ScDPDataMember::UpdateDataRow(
2171 : const ScDPResultMember* pRefMember, long nMeasure, bool bIsSubTotalRow,
2172 : const ScDPSubTotalState& rSubState )
2173 : {
2174 : OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2175 :
2176 : // Calculate must be called even if not visible (for use as reference value)
2177 1807 : const ScDPDataDimension* pDataChild = GetChildDimension();
2178 1807 : const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2179 :
2180 : // leave space for children even if the DataMember hasn't been initialized
2181 : // (pDataChild is null then, this happens when no values for it are in this row)
2182 1807 : bool bHasChild = ( pRefChild != NULL );
2183 :
2184 : // process subtotals even if not shown
2185 1807 : long nUserSubCount = pRefMember->GetSubTotalCount();
2186 :
2187 : // Calculate at least automatic if no subtotals are selected,
2188 : // show only own values if there's no child dimension (innermost).
2189 1807 : if ( !nUserSubCount || !bHasChild )
2190 1559 : nUserSubCount = 1;
2191 :
2192 1807 : ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
2193 :
2194 1807 : long nMemberMeasure = nMeasure;
2195 1807 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
2196 :
2197 3614 : for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
2198 : {
2199 1807 : if ( pChildDimension && nUserSubCount > 1 )
2200 : {
2201 0 : const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
2202 0 : aLocalSubState.nColSubTotalFunc = nUserPos;
2203 0 : aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
2204 : }
2205 :
2206 3617 : for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
2207 : {
2208 1810 : if ( nMeasure == SC_DPMEASURE_ALL )
2209 6 : nMemberMeasure = nSubCount;
2210 :
2211 : // update data...
2212 1810 : ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
2213 1810 : if (pAggData)
2214 : {
2215 : //! aLocalSubState?
2216 1810 : ScSubTotalFunc eFunc = pResultData->GetMeasureFunction( nMemberMeasure );
2217 1810 : sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
2218 1810 : sal_Int32 eRefType = aReferenceValue.ReferenceType;
2219 :
2220 : // calculate the result first - for all members, regardless of reference value
2221 1810 : pAggData->Calculate( eFunc, aLocalSubState );
2222 :
2223 1810 : if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
2224 1800 : eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
2225 : eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
2226 : {
2227 : // copy the result into auxiliary value, so differences can be
2228 : // calculated in any order
2229 15 : pAggData->SetAuxiliary( pAggData->GetResult() );
2230 1810 : }
2231 : // column/row percentage/index is now in UpdateRunningTotals, so it doesn't disturb sorting
2232 : }
2233 : }
2234 : }
2235 :
2236 1807 : if ( bHasChild ) // child dimension must be processed last, so the row total is known
2237 : {
2238 422 : if ( pDataChild )
2239 302 : pDataChild->UpdateDataRow( pRefChild, nMeasure, bIsSubTotalRow, rSubState );
2240 : }
2241 1807 : }
2242 :
2243 277 : void ScDPDataMember::SortMembers( ScDPResultMember* pRefMember )
2244 : {
2245 : OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2246 :
2247 277 : if ( pRefMember->IsVisible() ) //! here or in ScDPDataDimension ???
2248 : {
2249 277 : ScDPDataDimension* pDataChild = GetChildDimension();
2250 277 : ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2251 277 : if ( pRefChild && pDataChild )
2252 57 : pDataChild->SortMembers( pRefChild ); // sorting is done at the dimension
2253 : }
2254 277 : }
2255 :
2256 6 : void ScDPDataMember::DoAutoShow( ScDPResultMember* pRefMember )
2257 : {
2258 : OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2259 :
2260 6 : if ( pRefMember->IsVisible() ) //! here or in ScDPDataDimension ???
2261 : {
2262 6 : ScDPDataDimension* pDataChild = GetChildDimension();
2263 6 : ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2264 6 : if ( pRefChild && pDataChild )
2265 1 : pDataChild->DoAutoShow( pRefChild ); // sorting is done at the dimension
2266 : }
2267 6 : }
2268 :
2269 41 : void ScDPDataMember::ResetResults()
2270 : {
2271 41 : aAggregate.Reset();
2272 :
2273 41 : ScDPDataDimension* pDataChild = GetChildDimension();
2274 41 : if ( pDataChild )
2275 6 : pDataChild->ResetResults();
2276 41 : }
2277 :
2278 1591 : void ScDPDataMember::UpdateRunningTotals(
2279 : const ScDPResultMember* pRefMember, long nMeasure, bool bIsSubTotalRow,
2280 : const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
2281 : ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent )
2282 : {
2283 : OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
2284 :
2285 1591 : const ScDPDataDimension* pDataChild = GetChildDimension();
2286 1591 : const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2287 :
2288 1591 : bool bIsRoot = ( pResultMember == NULL || pResultMember->GetParentLevel() == NULL );
2289 :
2290 : // leave space for children even if the DataMember hasn't been initialized
2291 : // (pDataChild is null then, this happens when no values for it are in this row)
2292 1591 : bool bHasChild = ( pRefChild != NULL );
2293 :
2294 1591 : long nUserSubCount = pRefMember->GetSubTotalCount();
2295 : {
2296 : // Calculate at least automatic if no subtotals are selected,
2297 : // show only own values if there's no child dimension (innermost).
2298 1591 : if ( !nUserSubCount || !bHasChild )
2299 1349 : nUserSubCount = 1;
2300 :
2301 1591 : ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
2302 :
2303 1591 : long nMemberMeasure = nMeasure;
2304 1591 : long nSubSize = pResultData->GetCountForMeasure(nMeasure);
2305 :
2306 3182 : for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
2307 : {
2308 1591 : if ( pChildDimension && nUserSubCount > 1 )
2309 : {
2310 0 : const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
2311 0 : aLocalSubState.nColSubTotalFunc = nUserPos;
2312 0 : aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
2313 : }
2314 :
2315 3185 : for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
2316 : {
2317 1594 : if ( nMeasure == SC_DPMEASURE_ALL )
2318 6 : nMemberMeasure = nSubCount;
2319 :
2320 : // update data...
2321 1594 : ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
2322 1594 : if (pAggData)
2323 : {
2324 : //! aLocalSubState?
2325 1594 : sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
2326 1594 : sal_Int32 eRefType = aReferenceValue.ReferenceType;
2327 :
2328 1594 : if ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL ||
2329 1584 : eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
2330 1579 : eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
2331 : eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
2332 : {
2333 20 : bool bRunningTotal = ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL );
2334 : bool bRelative =
2335 20 : ( aReferenceValue.ReferenceItemType != sheet::DataPilotFieldReferenceItemType::NAMED && !bRunningTotal );
2336 : long nRelativeDir = bRelative ?
2337 20 : ( ( aReferenceValue.ReferenceItemType == sheet::DataPilotFieldReferenceItemType::PREVIOUS ) ? -1 : 1 ) : 0;
2338 :
2339 20 : const ScDPRunningTotalState::IndexArray& rColVisible = rRunning.GetColVisible();
2340 20 : const ScDPRunningTotalState::IndexArray& rColSorted = rRunning.GetColSorted();
2341 20 : const ScDPRunningTotalState::IndexArray& rRowVisible = rRunning.GetRowVisible();
2342 20 : const ScDPRunningTotalState::IndexArray& rRowSorted = rRunning.GetRowSorted();
2343 :
2344 20 : String aRefFieldName = aReferenceValue.ReferenceField;
2345 :
2346 : //! aLocalSubState?
2347 20 : sal_uInt16 nRefOrient = pResultData->GetMeasureRefOrient( nMemberMeasure );
2348 20 : bool bRefDimInCol = ( nRefOrient == sheet::DataPilotFieldOrientation_COLUMN );
2349 20 : bool bRefDimInRow = ( nRefOrient == sheet::DataPilotFieldOrientation_ROW );
2350 :
2351 20 : ScDPResultDimension* pSelectDim = NULL;
2352 20 : long nRowPos = 0;
2353 20 : long nColPos = 0;
2354 :
2355 : //
2356 : // find the reference field in column or row dimensions
2357 : //
2358 :
2359 20 : if ( bRefDimInRow ) // look in row dimensions
2360 : {
2361 20 : pSelectDim = rRunning.GetRowResRoot()->GetChildDimension();
2362 40 : while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
2363 : {
2364 0 : long nIndex = rRowSorted[nRowPos];
2365 0 : if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
2366 0 : pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
2367 : else
2368 0 : pSelectDim = NULL;
2369 0 : ++nRowPos;
2370 : }
2371 : // child dimension of innermost member?
2372 20 : if ( pSelectDim && rRowSorted[nRowPos] < 0 )
2373 4 : pSelectDim = NULL;
2374 : }
2375 :
2376 20 : if ( bRefDimInCol ) // look in column dimensions
2377 : {
2378 0 : pSelectDim = rRunning.GetColResRoot()->GetChildDimension();
2379 0 : while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
2380 : {
2381 0 : long nIndex = rColSorted[nColPos];
2382 0 : if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
2383 0 : pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
2384 : else
2385 0 : pSelectDim = NULL;
2386 0 : ++nColPos;
2387 : }
2388 : // child dimension of innermost member?
2389 0 : if ( pSelectDim && rColSorted[nColPos] < 0 )
2390 0 : pSelectDim = NULL;
2391 : }
2392 :
2393 20 : bool bNoDetailsInRef = false;
2394 20 : if ( pSelectDim && bRunningTotal )
2395 : {
2396 : // Running totals:
2397 : // If details are hidden for this member in the reference dimension,
2398 : // don't show or sum up the value. Otherwise, for following members,
2399 : // the running totals of details and subtotals wouldn't match.
2400 :
2401 4 : long nMyIndex = bRefDimInCol ? rColSorted[nColPos] : rRowSorted[nRowPos];
2402 4 : if ( nMyIndex >= 0 && nMyIndex < pSelectDim->GetMemberCount() )
2403 : {
2404 4 : const ScDPResultMember* pMyRefMember = pSelectDim->GetMember(nMyIndex);
2405 4 : if ( pMyRefMember && pMyRefMember->HasHiddenDetails() )
2406 : {
2407 0 : pSelectDim = NULL; // don't calculate
2408 0 : bNoDetailsInRef = true; // show error, not empty
2409 : }
2410 : }
2411 : }
2412 :
2413 20 : if ( bRelative )
2414 : {
2415 : // Difference/Percentage from previous/next:
2416 : // If details are hidden for this member in the innermost column/row
2417 : // dimension (the orientation of the reference dimension), show an
2418 : // error value.
2419 : // - If the no-details dimension is the reference dimension, its
2420 : // members will be skipped when finding the previous/next member,
2421 : // so there must be no results for its members.
2422 : // - If the no-details dimension is outside of the reference dimension,
2423 : // no calculation in the reference dimension is possible.
2424 : // - Otherwise, the error isn't strictly necessary, but shown for
2425 : // consistency.
2426 :
2427 : bool bInnerNoDetails = bRefDimInCol ? HasHiddenDetails() :
2428 0 : ( bRefDimInRow ? rRowParent.HasHiddenDetails() : true );
2429 0 : if ( bInnerNoDetails )
2430 : {
2431 0 : pSelectDim = NULL;
2432 0 : bNoDetailsInRef = true; // show error, not empty
2433 : }
2434 : }
2435 :
2436 20 : if ( !bRefDimInCol && !bRefDimInRow ) // invalid dimension specified
2437 0 : bNoDetailsInRef = true; // pSelectDim is then already NULL
2438 :
2439 : //
2440 : // get the member for the reference item and do the calculation
2441 : //
2442 :
2443 20 : if ( bRunningTotal )
2444 : {
2445 : // running total in (dimension) -> find first existing member
2446 :
2447 5 : if ( pSelectDim )
2448 : {
2449 : ScDPDataMember* pSelectMember;
2450 4 : if ( bRefDimInCol )
2451 : pSelectMember = ScDPResultDimension::GetColReferenceMember( NULL, NULL,
2452 0 : nColPos, rRunning );
2453 : else
2454 : {
2455 4 : const long* pRowSorted = &rRowSorted[0];
2456 4 : const long* pColSorted = &rColSorted[0];
2457 4 : pRowSorted += nRowPos + 1; // including the reference dimension
2458 : pSelectMember = pSelectDim->GetRowReferenceMember(
2459 4 : NULL, NULL, pRowSorted, pColSorted);
2460 : }
2461 :
2462 4 : if ( pSelectMember )
2463 : {
2464 : // The running total is kept as the auxiliary value in
2465 : // the first available member for the reference dimension.
2466 : // Members are visited in final order, so each one's result
2467 : // can be used and then modified.
2468 :
2469 : ScDPAggData* pSelectData = pSelectMember->
2470 4 : GetAggData( nMemberMeasure, aLocalSubState );
2471 4 : if ( pSelectData )
2472 : {
2473 4 : double fTotal = pSelectData->GetAuxiliary();
2474 4 : fTotal += pAggData->GetResult();
2475 4 : pSelectData->SetAuxiliary( fTotal );
2476 4 : pAggData->SetResult( fTotal );
2477 4 : pAggData->SetEmpty(false); // always display
2478 : }
2479 : }
2480 : else
2481 0 : pAggData->SetError();
2482 : }
2483 1 : else if (bNoDetailsInRef)
2484 0 : pAggData->SetError();
2485 : else
2486 1 : pAggData->SetEmpty(true); // empty (dim set to 0 above)
2487 : }
2488 : else
2489 : {
2490 : // difference/percentage -> find specified member
2491 :
2492 15 : if ( pSelectDim )
2493 : {
2494 12 : OUString aRefItemName = aReferenceValue.ReferenceItemName;
2495 12 : ScDPRelativePos aRefItemPos( 0, nRelativeDir ); // nBasePos is modified later
2496 :
2497 12 : const OUString* pRefName = NULL;
2498 12 : const ScDPRelativePos* pRefPos = NULL;
2499 12 : if ( bRelative )
2500 0 : pRefPos = &aRefItemPos;
2501 : else
2502 12 : pRefName = &aRefItemName;
2503 :
2504 : ScDPDataMember* pSelectMember;
2505 12 : if ( bRefDimInCol )
2506 : {
2507 0 : aRefItemPos.nBasePos = rColVisible[nColPos]; // without sort order applied
2508 : pSelectMember = ScDPResultDimension::GetColReferenceMember( pRefPos, pRefName,
2509 0 : nColPos, rRunning );
2510 : }
2511 : else
2512 : {
2513 12 : aRefItemPos.nBasePos = rRowVisible[nRowPos]; // without sort order applied
2514 12 : const long* pRowSorted = &rRowSorted[0];
2515 12 : const long* pColSorted = &rColSorted[0];
2516 12 : pRowSorted += nRowPos + 1; // including the reference dimension
2517 : pSelectMember = pSelectDim->GetRowReferenceMember(
2518 12 : pRefPos, pRefName, pRowSorted, pColSorted);
2519 : }
2520 :
2521 : // difference or perc.difference is empty for the reference item itself
2522 12 : if ( pSelectMember == this &&
2523 : eRefType != sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE )
2524 : {
2525 2 : pAggData->SetEmpty(true);
2526 : }
2527 10 : else if ( pSelectMember )
2528 : {
2529 : const ScDPAggData* pOtherAggData = pSelectMember->
2530 10 : GetConstAggData( nMemberMeasure, aLocalSubState );
2531 : OSL_ENSURE( pOtherAggData, "no agg data" );
2532 10 : if ( pOtherAggData )
2533 : {
2534 : // Reference member may be visited before or after this one,
2535 : // so the auxiliary value is used for the original result.
2536 :
2537 10 : double fOtherResult = pOtherAggData->GetAuxiliary();
2538 10 : double fThisResult = pAggData->GetResult();
2539 10 : bool bError = false;
2540 10 : switch ( eRefType )
2541 : {
2542 : case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE:
2543 3 : fThisResult = fThisResult - fOtherResult;
2544 3 : break;
2545 : case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
2546 4 : if ( fOtherResult == 0.0 )
2547 0 : bError = true;
2548 : else
2549 4 : fThisResult = fThisResult / fOtherResult;
2550 4 : break;
2551 : case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
2552 3 : if ( fOtherResult == 0.0 )
2553 0 : bError = true;
2554 : else
2555 3 : fThisResult = ( fThisResult - fOtherResult ) / fOtherResult;
2556 3 : break;
2557 : default:
2558 : OSL_FAIL("invalid calculation type");
2559 : }
2560 10 : if ( bError )
2561 : {
2562 0 : pAggData->SetError();
2563 : }
2564 : else
2565 : {
2566 10 : pAggData->SetResult(fThisResult);
2567 10 : pAggData->SetEmpty(false); // always display
2568 : }
2569 : //! errors in data?
2570 : }
2571 : }
2572 0 : else if (bRelative && !bNoDetailsInRef)
2573 0 : pAggData->SetEmpty(true); // empty
2574 : else
2575 0 : pAggData->SetError(); // error
2576 : }
2577 3 : else if (bNoDetailsInRef)
2578 0 : pAggData->SetError(); // error
2579 : else
2580 3 : pAggData->SetEmpty(true); // empty
2581 20 : }
2582 : }
2583 1574 : else if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE ||
2584 1569 : eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE ||
2585 1569 : eRefType == sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE ||
2586 : eRefType == sheet::DataPilotFieldReferenceType::INDEX )
2587 : {
2588 : //
2589 : // set total values when they are encountered (always before their use)
2590 : //
2591 :
2592 5 : ScDPAggData* pColTotalData = pRefMember->GetColTotal( nMemberMeasure );
2593 5 : ScDPAggData* pRowTotalData = rTotals.GetRowTotal( nMemberMeasure );
2594 5 : ScDPAggData* pGrandTotalData = rTotals.GetGrandTotal( nMemberMeasure );
2595 :
2596 5 : double fTotalValue = pAggData->HasError() ? 0 : pAggData->GetResult();
2597 :
2598 5 : if ( bIsRoot && rTotals.IsInColRoot() && pGrandTotalData )
2599 1 : pGrandTotalData->SetAuxiliary( fTotalValue );
2600 :
2601 5 : if ( bIsRoot && pRowTotalData )
2602 5 : pRowTotalData->SetAuxiliary( fTotalValue );
2603 :
2604 5 : if ( rTotals.IsInColRoot() && pColTotalData )
2605 1 : pColTotalData->SetAuxiliary( fTotalValue );
2606 :
2607 : //
2608 : // find relation to total values
2609 : //
2610 :
2611 5 : switch ( eRefType )
2612 : {
2613 : case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
2614 : case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
2615 : case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
2616 : {
2617 : double nTotal;
2618 5 : if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE )
2619 0 : nTotal = pRowTotalData->GetAuxiliary();
2620 5 : else if ( eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE )
2621 5 : nTotal = pColTotalData->GetAuxiliary();
2622 : else
2623 0 : nTotal = pGrandTotalData->GetAuxiliary();
2624 :
2625 5 : if ( nTotal == 0.0 )
2626 0 : pAggData->SetError();
2627 : else
2628 5 : pAggData->SetResult( pAggData->GetResult() / nTotal );
2629 : }
2630 5 : break;
2631 : case sheet::DataPilotFieldReferenceType::INDEX:
2632 : {
2633 0 : double nColTotal = pColTotalData->GetAuxiliary();
2634 0 : double nRowTotal = pRowTotalData->GetAuxiliary();
2635 0 : double nGrandTotal = pGrandTotalData->GetAuxiliary();
2636 0 : if ( nRowTotal == 0.0 || nColTotal == 0.0 )
2637 0 : pAggData->SetError();
2638 : else
2639 : pAggData->SetResult(
2640 0 : ( pAggData->GetResult() * nGrandTotal ) /
2641 0 : ( nRowTotal * nColTotal ) );
2642 : }
2643 0 : break;
2644 : }
2645 1594 : }
2646 : }
2647 : }
2648 : }
2649 : }
2650 :
2651 1591 : if ( bHasChild ) // child dimension must be processed last, so the row total is known
2652 : {
2653 416 : if ( pDataChild )
2654 : pDataChild->UpdateRunningTotals( pRefChild, nMeasure,
2655 296 : bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent );
2656 : }
2657 1591 : }
2658 :
2659 : #if DEBUG_PIVOT_TABLE
2660 : void ScDPDataMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
2661 : {
2662 : lcl_DumpRow( OUString("ScDPDataMember"), GetName(), &aAggregate, pDoc, rPos );
2663 : SCROW nStartRow = rPos.Row();
2664 :
2665 : const ScDPDataDimension* pDataChild = GetChildDimension();
2666 : const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
2667 : if ( pDataChild && pRefChild )
2668 : pDataChild->DumpState( pRefChild, pDoc, rPos );
2669 :
2670 : lcl_Indent( pDoc, nStartRow, rPos );
2671 : }
2672 :
2673 : void ScDPDataMember::Dump(int nIndent) const
2674 : {
2675 : std::string aIndent(nIndent*2, ' ');
2676 : std::cout << aIndent << "-- data member '"
2677 : << (pResultMember ? pResultMember->GetName() : OUString()) << "'" << std::endl;
2678 : for (const ScDPAggData* pAgg = &aAggregate; pAgg; pAgg = pAgg->GetExistingChild())
2679 : pAgg->Dump(nIndent+1);
2680 :
2681 : if (pChildDimension)
2682 : pChildDimension->Dump(nIndent+1);
2683 : }
2684 : #endif
2685 :
2686 : // -----------------------------------------------------------------------
2687 :
2688 : // Helper class to select the members to include in
2689 : // ScDPResultDimension::InitFrom or LateInitFrom if groups are used
2690 :
2691 : class ScDPGroupCompare
2692 : {
2693 : private:
2694 : const ScDPResultData* pResultData;
2695 : const ScDPInitState& rInitState;
2696 : long nDimSource;
2697 : bool bIncludeAll;
2698 : bool bIsBase;
2699 : long nGroupBase;
2700 : public:
2701 : ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension );
2702 199 : ~ScDPGroupCompare() {}
2703 :
2704 601 : bool IsIncluded( const ScDPMember& rMember ) { return bIncludeAll || TestIncluded( rMember ); }
2705 : bool TestIncluded( const ScDPMember& rMember );
2706 : };
2707 :
2708 199 : ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension ) :
2709 : pResultData( pData ),
2710 : rInitState( rState ),
2711 199 : nDimSource( nDimension )
2712 : {
2713 199 : bIsBase = pResultData->IsBaseForGroup( nDimSource );
2714 199 : nGroupBase = pResultData->GetGroupBase( nDimSource ); //! get together in one call?
2715 :
2716 : // if bIncludeAll is set, TestIncluded doesn't need to be called
2717 199 : bIncludeAll = !( bIsBase || nGroupBase >= 0 );
2718 199 : }
2719 :
2720 79 : bool ScDPGroupCompare::TestIncluded( const ScDPMember& rMember )
2721 : {
2722 79 : bool bInclude = true;
2723 79 : if ( bIsBase )
2724 : {
2725 : // need to check all previous groups
2726 : //! get array of groups (or indexes) before loop?
2727 45 : ScDPItemData aMemberData;
2728 45 : rMember.FillItemData( aMemberData );
2729 :
2730 45 : const std::vector<ScDPInitState::Member>& rMemStates = rInitState.GetMembers();
2731 45 : std::vector<ScDPInitState::Member>::const_iterator it = rMemStates.begin(), itEnd = rMemStates.end();
2732 104 : for (; it != itEnd && bInclude; ++it)
2733 : {
2734 59 : if (pResultData->GetGroupBase(it->mnSrcIndex) == nDimSource)
2735 : {
2736 : bInclude = pResultData->IsInGroup(
2737 59 : it->mnNameIndex, it->mnSrcIndex, aMemberData, nDimSource);
2738 : }
2739 45 : }
2740 : }
2741 34 : else if ( nGroupBase >= 0 )
2742 : {
2743 : // base isn't used in preceding fields
2744 : // -> look for other groups using the same base
2745 :
2746 : //! get array of groups (or indexes) before loop?
2747 34 : ScDPItemData aMemberData;
2748 34 : rMember.FillItemData( aMemberData );
2749 34 : const std::vector<ScDPInitState::Member>& rMemStates = rInitState.GetMembers();
2750 34 : std::vector<ScDPInitState::Member>::const_iterator it = rMemStates.begin(), itEnd = rMemStates.end();
2751 42 : for (; it != itEnd && bInclude; ++it)
2752 : {
2753 8 : if (pResultData->GetGroupBase(it->mnSrcIndex) == nGroupBase)
2754 : {
2755 : // same base (hierarchy between the two groups is irrelevant)
2756 : bInclude = pResultData->HasCommonElement(
2757 8 : it->mnNameIndex, it->mnSrcIndex, aMemberData, nDimSource);
2758 : }
2759 :
2760 34 : }
2761 : }
2762 :
2763 79 : return bInclude;
2764 : }
2765 :
2766 : // -----------------------------------------------------------------------
2767 :
2768 167 : ScDPResultDimension::ScDPResultDimension( const ScDPResultData* pData ) :
2769 : pResultData( pData ),
2770 : nSortMeasure( 0 ),
2771 : bIsDataLayout( false ),
2772 : bSortByData( false ),
2773 : bSortAscending( false ),
2774 : bAutoShow( false ),
2775 : bAutoTopItems( false ),
2776 : bInitialized( false ),
2777 : nAutoMeasure( 0 ),
2778 167 : nAutoCount( 0 )
2779 : {
2780 167 : }
2781 :
2782 334 : ScDPResultDimension::~ScDPResultDimension()
2783 : {
2784 935 : for( int i = maMemberArray.size () ; i-- > 0 ; )
2785 601 : delete maMemberArray[i];
2786 167 : }
2787 :
2788 1910 : ScDPResultMember *ScDPResultDimension::FindMember( SCROW iData ) const
2789 : {
2790 1910 : if( bIsDataLayout )
2791 76 : return maMemberArray[0];
2792 :
2793 1834 : MemberHash::const_iterator aRes = maMemberHash.find( iData );
2794 1834 : if( aRes != maMemberHash.end()) {
2795 1815 : if ( aRes->second->IsNamedItem( iData ) )
2796 1815 : return aRes->second;
2797 : OSL_FAIL("problem! hash result is not the same as IsNamedItem");
2798 : }
2799 :
2800 : unsigned int i;
2801 19 : unsigned int nCount = maMemberArray.size();
2802 : ScDPResultMember* pResultMember;
2803 43 : for( i = 0; i < nCount ; i++ )
2804 : {
2805 24 : pResultMember = maMemberArray[i];
2806 24 : if ( pResultMember->IsNamedItem( iData ) )
2807 0 : return pResultMember;
2808 : }
2809 19 : return NULL;
2810 : }
2811 :
2812 4 : void ScDPResultDimension::InitFrom(
2813 : const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
2814 : size_t nPos, ScDPInitState& rInitState, bool bInitChild )
2815 : {
2816 4 : if (nPos >= ppDim.size() || nPos >= ppLev.size())
2817 : {
2818 0 : bInitialized = true;
2819 0 : return;
2820 : }
2821 :
2822 4 : ScDPDimension* pThisDim = ppDim[nPos];
2823 4 : ScDPLevel* pThisLevel = ppLev[nPos];
2824 :
2825 4 : if (!pThisDim || !pThisLevel)
2826 : {
2827 0 : bInitialized = true;
2828 0 : return;
2829 : }
2830 :
2831 4 : bIsDataLayout = pThisDim->getIsDataLayoutDimension(); // member
2832 4 : aDimensionName = pThisDim->getName(); // member
2833 :
2834 : // Check the autoshow setting. If it's enabled, store the settings.
2835 4 : const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
2836 4 : if ( rAutoInfo.IsEnabled )
2837 : {
2838 0 : bAutoShow = true;
2839 0 : bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
2840 0 : nAutoMeasure = pThisLevel->GetAutoMeasure();
2841 0 : nAutoCount = rAutoInfo.ItemCount;
2842 : }
2843 :
2844 : // Check the sort info, and store the settings if appropriate.
2845 4 : const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
2846 4 : if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
2847 : {
2848 0 : bSortByData = true;
2849 0 : bSortAscending = rSortInfo.IsAscending;
2850 0 : nSortMeasure = pThisLevel->GetSortMeasure();
2851 : }
2852 :
2853 : // global order is used to initialize aMembers, so it doesn't have to be looked at later
2854 4 : const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
2855 :
2856 4 : long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
2857 4 : ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
2858 :
2859 : // Now, go through all members and initialize them.
2860 4 : ScDPMembers* pMembers = pThisLevel->GetMembersObject();
2861 4 : long nMembCount = pMembers->getCount();
2862 20 : for ( long i=0; i<nMembCount; i++ )
2863 : {
2864 16 : long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
2865 :
2866 16 : ScDPMember* pMember = pMembers->getByIndex(nSorted);
2867 16 : if ( aCompare.IsIncluded( *pMember ) )
2868 : {
2869 16 : ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember);
2870 16 : ScDPResultMember* pNew = AddMember( aData );
2871 :
2872 16 : rInitState.AddMember(nDimSource, pNew->GetDataId());
2873 16 : pNew->InitFrom( ppDim, ppLev, nPos+1, rInitState, bInitChild );
2874 16 : rInitState.RemoveMember();
2875 : }
2876 : }
2877 4 : bInitialized = true;
2878 : }
2879 :
2880 655 : void ScDPResultDimension::LateInitFrom(
2881 : LateInitParams& rParams, const vector<SCROW>& pItemData, size_t nPos, ScDPInitState& rInitState)
2882 : {
2883 655 : if ( rParams.IsEnd( nPos ) )
2884 0 : return;
2885 : OSL_ENSURE( nPos <= pItemData.size(), OString::number(pItemData.size()).getStr() );
2886 655 : ScDPDimension* pThisDim = rParams.GetDim( nPos );
2887 655 : ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
2888 655 : SCROW rThisData = pItemData[nPos];
2889 :
2890 655 : if (!pThisDim || !pThisLevel)
2891 0 : return;
2892 :
2893 655 : long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
2894 :
2895 655 : bool bShowEmpty = pThisLevel->getShowEmpty();
2896 :
2897 655 : if ( !bInitialized )
2898 : { // init some values
2899 : // create all members at the first call (preserve order)
2900 163 : bIsDataLayout = pThisDim->getIsDataLayoutDimension();
2901 163 : aDimensionName = pThisDim->getName();
2902 :
2903 163 : const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
2904 163 : if ( rAutoInfo.IsEnabled )
2905 : {
2906 1 : bAutoShow = true;
2907 1 : bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
2908 1 : nAutoMeasure = pThisLevel->GetAutoMeasure();
2909 1 : nAutoCount = rAutoInfo.ItemCount;
2910 : }
2911 :
2912 163 : const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
2913 163 : if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
2914 : {
2915 0 : bSortByData = true;
2916 0 : bSortAscending = rSortInfo.IsAscending;
2917 0 : nSortMeasure = pThisLevel->GetSortMeasure();
2918 : }
2919 : }
2920 :
2921 655 : bool bLateInitAllMembers= bIsDataLayout || rParams.GetInitAllChild() || bShowEmpty;
2922 :
2923 655 : if ( !bLateInitAllMembers )
2924 : {
2925 617 : ResultMembers* pMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
2926 617 : bLateInitAllMembers = pMembers->IsHasHideDetailsMembers();
2927 : #if OSL_DEBUG_LEVEL > 1
2928 : OSL_TRACE( "%s", aDimensionName.getStr() );
2929 : if ( pMembers->IsHasHideDetailsMembers() )
2930 : OSL_TRACE( "HasHideDetailsMembers" );
2931 : #endif
2932 617 : pMembers->SetHasHideDetailsMembers( false );
2933 : }
2934 :
2935 655 : bool bNewAllMembers = (!rParams.IsRow()) || nPos == 0 || bLateInitAllMembers;
2936 :
2937 655 : if (bNewAllMembers )
2938 : {
2939 : // global order is used to initialize aMembers, so it doesn't have to be looked at later
2940 579 : if ( !bInitialized )
2941 : { //init all members
2942 119 : const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
2943 :
2944 119 : ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
2945 119 : ScDPMembers* pMembers = pThisLevel->GetMembersObject();
2946 119 : long nMembCount = pMembers->getCount();
2947 641 : for ( long i=0; i<nMembCount; i++ )
2948 : {
2949 522 : long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
2950 :
2951 522 : ScDPMember* pMember = pMembers->getByIndex(nSorted);
2952 522 : if ( aCompare.IsIncluded( *pMember ) )
2953 : { // add all members
2954 522 : ScDPParentDimData aData( i, pThisDim, pThisLevel, pMember );
2955 522 : AddMember( aData );
2956 : }
2957 : }
2958 119 : bInitialized = true; // don't call again, even if no members were included
2959 : }
2960 : // initialize only specific member (or all if "show empty" flag is set)
2961 579 : if ( bLateInitAllMembers )
2962 : {
2963 38 : long nCount = maMemberArray.size();
2964 114 : for (long i=0; i<nCount; i++)
2965 : {
2966 76 : ScDPResultMember* pResultMember = maMemberArray[i];
2967 :
2968 : // check show empty
2969 76 : bool bAllChildren = false;
2970 76 : if( bShowEmpty )
2971 : {
2972 76 : if ( pResultMember->IsNamedItem( rThisData ) )
2973 0 : bAllChildren = false;
2974 : else
2975 76 : bAllChildren = true;
2976 : }
2977 76 : rParams.SetInitAllChildren( bAllChildren );
2978 76 : rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
2979 76 : pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
2980 76 : rInitState.RemoveMember();
2981 : }
2982 : }
2983 : else
2984 : {
2985 541 : ScDPResultMember* pResultMember = FindMember( rThisData );
2986 541 : if( NULL != pResultMember )
2987 : {
2988 541 : rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
2989 541 : pResultMember->LateInitFrom( rParams, pItemData, nPos+1, rInitState );
2990 541 : rInitState.RemoveMember();
2991 : }
2992 : }
2993 : }
2994 : else
2995 76 : InitWithMembers( rParams, pItemData, nPos, rInitState );
2996 : }
2997 :
2998 1126 : long ScDPResultDimension::GetSize(long nMeasure) const
2999 : {
3000 1126 : long nTotal = 0;
3001 1126 : long nMemberCount = maMemberArray.size();
3002 1126 : if (bIsDataLayout)
3003 : {
3004 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3005 : "DataLayout dimension twice?");
3006 : // repeat first member...
3007 34 : nTotal = nMemberCount * maMemberArray[0]->GetSize(0); // all measures have equal size
3008 : }
3009 : else
3010 : {
3011 : // add all members
3012 5308 : for (long nMem=0; nMem<nMemberCount; nMem++)
3013 4216 : nTotal += maMemberArray[nMem]->GetSize(nMeasure);
3014 : }
3015 1126 : return nTotal;
3016 : }
3017 :
3018 671 : bool ScDPResultDimension::IsValidEntry( const vector< SCROW >& aMembers ) const
3019 : {
3020 671 : if (aMembers.empty())
3021 0 : return false;
3022 :
3023 671 : const ScDPResultMember* pMember = FindMember( aMembers[0] );
3024 671 : if ( NULL != pMember )
3025 671 : return pMember->IsValidEntry( aMembers );
3026 : #if OSL_DEBUG_LEVEL > 1
3027 : OStringBuffer strTemp(RTL_CONSTASCII_STRINGPARAM(
3028 : "IsValidEntry: Member not found, DimName = "));
3029 : strTemp.append(OUStringToOString(GetName(), RTL_TEXTENCODING_UTF8));
3030 : OSL_TRACE("%s", strTemp.getStr());
3031 : #endif
3032 0 : return false;
3033 : }
3034 :
3035 666 : void ScDPResultDimension::ProcessData( const vector< SCROW >& aMembers,
3036 : const ScDPResultDimension* pDataDim,
3037 : const vector< SCROW >& aDataMembers,
3038 : const vector<ScDPValue>& aValues ) const
3039 : {
3040 666 : if (aMembers.empty())
3041 0 : return;
3042 :
3043 666 : ScDPResultMember* pMember = FindMember( aMembers[0] );
3044 666 : if ( NULL != pMember )
3045 : {
3046 666 : vector<SCROW> aChildMembers;
3047 666 : if (aMembers.size() > 1)
3048 : {
3049 96 : vector<SCROW>::const_iterator itr = aMembers.begin();
3050 96 : aChildMembers.insert(aChildMembers.begin(), ++itr, aMembers.end());
3051 : }
3052 666 : pMember->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
3053 666 : return;
3054 : }
3055 :
3056 : OSL_FAIL("ProcessData: Member not found");
3057 : }
3058 :
3059 164 : void ScDPResultDimension::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
3060 : long nStart, long nMeasure )
3061 : {
3062 164 : long nPos = nStart;
3063 164 : long nCount = maMemberArray.size();
3064 :
3065 759 : for (long i=0; i<nCount; i++)
3066 : {
3067 595 : long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
3068 :
3069 595 : ScDPResultMember* pMember = maMemberArray[nSorted];
3070 : // in data layout dimension, use first member with different measures/names
3071 595 : if ( bIsDataLayout )
3072 : {
3073 14 : bool bTotalResult = false;
3074 14 : OUString aMbrName = pResultData->GetMeasureDimensionName( nSorted );
3075 28 : OUString aMbrCapt = pResultData->GetMeasureString( nSorted, false, SUBTOTAL_FUNC_NONE, bTotalResult );
3076 28 : maMemberArray[0]->FillMemberResults( pSequences, nPos, nSorted, false, &aMbrName, &aMbrCapt );
3077 : }
3078 581 : else if ( pMember->IsVisible() )
3079 : {
3080 516 : pMember->FillMemberResults( pSequences, nPos, nMeasure, false, NULL, NULL );
3081 : }
3082 : // nPos is modified
3083 : }
3084 164 : }
3085 :
3086 107 : void ScDPResultDimension::FillDataResults(
3087 : const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
3088 : uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence, long nMeasure) const
3089 : {
3090 107 : FilterStack aFilterStack(rFilterCxt.maFilters);
3091 107 : aFilterStack.pushDimName(GetName(), bIsDataLayout);
3092 :
3093 107 : long nMemberMeasure = nMeasure;
3094 107 : long nCount = maMemberArray.size();
3095 441 : for (long i=0; i<nCount; i++)
3096 : {
3097 334 : long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
3098 :
3099 : const ScDPResultMember* pMember;
3100 334 : if (bIsDataLayout)
3101 : {
3102 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3103 : "DataLayout dimension twice?");
3104 12 : pMember = maMemberArray[0];
3105 12 : nMemberMeasure = nSorted;
3106 : }
3107 : else
3108 322 : pMember = maMemberArray[nSorted];
3109 :
3110 334 : if ( pMember->IsVisible() )
3111 329 : pMember->FillDataResults(pRefMember, rFilterCxt, rSequence, nMemberMeasure);
3112 107 : }
3113 107 : }
3114 :
3115 108 : void ScDPResultDimension::UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const
3116 : {
3117 108 : long nMemberMeasure = nMeasure;
3118 108 : long nCount = maMemberArray.size();
3119 447 : for (long i=0; i<nCount; i++)
3120 : {
3121 : const ScDPResultMember* pMember;
3122 339 : if (bIsDataLayout)
3123 : {
3124 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3125 : "DataLayout dimension twice?");
3126 12 : pMember = maMemberArray[0];
3127 12 : nMemberMeasure = i;
3128 : }
3129 : else
3130 327 : pMember = maMemberArray[i];
3131 :
3132 339 : if ( pMember->IsVisible() )
3133 334 : pMember->UpdateDataResults( pRefMember, nMemberMeasure );
3134 : }
3135 108 : }
3136 :
3137 107 : void ScDPResultDimension::SortMembers( ScDPResultMember* pRefMember )
3138 : {
3139 107 : long nCount = maMemberArray.size();
3140 :
3141 107 : if ( bSortByData )
3142 : {
3143 : // sort members
3144 :
3145 : OSL_ENSURE( aMemberOrder.empty(), "sort twice?" );
3146 0 : aMemberOrder.resize( nCount );
3147 0 : for (long nPos=0; nPos<nCount; nPos++)
3148 0 : aMemberOrder[nPos] = nPos;
3149 :
3150 0 : ScDPRowMembersOrder aComp( *this, nSortMeasure, bSortAscending );
3151 0 : ::std::sort( aMemberOrder.begin(), aMemberOrder.end(), aComp );
3152 : }
3153 :
3154 : // handle children
3155 :
3156 : // for data layout, call only once - sorting measure is always taken from settings
3157 107 : long nLoopCount = bIsDataLayout ? 1 : nCount;
3158 435 : for (long i=0; i<nLoopCount; i++)
3159 : {
3160 328 : ScDPResultMember* pMember = maMemberArray[i];
3161 328 : if ( pMember->IsVisible() )
3162 323 : pMember->SortMembers( pRefMember );
3163 : }
3164 107 : }
3165 :
3166 1 : void ScDPResultDimension::DoAutoShow( ScDPResultMember* pRefMember )
3167 : {
3168 1 : long nCount = maMemberArray.size();
3169 :
3170 : // handle children first, before changing the visible state
3171 :
3172 : // for data layout, call only once - sorting measure is always taken from settings
3173 1 : long nLoopCount = bIsDataLayout ? 1 : nCount;
3174 6 : for (long i=0; i<nLoopCount; i++)
3175 : {
3176 5 : ScDPResultMember* pMember = maMemberArray[i];
3177 5 : if ( pMember->IsVisible() )
3178 5 : pMember->DoAutoShow( pRefMember );
3179 : }
3180 :
3181 1 : if ( bAutoShow && nAutoCount > 0 && nAutoCount < nCount )
3182 : {
3183 : // establish temporary order, hide remaining members
3184 :
3185 0 : ScMemberSortOrder aAutoOrder;
3186 0 : aAutoOrder.resize( nCount );
3187 : long nPos;
3188 0 : for (nPos=0; nPos<nCount; nPos++)
3189 0 : aAutoOrder[nPos] = nPos;
3190 :
3191 0 : ScDPRowMembersOrder aComp( *this, nAutoMeasure, !bAutoTopItems );
3192 0 : ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );
3193 :
3194 : // look for equal values to the last included one
3195 :
3196 0 : long nIncluded = nAutoCount;
3197 0 : const ScDPResultMember* pMember1 = maMemberArray[aAutoOrder[nIncluded - 1]];
3198 0 : const ScDPDataMember* pDataMember1 = pMember1->IsVisible() ? pMember1->GetDataRoot() : NULL;
3199 0 : bool bContinue = true;
3200 0 : while ( bContinue )
3201 : {
3202 0 : bContinue = false;
3203 0 : if ( nIncluded < nCount )
3204 : {
3205 0 : const ScDPResultMember* pMember2 = maMemberArray[aAutoOrder[nIncluded]];
3206 0 : const ScDPDataMember* pDataMember2 = pMember2->IsVisible() ? pMember2->GetDataRoot() : NULL;
3207 :
3208 0 : if ( lcl_IsEqual( pDataMember1, pDataMember2, nAutoMeasure ) )
3209 : {
3210 0 : ++nIncluded; // include more members if values are equal
3211 0 : bContinue = true;
3212 : }
3213 : }
3214 : }
3215 :
3216 : // hide the remaining members
3217 :
3218 0 : for (nPos = nIncluded; nPos < nCount; nPos++)
3219 : {
3220 0 : ScDPResultMember* pMember = maMemberArray[aAutoOrder[nPos]];
3221 0 : pMember->SetAutoHidden();
3222 0 : }
3223 : }
3224 1 : }
3225 :
3226 2 : void ScDPResultDimension::ResetResults()
3227 : {
3228 2 : long nCount = maMemberArray.size();
3229 12 : for (long i=0; i<nCount; i++)
3230 : {
3231 : // sort order doesn't matter
3232 10 : ScDPResultMember* pMember = maMemberArray[bIsDataLayout ? 0 : i];
3233 10 : pMember->ResetResults();
3234 : }
3235 2 : }
3236 :
3237 28 : long ScDPResultDimension::GetSortedIndex( long nUnsorted ) const
3238 : {
3239 28 : return aMemberOrder.empty() ? nUnsorted : aMemberOrder[nUnsorted];
3240 : }
3241 :
3242 107 : void ScDPResultDimension::UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
3243 : ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
3244 : {
3245 : const ScDPResultMember* pMember;
3246 107 : long nMemberMeasure = nMeasure;
3247 107 : long nCount = maMemberArray.size();
3248 441 : for (long i=0; i<nCount; i++)
3249 : {
3250 334 : long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
3251 :
3252 334 : if (bIsDataLayout)
3253 : {
3254 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3255 : "DataLayout dimension twice?");
3256 12 : pMember = maMemberArray[0];
3257 12 : nMemberMeasure = nSorted;
3258 : }
3259 : else
3260 322 : pMember = maMemberArray[nSorted];
3261 :
3262 334 : if ( pMember->IsVisible() )
3263 : {
3264 329 : if ( bIsDataLayout )
3265 12 : rRunning.AddRowIndex( 0, 0 );
3266 : else
3267 317 : rRunning.AddRowIndex( i, nSorted );
3268 329 : pMember->UpdateRunningTotals( pRefMember, nMemberMeasure, rRunning, rTotals );
3269 329 : rRunning.RemoveRowIndex();
3270 : }
3271 : }
3272 107 : }
3273 :
3274 16 : ScDPDataMember* ScDPResultDimension::GetRowReferenceMember(
3275 : const ScDPRelativePos* pRelativePos, const OUString* pName,
3276 : const long* pRowIndexes, const long* pColIndexes ) const
3277 : {
3278 : // get named, previous/next, or first member of this dimension (first existing if pRelativePos and pName are NULL)
3279 :
3280 : OSL_ENSURE( pRelativePos == NULL || pName == NULL, "can't use position and name" );
3281 :
3282 16 : ScDPDataMember* pColMember = NULL;
3283 :
3284 16 : bool bFirstExisting = ( pRelativePos == NULL && pName == NULL );
3285 16 : long nMemberCount = maMemberArray.size();
3286 16 : long nMemberIndex = 0; // unsorted
3287 16 : long nDirection = 1; // forward if no relative position is used
3288 16 : if ( pRelativePos )
3289 : {
3290 0 : nDirection = pRelativePos->nDirection;
3291 0 : nMemberIndex = pRelativePos->nBasePos + nDirection; // bounds are handled below
3292 :
3293 : OSL_ENSURE( nDirection == 1 || nDirection == -1, "Direction must be 1 or -1" );
3294 : }
3295 16 : else if ( pName )
3296 : {
3297 : // search for named member
3298 :
3299 12 : const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
3300 :
3301 : //! use ScDPItemData, as in ScDPDimension::IsValidPage?
3302 24 : while ( pRowMember && pRowMember->GetName() != *pName )
3303 : {
3304 0 : ++nMemberIndex;
3305 0 : if ( nMemberIndex < nMemberCount )
3306 0 : pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
3307 : else
3308 0 : pRowMember = NULL;
3309 : }
3310 : }
3311 :
3312 16 : bool bContinue = true;
3313 48 : while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nMemberCount )
3314 : {
3315 16 : const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
3316 :
3317 : // get child members by given indexes
3318 :
3319 16 : const long* pNextRowIndex = pRowIndexes;
3320 32 : while ( *pNextRowIndex >= 0 && pRowMember )
3321 : {
3322 0 : const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
3323 0 : if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
3324 0 : pRowMember = pRowChild->GetMember( *pNextRowIndex );
3325 : else
3326 0 : pRowMember = NULL;
3327 0 : ++pNextRowIndex;
3328 : }
3329 :
3330 16 : if ( pRowMember && pRelativePos )
3331 : {
3332 : // Skip the member if it has hidden details
3333 : // (because when looking for the details, it is skipped, too).
3334 : // Also skip if the member is invisible because it has no data,
3335 : // for consistent ordering.
3336 0 : if ( pRowMember->HasHiddenDetails() || !pRowMember->IsVisible() )
3337 0 : pRowMember = NULL;
3338 : }
3339 :
3340 16 : if ( pRowMember )
3341 : {
3342 16 : pColMember = pRowMember->GetDataRoot();
3343 :
3344 16 : const long* pNextColIndex = pColIndexes;
3345 32 : while ( *pNextColIndex >= 0 && pColMember )
3346 : {
3347 0 : ScDPDataDimension* pColChild = pColMember->GetChildDimension();
3348 0 : if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
3349 0 : pColMember = pColChild->GetMember( *pNextColIndex );
3350 : else
3351 0 : pColMember = NULL;
3352 0 : ++pNextColIndex;
3353 : }
3354 : }
3355 :
3356 : // continue searching only if looking for first existing or relative position
3357 16 : bContinue = ( pColMember == NULL && ( bFirstExisting || pRelativePos ) );
3358 16 : nMemberIndex += nDirection;
3359 : }
3360 :
3361 16 : return pColMember;
3362 : }
3363 :
3364 0 : ScDPDataMember* ScDPResultDimension::GetColReferenceMember(
3365 : const ScDPRelativePos* pRelativePos, const OUString* pName,
3366 : long nRefDimPos, const ScDPRunningTotalState& rRunning )
3367 : {
3368 : OSL_ENSURE( pRelativePos == NULL || pName == NULL, "can't use position and name" );
3369 :
3370 0 : const long* pColIndexes = &rRunning.GetColSorted()[0];
3371 0 : const long* pRowIndexes = &rRunning.GetRowSorted()[0];
3372 :
3373 : // get own row member using all indexes
3374 :
3375 0 : const ScDPResultMember* pRowMember = rRunning.GetRowResRoot();
3376 0 : ScDPDataMember* pColMember = NULL;
3377 :
3378 0 : const long* pNextRowIndex = pRowIndexes;
3379 0 : while ( *pNextRowIndex >= 0 && pRowMember )
3380 : {
3381 0 : const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
3382 0 : if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
3383 0 : pRowMember = pRowChild->GetMember( *pNextRowIndex );
3384 : else
3385 0 : pRowMember = NULL;
3386 0 : ++pNextRowIndex;
3387 : }
3388 :
3389 : // get column (data) members before the reference field
3390 : //! pass rRowParent from ScDPDataMember::UpdateRunningTotals instead
3391 :
3392 0 : if ( pRowMember )
3393 : {
3394 0 : pColMember = pRowMember->GetDataRoot();
3395 :
3396 0 : const long* pNextColIndex = pColIndexes;
3397 0 : long nColSkipped = 0;
3398 0 : while ( *pNextColIndex >= 0 && pColMember && nColSkipped < nRefDimPos )
3399 : {
3400 0 : ScDPDataDimension* pColChild = pColMember->GetChildDimension();
3401 0 : if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
3402 0 : pColMember = pColChild->GetMember( *pNextColIndex );
3403 : else
3404 0 : pColMember = NULL;
3405 0 : ++pNextColIndex;
3406 0 : ++nColSkipped;
3407 : }
3408 : }
3409 :
3410 : // get column member for the reference field
3411 :
3412 0 : if ( pColMember )
3413 : {
3414 0 : ScDPDataDimension* pReferenceDim = pColMember->GetChildDimension();
3415 0 : if ( pReferenceDim )
3416 : {
3417 0 : long nReferenceCount = pReferenceDim->GetMemberCount();
3418 :
3419 0 : bool bFirstExisting = ( pRelativePos == NULL && pName == NULL );
3420 0 : long nMemberIndex = 0; // unsorted
3421 0 : long nDirection = 1; // forward if no relative position is used
3422 0 : pColMember = NULL; // don't use parent dimension's member if none found
3423 0 : if ( pRelativePos )
3424 : {
3425 0 : nDirection = pRelativePos->nDirection;
3426 0 : nMemberIndex = pRelativePos->nBasePos + nDirection; // bounds are handled below
3427 : }
3428 0 : else if ( pName )
3429 : {
3430 : // search for named member
3431 :
3432 0 : pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
3433 :
3434 : //! use ScDPItemData, as in ScDPDimension::IsValidPage?
3435 0 : while ( pColMember && pColMember->GetName() != *pName )
3436 : {
3437 0 : ++nMemberIndex;
3438 0 : if ( nMemberIndex < nReferenceCount )
3439 0 : pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
3440 : else
3441 0 : pColMember = NULL;
3442 : }
3443 : }
3444 :
3445 0 : bool bContinue = true;
3446 0 : while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nReferenceCount )
3447 : {
3448 0 : pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
3449 :
3450 : // get column members below the reference field
3451 :
3452 0 : const long* pNextColIndex = pColIndexes + nRefDimPos + 1;
3453 0 : while ( *pNextColIndex >= 0 && pColMember )
3454 : {
3455 0 : ScDPDataDimension* pColChild = pColMember->GetChildDimension();
3456 0 : if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
3457 0 : pColMember = pColChild->GetMember( *pNextColIndex );
3458 : else
3459 0 : pColMember = NULL;
3460 0 : ++pNextColIndex;
3461 : }
3462 :
3463 0 : if ( pColMember && pRelativePos )
3464 : {
3465 : // Skip the member if it has hidden details
3466 : // (because when looking for the details, it is skipped, too).
3467 : // Also skip if the member is invisible because it has no data,
3468 : // for consistent ordering.
3469 0 : if ( pColMember->HasHiddenDetails() || !pColMember->IsVisible() )
3470 0 : pColMember = NULL;
3471 : }
3472 :
3473 : // continue searching only if looking for first existing or relative position
3474 0 : bContinue = ( pColMember == NULL && ( bFirstExisting || pRelativePos ) );
3475 0 : nMemberIndex += nDirection;
3476 : }
3477 : }
3478 : else
3479 0 : pColMember = NULL;
3480 : }
3481 :
3482 0 : return pColMember;
3483 : }
3484 :
3485 : #if DEBUG_PIVOT_TABLE
3486 : void ScDPResultDimension::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
3487 : {
3488 : OUString aDimName = bIsDataLayout ? OUString("(data layout)") : OUString(GetName());
3489 : lcl_DumpRow( OUString("ScDPResultDimension"), aDimName, NULL, pDoc, rPos );
3490 :
3491 : SCROW nStartRow = rPos.Row();
3492 :
3493 : long nCount = bIsDataLayout ? 1 : maMemberArray.size();
3494 : for (long i=0; i<nCount; i++)
3495 : {
3496 : const ScDPResultMember* pMember = maMemberArray[i];
3497 : pMember->DumpState( pRefMember, pDoc, rPos );
3498 : }
3499 :
3500 : lcl_Indent( pDoc, nStartRow, rPos );
3501 : }
3502 :
3503 : void ScDPResultDimension::Dump(int nIndent) const
3504 : {
3505 : std::string aIndent(nIndent*2, ' ');
3506 : std::cout << aIndent << "-- dimension '" << GetName() << "'" << std::endl;
3507 : MemberArray::const_iterator it = maMemberArray.begin(), itEnd = maMemberArray.end();
3508 : for (; it != itEnd; ++it)
3509 : {
3510 : const ScDPResultMember* p = *it;
3511 : p->Dump(nIndent+1);
3512 : }
3513 : }
3514 : #endif
3515 :
3516 300 : long ScDPResultDimension::GetMemberCount() const
3517 : {
3518 300 : return maMemberArray.size();
3519 : }
3520 :
3521 5267 : const ScDPResultMember* ScDPResultDimension::GetMember(long n) const
3522 : {
3523 5267 : return maMemberArray[n];
3524 : }
3525 269 : ScDPResultMember* ScDPResultDimension::GetMember(long n)
3526 : {
3527 269 : return maMemberArray[n];
3528 : }
3529 :
3530 2 : ScDPResultDimension* ScDPResultDimension::GetFirstChildDimension() const
3531 : {
3532 2 : if ( maMemberArray.size() > 0 )
3533 2 : return maMemberArray[0]->GetChildDimension();
3534 : else
3535 0 : return NULL;
3536 : }
3537 :
3538 1596 : void ScDPResultDimension::FillVisibilityData(ScDPResultVisibilityData& rData) const
3539 : {
3540 1596 : if (IsDataLayout())
3541 1596 : return;
3542 :
3543 1596 : MemberArray::const_iterator itr = maMemberArray.begin(), itrEnd = maMemberArray.end();
3544 :
3545 6916 : for (;itr != itrEnd; ++itr)
3546 : {
3547 5320 : ScDPResultMember* pMember = *itr;
3548 5320 : if (pMember->IsValid())
3549 : {
3550 5320 : ScDPItemData aItem;
3551 5320 : pMember->FillItemData(aItem);
3552 5320 : rData.addVisibleMember(GetName(), aItem);
3553 5320 : pMember->FillVisibilityData(rData);
3554 : }
3555 : }
3556 : }
3557 :
3558 : // -----------------------------------------------------------------------
3559 :
3560 296 : ScDPDataDimension::ScDPDataDimension( const ScDPResultData* pData ) :
3561 : pResultData( pData ),
3562 : pResultDimension( NULL ),
3563 296 : bIsDataLayout( false )
3564 : {
3565 296 : }
3566 :
3567 592 : ScDPDataDimension::~ScDPDataDimension()
3568 : {
3569 296 : std::for_each(maMembers.begin(), maMembers.end(), ScDeleteObjectByPtr<ScDPDataMember>());
3570 296 : }
3571 :
3572 296 : void ScDPDataDimension::InitFrom( const ScDPResultDimension* pDim )
3573 : {
3574 296 : if (!pDim)
3575 296 : return;
3576 :
3577 296 : pResultDimension = pDim;
3578 296 : bIsDataLayout = pDim->IsDataLayout();
3579 :
3580 : // Go through all result members under the given result dimension, and
3581 : // create a new data member instance for each result member.
3582 296 : long nCount = pDim->GetMemberCount();
3583 1654 : for (long i=0; i<nCount; i++)
3584 : {
3585 1358 : const ScDPResultMember* pResMem = pDim->GetMember(i);
3586 :
3587 1358 : ScDPDataMember* pNew = new ScDPDataMember( pResultData, pResMem );
3588 1358 : maMembers.push_back( pNew);
3589 :
3590 1358 : if ( !pResultData->IsLateInit() )
3591 : {
3592 : // with LateInit, pResMem hasn't necessarily been initialized yet,
3593 : // so InitFrom for the new result member is called from its ProcessData method
3594 :
3595 0 : const ScDPResultDimension* pChildDim = pResMem->GetChildDimension();
3596 0 : if ( pChildDim )
3597 0 : pNew->InitFrom( pChildDim );
3598 : }
3599 : }
3600 : }
3601 :
3602 496 : void ScDPDataDimension::ProcessData( const vector< SCROW >& aDataMembers, const vector<ScDPValue>& aValues,
3603 : const ScDPSubTotalState& rSubState )
3604 : {
3605 : // the ScDPItemData array must contain enough entries for all dimensions - this isn't checked
3606 :
3607 496 : long nCount = maMembers.size();
3608 1350 : for (long i=0; i<nCount; i++)
3609 : {
3610 1350 : ScDPDataMember* pMember = maMembers[(sal_uInt16)i];
3611 :
3612 : // always first member for data layout dim
3613 1350 : if ( bIsDataLayout || ( !aDataMembers.empty() && pMember->IsNamedItem(aDataMembers[0]) ) )
3614 : {
3615 496 : vector<SCROW> aChildDataMembers;
3616 496 : if (aDataMembers.size() > 1)
3617 : {
3618 55 : vector<SCROW>::const_iterator itr = aDataMembers.begin();
3619 55 : aChildDataMembers.insert(aChildDataMembers.begin(), ++itr, aDataMembers.end());
3620 : }
3621 496 : pMember->ProcessData( aChildDataMembers, aValues, rSubState );
3622 992 : return;
3623 : }
3624 : }
3625 :
3626 : OSL_FAIL("ProcessData: Member not found");
3627 : }
3628 :
3629 257 : void ScDPDataDimension::FillDataRow(
3630 : const ScDPResultDimension* pRefDim, ScDPResultFilterContext& rFilterCxt,
3631 : uno::Sequence<sheet::DataResult>& rSequence, long nMeasure, bool bIsSubTotalRow,
3632 : const ScDPSubTotalState& rSubState) const
3633 : {
3634 257 : OUString aDimName;
3635 257 : bool bDataLayout = false;
3636 257 : if (pResultDimension)
3637 : {
3638 257 : aDimName = pResultDimension->GetName();
3639 257 : bDataLayout = pResultDimension->IsDataLayout();
3640 : }
3641 :
3642 514 : FilterStack aFilterStack(rFilterCxt.maFilters);
3643 257 : aFilterStack.pushDimName(aDimName, bDataLayout);
3644 :
3645 : OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3646 : OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3647 :
3648 257 : const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
3649 :
3650 257 : long nMemberMeasure = nMeasure;
3651 257 : long nCount = maMembers.size();
3652 1420 : for (long i=0; i<nCount; i++)
3653 : {
3654 1163 : long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];
3655 :
3656 1163 : long nMemberPos = nSorted;
3657 1163 : if (bIsDataLayout)
3658 : {
3659 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3660 : "DataLayout dimension twice?");
3661 6 : nMemberPos = 0;
3662 6 : nMemberMeasure = nSorted;
3663 : }
3664 :
3665 1163 : const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
3666 1163 : if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember::FillDataRow ???
3667 : {
3668 1043 : const ScDPDataMember* pDataMember = maMembers[(sal_uInt16)nMemberPos];
3669 1043 : pDataMember->FillDataRow(pRefMember, rFilterCxt, rSequence, nMemberMeasure, bIsSubTotalRow, rSubState);
3670 : }
3671 257 : }
3672 257 : }
3673 :
3674 302 : void ScDPDataDimension::UpdateDataRow( const ScDPResultDimension* pRefDim,
3675 : long nMeasure, bool bIsSubTotalRow,
3676 : const ScDPSubTotalState& rSubState ) const
3677 : {
3678 : OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3679 : OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3680 :
3681 302 : long nMemberMeasure = nMeasure;
3682 302 : long nCount = maMembers.size();
3683 1690 : for (long i=0; i<nCount; i++)
3684 : {
3685 1388 : long nMemberPos = i;
3686 1388 : if (bIsDataLayout)
3687 : {
3688 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3689 : "DataLayout dimension twice?");
3690 6 : nMemberPos = 0;
3691 6 : nMemberMeasure = i;
3692 : }
3693 :
3694 : // Calculate must be called even if the member is not visible (for use as reference value)
3695 1388 : const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
3696 1388 : ScDPDataMember* pDataMember = maMembers[(sal_uInt16)nMemberPos];
3697 1388 : pDataMember->UpdateDataRow( pRefMember, nMemberMeasure, bIsSubTotalRow, rSubState );
3698 : }
3699 302 : }
3700 :
3701 57 : void ScDPDataDimension::SortMembers( ScDPResultDimension* pRefDim )
3702 : {
3703 57 : long nCount = maMembers.size();
3704 :
3705 57 : if ( pRefDim->IsSortByData() )
3706 : {
3707 : // sort members
3708 :
3709 0 : ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
3710 : OSL_ENSURE( rMemberOrder.empty(), "sort twice?" );
3711 0 : rMemberOrder.resize( nCount );
3712 0 : for (long nPos=0; nPos<nCount; nPos++)
3713 0 : rMemberOrder[nPos] = nPos;
3714 :
3715 0 : ScDPColMembersOrder aComp( *this, pRefDim->GetSortMeasure(), pRefDim->IsSortAscending() );
3716 0 : ::std::sort( rMemberOrder.begin(), rMemberOrder.end(), aComp );
3717 : }
3718 :
3719 : // handle children
3720 :
3721 : OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3722 : OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3723 :
3724 : // for data layout, call only once - sorting measure is always taken from settings
3725 57 : long nLoopCount = bIsDataLayout ? 1 : nCount;
3726 317 : for (long i=0; i<nLoopCount; i++)
3727 : {
3728 260 : ScDPResultMember* pRefMember = pRefDim->GetMember(i);
3729 260 : if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember ???
3730 : {
3731 200 : ScDPDataMember* pDataMember = maMembers[(sal_uInt16)i];
3732 200 : pDataMember->SortMembers( pRefMember );
3733 : }
3734 : }
3735 57 : }
3736 :
3737 1 : void ScDPDataDimension::DoAutoShow( ScDPResultDimension* pRefDim )
3738 : {
3739 1 : long nCount = maMembers.size();
3740 :
3741 : // handle children first, before changing the visible state
3742 :
3743 : OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3744 : OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3745 :
3746 : // for data layout, call only once - sorting measure is always taken from settings
3747 1 : long nLoopCount = bIsDataLayout ? 1 : nCount;
3748 6 : for (long i=0; i<nLoopCount; i++)
3749 : {
3750 5 : ScDPResultMember* pRefMember = pRefDim->GetMember(i);
3751 5 : if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember ???
3752 : {
3753 5 : ScDPDataMember* pDataMember = maMembers[i];
3754 5 : pDataMember->DoAutoShow( pRefMember );
3755 : }
3756 : }
3757 :
3758 1 : if ( pRefDim->IsAutoShow() && pRefDim->GetAutoCount() > 0 && pRefDim->GetAutoCount() < nCount )
3759 : {
3760 : // establish temporary order, hide remaining members
3761 :
3762 0 : ScMemberSortOrder aAutoOrder;
3763 0 : aAutoOrder.resize( nCount );
3764 : long nPos;
3765 0 : for (nPos=0; nPos<nCount; nPos++)
3766 0 : aAutoOrder[nPos] = nPos;
3767 :
3768 0 : ScDPColMembersOrder aComp( *this, pRefDim->GetAutoMeasure(), !pRefDim->IsAutoTopItems() );
3769 0 : ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );
3770 :
3771 : // look for equal values to the last included one
3772 :
3773 0 : long nIncluded = pRefDim->GetAutoCount();
3774 0 : ScDPDataMember* pDataMember1 = maMembers[aAutoOrder[nIncluded - 1]];
3775 0 : if ( !pDataMember1->IsVisible() )
3776 0 : pDataMember1 = NULL;
3777 0 : bool bContinue = true;
3778 0 : while ( bContinue )
3779 : {
3780 0 : bContinue = false;
3781 0 : if ( nIncluded < nCount )
3782 : {
3783 0 : ScDPDataMember* pDataMember2 = maMembers[aAutoOrder[nIncluded]];
3784 0 : if ( !pDataMember2->IsVisible() )
3785 0 : pDataMember2 = NULL;
3786 :
3787 0 : if ( lcl_IsEqual( pDataMember1, pDataMember2, pRefDim->GetAutoMeasure() ) )
3788 : {
3789 0 : ++nIncluded; // include more members if values are equal
3790 0 : bContinue = true;
3791 : }
3792 : }
3793 : }
3794 :
3795 : // hide the remaining members
3796 :
3797 0 : for (nPos = nIncluded; nPos < nCount; nPos++)
3798 : {
3799 0 : ScDPResultMember* pMember = pRefDim->GetMember(aAutoOrder[nPos]);
3800 0 : pMember->SetAutoHidden();
3801 0 : }
3802 : }
3803 1 : }
3804 :
3805 6 : void ScDPDataDimension::ResetResults()
3806 : {
3807 6 : long nCount = maMembers.size();
3808 36 : for (long i=0; i<nCount; i++)
3809 : {
3810 : // sort order doesn't matter
3811 :
3812 30 : long nMemberPos = bIsDataLayout ? 0 : i;
3813 30 : ScDPDataMember* pDataMember = maMembers[nMemberPos];
3814 30 : pDataMember->ResetResults();
3815 : }
3816 6 : }
3817 :
3818 0 : long ScDPDataDimension::GetSortedIndex( long nUnsorted ) const
3819 : {
3820 0 : if (!pResultDimension)
3821 0 : return nUnsorted;
3822 :
3823 0 : const ScMemberSortOrder& rMemberOrder = pResultDimension->GetMemberOrder();
3824 0 : return rMemberOrder.empty() ? nUnsorted : rMemberOrder[nUnsorted];
3825 : }
3826 :
3827 296 : void ScDPDataDimension::UpdateRunningTotals( const ScDPResultDimension* pRefDim,
3828 : long nMeasure, bool bIsSubTotalRow,
3829 : const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
3830 : ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent ) const
3831 : {
3832 : OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
3833 : OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
3834 :
3835 296 : long nMemberMeasure = nMeasure;
3836 296 : long nCount = maMembers.size();
3837 1654 : for (long i=0; i<nCount; i++)
3838 : {
3839 1358 : const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
3840 1358 : long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];
3841 :
3842 1358 : long nMemberPos = nSorted;
3843 1358 : if (bIsDataLayout)
3844 : {
3845 : OSL_ENSURE(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
3846 : "DataLayout dimension twice?");
3847 6 : nMemberPos = 0;
3848 6 : nMemberMeasure = nSorted;
3849 : }
3850 :
3851 1358 : const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
3852 1358 : if ( pRefMember->IsVisible() )
3853 : {
3854 1178 : if ( bIsDataLayout )
3855 6 : rRunning.AddColIndex( 0, 0 );
3856 : else
3857 1172 : rRunning.AddColIndex( i, nSorted );
3858 :
3859 1178 : ScDPDataMember* pDataMember = maMembers[nMemberPos];
3860 : pDataMember->UpdateRunningTotals(
3861 1178 : pRefMember, nMemberMeasure, bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent);
3862 :
3863 1178 : rRunning.RemoveColIndex();
3864 : }
3865 : }
3866 296 : }
3867 :
3868 : #if DEBUG_PIVOT_TABLE
3869 : void ScDPDataDimension::DumpState( const ScDPResultDimension* pRefDim, ScDocument* pDoc, ScAddress& rPos ) const
3870 : {
3871 : OUString aDimName = bIsDataLayout ? OUString("(data layout)") : OUString("(unknown)");
3872 : lcl_DumpRow( OUString("ScDPDataDimension"), aDimName, NULL, pDoc, rPos );
3873 :
3874 : SCROW nStartRow = rPos.Row();
3875 :
3876 : long nCount = bIsDataLayout ? 1 : maMembers.size();
3877 : for (long i=0; i<nCount; i++)
3878 : {
3879 : const ScDPResultMember* pRefMember = pRefDim->GetMember(i);
3880 : const ScDPDataMember* pDataMember = maMembers[i];
3881 : pDataMember->DumpState( pRefMember, pDoc, rPos );
3882 : }
3883 :
3884 : lcl_Indent( pDoc, nStartRow, rPos );
3885 : }
3886 :
3887 : void ScDPDataDimension::Dump(int nIndent) const
3888 : {
3889 : std::string aIndent(nIndent*2, ' ');
3890 : std::cout << aIndent << "-- data dimension '"
3891 : << (pResultDimension ? pResultDimension->GetName() : OUString()) << "'" << std::endl;
3892 : ScDPDataMembers::const_iterator it = maMembers.begin(), itEnd = maMembers.end();
3893 : for (; it != itEnd; ++it)
3894 : (*it)->Dump(nIndent+1);
3895 : }
3896 : #endif
3897 :
3898 0 : long ScDPDataDimension::GetMemberCount() const
3899 : {
3900 0 : return maMembers.size();
3901 : }
3902 :
3903 0 : const ScDPDataMember* ScDPDataDimension::GetMember(long n) const
3904 : {
3905 0 : return maMembers[n];
3906 : }
3907 :
3908 0 : ScDPDataMember* ScDPDataDimension::GetMember(long n)
3909 : {
3910 0 : return maMembers[n];
3911 : }
3912 :
3913 : // ----------------------------------------------------------------------------
3914 :
3915 133 : ScDPResultVisibilityData::ScDPResultVisibilityData(
3916 : ScDPSource* pSource) :
3917 133 : mpSource(pSource)
3918 : {
3919 133 : }
3920 :
3921 133 : ScDPResultVisibilityData::~ScDPResultVisibilityData()
3922 : {
3923 133 : }
3924 :
3925 5320 : void ScDPResultVisibilityData::addVisibleMember(const OUString& rDimName, const ScDPItemData& rMemberItem)
3926 : {
3927 5320 : DimMemberType::iterator itr = maDimensions.find(rDimName);
3928 5320 : if (itr == maDimensions.end())
3929 : {
3930 : pair<DimMemberType::iterator, bool> r = maDimensions.insert(
3931 532 : DimMemberType::value_type(rDimName, VisibleMemberType()));
3932 :
3933 532 : if (!r.second)
3934 : // insertion failed.
3935 5320 : return;
3936 :
3937 532 : itr = r.first;
3938 : }
3939 5320 : VisibleMemberType& rMem = itr->second;
3940 5320 : VisibleMemberType::iterator itrMem = rMem.find(rMemberItem);
3941 5320 : if (itrMem == rMem.end())
3942 2660 : rMem.insert(rMemberItem);
3943 : }
3944 :
3945 133 : void ScDPResultVisibilityData::fillFieldFilters(vector<ScDPFilteredCache::Criterion>& rFilters) const
3946 : {
3947 : typedef boost::unordered_map<String, long, ScStringHashCode> FieldNameMapType;
3948 133 : FieldNameMapType aFieldNames;
3949 133 : ScDPTableData* pData = mpSource->GetData();
3950 133 : long nColumnCount = pData->GetColumnCount();
3951 798 : for (long i = 0; i < nColumnCount; ++i)
3952 : {
3953 : aFieldNames.insert(
3954 665 : FieldNameMapType::value_type(pData->getDimensionName(i), i));
3955 : }
3956 :
3957 133 : const ScDPDimensions* pDims = mpSource->GetDimensionsObject();
3958 665 : for (DimMemberType::const_iterator itr = maDimensions.begin(), itrEnd = maDimensions.end();
3959 : itr != itrEnd; ++itr)
3960 : {
3961 532 : const String& rDimName = itr->first;
3962 1064 : ScDPFilteredCache::Criterion aCri;
3963 532 : FieldNameMapType::const_iterator itrField = aFieldNames.find(rDimName);
3964 532 : if (itrField == aFieldNames.end())
3965 : // This should never happen!
3966 0 : continue;
3967 :
3968 532 : long nDimIndex = itrField->second;
3969 532 : aCri.mnFieldIndex = static_cast<sal_Int32>(nDimIndex);
3970 532 : aCri.mpFilter.reset(new ScDPFilteredCache::GroupFilter);
3971 :
3972 : ScDPFilteredCache::GroupFilter* pGrpFilter =
3973 532 : static_cast<ScDPFilteredCache::GroupFilter*>(aCri.mpFilter.get());
3974 :
3975 532 : const VisibleMemberType& rMem = itr->second;
3976 3192 : for (VisibleMemberType::const_iterator itrMem = rMem.begin(), itrMemEnd = rMem.end();
3977 : itrMem != itrMemEnd; ++itrMem)
3978 : {
3979 2660 : const ScDPItemData& rMemItem = *itrMem;
3980 2660 : pGrpFilter->addMatchItem(rMemItem);
3981 : }
3982 :
3983 532 : ScDPDimension* pDim = pDims->getByIndex(nDimIndex);
3984 532 : ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
3985 532 : GetLevelsObject()->getByIndex(0)->GetMembersObject();
3986 532 : if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(pMembers->getCount()))
3987 0 : rFilters.push_back(aCri);
3988 665 : }
3989 133 : }
3990 :
3991 7980 : size_t ScDPResultVisibilityData::MemberHash::operator() (const ScDPItemData& r) const
3992 : {
3993 7980 : if (r.IsValue())
3994 7980 : return static_cast<size_t>(::rtl::math::approxFloor(r.GetValue()));
3995 : else
3996 0 : return rtl_ustr_hashCode_WithLength(r.GetString().getStr(), r.GetString().getLength());
3997 : }
3998 1247 : SCROW ScDPResultMember::GetDataId( ) const
3999 : {
4000 1247 : const ScDPMember* pMemberDesc = GetDPMember();
4001 1247 : if (pMemberDesc)
4002 1247 : return pMemberDesc->GetItemDataId();
4003 0 : return -1;
4004 : }
4005 :
4006 538 : ScDPResultMember* ScDPResultDimension::AddMember(const ScDPParentDimData &aData )
4007 : {
4008 538 : ScDPResultMember* pMember = new ScDPResultMember( pResultData, aData, false );
4009 538 : SCROW nDataIndex = pMember->GetDataId();
4010 538 : maMemberArray.push_back( pMember );
4011 :
4012 538 : if ( maMemberHash.end() == maMemberHash.find( nDataIndex ) )
4013 531 : maMemberHash.insert( std::pair< SCROW, ScDPResultMember *>( nDataIndex, pMember ) );
4014 538 : return pMember;
4015 : }
4016 :
4017 63 : ScDPResultMember* ScDPResultDimension::InsertMember(ScDPParentDimData *pMemberData)
4018 : {
4019 63 : SCROW nInsert = 0;
4020 63 : if ( !lcl_SearchMember( maMemberArray, pMemberData->mnOrder , nInsert ) )
4021 : {
4022 63 : ScDPResultMember* pNew = new ScDPResultMember( pResultData, *pMemberData, false );
4023 63 : maMemberArray.insert( maMemberArray.begin()+nInsert, pNew );
4024 :
4025 63 : SCROW nDataIndex = pMemberData->mpMemberDesc->GetItemDataId();
4026 63 : if ( maMemberHash.end() == maMemberHash.find( nDataIndex ) )
4027 63 : maMemberHash.insert( std::pair< SCROW, ScDPResultMember *>( nDataIndex, pNew ) );
4028 63 : return pNew;
4029 : }
4030 0 : return maMemberArray[ nInsert ];
4031 : }
4032 :
4033 76 : void ScDPResultDimension::InitWithMembers(
4034 : LateInitParams& rParams, const std::vector<SCROW>& pItemData, size_t nPos,
4035 : ScDPInitState& rInitState)
4036 : {
4037 76 : if ( rParams.IsEnd( nPos ) )
4038 76 : return;
4039 76 : ScDPDimension* pThisDim = rParams.GetDim( nPos );
4040 76 : ScDPLevel* pThisLevel = rParams.GetLevel( nPos );
4041 76 : SCROW nDataID = pItemData[nPos];
4042 :
4043 76 : if (pThisDim && pThisLevel)
4044 : {
4045 76 : long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
4046 :
4047 : // create all members at the first call (preserve order)
4048 76 : ResultMembers* pMembers = pResultData->GetDimResultMembers(nDimSource, pThisDim, pThisLevel);
4049 76 : ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
4050 : // initialize only specific member (or all if "show empty" flag is set)
4051 76 : ScDPResultMember* pResultMember = NULL;
4052 76 : if ( bInitialized )
4053 32 : pResultMember = FindMember( nDataID );
4054 : else
4055 44 : bInitialized = true;
4056 :
4057 76 : if ( pResultMember == NULL )
4058 : { //only insert found item
4059 63 : ScDPParentDimData* pMemberData = pMembers->FindMember( nDataID );
4060 63 : if ( pMemberData && aCompare.IsIncluded( *( pMemberData->mpMemberDesc ) ) )
4061 63 : pResultMember = InsertMember( pMemberData );
4062 : }
4063 76 : if ( pResultMember )
4064 : {
4065 76 : rInitState.AddMember( nDimSource, pResultMember->GetDataId() );
4066 76 : pResultMember->LateInitFrom(rParams, pItemData, nPos+1, rInitState);
4067 76 : rInitState.RemoveMember();
4068 76 : }
4069 : }
4070 : }
4071 :
4072 156 : ScDPParentDimData::ScDPParentDimData() :
4073 156 : mnOrder(-1), mpParentDim(NULL), mpParentLevel(NULL), mpMemberDesc(NULL) {}
4074 :
4075 1191 : ScDPParentDimData::ScDPParentDimData(
4076 : SCROW nIndex, const ScDPDimension* pDim, const ScDPLevel* pLev, const ScDPMember* pMember) :
4077 1191 : mnOrder(nIndex), mpParentDim(pDim), mpParentLevel(pLev), mpMemberDesc(pMember) {}
4078 :
4079 716 : ScDPParentDimData* ResultMembers::FindMember( SCROW nIndex ) const
4080 : {
4081 716 : DimMemberHash::const_iterator aRes = maMemberHash.find( nIndex );
4082 716 : if( aRes != maMemberHash.end()) {
4083 63 : if ( aRes->second->mpMemberDesc && aRes->second->mpMemberDesc->GetItemDataId()==nIndex )
4084 63 : return aRes->second;
4085 : }
4086 653 : return NULL;
4087 : }
4088 653 : void ResultMembers::InsertMember( ScDPParentDimData* pNew )
4089 : {
4090 653 : if ( !pNew->mpMemberDesc->getShowDetails() )
4091 0 : mbHasHideDetailsMember = true;
4092 653 : maMemberHash.insert( std::pair< const SCROW, ScDPParentDimData *>( pNew->mpMemberDesc->GetItemDataId(), pNew ) );
4093 653 : }
4094 :
4095 142 : ResultMembers::ResultMembers():
4096 142 : mbHasHideDetailsMember( false )
4097 : {
4098 142 : }
4099 336 : ResultMembers::~ResultMembers()
4100 : {
4101 641 : for ( DimMemberHash::const_iterator iter = maMemberHash.begin(); iter != maMemberHash.end(); ++iter )
4102 529 : delete iter->second;
4103 224 : }
4104 : // -----------------------------------------------------------------------
4105 828 : LateInitParams::LateInitParams(
4106 : const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev, bool bRow, bool bInitChild, bool bAllChildren ) :
4107 : mppDim( ppDim ),
4108 : mppLev( ppLev ),
4109 : mbRow( bRow ),
4110 : mbInitChild( bInitChild ),
4111 828 : mbAllChildren( bAllChildren )
4112 : {
4113 828 : }
4114 :
4115 828 : LateInitParams::~LateInitParams()
4116 : {
4117 828 : }
4118 :
4119 2220 : bool LateInitParams::IsEnd( size_t nPos ) const
4120 : {
4121 2220 : return nPos >= mppDim.size();
4122 : }
4123 :
4124 164 : void ScDPResultDimension::CheckShowEmpty( bool bShow )
4125 : {
4126 164 : long nCount = maMemberArray.size();
4127 :
4128 164 : ScDPResultMember* pMember = NULL;
4129 759 : for (long i=0; i<nCount; i++)
4130 : {
4131 595 : pMember = maMemberArray.at(i);
4132 595 : pMember->CheckShowEmpty(bShow);
4133 : }
4134 :
4135 164 : }
4136 :
4137 751 : void ScDPResultMember::CheckShowEmpty( bool bShow )
4138 : {
4139 751 : if (bHasElements)
4140 : {
4141 679 : ScDPResultDimension* pChildDim = GetChildDimension();
4142 679 : if (pChildDim)
4143 164 : pChildDim->CheckShowEmpty();
4144 : }
4145 72 : else if (IsValid() && bInitialized)
4146 : {
4147 7 : bShow = bShow || (GetParentLevel() && GetParentLevel()->getShowEmpty());
4148 7 : if (bShow)
4149 : {
4150 7 : SetHasElements();
4151 7 : ScDPResultDimension* pChildDim = GetChildDimension();
4152 7 : if (pChildDim)
4153 0 : pChildDim->CheckShowEmpty(true);
4154 : }
4155 : }
4156 844 : }
4157 :
4158 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|