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