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