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