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