1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dptabres.hxx"
22 #include "dptabdat.hxx"
23 #include "dptabsrc.hxx"
25 #include "subtotal.hxx"
26 #include "globstr.hrc"
27 #include "dpitemdata.hxx"
29 #include "document.hxx"
30 #include "dpresfilter.hxx"
33 #include <osl/diagnose.h>
34 #include <rtl/math.hxx>
35 #include <rtl/strbuf.hxx>
40 #include <unordered_map>
41 #include <boost/checked_delete.hpp>
42 #include <boost/scoped_ptr.hpp>
44 #include <com/sun/star/sheet/DataResultFlags.hpp>
45 #include <com/sun/star/sheet/MemberResultFlags.hpp>
46 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
47 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
48 #include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
49 #include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
50 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
51 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
53 using namespace com::sun::star
;
56 using ::com::sun::star::uno::Sequence
;
60 sal_uInt16 nFuncStrIds
[12] = // matching enum ScSubTotalFunc
62 0, // SUBTOTAL_FUNC_NONE
63 STR_FUN_TEXT_AVG
, // SUBTOTAL_FUNC_AVE
64 STR_FUN_TEXT_COUNT
, // SUBTOTAL_FUNC_CNT
65 STR_FUN_TEXT_COUNT
, // SUBTOTAL_FUNC_CNT2
66 STR_FUN_TEXT_MAX
, // SUBTOTAL_FUNC_MAX
67 STR_FUN_TEXT_MIN
, // SUBTOTAL_FUNC_MIN
68 STR_FUN_TEXT_PRODUCT
, // SUBTOTAL_FUNC_PROD
69 STR_FUN_TEXT_STDDEV
, // SUBTOTAL_FUNC_STD
70 STR_FUN_TEXT_STDDEV
, // SUBTOTAL_FUNC_STDP
71 STR_FUN_TEXT_SUM
, // SUBTOTAL_FUNC_SUM
72 STR_FUN_TEXT_VAR
, // SUBTOTAL_FUNC_VAR
73 STR_FUN_TEXT_VAR
// SUBTOTAL_FUNC_VARP
76 bool lcl_SearchMember( const std::vector
<ScDPResultMember
*>& list
, SCROW nOrder
, SCROW
& rIndex
)
81 SCROW nHi
= list
.size() - 1;
85 nIndex
= (nLo
+ nHi
) / 2;
86 if ( list
[nIndex
]->GetOrder() < nOrder
)
91 if ( list
[nIndex
]->GetOrder() == nOrder
)
104 std::vector
<ScDPResultFilter
>& mrFilters
;
106 FilterStack(std::vector
<ScDPResultFilter
>& rFilters
) : mrFilters(rFilters
) {}
108 void pushDimName(const OUString
& rName
, bool bDataLayout
)
110 mrFilters
.push_back(ScDPResultFilter(rName
, bDataLayout
));
113 void pushDimValue(const OUString
& rValue
)
115 ScDPResultFilter
& rFilter
= mrFilters
.back();
116 rFilter
.maValue
= rValue
;
117 rFilter
.mbHasValue
= true;
122 ScDPResultFilter
& rFilter
= mrFilters
.back();
123 if (rFilter
.mbHasValue
)
124 rFilter
.mbHasValue
= false;
126 mrFilters
.pop_back();
132 // function objects for sorting of the column and row members:
134 class ScDPRowMembersOrder
136 ScDPResultDimension
& rDimension
;
141 ScDPRowMembersOrder( ScDPResultDimension
& rDim
, long nM
, bool bAsc
) :
146 ~ScDPRowMembersOrder() {}
148 bool operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const;
151 class ScDPColMembersOrder
153 ScDPDataDimension
& rDimension
;
158 ScDPColMembersOrder( ScDPDataDimension
& rDim
, long nM
, bool bAsc
) :
163 ~ScDPColMembersOrder() {}
165 bool operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const;
168 static bool lcl_IsLess( const ScDPDataMember
* pDataMember1
, const ScDPDataMember
* pDataMember2
, long nMeasure
, bool bAscending
)
170 // members can be NULL if used for rows
172 ScDPSubTotalState aEmptyState
;
173 const ScDPAggData
* pAgg1
= pDataMember1
? pDataMember1
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
174 const ScDPAggData
* pAgg2
= pDataMember2
? pDataMember2
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
176 bool bError1
= pAgg1
&& pAgg1
->HasError();
177 bool bError2
= pAgg2
&& pAgg2
->HasError();
179 return false; // errors are always sorted at the end
181 return true; // errors are always sorted at the end
184 double fVal1
= ( pAgg1
&& pAgg1
->HasData() ) ? pAgg1
->GetResult() : 0.0; // no data is sorted as 0
185 double fVal2
= ( pAgg2
&& pAgg2
->HasData() ) ? pAgg2
->GetResult() : 0.0;
188 // don't have to check approxEqual, as this is the only sort criterion
190 return bAscending
? ( fVal1
< fVal2
) : ( fVal1
> fVal2
);
194 static bool lcl_IsEqual( const ScDPDataMember
* pDataMember1
, const ScDPDataMember
* pDataMember2
, long nMeasure
)
196 // members can be NULL if used for rows
198 ScDPSubTotalState aEmptyState
;
199 const ScDPAggData
* pAgg1
= pDataMember1
? pDataMember1
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
200 const ScDPAggData
* pAgg2
= pDataMember2
? pDataMember2
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
202 bool bError1
= pAgg1
&& pAgg1
->HasError();
203 bool bError2
= pAgg2
&& pAgg2
->HasError();
207 return true; // equal
215 double fVal1
= ( pAgg1
&& pAgg1
->HasData() ) ? pAgg1
->GetResult() : 0.0; // no data is sorted as 0
216 double fVal2
= ( pAgg2
&& pAgg2
->HasData() ) ? pAgg2
->GetResult() : 0.0;
219 // this is used to find equal data at the end of the AutoShow range, so approxEqual must be used
221 return rtl::math::approxEqual( fVal1
, fVal2
);
225 bool ScDPRowMembersOrder::operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const
227 const ScDPResultMember
* pMember1
= rDimension
.GetMember(nIndex1
);
228 const ScDPResultMember
* pMember2
= rDimension
.GetMember(nIndex2
);
230 // make the hide item to the largest order.
231 if ( !pMember1
->IsVisible() || !pMember2
->IsVisible() )
232 return pMember1
->IsVisible();
233 const ScDPDataMember
* pDataMember1
= pMember1
->GetDataRoot() ;
234 const ScDPDataMember
* pDataMember2
= pMember2
->GetDataRoot();
235 // GetDataRoot can be NULL if there was no data.
236 // IsVisible == false can happen after AutoShow.
237 return lcl_IsLess( pDataMember1
, pDataMember2
, nMeasure
, bAscending
);
240 bool ScDPColMembersOrder::operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const
242 const ScDPDataMember
* pDataMember1
= rDimension
.GetMember(nIndex1
);
243 const ScDPDataMember
* pDataMember2
= rDimension
.GetMember(nIndex2
);
244 bool bHide1
= pDataMember1
&& !pDataMember1
->IsVisible();
245 bool bHide2
= pDataMember2
&& !pDataMember2
->IsVisible();
246 if ( bHide1
|| bHide2
)
248 return lcl_IsLess( pDataMember1
, pDataMember2
, nMeasure
, bAscending
);
251 ScDPInitState::Member::Member(long nSrcIndex
, SCROW nNameIndex
) :
252 mnSrcIndex(nSrcIndex
), mnNameIndex(nNameIndex
) {}
254 void ScDPInitState::AddMember( long nSourceIndex
, SCROW nMember
)
256 maMembers
.push_back(Member(nSourceIndex
, nMember
));
259 void ScDPInitState::RemoveMember()
261 OSL_ENSURE(!maMembers
.empty(), "ScDPInitState::RemoveMember: Attempt to remmove member while empty.");
262 if (!maMembers
.empty())
263 maMembers
.pop_back();
268 #if DEBUG_PIVOT_TABLE
270 const OUString
& rType
, const OUString
& rName
, const ScDPAggData
* pAggData
,
271 ScDocument
* pDoc
, ScAddress
& rPos
)
273 SCCOL nCol
= rPos
.Col();
274 SCROW nRow
= rPos
.Row();
275 SCTAB nTab
= rPos
.Tab();
276 pDoc
->SetString( nCol
++, nRow
, nTab
, rType
);
277 pDoc
->SetString( nCol
++, nRow
, nTab
, rName
);
280 pDoc
->SetValue( nCol
++, nRow
, nTab
, pAggData
->GetResult() );
281 pAggData
= pAggData
->GetExistingChild();
283 rPos
.SetRow( nRow
+ 1 );
286 void lcl_Indent( ScDocument
* pDoc
, SCROW nStartRow
, const ScAddress
& rPos
)
288 SCCOL nCol
= rPos
.Col();
289 SCTAB nTab
= rPos
.Tab();
292 for (SCROW nRow
= nStartRow
; nRow
< rPos
.Row(); nRow
++)
294 aString
= pDoc
->GetString(nCol
, nRow
, nTab
);
295 if (!aString
.isEmpty())
297 aString
= " " + aString
;
298 pDoc
->SetString( nCol
, nRow
, nTab
, aString
);
306 ScDPRunningTotalState::ScDPRunningTotalState( ScDPResultMember
* pColRoot
, ScDPResultMember
* pRowRoot
) :
307 pColResRoot(pColRoot
), pRowResRoot(pRowRoot
)
309 // These arrays should never be empty as the terminating value must be present at all times.
310 maColVisible
.push_back(-1);
311 maColSorted
.push_back(-1);
312 maRowVisible
.push_back(-1);
313 maRowSorted
.push_back(-1);
316 void ScDPRunningTotalState::AddColIndex( long nVisible
, long nSorted
)
318 maColVisible
.back() = nVisible
;
319 maColVisible
.push_back(-1);
321 maColSorted
.back() = nSorted
;
322 maColSorted
.push_back(-1);
325 void ScDPRunningTotalState::AddRowIndex( long nVisible
, long nSorted
)
327 maRowVisible
.back() = nVisible
;
328 maRowVisible
.push_back(-1);
330 maRowSorted
.back() = nSorted
;
331 maRowSorted
.push_back(-1);
334 void ScDPRunningTotalState::RemoveColIndex()
336 OSL_ENSURE(!maColVisible
.empty() && !maColSorted
.empty(), "ScDPRunningTotalState::RemoveColIndex: array is already empty!");
337 if (maColVisible
.size() >= 2)
339 maColVisible
.pop_back();
340 maColVisible
.back() = -1;
343 if (maColSorted
.size() >= 2)
345 maColSorted
.pop_back();
346 maColSorted
.back() = -1;
350 void ScDPRunningTotalState::RemoveRowIndex()
352 OSL_ENSURE(!maRowVisible
.empty() && !maRowSorted
.empty(), "ScDPRunningTotalState::RemoveRowIndex: array is already empty!");
353 if (maRowVisible
.size() >= 2)
355 maRowVisible
.pop_back();
356 maRowVisible
.back() = -1;
359 if (maRowSorted
.size() >= 2)
361 maRowSorted
.pop_back();
362 maRowSorted
.back() = -1;
366 ScDPRelativePos::ScDPRelativePos( long nBase
, long nDir
) :
372 void ScDPAggData::Update( const ScDPValue
& rNext
, ScSubTotalFunc eFunc
, const ScDPSubTotalState
& rSubState
)
374 if (nCount
<0) // error?
375 return; // nothing more...
377 if (rNext
.meType
== ScDPValue::Empty
)
380 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
&& rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
&&
381 rSubState
.eColForce
!= rSubState
.eRowForce
)
383 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eColForce
;
384 if ( rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eRowForce
;
386 if ( eFunc
== SUBTOTAL_FUNC_NONE
)
389 if ( eFunc
!= SUBTOTAL_FUNC_CNT2
) // CNT2 counts everything, incl. strings and errors
391 if (rNext
.meType
== ScDPValue::Error
)
393 nCount
= -1; // -1 for error (not for CNT2)
396 if (rNext
.meType
== ScDPValue::String
)
400 ++nCount
; // for all functions
404 case SUBTOTAL_FUNC_SUM
:
405 case SUBTOTAL_FUNC_AVE
:
406 if ( !SubTotal::SafePlus( fVal
, rNext
.mfValue
) )
407 nCount
= -1; // -1 for error
409 case SUBTOTAL_FUNC_PROD
:
410 if ( nCount
== 1 ) // copy first value (fVal is initialized to 0)
411 fVal
= rNext
.mfValue
;
412 else if ( !SubTotal::SafeMult( fVal
, rNext
.mfValue
) )
413 nCount
= -1; // -1 for error
415 case SUBTOTAL_FUNC_CNT
:
416 case SUBTOTAL_FUNC_CNT2
:
417 // nothing more than incrementing nCount
419 case SUBTOTAL_FUNC_MAX
:
420 if ( nCount
== 1 || rNext
.mfValue
> fVal
)
421 fVal
= rNext
.mfValue
;
423 case SUBTOTAL_FUNC_MIN
:
424 if ( nCount
== 1 || rNext
.mfValue
< fVal
)
425 fVal
= rNext
.mfValue
;
427 case SUBTOTAL_FUNC_STD
:
428 case SUBTOTAL_FUNC_STDP
:
429 case SUBTOTAL_FUNC_VAR
:
430 case SUBTOTAL_FUNC_VARP
:
432 // fAux is used to sum up squares
433 if ( !SubTotal::SafePlus( fVal
, rNext
.mfValue
) )
434 nCount
= -1; // -1 for error
435 double fAdd
= rNext
.mfValue
;
436 if ( !SubTotal::SafeMult( fAdd
, rNext
.mfValue
) ||
437 !SubTotal::SafePlus( fAux
, fAdd
) )
438 nCount
= -1; // -1 for error
442 OSL_FAIL("invalid function");
446 void ScDPAggData::Calculate( ScSubTotalFunc eFunc
, const ScDPSubTotalState
& rSubState
)
448 // calculate the original result
449 // (without reference value, used as the basis for reference value calculation)
451 // called several times at the cross-section of several subtotals - don't calculate twice then
452 if ( IsCalculated() )
455 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eColForce
;
456 if ( rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eRowForce
;
458 if ( eFunc
== SUBTOTAL_FUNC_NONE
) // this happens when there is no data dimension
460 nCount
= SC_DPAGG_RESULT_EMPTY
; // make sure there's a valid state for HasData etc.
464 // check the error conditions for the selected function
469 case SUBTOTAL_FUNC_SUM
:
470 case SUBTOTAL_FUNC_PROD
:
471 case SUBTOTAL_FUNC_CNT
:
472 case SUBTOTAL_FUNC_CNT2
:
473 bError
= ( nCount
< 0 ); // only real errors
476 case SUBTOTAL_FUNC_AVE
:
477 case SUBTOTAL_FUNC_MAX
:
478 case SUBTOTAL_FUNC_MIN
:
479 case SUBTOTAL_FUNC_STDP
:
480 case SUBTOTAL_FUNC_VARP
:
481 bError
= ( nCount
<= 0 ); // no data is an error
484 case SUBTOTAL_FUNC_STD
:
485 case SUBTOTAL_FUNC_VAR
:
486 bError
= ( nCount
< 2 ); // need at least 2 values
490 OSL_FAIL("invalid function");
493 // calculate the selected function
495 double fResult
= 0.0;
500 case SUBTOTAL_FUNC_MAX
:
501 case SUBTOTAL_FUNC_MIN
:
502 case SUBTOTAL_FUNC_SUM
:
503 case SUBTOTAL_FUNC_PROD
:
504 // different error conditions are handled above
508 case SUBTOTAL_FUNC_CNT
:
509 case SUBTOTAL_FUNC_CNT2
:
513 case SUBTOTAL_FUNC_AVE
:
515 fResult
= fVal
/ (double) nCount
;
518 //TODO: use safe mul for fVal * fVal
520 case SUBTOTAL_FUNC_STD
:
522 fResult
= sqrt((fAux
- fVal
*fVal
/(double)(nCount
)) / (double)(nCount
-1));
524 case SUBTOTAL_FUNC_VAR
:
526 fResult
= (fAux
- fVal
*fVal
/(double)(nCount
)) / (double)(nCount
-1);
528 case SUBTOTAL_FUNC_STDP
:
530 fResult
= sqrt((fAux
- fVal
*fVal
/(double)(nCount
)) / (double)nCount
);
532 case SUBTOTAL_FUNC_VARP
:
534 fResult
= (fAux
- fVal
*fVal
/(double)(nCount
)) / (double)nCount
;
537 OSL_FAIL("invalid function");
541 bool bEmpty
= ( nCount
== 0 ); // no data
544 // Empty is checked first, so empty results are shown empty even for "average" etc.
545 // If these results should be treated as errors in reference value calculations,
546 // a separate state value (EMPTY_ERROR) is needed.
547 // Now, for compatibility, empty "average" results are counted as 0.
550 nCount
= SC_DPAGG_RESULT_EMPTY
;
552 nCount
= SC_DPAGG_RESULT_ERROR
;
554 nCount
= SC_DPAGG_RESULT_VALID
;
556 if ( bEmpty
|| bError
)
557 fResult
= 0.0; // default, in case the state is later modified
559 fVal
= fResult
; // used directly from now on
560 fAux
= 0.0; // used for running total or original result of reference value
563 bool ScDPAggData::IsCalculated() const
565 return ( nCount
<= SC_DPAGG_RESULT_EMPTY
);
568 double ScDPAggData::GetResult() const
570 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
572 return fVal
; // use calculated value
575 bool ScDPAggData::HasError() const
577 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
579 return ( nCount
== SC_DPAGG_RESULT_ERROR
);
582 bool ScDPAggData::HasData() const
584 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
586 return ( nCount
!= SC_DPAGG_RESULT_EMPTY
); // values or error
589 void ScDPAggData::SetResult( double fNew
)
591 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
593 fVal
= fNew
; // don't reset error flag
596 void ScDPAggData::SetError()
598 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
600 nCount
= SC_DPAGG_RESULT_ERROR
;
603 void ScDPAggData::SetEmpty( bool bSet
)
605 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
608 nCount
= SC_DPAGG_RESULT_EMPTY
;
610 nCount
= SC_DPAGG_RESULT_VALID
;
613 double ScDPAggData::GetAuxiliary() const
615 // after Calculate, fAux is used as auxiliary value for running totals and reference values
616 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
621 void ScDPAggData::SetAuxiliary( double fNew
)
623 // after Calculate, fAux is used as auxiliary value for running totals and reference values
624 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
629 ScDPAggData
* ScDPAggData::GetChild()
632 pChild
= new ScDPAggData
;
636 void ScDPAggData::Reset()
640 nCount
= SC_DPAGG_EMPTY
;
645 #if DEBUG_PIVOT_TABLE
646 void ScDPAggData::Dump(int nIndent
) const
648 std::string
aIndent(nIndent
*2, ' ');
649 std::cout
<< aIndent
<< "* ";
651 std::cout
<< GetResult();
653 std::cout
<< "not calculated";
655 std::cout
<< " [val=" << fVal
<< "; aux=" << fAux
<< "; count=" << nCount
<< "]" << std::endl
;
659 ScDPRowTotals::ScDPRowTotals() :
660 bIsInColRoot( false )
664 ScDPRowTotals::~ScDPRowTotals()
668 static ScDPAggData
* lcl_GetChildTotal( ScDPAggData
* pFirst
, long nMeasure
)
670 OSL_ENSURE( nMeasure
>= 0, "GetColTotal: no measure" );
672 ScDPAggData
* pAgg
= pFirst
;
673 long nSkip
= nMeasure
;
675 // subtotal settings are ignored - column/row totals exist once per measure
677 for ( long nPos
=0; nPos
<nSkip
; nPos
++ )
678 pAgg
= pAgg
->GetChild(); // column total is constructed empty - children need to be created
680 if ( !pAgg
->IsCalculated() )
682 // for first use, simulate an empty calculation
683 ScDPSubTotalState aEmptyState
;
684 pAgg
->Calculate( SUBTOTAL_FUNC_SUM
, aEmptyState
);
690 ScDPAggData
* ScDPRowTotals::GetRowTotal( long nMeasure
)
692 return lcl_GetChildTotal( &aRowTotal
, nMeasure
);
695 ScDPAggData
* ScDPRowTotals::GetGrandTotal( long nMeasure
)
697 return lcl_GetChildTotal( &aGrandTotal
, nMeasure
);
700 static ScSubTotalFunc
lcl_GetForceFunc( const ScDPLevel
* pLevel
, long nFuncNo
)
702 ScSubTotalFunc eRet
= SUBTOTAL_FUNC_NONE
;
705 //TODO: direct access via ScDPLevel
707 uno::Sequence
<sheet::GeneralFunction
> aSeq
= pLevel
->getSubTotals();
708 long nSequence
= aSeq
.getLength();
709 if ( nSequence
&& aSeq
[0] != sheet::GeneralFunction_AUTO
)
711 // For manual subtotals, "automatic" is added as first function.
712 // ScDPResultMember::GetSubTotalCount adds to the count, here NONE has to be
713 // returned as the first function then.
715 --nFuncNo
; // keep NONE for first (check below), move the other entries
718 if ( nFuncNo
>= 0 && nFuncNo
< nSequence
)
720 sheet::GeneralFunction eUser
= aSeq
.getConstArray()[nFuncNo
];
721 if (eUser
!= sheet::GeneralFunction_AUTO
)
722 eRet
= ScDPUtil::toSubTotalFunc(eUser
);
728 ScDPResultData::ScDPResultData( ScDPSource
& rSrc
) :
736 ScDPResultData::~ScDPResultData()
738 std::for_each(maDimMembers
.begin(), maDimMembers
.end(), boost::checked_deleter
<ResultMembers
>());
741 void ScDPResultData::SetMeasureData(
742 std::vector
<ScSubTotalFunc
>& rFunctions
, std::vector
<sheet::DataPilotFieldReference
>& rRefs
,
743 std::vector
<sal_uInt16
>& rRefOrient
, std::vector
<OUString
>& rNames
)
745 // We need to have at least one measure data at all times.
747 maMeasureFuncs
.swap(rFunctions
);
748 if (maMeasureFuncs
.empty())
749 maMeasureFuncs
.push_back(SUBTOTAL_FUNC_NONE
);
751 maMeasureRefs
.swap(rRefs
);
752 if (maMeasureRefs
.empty())
753 maMeasureRefs
.push_back(sheet::DataPilotFieldReference()); // default ctor is ok.
755 maMeasureRefOrients
.swap(rRefOrient
);
756 if (maMeasureRefOrients
.empty())
757 maMeasureRefOrients
.push_back(sheet::DataPilotFieldOrientation_HIDDEN
);
759 maMeasureNames
.swap(rNames
);
760 if (maMeasureNames
.empty())
761 maMeasureNames
.push_back(ScGlobal::GetRscString(STR_EMPTYDATA
));
764 void ScDPResultData::SetDataLayoutOrientation( sal_uInt16 nOrient
)
766 bDataAtCol
= ( nOrient
== sheet::DataPilotFieldOrientation_COLUMN
);
767 bDataAtRow
= ( nOrient
== sheet::DataPilotFieldOrientation_ROW
);
770 void ScDPResultData::SetLateInit( bool bSet
)
775 long ScDPResultData::GetColStartMeasure() const
777 if (maMeasureFuncs
.size() == 1)
780 return bDataAtCol
? SC_DPMEASURE_ALL
: SC_DPMEASURE_ANY
;
783 long ScDPResultData::GetRowStartMeasure() const
785 if (maMeasureFuncs
.size() == 1)
788 return bDataAtRow
? SC_DPMEASURE_ALL
: SC_DPMEASURE_ANY
;
791 ScSubTotalFunc
ScDPResultData::GetMeasureFunction(long nMeasure
) const
793 OSL_ENSURE((size_t) nMeasure
< maMeasureFuncs
.size(), "bumm");
794 return maMeasureFuncs
[nMeasure
];
797 const sheet::DataPilotFieldReference
& ScDPResultData::GetMeasureRefVal(long nMeasure
) const
799 OSL_ENSURE((size_t) nMeasure
< maMeasureRefs
.size(), "bumm");
800 return maMeasureRefs
[nMeasure
];
803 sal_uInt16
ScDPResultData::GetMeasureRefOrient(long nMeasure
) const
805 OSL_ENSURE((size_t) nMeasure
< maMeasureRefOrients
.size(), "bumm");
806 return maMeasureRefOrients
[nMeasure
];
809 OUString
ScDPResultData::GetMeasureString(long nMeasure
, bool bForce
, ScSubTotalFunc eForceFunc
, bool& rbTotalResult
) const
811 // with bForce==true, return function instead of "result" for single measure
812 // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
813 rbTotalResult
= false;
814 if ( nMeasure
< 0 || (maMeasureFuncs
.size() == 1 && !bForce
&& eForceFunc
== SUBTOTAL_FUNC_NONE
) )
816 // for user-specified subtotal function with all measures,
817 // display only function name
818 if ( eForceFunc
!= SUBTOTAL_FUNC_NONE
)
819 return ScGlobal::GetRscString(nFuncStrIds
[eForceFunc
]);
821 rbTotalResult
= true;
822 return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS
);
826 OSL_ENSURE((size_t) nMeasure
< maMeasureFuncs
.size(), "bumm");
827 const ScDPDimension
* pDataDim
= mrSource
.GetDataDimension(nMeasure
);
830 const OUString
* pLayoutName
= pDataDim
->GetLayoutName();
835 ScSubTotalFunc eFunc
= ( eForceFunc
== SUBTOTAL_FUNC_NONE
) ?
836 GetMeasureFunction(nMeasure
) : eForceFunc
;
838 return ScDPUtil::getDisplayedMeasureName(maMeasureNames
[nMeasure
], eFunc
);
842 OUString
ScDPResultData::GetMeasureDimensionName(long nMeasure
) const
846 OSL_FAIL("GetMeasureDimensionName: negative");
847 return OUString("***");
850 return mrSource
.GetDataDimName(nMeasure
);
853 bool ScDPResultData::IsBaseForGroup( long nDim
) const
855 return mrSource
.GetData()->IsBaseForGroup(nDim
);
858 long ScDPResultData::GetGroupBase( long nGroupDim
) const
860 return mrSource
.GetData()->GetGroupBase(nGroupDim
);
863 bool ScDPResultData::IsNumOrDateGroup( long nDim
) const
865 return mrSource
.GetData()->IsNumOrDateGroup(nDim
);
868 bool ScDPResultData::IsInGroup( SCROW nGroupDataId
, long nGroupIndex
,
869 const ScDPItemData
& rBaseData
, long nBaseIndex
) const
871 const ScDPItemData
* pGroupData
= mrSource
.GetItemDataById(nGroupIndex
, nGroupDataId
);
873 return mrSource
.GetData()->IsInGroup(*pGroupData
, nGroupIndex
, rBaseData
, nBaseIndex
);
878 bool ScDPResultData::HasCommonElement( SCROW nFirstDataId
, long nFirstIndex
,
879 const ScDPItemData
& rSecondData
, long nSecondIndex
) const
881 const ScDPItemData
* pFirstData
= mrSource
.GetItemDataById(nFirstIndex
, nFirstDataId
);
883 return mrSource
.GetData()->HasCommonElement(*pFirstData
, nFirstIndex
, rSecondData
, nSecondIndex
);
888 ResultMembers
* ScDPResultData::GetDimResultMembers(long nDim
, ScDPDimension
* pDim
, ScDPLevel
* pLevel
) const
890 if (nDim
< static_cast<long>(maDimMembers
.size()) && maDimMembers
[nDim
])
891 return maDimMembers
[nDim
];
893 maDimMembers
.resize(nDim
+1, NULL
);
895 ResultMembers
* pResultMembers
= new ResultMembers();
896 // global order is used to initialize aMembers, so it doesn't have to be looked at later
897 const ScMemberSortOrder
& rGlobalOrder
= pLevel
->GetGlobalOrder();
899 ScDPMembers
* pMembers
= pLevel
->GetMembersObject();
900 long nMembCount
= pMembers
->getCount();
901 for (long i
= 0; i
< nMembCount
; ++i
)
903 long nSorted
= rGlobalOrder
.empty() ? i
: rGlobalOrder
[i
];
904 ScDPMember
* pMember
= pMembers
->getByIndex(nSorted
);
905 if (!pResultMembers
->FindMember(pMember
->GetItemDataId()))
907 ScDPParentDimData
* pNew
= new ScDPParentDimData(i
, pDim
, pLevel
, pMember
);
908 pResultMembers
->InsertMember(pNew
);
912 maDimMembers
[nDim
] = pResultMembers
;
913 return maDimMembers
[nDim
];
916 ScDPResultMember::ScDPResultMember(
917 const ScDPResultData
* pData
, const ScDPParentDimData
& rParentDimData
, bool bForceSub
) :
918 pResultData( pData
),
919 aParentDimData( rParentDimData
),
920 pChildDimension( NULL
),
922 bHasElements( false ),
923 bForceSubTotal( bForceSub
),
924 bHasHiddenDetails( false ),
925 bInitialized( false ),
926 bAutoHidden( false ),
929 // pParentLevel/pMemberDesc is 0 for root members
932 ScDPResultMember::ScDPResultMember(
933 const ScDPResultData
* pData
, bool bForceSub
) :
934 pResultData( pData
),
935 pChildDimension( NULL
),
937 bHasElements( false ),
938 bForceSubTotal( bForceSub
),
939 bHasHiddenDetails( false ),
940 bInitialized( false ),
941 bAutoHidden( false ),
945 ScDPResultMember::~ScDPResultMember()
947 delete pChildDimension
;
951 OUString
ScDPResultMember::GetName() const
953 const ScDPMember
* pMemberDesc
= GetDPMember();
955 return pMemberDesc
->GetNameStr();
957 return ScGlobal::GetRscString(STR_PIVOT_TOTAL
); // root member
960 OUString
ScDPResultMember::GetDisplayName() const
962 const ScDPMember
* pDPMember
= GetDPMember();
967 pDPMember
->FillItemData(aItem
);
968 if (aParentDimData
.mpParentDim
)
970 long nDim
= aParentDimData
.mpParentDim
->GetDimension();
971 return pResultData
->GetSource().GetData()->GetFormattedString(nDim
, aItem
);
974 return aItem
.GetString();
977 void ScDPResultMember::FillItemData( ScDPItemData
& rData
) const
979 const ScDPMember
* pMemberDesc
= GetDPMember();
981 pMemberDesc
->FillItemData( rData
);
983 rData
.SetString( ScGlobal::GetRscString(STR_PIVOT_TOTAL
) ); // root member
986 bool ScDPResultMember::IsNamedItem( SCROW nIndex
) const
988 //TODO: store ScDPMember pointer instead of ScDPMember ???
989 const ScDPMember
* pMemberDesc
= GetDPMember();
991 return pMemberDesc
->IsNamedItem(nIndex
);
995 bool ScDPResultMember::IsValidEntry( const vector
< SCROW
>& aMembers
) const
1000 const ScDPResultDimension
* pChildDim
= GetChildDimension();
1003 if (aMembers
.size() < 2)
1006 vector
<SCROW
>::const_iterator itr
= aMembers
.begin();
1007 vector
<SCROW
> aChildMembers(++itr
, aMembers
.end());
1008 return pChildDim
->IsValidEntry(aChildMembers
);
1014 void ScDPResultMember::InitFrom( const vector
<ScDPDimension
*>& ppDim
, const vector
<ScDPLevel
*>& ppLev
,
1015 size_t nPos
, ScDPInitState
& rInitState
,
1018 // with LateInit, initialize only those members that have data
1019 if ( pResultData
->IsLateInit() )
1022 bInitialized
= true;
1024 if (nPos
>= ppDim
.size())
1027 // skip child dimension if details are not shown
1028 if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1030 // Show DataLayout dimension
1032 while ( nPos
< ppDim
.size() )
1034 if ( ppDim
[nPos
]->getIsDataLayoutDimension() )
1036 if ( !pChildDimension
)
1037 pChildDimension
= new ScDPResultDimension( pResultData
);
1038 pChildDimension
->InitFrom( ppDim
, ppLev
, nPos
, rInitState
, false );
1047 bHasHiddenDetails
= true; // only if there is a next dimension
1053 pChildDimension
= new ScDPResultDimension( pResultData
);
1054 pChildDimension
->InitFrom(ppDim
, ppLev
, nPos
, rInitState
, true);
1058 void ScDPResultMember::LateInitFrom(
1059 LateInitParams
& rParams
, const vector
<SCROW
>& pItemData
, size_t nPos
, ScDPInitState
& rInitState
)
1061 // without LateInit, everything has already been initialized
1062 if ( !pResultData
->IsLateInit() )
1065 bInitialized
= true;
1067 if ( rParams
.IsEnd( nPos
) /*nPos >= ppDim.size()*/)
1068 // No next dimension. Bail out.
1071 // skip child dimension if details are not shown
1072 if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1074 // Show DataLayout dimension
1076 while ( !rParams
.IsEnd( nPos
) )
1078 if ( rParams
.GetDim( nPos
)->getIsDataLayoutDimension() )
1080 if ( !pChildDimension
)
1081 pChildDimension
= new ScDPResultDimension( pResultData
);
1083 // #i111462# reset InitChild flag only for this child dimension's LateInitFrom call,
1084 // not for following members of parent dimensions
1085 bool bWasInitChild
= rParams
.GetInitChild();
1086 rParams
.SetInitChild( false );
1087 pChildDimension
->LateInitFrom( rParams
, pItemData
, nPos
, rInitState
);
1088 rParams
.SetInitChild( bWasInitChild
);
1097 bHasHiddenDetails
= true; // only if there is a next dimension
1101 // LateInitFrom is called several times...
1102 if ( rParams
.GetInitChild() )
1104 if ( !pChildDimension
)
1105 pChildDimension
= new ScDPResultDimension( pResultData
);
1106 pChildDimension
->LateInitFrom( rParams
, pItemData
, nPos
, rInitState
);
1110 bool ScDPResultMember::IsSubTotalInTitle(long nMeasure
) const
1113 if ( pChildDimension
&& /*pParentLevel*/GetParentLevel() &&
1114 /*pParentLevel*/GetParentLevel()->IsOutlineLayout() && /*pParentLevel*/GetParentLevel()->IsSubtotalsAtTop() )
1117 long nSubTotals
= GetSubTotalCount( &nUserSubStart
);
1118 nSubTotals
-= nUserSubStart
; // visible count
1121 if ( nMeasure
== SC_DPMEASURE_ALL
)
1122 nSubTotals
*= pResultData
->GetMeasureCount(); // number of subtotals that will be inserted
1124 // only a single subtotal row will be shown in the outline title row
1125 if ( nSubTotals
== 1 )
1132 long ScDPResultMember::GetSize(long nMeasure
) const
1136 const ScDPLevel
* pParentLevel
= GetParentLevel();
1137 long nExtraSpace
= 0;
1138 if ( pParentLevel
&& pParentLevel
->IsAddEmpty() )
1141 if ( pChildDimension
)
1143 // outline layout takes up an extra row for the title only if subtotals aren't shown in that row
1144 if ( pParentLevel
&& pParentLevel
->IsOutlineLayout() && !IsSubTotalInTitle( nMeasure
) )
1147 long nSize
= pChildDimension
->GetSize(nMeasure
);
1149 long nUserSubCount
= GetSubTotalCount( &nUserSubStart
);
1150 nUserSubCount
-= nUserSubStart
; // for output size, use visible count
1151 if ( nUserSubCount
)
1153 if ( nMeasure
== SC_DPMEASURE_ALL
)
1154 nSize
+= pResultData
->GetMeasureCount() * nUserSubCount
;
1156 nSize
+= nUserSubCount
;
1158 return nSize
+ nExtraSpace
;
1162 if ( nMeasure
== SC_DPMEASURE_ALL
)
1163 return pResultData
->GetMeasureCount() + nExtraSpace
;
1165 return 1 + nExtraSpace
;
1169 bool ScDPResultMember::IsVisible() const
1180 // not initialized -> shouldn't be there at all
1181 // (allocated only to preserve ordering)
1182 const ScDPLevel
* pParentLevel
= GetParentLevel();
1184 return (pParentLevel
&& pParentLevel
->getShowEmpty());
1187 bool ScDPResultMember::IsValid() const
1189 // non-Valid members are left out of calculation
1191 // was member set no invisible at the DataPilotSource?
1192 const ScDPMember
* pMemberDesc
= GetDPMember();
1193 if ( pMemberDesc
&& !pMemberDesc
->isVisible() )
1202 long ScDPResultMember::GetSubTotalCount( long* pUserSubStart
) const
1204 if ( pUserSubStart
)
1205 *pUserSubStart
= 0; // default
1207 const ScDPLevel
* pParentLevel
= GetParentLevel();
1209 if ( bForceSubTotal
) // set if needed for root members
1210 return 1; // grand total is always "automatic"
1211 else if ( pParentLevel
)
1213 //TODO: direct access via ScDPLevel
1215 uno::Sequence
<sheet::GeneralFunction
> aSeq
= pParentLevel
->getSubTotals();
1216 long nSequence
= aSeq
.getLength();
1217 if ( nSequence
&& aSeq
[0] != sheet::GeneralFunction_AUTO
)
1219 // For manual subtotals, always add "automatic" as first function
1220 // (used for calculation, but not for display, needed for sorting, see lcl_GetForceFunc)
1223 if ( pUserSubStart
)
1224 *pUserSubStart
= 1; // visible subtotals start at 1
1232 void ScDPResultMember::ProcessData( const vector
< SCROW
>& aChildMembers
, const ScDPResultDimension
* pDataDim
,
1233 const vector
< SCROW
>& aDataMembers
, const vector
<ScDPValue
>& aValues
)
1237 if (pChildDimension
)
1238 pChildDimension
->ProcessData( aChildMembers
, pDataDim
, aDataMembers
, aValues
);
1242 pDataRoot
= new ScDPDataMember( pResultData
, NULL
);
1244 pDataRoot
->InitFrom( pDataDim
); // recursive
1247 ScDPSubTotalState aSubState
; // initial state
1249 long nUserSubCount
= GetSubTotalCount();
1251 // Calculate at least automatic if no subtotals are selected,
1252 // show only own values if there's no child dimension (innermost).
1253 if ( !nUserSubCount
|| !pChildDimension
)
1256 const ScDPLevel
* pParentLevel
= GetParentLevel();
1258 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
1260 // #i68338# if nUserSubCount is 1 (automatic only), don't set nRowSubTotalFunc
1261 if ( pChildDimension
&& nUserSubCount
> 1 )
1263 aSubState
.nRowSubTotalFunc
= nUserPos
;
1264 aSubState
.eRowForce
= lcl_GetForceFunc( pParentLevel
, nUserPos
);
1267 pDataRoot
->ProcessData( aDataMembers
, aValues
, aSubState
);
1272 * Parse subtotal string and replace all occurrences of '?' with the caption
1273 * string. Do ensure that escaped characters are not translated.
1275 static OUString
lcl_parseSubtotalName(const OUString
& rSubStr
, const OUString
& rCaption
)
1277 OUStringBuffer aNewStr
;
1278 sal_Int32 n
= rSubStr
.getLength();
1279 bool bEscaped
= false;
1280 for (sal_Int32 i
= 0; i
< n
; ++i
)
1282 sal_Unicode c
= rSubStr
[i
];
1283 if (!bEscaped
&& c
== '\\')
1289 if (!bEscaped
&& c
== '?')
1290 aNewStr
.append(rCaption
);
1295 return aNewStr
.makeStringAndClear();
1298 void ScDPResultMember::FillMemberResults(
1299 uno::Sequence
<sheet::MemberResult
>* pSequences
, long& rPos
, long nMeasure
, bool bRoot
,
1300 const OUString
* pMemberName
, const OUString
* pMemberCaption
)
1302 // IsVisible() test is in ScDPResultDimension::FillMemberResults
1303 // (not on data layout dimension)
1305 if (!pSequences
->getLength())
1306 // empty sequence. Bail out.
1309 long nSize
= GetSize(nMeasure
);
1310 sheet::MemberResult
* pArray
= pSequences
->getArray();
1311 OSL_ENSURE( rPos
+nSize
<= pSequences
->getLength(), "bumm" );
1313 bool bIsNumeric
= false;
1315 if ( pMemberName
) // if pMemberName != NULL, use instead of real member name
1317 aName
= *pMemberName
;
1321 ScDPItemData aItemData
;
1322 FillItemData( aItemData
);
1323 if (aParentDimData
.mpParentDim
)
1325 long nDim
= aParentDimData
.mpParentDim
->GetDimension();
1326 aName
= pResultData
->GetSource().GetData()->GetFormattedString(nDim
, aItemData
);
1331 const ScDPMember
* pMem
= GetDPMember();
1333 nDim
= pMem
->GetDim();
1334 aName
= pResultData
->GetSource().GetData()->GetFormattedString(nDim
, aItemData
);
1337 ScDPItemData::Type eType
= aItemData
.GetType();
1338 bIsNumeric
= eType
== ScDPItemData::Value
|| eType
== ScDPItemData::GroupValue
;
1341 const ScDPDimension
* pParentDim
= GetParentDim();
1342 if ( bIsNumeric
&& pParentDim
&& pResultData
->IsNumOrDateGroup( pParentDim
->GetDimension() ) )
1344 // Numeric group dimensions use numeric entries for proper sorting,
1345 // but the group titles must be output as text.
1349 OUString aCaption
= aName
;
1350 const ScDPMember
* pMemberDesc
= GetDPMember();
1353 const OUString
* pLayoutName
= pMemberDesc
->GetLayoutName();
1356 aCaption
= *pLayoutName
;
1357 bIsNumeric
= false; // layout name is always non-numeric.
1361 if ( pMemberCaption
) // use pMemberCaption if != NULL
1362 aCaption
= *pMemberCaption
;
1363 if (aCaption
.isEmpty())
1364 aCaption
= ScGlobal::GetRscString(STR_EMPTYDATA
);
1367 pArray
[rPos
].Flags
|= sheet::MemberResultFlags::NUMERIC
;
1369 pArray
[rPos
].Flags
&= ~sheet::MemberResultFlags::NUMERIC
;
1371 const ScDPLevel
* pParentLevel
= GetParentLevel();
1372 if ( nSize
&& !bRoot
) // root is overwritten by first dimension
1374 pArray
[rPos
].Name
= aName
;
1375 pArray
[rPos
].Caption
= aCaption
;
1376 pArray
[rPos
].Flags
|= sheet::MemberResultFlags::HASMEMBER
;
1378 // set "continue" flag (removed for subtotals later)
1379 for (long i
=1; i
<nSize
; i
++)
1380 pArray
[rPos
+i
].Flags
|= sheet::MemberResultFlags::CONTINUE
;
1381 if ( pParentLevel
&& pParentLevel
->getRepeatItemLabels() )
1383 long nSizeNonEmpty
= nSize
;
1384 if ( pParentLevel
->IsAddEmpty() )
1386 for (long i
=1; i
<nSizeNonEmpty
; i
++)
1388 pArray
[rPos
+i
].Name
= aName
;
1389 pArray
[rPos
+i
].Caption
= aCaption
;
1390 pArray
[rPos
+i
].Flags
|= sheet::MemberResultFlags::HASMEMBER
;
1395 long nExtraSpace
= 0;
1396 if ( pParentLevel
&& pParentLevel
->IsAddEmpty() )
1399 bool bTitleLine
= false;
1400 if ( pParentLevel
&& pParentLevel
->IsOutlineLayout() )
1403 // if the subtotals are shown at the top (title row) in outline layout,
1404 // no extra row for the subtotals is needed
1405 bool bSubTotalInTitle
= IsSubTotalInTitle( nMeasure
);
1407 bool bHasChild
= ( pChildDimension
!= NULL
);
1410 if ( bTitleLine
) // in tabular layout the title is on a separate row
1411 ++rPos
; // -> fill child dimension one row below
1413 if (bRoot
) // same sequence for root member
1414 pChildDimension
->FillMemberResults( pSequences
, rPos
, nMeasure
);
1416 pChildDimension
->FillMemberResults( pSequences
+ nMemberStep
/*1*/, rPos
, nMeasure
);
1418 if ( bTitleLine
) // title row is included in GetSize, so the following
1419 --rPos
; // positions are calculated with the normal values
1425 long nUserSubCount
= GetSubTotalCount(&nUserSubStart
);
1426 if ( nUserSubCount
&& pChildDimension
&& !bSubTotalInTitle
)
1428 long nMemberMeasure
= nMeasure
;
1429 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1431 rPos
-= nSubSize
* (nUserSubCount
- nUserSubStart
); // GetSize includes space for SubTotal
1432 rPos
-= nExtraSpace
; // GetSize includes the empty line
1434 for (long nUserPos
=nUserSubStart
; nUserPos
<nUserSubCount
; nUserPos
++)
1436 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
1438 if ( nMeasure
== SC_DPMEASURE_ALL
)
1439 nMemberMeasure
= nSubCount
;
1441 ScSubTotalFunc eForce
= SUBTOTAL_FUNC_NONE
;
1443 eForce
= lcl_GetForceFunc( pParentLevel
, nUserPos
);
1445 bool bTotalResult
= false;
1446 OUString aSubStr
= aCaption
+ " " + pResultData
->GetMeasureString(nMemberMeasure
, false, eForce
, bTotalResult
);
1452 // single data field layout.
1453 const OUString
* pSubtotalName
= pParentDim
->GetSubtotalName();
1455 aSubStr
= lcl_parseSubtotalName(*pSubtotalName
, aCaption
);
1456 pArray
[rPos
].Flags
&= ~sheet::MemberResultFlags::GRANDTOTAL
;
1460 // root member - subtotal (grand total?) for multi-data field layout.
1461 const OUString
* pGrandTotalName
= pResultData
->GetSource().GetGrandTotalName();
1462 if (pGrandTotalName
)
1463 aSubStr
= *pGrandTotalName
;
1464 pArray
[rPos
].Flags
|= sheet::MemberResultFlags::GRANDTOTAL
;
1468 pArray
[rPos
].Name
= aName
;
1469 pArray
[rPos
].Caption
= aSubStr
;
1470 pArray
[rPos
].Flags
= ( pArray
[rPos
].Flags
|
1471 ( sheet::MemberResultFlags::HASMEMBER
| sheet::MemberResultFlags::SUBTOTAL
) ) &
1472 ~sheet::MemberResultFlags::CONTINUE
;
1474 if ( nMeasure
== SC_DPMEASURE_ALL
)
1476 // data layout dimension is (direct/indirect) child of this.
1477 // data layout dimension must have name for all entries.
1479 uno::Sequence
<sheet::MemberResult
>* pLayoutSeq
= pSequences
;
1482 ScDPResultDimension
* pLayoutDim
= pChildDimension
;
1483 while ( pLayoutDim
&& !pLayoutDim
->IsDataLayout() )
1485 pLayoutDim
= pLayoutDim
->GetFirstChildDimension();
1490 sheet::MemberResult
* pLayoutArray
= pLayoutSeq
->getArray();
1491 pLayoutArray
[rPos
].Name
= pResultData
->GetMeasureDimensionName(nMemberMeasure
);
1499 rPos
+= nExtraSpace
; // add again (subtracted above)
1503 void ScDPResultMember::FillDataResults(
1504 const ScDPResultMember
* pRefMember
,
1505 ScDPResultFilterContext
& rFilterCxt
, uno::Sequence
<uno::Sequence
<sheet::DataResult
> >& rSequence
,
1506 long nMeasure
) const
1508 boost::scoped_ptr
<FilterStack
> pFilterStack
;
1509 const ScDPMember
* pDPMember
= GetDPMember();
1512 // Root result has no corresponding DP member. Only take the non-root results.
1513 OUString aMemStr
= GetDisplayName();
1514 pFilterStack
.reset(new FilterStack(rFilterCxt
.maFilters
));
1515 pFilterStack
->pushDimValue(aMemStr
);
1518 // IsVisible() test is in ScDPResultDimension::FillDataResults
1519 // (not on data layout dimension)
1520 const ScDPLevel
* pParentLevel
= GetParentLevel();
1521 long nStartRow
= rFilterCxt
.mnRow
;
1523 long nExtraSpace
= 0;
1524 if ( pParentLevel
&& pParentLevel
->IsAddEmpty() )
1527 bool bTitleLine
= false;
1528 if ( pParentLevel
&& pParentLevel
->IsOutlineLayout() )
1531 bool bSubTotalInTitle
= IsSubTotalInTitle( nMeasure
);
1533 bool bHasChild
= ( pChildDimension
!= NULL
);
1536 if ( bTitleLine
) // in tabular layout the title is on a separate row
1537 ++rFilterCxt
.mnRow
; // -> fill child dimension one row below
1539 long nOldRow
= rFilterCxt
.mnRow
;
1540 pChildDimension
->FillDataResults(pRefMember
, rFilterCxt
, rSequence
, nMeasure
);
1541 rFilterCxt
.mnRow
= nOldRow
; // Revert to the original row before the call.
1543 rFilterCxt
.mnRow
+= GetSize( nMeasure
);
1545 if ( bTitleLine
) // title row is included in GetSize, so the following
1546 --rFilterCxt
.mnRow
; // positions are calculated with the normal values
1550 long nUserSubCount
= GetSubTotalCount(&nUserSubStart
);
1551 if ( nUserSubCount
|| !bHasChild
)
1553 // Calculate at least automatic if no subtotals are selected,
1554 // show only own values if there's no child dimension (innermost).
1555 if ( !nUserSubCount
|| !bHasChild
)
1561 long nMemberMeasure
= nMeasure
;
1562 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1565 rFilterCxt
.mnRow
-= nSubSize
* ( nUserSubCount
- nUserSubStart
); // GetSize includes space for SubTotal
1566 rFilterCxt
.mnRow
-= nExtraSpace
; // GetSize includes the empty line
1569 long nMoveSubTotal
= 0;
1570 if ( bSubTotalInTitle
)
1572 nMoveSubTotal
= rFilterCxt
.mnRow
- nStartRow
; // force to first (title) row
1573 rFilterCxt
.mnRow
= nStartRow
;
1578 ScDPSubTotalState aSubState
; // initial state
1580 for (long nUserPos
=nUserSubStart
; nUserPos
<nUserSubCount
; nUserPos
++)
1582 if ( bHasChild
&& nUserSubCount
> 1 )
1584 aSubState
.nRowSubTotalFunc
= nUserPos
;
1585 aSubState
.eRowForce
= lcl_GetForceFunc( /*pParentLevel*/GetParentLevel() , nUserPos
);
1588 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
1590 if ( nMeasure
== SC_DPMEASURE_ALL
)
1591 nMemberMeasure
= nSubCount
;
1592 else if ( pResultData
->GetColStartMeasure() == SC_DPMEASURE_ALL
)
1593 nMemberMeasure
= SC_DPMEASURE_ALL
;
1595 OSL_ENSURE( rFilterCxt
.mnRow
< rSequence
.getLength(), "bumm" );
1596 uno::Sequence
<sheet::DataResult
>& rSubSeq
= rSequence
.getArray()[rFilterCxt
.mnRow
];
1597 rFilterCxt
.mnCol
= 0;
1598 if (pRefMember
->IsVisible())
1599 pDataRoot
->FillDataRow(pRefMember
, rFilterCxt
, rSubSeq
, nMemberMeasure
, bHasChild
, aSubState
);
1601 rFilterCxt
.mnRow
+= 1;
1606 rFilterCxt
.mnRow
+= nSubSize
* ( nUserSubCount
- nUserSubStart
); // empty rows occur when ShowEmpty is true
1608 // add extra space again if subtracted from GetSize above,
1609 // add to own size if no children
1610 rFilterCxt
.mnRow
+= nExtraSpace
;
1611 rFilterCxt
.mnRow
+= nMoveSubTotal
;
1615 void ScDPResultMember::UpdateDataResults( const ScDPResultMember
* pRefMember
, long nMeasure
) const
1617 // IsVisible() test is in ScDPResultDimension::FillDataResults
1618 // (not on data layout dimension)
1620 bool bHasChild
= ( pChildDimension
!= NULL
);
1622 long nUserSubCount
= GetSubTotalCount();
1624 // process subtotals even if not shown
1626 // Calculate at least automatic if no subtotals are selected,
1627 // show only own values if there's no child dimension (innermost).
1628 if (!nUserSubCount
|| !bHasChild
)
1631 long nMemberMeasure
= nMeasure
;
1632 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1636 ScDPSubTotalState aSubState
; // initial state
1638 for (long nUserPos
= 0; nUserPos
< nUserSubCount
; ++nUserPos
) // including hidden "automatic"
1640 if (bHasChild
&& nUserSubCount
> 1)
1642 aSubState
.nRowSubTotalFunc
= nUserPos
;
1643 aSubState
.eRowForce
= lcl_GetForceFunc(GetParentLevel(), nUserPos
);
1646 for (long nSubCount
= 0; nSubCount
< nSubSize
; ++nSubCount
)
1648 if (nMeasure
== SC_DPMEASURE_ALL
)
1649 nMemberMeasure
= nSubCount
;
1650 else if (pResultData
->GetColStartMeasure() == SC_DPMEASURE_ALL
)
1651 nMemberMeasure
= SC_DPMEASURE_ALL
;
1653 pDataRoot
->UpdateDataRow(pRefMember
, nMemberMeasure
, bHasChild
, aSubState
);
1658 if (bHasChild
) // child dimension must be processed last, so the column total is known
1660 pChildDimension
->UpdateDataResults( pRefMember
, nMeasure
);
1664 void ScDPResultMember::SortMembers( ScDPResultMember
* pRefMember
)
1666 bool bHasChild
= ( pChildDimension
!= NULL
);
1668 pChildDimension
->SortMembers( pRefMember
); // sorting is done at the dimension
1670 if ( IsRoot() && pDataRoot
)
1672 // use the row root member to sort columns
1673 // sub total count is always 1
1675 pDataRoot
->SortMembers( pRefMember
);
1679 void ScDPResultMember::DoAutoShow( ScDPResultMember
* pRefMember
)
1681 bool bHasChild
= ( pChildDimension
!= NULL
);
1683 pChildDimension
->DoAutoShow( pRefMember
); // sorting is done at the dimension
1685 if ( IsRoot()&& pDataRoot
)
1687 // use the row root member to sort columns
1688 // sub total count is always 1
1690 pDataRoot
->DoAutoShow( pRefMember
);
1694 void ScDPResultMember::ResetResults()
1697 pDataRoot
->ResetResults();
1699 if (pChildDimension
)
1700 pChildDimension
->ResetResults();
1703 void ScDPResultMember::UpdateRunningTotals( const ScDPResultMember
* pRefMember
, long nMeasure
,
1704 ScDPRunningTotalState
& rRunning
, ScDPRowTotals
& rTotals
) const
1706 // IsVisible() test is in ScDPResultDimension::FillDataResults
1707 // (not on data layout dimension)
1709 rTotals
.SetInColRoot( IsRoot() );
1711 bool bHasChild
= ( pChildDimension
!= NULL
);
1713 long nUserSubCount
= GetSubTotalCount();
1714 //if ( nUserSubCount || !bHasChild )
1716 // Calculate at least automatic if no subtotals are selected,
1717 // show only own values if there's no child dimension (innermost).
1718 if ( !nUserSubCount
|| !bHasChild
)
1721 long nMemberMeasure
= nMeasure
;
1722 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1726 ScDPSubTotalState aSubState
; // initial state
1728 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
1730 if ( bHasChild
&& nUserSubCount
> 1 )
1732 aSubState
.nRowSubTotalFunc
= nUserPos
;
1733 aSubState
.eRowForce
= lcl_GetForceFunc(GetParentLevel(), nUserPos
);
1736 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
1738 if ( nMeasure
== SC_DPMEASURE_ALL
)
1739 nMemberMeasure
= nSubCount
;
1740 else if ( pResultData
->GetColStartMeasure() == SC_DPMEASURE_ALL
)
1741 nMemberMeasure
= SC_DPMEASURE_ALL
;
1743 if (pRefMember
->IsVisible())
1744 pDataRoot
->UpdateRunningTotals(
1745 pRefMember
, nMemberMeasure
, bHasChild
, aSubState
, rRunning
, rTotals
, *this);
1751 if (bHasChild
) // child dimension must be processed last, so the column total is known
1753 pChildDimension
->UpdateRunningTotals( pRefMember
, nMeasure
, rRunning
, rTotals
);
1757 #if DEBUG_PIVOT_TABLE
1758 void ScDPResultMember::DumpState( const ScDPResultMember
* pRefMember
, ScDocument
* pDoc
, ScAddress
& rPos
) const
1760 lcl_DumpRow( OUString("ScDPResultMember"), GetName(), NULL
, pDoc
, rPos
);
1761 SCROW nStartRow
= rPos
.Row();
1764 pDataRoot
->DumpState( pRefMember
, pDoc
, rPos
);
1766 if (pChildDimension
)
1767 pChildDimension
->DumpState( pRefMember
, pDoc
, rPos
);
1769 lcl_Indent( pDoc
, nStartRow
, rPos
);
1772 void ScDPResultMember::Dump(int nIndent
) const
1774 std::string
aIndent(nIndent
*2, ' ');
1775 std::cout
<< aIndent
<< "-- result member '" << GetName() << "'" << std::endl
;
1777 std::cout
<< aIndent
<< " column totals" << std::endl
;
1778 for (const ScDPAggData
* p
= &aColTotal
; p
; p
= p
->GetExistingChild())
1781 if (pChildDimension
)
1782 pChildDimension
->Dump(nIndent
+1);
1786 std::cout
<< aIndent
<< " data root" << std::endl
;
1787 pDataRoot
->Dump(nIndent
+1);
1792 ScDPAggData
* ScDPResultMember::GetColTotal( long nMeasure
) const
1794 return lcl_GetChildTotal( const_cast<ScDPAggData
*>(&aColTotal
), nMeasure
);
1797 void ScDPResultMember::FillVisibilityData(ScDPResultVisibilityData
& rData
) const
1799 if (pChildDimension
)
1800 pChildDimension
->FillVisibilityData(rData
);
1803 ScDPDataMember::ScDPDataMember( const ScDPResultData
* pData
, const ScDPResultMember
* pRes
) :
1804 pResultData( pData
),
1805 pResultMember( pRes
),
1806 pChildDimension( NULL
)
1808 // pResultMember is 0 for root members
1811 ScDPDataMember::~ScDPDataMember()
1813 delete pChildDimension
;
1816 OUString
ScDPDataMember::GetName() const
1819 return pResultMember
->GetName();
1821 return EMPTY_OUSTRING
;
1824 bool ScDPDataMember::IsVisible() const
1827 return pResultMember
->IsVisible();
1832 bool ScDPDataMember::IsNamedItem( SCROW nRow
) const
1835 return pResultMember
->IsNamedItem(nRow
);
1840 bool ScDPDataMember::HasHiddenDetails() const
1843 return pResultMember
->HasHiddenDetails();
1848 void ScDPDataMember::InitFrom( const ScDPResultDimension
* pDim
)
1850 if ( !pChildDimension
)
1851 pChildDimension
= new ScDPDataDimension(pResultData
);
1852 pChildDimension
->InitFrom(pDim
);
1855 const long SC_SUBTOTALPOS_AUTO
= -1; // default
1856 const long SC_SUBTOTALPOS_SKIP
= -2; // don't use
1858 static long lcl_GetSubTotalPos( const ScDPSubTotalState
& rSubState
)
1860 if ( rSubState
.nColSubTotalFunc
>= 0 && rSubState
.nRowSubTotalFunc
>= 0 &&
1861 rSubState
.nColSubTotalFunc
!= rSubState
.nRowSubTotalFunc
)
1863 // #i68338# don't return the same index for different combinations (leading to repeated updates),
1864 // return a "don't use" value instead
1866 return SC_SUBTOTALPOS_SKIP
;
1869 long nRet
= SC_SUBTOTALPOS_AUTO
;
1870 if ( rSubState
.nColSubTotalFunc
>= 0 ) nRet
= rSubState
.nColSubTotalFunc
;
1871 if ( rSubState
.nRowSubTotalFunc
>= 0 ) nRet
= rSubState
.nRowSubTotalFunc
;
1875 void ScDPDataMember::UpdateValues( const vector
<ScDPValue
>& aValues
, const ScDPSubTotalState
& rSubState
)
1877 //TODO: find out how many and which subtotals are used
1879 ScDPAggData
* pAgg
= &aAggregate
;
1881 long nSubPos
= lcl_GetSubTotalPos(rSubState
);
1882 if (nSubPos
== SC_SUBTOTALPOS_SKIP
)
1886 long nSkip
= nSubPos
* pResultData
->GetMeasureCount();
1887 for (long i
=0; i
<nSkip
; i
++)
1888 pAgg
= pAgg
->GetChild(); // created if not there
1891 size_t nCount
= aValues
.size();
1892 for (size_t nPos
= 0; nPos
< nCount
; ++nPos
)
1894 pAgg
->Update(aValues
[nPos
], pResultData
->GetMeasureFunction(nPos
), rSubState
);
1895 pAgg
= pAgg
->GetChild();
1899 void ScDPDataMember::ProcessData( const vector
< SCROW
>& aChildMembers
, const vector
<ScDPValue
>& aValues
,
1900 const ScDPSubTotalState
& rSubState
)
1902 if ( pResultData
->IsLateInit() && !pChildDimension
&& pResultMember
&& pResultMember
->GetChildDimension() )
1904 // if this DataMember doesn't have a child dimension because the ResultMember's
1905 // child dimension wasn't there yet during this DataMembers's creation,
1906 // create the child dimension now
1907 InitFrom( pResultMember
->GetChildDimension() );
1910 long nUserSubCount
= pResultMember
? pResultMember
->GetSubTotalCount() : 0;
1912 // Calculate at least automatic if no subtotals are selected,
1913 // show only own values if there's no child dimension (innermost).
1914 if ( !nUserSubCount
|| !pChildDimension
)
1917 ScDPSubTotalState aLocalSubState
= rSubState
; // keep row state, modify column
1918 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
1920 if ( pChildDimension
&& nUserSubCount
> 1 )
1922 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
1923 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
1924 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
1927 UpdateValues( aValues
, aLocalSubState
);
1930 if (pChildDimension
)
1931 pChildDimension
->ProcessData( aChildMembers
, aValues
, rSubState
); // with unmodified subtotal state
1934 bool ScDPDataMember::HasData( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1936 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
&& rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
&&
1937 rSubState
.eColForce
!= rSubState
.eRowForce
)
1940 // HasData can be different between measures!
1942 const ScDPAggData
* pAgg
= GetConstAggData( nMeasure
, rSubState
);
1944 return false; //TODO: error?
1946 return pAgg
->HasData();
1949 bool ScDPDataMember::HasError( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1951 const ScDPAggData
* pAgg
= GetConstAggData( nMeasure
, rSubState
);
1955 return pAgg
->HasError();
1958 double ScDPDataMember::GetAggregate( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1960 const ScDPAggData
* pAgg
= GetConstAggData( nMeasure
, rSubState
);
1962 return DBL_MAX
; //TODO: error?
1964 return pAgg
->GetResult();
1967 ScDPAggData
* ScDPDataMember::GetAggData( long nMeasure
, const ScDPSubTotalState
& rSubState
)
1969 OSL_ENSURE( nMeasure
>= 0, "GetAggData: no measure" );
1971 ScDPAggData
* pAgg
= &aAggregate
;
1972 long nSkip
= nMeasure
;
1973 long nSubPos
= lcl_GetSubTotalPos(rSubState
);
1974 if (nSubPos
== SC_SUBTOTALPOS_SKIP
)
1977 nSkip
+= nSubPos
* pResultData
->GetMeasureCount();
1979 for ( long nPos
=0; nPos
<nSkip
; nPos
++ )
1980 pAgg
= pAgg
->GetChild(); //TODO: need to create children here?
1985 const ScDPAggData
* ScDPDataMember::GetConstAggData( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1987 OSL_ENSURE( nMeasure
>= 0, "GetConstAggData: no measure" );
1989 const ScDPAggData
* pAgg
= &aAggregate
;
1990 long nSkip
= nMeasure
;
1991 long nSubPos
= lcl_GetSubTotalPos(rSubState
);
1992 if (nSubPos
== SC_SUBTOTALPOS_SKIP
)
1995 nSkip
+= nSubPos
* pResultData
->GetMeasureCount();
1997 for ( long nPos
=0; nPos
<nSkip
; nPos
++ )
1999 pAgg
= pAgg
->GetExistingChild();
2007 void ScDPDataMember::FillDataRow(
2008 const ScDPResultMember
* pRefMember
, ScDPResultFilterContext
& rFilterCxt
,
2009 uno::Sequence
<sheet::DataResult
>& rSequence
, long nMeasure
, bool bIsSubTotalRow
,
2010 const ScDPSubTotalState
& rSubState
) const
2012 boost::scoped_ptr
<FilterStack
> pFilterStack
;
2015 // Topmost data member (pResultMember=NULL) doesn't need to be handled
2016 // since its immediate parent result member is linked to the same
2017 // dimension member.
2018 pFilterStack
.reset(new FilterStack(rFilterCxt
.maFilters
));
2019 pFilterStack
->pushDimValue(pResultMember
->GetDisplayName());
2022 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2024 long nStartCol
= rFilterCxt
.mnCol
;
2026 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2027 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2029 const ScDPLevel
* pRefParentLevel
= pRefMember
->GetParentLevel();
2031 long nExtraSpace
= 0;
2032 if ( pRefParentLevel
&& pRefParentLevel
->IsAddEmpty() )
2035 bool bTitleLine
= false;
2036 if ( pRefParentLevel
&& pRefParentLevel
->IsOutlineLayout() )
2039 bool bSubTotalInTitle
= pRefMember
->IsSubTotalInTitle( nMeasure
);
2041 // leave space for children even if the DataMember hasn't been initialized
2042 // (pDataChild is null then, this happens when no values for it are in this row)
2043 bool bHasChild
= ( pRefChild
!= NULL
);
2047 if ( bTitleLine
) // in tabular layout the title is on a separate column
2048 ++rFilterCxt
.mnCol
; // -> fill child dimension one column below
2052 long nOldCol
= rFilterCxt
.mnCol
;
2053 pDataChild
->FillDataRow(pRefChild
, rFilterCxt
, rSequence
, nMeasure
, bIsSubTotalRow
, rSubState
);
2054 rFilterCxt
.mnCol
= nOldCol
; // Revert to the old column value before the call.
2056 rFilterCxt
.mnCol
+= (sal_uInt16
)pRefMember
->GetSize( nMeasure
);
2058 if ( bTitleLine
) // title column is included in GetSize, so the following
2059 --rFilterCxt
.mnCol
; // positions are calculated with the normal values
2063 long nUserSubCount
= pRefMember
->GetSubTotalCount(&nUserSubStart
);
2064 if ( nUserSubCount
|| !bHasChild
)
2066 // Calculate at least automatic if no subtotals are selected,
2067 // show only own values if there's no child dimension (innermost).
2068 if ( !nUserSubCount
|| !bHasChild
)
2074 ScDPSubTotalState
aLocalSubState(rSubState
); // keep row state, modify column
2076 long nMemberMeasure
= nMeasure
;
2077 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
2080 rFilterCxt
.mnCol
-= nSubSize
* ( nUserSubCount
- nUserSubStart
); // GetSize includes space for SubTotal
2081 rFilterCxt
.mnCol
-= nExtraSpace
; // GetSize includes the empty line
2084 long nMoveSubTotal
= 0;
2085 if ( bSubTotalInTitle
)
2087 nMoveSubTotal
= rFilterCxt
.mnCol
- nStartCol
; // force to first (title) column
2088 rFilterCxt
.mnCol
= nStartCol
;
2091 for (long nUserPos
=nUserSubStart
; nUserPos
<nUserSubCount
; nUserPos
++)
2093 if ( pChildDimension
&& nUserSubCount
> 1 )
2095 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
2096 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
2097 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
2100 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
2102 if ( nMeasure
== SC_DPMEASURE_ALL
)
2103 nMemberMeasure
= nSubCount
;
2105 OSL_ENSURE( rFilterCxt
.mnCol
< rSequence
.getLength(), "bumm" );
2106 sheet::DataResult
& rRes
= rSequence
.getArray()[rFilterCxt
.mnCol
];
2108 if ( HasData( nMemberMeasure
, aLocalSubState
) )
2110 if ( HasError( nMemberMeasure
, aLocalSubState
) )
2113 rRes
.Flags
|= sheet::DataResultFlags::ERROR
;
2117 rRes
.Value
= GetAggregate( nMemberMeasure
, aLocalSubState
);
2118 rRes
.Flags
|= sheet::DataResultFlags::HASDATA
;
2122 if ( bHasChild
|| bIsSubTotalRow
)
2123 rRes
.Flags
|= sheet::DataResultFlags::SUBTOTAL
;
2125 rFilterCxt
.maFilterSet
.add(rFilterCxt
.maFilters
, rFilterCxt
.mnCol
, rFilterCxt
.mnRow
, rRes
.Value
);
2126 rFilterCxt
.mnCol
+= 1;
2130 // add extra space again if subtracted from GetSize above,
2131 // add to own size if no children
2132 rFilterCxt
.mnCol
+= nExtraSpace
;
2133 rFilterCxt
.mnCol
+= nMoveSubTotal
;
2137 void ScDPDataMember::UpdateDataRow(
2138 const ScDPResultMember
* pRefMember
, long nMeasure
, bool bIsSubTotalRow
,
2139 const ScDPSubTotalState
& rSubState
)
2141 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2143 // Calculate must be called even if not visible (for use as reference value)
2144 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2145 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2147 // leave space for children even if the DataMember hasn't been initialized
2148 // (pDataChild is null then, this happens when no values for it are in this row)
2149 bool bHasChild
= ( pRefChild
!= NULL
);
2151 // process subtotals even if not shown
2152 long nUserSubCount
= pRefMember
->GetSubTotalCount();
2154 // Calculate at least automatic if no subtotals are selected,
2155 // show only own values if there's no child dimension (innermost).
2156 if ( !nUserSubCount
|| !bHasChild
)
2159 ScDPSubTotalState
aLocalSubState(rSubState
); // keep row state, modify column
2161 long nMemberMeasure
= nMeasure
;
2162 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
2164 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
2166 if ( pChildDimension
&& nUserSubCount
> 1 )
2168 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
2169 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
2170 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
2173 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
2175 if ( nMeasure
== SC_DPMEASURE_ALL
)
2176 nMemberMeasure
= nSubCount
;
2179 ScDPAggData
* pAggData
= GetAggData( nMemberMeasure
, aLocalSubState
);
2182 //TODO: aLocalSubState?
2183 ScSubTotalFunc eFunc
= pResultData
->GetMeasureFunction( nMemberMeasure
);
2184 sheet::DataPilotFieldReference aReferenceValue
= pResultData
->GetMeasureRefVal( nMemberMeasure
);
2185 sal_Int32 eRefType
= aReferenceValue
.ReferenceType
;
2187 // calculate the result first - for all members, regardless of reference value
2188 pAggData
->Calculate( eFunc
, aLocalSubState
);
2190 if ( eRefType
== sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE
||
2191 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
||
2192 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE
)
2194 // copy the result into auxiliary value, so differences can be
2195 // calculated in any order
2196 pAggData
->SetAuxiliary( pAggData
->GetResult() );
2198 // column/row percentage/index is now in UpdateRunningTotals, so it doesn't disturb sorting
2203 if ( bHasChild
) // child dimension must be processed last, so the row total is known
2206 pDataChild
->UpdateDataRow( pRefChild
, nMeasure
, bIsSubTotalRow
, rSubState
);
2210 void ScDPDataMember::SortMembers( ScDPResultMember
* pRefMember
)
2212 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2214 if ( pRefMember
->IsVisible() ) //TODO: here or in ScDPDataDimension ???
2216 ScDPDataDimension
* pDataChild
= GetChildDimension();
2217 ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2218 if ( pRefChild
&& pDataChild
)
2219 pDataChild
->SortMembers( pRefChild
); // sorting is done at the dimension
2223 void ScDPDataMember::DoAutoShow( ScDPResultMember
* pRefMember
)
2225 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2227 if ( pRefMember
->IsVisible() ) //TODO: here or in ScDPDataDimension ???
2229 ScDPDataDimension
* pDataChild
= GetChildDimension();
2230 ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2231 if ( pRefChild
&& pDataChild
)
2232 pDataChild
->DoAutoShow( pRefChild
); // sorting is done at the dimension
2236 void ScDPDataMember::ResetResults()
2240 ScDPDataDimension
* pDataChild
= GetChildDimension();
2242 pDataChild
->ResetResults();
2245 void ScDPDataMember::UpdateRunningTotals(
2246 const ScDPResultMember
* pRefMember
, long nMeasure
, bool bIsSubTotalRow
,
2247 const ScDPSubTotalState
& rSubState
, ScDPRunningTotalState
& rRunning
,
2248 ScDPRowTotals
& rTotals
, const ScDPResultMember
& rRowParent
)
2250 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2252 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2253 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2255 bool bIsRoot
= ( pResultMember
== NULL
|| pResultMember
->GetParentLevel() == NULL
);
2257 // leave space for children even if the DataMember hasn't been initialized
2258 // (pDataChild is null then, this happens when no values for it are in this row)
2259 bool bHasChild
= ( pRefChild
!= NULL
);
2261 long nUserSubCount
= pRefMember
->GetSubTotalCount();
2263 // Calculate at least automatic if no subtotals are selected,
2264 // show only own values if there's no child dimension (innermost).
2265 if ( !nUserSubCount
|| !bHasChild
)
2268 ScDPSubTotalState
aLocalSubState(rSubState
); // keep row state, modify column
2270 long nMemberMeasure
= nMeasure
;
2271 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
2273 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
2275 if ( pChildDimension
&& nUserSubCount
> 1 )
2277 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
2278 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
2279 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
2282 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
2284 if ( nMeasure
== SC_DPMEASURE_ALL
)
2285 nMemberMeasure
= nSubCount
;
2288 ScDPAggData
* pAggData
= GetAggData( nMemberMeasure
, aLocalSubState
);
2291 //TODO: aLocalSubState?
2292 sheet::DataPilotFieldReference aReferenceValue
= pResultData
->GetMeasureRefVal( nMemberMeasure
);
2293 sal_Int32 eRefType
= aReferenceValue
.ReferenceType
;
2295 if ( eRefType
== sheet::DataPilotFieldReferenceType::RUNNING_TOTAL
||
2296 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE
||
2297 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
||
2298 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE
)
2300 bool bRunningTotal
= ( eRefType
== sheet::DataPilotFieldReferenceType::RUNNING_TOTAL
);
2302 ( aReferenceValue
.ReferenceItemType
!= sheet::DataPilotFieldReferenceItemType::NAMED
&& !bRunningTotal
);
2303 long nRelativeDir
= bRelative
?
2304 ( ( aReferenceValue
.ReferenceItemType
== sheet::DataPilotFieldReferenceItemType::PREVIOUS
) ? -1 : 1 ) : 0;
2306 const ScDPRunningTotalState::IndexArray
& rColVisible
= rRunning
.GetColVisible();
2307 const ScDPRunningTotalState::IndexArray
& rColSorted
= rRunning
.GetColSorted();
2308 const ScDPRunningTotalState::IndexArray
& rRowVisible
= rRunning
.GetRowVisible();
2309 const ScDPRunningTotalState::IndexArray
& rRowSorted
= rRunning
.GetRowSorted();
2311 OUString aRefFieldName
= aReferenceValue
.ReferenceField
;
2313 //TODO: aLocalSubState?
2314 sal_uInt16 nRefOrient
= pResultData
->GetMeasureRefOrient( nMemberMeasure
);
2315 bool bRefDimInCol
= ( nRefOrient
== sheet::DataPilotFieldOrientation_COLUMN
);
2316 bool bRefDimInRow
= ( nRefOrient
== sheet::DataPilotFieldOrientation_ROW
);
2318 ScDPResultDimension
* pSelectDim
= NULL
;
2322 // find the reference field in column or row dimensions
2324 if ( bRefDimInRow
) // look in row dimensions
2326 pSelectDim
= rRunning
.GetRowResRoot()->GetChildDimension();
2327 while ( pSelectDim
&& pSelectDim
->GetName() != aRefFieldName
)
2329 long nIndex
= rRowSorted
[nRowPos
];
2330 if ( nIndex
>= 0 && nIndex
< pSelectDim
->GetMemberCount() )
2331 pSelectDim
= pSelectDim
->GetMember(nIndex
)->GetChildDimension();
2336 // child dimension of innermost member?
2337 if ( pSelectDim
&& rRowSorted
[nRowPos
] < 0 )
2341 if ( bRefDimInCol
) // look in column dimensions
2343 pSelectDim
= rRunning
.GetColResRoot()->GetChildDimension();
2344 while ( pSelectDim
&& pSelectDim
->GetName() != aRefFieldName
)
2346 long nIndex
= rColSorted
[nColPos
];
2347 if ( nIndex
>= 0 && nIndex
< pSelectDim
->GetMemberCount() )
2348 pSelectDim
= pSelectDim
->GetMember(nIndex
)->GetChildDimension();
2353 // child dimension of innermost member?
2354 if ( pSelectDim
&& rColSorted
[nColPos
] < 0 )
2358 bool bNoDetailsInRef
= false;
2359 if ( pSelectDim
&& bRunningTotal
)
2362 // If details are hidden for this member in the reference dimension,
2363 // don't show or sum up the value. Otherwise, for following members,
2364 // the running totals of details and subtotals wouldn't match.
2366 long nMyIndex
= bRefDimInCol
? rColSorted
[nColPos
] : rRowSorted
[nRowPos
];
2367 if ( nMyIndex
>= 0 && nMyIndex
< pSelectDim
->GetMemberCount() )
2369 const ScDPResultMember
* pMyRefMember
= pSelectDim
->GetMember(nMyIndex
);
2370 if ( pMyRefMember
&& pMyRefMember
->HasHiddenDetails() )
2372 pSelectDim
= NULL
; // don't calculate
2373 bNoDetailsInRef
= true; // show error, not empty
2380 // Difference/Percentage from previous/next:
2381 // If details are hidden for this member in the innermost column/row
2382 // dimension (the orientation of the reference dimension), show an
2384 // - If the no-details dimension is the reference dimension, its
2385 // members will be skipped when finding the previous/next member,
2386 // so there must be no results for its members.
2387 // - If the no-details dimension is outside of the reference dimension,
2388 // no calculation in the reference dimension is possible.
2389 // - Otherwise, the error isn't strictly necessary, but shown for
2392 bool bInnerNoDetails
= bRefDimInCol
? HasHiddenDetails() :
2393 ( !bRefDimInRow
|| rRowParent
.HasHiddenDetails() );
2394 if ( bInnerNoDetails
)
2397 bNoDetailsInRef
= true; // show error, not empty
2401 if ( !bRefDimInCol
&& !bRefDimInRow
) // invalid dimension specified
2402 bNoDetailsInRef
= true; // pSelectDim is then already NULL
2404 // get the member for the reference item and do the calculation
2406 if ( bRunningTotal
)
2408 // running total in (dimension) -> find first existing member
2412 ScDPDataMember
* pSelectMember
;
2414 pSelectMember
= ScDPResultDimension::GetColReferenceMember( NULL
, NULL
,
2415 nColPos
, rRunning
);
2418 const long* pRowSorted
= &rRowSorted
[0];
2419 const long* pColSorted
= &rColSorted
[0];
2420 pRowSorted
+= nRowPos
+ 1; // including the reference dimension
2421 pSelectMember
= pSelectDim
->GetRowReferenceMember(
2422 NULL
, NULL
, pRowSorted
, pColSorted
);
2425 if ( pSelectMember
)
2427 // The running total is kept as the auxiliary value in
2428 // the first available member for the reference dimension.
2429 // Members are visited in final order, so each one's result
2430 // can be used and then modified.
2432 ScDPAggData
* pSelectData
= pSelectMember
->
2433 GetAggData( nMemberMeasure
, aLocalSubState
);
2436 double fTotal
= pSelectData
->GetAuxiliary();
2437 fTotal
+= pAggData
->GetResult();
2438 pSelectData
->SetAuxiliary( fTotal
);
2439 pAggData
->SetResult( fTotal
);
2440 pAggData
->SetEmpty(false); // always display
2444 pAggData
->SetError();
2446 else if (bNoDetailsInRef
)
2447 pAggData
->SetError();
2449 pAggData
->SetEmpty(true); // empty (dim set to 0 above)
2453 // difference/percentage -> find specified member
2457 OUString aRefItemName
= aReferenceValue
.ReferenceItemName
;
2458 ScDPRelativePos
aRefItemPos( 0, nRelativeDir
); // nBasePos is modified later
2460 const OUString
* pRefName
= NULL
;
2461 const ScDPRelativePos
* pRefPos
= NULL
;
2463 pRefPos
= &aRefItemPos
;
2465 pRefName
= &aRefItemName
;
2467 ScDPDataMember
* pSelectMember
;
2470 aRefItemPos
.nBasePos
= rColVisible
[nColPos
]; // without sort order applied
2471 pSelectMember
= ScDPResultDimension::GetColReferenceMember( pRefPos
, pRefName
,
2472 nColPos
, rRunning
);
2476 aRefItemPos
.nBasePos
= rRowVisible
[nRowPos
]; // without sort order applied
2477 const long* pRowSorted
= &rRowSorted
[0];
2478 const long* pColSorted
= &rColSorted
[0];
2479 pRowSorted
+= nRowPos
+ 1; // including the reference dimension
2480 pSelectMember
= pSelectDim
->GetRowReferenceMember(
2481 pRefPos
, pRefName
, pRowSorted
, pColSorted
);
2484 // difference or perc.difference is empty for the reference item itself
2485 if ( pSelectMember
== this &&
2486 eRefType
!= sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
)
2488 pAggData
->SetEmpty(true);
2490 else if ( pSelectMember
)
2492 const ScDPAggData
* pOtherAggData
= pSelectMember
->
2493 GetConstAggData( nMemberMeasure
, aLocalSubState
);
2494 OSL_ENSURE( pOtherAggData
, "no agg data" );
2495 if ( pOtherAggData
)
2497 // Reference member may be visited before or after this one,
2498 // so the auxiliary value is used for the original result.
2500 double fOtherResult
= pOtherAggData
->GetAuxiliary();
2501 double fThisResult
= pAggData
->GetResult();
2502 bool bError
= false;
2505 case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE
:
2506 fThisResult
= fThisResult
- fOtherResult
;
2508 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
:
2509 if ( fOtherResult
== 0.0 )
2512 fThisResult
= fThisResult
/ fOtherResult
;
2514 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE
:
2515 if ( fOtherResult
== 0.0 )
2518 fThisResult
= ( fThisResult
- fOtherResult
) / fOtherResult
;
2521 OSL_FAIL("invalid calculation type");
2525 pAggData
->SetError();
2529 pAggData
->SetResult(fThisResult
);
2530 pAggData
->SetEmpty(false); // always display
2532 //TODO: errors in data?
2535 else if (bRelative
&& !bNoDetailsInRef
)
2536 pAggData
->SetEmpty(true); // empty
2538 pAggData
->SetError(); // error
2540 else if (bNoDetailsInRef
)
2541 pAggData
->SetError(); // error
2543 pAggData
->SetEmpty(true); // empty
2546 else if ( eRefType
== sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE
||
2547 eRefType
== sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE
||
2548 eRefType
== sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE
||
2549 eRefType
== sheet::DataPilotFieldReferenceType::INDEX
)
2552 // set total values when they are encountered (always before their use)
2554 ScDPAggData
* pColTotalData
= pRefMember
->GetColTotal( nMemberMeasure
);
2555 ScDPAggData
* pRowTotalData
= rTotals
.GetRowTotal( nMemberMeasure
);
2556 ScDPAggData
* pGrandTotalData
= rTotals
.GetGrandTotal( nMemberMeasure
);
2558 double fTotalValue
= pAggData
->HasError() ? 0 : pAggData
->GetResult();
2560 if ( bIsRoot
&& rTotals
.IsInColRoot() && pGrandTotalData
)
2561 pGrandTotalData
->SetAuxiliary( fTotalValue
);
2563 if ( bIsRoot
&& pRowTotalData
)
2564 pRowTotalData
->SetAuxiliary( fTotalValue
);
2566 if ( rTotals
.IsInColRoot() && pColTotalData
)
2567 pColTotalData
->SetAuxiliary( fTotalValue
);
2569 // find relation to total values
2573 case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE
:
2574 case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE
:
2575 case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE
:
2578 if ( eRefType
== sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE
)
2579 nTotal
= pRowTotalData
->GetAuxiliary();
2580 else if ( eRefType
== sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE
)
2581 nTotal
= pColTotalData
->GetAuxiliary();
2583 nTotal
= pGrandTotalData
->GetAuxiliary();
2585 if ( nTotal
== 0.0 )
2586 pAggData
->SetError();
2588 pAggData
->SetResult( pAggData
->GetResult() / nTotal
);
2591 case sheet::DataPilotFieldReferenceType::INDEX
:
2593 double nColTotal
= pColTotalData
->GetAuxiliary();
2594 double nRowTotal
= pRowTotalData
->GetAuxiliary();
2595 double nGrandTotal
= pGrandTotalData
->GetAuxiliary();
2596 if ( nRowTotal
== 0.0 || nColTotal
== 0.0 )
2597 pAggData
->SetError();
2599 pAggData
->SetResult(
2600 ( pAggData
->GetResult() * nGrandTotal
) /
2601 ( nRowTotal
* nColTotal
) );
2611 if ( bHasChild
) // child dimension must be processed last, so the row total is known
2614 pDataChild
->UpdateRunningTotals( pRefChild
, nMeasure
,
2615 bIsSubTotalRow
, rSubState
, rRunning
, rTotals
, rRowParent
);
2619 #if DEBUG_PIVOT_TABLE
2620 void ScDPDataMember::DumpState( const ScDPResultMember
* pRefMember
, ScDocument
* pDoc
, ScAddress
& rPos
) const
2622 lcl_DumpRow( OUString("ScDPDataMember"), GetName(), &aAggregate
, pDoc
, rPos
);
2623 SCROW nStartRow
= rPos
.Row();
2625 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2626 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2627 if ( pDataChild
&& pRefChild
)
2628 pDataChild
->DumpState( pRefChild
, pDoc
, rPos
);
2630 lcl_Indent( pDoc
, nStartRow
, rPos
);
2633 void ScDPDataMember::Dump(int nIndent
) const
2635 std::string
aIndent(nIndent
*2, ' ');
2636 std::cout
<< aIndent
<< "-- data member '"
2637 << (pResultMember
? pResultMember
->GetName() : OUString()) << "'" << std::endl
;
2638 for (const ScDPAggData
* pAgg
= &aAggregate
; pAgg
; pAgg
= pAgg
->GetExistingChild())
2639 pAgg
->Dump(nIndent
+1);
2641 if (pChildDimension
)
2642 pChildDimension
->Dump(nIndent
+1);
2646 // Helper class to select the members to include in
2647 // ScDPResultDimension::InitFrom or LateInitFrom if groups are used
2649 class ScDPGroupCompare
2652 const ScDPResultData
* pResultData
;
2653 const ScDPInitState
& rInitState
;
2659 ScDPGroupCompare( const ScDPResultData
* pData
, const ScDPInitState
& rState
, long nDimension
);
2660 ~ScDPGroupCompare() {}
2662 bool IsIncluded( const ScDPMember
& rMember
) { return bIncludeAll
|| TestIncluded( rMember
); }
2663 bool TestIncluded( const ScDPMember
& rMember
);
2666 ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData
* pData
, const ScDPInitState
& rState
, long nDimension
) :
2667 pResultData( pData
),
2668 rInitState( rState
),
2669 nDimSource( nDimension
)
2671 bIsBase
= pResultData
->IsBaseForGroup( nDimSource
);
2672 nGroupBase
= pResultData
->GetGroupBase( nDimSource
); //TODO: get together in one call?
2674 // if bIncludeAll is set, TestIncluded doesn't need to be called
2675 bIncludeAll
= !( bIsBase
|| nGroupBase
>= 0 );
2678 bool ScDPGroupCompare::TestIncluded( const ScDPMember
& rMember
)
2680 bool bInclude
= true;
2683 // need to check all previous groups
2684 //TODO: get array of groups (or indexes) before loop?
2685 ScDPItemData aMemberData
;
2686 rMember
.FillItemData( aMemberData
);
2688 const std::vector
<ScDPInitState::Member
>& rMemStates
= rInitState
.GetMembers();
2689 std::vector
<ScDPInitState::Member
>::const_iterator it
= rMemStates
.begin(), itEnd
= rMemStates
.end();
2690 for (; it
!= itEnd
&& bInclude
; ++it
)
2692 if (pResultData
->GetGroupBase(it
->mnSrcIndex
) == nDimSource
)
2694 bInclude
= pResultData
->IsInGroup(
2695 it
->mnNameIndex
, it
->mnSrcIndex
, aMemberData
, nDimSource
);
2699 else if ( nGroupBase
>= 0 )
2701 // base isn't used in preceding fields
2702 // -> look for other groups using the same base
2704 //TODO: get array of groups (or indexes) before loop?
2705 ScDPItemData aMemberData
;
2706 rMember
.FillItemData( aMemberData
);
2707 const std::vector
<ScDPInitState::Member
>& rMemStates
= rInitState
.GetMembers();
2708 std::vector
<ScDPInitState::Member
>::const_iterator it
= rMemStates
.begin(), itEnd
= rMemStates
.end();
2709 for (; it
!= itEnd
&& bInclude
; ++it
)
2711 if (pResultData
->GetGroupBase(it
->mnSrcIndex
) == nGroupBase
)
2713 // coverity[copy_paste_error] - same base (hierarchy between
2714 // the two groups is irrelevant)
2715 bInclude
= pResultData
->HasCommonElement(
2716 it
->mnNameIndex
, it
->mnSrcIndex
, aMemberData
, nDimSource
);
2725 ScDPResultDimension::ScDPResultDimension( const ScDPResultData
* pData
) :
2726 pResultData( pData
),
2728 bIsDataLayout( false ),
2729 bSortByData( false ),
2730 bSortAscending( false ),
2732 bAutoTopItems( false ),
2733 bInitialized( false ),
2739 ScDPResultDimension::~ScDPResultDimension()
2741 for( int i
= maMemberArray
.size () ; i
-- > 0 ; )
2742 delete maMemberArray
[i
];
2745 ScDPResultMember
*ScDPResultDimension::FindMember( SCROW iData
) const
2748 return maMemberArray
[0];
2750 MemberHash::const_iterator aRes
= maMemberHash
.find( iData
);
2751 if( aRes
!= maMemberHash
.end()) {
2752 if ( aRes
->second
->IsNamedItem( iData
) )
2753 return aRes
->second
;
2754 OSL_FAIL("problem! hash result is not the same as IsNamedItem");
2758 unsigned int nCount
= maMemberArray
.size();
2759 ScDPResultMember
* pResultMember
;
2760 for( i
= 0; i
< nCount
; i
++ )
2762 pResultMember
= maMemberArray
[i
];
2763 if ( pResultMember
->IsNamedItem( iData
) )
2764 return pResultMember
;
2769 void ScDPResultDimension::InitFrom(
2770 const vector
<ScDPDimension
*>& ppDim
, const vector
<ScDPLevel
*>& ppLev
,
2771 size_t nPos
, ScDPInitState
& rInitState
, bool bInitChild
)
2773 if (nPos
>= ppDim
.size() || nPos
>= ppLev
.size())
2775 bInitialized
= true;
2779 ScDPDimension
* pThisDim
= ppDim
[nPos
];
2780 ScDPLevel
* pThisLevel
= ppLev
[nPos
];
2782 if (!pThisDim
|| !pThisLevel
)
2784 bInitialized
= true;
2788 bIsDataLayout
= pThisDim
->getIsDataLayoutDimension(); // member
2789 aDimensionName
= pThisDim
->getName(); // member
2791 // Check the autoshow setting. If it's enabled, store the settings.
2792 const sheet::DataPilotFieldAutoShowInfo
& rAutoInfo
= pThisLevel
->GetAutoShow();
2793 if ( rAutoInfo
.IsEnabled
)
2796 bAutoTopItems
= ( rAutoInfo
.ShowItemsMode
== sheet::DataPilotFieldShowItemsMode::FROM_TOP
);
2797 nAutoMeasure
= pThisLevel
->GetAutoMeasure();
2798 nAutoCount
= rAutoInfo
.ItemCount
;
2801 // Check the sort info, and store the settings if appropriate.
2802 const sheet::DataPilotFieldSortInfo
& rSortInfo
= pThisLevel
->GetSortInfo();
2803 if ( rSortInfo
.Mode
== sheet::DataPilotFieldSortMode::DATA
)
2806 bSortAscending
= rSortInfo
.IsAscending
;
2807 nSortMeasure
= pThisLevel
->GetSortMeasure();
2810 // global order is used to initialize aMembers, so it doesn't have to be looked at later
2811 const ScMemberSortOrder
& rGlobalOrder
= pThisLevel
->GetGlobalOrder();
2813 long nDimSource
= pThisDim
->GetDimension(); //TODO: check GetSourceDim?
2814 ScDPGroupCompare
aCompare( pResultData
, rInitState
, nDimSource
);
2816 // Now, go through all members and initialize them.
2817 ScDPMembers
* pMembers
= pThisLevel
->GetMembersObject();
2818 long nMembCount
= pMembers
->getCount();
2819 for ( long i
=0; i
<nMembCount
; i
++ )
2821 long nSorted
= rGlobalOrder
.empty() ? i
: rGlobalOrder
[i
];
2823 ScDPMember
* pMember
= pMembers
->getByIndex(nSorted
);
2824 if ( aCompare
.IsIncluded( *pMember
) )
2826 ScDPParentDimData
aData( i
, pThisDim
, pThisLevel
, pMember
);
2827 ScDPResultMember
* pNew
= AddMember( aData
);
2829 rInitState
.AddMember(nDimSource
, pNew
->GetDataId());
2830 pNew
->InitFrom( ppDim
, ppLev
, nPos
+1, rInitState
, bInitChild
);
2831 rInitState
.RemoveMember();
2834 bInitialized
= true;
2837 void ScDPResultDimension::LateInitFrom(
2838 LateInitParams
& rParams
, const vector
<SCROW
>& pItemData
, size_t nPos
, ScDPInitState
& rInitState
)
2840 if ( rParams
.IsEnd( nPos
) )
2842 OSL_ENSURE( nPos
<= pItemData
.size(), OString::number(pItemData
.size()).getStr() );
2843 ScDPDimension
* pThisDim
= rParams
.GetDim( nPos
);
2844 ScDPLevel
* pThisLevel
= rParams
.GetLevel( nPos
);
2845 SCROW rThisData
= pItemData
[nPos
];
2847 if (!pThisDim
|| !pThisLevel
)
2850 long nDimSource
= pThisDim
->GetDimension(); //TODO: check GetSourceDim?
2852 bool bShowEmpty
= pThisLevel
->getShowEmpty();
2854 if ( !bInitialized
)
2855 { // init some values
2856 // create all members at the first call (preserve order)
2857 bIsDataLayout
= pThisDim
->getIsDataLayoutDimension();
2858 aDimensionName
= pThisDim
->getName();
2860 const sheet::DataPilotFieldAutoShowInfo
& rAutoInfo
= pThisLevel
->GetAutoShow();
2861 if ( rAutoInfo
.IsEnabled
)
2864 bAutoTopItems
= ( rAutoInfo
.ShowItemsMode
== sheet::DataPilotFieldShowItemsMode::FROM_TOP
);
2865 nAutoMeasure
= pThisLevel
->GetAutoMeasure();
2866 nAutoCount
= rAutoInfo
.ItemCount
;
2869 const sheet::DataPilotFieldSortInfo
& rSortInfo
= pThisLevel
->GetSortInfo();
2870 if ( rSortInfo
.Mode
== sheet::DataPilotFieldSortMode::DATA
)
2873 bSortAscending
= rSortInfo
.IsAscending
;
2874 nSortMeasure
= pThisLevel
->GetSortMeasure();
2878 bool bLateInitAllMembers
= bIsDataLayout
|| rParams
.GetInitAllChild() || bShowEmpty
;
2880 if ( !bLateInitAllMembers
)
2882 ResultMembers
* pMembers
= pResultData
->GetDimResultMembers(nDimSource
, pThisDim
, pThisLevel
);
2883 bLateInitAllMembers
= pMembers
->IsHasHideDetailsMembers();
2884 #if OSL_DEBUG_LEVEL > 1
2885 OSL_TRACE( "%s", OUStringToOString(aDimensionName
, RTL_TEXTENCODING_UTF8
).getStr() );
2886 if ( pMembers
->IsHasHideDetailsMembers() )
2887 OSL_TRACE( "HasHideDetailsMembers" );
2889 pMembers
->SetHasHideDetailsMembers( false );
2892 bool bNewAllMembers
= (!rParams
.IsRow()) || nPos
== 0 || bLateInitAllMembers
;
2894 if (bNewAllMembers
)
2896 // global order is used to initialize aMembers, so it doesn't have to be looked at later
2897 if ( !bInitialized
)
2898 { //init all members
2899 const ScMemberSortOrder
& rGlobalOrder
= pThisLevel
->GetGlobalOrder();
2901 ScDPGroupCompare
aCompare( pResultData
, rInitState
, nDimSource
);
2902 ScDPMembers
* pMembers
= pThisLevel
->GetMembersObject();
2903 long nMembCount
= pMembers
->getCount();
2904 for ( long i
=0; i
<nMembCount
; i
++ )
2906 long nSorted
= rGlobalOrder
.empty() ? i
: rGlobalOrder
[i
];
2908 ScDPMember
* pMember
= pMembers
->getByIndex(nSorted
);
2909 if ( aCompare
.IsIncluded( *pMember
) )
2910 { // add all members
2911 ScDPParentDimData
aData( i
, pThisDim
, pThisLevel
, pMember
);
2915 bInitialized
= true; // don't call again, even if no members were included
2917 // initialize only specific member (or all if "show empty" flag is set)
2918 if ( bLateInitAllMembers
)
2920 long nCount
= maMemberArray
.size();
2921 for (long i
=0; i
<nCount
; i
++)
2923 ScDPResultMember
* pResultMember
= maMemberArray
[i
];
2926 bool bAllChildren
= false;
2929 if ( pResultMember
->IsNamedItem( rThisData
) )
2930 bAllChildren
= false;
2932 bAllChildren
= true;
2934 rParams
.SetInitAllChildren( bAllChildren
);
2935 rInitState
.AddMember( nDimSource
, pResultMember
->GetDataId() );
2936 pResultMember
->LateInitFrom( rParams
, pItemData
, nPos
+1, rInitState
);
2937 rInitState
.RemoveMember();
2942 ScDPResultMember
* pResultMember
= FindMember( rThisData
);
2943 if( NULL
!= pResultMember
)
2945 rInitState
.AddMember( nDimSource
, pResultMember
->GetDataId() );
2946 pResultMember
->LateInitFrom( rParams
, pItemData
, nPos
+1, rInitState
);
2947 rInitState
.RemoveMember();
2952 InitWithMembers( rParams
, pItemData
, nPos
, rInitState
);
2955 long ScDPResultDimension::GetSize(long nMeasure
) const
2958 long nMemberCount
= maMemberArray
.size();
2961 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
2962 "DataLayout dimension twice?");
2963 // repeat first member...
2964 nTotal
= nMemberCount
* maMemberArray
[0]->GetSize(0); // all measures have equal size
2969 for (long nMem
=0; nMem
<nMemberCount
; nMem
++)
2970 nTotal
+= maMemberArray
[nMem
]->GetSize(nMeasure
);
2975 bool ScDPResultDimension::IsValidEntry( const vector
< SCROW
>& aMembers
) const
2977 if (aMembers
.empty())
2980 const ScDPResultMember
* pMember
= FindMember( aMembers
[0] );
2981 if ( NULL
!= pMember
)
2982 return pMember
->IsValidEntry( aMembers
);
2983 #if OSL_DEBUG_LEVEL > 1
2984 OStringBuffer
strTemp("IsValidEntry: Member not found, DimName = ");
2985 strTemp
.append(OUStringToOString(GetName(), RTL_TEXTENCODING_UTF8
));
2986 OSL_TRACE("%s", strTemp
.getStr());
2991 void ScDPResultDimension::ProcessData( const vector
< SCROW
>& aMembers
,
2992 const ScDPResultDimension
* pDataDim
,
2993 const vector
< SCROW
>& aDataMembers
,
2994 const vector
<ScDPValue
>& aValues
) const
2996 if (aMembers
.empty())
2999 ScDPResultMember
* pMember
= FindMember( aMembers
[0] );
3000 if ( NULL
!= pMember
)
3002 vector
<SCROW
> aChildMembers
;
3003 if (aMembers
.size() > 1)
3005 vector
<SCROW
>::const_iterator itr
= aMembers
.begin();
3006 aChildMembers
.insert(aChildMembers
.begin(), ++itr
, aMembers
.end());
3008 pMember
->ProcessData( aChildMembers
, pDataDim
, aDataMembers
, aValues
);
3012 OSL_FAIL("ProcessData: Member not found");
3015 void ScDPResultDimension::FillMemberResults( uno::Sequence
<sheet::MemberResult
>* pSequences
,
3016 long nStart
, long nMeasure
)
3019 long nCount
= maMemberArray
.size();
3021 for (long i
=0; i
<nCount
; i
++)
3023 long nSorted
= aMemberOrder
.empty() ? i
: aMemberOrder
[i
];
3025 ScDPResultMember
* pMember
= maMemberArray
[nSorted
];
3026 // in data layout dimension, use first member with different measures/names
3027 if ( bIsDataLayout
)
3029 bool bTotalResult
= false;
3030 OUString aMbrName
= pResultData
->GetMeasureDimensionName( nSorted
);
3031 OUString aMbrCapt
= pResultData
->GetMeasureString( nSorted
, false, SUBTOTAL_FUNC_NONE
, bTotalResult
);
3032 maMemberArray
[0]->FillMemberResults( pSequences
, nPos
, nSorted
, false, &aMbrName
, &aMbrCapt
);
3034 else if ( pMember
->IsVisible() )
3036 pMember
->FillMemberResults( pSequences
, nPos
, nMeasure
, false, NULL
, NULL
);
3042 void ScDPResultDimension::FillDataResults(
3043 const ScDPResultMember
* pRefMember
, ScDPResultFilterContext
& rFilterCxt
,
3044 uno::Sequence
< uno::Sequence
<sheet::DataResult
> >& rSequence
, long nMeasure
) const
3046 FilterStack
aFilterStack(rFilterCxt
.maFilters
);
3047 aFilterStack
.pushDimName(GetName(), bIsDataLayout
);
3049 long nMemberMeasure
= nMeasure
;
3050 long nCount
= maMemberArray
.size();
3051 for (long i
=0; i
<nCount
; i
++)
3053 long nSorted
= aMemberOrder
.empty() ? i
: aMemberOrder
[i
];
3055 const ScDPResultMember
* pMember
;
3058 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3059 "DataLayout dimension twice?");
3060 pMember
= maMemberArray
[0];
3061 nMemberMeasure
= nSorted
;
3064 pMember
= maMemberArray
[nSorted
];
3066 if ( pMember
->IsVisible() )
3067 pMember
->FillDataResults(pRefMember
, rFilterCxt
, rSequence
, nMemberMeasure
);
3071 void ScDPResultDimension::UpdateDataResults( const ScDPResultMember
* pRefMember
, long nMeasure
) const
3073 long nMemberMeasure
= nMeasure
;
3074 long nCount
= maMemberArray
.size();
3075 for (long i
=0; i
<nCount
; i
++)
3077 const ScDPResultMember
* pMember
;
3080 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3081 "DataLayout dimension twice?");
3082 pMember
= maMemberArray
[0];
3086 pMember
= maMemberArray
[i
];
3088 if ( pMember
->IsVisible() )
3089 pMember
->UpdateDataResults( pRefMember
, nMemberMeasure
);
3093 void ScDPResultDimension::SortMembers( ScDPResultMember
* pRefMember
)
3095 long nCount
= maMemberArray
.size();
3101 OSL_ENSURE( aMemberOrder
.empty(), "sort twice?" );
3102 aMemberOrder
.resize( nCount
);
3103 for (long nPos
=0; nPos
<nCount
; nPos
++)
3104 aMemberOrder
[nPos
] = nPos
;
3106 ScDPRowMembersOrder
aComp( *this, nSortMeasure
, bSortAscending
);
3107 ::std::sort( aMemberOrder
.begin(), aMemberOrder
.end(), aComp
);
3112 // for data layout, call only once - sorting measure is always taken from settings
3113 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3114 for (long i
=0; i
<nLoopCount
; i
++)
3116 ScDPResultMember
* pMember
= maMemberArray
[i
];
3117 if ( pMember
->IsVisible() )
3118 pMember
->SortMembers( pRefMember
);
3122 void ScDPResultDimension::DoAutoShow( ScDPResultMember
* pRefMember
)
3124 long nCount
= maMemberArray
.size();
3126 // handle children first, before changing the visible state
3128 // for data layout, call only once - sorting measure is always taken from settings
3129 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3130 for (long i
=0; i
<nLoopCount
; i
++)
3132 ScDPResultMember
* pMember
= maMemberArray
[i
];
3133 if ( pMember
->IsVisible() )
3134 pMember
->DoAutoShow( pRefMember
);
3137 if ( bAutoShow
&& nAutoCount
> 0 && nAutoCount
< nCount
)
3139 // establish temporary order, hide remaining members
3141 ScMemberSortOrder aAutoOrder
;
3142 aAutoOrder
.resize( nCount
);
3144 for (nPos
=0; nPos
<nCount
; nPos
++)
3145 aAutoOrder
[nPos
] = nPos
;
3147 ScDPRowMembersOrder
aComp( *this, nAutoMeasure
, !bAutoTopItems
);
3148 ::std::sort( aAutoOrder
.begin(), aAutoOrder
.end(), aComp
);
3150 // look for equal values to the last included one
3152 long nIncluded
= nAutoCount
;
3153 const ScDPResultMember
* pMember1
= maMemberArray
[aAutoOrder
[nIncluded
- 1]];
3154 const ScDPDataMember
* pDataMember1
= pMember1
->IsVisible() ? pMember1
->GetDataRoot() : NULL
;
3155 bool bContinue
= true;
3159 if ( nIncluded
< nCount
)
3161 const ScDPResultMember
* pMember2
= maMemberArray
[aAutoOrder
[nIncluded
]];
3162 const ScDPDataMember
* pDataMember2
= pMember2
->IsVisible() ? pMember2
->GetDataRoot() : NULL
;
3164 if ( lcl_IsEqual( pDataMember1
, pDataMember2
, nAutoMeasure
) )
3166 ++nIncluded
; // include more members if values are equal
3172 // hide the remaining members
3174 for (nPos
= nIncluded
; nPos
< nCount
; nPos
++)
3176 ScDPResultMember
* pMember
= maMemberArray
[aAutoOrder
[nPos
]];
3177 pMember
->SetAutoHidden();
3182 void ScDPResultDimension::ResetResults()
3184 long nCount
= maMemberArray
.size();
3185 for (long i
=0; i
<nCount
; i
++)
3187 // sort order doesn't matter
3188 ScDPResultMember
* pMember
= maMemberArray
[bIsDataLayout
? 0 : i
];
3189 pMember
->ResetResults();
3193 long ScDPResultDimension::GetSortedIndex( long nUnsorted
) const
3195 return aMemberOrder
.empty() ? nUnsorted
: aMemberOrder
[nUnsorted
];
3198 void ScDPResultDimension::UpdateRunningTotals( const ScDPResultMember
* pRefMember
, long nMeasure
,
3199 ScDPRunningTotalState
& rRunning
, ScDPRowTotals
& rTotals
) const
3201 const ScDPResultMember
* pMember
;
3202 long nMemberMeasure
= nMeasure
;
3203 long nCount
= maMemberArray
.size();
3204 for (long i
=0; i
<nCount
; i
++)
3206 long nSorted
= aMemberOrder
.empty() ? i
: aMemberOrder
[i
];
3210 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3211 "DataLayout dimension twice?");
3212 pMember
= maMemberArray
[0];
3213 nMemberMeasure
= nSorted
;
3216 pMember
= maMemberArray
[nSorted
];
3218 if ( pMember
->IsVisible() )
3220 if ( bIsDataLayout
)
3221 rRunning
.AddRowIndex( 0, 0 );
3223 rRunning
.AddRowIndex( i
, nSorted
);
3224 pMember
->UpdateRunningTotals( pRefMember
, nMemberMeasure
, rRunning
, rTotals
);
3225 rRunning
.RemoveRowIndex();
3230 ScDPDataMember
* ScDPResultDimension::GetRowReferenceMember(
3231 const ScDPRelativePos
* pRelativePos
, const OUString
* pName
,
3232 const long* pRowIndexes
, const long* pColIndexes
) const
3234 // get named, previous/next, or first member of this dimension (first existing if pRelativePos and pName are NULL)
3236 OSL_ENSURE( pRelativePos
== NULL
|| pName
== NULL
, "can't use position and name" );
3238 ScDPDataMember
* pColMember
= NULL
;
3240 bool bFirstExisting
= ( pRelativePos
== NULL
&& pName
== NULL
);
3241 long nMemberCount
= maMemberArray
.size();
3242 long nMemberIndex
= 0; // unsorted
3243 long nDirection
= 1; // forward if no relative position is used
3246 nDirection
= pRelativePos
->nDirection
;
3247 nMemberIndex
= pRelativePos
->nBasePos
+ nDirection
; // bounds are handled below
3249 OSL_ENSURE( nDirection
== 1 || nDirection
== -1, "Direction must be 1 or -1" );
3253 // search for named member
3255 const ScDPResultMember
* pRowMember
= maMemberArray
[GetSortedIndex(nMemberIndex
)];
3257 //TODO: use ScDPItemData, as in ScDPDimension::IsValidPage?
3258 while ( pRowMember
&& pRowMember
->GetName() != *pName
)
3261 if ( nMemberIndex
< nMemberCount
)
3262 pRowMember
= maMemberArray
[GetSortedIndex(nMemberIndex
)];
3268 bool bContinue
= true;
3269 while ( bContinue
&& nMemberIndex
>= 0 && nMemberIndex
< nMemberCount
)
3271 const ScDPResultMember
* pRowMember
= maMemberArray
[GetSortedIndex(nMemberIndex
)];
3273 // get child members by given indexes
3275 const long* pNextRowIndex
= pRowIndexes
;
3276 while ( *pNextRowIndex
>= 0 && pRowMember
)
3278 const ScDPResultDimension
* pRowChild
= pRowMember
->GetChildDimension();
3279 if ( pRowChild
&& *pNextRowIndex
< pRowChild
->GetMemberCount() )
3280 pRowMember
= pRowChild
->GetMember( *pNextRowIndex
);
3286 if ( pRowMember
&& pRelativePos
)
3288 // Skip the member if it has hidden details
3289 // (because when looking for the details, it is skipped, too).
3290 // Also skip if the member is invisible because it has no data,
3291 // for consistent ordering.
3292 if ( pRowMember
->HasHiddenDetails() || !pRowMember
->IsVisible() )
3298 pColMember
= pRowMember
->GetDataRoot();
3300 const long* pNextColIndex
= pColIndexes
;
3301 while ( *pNextColIndex
>= 0 && pColMember
)
3303 ScDPDataDimension
* pColChild
= pColMember
->GetChildDimension();
3304 if ( pColChild
&& *pNextColIndex
< pColChild
->GetMemberCount() )
3305 pColMember
= pColChild
->GetMember( *pNextColIndex
);
3312 // continue searching only if looking for first existing or relative position
3313 bContinue
= ( pColMember
== NULL
&& ( bFirstExisting
|| pRelativePos
) );
3314 nMemberIndex
+= nDirection
;
3320 ScDPDataMember
* ScDPResultDimension::GetColReferenceMember(
3321 const ScDPRelativePos
* pRelativePos
, const OUString
* pName
,
3322 long nRefDimPos
, const ScDPRunningTotalState
& rRunning
)
3324 OSL_ENSURE( pRelativePos
== NULL
|| pName
== NULL
, "can't use position and name" );
3326 const long* pColIndexes
= &rRunning
.GetColSorted()[0];
3327 const long* pRowIndexes
= &rRunning
.GetRowSorted()[0];
3329 // get own row member using all indexes
3331 const ScDPResultMember
* pRowMember
= rRunning
.GetRowResRoot();
3332 ScDPDataMember
* pColMember
= NULL
;
3334 const long* pNextRowIndex
= pRowIndexes
;
3335 while ( *pNextRowIndex
>= 0 && pRowMember
)
3337 const ScDPResultDimension
* pRowChild
= pRowMember
->GetChildDimension();
3338 if ( pRowChild
&& *pNextRowIndex
< pRowChild
->GetMemberCount() )
3339 pRowMember
= pRowChild
->GetMember( *pNextRowIndex
);
3345 // get column (data) members before the reference field
3346 //TODO: pass rRowParent from ScDPDataMember::UpdateRunningTotals instead
3350 pColMember
= pRowMember
->GetDataRoot();
3352 const long* pNextColIndex
= pColIndexes
;
3353 long nColSkipped
= 0;
3354 while ( *pNextColIndex
>= 0 && pColMember
&& nColSkipped
< nRefDimPos
)
3356 ScDPDataDimension
* pColChild
= pColMember
->GetChildDimension();
3357 if ( pColChild
&& *pNextColIndex
< pColChild
->GetMemberCount() )
3358 pColMember
= pColChild
->GetMember( *pNextColIndex
);
3366 // get column member for the reference field
3370 ScDPDataDimension
* pReferenceDim
= pColMember
->GetChildDimension();
3371 if ( pReferenceDim
)
3373 long nReferenceCount
= pReferenceDim
->GetMemberCount();
3375 bool bFirstExisting
= ( pRelativePos
== NULL
&& pName
== NULL
);
3376 long nMemberIndex
= 0; // unsorted
3377 long nDirection
= 1; // forward if no relative position is used
3378 pColMember
= NULL
; // don't use parent dimension's member if none found
3381 nDirection
= pRelativePos
->nDirection
;
3382 nMemberIndex
= pRelativePos
->nBasePos
+ nDirection
; // bounds are handled below
3386 // search for named member
3388 pColMember
= pReferenceDim
->GetMember( pReferenceDim
->GetSortedIndex( nMemberIndex
) );
3390 //TODO: use ScDPItemData, as in ScDPDimension::IsValidPage?
3391 while ( pColMember
&& pColMember
->GetName() != *pName
)
3394 if ( nMemberIndex
< nReferenceCount
)
3395 pColMember
= pReferenceDim
->GetMember( pReferenceDim
->GetSortedIndex( nMemberIndex
) );
3401 bool bContinue
= true;
3402 while ( bContinue
&& nMemberIndex
>= 0 && nMemberIndex
< nReferenceCount
)
3404 pColMember
= pReferenceDim
->GetMember( pReferenceDim
->GetSortedIndex( nMemberIndex
) );
3406 // get column members below the reference field
3408 const long* pNextColIndex
= pColIndexes
+ nRefDimPos
+ 1;
3409 while ( *pNextColIndex
>= 0 && pColMember
)
3411 ScDPDataDimension
* pColChild
= pColMember
->GetChildDimension();
3412 if ( pColChild
&& *pNextColIndex
< pColChild
->GetMemberCount() )
3413 pColMember
= pColChild
->GetMember( *pNextColIndex
);
3419 if ( pColMember
&& pRelativePos
)
3421 // Skip the member if it has hidden details
3422 // (because when looking for the details, it is skipped, too).
3423 // Also skip if the member is invisible because it has no data,
3424 // for consistent ordering.
3425 if ( pColMember
->HasHiddenDetails() || !pColMember
->IsVisible() )
3429 // continue searching only if looking for first existing or relative position
3430 bContinue
= ( pColMember
== NULL
&& ( bFirstExisting
|| pRelativePos
) );
3431 nMemberIndex
+= nDirection
;
3441 #if DEBUG_PIVOT_TABLE
3442 void ScDPResultDimension::DumpState( const ScDPResultMember
* pRefMember
, ScDocument
* pDoc
, ScAddress
& rPos
) const
3444 OUString aDimName
= bIsDataLayout
? OUString("(data layout)") : OUString(GetName());
3445 lcl_DumpRow( OUString("ScDPResultDimension"), aDimName
, NULL
, pDoc
, rPos
);
3447 SCROW nStartRow
= rPos
.Row();
3449 long nCount
= bIsDataLayout
? 1 : maMemberArray
.size();
3450 for (long i
=0; i
<nCount
; i
++)
3452 const ScDPResultMember
* pMember
= maMemberArray
[i
];
3453 pMember
->DumpState( pRefMember
, pDoc
, rPos
);
3456 lcl_Indent( pDoc
, nStartRow
, rPos
);
3459 void ScDPResultDimension::Dump(int nIndent
) const
3461 std::string
aIndent(nIndent
*2, ' ');
3462 std::cout
<< aIndent
<< "-- dimension '" << GetName() << "'" << std::endl
;
3463 MemberArray::const_iterator it
= maMemberArray
.begin(), itEnd
= maMemberArray
.end();
3464 for (; it
!= itEnd
; ++it
)
3466 const ScDPResultMember
* p
= *it
;
3472 long ScDPResultDimension::GetMemberCount() const
3474 return maMemberArray
.size();
3477 const ScDPResultMember
* ScDPResultDimension::GetMember(long n
) const
3479 return maMemberArray
[n
];
3481 ScDPResultMember
* ScDPResultDimension::GetMember(long n
)
3483 return maMemberArray
[n
];
3486 ScDPResultDimension
* ScDPResultDimension::GetFirstChildDimension() const
3488 if ( maMemberArray
.size() > 0 )
3489 return maMemberArray
[0]->GetChildDimension();
3494 void ScDPResultDimension::FillVisibilityData(ScDPResultVisibilityData
& rData
) const
3499 MemberArray::const_iterator itr
= maMemberArray
.begin(), itrEnd
= maMemberArray
.end();
3501 for (;itr
!= itrEnd
; ++itr
)
3503 ScDPResultMember
* pMember
= *itr
;
3504 if (pMember
->IsValid())
3507 pMember
->FillItemData(aItem
);
3508 rData
.addVisibleMember(GetName(), aItem
);
3509 pMember
->FillVisibilityData(rData
);
3514 ScDPDataDimension::ScDPDataDimension( const ScDPResultData
* pData
) :
3515 pResultData( pData
),
3516 pResultDimension( NULL
),
3517 bIsDataLayout( false )
3521 ScDPDataDimension::~ScDPDataDimension()
3523 std::for_each(maMembers
.begin(), maMembers
.end(), boost::checked_deleter
<ScDPDataMember
>());
3526 void ScDPDataDimension::InitFrom( const ScDPResultDimension
* pDim
)
3531 pResultDimension
= pDim
;
3532 bIsDataLayout
= pDim
->IsDataLayout();
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
++)
3539 const ScDPResultMember
* pResMem
= pDim
->GetMember(i
);
3541 ScDPDataMember
* pNew
= new ScDPDataMember( pResultData
, pResMem
);
3542 maMembers
.push_back( pNew
);
3544 if ( !pResultData
->IsLateInit() )
3546 // with LateInit, pResMem hasn't necessarily been initialized yet,
3547 // so InitFrom for the new result member is called from its ProcessData method
3549 const ScDPResultDimension
* pChildDim
= pResMem
->GetChildDimension();
3551 pNew
->InitFrom( pChildDim
);
3556 void ScDPDataDimension::ProcessData( const vector
< SCROW
>& aDataMembers
, const vector
<ScDPValue
>& aValues
,
3557 const ScDPSubTotalState
& rSubState
)
3559 // the ScDPItemData array must contain enough entries for all dimensions - this isn't checked
3561 long nCount
= maMembers
.size();
3562 for (long i
=0; i
<nCount
; i
++)
3564 ScDPDataMember
* pMember
= maMembers
[(sal_uInt16
)i
];
3566 // always first member for data layout dim
3567 if ( bIsDataLayout
|| ( !aDataMembers
.empty() && pMember
->IsNamedItem(aDataMembers
[0]) ) )
3569 vector
<SCROW
> aChildDataMembers
;
3570 if (aDataMembers
.size() > 1)
3572 vector
<SCROW
>::const_iterator itr
= aDataMembers
.begin();
3573 aChildDataMembers
.insert(aChildDataMembers
.begin(), ++itr
, aDataMembers
.end());
3575 pMember
->ProcessData( aChildDataMembers
, aValues
, rSubState
);
3580 OSL_FAIL("ProcessData: Member not found");
3583 void ScDPDataDimension::FillDataRow(
3584 const ScDPResultDimension
* pRefDim
, ScDPResultFilterContext
& rFilterCxt
,
3585 uno::Sequence
<sheet::DataResult
>& rSequence
, long nMeasure
, bool bIsSubTotalRow
,
3586 const ScDPSubTotalState
& rSubState
) const
3589 bool bDataLayout
= false;
3590 if (pResultDimension
)
3592 aDimName
= pResultDimension
->GetName();
3593 bDataLayout
= pResultDimension
->IsDataLayout();
3596 FilterStack
aFilterStack(rFilterCxt
.maFilters
);
3597 aFilterStack
.pushDimName(aDimName
, bDataLayout
);
3599 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3600 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3602 const ScMemberSortOrder
& rMemberOrder
= pRefDim
->GetMemberOrder();
3604 long nMemberMeasure
= nMeasure
;
3605 long nCount
= maMembers
.size();
3606 for (long i
=0; i
<nCount
; i
++)
3608 long nSorted
= rMemberOrder
.empty() ? i
: rMemberOrder
[i
];
3610 long nMemberPos
= nSorted
;
3613 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3614 "DataLayout dimension twice?");
3616 nMemberMeasure
= nSorted
;
3619 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(nMemberPos
);
3620 if ( pRefMember
->IsVisible() ) //TODO: here or in ScDPDataMember::FillDataRow ???
3622 const ScDPDataMember
* pDataMember
= maMembers
[(sal_uInt16
)nMemberPos
];
3623 pDataMember
->FillDataRow(pRefMember
, rFilterCxt
, rSequence
, nMemberMeasure
, bIsSubTotalRow
, rSubState
);
3628 void ScDPDataDimension::UpdateDataRow( const ScDPResultDimension
* pRefDim
,
3629 long nMeasure
, bool bIsSubTotalRow
,
3630 const ScDPSubTotalState
& rSubState
) const
3632 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3633 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3635 long nMemberMeasure
= nMeasure
;
3636 long nCount
= maMembers
.size();
3637 for (long i
=0; i
<nCount
; i
++)
3639 long nMemberPos
= i
;
3642 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3643 "DataLayout dimension twice?");
3648 // Calculate must be called even if the member is not visible (for use as reference value)
3649 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(nMemberPos
);
3650 ScDPDataMember
* pDataMember
= maMembers
[(sal_uInt16
)nMemberPos
];
3651 pDataMember
->UpdateDataRow( pRefMember
, nMemberMeasure
, bIsSubTotalRow
, rSubState
);
3655 void ScDPDataDimension::SortMembers( ScDPResultDimension
* pRefDim
)
3657 long nCount
= maMembers
.size();
3659 if ( pRefDim
->IsSortByData() )
3663 ScMemberSortOrder
& rMemberOrder
= pRefDim
->GetMemberOrder();
3664 OSL_ENSURE( rMemberOrder
.empty(), "sort twice?" );
3665 rMemberOrder
.resize( nCount
);
3666 for (long nPos
=0; nPos
<nCount
; nPos
++)
3667 rMemberOrder
[nPos
] = nPos
;
3669 ScDPColMembersOrder
aComp( *this, pRefDim
->GetSortMeasure(), pRefDim
->IsSortAscending() );
3670 ::std::sort( rMemberOrder
.begin(), rMemberOrder
.end(), aComp
);
3675 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3676 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3678 // for data layout, call only once - sorting measure is always taken from settings
3679 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3680 for (long i
=0; i
<nLoopCount
; i
++)
3682 ScDPResultMember
* pRefMember
= pRefDim
->GetMember(i
);
3683 if ( pRefMember
->IsVisible() ) //TODO: here or in ScDPDataMember ???
3685 ScDPDataMember
* pDataMember
= maMembers
[(sal_uInt16
)i
];
3686 pDataMember
->SortMembers( pRefMember
);
3691 void ScDPDataDimension::DoAutoShow( ScDPResultDimension
* pRefDim
)
3693 long nCount
= maMembers
.size();
3695 // handle children first, before changing the visible state
3697 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3698 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3700 // for data layout, call only once - sorting measure is always taken from settings
3701 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3702 for (long i
=0; i
<nLoopCount
; i
++)
3704 ScDPResultMember
* pRefMember
= pRefDim
->GetMember(i
);
3705 if ( pRefMember
->IsVisible() ) //TODO: here or in ScDPDataMember ???
3707 ScDPDataMember
* pDataMember
= maMembers
[i
];
3708 pDataMember
->DoAutoShow( pRefMember
);
3712 if ( pRefDim
->IsAutoShow() && pRefDim
->GetAutoCount() > 0 && pRefDim
->GetAutoCount() < nCount
)
3714 // establish temporary order, hide remaining members
3716 ScMemberSortOrder aAutoOrder
;
3717 aAutoOrder
.resize( nCount
);
3719 for (nPos
=0; nPos
<nCount
; nPos
++)
3720 aAutoOrder
[nPos
] = nPos
;
3722 ScDPColMembersOrder
aComp( *this, pRefDim
->GetAutoMeasure(), !pRefDim
->IsAutoTopItems() );
3723 ::std::sort( aAutoOrder
.begin(), aAutoOrder
.end(), aComp
);
3725 // look for equal values to the last included one
3727 long nIncluded
= pRefDim
->GetAutoCount();
3728 ScDPDataMember
* pDataMember1
= maMembers
[aAutoOrder
[nIncluded
- 1]];
3729 if ( !pDataMember1
->IsVisible() )
3730 pDataMember1
= NULL
;
3731 bool bContinue
= true;
3735 if ( nIncluded
< nCount
)
3737 ScDPDataMember
* pDataMember2
= maMembers
[aAutoOrder
[nIncluded
]];
3738 if ( !pDataMember2
->IsVisible() )
3739 pDataMember2
= NULL
;
3741 if ( lcl_IsEqual( pDataMember1
, pDataMember2
, pRefDim
->GetAutoMeasure() ) )
3743 ++nIncluded
; // include more members if values are equal
3749 // hide the remaining members
3751 for (nPos
= nIncluded
; nPos
< nCount
; nPos
++)
3753 ScDPResultMember
* pMember
= pRefDim
->GetMember(aAutoOrder
[nPos
]);
3754 pMember
->SetAutoHidden();
3759 void ScDPDataDimension::ResetResults()
3761 long nCount
= maMembers
.size();
3762 for (long i
=0; i
<nCount
; i
++)
3764 // sort order doesn't matter
3766 long nMemberPos
= bIsDataLayout
? 0 : i
;
3767 ScDPDataMember
* pDataMember
= maMembers
[nMemberPos
];
3768 pDataMember
->ResetResults();
3772 long ScDPDataDimension::GetSortedIndex( long nUnsorted
) const
3774 if (!pResultDimension
)
3777 const ScMemberSortOrder
& rMemberOrder
= pResultDimension
->GetMemberOrder();
3778 return rMemberOrder
.empty() ? nUnsorted
: rMemberOrder
[nUnsorted
];
3781 void ScDPDataDimension::UpdateRunningTotals( const ScDPResultDimension
* pRefDim
,
3782 long nMeasure
, bool bIsSubTotalRow
,
3783 const ScDPSubTotalState
& rSubState
, ScDPRunningTotalState
& rRunning
,
3784 ScDPRowTotals
& rTotals
, const ScDPResultMember
& rRowParent
) const
3786 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3787 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3789 long nMemberMeasure
= nMeasure
;
3790 long nCount
= maMembers
.size();
3791 for (long i
=0; i
<nCount
; i
++)
3793 const ScMemberSortOrder
& rMemberOrder
= pRefDim
->GetMemberOrder();
3794 long nSorted
= rMemberOrder
.empty() ? i
: rMemberOrder
[i
];
3796 long nMemberPos
= nSorted
;
3799 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3800 "DataLayout dimension twice?");
3802 nMemberMeasure
= nSorted
;
3805 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(nMemberPos
);
3806 if ( pRefMember
->IsVisible() )
3808 if ( bIsDataLayout
)
3809 rRunning
.AddColIndex( 0, 0 );
3811 rRunning
.AddColIndex( i
, nSorted
);
3813 ScDPDataMember
* pDataMember
= maMembers
[nMemberPos
];
3814 pDataMember
->UpdateRunningTotals(
3815 pRefMember
, nMemberMeasure
, bIsSubTotalRow
, rSubState
, rRunning
, rTotals
, rRowParent
);
3817 rRunning
.RemoveColIndex();
3822 #if DEBUG_PIVOT_TABLE
3823 void ScDPDataDimension::DumpState( const ScDPResultDimension
* pRefDim
, ScDocument
* pDoc
, ScAddress
& rPos
) const
3825 OUString aDimName
= bIsDataLayout
? OUString("(data layout)") : OUString("(unknown)");
3826 lcl_DumpRow( OUString("ScDPDataDimension"), aDimName
, NULL
, pDoc
, rPos
);
3828 SCROW nStartRow
= rPos
.Row();
3830 long nCount
= bIsDataLayout
? 1 : maMembers
.size();
3831 for (long i
=0; i
<nCount
; i
++)
3833 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(i
);
3834 const ScDPDataMember
* pDataMember
= maMembers
[i
];
3835 pDataMember
->DumpState( pRefMember
, pDoc
, rPos
);
3838 lcl_Indent( pDoc
, nStartRow
, rPos
);
3841 void ScDPDataDimension::Dump(int nIndent
) const
3843 std::string
aIndent(nIndent
*2, ' ');
3844 std::cout
<< aIndent
<< "-- data dimension '"
3845 << (pResultDimension
? pResultDimension
->GetName() : OUString()) << "'" << std::endl
;
3846 ScDPDataMembers::const_iterator it
= maMembers
.begin(), itEnd
= maMembers
.end();
3847 for (; it
!= itEnd
; ++it
)
3848 (*it
)->Dump(nIndent
+1);
3852 long ScDPDataDimension::GetMemberCount() const
3854 return maMembers
.size();
3857 const ScDPDataMember
* ScDPDataDimension::GetMember(long n
) const
3859 return maMembers
[n
];
3862 ScDPDataMember
* ScDPDataDimension::GetMember(long n
)
3864 return maMembers
[n
];
3867 ScDPResultVisibilityData::ScDPResultVisibilityData(
3868 ScDPSource
* pSource
) :
3873 ScDPResultVisibilityData::~ScDPResultVisibilityData()
3877 void ScDPResultVisibilityData::addVisibleMember(const OUString
& rDimName
, const ScDPItemData
& rMemberItem
)
3879 DimMemberType::iterator itr
= maDimensions
.find(rDimName
);
3880 if (itr
== maDimensions
.end())
3882 pair
<DimMemberType::iterator
, bool> r
= maDimensions
.insert(
3883 DimMemberType::value_type(rDimName
, VisibleMemberType()));
3886 // insertion failed.
3891 VisibleMemberType
& rMem
= itr
->second
;
3892 VisibleMemberType::iterator itrMem
= rMem
.find(rMemberItem
);
3893 if (itrMem
== rMem
.end())
3894 rMem
.insert(rMemberItem
);
3897 void ScDPResultVisibilityData::fillFieldFilters(vector
<ScDPFilteredCache::Criterion
>& rFilters
) const
3899 typedef std::unordered_map
<OUString
, long, OUStringHash
> FieldNameMapType
;
3900 FieldNameMapType aFieldNames
;
3901 ScDPTableData
* pData
= mpSource
->GetData();
3902 long nColumnCount
= pData
->GetColumnCount();
3903 for (long i
= 0; i
< nColumnCount
; ++i
)
3906 FieldNameMapType::value_type(pData
->getDimensionName(i
), i
));
3909 const ScDPDimensions
* pDims
= mpSource
->GetDimensionsObject();
3910 for (DimMemberType::const_iterator itr
= maDimensions
.begin(), itrEnd
= maDimensions
.end();
3911 itr
!= itrEnd
; ++itr
)
3913 const OUString
& rDimName
= itr
->first
;
3914 ScDPFilteredCache::Criterion aCri
;
3915 FieldNameMapType::const_iterator itrField
= aFieldNames
.find(rDimName
);
3916 if (itrField
== aFieldNames
.end())
3917 // This should never happen!
3920 long nDimIndex
= itrField
->second
;
3921 aCri
.mnFieldIndex
= static_cast<sal_Int32
>(nDimIndex
);
3922 aCri
.mpFilter
.reset(new ScDPFilteredCache::GroupFilter
);
3924 ScDPFilteredCache::GroupFilter
* pGrpFilter
=
3925 static_cast<ScDPFilteredCache::GroupFilter
*>(aCri
.mpFilter
.get());
3927 const VisibleMemberType
& rMem
= itr
->second
;
3928 for (VisibleMemberType::const_iterator itrMem
= rMem
.begin(), itrMemEnd
= rMem
.end();
3929 itrMem
!= itrMemEnd
; ++itrMem
)
3931 const ScDPItemData
& rMemItem
= *itrMem
;
3932 pGrpFilter
->addMatchItem(rMemItem
);
3935 ScDPDimension
* pDim
= pDims
->getByIndex(nDimIndex
);
3936 ScDPMembers
* pMembers
= pDim
->GetHierarchiesObject()->getByIndex(0)->
3937 GetLevelsObject()->getByIndex(0)->GetMembersObject();
3938 if (pGrpFilter
->getMatchItemCount() < static_cast<size_t>(pMembers
->getCount()))
3939 rFilters
.push_back(aCri
);
3943 size_t ScDPResultVisibilityData::MemberHash::operator() (const ScDPItemData
& r
) const
3946 return static_cast<size_t>(::rtl::math::approxFloor(r
.GetValue()));
3948 return r
.GetString().hashCode();
3950 SCROW
ScDPResultMember::GetDataId( ) const
3952 const ScDPMember
* pMemberDesc
= GetDPMember();
3954 return pMemberDesc
->GetItemDataId();
3958 ScDPResultMember
* ScDPResultDimension::AddMember(const ScDPParentDimData
&aData
)
3960 ScDPResultMember
* pMember
= new ScDPResultMember( pResultData
, aData
, false );
3961 SCROW nDataIndex
= pMember
->GetDataId();
3962 maMemberArray
.push_back( pMember
);
3964 if ( maMemberHash
.end() == maMemberHash
.find( nDataIndex
) )
3965 maMemberHash
.insert( std::pair
< SCROW
, ScDPResultMember
*>( nDataIndex
, pMember
) );
3969 ScDPResultMember
* ScDPResultDimension::InsertMember(ScDPParentDimData
*pMemberData
)
3972 if ( !lcl_SearchMember( maMemberArray
, pMemberData
->mnOrder
, nInsert
) )
3974 ScDPResultMember
* pNew
= new ScDPResultMember( pResultData
, *pMemberData
, false );
3975 maMemberArray
.insert( maMemberArray
.begin()+nInsert
, pNew
);
3977 SCROW nDataIndex
= pMemberData
->mpMemberDesc
->GetItemDataId();
3978 if ( maMemberHash
.end() == maMemberHash
.find( nDataIndex
) )
3979 maMemberHash
.insert( std::pair
< SCROW
, ScDPResultMember
*>( nDataIndex
, pNew
) );
3982 return maMemberArray
[ nInsert
];
3985 void ScDPResultDimension::InitWithMembers(
3986 LateInitParams
& rParams
, const std::vector
<SCROW
>& pItemData
, size_t nPos
,
3987 ScDPInitState
& rInitState
)
3989 if ( rParams
.IsEnd( nPos
) )
3991 ScDPDimension
* pThisDim
= rParams
.GetDim( nPos
);
3992 ScDPLevel
* pThisLevel
= rParams
.GetLevel( nPos
);
3993 SCROW nDataID
= pItemData
[nPos
];
3995 if (pThisDim
&& pThisLevel
)
3997 long nDimSource
= pThisDim
->GetDimension(); //TODO: check GetSourceDim?
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
;
4005 pResultMember
= FindMember( nDataID
);
4007 bInitialized
= true;
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
);
4015 if ( pResultMember
)
4017 rInitState
.AddMember( nDimSource
, pResultMember
->GetDataId() );
4018 pResultMember
->LateInitFrom(rParams
, pItemData
, nPos
+1, rInitState
);
4019 rInitState
.RemoveMember();
4024 ScDPParentDimData::ScDPParentDimData() :
4025 mnOrder(-1), mpParentDim(NULL
), mpParentLevel(NULL
), mpMemberDesc(NULL
) {}
4027 ScDPParentDimData::ScDPParentDimData(
4028 SCROW nIndex
, const ScDPDimension
* pDim
, const ScDPLevel
* pLev
, const ScDPMember
* pMember
) :
4029 mnOrder(nIndex
), mpParentDim(pDim
), mpParentLevel(pLev
), mpMemberDesc(pMember
) {}
4031 ScDPParentDimData
* ResultMembers::FindMember( SCROW nIndex
) const
4033 DimMemberHash::const_iterator aRes
= maMemberHash
.find( nIndex
);
4034 if( aRes
!= maMemberHash
.end()) {
4035 if ( aRes
->second
->mpMemberDesc
&& aRes
->second
->mpMemberDesc
->GetItemDataId()==nIndex
)
4036 return aRes
->second
;
4040 void ResultMembers::InsertMember( ScDPParentDimData
* pNew
)
4042 if ( !pNew
->mpMemberDesc
->getShowDetails() )
4043 mbHasHideDetailsMember
= true;
4044 maMemberHash
.insert( std::pair
< const SCROW
, ScDPParentDimData
*>( pNew
->mpMemberDesc
->GetItemDataId(), pNew
) );
4047 ResultMembers::ResultMembers():
4048 mbHasHideDetailsMember( false )
4051 ResultMembers::~ResultMembers()
4053 for ( DimMemberHash::const_iterator iter
= maMemberHash
.begin(); iter
!= maMemberHash
.end(); ++iter
)
4054 delete iter
->second
;
4057 LateInitParams::LateInitParams(
4058 const vector
<ScDPDimension
*>& ppDim
, const vector
<ScDPLevel
*>& ppLev
, bool bRow
, bool bInitChild
, bool bAllChildren
) :
4062 mbInitChild( bInitChild
),
4063 mbAllChildren( bAllChildren
)
4067 LateInitParams::~LateInitParams()
4071 bool LateInitParams::IsEnd( size_t nPos
) const
4073 return nPos
>= mppDim
.size();
4076 void ScDPResultDimension::CheckShowEmpty( bool bShow
)
4078 long nCount
= maMemberArray
.size();
4080 ScDPResultMember
* pMember
= NULL
;
4081 for (long i
=0; i
<nCount
; i
++)
4083 pMember
= maMemberArray
.at(i
);
4084 pMember
->CheckShowEmpty(bShow
);
4089 void ScDPResultMember::CheckShowEmpty( bool bShow
)
4093 ScDPResultDimension
* pChildDim
= GetChildDimension();
4095 pChildDim
->CheckShowEmpty();
4097 else if (IsValid() && bInitialized
)
4099 bShow
= bShow
|| (GetParentLevel() && GetParentLevel()->getShowEmpty());
4103 ScDPResultDimension
* pChildDim
= GetChildDimension();
4105 pChildDim
->CheckShowEmpty(true);
4110 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */