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