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