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