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 "stlalgorithm.hxx"
31 #include "dpresfilter.hxx"
34 #include <osl/diagnose.h>
35 #include <rtl/math.hxx>
36 #include <rtl/strbuf.hxx>
41 #include <boost/unordered_map.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] = // passend zum 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();
133 // function objects for sorting of the column and row members:
136 class ScDPRowMembersOrder
138 ScDPResultDimension
& rDimension
;
143 ScDPRowMembersOrder( ScDPResultDimension
& rDim
, long nM
, bool bAsc
) :
148 ~ScDPRowMembersOrder() {}
150 bool operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const;
153 class ScDPColMembersOrder
155 ScDPDataDimension
& rDimension
;
160 ScDPColMembersOrder( ScDPDataDimension
& rDim
, long nM
, bool bAsc
) :
165 ~ScDPColMembersOrder() {}
167 bool operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const;
170 static bool lcl_IsLess( const ScDPDataMember
* pDataMember1
, const ScDPDataMember
* pDataMember2
, long nMeasure
, bool bAscending
)
172 // members can be NULL if used for rows
174 ScDPSubTotalState aEmptyState
;
175 const ScDPAggData
* pAgg1
= pDataMember1
? pDataMember1
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
176 const ScDPAggData
* pAgg2
= pDataMember2
? pDataMember2
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
178 bool bError1
= pAgg1
&& pAgg1
->HasError();
179 bool bError2
= pAgg2
&& pAgg2
->HasError();
181 return false; // errors are always sorted at the end
183 return true; // errors are always sorted at the end
186 double fVal1
= ( pAgg1
&& pAgg1
->HasData() ) ? pAgg1
->GetResult() : 0.0; // no data is sorted as 0
187 double fVal2
= ( pAgg2
&& pAgg2
->HasData() ) ? pAgg2
->GetResult() : 0.0;
190 // don't have to check approxEqual, as this is the only sort criterion
192 return bAscending
? ( fVal1
< fVal2
) : ( fVal1
> fVal2
);
196 static bool lcl_IsEqual( const ScDPDataMember
* pDataMember1
, const ScDPDataMember
* pDataMember2
, long nMeasure
)
198 // members can be NULL if used for rows
200 ScDPSubTotalState aEmptyState
;
201 const ScDPAggData
* pAgg1
= pDataMember1
? pDataMember1
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
202 const ScDPAggData
* pAgg2
= pDataMember2
? pDataMember2
->GetConstAggData( nMeasure
, aEmptyState
) : NULL
;
204 bool bError1
= pAgg1
&& pAgg1
->HasError();
205 bool bError2
= pAgg2
&& pAgg2
->HasError();
209 return true; // equal
217 double fVal1
= ( pAgg1
&& pAgg1
->HasData() ) ? pAgg1
->GetResult() : 0.0; // no data is sorted as 0
218 double fVal2
= ( pAgg2
&& pAgg2
->HasData() ) ? pAgg2
->GetResult() : 0.0;
221 // this is used to find equal data at the end of the AutoShow range, so approxEqual must be used
223 return rtl::math::approxEqual( fVal1
, fVal2
);
227 bool ScDPRowMembersOrder::operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const
229 const ScDPResultMember
* pMember1
= rDimension
.GetMember(nIndex1
);
230 const ScDPResultMember
* pMember2
= rDimension
.GetMember(nIndex2
);
232 // make the hide item to the largest order.
233 if ( !pMember1
->IsVisible() || !pMember2
->IsVisible() )
234 return pMember1
->IsVisible();
235 const ScDPDataMember
* pDataMember1
= pMember1
->GetDataRoot() ;
236 const ScDPDataMember
* pDataMember2
= pMember2
->GetDataRoot();
237 // GetDataRoot can be NULL if there was no data.
238 // IsVisible == false can happen after AutoShow.
239 return lcl_IsLess( pDataMember1
, pDataMember2
, nMeasure
, bAscending
);
242 bool ScDPColMembersOrder::operator()( sal_Int32 nIndex1
, sal_Int32 nIndex2
) const
244 const ScDPDataMember
* pDataMember1
= rDimension
.GetMember(nIndex1
);
245 const ScDPDataMember
* pDataMember2
= rDimension
.GetMember(nIndex2
);
246 bool bHide1
= pDataMember1
&& !pDataMember1
->IsVisible();
247 bool bHide2
= pDataMember2
&& !pDataMember2
->IsVisible();
248 if ( bHide1
|| bHide2
)
250 return lcl_IsLess( pDataMember1
, pDataMember2
, nMeasure
, bAscending
);
253 ScDPInitState::Member::Member(long nSrcIndex
, SCROW nNameIndex
) :
254 mnSrcIndex(nSrcIndex
), mnNameIndex(nNameIndex
) {}
256 void ScDPInitState::AddMember( long nSourceIndex
, SCROW nMember
)
258 maMembers
.push_back(Member(nSourceIndex
, nMember
));
261 void ScDPInitState::RemoveMember()
263 OSL_ENSURE(!maMembers
.empty(), "ScDPInitState::RemoveMember: Attempt to remmove member while empty.");
264 if (!maMembers
.empty())
265 maMembers
.pop_back();
270 #if DEBUG_PIVOT_TABLE
272 const OUString
& rType
, const OUString
& rName
, const ScDPAggData
* pAggData
,
273 ScDocument
* pDoc
, ScAddress
& rPos
)
275 SCCOL nCol
= rPos
.Col();
276 SCROW nRow
= rPos
.Row();
277 SCTAB nTab
= rPos
.Tab();
278 pDoc
->SetString( nCol
++, nRow
, nTab
, rType
);
279 pDoc
->SetString( nCol
++, nRow
, nTab
, rName
);
282 pDoc
->SetValue( nCol
++, nRow
, nTab
, pAggData
->GetResult() );
283 pAggData
= pAggData
->GetExistingChild();
285 rPos
.SetRow( nRow
+ 1 );
288 void lcl_Indent( ScDocument
* pDoc
, SCROW nStartRow
, const ScAddress
& rPos
)
290 SCCOL nCol
= rPos
.Col();
291 SCTAB nTab
= rPos
.Tab();
294 for (SCROW nRow
= nStartRow
; nRow
< rPos
.Row(); nRow
++)
296 aString
= pDoc
->GetString(nCol
, nRow
, nTab
);
297 if (!aString
.isEmpty())
299 aString
= " " + aString
;
300 pDoc
->SetString( nCol
, nRow
, nTab
, aString
);
308 ScDPRunningTotalState::ScDPRunningTotalState( ScDPResultMember
* pColRoot
, ScDPResultMember
* pRowRoot
) :
309 pColResRoot(pColRoot
), pRowResRoot(pRowRoot
)
311 // These arrays should never be empty as the terminating value must be present at all times.
312 maColVisible
.push_back(-1);
313 maColSorted
.push_back(-1);
314 maRowVisible
.push_back(-1);
315 maRowSorted
.push_back(-1);
318 const ScDPRunningTotalState::IndexArray
& ScDPRunningTotalState::GetColVisible() const
323 const ScDPRunningTotalState::IndexArray
& ScDPRunningTotalState::GetColSorted() const
328 const ScDPRunningTotalState::IndexArray
& ScDPRunningTotalState::GetRowVisible() const
333 const ScDPRunningTotalState::IndexArray
& ScDPRunningTotalState::GetRowSorted() const
338 void ScDPRunningTotalState::AddColIndex( long nVisible
, long nSorted
)
340 maColVisible
.back() = nVisible
;
341 maColVisible
.push_back(-1);
343 maColSorted
.back() = nSorted
;
344 maColSorted
.push_back(-1);
347 void ScDPRunningTotalState::AddRowIndex( long nVisible
, long nSorted
)
349 maRowVisible
.back() = nVisible
;
350 maRowVisible
.push_back(-1);
352 maRowSorted
.back() = nSorted
;
353 maRowSorted
.push_back(-1);
356 void ScDPRunningTotalState::RemoveColIndex()
358 OSL_ENSURE(!maColVisible
.empty() && !maColSorted
.empty(), "ScDPRunningTotalState::RemoveColIndex: array is already empty!");
359 if (maColVisible
.size() >= 2)
361 maColVisible
.pop_back();
362 maColVisible
.back() = -1;
365 if (maColSorted
.size() >= 2)
367 maColSorted
.pop_back();
368 maColSorted
.back() = -1;
372 void ScDPRunningTotalState::RemoveRowIndex()
374 OSL_ENSURE(!maRowVisible
.empty() && !maRowSorted
.empty(), "ScDPRunningTotalState::RemoveRowIndex: array is already empty!");
375 if (maRowVisible
.size() >= 2)
377 maRowVisible
.pop_back();
378 maRowVisible
.back() = -1;
381 if (maRowSorted
.size() >= 2)
383 maRowSorted
.pop_back();
384 maRowSorted
.back() = -1;
388 // -----------------------------------------------------------------------
390 ScDPRelativePos::ScDPRelativePos( long nBase
, long nDir
) :
396 // -----------------------------------------------------------------------
398 void ScDPAggData::Update( const ScDPValue
& rNext
, ScSubTotalFunc eFunc
, const ScDPSubTotalState
& rSubState
)
400 if (nCount
<0) // error?
401 return; // nothing more...
403 if (rNext
.meType
== ScDPValue::Empty
)
406 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
&& rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
&&
407 rSubState
.eColForce
!= rSubState
.eRowForce
)
409 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eColForce
;
410 if ( rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eRowForce
;
412 if ( eFunc
== SUBTOTAL_FUNC_NONE
)
415 if ( eFunc
!= SUBTOTAL_FUNC_CNT2
) // CNT2 counts everything, incl. strings and errors
417 if (rNext
.meType
== ScDPValue::Error
)
419 nCount
= -1; // -1 for error (not for CNT2)
422 if (rNext
.meType
== ScDPValue::String
)
426 ++nCount
; // for all functions
430 case SUBTOTAL_FUNC_SUM
:
431 case SUBTOTAL_FUNC_AVE
:
432 if ( !SubTotal::SafePlus( fVal
, rNext
.mfValue
) )
433 nCount
= -1; // -1 for error
435 case SUBTOTAL_FUNC_PROD
:
436 if ( nCount
== 1 ) // copy first value (fVal is initialized to 0)
437 fVal
= rNext
.mfValue
;
438 else if ( !SubTotal::SafeMult( fVal
, rNext
.mfValue
) )
439 nCount
= -1; // -1 for error
441 case SUBTOTAL_FUNC_CNT
:
442 case SUBTOTAL_FUNC_CNT2
:
443 // nothing more than incrementing nCount
445 case SUBTOTAL_FUNC_MAX
:
446 if ( nCount
== 1 || rNext
.mfValue
> fVal
)
447 fVal
= rNext
.mfValue
;
449 case SUBTOTAL_FUNC_MIN
:
450 if ( nCount
== 1 || rNext
.mfValue
< fVal
)
451 fVal
= rNext
.mfValue
;
453 case SUBTOTAL_FUNC_STD
:
454 case SUBTOTAL_FUNC_STDP
:
455 case SUBTOTAL_FUNC_VAR
:
456 case SUBTOTAL_FUNC_VARP
:
458 // fAux is used to sum up squares
459 if ( !SubTotal::SafePlus( fVal
, rNext
.mfValue
) )
460 nCount
= -1; // -1 for error
461 double fAdd
= rNext
.mfValue
;
462 if ( !SubTotal::SafeMult( fAdd
, rNext
.mfValue
) ||
463 !SubTotal::SafePlus( fAux
, fAdd
) )
464 nCount
= -1; // -1 for error
468 OSL_FAIL("invalid function");
472 void ScDPAggData::Calculate( ScSubTotalFunc eFunc
, const ScDPSubTotalState
& rSubState
)
474 // calculate the original result
475 // (without reference value, used as the basis for reference value calculation)
477 // called several times at the cross-section of several subtotals - don't calculate twice then
478 if ( IsCalculated() )
481 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eColForce
;
482 if ( rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
) eFunc
= rSubState
.eRowForce
;
484 if ( eFunc
== SUBTOTAL_FUNC_NONE
) // this happens when there is no data dimension
486 nCount
= SC_DPAGG_RESULT_EMPTY
; // make sure there's a valid state for HasData etc.
490 // check the error conditions for the selected function
495 case SUBTOTAL_FUNC_SUM
:
496 case SUBTOTAL_FUNC_PROD
:
497 case SUBTOTAL_FUNC_CNT
:
498 case SUBTOTAL_FUNC_CNT2
:
499 bError
= ( nCount
< 0 ); // only real errors
502 case SUBTOTAL_FUNC_AVE
:
503 case SUBTOTAL_FUNC_MAX
:
504 case SUBTOTAL_FUNC_MIN
:
505 case SUBTOTAL_FUNC_STDP
:
506 case SUBTOTAL_FUNC_VARP
:
507 bError
= ( nCount
<= 0 ); // no data is an error
510 case SUBTOTAL_FUNC_STD
:
511 case SUBTOTAL_FUNC_VAR
:
512 bError
= ( nCount
< 2 ); // need at least 2 values
516 OSL_FAIL("invalid function");
519 // calculate the selected function
521 double fResult
= 0.0;
526 case SUBTOTAL_FUNC_MAX
:
527 case SUBTOTAL_FUNC_MIN
:
528 case SUBTOTAL_FUNC_SUM
:
529 case SUBTOTAL_FUNC_PROD
:
530 // different error conditions are handled above
534 case SUBTOTAL_FUNC_CNT
:
535 case SUBTOTAL_FUNC_CNT2
:
539 case SUBTOTAL_FUNC_AVE
:
541 fResult
= fVal
/ (double) nCount
;
544 //! use safe mul for fVal * fVal
546 case SUBTOTAL_FUNC_STD
:
548 fResult
= sqrt((fAux
- fVal
*fVal
/(double)(nCount
)) / (double)(nCount
-1));
550 case SUBTOTAL_FUNC_VAR
:
552 fResult
= (fAux
- fVal
*fVal
/(double)(nCount
)) / (double)(nCount
-1);
554 case SUBTOTAL_FUNC_STDP
:
556 fResult
= sqrt((fAux
- fVal
*fVal
/(double)(nCount
)) / (double)nCount
);
558 case SUBTOTAL_FUNC_VARP
:
560 fResult
= (fAux
- fVal
*fVal
/(double)(nCount
)) / (double)nCount
;
563 OSL_FAIL("invalid function");
567 bool bEmpty
= ( nCount
== 0 ); // no data
570 // Empty is checked first, so empty results are shown empty even for "average" etc.
571 // If these results should be treated as errors in reference value calculations,
572 // a separate state value (EMPTY_ERROR) is needed.
573 // Now, for compatibility, empty "average" results are counted as 0.
576 nCount
= SC_DPAGG_RESULT_EMPTY
;
578 nCount
= SC_DPAGG_RESULT_ERROR
;
580 nCount
= SC_DPAGG_RESULT_VALID
;
582 if ( bEmpty
|| bError
)
583 fResult
= 0.0; // default, in case the state is later modified
585 fVal
= fResult
; // used directly from now on
586 fAux
= 0.0; // used for running total or original result of reference value
589 bool ScDPAggData::IsCalculated() const
591 return ( nCount
<= SC_DPAGG_RESULT_EMPTY
);
594 double ScDPAggData::GetResult() const
596 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
598 return fVal
; // use calculated value
601 bool ScDPAggData::HasError() const
603 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
605 return ( nCount
== SC_DPAGG_RESULT_ERROR
);
608 bool ScDPAggData::HasData() const
610 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
612 return ( nCount
!= SC_DPAGG_RESULT_EMPTY
); // values or error
615 void ScDPAggData::SetResult( double fNew
)
617 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
619 fVal
= fNew
; // don't reset error flag
622 void ScDPAggData::SetError()
624 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
626 nCount
= SC_DPAGG_RESULT_ERROR
;
629 void ScDPAggData::SetEmpty( bool bSet
)
631 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
634 nCount
= SC_DPAGG_RESULT_EMPTY
;
636 nCount
= SC_DPAGG_RESULT_VALID
;
639 double ScDPAggData::GetAuxiliary() const
641 // after Calculate, fAux is used as auxiliary value for running totals and reference values
642 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
647 void ScDPAggData::SetAuxiliary( double fNew
)
649 // after Calculate, fAux is used as auxiliary value for running totals and reference values
650 OSL_ENSURE( IsCalculated(), "ScDPAggData not calculated" );
655 ScDPAggData
* ScDPAggData::GetChild()
658 pChild
= new ScDPAggData
;
662 void ScDPAggData::Reset()
666 nCount
= SC_DPAGG_EMPTY
;
671 #if DEBUG_PIVOT_TABLE
672 void ScDPAggData::Dump(int nIndent
) const
674 std::string
aIndent(nIndent
*2, ' ');
675 std::cout
<< aIndent
<< "* ";
677 std::cout
<< GetResult();
679 std::cout
<< "not calculated";
681 std::cout
<< " [val=" << fVal
<< "; aux=" << fAux
<< "; count=" << nCount
<< "]" << std::endl
;
685 // -----------------------------------------------------------------------
687 ScDPRowTotals::ScDPRowTotals() :
688 bIsInColRoot( false )
692 ScDPRowTotals::~ScDPRowTotals()
696 static ScDPAggData
* lcl_GetChildTotal( ScDPAggData
* pFirst
, long nMeasure
)
698 OSL_ENSURE( nMeasure
>= 0, "GetColTotal: no measure" );
700 ScDPAggData
* pAgg
= pFirst
;
701 long nSkip
= nMeasure
;
703 // subtotal settings are ignored - colum/row totals exist once per measure
705 for ( long nPos
=0; nPos
<nSkip
; nPos
++ )
706 pAgg
= pAgg
->GetChild(); // column total is constructed empty - children need to be created
708 if ( !pAgg
->IsCalculated() )
710 // for first use, simulate an empty calculation
711 ScDPSubTotalState aEmptyState
;
712 pAgg
->Calculate( SUBTOTAL_FUNC_SUM
, aEmptyState
);
718 ScDPAggData
* ScDPRowTotals::GetRowTotal( long nMeasure
)
720 return lcl_GetChildTotal( &aRowTotal
, nMeasure
);
723 ScDPAggData
* ScDPRowTotals::GetGrandTotal( long nMeasure
)
725 return lcl_GetChildTotal( &aGrandTotal
, nMeasure
);
728 // -----------------------------------------------------------------------
730 static ScSubTotalFunc
lcl_GetForceFunc( const ScDPLevel
* pLevel
, long nFuncNo
)
732 ScSubTotalFunc eRet
= SUBTOTAL_FUNC_NONE
;
735 //! direct access via ScDPLevel
737 uno::Sequence
<sheet::GeneralFunction
> aSeq
= pLevel
->getSubTotals();
738 long nSequence
= aSeq
.getLength();
739 if ( nSequence
&& aSeq
[0] != sheet::GeneralFunction_AUTO
)
741 // For manual subtotals, "automatic" is added as first function.
742 // ScDPResultMember::GetSubTotalCount adds to the count, here NONE has to be
743 // returned as the first function then.
745 --nFuncNo
; // keep NONE for first (check below), move the other entries
748 if ( nFuncNo
>= 0 && nFuncNo
< nSequence
)
750 sheet::GeneralFunction eUser
= aSeq
.getConstArray()[nFuncNo
];
751 if (eUser
!= sheet::GeneralFunction_AUTO
)
752 eRet
= ScDPUtil::toSubTotalFunc(eUser
);
758 // -----------------------------------------------------------------------
760 ScDPResultData::ScDPResultData( ScDPSource
& rSrc
) :
768 ScDPResultData::~ScDPResultData()
770 std::for_each(maDimMembers
.begin(), maDimMembers
.end(), ScDeleteObjectByPtr
<ResultMembers
>());
773 void ScDPResultData::SetMeasureData(
774 std::vector
<ScSubTotalFunc
>& rFunctions
, std::vector
<sheet::DataPilotFieldReference
>& rRefs
,
775 std::vector
<sal_uInt16
>& rRefOrient
, std::vector
<OUString
>& rNames
)
777 // We need to have at least one measure data at all times.
779 maMeasureFuncs
.swap(rFunctions
);
780 if (maMeasureFuncs
.empty())
781 maMeasureFuncs
.push_back(SUBTOTAL_FUNC_NONE
);
783 maMeasureRefs
.swap(rRefs
);
784 if (maMeasureRefs
.empty())
785 maMeasureRefs
.push_back(sheet::DataPilotFieldReference()); // default ctor is ok.
787 maMeasureRefOrients
.swap(rRefOrient
);
788 if (maMeasureRefOrients
.empty())
789 maMeasureRefOrients
.push_back(sheet::DataPilotFieldOrientation_HIDDEN
);
791 maMeasureNames
.swap(rNames
);
792 if (maMeasureNames
.empty())
793 maMeasureNames
.push_back(ScGlobal::GetRscString(STR_EMPTYDATA
));
796 void ScDPResultData::SetDataLayoutOrientation( sal_uInt16 nOrient
)
798 bDataAtCol
= ( nOrient
== sheet::DataPilotFieldOrientation_COLUMN
);
799 bDataAtRow
= ( nOrient
== sheet::DataPilotFieldOrientation_ROW
);
802 void ScDPResultData::SetLateInit( bool bSet
)
807 long ScDPResultData::GetColStartMeasure() const
809 if (maMeasureFuncs
.size() == 1)
812 return bDataAtCol
? SC_DPMEASURE_ALL
: SC_DPMEASURE_ANY
;
815 long ScDPResultData::GetRowStartMeasure() const
817 if (maMeasureFuncs
.size() == 1)
820 return bDataAtRow
? SC_DPMEASURE_ALL
: SC_DPMEASURE_ANY
;
823 ScSubTotalFunc
ScDPResultData::GetMeasureFunction(long nMeasure
) const
825 OSL_ENSURE((size_t) nMeasure
< maMeasureFuncs
.size(), "bumm");
826 return maMeasureFuncs
[nMeasure
];
829 const sheet::DataPilotFieldReference
& ScDPResultData::GetMeasureRefVal(long nMeasure
) const
831 OSL_ENSURE((size_t) nMeasure
< maMeasureRefs
.size(), "bumm");
832 return maMeasureRefs
[nMeasure
];
835 sal_uInt16
ScDPResultData::GetMeasureRefOrient(long nMeasure
) const
837 OSL_ENSURE((size_t) nMeasure
< maMeasureRefOrients
.size(), "bumm");
838 return maMeasureRefOrients
[nMeasure
];
841 OUString
ScDPResultData::GetMeasureString(long nMeasure
, bool bForce
, ScSubTotalFunc eForceFunc
, bool& rbTotalResult
) const
843 // with bForce==true, return function instead of "result" for single measure
844 // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
845 rbTotalResult
= false;
846 if ( nMeasure
< 0 || (maMeasureFuncs
.size() == 1 && !bForce
&& eForceFunc
== SUBTOTAL_FUNC_NONE
) )
848 // for user-specified subtotal function with all measures,
849 // display only function name
850 if ( eForceFunc
!= SUBTOTAL_FUNC_NONE
)
851 return ScGlobal::GetRscString(nFuncStrIds
[eForceFunc
]);
853 rbTotalResult
= true;
854 return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS
);
858 OSL_ENSURE((size_t) nMeasure
< maMeasureFuncs
.size(), "bumm");
859 const ScDPDimension
* pDataDim
= mrSource
.GetDataDimension(nMeasure
);
862 const OUString
* pLayoutName
= pDataDim
->GetLayoutName();
867 ScSubTotalFunc eFunc
= ( eForceFunc
== SUBTOTAL_FUNC_NONE
) ?
868 GetMeasureFunction(nMeasure
) : eForceFunc
;
870 return ScDPUtil::getDisplayedMeasureName(maMeasureNames
[nMeasure
], eFunc
);
874 OUString
ScDPResultData::GetMeasureDimensionName(long nMeasure
) const
878 OSL_FAIL("GetMeasureDimensionName: negative");
879 return OUString("***");
882 return mrSource
.GetDataDimName(nMeasure
);
885 bool ScDPResultData::IsBaseForGroup( long nDim
) const
887 return mrSource
.GetData()->IsBaseForGroup(nDim
);
890 long ScDPResultData::GetGroupBase( long nGroupDim
) const
892 return mrSource
.GetData()->GetGroupBase(nGroupDim
);
895 bool ScDPResultData::IsNumOrDateGroup( long nDim
) const
897 return mrSource
.GetData()->IsNumOrDateGroup(nDim
);
900 bool ScDPResultData::IsInGroup( SCROW nGroupDataId
, long nGroupIndex
,
901 const ScDPItemData
& rBaseData
, long nBaseIndex
) const
903 const ScDPItemData
* pGroupData
= mrSource
.GetItemDataById(nGroupIndex
, nGroupDataId
);
905 return mrSource
.GetData()->IsInGroup(*pGroupData
, nGroupIndex
, rBaseData
, nBaseIndex
);
910 bool ScDPResultData::HasCommonElement( SCROW nFirstDataId
, long nFirstIndex
,
911 const ScDPItemData
& rSecondData
, long nSecondIndex
) const
913 const ScDPItemData
* pFirstData
= mrSource
.GetItemDataById(nFirstIndex
, nFirstDataId
);
915 return mrSource
.GetData()->HasCommonElement(*pFirstData
, nFirstIndex
, rSecondData
, nSecondIndex
);
920 const ScDPSource
& ScDPResultData::GetSource() const
925 ResultMembers
* ScDPResultData::GetDimResultMembers(long nDim
, ScDPDimension
* pDim
, ScDPLevel
* pLevel
) const
927 if (nDim
< static_cast<long>(maDimMembers
.size()) && maDimMembers
[nDim
])
928 return maDimMembers
[nDim
];
930 maDimMembers
.resize(nDim
+1, NULL
);
932 ResultMembers
* pResultMembers
= new ResultMembers();
933 // global order is used to initialize aMembers, so it doesn't have to be looked at later
934 const ScMemberSortOrder
& rGlobalOrder
= pLevel
->GetGlobalOrder();
936 ScDPMembers
* pMembers
= pLevel
->GetMembersObject();
937 long nMembCount
= pMembers
->getCount();
938 for (long i
= 0; i
< nMembCount
; ++i
)
940 long nSorted
= rGlobalOrder
.empty() ? i
: rGlobalOrder
[i
];
941 ScDPMember
* pMember
= pMembers
->getByIndex(nSorted
);
942 if (!pResultMembers
->FindMember(pMember
->GetItemDataId()))
944 ScDPParentDimData
* pNew
= new ScDPParentDimData(i
, pDim
, pLevel
, pMember
);
945 pResultMembers
->InsertMember(pNew
);
949 maDimMembers
[nDim
] = pResultMembers
;
950 return maDimMembers
[nDim
];
953 // -----------------------------------------------------------------------
956 ScDPResultMember::ScDPResultMember(
957 const ScDPResultData
* pData
, const ScDPParentDimData
& rParentDimData
, bool bForceSub
) :
958 pResultData( pData
),
959 aParentDimData( rParentDimData
),
960 pChildDimension( NULL
),
962 bHasElements( false ),
963 bForceSubTotal( bForceSub
),
964 bHasHiddenDetails( false ),
965 bInitialized( false ),
966 bAutoHidden( false ),
969 // pParentLevel/pMemberDesc is 0 for root members
972 ScDPResultMember::ScDPResultMember(
973 const ScDPResultData
* pData
, bool bForceSub
) :
974 pResultData( pData
),
975 pChildDimension( NULL
),
977 bHasElements( false ),
978 bForceSubTotal( bForceSub
),
979 bHasHiddenDetails( false ),
980 bInitialized( false ),
981 bAutoHidden( false ),
985 ScDPResultMember::~ScDPResultMember()
987 delete pChildDimension
;
991 OUString
ScDPResultMember::GetName() const
993 const ScDPMember
* pMemberDesc
= GetDPMember();
995 return pMemberDesc
->GetNameStr();
997 return ScGlobal::GetRscString(STR_PIVOT_TOTAL
); // root member
1000 OUString
ScDPResultMember::GetDisplayName() const
1002 const ScDPMember
* pDPMember
= GetDPMember();
1007 pDPMember
->FillItemData(aItem
);
1008 if (aParentDimData
.mpParentDim
)
1010 long nDim
= aParentDimData
.mpParentDim
->GetDimension();
1011 return pResultData
->GetSource().GetData()->GetFormattedString(nDim
, aItem
);
1014 return aItem
.GetString();
1017 void ScDPResultMember::FillItemData( ScDPItemData
& rData
) const
1019 const ScDPMember
* pMemberDesc
= GetDPMember();
1021 pMemberDesc
->FillItemData( rData
);
1023 rData
.SetString( ScGlobal::GetRscString(STR_PIVOT_TOTAL
) ); // root member
1026 bool ScDPResultMember::IsNamedItem( SCROW nIndex
) const
1028 //! store ScDPMember pointer instead of ScDPMember ???
1029 const ScDPMember
* pMemberDesc
= GetDPMember();
1031 return pMemberDesc
->IsNamedItem(nIndex
);
1035 bool ScDPResultMember::IsValidEntry( const vector
< SCROW
>& aMembers
) const
1040 const ScDPResultDimension
* pChildDim
= GetChildDimension();
1043 if (aMembers
.size() < 2)
1046 vector
<SCROW
>::const_iterator itr
= aMembers
.begin();
1047 vector
<SCROW
> aChildMembers(++itr
, aMembers
.end());
1048 return pChildDim
->IsValidEntry(aChildMembers
);
1054 void ScDPResultMember::InitFrom( const vector
<ScDPDimension
*>& ppDim
, const vector
<ScDPLevel
*>& ppLev
,
1055 size_t nPos
, ScDPInitState
& rInitState
,
1058 // with LateInit, initialize only those members that have data
1059 if ( pResultData
->IsLateInit() )
1062 bInitialized
= true;
1064 if (nPos
>= ppDim
.size())
1067 // skip child dimension if details are not shown
1068 if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1070 // Show DataLayout dimention
1072 while ( nPos
< ppDim
.size() )
1074 if ( ppDim
[nPos
] ->getIsDataLayoutDimension() )
1076 if ( !pChildDimension
)
1077 pChildDimension
= new ScDPResultDimension( pResultData
);
1078 pChildDimension
->InitFrom( ppDim
, ppLev
, nPos
, rInitState
, false );
1087 bHasHiddenDetails
= true; // only if there is a next dimension
1093 pChildDimension
= new ScDPResultDimension( pResultData
);
1094 pChildDimension
->InitFrom(ppDim
, ppLev
, nPos
, rInitState
, true);
1098 void ScDPResultMember::LateInitFrom(
1099 LateInitParams
& rParams
, const vector
<SCROW
>& pItemData
, size_t nPos
, ScDPInitState
& rInitState
)
1101 // without LateInit, everything has already been initialized
1102 if ( !pResultData
->IsLateInit() )
1105 bInitialized
= true;
1107 if ( rParams
.IsEnd( nPos
) /*nPos >= ppDim.size()*/)
1108 // No next dimension. Bail out.
1111 // skip child dimension if details are not shown
1112 if ( GetDPMember() && !GetDPMember()->getShowDetails() )
1114 // Show DataLayout dimention
1116 while ( !rParams
.IsEnd( nPos
) )
1118 if ( rParams
.GetDim( nPos
) ->getIsDataLayoutDimension() )
1120 if ( !pChildDimension
)
1121 pChildDimension
= new ScDPResultDimension( pResultData
);
1123 // #i111462# reset InitChild flag only for this child dimension's LateInitFrom call,
1124 // not for following members of parent dimensions
1125 bool bWasInitChild
= rParams
.GetInitChild();
1126 rParams
.SetInitChild( false );
1127 pChildDimension
->LateInitFrom( rParams
, pItemData
, nPos
, rInitState
);
1128 rParams
.SetInitChild( bWasInitChild
);
1137 bHasHiddenDetails
= true; // only if there is a next dimension
1141 // LateInitFrom is called several times...
1142 if ( rParams
.GetInitChild() )
1144 if ( !pChildDimension
)
1145 pChildDimension
= new ScDPResultDimension( pResultData
);
1146 pChildDimension
->LateInitFrom( rParams
, pItemData
, nPos
, rInitState
);
1150 bool ScDPResultMember::IsSubTotalInTitle(long nMeasure
) const
1153 if ( pChildDimension
&& /*pParentLevel*/GetParentLevel() &&
1154 /*pParentLevel*/GetParentLevel()->IsOutlineLayout() && /*pParentLevel*/GetParentLevel()->IsSubtotalsAtTop() )
1157 long nSubTotals
= GetSubTotalCount( &nUserSubStart
);
1158 nSubTotals
-= nUserSubStart
; // visible count
1161 if ( nMeasure
== SC_DPMEASURE_ALL
)
1162 nSubTotals
*= pResultData
->GetMeasureCount(); // number of subtotals that will be inserted
1164 // only a single subtotal row will be shown in the outline title row
1165 if ( nSubTotals
== 1 )
1172 long ScDPResultMember::GetSize(long nMeasure
) const
1176 const ScDPLevel
* pParentLevel
= GetParentLevel();
1177 long nExtraSpace
= 0;
1178 if ( pParentLevel
&& pParentLevel
->IsAddEmpty() )
1181 if ( pChildDimension
)
1183 // outline layout takes up an extra row for the title only if subtotals aren't shown in that row
1184 if ( pParentLevel
&& pParentLevel
->IsOutlineLayout() && !IsSubTotalInTitle( nMeasure
) )
1187 long nSize
= pChildDimension
->GetSize(nMeasure
);
1189 long nUserSubCount
= GetSubTotalCount( &nUserSubStart
);
1190 nUserSubCount
-= nUserSubStart
; // for output size, use visible count
1191 if ( nUserSubCount
)
1193 if ( nMeasure
== SC_DPMEASURE_ALL
)
1194 nSize
+= pResultData
->GetMeasureCount() * nUserSubCount
;
1196 nSize
+= nUserSubCount
;
1198 return nSize
+ nExtraSpace
;
1202 if ( nMeasure
== SC_DPMEASURE_ALL
)
1203 return pResultData
->GetMeasureCount() + nExtraSpace
;
1205 return 1 + nExtraSpace
;
1209 bool ScDPResultMember::IsVisible() const
1220 // not initialized -> shouldn't be there at all
1221 // (allocated only to preserve ordering)
1222 const ScDPLevel
* pParentLevel
= GetParentLevel();
1224 return (pParentLevel
&& pParentLevel
->getShowEmpty());
1227 bool ScDPResultMember::IsValid() const
1229 // non-Valid members are left out of calculation
1231 // was member set no invisible at the DataPilotSource?
1232 const ScDPMember
* pMemberDesc
= GetDPMember();
1233 if ( pMemberDesc
&& !pMemberDesc
->isVisible() )
1242 bool ScDPResultMember::HasHiddenDetails() const
1244 // bHasHiddenDetails is set only if the "show details" flag is off,
1245 // and there was a child dimension to skip
1247 return bHasHiddenDetails
;
1250 long ScDPResultMember::GetSubTotalCount( long* pUserSubStart
) const
1252 if ( pUserSubStart
)
1253 *pUserSubStart
= 0; // default
1255 const ScDPLevel
* pParentLevel
= GetParentLevel();
1257 if ( bForceSubTotal
) // set if needed for root members
1258 return 1; // grand total is always "automatic"
1259 else if ( pParentLevel
)
1261 //! direct access via ScDPLevel
1263 uno::Sequence
<sheet::GeneralFunction
> aSeq
= pParentLevel
->getSubTotals();
1264 long nSequence
= aSeq
.getLength();
1265 if ( nSequence
&& aSeq
[0] != sheet::GeneralFunction_AUTO
)
1267 // For manual subtotals, always add "automatic" as first function
1268 // (used for calculation, but not for display, needed for sorting, see lcl_GetForceFunc)
1271 if ( pUserSubStart
)
1272 *pUserSubStart
= 1; // visible subtotals start at 1
1280 void ScDPResultMember::ProcessData( const vector
< SCROW
>& aChildMembers
, const ScDPResultDimension
* pDataDim
,
1281 const vector
< SCROW
>& aDataMembers
, const vector
<ScDPValue
>& aValues
)
1285 if (pChildDimension
)
1286 pChildDimension
->ProcessData( aChildMembers
, pDataDim
, aDataMembers
, aValues
);
1290 pDataRoot
= new ScDPDataMember( pResultData
, NULL
);
1292 pDataRoot
->InitFrom( pDataDim
); // recursive
1295 ScDPSubTotalState aSubState
; // initial state
1297 long nUserSubCount
= GetSubTotalCount();
1299 // Calculate at least automatic if no subtotals are selected,
1300 // show only own values if there's no child dimension (innermost).
1301 if ( !nUserSubCount
|| !pChildDimension
)
1304 const ScDPLevel
* pParentLevel
= GetParentLevel();
1306 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
1308 // #i68338# if nUserSubCount is 1 (automatic only), don't set nRowSubTotalFunc
1309 if ( pChildDimension
&& nUserSubCount
> 1 )
1311 aSubState
.nRowSubTotalFunc
= nUserPos
;
1312 aSubState
.eRowForce
= lcl_GetForceFunc( pParentLevel
, nUserPos
);
1315 pDataRoot
->ProcessData( aDataMembers
, aValues
, aSubState
);
1320 * Parse subtotal string and replace all occurrences of '?' with the caption
1321 * string. Do ensure that escaped characters are not translated.
1323 static OUString
lcl_parseSubtotalName(const OUString
& rSubStr
, const OUString
& rCaption
)
1325 OUStringBuffer aNewStr
;
1326 sal_Int32 n
= rSubStr
.getLength();
1327 bool bEscaped
= false;
1328 for (sal_Int32 i
= 0; i
< n
; ++i
)
1330 sal_Unicode c
= rSubStr
[i
];
1331 if (!bEscaped
&& c
== '\\')
1337 if (!bEscaped
&& c
== '?')
1338 aNewStr
.append(rCaption
);
1343 return aNewStr
.makeStringAndClear();
1346 void ScDPResultMember::FillMemberResults(
1347 uno::Sequence
<sheet::MemberResult
>* pSequences
, long& rPos
, long nMeasure
, bool bRoot
,
1348 const OUString
* pMemberName
, const OUString
* pMemberCaption
)
1350 // IsVisible() test is in ScDPResultDimension::FillMemberResults
1351 // (not on data layout dimension)
1353 if (!pSequences
->getLength())
1354 // empty sequence. Bail out.
1357 long nSize
= GetSize(nMeasure
);
1358 sheet::MemberResult
* pArray
= pSequences
->getArray();
1359 OSL_ENSURE( rPos
+nSize
<= pSequences
->getLength(), "bumm" );
1361 bool bIsNumeric
= false;
1363 if ( pMemberName
) // if pMemberName != NULL, use instead of real member name
1365 aName
= *pMemberName
;
1369 ScDPItemData aItemData
;
1370 FillItemData( aItemData
);
1371 if (aParentDimData
.mpParentDim
)
1373 long nDim
= aParentDimData
.mpParentDim
->GetDimension();
1374 aName
= pResultData
->GetSource().GetData()->GetFormattedString(nDim
, aItemData
);
1379 const ScDPMember
* pMem
= GetDPMember();
1381 nDim
= pMem
->GetDim();
1382 aName
= pResultData
->GetSource().GetData()->GetFormattedString(nDim
, aItemData
);
1385 ScDPItemData::Type eType
= aItemData
.GetType();
1386 bIsNumeric
= eType
== ScDPItemData::Value
|| ScDPItemData::GroupValue
;
1389 const ScDPDimension
* pParentDim
= GetParentDim();
1390 if ( bIsNumeric
&& pParentDim
&& pResultData
->IsNumOrDateGroup( pParentDim
->GetDimension() ) )
1392 // Numeric group dimensions use numeric entries for proper sorting,
1393 // but the group titles must be output as text.
1397 OUString aCaption
= aName
;
1398 const ScDPMember
* pMemberDesc
= GetDPMember();
1401 const OUString
* pLayoutName
= pMemberDesc
->GetLayoutName();
1404 aCaption
= *pLayoutName
;
1405 bIsNumeric
= false; // layout name is always non-numeric.
1409 if ( pMemberCaption
) // use pMemberCaption if != NULL
1410 aCaption
= *pMemberCaption
;
1411 if (aCaption
.isEmpty())
1412 aCaption
= ScGlobal::GetRscString(STR_EMPTYDATA
);
1415 pArray
[rPos
].Flags
|= sheet::MemberResultFlags::NUMERIC
;
1417 pArray
[rPos
].Flags
&= ~sheet::MemberResultFlags::NUMERIC
;
1419 if ( nSize
&& !bRoot
) // root is overwritten by first dimension
1421 pArray
[rPos
].Name
= aName
;
1422 pArray
[rPos
].Caption
= aCaption
;
1423 pArray
[rPos
].Flags
|= sheet::MemberResultFlags::HASMEMBER
;
1425 // set "continue" flag (removed for subtotals later)
1426 for (long i
=1; i
<nSize
; i
++)
1427 pArray
[rPos
+i
].Flags
|= sheet::MemberResultFlags::CONTINUE
;
1430 const ScDPLevel
* pParentLevel
= GetParentLevel();
1431 long nExtraSpace
= 0;
1432 if ( pParentLevel
&& pParentLevel
->IsAddEmpty() )
1435 bool bTitleLine
= false;
1436 if ( pParentLevel
&& pParentLevel
->IsOutlineLayout() )
1439 // if the subtotals are shown at the top (title row) in outline layout,
1440 // no extra row for the subtotals is needed
1441 bool bSubTotalInTitle
= IsSubTotalInTitle( nMeasure
);
1443 bool bHasChild
= ( pChildDimension
!= NULL
);
1446 if ( bTitleLine
) // in tabular layout the title is on a separate row
1447 ++rPos
; // -> fill child dimension one row below
1449 if (bRoot
) // same sequence for root member
1450 pChildDimension
->FillMemberResults( pSequences
, rPos
, nMeasure
);
1452 pChildDimension
->FillMemberResults( pSequences
+ nMemberStep
/*1*/, rPos
, nMeasure
);
1454 if ( bTitleLine
) // title row is included in GetSize, so the following
1455 --rPos
; // positions are calculated with the normal values
1461 long nUserSubCount
= GetSubTotalCount(&nUserSubStart
);
1462 if ( nUserSubCount
&& pChildDimension
&& !bSubTotalInTitle
)
1464 long nMemberMeasure
= nMeasure
;
1465 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1467 rPos
-= nSubSize
* (nUserSubCount
- nUserSubStart
); // GetSize includes space for SubTotal
1468 rPos
-= nExtraSpace
; // GetSize includes the empty line
1470 for (long nUserPos
=nUserSubStart
; nUserPos
<nUserSubCount
; nUserPos
++)
1472 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
1474 if ( nMeasure
== SC_DPMEASURE_ALL
)
1475 nMemberMeasure
= nSubCount
;
1477 ScSubTotalFunc eForce
= SUBTOTAL_FUNC_NONE
;
1479 eForce
= lcl_GetForceFunc( pParentLevel
, nUserPos
);
1481 bool bTotalResult
= false;
1482 OUString aSubStr
= aCaption
+ " " + pResultData
->GetMeasureString(nMemberMeasure
, false, eForce
, bTotalResult
);
1488 // single data field layout.
1489 const OUString
* pSubtotalName
= pParentDim
->GetSubtotalName();
1491 aSubStr
= lcl_parseSubtotalName(*pSubtotalName
, aCaption
);
1492 pArray
[rPos
].Flags
&= ~sheet::MemberResultFlags::GRANDTOTAL
;
1496 // root member - subtotal (grand total?) for multi-data field layout.
1497 const OUString
* pGrandTotalName
= pResultData
->GetSource().GetGrandTotalName();
1498 if (pGrandTotalName
)
1499 aSubStr
= *pGrandTotalName
;
1500 pArray
[rPos
].Flags
|= sheet::MemberResultFlags::GRANDTOTAL
;
1504 pArray
[rPos
].Name
= aName
;
1505 pArray
[rPos
].Caption
= aSubStr
;
1506 pArray
[rPos
].Flags
= ( pArray
[rPos
].Flags
|
1507 ( sheet::MemberResultFlags::HASMEMBER
| sheet::MemberResultFlags::SUBTOTAL
) ) &
1508 ~sheet::MemberResultFlags::CONTINUE
;
1510 if ( nMeasure
== SC_DPMEASURE_ALL
)
1512 // data layout dimension is (direct/indirect) child of this.
1513 // data layout dimension must have name for all entries.
1515 uno::Sequence
<sheet::MemberResult
>* pLayoutSeq
= pSequences
;
1518 ScDPResultDimension
* pLayoutDim
= pChildDimension
;
1519 while ( pLayoutDim
&& !pLayoutDim
->IsDataLayout() )
1521 pLayoutDim
= pLayoutDim
->GetFirstChildDimension();
1526 sheet::MemberResult
* pLayoutArray
= pLayoutSeq
->getArray();
1527 pLayoutArray
[rPos
].Name
= pResultData
->GetMeasureDimensionName(nMemberMeasure
);
1535 rPos
+= nExtraSpace
; // add again (subtracted above)
1539 void ScDPResultMember::FillDataResults(
1540 const ScDPResultMember
* pRefMember
,
1541 ScDPResultFilterContext
& rFilterCxt
, uno::Sequence
<uno::Sequence
<sheet::DataResult
> >& rSequence
,
1542 long nMeasure
) const
1544 boost::scoped_ptr
<FilterStack
> pFilterStack
;
1545 const ScDPMember
* pDPMember
= GetDPMember();
1548 // Root result has no corresponding DP member. Only take the non-root results.
1549 OUString aMemStr
= GetDisplayName();
1550 pFilterStack
.reset(new FilterStack(rFilterCxt
.maFilters
));
1551 pFilterStack
->pushDimValue(aMemStr
);
1554 // IsVisible() test is in ScDPResultDimension::FillDataResults
1555 // (not on data layout dimension)
1556 const ScDPLevel
* pParentLevel
= GetParentLevel();
1557 long nStartRow
= rFilterCxt
.mnRow
;
1559 long nExtraSpace
= 0;
1560 if ( pParentLevel
&& pParentLevel
->IsAddEmpty() )
1563 bool bTitleLine
= false;
1564 if ( pParentLevel
&& pParentLevel
->IsOutlineLayout() )
1567 bool bSubTotalInTitle
= IsSubTotalInTitle( nMeasure
);
1569 bool bHasChild
= ( pChildDimension
!= NULL
);
1572 if ( bTitleLine
) // in tabular layout the title is on a separate row
1573 ++rFilterCxt
.mnRow
; // -> fill child dimension one row below
1575 long nOldRow
= rFilterCxt
.mnRow
;
1576 pChildDimension
->FillDataResults(pRefMember
, rFilterCxt
, rSequence
, nMeasure
);
1577 rFilterCxt
.mnRow
= nOldRow
; // Revert to the original row before the call.
1579 rFilterCxt
.mnRow
+= GetSize( nMeasure
);
1581 if ( bTitleLine
) // title row is included in GetSize, so the following
1582 --rFilterCxt
.mnRow
; // positions are calculated with the normal values
1586 long nUserSubCount
= GetSubTotalCount(&nUserSubStart
);
1587 if ( nUserSubCount
|| !bHasChild
)
1589 // Calculate at least automatic if no subtotals are selected,
1590 // show only own values if there's no child dimension (innermost).
1591 if ( !nUserSubCount
|| !bHasChild
)
1597 long nMemberMeasure
= nMeasure
;
1598 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1601 rFilterCxt
.mnRow
-= nSubSize
* ( nUserSubCount
- nUserSubStart
); // GetSize includes space for SubTotal
1602 rFilterCxt
.mnRow
-= nExtraSpace
; // GetSize includes the empty line
1605 long nMoveSubTotal
= 0;
1606 if ( bSubTotalInTitle
)
1608 nMoveSubTotal
= rFilterCxt
.mnRow
- nStartRow
; // force to first (title) row
1609 rFilterCxt
.mnRow
= nStartRow
;
1614 ScDPSubTotalState aSubState
; // initial state
1616 for (long nUserPos
=nUserSubStart
; nUserPos
<nUserSubCount
; nUserPos
++)
1618 if ( bHasChild
&& nUserSubCount
> 1 )
1620 aSubState
.nRowSubTotalFunc
= nUserPos
;
1621 aSubState
.eRowForce
= lcl_GetForceFunc( /*pParentLevel*/GetParentLevel() , nUserPos
);
1624 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
1626 if ( nMeasure
== SC_DPMEASURE_ALL
)
1627 nMemberMeasure
= nSubCount
;
1628 else if ( pResultData
->GetColStartMeasure() == SC_DPMEASURE_ALL
)
1629 nMemberMeasure
= SC_DPMEASURE_ALL
;
1631 OSL_ENSURE( rFilterCxt
.mnRow
< rSequence
.getLength(), "bumm" );
1632 uno::Sequence
<sheet::DataResult
>& rSubSeq
= rSequence
.getArray()[rFilterCxt
.mnRow
];
1633 rFilterCxt
.mnCol
= 0;
1634 if (pRefMember
->IsVisible())
1635 pDataRoot
->FillDataRow(pRefMember
, rFilterCxt
, rSubSeq
, nMemberMeasure
, bHasChild
, aSubState
);
1637 rFilterCxt
.mnRow
+= 1;
1642 rFilterCxt
.mnRow
+= nSubSize
* ( nUserSubCount
- nUserSubStart
); // empty rows occur when ShowEmpty is true
1644 // add extra space again if subtracted from GetSize above,
1645 // add to own size if no children
1646 rFilterCxt
.mnRow
+= nExtraSpace
;
1647 rFilterCxt
.mnRow
+= nMoveSubTotal
;
1651 void ScDPResultMember::UpdateDataResults( const ScDPResultMember
* pRefMember
, long nMeasure
) const
1653 // IsVisible() test is in ScDPResultDimension::FillDataResults
1654 // (not on data layout dimension)
1656 bool bHasChild
= ( pChildDimension
!= NULL
);
1658 long nUserSubCount
= GetSubTotalCount();
1660 // process subtotals even if not shown
1662 // Calculate at least automatic if no subtotals are selected,
1663 // show only own values if there's no child dimension (innermost).
1664 if (!nUserSubCount
|| !bHasChild
)
1667 long nMemberMeasure
= nMeasure
;
1668 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1672 ScDPSubTotalState aSubState
; // initial state
1674 for (long nUserPos
= 0; nUserPos
< nUserSubCount
; ++nUserPos
) // including hidden "automatic"
1676 if (bHasChild
&& nUserSubCount
> 1)
1678 aSubState
.nRowSubTotalFunc
= nUserPos
;
1679 aSubState
.eRowForce
= lcl_GetForceFunc(GetParentLevel(), nUserPos
);
1682 for (long nSubCount
= 0; nSubCount
< nSubSize
; ++nSubCount
)
1684 if (nMeasure
== SC_DPMEASURE_ALL
)
1685 nMemberMeasure
= nSubCount
;
1686 else if (pResultData
->GetColStartMeasure() == SC_DPMEASURE_ALL
)
1687 nMemberMeasure
= SC_DPMEASURE_ALL
;
1689 pDataRoot
->UpdateDataRow(pRefMember
, nMemberMeasure
, bHasChild
, aSubState
);
1694 if (bHasChild
) // child dimension must be processed last, so the column total is known
1696 pChildDimension
->UpdateDataResults( pRefMember
, nMeasure
);
1700 void ScDPResultMember::SortMembers( ScDPResultMember
* pRefMember
)
1702 bool bHasChild
= ( pChildDimension
!= NULL
);
1704 pChildDimension
->SortMembers( pRefMember
); // sorting is done at the dimension
1706 if ( IsRoot() && pDataRoot
)
1708 // use the row root member to sort columns
1709 // sub total count is always 1
1711 pDataRoot
->SortMembers( pRefMember
);
1715 void ScDPResultMember::DoAutoShow( ScDPResultMember
* pRefMember
)
1717 bool bHasChild
= ( pChildDimension
!= NULL
);
1719 pChildDimension
->DoAutoShow( pRefMember
); // sorting is done at the dimension
1721 if ( IsRoot()&& pDataRoot
)
1723 // use the row root member to sort columns
1724 // sub total count is always 1
1726 pDataRoot
->DoAutoShow( pRefMember
);
1730 void ScDPResultMember::ResetResults()
1733 pDataRoot
->ResetResults();
1735 if (pChildDimension
)
1736 pChildDimension
->ResetResults();
1739 void ScDPResultMember::UpdateRunningTotals( const ScDPResultMember
* pRefMember
, long nMeasure
,
1740 ScDPRunningTotalState
& rRunning
, ScDPRowTotals
& rTotals
) const
1742 // IsVisible() test is in ScDPResultDimension::FillDataResults
1743 // (not on data layout dimension)
1745 rTotals
.SetInColRoot( IsRoot() );
1747 bool bHasChild
= ( pChildDimension
!= NULL
);
1749 long nUserSubCount
= GetSubTotalCount();
1750 //if ( nUserSubCount || !bHasChild )
1752 // Calculate at least automatic if no subtotals are selected,
1753 // show only own values if there's no child dimension (innermost).
1754 if ( !nUserSubCount
|| !bHasChild
)
1757 long nMemberMeasure
= nMeasure
;
1758 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
1762 ScDPSubTotalState aSubState
; // initial state
1764 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
1766 if ( bHasChild
&& nUserSubCount
> 1 )
1768 aSubState
.nRowSubTotalFunc
= nUserPos
;
1769 aSubState
.eRowForce
= lcl_GetForceFunc(GetParentLevel(), nUserPos
);
1772 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
1774 if ( nMeasure
== SC_DPMEASURE_ALL
)
1775 nMemberMeasure
= nSubCount
;
1776 else if ( pResultData
->GetColStartMeasure() == SC_DPMEASURE_ALL
)
1777 nMemberMeasure
= SC_DPMEASURE_ALL
;
1779 if (pRefMember
->IsVisible())
1780 pDataRoot
->UpdateRunningTotals(
1781 pRefMember
, nMemberMeasure
, bHasChild
, aSubState
, rRunning
, rTotals
, *this);
1787 if (bHasChild
) // child dimension must be processed last, so the column total is known
1789 pChildDimension
->UpdateRunningTotals( pRefMember
, nMeasure
, rRunning
, rTotals
);
1793 #if DEBUG_PIVOT_TABLE
1794 void ScDPResultMember::DumpState( const ScDPResultMember
* pRefMember
, ScDocument
* pDoc
, ScAddress
& rPos
) const
1796 lcl_DumpRow( OUString("ScDPResultMember"), GetName(), NULL
, pDoc
, rPos
);
1797 SCROW nStartRow
= rPos
.Row();
1800 pDataRoot
->DumpState( pRefMember
, pDoc
, rPos
);
1802 if (pChildDimension
)
1803 pChildDimension
->DumpState( pRefMember
, pDoc
, rPos
);
1805 lcl_Indent( pDoc
, nStartRow
, rPos
);
1808 void ScDPResultMember::Dump(int nIndent
) const
1810 std::string
aIndent(nIndent
*2, ' ');
1811 std::cout
<< aIndent
<< "-- result member '" << GetName() << "'" << std::endl
;
1813 std::cout
<< aIndent
<< " column totals" << std::endl
;
1814 for (const ScDPAggData
* p
= &aColTotal
; p
; p
= p
->GetExistingChild())
1817 if (pChildDimension
)
1818 pChildDimension
->Dump(nIndent
+1);
1822 std::cout
<< aIndent
<< " data root" << std::endl
;
1823 pDataRoot
->Dump(nIndent
+1);
1828 ScDPAggData
* ScDPResultMember::GetColTotal( long nMeasure
) const
1830 return lcl_GetChildTotal( const_cast<ScDPAggData
*>(&aColTotal
), nMeasure
);
1833 void ScDPResultMember::FillVisibilityData(ScDPResultVisibilityData
& rData
) const
1835 if (pChildDimension
)
1836 pChildDimension
->FillVisibilityData(rData
);
1839 // -----------------------------------------------------------------------
1841 ScDPDataMember::ScDPDataMember( const ScDPResultData
* pData
, const ScDPResultMember
* pRes
) :
1842 pResultData( pData
),
1843 pResultMember( pRes
),
1844 pChildDimension( NULL
)
1846 // pResultMember is 0 for root members
1849 ScDPDataMember::~ScDPDataMember()
1851 delete pChildDimension
;
1854 OUString
ScDPDataMember::GetName() const
1857 return pResultMember
->GetName();
1859 return EMPTY_OUSTRING
;
1862 bool ScDPDataMember::IsVisible() const
1865 return pResultMember
->IsVisible();
1870 bool ScDPDataMember::IsNamedItem( SCROW nRow
) const
1873 return pResultMember
->IsNamedItem(nRow
);
1878 bool ScDPDataMember::HasHiddenDetails() const
1881 return pResultMember
->HasHiddenDetails();
1886 void ScDPDataMember::InitFrom( const ScDPResultDimension
* pDim
)
1888 if ( !pChildDimension
)
1889 pChildDimension
= new ScDPDataDimension(pResultData
);
1890 pChildDimension
->InitFrom(pDim
);
1893 const long SC_SUBTOTALPOS_AUTO
= -1; // default
1894 const long SC_SUBTOTALPOS_SKIP
= -2; // don't use
1896 static long lcl_GetSubTotalPos( const ScDPSubTotalState
& rSubState
)
1898 if ( rSubState
.nColSubTotalFunc
>= 0 && rSubState
.nRowSubTotalFunc
>= 0 &&
1899 rSubState
.nColSubTotalFunc
!= rSubState
.nRowSubTotalFunc
)
1901 // #i68338# don't return the same index for different combinations (leading to repeated updates),
1902 // return a "don't use" value instead
1904 return SC_SUBTOTALPOS_SKIP
;
1907 long nRet
= SC_SUBTOTALPOS_AUTO
;
1908 if ( rSubState
.nColSubTotalFunc
>= 0 ) nRet
= rSubState
.nColSubTotalFunc
;
1909 if ( rSubState
.nRowSubTotalFunc
>= 0 ) nRet
= rSubState
.nRowSubTotalFunc
;
1913 void ScDPDataMember::UpdateValues( const vector
<ScDPValue
>& aValues
, const ScDPSubTotalState
& rSubState
)
1915 //! find out how many and which subtotals are used
1917 ScDPAggData
* pAgg
= &aAggregate
;
1919 long nSubPos
= lcl_GetSubTotalPos(rSubState
);
1920 if (nSubPos
== SC_SUBTOTALPOS_SKIP
)
1924 long nSkip
= nSubPos
* pResultData
->GetMeasureCount();
1925 for (long i
=0; i
<nSkip
; i
++)
1926 pAgg
= pAgg
->GetChild(); // created if not there
1929 size_t nCount
= aValues
.size();
1930 for (size_t nPos
= 0; nPos
< nCount
; ++nPos
)
1932 pAgg
->Update(aValues
[nPos
], pResultData
->GetMeasureFunction(nPos
), rSubState
);
1933 pAgg
= pAgg
->GetChild();
1937 void ScDPDataMember::ProcessData( const vector
< SCROW
>& aChildMembers
, const vector
<ScDPValue
>& aValues
,
1938 const ScDPSubTotalState
& rSubState
)
1940 if ( pResultData
->IsLateInit() && !pChildDimension
&& pResultMember
&& pResultMember
->GetChildDimension() )
1942 // if this DataMember doesn't have a child dimension because the ResultMember's
1943 // child dimension wasn't there yet during this DataMembers's creation,
1944 // create the child dimension now
1945 InitFrom( pResultMember
->GetChildDimension() );
1948 long nUserSubCount
= pResultMember
? pResultMember
->GetSubTotalCount() : 0;
1950 // Calculate at least automatic if no subtotals are selected,
1951 // show only own values if there's no child dimension (innermost).
1952 if ( !nUserSubCount
|| !pChildDimension
)
1955 ScDPSubTotalState aLocalSubState
= rSubState
; // keep row state, modify column
1956 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
1958 if ( pChildDimension
&& nUserSubCount
> 1 )
1960 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
1961 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
1962 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
1965 UpdateValues( aValues
, aLocalSubState
);
1968 if (pChildDimension
)
1969 pChildDimension
->ProcessData( aChildMembers
, aValues
, rSubState
); // with unmodified subtotal state
1972 bool ScDPDataMember::HasData( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1974 if ( rSubState
.eColForce
!= SUBTOTAL_FUNC_NONE
&& rSubState
.eRowForce
!= SUBTOTAL_FUNC_NONE
&&
1975 rSubState
.eColForce
!= rSubState
.eRowForce
)
1978 // HasData can be different between measures!
1980 const ScDPAggData
* pAgg
= GetConstAggData( nMeasure
, rSubState
);
1982 return false; //! error?
1984 return pAgg
->HasData();
1987 bool ScDPDataMember::HasError( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1989 const ScDPAggData
* pAgg
= GetConstAggData( nMeasure
, rSubState
);
1993 return pAgg
->HasError();
1996 double ScDPDataMember::GetAggregate( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
1998 const ScDPAggData
* pAgg
= GetConstAggData( nMeasure
, rSubState
);
2000 return DBL_MAX
; //! error?
2002 return pAgg
->GetResult();
2005 ScDPAggData
* ScDPDataMember::GetAggData( long nMeasure
, const ScDPSubTotalState
& rSubState
)
2007 OSL_ENSURE( nMeasure
>= 0, "GetAggData: no measure" );
2009 ScDPAggData
* pAgg
= &aAggregate
;
2010 long nSkip
= nMeasure
;
2011 long nSubPos
= lcl_GetSubTotalPos(rSubState
);
2012 if (nSubPos
== SC_SUBTOTALPOS_SKIP
)
2015 nSkip
+= nSubPos
* pResultData
->GetMeasureCount();
2017 for ( long nPos
=0; nPos
<nSkip
; nPos
++ )
2018 pAgg
= pAgg
->GetChild(); //! need to create children here?
2023 const ScDPAggData
* ScDPDataMember::GetConstAggData( long nMeasure
, const ScDPSubTotalState
& rSubState
) const
2025 OSL_ENSURE( nMeasure
>= 0, "GetConstAggData: no measure" );
2027 const ScDPAggData
* pAgg
= &aAggregate
;
2028 long nSkip
= nMeasure
;
2029 long nSubPos
= lcl_GetSubTotalPos(rSubState
);
2030 if (nSubPos
== SC_SUBTOTALPOS_SKIP
)
2033 nSkip
+= nSubPos
* pResultData
->GetMeasureCount();
2035 for ( long nPos
=0; nPos
<nSkip
; nPos
++ )
2037 pAgg
= pAgg
->GetExistingChild();
2045 void ScDPDataMember::FillDataRow(
2046 const ScDPResultMember
* pRefMember
, ScDPResultFilterContext
& rFilterCxt
,
2047 uno::Sequence
<sheet::DataResult
>& rSequence
, long nMeasure
, bool bIsSubTotalRow
,
2048 const ScDPSubTotalState
& rSubState
) const
2050 boost::scoped_ptr
<FilterStack
> pFilterStack
;
2053 // Topmost data member (pResultMember=NULL) doesn't need to be handled
2054 // since its immediate parent result member is linked to the same
2055 // dimension member.
2056 pFilterStack
.reset(new FilterStack(rFilterCxt
.maFilters
));
2057 pFilterStack
->pushDimValue(pResultMember
->GetDisplayName());
2060 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2062 long nStartCol
= rFilterCxt
.mnCol
;
2064 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2065 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2067 const ScDPLevel
* pRefParentLevel
= const_cast<ScDPResultMember
*>(pRefMember
)->GetParentLevel();
2069 long nExtraSpace
= 0;
2070 if ( pRefParentLevel
&& pRefParentLevel
->IsAddEmpty() )
2073 bool bTitleLine
= false;
2074 if ( pRefParentLevel
&& pRefParentLevel
->IsOutlineLayout() )
2077 bool bSubTotalInTitle
= pRefMember
->IsSubTotalInTitle( nMeasure
);
2079 // leave space for children even if the DataMember hasn't been initialized
2080 // (pDataChild is null then, this happens when no values for it are in this row)
2081 bool bHasChild
= ( pRefChild
!= NULL
);
2085 if ( bTitleLine
) // in tabular layout the title is on a separate column
2086 ++rFilterCxt
.mnCol
; // -> fill child dimension one column below
2090 long nOldCol
= rFilterCxt
.mnCol
;
2091 pDataChild
->FillDataRow(pRefChild
, rFilterCxt
, rSequence
, nMeasure
, bIsSubTotalRow
, rSubState
);
2092 rFilterCxt
.mnCol
= nOldCol
; // Revert to the old column value before the call.
2094 rFilterCxt
.mnCol
+= (sal_uInt16
)pRefMember
->GetSize( nMeasure
);
2096 if ( bTitleLine
) // title column is included in GetSize, so the following
2097 --rFilterCxt
.mnCol
; // positions are calculated with the normal values
2101 long nUserSubCount
= pRefMember
->GetSubTotalCount(&nUserSubStart
);
2102 if ( nUserSubCount
|| !bHasChild
)
2104 // Calculate at least automatic if no subtotals are selected,
2105 // show only own values if there's no child dimension (innermost).
2106 if ( !nUserSubCount
|| !bHasChild
)
2112 ScDPSubTotalState
aLocalSubState(rSubState
); // keep row state, modify column
2114 long nMemberMeasure
= nMeasure
;
2115 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
2118 rFilterCxt
.mnCol
-= nSubSize
* ( nUserSubCount
- nUserSubStart
); // GetSize includes space for SubTotal
2119 rFilterCxt
.mnCol
-= nExtraSpace
; // GetSize includes the empty line
2122 long nMoveSubTotal
= 0;
2123 if ( bSubTotalInTitle
)
2125 nMoveSubTotal
= rFilterCxt
.mnCol
- nStartCol
; // force to first (title) column
2126 rFilterCxt
.mnCol
= nStartCol
;
2129 for (long nUserPos
=nUserSubStart
; nUserPos
<nUserSubCount
; nUserPos
++)
2131 if ( pChildDimension
&& nUserSubCount
> 1 )
2133 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
2134 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
2135 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
2138 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
2140 if ( nMeasure
== SC_DPMEASURE_ALL
)
2141 nMemberMeasure
= nSubCount
;
2143 OSL_ENSURE( rFilterCxt
.mnCol
< rSequence
.getLength(), "bumm" );
2144 sheet::DataResult
& rRes
= rSequence
.getArray()[rFilterCxt
.mnCol
];
2146 if ( HasData( nMemberMeasure
, aLocalSubState
) )
2148 if ( HasError( nMemberMeasure
, aLocalSubState
) )
2151 rRes
.Flags
|= sheet::DataResultFlags::ERROR
;
2155 rRes
.Value
= GetAggregate( nMemberMeasure
, aLocalSubState
);
2156 rRes
.Flags
|= sheet::DataResultFlags::HASDATA
;
2160 if ( bHasChild
|| bIsSubTotalRow
)
2161 rRes
.Flags
|= sheet::DataResultFlags::SUBTOTAL
;
2163 rFilterCxt
.maFilterSet
.add(rFilterCxt
.maFilters
, rFilterCxt
.mnCol
, rFilterCxt
.mnRow
, rRes
.Value
);
2164 rFilterCxt
.mnCol
+= 1;
2168 // add extra space again if subtracted from GetSize above,
2169 // add to own size if no children
2170 rFilterCxt
.mnCol
+= nExtraSpace
;
2171 rFilterCxt
.mnCol
+= nMoveSubTotal
;
2175 void ScDPDataMember::UpdateDataRow(
2176 const ScDPResultMember
* pRefMember
, long nMeasure
, bool bIsSubTotalRow
,
2177 const ScDPSubTotalState
& rSubState
)
2179 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2181 // Calculate must be called even if not visible (for use as reference value)
2182 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2183 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2185 // leave space for children even if the DataMember hasn't been initialized
2186 // (pDataChild is null then, this happens when no values for it are in this row)
2187 bool bHasChild
= ( pRefChild
!= NULL
);
2189 // process subtotals even if not shown
2190 long nUserSubCount
= pRefMember
->GetSubTotalCount();
2192 // Calculate at least automatic if no subtotals are selected,
2193 // show only own values if there's no child dimension (innermost).
2194 if ( !nUserSubCount
|| !bHasChild
)
2197 ScDPSubTotalState
aLocalSubState(rSubState
); // keep row state, modify column
2199 long nMemberMeasure
= nMeasure
;
2200 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
2202 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
2204 if ( pChildDimension
&& nUserSubCount
> 1 )
2206 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
2207 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
2208 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
2211 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
2213 if ( nMeasure
== SC_DPMEASURE_ALL
)
2214 nMemberMeasure
= nSubCount
;
2217 ScDPAggData
* pAggData
= GetAggData( nMemberMeasure
, aLocalSubState
);
2221 ScSubTotalFunc eFunc
= pResultData
->GetMeasureFunction( nMemberMeasure
);
2222 sheet::DataPilotFieldReference aReferenceValue
= pResultData
->GetMeasureRefVal( nMemberMeasure
);
2223 sal_Int32 eRefType
= aReferenceValue
.ReferenceType
;
2225 // calculate the result first - for all members, regardless of reference value
2226 pAggData
->Calculate( eFunc
, aLocalSubState
);
2228 if ( eRefType
== sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE
||
2229 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
||
2230 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE
)
2232 // copy the result into auxiliary value, so differences can be
2233 // calculated in any order
2234 pAggData
->SetAuxiliary( pAggData
->GetResult() );
2236 // column/row percentage/index is now in UpdateRunningTotals, so it doesn't disturb sorting
2241 if ( bHasChild
) // child dimension must be processed last, so the row total is known
2244 pDataChild
->UpdateDataRow( pRefChild
, nMeasure
, bIsSubTotalRow
, rSubState
);
2248 void ScDPDataMember::SortMembers( ScDPResultMember
* pRefMember
)
2250 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2252 if ( pRefMember
->IsVisible() ) //! here or in ScDPDataDimension ???
2254 ScDPDataDimension
* pDataChild
= GetChildDimension();
2255 ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2256 if ( pRefChild
&& pDataChild
)
2257 pDataChild
->SortMembers( pRefChild
); // sorting is done at the dimension
2261 void ScDPDataMember::DoAutoShow( ScDPResultMember
* pRefMember
)
2263 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2265 if ( pRefMember
->IsVisible() ) //! here or in ScDPDataDimension ???
2267 ScDPDataDimension
* pDataChild
= GetChildDimension();
2268 ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2269 if ( pRefChild
&& pDataChild
)
2270 pDataChild
->DoAutoShow( pRefChild
); // sorting is done at the dimension
2274 void ScDPDataMember::ResetResults()
2278 ScDPDataDimension
* pDataChild
= GetChildDimension();
2280 pDataChild
->ResetResults();
2283 void ScDPDataMember::UpdateRunningTotals(
2284 const ScDPResultMember
* pRefMember
, long nMeasure
, bool bIsSubTotalRow
,
2285 const ScDPSubTotalState
& rSubState
, ScDPRunningTotalState
& rRunning
,
2286 ScDPRowTotals
& rTotals
, const ScDPResultMember
& rRowParent
)
2288 OSL_ENSURE( pRefMember
== pResultMember
|| !pResultMember
, "bla" );
2290 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2291 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2293 bool bIsRoot
= ( pResultMember
== NULL
|| pResultMember
->GetParentLevel() == NULL
);
2295 // leave space for children even if the DataMember hasn't been initialized
2296 // (pDataChild is null then, this happens when no values for it are in this row)
2297 bool bHasChild
= ( pRefChild
!= NULL
);
2299 long nUserSubCount
= pRefMember
->GetSubTotalCount();
2301 // Calculate at least automatic if no subtotals are selected,
2302 // show only own values if there's no child dimension (innermost).
2303 if ( !nUserSubCount
|| !bHasChild
)
2306 ScDPSubTotalState
aLocalSubState(rSubState
); // keep row state, modify column
2308 long nMemberMeasure
= nMeasure
;
2309 long nSubSize
= pResultData
->GetCountForMeasure(nMeasure
);
2311 for (long nUserPos
=0; nUserPos
<nUserSubCount
; nUserPos
++) // including hidden "automatic"
2313 if ( pChildDimension
&& nUserSubCount
> 1 )
2315 const ScDPLevel
* pForceLevel
= pResultMember
? pResultMember
->GetParentLevel() : NULL
;
2316 aLocalSubState
.nColSubTotalFunc
= nUserPos
;
2317 aLocalSubState
.eColForce
= lcl_GetForceFunc( pForceLevel
, nUserPos
);
2320 for ( long nSubCount
=0; nSubCount
<nSubSize
; nSubCount
++ )
2322 if ( nMeasure
== SC_DPMEASURE_ALL
)
2323 nMemberMeasure
= nSubCount
;
2326 ScDPAggData
* pAggData
= GetAggData( nMemberMeasure
, aLocalSubState
);
2330 sheet::DataPilotFieldReference aReferenceValue
= pResultData
->GetMeasureRefVal( nMemberMeasure
);
2331 sal_Int32 eRefType
= aReferenceValue
.ReferenceType
;
2333 if ( eRefType
== sheet::DataPilotFieldReferenceType::RUNNING_TOTAL
||
2334 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE
||
2335 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
||
2336 eRefType
== sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE
)
2338 bool bRunningTotal
= ( eRefType
== sheet::DataPilotFieldReferenceType::RUNNING_TOTAL
);
2340 ( aReferenceValue
.ReferenceItemType
!= sheet::DataPilotFieldReferenceItemType::NAMED
&& !bRunningTotal
);
2341 long nRelativeDir
= bRelative
?
2342 ( ( aReferenceValue
.ReferenceItemType
== sheet::DataPilotFieldReferenceItemType::PREVIOUS
) ? -1 : 1 ) : 0;
2344 const ScDPRunningTotalState::IndexArray
& rColVisible
= rRunning
.GetColVisible();
2345 const ScDPRunningTotalState::IndexArray
& rColSorted
= rRunning
.GetColSorted();
2346 const ScDPRunningTotalState::IndexArray
& rRowVisible
= rRunning
.GetRowVisible();
2347 const ScDPRunningTotalState::IndexArray
& rRowSorted
= rRunning
.GetRowSorted();
2349 OUString aRefFieldName
= aReferenceValue
.ReferenceField
;
2352 sal_uInt16 nRefOrient
= pResultData
->GetMeasureRefOrient( nMemberMeasure
);
2353 bool bRefDimInCol
= ( nRefOrient
== sheet::DataPilotFieldOrientation_COLUMN
);
2354 bool bRefDimInRow
= ( nRefOrient
== sheet::DataPilotFieldOrientation_ROW
);
2356 ScDPResultDimension
* pSelectDim
= NULL
;
2361 // find the reference field in column or row dimensions
2364 if ( bRefDimInRow
) // look in row dimensions
2366 pSelectDim
= rRunning
.GetRowResRoot()->GetChildDimension();
2367 while ( pSelectDim
&& pSelectDim
->GetName() != aRefFieldName
)
2369 long nIndex
= rRowSorted
[nRowPos
];
2370 if ( nIndex
>= 0 && nIndex
< pSelectDim
->GetMemberCount() )
2371 pSelectDim
= pSelectDim
->GetMember(nIndex
)->GetChildDimension();
2376 // child dimension of innermost member?
2377 if ( pSelectDim
&& rRowSorted
[nRowPos
] < 0 )
2381 if ( bRefDimInCol
) // look in column dimensions
2383 pSelectDim
= rRunning
.GetColResRoot()->GetChildDimension();
2384 while ( pSelectDim
&& pSelectDim
->GetName() != aRefFieldName
)
2386 long nIndex
= rColSorted
[nColPos
];
2387 if ( nIndex
>= 0 && nIndex
< pSelectDim
->GetMemberCount() )
2388 pSelectDim
= pSelectDim
->GetMember(nIndex
)->GetChildDimension();
2393 // child dimension of innermost member?
2394 if ( pSelectDim
&& rColSorted
[nColPos
] < 0 )
2398 bool bNoDetailsInRef
= false;
2399 if ( pSelectDim
&& bRunningTotal
)
2402 // If details are hidden for this member in the reference dimension,
2403 // don't show or sum up the value. Otherwise, for following members,
2404 // the running totals of details and subtotals wouldn't match.
2406 long nMyIndex
= bRefDimInCol
? rColSorted
[nColPos
] : rRowSorted
[nRowPos
];
2407 if ( nMyIndex
>= 0 && nMyIndex
< pSelectDim
->GetMemberCount() )
2409 const ScDPResultMember
* pMyRefMember
= pSelectDim
->GetMember(nMyIndex
);
2410 if ( pMyRefMember
&& pMyRefMember
->HasHiddenDetails() )
2412 pSelectDim
= NULL
; // don't calculate
2413 bNoDetailsInRef
= true; // show error, not empty
2420 // Difference/Percentage from previous/next:
2421 // If details are hidden for this member in the innermost column/row
2422 // dimension (the orientation of the reference dimension), show an
2424 // - If the no-details dimension is the reference dimension, its
2425 // members will be skipped when finding the previous/next member,
2426 // so there must be no results for its members.
2427 // - If the no-details dimension is outside of the reference dimension,
2428 // no calculation in the reference dimension is possible.
2429 // - Otherwise, the error isn't strictly necessary, but shown for
2432 bool bInnerNoDetails
= bRefDimInCol
? HasHiddenDetails() :
2433 ( bRefDimInRow
? rRowParent
.HasHiddenDetails() : true );
2434 if ( bInnerNoDetails
)
2437 bNoDetailsInRef
= true; // show error, not empty
2441 if ( !bRefDimInCol
&& !bRefDimInRow
) // invalid dimension specified
2442 bNoDetailsInRef
= true; // pSelectDim is then already NULL
2445 // get the member for the reference item and do the calculation
2448 if ( bRunningTotal
)
2450 // running total in (dimension) -> find first existing member
2454 ScDPDataMember
* pSelectMember
;
2456 pSelectMember
= ScDPResultDimension::GetColReferenceMember( NULL
, NULL
,
2457 nColPos
, rRunning
);
2460 const long* pRowSorted
= &rRowSorted
[0];
2461 const long* pColSorted
= &rColSorted
[0];
2462 pRowSorted
+= nRowPos
+ 1; // including the reference dimension
2463 pSelectMember
= pSelectDim
->GetRowReferenceMember(
2464 NULL
, NULL
, pRowSorted
, pColSorted
);
2467 if ( pSelectMember
)
2469 // The running total is kept as the auxiliary value in
2470 // the first available member for the reference dimension.
2471 // Members are visited in final order, so each one's result
2472 // can be used and then modified.
2474 ScDPAggData
* pSelectData
= pSelectMember
->
2475 GetAggData( nMemberMeasure
, aLocalSubState
);
2478 double fTotal
= pSelectData
->GetAuxiliary();
2479 fTotal
+= pAggData
->GetResult();
2480 pSelectData
->SetAuxiliary( fTotal
);
2481 pAggData
->SetResult( fTotal
);
2482 pAggData
->SetEmpty(false); // always display
2486 pAggData
->SetError();
2488 else if (bNoDetailsInRef
)
2489 pAggData
->SetError();
2491 pAggData
->SetEmpty(true); // empty (dim set to 0 above)
2495 // difference/percentage -> find specified member
2499 OUString aRefItemName
= aReferenceValue
.ReferenceItemName
;
2500 ScDPRelativePos
aRefItemPos( 0, nRelativeDir
); // nBasePos is modified later
2502 const OUString
* pRefName
= NULL
;
2503 const ScDPRelativePos
* pRefPos
= NULL
;
2505 pRefPos
= &aRefItemPos
;
2507 pRefName
= &aRefItemName
;
2509 ScDPDataMember
* pSelectMember
;
2512 aRefItemPos
.nBasePos
= rColVisible
[nColPos
]; // without sort order applied
2513 pSelectMember
= ScDPResultDimension::GetColReferenceMember( pRefPos
, pRefName
,
2514 nColPos
, rRunning
);
2518 aRefItemPos
.nBasePos
= rRowVisible
[nRowPos
]; // without sort order applied
2519 const long* pRowSorted
= &rRowSorted
[0];
2520 const long* pColSorted
= &rColSorted
[0];
2521 pRowSorted
+= nRowPos
+ 1; // including the reference dimension
2522 pSelectMember
= pSelectDim
->GetRowReferenceMember(
2523 pRefPos
, pRefName
, pRowSorted
, pColSorted
);
2526 // difference or perc.difference is empty for the reference item itself
2527 if ( pSelectMember
== this &&
2528 eRefType
!= sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
)
2530 pAggData
->SetEmpty(true);
2532 else if ( pSelectMember
)
2534 const ScDPAggData
* pOtherAggData
= pSelectMember
->
2535 GetConstAggData( nMemberMeasure
, aLocalSubState
);
2536 OSL_ENSURE( pOtherAggData
, "no agg data" );
2537 if ( pOtherAggData
)
2539 // Reference member may be visited before or after this one,
2540 // so the auxiliary value is used for the original result.
2542 double fOtherResult
= pOtherAggData
->GetAuxiliary();
2543 double fThisResult
= pAggData
->GetResult();
2544 bool bError
= false;
2547 case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE
:
2548 fThisResult
= fThisResult
- fOtherResult
;
2550 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE
:
2551 if ( fOtherResult
== 0.0 )
2554 fThisResult
= fThisResult
/ fOtherResult
;
2556 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE
:
2557 if ( fOtherResult
== 0.0 )
2560 fThisResult
= ( fThisResult
- fOtherResult
) / fOtherResult
;
2563 OSL_FAIL("invalid calculation type");
2567 pAggData
->SetError();
2571 pAggData
->SetResult(fThisResult
);
2572 pAggData
->SetEmpty(false); // always display
2577 else if (bRelative
&& !bNoDetailsInRef
)
2578 pAggData
->SetEmpty(true); // empty
2580 pAggData
->SetError(); // error
2582 else if (bNoDetailsInRef
)
2583 pAggData
->SetError(); // error
2585 pAggData
->SetEmpty(true); // empty
2588 else if ( eRefType
== sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE
||
2589 eRefType
== sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE
||
2590 eRefType
== sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE
||
2591 eRefType
== sheet::DataPilotFieldReferenceType::INDEX
)
2594 // set total values when they are encountered (always before their use)
2597 ScDPAggData
* pColTotalData
= pRefMember
->GetColTotal( nMemberMeasure
);
2598 ScDPAggData
* pRowTotalData
= rTotals
.GetRowTotal( nMemberMeasure
);
2599 ScDPAggData
* pGrandTotalData
= rTotals
.GetGrandTotal( nMemberMeasure
);
2601 double fTotalValue
= pAggData
->HasError() ? 0 : pAggData
->GetResult();
2603 if ( bIsRoot
&& rTotals
.IsInColRoot() && pGrandTotalData
)
2604 pGrandTotalData
->SetAuxiliary( fTotalValue
);
2606 if ( bIsRoot
&& pRowTotalData
)
2607 pRowTotalData
->SetAuxiliary( fTotalValue
);
2609 if ( rTotals
.IsInColRoot() && pColTotalData
)
2610 pColTotalData
->SetAuxiliary( fTotalValue
);
2613 // find relation to total values
2618 case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE
:
2619 case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE
:
2620 case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE
:
2623 if ( eRefType
== sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE
)
2624 nTotal
= pRowTotalData
->GetAuxiliary();
2625 else if ( eRefType
== sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE
)
2626 nTotal
= pColTotalData
->GetAuxiliary();
2628 nTotal
= pGrandTotalData
->GetAuxiliary();
2630 if ( nTotal
== 0.0 )
2631 pAggData
->SetError();
2633 pAggData
->SetResult( pAggData
->GetResult() / nTotal
);
2636 case sheet::DataPilotFieldReferenceType::INDEX
:
2638 double nColTotal
= pColTotalData
->GetAuxiliary();
2639 double nRowTotal
= pRowTotalData
->GetAuxiliary();
2640 double nGrandTotal
= pGrandTotalData
->GetAuxiliary();
2641 if ( nRowTotal
== 0.0 || nColTotal
== 0.0 )
2642 pAggData
->SetError();
2644 pAggData
->SetResult(
2645 ( pAggData
->GetResult() * nGrandTotal
) /
2646 ( nRowTotal
* nColTotal
) );
2656 if ( bHasChild
) // child dimension must be processed last, so the row total is known
2659 pDataChild
->UpdateRunningTotals( pRefChild
, nMeasure
,
2660 bIsSubTotalRow
, rSubState
, rRunning
, rTotals
, rRowParent
);
2664 #if DEBUG_PIVOT_TABLE
2665 void ScDPDataMember::DumpState( const ScDPResultMember
* pRefMember
, ScDocument
* pDoc
, ScAddress
& rPos
) const
2667 lcl_DumpRow( OUString("ScDPDataMember"), GetName(), &aAggregate
, pDoc
, rPos
);
2668 SCROW nStartRow
= rPos
.Row();
2670 const ScDPDataDimension
* pDataChild
= GetChildDimension();
2671 const ScDPResultDimension
* pRefChild
= pRefMember
->GetChildDimension();
2672 if ( pDataChild
&& pRefChild
)
2673 pDataChild
->DumpState( pRefChild
, pDoc
, rPos
);
2675 lcl_Indent( pDoc
, nStartRow
, rPos
);
2678 void ScDPDataMember::Dump(int nIndent
) const
2680 std::string
aIndent(nIndent
*2, ' ');
2681 std::cout
<< aIndent
<< "-- data member '"
2682 << (pResultMember
? pResultMember
->GetName() : OUString()) << "'" << std::endl
;
2683 for (const ScDPAggData
* pAgg
= &aAggregate
; pAgg
; pAgg
= pAgg
->GetExistingChild())
2684 pAgg
->Dump(nIndent
+1);
2686 if (pChildDimension
)
2687 pChildDimension
->Dump(nIndent
+1);
2691 // -----------------------------------------------------------------------
2693 // Helper class to select the members to include in
2694 // ScDPResultDimension::InitFrom or LateInitFrom if groups are used
2696 class ScDPGroupCompare
2699 const ScDPResultData
* pResultData
;
2700 const ScDPInitState
& rInitState
;
2706 ScDPGroupCompare( const ScDPResultData
* pData
, const ScDPInitState
& rState
, long nDimension
);
2707 ~ScDPGroupCompare() {}
2709 bool IsIncluded( const ScDPMember
& rMember
) { return bIncludeAll
|| TestIncluded( rMember
); }
2710 bool TestIncluded( const ScDPMember
& rMember
);
2713 ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData
* pData
, const ScDPInitState
& rState
, long nDimension
) :
2714 pResultData( pData
),
2715 rInitState( rState
),
2716 nDimSource( nDimension
)
2718 bIsBase
= pResultData
->IsBaseForGroup( nDimSource
);
2719 nGroupBase
= pResultData
->GetGroupBase( nDimSource
); //! get together in one call?
2721 // if bIncludeAll is set, TestIncluded doesn't need to be called
2722 bIncludeAll
= !( bIsBase
|| nGroupBase
>= 0 );
2725 bool ScDPGroupCompare::TestIncluded( const ScDPMember
& rMember
)
2727 bool bInclude
= true;
2730 // need to check all previous groups
2731 //! get array of groups (or indexes) before loop?
2732 ScDPItemData aMemberData
;
2733 rMember
.FillItemData( aMemberData
);
2735 const std::vector
<ScDPInitState::Member
>& rMemStates
= rInitState
.GetMembers();
2736 std::vector
<ScDPInitState::Member
>::const_iterator it
= rMemStates
.begin(), itEnd
= rMemStates
.end();
2737 for (; it
!= itEnd
&& bInclude
; ++it
)
2739 if (pResultData
->GetGroupBase(it
->mnSrcIndex
) == nDimSource
)
2741 bInclude
= pResultData
->IsInGroup(
2742 it
->mnNameIndex
, it
->mnSrcIndex
, aMemberData
, nDimSource
);
2746 else if ( nGroupBase
>= 0 )
2748 // base isn't used in preceding fields
2749 // -> look for other groups using the same base
2751 //! get array of groups (or indexes) before loop?
2752 ScDPItemData aMemberData
;
2753 rMember
.FillItemData( aMemberData
);
2754 const std::vector
<ScDPInitState::Member
>& rMemStates
= rInitState
.GetMembers();
2755 std::vector
<ScDPInitState::Member
>::const_iterator it
= rMemStates
.begin(), itEnd
= rMemStates
.end();
2756 for (; it
!= itEnd
&& bInclude
; ++it
)
2758 if (pResultData
->GetGroupBase(it
->mnSrcIndex
) == nGroupBase
)
2760 // same base (hierarchy between the two groups is irrelevant)
2761 bInclude
= pResultData
->HasCommonElement(
2762 it
->mnNameIndex
, it
->mnSrcIndex
, aMemberData
, nDimSource
);
2771 // -----------------------------------------------------------------------
2773 ScDPResultDimension::ScDPResultDimension( const ScDPResultData
* pData
) :
2774 pResultData( pData
),
2776 bIsDataLayout( false ),
2777 bSortByData( false ),
2778 bSortAscending( false ),
2780 bAutoTopItems( false ),
2781 bInitialized( false ),
2787 ScDPResultDimension::~ScDPResultDimension()
2789 for( int i
= maMemberArray
.size () ; i
-- > 0 ; )
2790 delete maMemberArray
[i
];
2793 ScDPResultMember
*ScDPResultDimension::FindMember( SCROW iData
) const
2796 return maMemberArray
[0];
2798 MemberHash::const_iterator aRes
= maMemberHash
.find( iData
);
2799 if( aRes
!= maMemberHash
.end()) {
2800 if ( aRes
->second
->IsNamedItem( iData
) )
2801 return aRes
->second
;
2802 OSL_FAIL("problem! hash result is not the same as IsNamedItem");
2806 unsigned int nCount
= maMemberArray
.size();
2807 ScDPResultMember
* pResultMember
;
2808 for( i
= 0; i
< nCount
; i
++ )
2810 pResultMember
= maMemberArray
[i
];
2811 if ( pResultMember
->IsNamedItem( iData
) )
2812 return pResultMember
;
2817 void ScDPResultDimension::InitFrom(
2818 const vector
<ScDPDimension
*>& ppDim
, const vector
<ScDPLevel
*>& ppLev
,
2819 size_t nPos
, ScDPInitState
& rInitState
, bool bInitChild
)
2821 if (nPos
>= ppDim
.size() || nPos
>= ppLev
.size())
2823 bInitialized
= true;
2827 ScDPDimension
* pThisDim
= ppDim
[nPos
];
2828 ScDPLevel
* pThisLevel
= ppLev
[nPos
];
2830 if (!pThisDim
|| !pThisLevel
)
2832 bInitialized
= true;
2836 bIsDataLayout
= pThisDim
->getIsDataLayoutDimension(); // member
2837 aDimensionName
= pThisDim
->getName(); // member
2839 // Check the autoshow setting. If it's enabled, store the settings.
2840 const sheet::DataPilotFieldAutoShowInfo
& rAutoInfo
= pThisLevel
->GetAutoShow();
2841 if ( rAutoInfo
.IsEnabled
)
2844 bAutoTopItems
= ( rAutoInfo
.ShowItemsMode
== sheet::DataPilotFieldShowItemsMode::FROM_TOP
);
2845 nAutoMeasure
= pThisLevel
->GetAutoMeasure();
2846 nAutoCount
= rAutoInfo
.ItemCount
;
2849 // Check the sort info, and store the settings if appropriate.
2850 const sheet::DataPilotFieldSortInfo
& rSortInfo
= pThisLevel
->GetSortInfo();
2851 if ( rSortInfo
.Mode
== sheet::DataPilotFieldSortMode::DATA
)
2854 bSortAscending
= rSortInfo
.IsAscending
;
2855 nSortMeasure
= pThisLevel
->GetSortMeasure();
2858 // global order is used to initialize aMembers, so it doesn't have to be looked at later
2859 const ScMemberSortOrder
& rGlobalOrder
= pThisLevel
->GetGlobalOrder();
2861 long nDimSource
= pThisDim
->GetDimension(); //! check GetSourceDim?
2862 ScDPGroupCompare
aCompare( pResultData
, rInitState
, nDimSource
);
2864 // Now, go through all members and initialize them.
2865 ScDPMembers
* pMembers
= pThisLevel
->GetMembersObject();
2866 long nMembCount
= pMembers
->getCount();
2867 for ( long i
=0; i
<nMembCount
; i
++ )
2869 long nSorted
= rGlobalOrder
.empty() ? i
: rGlobalOrder
[i
];
2871 ScDPMember
* pMember
= pMembers
->getByIndex(nSorted
);
2872 if ( aCompare
.IsIncluded( *pMember
) )
2874 ScDPParentDimData
aData( i
, pThisDim
, pThisLevel
, pMember
);
2875 ScDPResultMember
* pNew
= AddMember( aData
);
2877 rInitState
.AddMember(nDimSource
, pNew
->GetDataId());
2878 pNew
->InitFrom( ppDim
, ppLev
, nPos
+1, rInitState
, bInitChild
);
2879 rInitState
.RemoveMember();
2882 bInitialized
= true;
2885 void ScDPResultDimension::LateInitFrom(
2886 LateInitParams
& rParams
, const vector
<SCROW
>& pItemData
, size_t nPos
, ScDPInitState
& rInitState
)
2888 if ( rParams
.IsEnd( nPos
) )
2890 OSL_ENSURE( nPos
<= pItemData
.size(), OString::number(pItemData
.size()).getStr() );
2891 ScDPDimension
* pThisDim
= rParams
.GetDim( nPos
);
2892 ScDPLevel
* pThisLevel
= rParams
.GetLevel( nPos
);
2893 SCROW rThisData
= pItemData
[nPos
];
2895 if (!pThisDim
|| !pThisLevel
)
2898 long nDimSource
= pThisDim
->GetDimension(); //! check GetSourceDim?
2900 bool bShowEmpty
= pThisLevel
->getShowEmpty();
2902 if ( !bInitialized
)
2903 { // init some values
2904 // create all members at the first call (preserve order)
2905 bIsDataLayout
= pThisDim
->getIsDataLayoutDimension();
2906 aDimensionName
= pThisDim
->getName();
2908 const sheet::DataPilotFieldAutoShowInfo
& rAutoInfo
= pThisLevel
->GetAutoShow();
2909 if ( rAutoInfo
.IsEnabled
)
2912 bAutoTopItems
= ( rAutoInfo
.ShowItemsMode
== sheet::DataPilotFieldShowItemsMode::FROM_TOP
);
2913 nAutoMeasure
= pThisLevel
->GetAutoMeasure();
2914 nAutoCount
= rAutoInfo
.ItemCount
;
2917 const sheet::DataPilotFieldSortInfo
& rSortInfo
= pThisLevel
->GetSortInfo();
2918 if ( rSortInfo
.Mode
== sheet::DataPilotFieldSortMode::DATA
)
2921 bSortAscending
= rSortInfo
.IsAscending
;
2922 nSortMeasure
= pThisLevel
->GetSortMeasure();
2926 bool bLateInitAllMembers
= bIsDataLayout
|| rParams
.GetInitAllChild() || bShowEmpty
;
2928 if ( !bLateInitAllMembers
)
2930 ResultMembers
* pMembers
= pResultData
->GetDimResultMembers(nDimSource
, pThisDim
, pThisLevel
);
2931 bLateInitAllMembers
= pMembers
->IsHasHideDetailsMembers();
2932 #if OSL_DEBUG_LEVEL > 1
2933 OSL_TRACE( "%s", aDimensionName
.getStr() );
2934 if ( pMembers
->IsHasHideDetailsMembers() )
2935 OSL_TRACE( "HasHideDetailsMembers" );
2937 pMembers
->SetHasHideDetailsMembers( false );
2940 bool bNewAllMembers
= (!rParams
.IsRow()) || nPos
== 0 || bLateInitAllMembers
;
2942 if (bNewAllMembers
)
2944 // global order is used to initialize aMembers, so it doesn't have to be looked at later
2945 if ( !bInitialized
)
2946 { //init all members
2947 const ScMemberSortOrder
& rGlobalOrder
= pThisLevel
->GetGlobalOrder();
2949 ScDPGroupCompare
aCompare( pResultData
, rInitState
, nDimSource
);
2950 ScDPMembers
* pMembers
= pThisLevel
->GetMembersObject();
2951 long nMembCount
= pMembers
->getCount();
2952 for ( long i
=0; i
<nMembCount
; i
++ )
2954 long nSorted
= rGlobalOrder
.empty() ? i
: rGlobalOrder
[i
];
2956 ScDPMember
* pMember
= pMembers
->getByIndex(nSorted
);
2957 if ( aCompare
.IsIncluded( *pMember
) )
2958 { // add all members
2959 ScDPParentDimData
aData( i
, pThisDim
, pThisLevel
, pMember
);
2963 bInitialized
= true; // don't call again, even if no members were included
2965 // initialize only specific member (or all if "show empty" flag is set)
2966 if ( bLateInitAllMembers
)
2968 long nCount
= maMemberArray
.size();
2969 for (long i
=0; i
<nCount
; i
++)
2971 ScDPResultMember
* pResultMember
= maMemberArray
[i
];
2974 bool bAllChildren
= false;
2977 if ( pResultMember
->IsNamedItem( rThisData
) )
2978 bAllChildren
= false;
2980 bAllChildren
= true;
2982 rParams
.SetInitAllChildren( bAllChildren
);
2983 rInitState
.AddMember( nDimSource
, pResultMember
->GetDataId() );
2984 pResultMember
->LateInitFrom( rParams
, pItemData
, nPos
+1, rInitState
);
2985 rInitState
.RemoveMember();
2990 ScDPResultMember
* pResultMember
= FindMember( rThisData
);
2991 if( NULL
!= pResultMember
)
2993 rInitState
.AddMember( nDimSource
, pResultMember
->GetDataId() );
2994 pResultMember
->LateInitFrom( rParams
, pItemData
, nPos
+1, rInitState
);
2995 rInitState
.RemoveMember();
3000 InitWithMembers( rParams
, pItemData
, nPos
, rInitState
);
3003 long ScDPResultDimension::GetSize(long nMeasure
) const
3006 long nMemberCount
= maMemberArray
.size();
3009 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3010 "DataLayout dimension twice?");
3011 // repeat first member...
3012 nTotal
= nMemberCount
* maMemberArray
[0]->GetSize(0); // all measures have equal size
3017 for (long nMem
=0; nMem
<nMemberCount
; nMem
++)
3018 nTotal
+= maMemberArray
[nMem
]->GetSize(nMeasure
);
3023 bool ScDPResultDimension::IsValidEntry( const vector
< SCROW
>& aMembers
) const
3025 if (aMembers
.empty())
3028 const ScDPResultMember
* pMember
= FindMember( aMembers
[0] );
3029 if ( NULL
!= pMember
)
3030 return pMember
->IsValidEntry( aMembers
);
3031 #if OSL_DEBUG_LEVEL > 1
3032 OStringBuffer
strTemp("IsValidEntry: Member not found, DimName = ");
3033 strTemp
.append(OUStringToOString(GetName(), RTL_TEXTENCODING_UTF8
));
3034 OSL_TRACE("%s", strTemp
.getStr());
3039 void ScDPResultDimension::ProcessData( const vector
< SCROW
>& aMembers
,
3040 const ScDPResultDimension
* pDataDim
,
3041 const vector
< SCROW
>& aDataMembers
,
3042 const vector
<ScDPValue
>& aValues
) const
3044 if (aMembers
.empty())
3047 ScDPResultMember
* pMember
= FindMember( aMembers
[0] );
3048 if ( NULL
!= pMember
)
3050 vector
<SCROW
> aChildMembers
;
3051 if (aMembers
.size() > 1)
3053 vector
<SCROW
>::const_iterator itr
= aMembers
.begin();
3054 aChildMembers
.insert(aChildMembers
.begin(), ++itr
, aMembers
.end());
3056 pMember
->ProcessData( aChildMembers
, pDataDim
, aDataMembers
, aValues
);
3060 OSL_FAIL("ProcessData: Member not found");
3063 void ScDPResultDimension::FillMemberResults( uno::Sequence
<sheet::MemberResult
>* pSequences
,
3064 long nStart
, long nMeasure
)
3067 long nCount
= maMemberArray
.size();
3069 for (long i
=0; i
<nCount
; i
++)
3071 long nSorted
= aMemberOrder
.empty() ? i
: aMemberOrder
[i
];
3073 ScDPResultMember
* pMember
= maMemberArray
[nSorted
];
3074 // in data layout dimension, use first member with different measures/names
3075 if ( bIsDataLayout
)
3077 bool bTotalResult
= false;
3078 OUString aMbrName
= pResultData
->GetMeasureDimensionName( nSorted
);
3079 OUString aMbrCapt
= pResultData
->GetMeasureString( nSorted
, false, SUBTOTAL_FUNC_NONE
, bTotalResult
);
3080 maMemberArray
[0]->FillMemberResults( pSequences
, nPos
, nSorted
, false, &aMbrName
, &aMbrCapt
);
3082 else if ( pMember
->IsVisible() )
3084 pMember
->FillMemberResults( pSequences
, nPos
, nMeasure
, false, NULL
, NULL
);
3090 void ScDPResultDimension::FillDataResults(
3091 const ScDPResultMember
* pRefMember
, ScDPResultFilterContext
& rFilterCxt
,
3092 uno::Sequence
< uno::Sequence
<sheet::DataResult
> >& rSequence
, long nMeasure
) const
3094 FilterStack
aFilterStack(rFilterCxt
.maFilters
);
3095 aFilterStack
.pushDimName(GetName(), bIsDataLayout
);
3097 long nMemberMeasure
= nMeasure
;
3098 long nCount
= maMemberArray
.size();
3099 for (long i
=0; i
<nCount
; i
++)
3101 long nSorted
= aMemberOrder
.empty() ? i
: aMemberOrder
[i
];
3103 const ScDPResultMember
* pMember
;
3106 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3107 "DataLayout dimension twice?");
3108 pMember
= maMemberArray
[0];
3109 nMemberMeasure
= nSorted
;
3112 pMember
= maMemberArray
[nSorted
];
3114 if ( pMember
->IsVisible() )
3115 pMember
->FillDataResults(pRefMember
, rFilterCxt
, rSequence
, nMemberMeasure
);
3119 void ScDPResultDimension::UpdateDataResults( const ScDPResultMember
* pRefMember
, long nMeasure
) const
3121 long nMemberMeasure
= nMeasure
;
3122 long nCount
= maMemberArray
.size();
3123 for (long i
=0; i
<nCount
; i
++)
3125 const ScDPResultMember
* pMember
;
3128 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3129 "DataLayout dimension twice?");
3130 pMember
= maMemberArray
[0];
3134 pMember
= maMemberArray
[i
];
3136 if ( pMember
->IsVisible() )
3137 pMember
->UpdateDataResults( pRefMember
, nMemberMeasure
);
3141 void ScDPResultDimension::SortMembers( ScDPResultMember
* pRefMember
)
3143 long nCount
= maMemberArray
.size();
3149 OSL_ENSURE( aMemberOrder
.empty(), "sort twice?" );
3150 aMemberOrder
.resize( nCount
);
3151 for (long nPos
=0; nPos
<nCount
; nPos
++)
3152 aMemberOrder
[nPos
] = nPos
;
3154 ScDPRowMembersOrder
aComp( *this, nSortMeasure
, bSortAscending
);
3155 ::std::sort( aMemberOrder
.begin(), aMemberOrder
.end(), aComp
);
3160 // for data layout, call only once - sorting measure is always taken from settings
3161 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3162 for (long i
=0; i
<nLoopCount
; i
++)
3164 ScDPResultMember
* pMember
= maMemberArray
[i
];
3165 if ( pMember
->IsVisible() )
3166 pMember
->SortMembers( pRefMember
);
3170 void ScDPResultDimension::DoAutoShow( ScDPResultMember
* pRefMember
)
3172 long nCount
= maMemberArray
.size();
3174 // handle children first, before changing the visible state
3176 // for data layout, call only once - sorting measure is always taken from settings
3177 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3178 for (long i
=0; i
<nLoopCount
; i
++)
3180 ScDPResultMember
* pMember
= maMemberArray
[i
];
3181 if ( pMember
->IsVisible() )
3182 pMember
->DoAutoShow( pRefMember
);
3185 if ( bAutoShow
&& nAutoCount
> 0 && nAutoCount
< nCount
)
3187 // establish temporary order, hide remaining members
3189 ScMemberSortOrder aAutoOrder
;
3190 aAutoOrder
.resize( nCount
);
3192 for (nPos
=0; nPos
<nCount
; nPos
++)
3193 aAutoOrder
[nPos
] = nPos
;
3195 ScDPRowMembersOrder
aComp( *this, nAutoMeasure
, !bAutoTopItems
);
3196 ::std::sort( aAutoOrder
.begin(), aAutoOrder
.end(), aComp
);
3198 // look for equal values to the last included one
3200 long nIncluded
= nAutoCount
;
3201 const ScDPResultMember
* pMember1
= maMemberArray
[aAutoOrder
[nIncluded
- 1]];
3202 const ScDPDataMember
* pDataMember1
= pMember1
->IsVisible() ? pMember1
->GetDataRoot() : NULL
;
3203 bool bContinue
= true;
3207 if ( nIncluded
< nCount
)
3209 const ScDPResultMember
* pMember2
= maMemberArray
[aAutoOrder
[nIncluded
]];
3210 const ScDPDataMember
* pDataMember2
= pMember2
->IsVisible() ? pMember2
->GetDataRoot() : NULL
;
3212 if ( lcl_IsEqual( pDataMember1
, pDataMember2
, nAutoMeasure
) )
3214 ++nIncluded
; // include more members if values are equal
3220 // hide the remaining members
3222 for (nPos
= nIncluded
; nPos
< nCount
; nPos
++)
3224 ScDPResultMember
* pMember
= maMemberArray
[aAutoOrder
[nPos
]];
3225 pMember
->SetAutoHidden();
3230 void ScDPResultDimension::ResetResults()
3232 long nCount
= maMemberArray
.size();
3233 for (long i
=0; i
<nCount
; i
++)
3235 // sort order doesn't matter
3236 ScDPResultMember
* pMember
= maMemberArray
[bIsDataLayout
? 0 : i
];
3237 pMember
->ResetResults();
3241 long ScDPResultDimension::GetSortedIndex( long nUnsorted
) const
3243 return aMemberOrder
.empty() ? nUnsorted
: aMemberOrder
[nUnsorted
];
3246 void ScDPResultDimension::UpdateRunningTotals( const ScDPResultMember
* pRefMember
, long nMeasure
,
3247 ScDPRunningTotalState
& rRunning
, ScDPRowTotals
& rTotals
) const
3249 const ScDPResultMember
* pMember
;
3250 long nMemberMeasure
= nMeasure
;
3251 long nCount
= maMemberArray
.size();
3252 for (long i
=0; i
<nCount
; i
++)
3254 long nSorted
= aMemberOrder
.empty() ? i
: aMemberOrder
[i
];
3258 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3259 "DataLayout dimension twice?");
3260 pMember
= maMemberArray
[0];
3261 nMemberMeasure
= nSorted
;
3264 pMember
= maMemberArray
[nSorted
];
3266 if ( pMember
->IsVisible() )
3268 if ( bIsDataLayout
)
3269 rRunning
.AddRowIndex( 0, 0 );
3271 rRunning
.AddRowIndex( i
, nSorted
);
3272 pMember
->UpdateRunningTotals( pRefMember
, nMemberMeasure
, rRunning
, rTotals
);
3273 rRunning
.RemoveRowIndex();
3278 ScDPDataMember
* ScDPResultDimension::GetRowReferenceMember(
3279 const ScDPRelativePos
* pRelativePos
, const OUString
* pName
,
3280 const long* pRowIndexes
, const long* pColIndexes
) const
3282 // get named, previous/next, or first member of this dimension (first existing if pRelativePos and pName are NULL)
3284 OSL_ENSURE( pRelativePos
== NULL
|| pName
== NULL
, "can't use position and name" );
3286 ScDPDataMember
* pColMember
= NULL
;
3288 bool bFirstExisting
= ( pRelativePos
== NULL
&& pName
== NULL
);
3289 long nMemberCount
= maMemberArray
.size();
3290 long nMemberIndex
= 0; // unsorted
3291 long nDirection
= 1; // forward if no relative position is used
3294 nDirection
= pRelativePos
->nDirection
;
3295 nMemberIndex
= pRelativePos
->nBasePos
+ nDirection
; // bounds are handled below
3297 OSL_ENSURE( nDirection
== 1 || nDirection
== -1, "Direction must be 1 or -1" );
3301 // search for named member
3303 const ScDPResultMember
* pRowMember
= maMemberArray
[GetSortedIndex(nMemberIndex
)];
3305 //! use ScDPItemData, as in ScDPDimension::IsValidPage?
3306 while ( pRowMember
&& pRowMember
->GetName() != *pName
)
3309 if ( nMemberIndex
< nMemberCount
)
3310 pRowMember
= maMemberArray
[GetSortedIndex(nMemberIndex
)];
3316 bool bContinue
= true;
3317 while ( bContinue
&& nMemberIndex
>= 0 && nMemberIndex
< nMemberCount
)
3319 const ScDPResultMember
* pRowMember
= maMemberArray
[GetSortedIndex(nMemberIndex
)];
3321 // get child members by given indexes
3323 const long* pNextRowIndex
= pRowIndexes
;
3324 while ( *pNextRowIndex
>= 0 && pRowMember
)
3326 const ScDPResultDimension
* pRowChild
= pRowMember
->GetChildDimension();
3327 if ( pRowChild
&& *pNextRowIndex
< pRowChild
->GetMemberCount() )
3328 pRowMember
= pRowChild
->GetMember( *pNextRowIndex
);
3334 if ( pRowMember
&& pRelativePos
)
3336 // Skip the member if it has hidden details
3337 // (because when looking for the details, it is skipped, too).
3338 // Also skip if the member is invisible because it has no data,
3339 // for consistent ordering.
3340 if ( pRowMember
->HasHiddenDetails() || !pRowMember
->IsVisible() )
3346 pColMember
= pRowMember
->GetDataRoot();
3348 const long* pNextColIndex
= pColIndexes
;
3349 while ( *pNextColIndex
>= 0 && pColMember
)
3351 ScDPDataDimension
* pColChild
= pColMember
->GetChildDimension();
3352 if ( pColChild
&& *pNextColIndex
< pColChild
->GetMemberCount() )
3353 pColMember
= pColChild
->GetMember( *pNextColIndex
);
3360 // continue searching only if looking for first existing or relative position
3361 bContinue
= ( pColMember
== NULL
&& ( bFirstExisting
|| pRelativePos
) );
3362 nMemberIndex
+= nDirection
;
3368 ScDPDataMember
* ScDPResultDimension::GetColReferenceMember(
3369 const ScDPRelativePos
* pRelativePos
, const OUString
* pName
,
3370 long nRefDimPos
, const ScDPRunningTotalState
& rRunning
)
3372 OSL_ENSURE( pRelativePos
== NULL
|| pName
== NULL
, "can't use position and name" );
3374 const long* pColIndexes
= &rRunning
.GetColSorted()[0];
3375 const long* pRowIndexes
= &rRunning
.GetRowSorted()[0];
3377 // get own row member using all indexes
3379 const ScDPResultMember
* pRowMember
= rRunning
.GetRowResRoot();
3380 ScDPDataMember
* pColMember
= NULL
;
3382 const long* pNextRowIndex
= pRowIndexes
;
3383 while ( *pNextRowIndex
>= 0 && pRowMember
)
3385 const ScDPResultDimension
* pRowChild
= pRowMember
->GetChildDimension();
3386 if ( pRowChild
&& *pNextRowIndex
< pRowChild
->GetMemberCount() )
3387 pRowMember
= pRowChild
->GetMember( *pNextRowIndex
);
3393 // get column (data) members before the reference field
3394 //! pass rRowParent from ScDPDataMember::UpdateRunningTotals instead
3398 pColMember
= pRowMember
->GetDataRoot();
3400 const long* pNextColIndex
= pColIndexes
;
3401 long nColSkipped
= 0;
3402 while ( *pNextColIndex
>= 0 && pColMember
&& nColSkipped
< nRefDimPos
)
3404 ScDPDataDimension
* pColChild
= pColMember
->GetChildDimension();
3405 if ( pColChild
&& *pNextColIndex
< pColChild
->GetMemberCount() )
3406 pColMember
= pColChild
->GetMember( *pNextColIndex
);
3414 // get column member for the reference field
3418 ScDPDataDimension
* pReferenceDim
= pColMember
->GetChildDimension();
3419 if ( pReferenceDim
)
3421 long nReferenceCount
= pReferenceDim
->GetMemberCount();
3423 bool bFirstExisting
= ( pRelativePos
== NULL
&& pName
== NULL
);
3424 long nMemberIndex
= 0; // unsorted
3425 long nDirection
= 1; // forward if no relative position is used
3426 pColMember
= NULL
; // don't use parent dimension's member if none found
3429 nDirection
= pRelativePos
->nDirection
;
3430 nMemberIndex
= pRelativePos
->nBasePos
+ nDirection
; // bounds are handled below
3434 // search for named member
3436 pColMember
= pReferenceDim
->GetMember( pReferenceDim
->GetSortedIndex( nMemberIndex
) );
3438 //! use ScDPItemData, as in ScDPDimension::IsValidPage?
3439 while ( pColMember
&& pColMember
->GetName() != *pName
)
3442 if ( nMemberIndex
< nReferenceCount
)
3443 pColMember
= pReferenceDim
->GetMember( pReferenceDim
->GetSortedIndex( nMemberIndex
) );
3449 bool bContinue
= true;
3450 while ( bContinue
&& nMemberIndex
>= 0 && nMemberIndex
< nReferenceCount
)
3452 pColMember
= pReferenceDim
->GetMember( pReferenceDim
->GetSortedIndex( nMemberIndex
) );
3454 // get column members below the reference field
3456 const long* pNextColIndex
= pColIndexes
+ nRefDimPos
+ 1;
3457 while ( *pNextColIndex
>= 0 && pColMember
)
3459 ScDPDataDimension
* pColChild
= pColMember
->GetChildDimension();
3460 if ( pColChild
&& *pNextColIndex
< pColChild
->GetMemberCount() )
3461 pColMember
= pColChild
->GetMember( *pNextColIndex
);
3467 if ( pColMember
&& pRelativePos
)
3469 // Skip the member if it has hidden details
3470 // (because when looking for the details, it is skipped, too).
3471 // Also skip if the member is invisible because it has no data,
3472 // for consistent ordering.
3473 if ( pColMember
->HasHiddenDetails() || !pColMember
->IsVisible() )
3477 // continue searching only if looking for first existing or relative position
3478 bContinue
= ( pColMember
== NULL
&& ( bFirstExisting
|| pRelativePos
) );
3479 nMemberIndex
+= nDirection
;
3489 #if DEBUG_PIVOT_TABLE
3490 void ScDPResultDimension::DumpState( const ScDPResultMember
* pRefMember
, ScDocument
* pDoc
, ScAddress
& rPos
) const
3492 OUString aDimName
= bIsDataLayout
? OUString("(data layout)") : OUString(GetName());
3493 lcl_DumpRow( OUString("ScDPResultDimension"), aDimName
, NULL
, pDoc
, rPos
);
3495 SCROW nStartRow
= rPos
.Row();
3497 long nCount
= bIsDataLayout
? 1 : maMemberArray
.size();
3498 for (long i
=0; i
<nCount
; i
++)
3500 const ScDPResultMember
* pMember
= maMemberArray
[i
];
3501 pMember
->DumpState( pRefMember
, pDoc
, rPos
);
3504 lcl_Indent( pDoc
, nStartRow
, rPos
);
3507 void ScDPResultDimension::Dump(int nIndent
) const
3509 std::string
aIndent(nIndent
*2, ' ');
3510 std::cout
<< aIndent
<< "-- dimension '" << GetName() << "'" << std::endl
;
3511 MemberArray::const_iterator it
= maMemberArray
.begin(), itEnd
= maMemberArray
.end();
3512 for (; it
!= itEnd
; ++it
)
3514 const ScDPResultMember
* p
= *it
;
3520 long ScDPResultDimension::GetMemberCount() const
3522 return maMemberArray
.size();
3525 const ScDPResultMember
* ScDPResultDimension::GetMember(long n
) const
3527 return maMemberArray
[n
];
3529 ScDPResultMember
* ScDPResultDimension::GetMember(long n
)
3531 return maMemberArray
[n
];
3534 ScDPResultDimension
* ScDPResultDimension::GetFirstChildDimension() const
3536 if ( maMemberArray
.size() > 0 )
3537 return maMemberArray
[0]->GetChildDimension();
3542 void ScDPResultDimension::FillVisibilityData(ScDPResultVisibilityData
& rData
) const
3547 MemberArray::const_iterator itr
= maMemberArray
.begin(), itrEnd
= maMemberArray
.end();
3549 for (;itr
!= itrEnd
; ++itr
)
3551 ScDPResultMember
* pMember
= *itr
;
3552 if (pMember
->IsValid())
3555 pMember
->FillItemData(aItem
);
3556 rData
.addVisibleMember(GetName(), aItem
);
3557 pMember
->FillVisibilityData(rData
);
3562 // -----------------------------------------------------------------------
3564 ScDPDataDimension::ScDPDataDimension( const ScDPResultData
* pData
) :
3565 pResultData( pData
),
3566 pResultDimension( NULL
),
3567 bIsDataLayout( false )
3571 ScDPDataDimension::~ScDPDataDimension()
3573 std::for_each(maMembers
.begin(), maMembers
.end(), ScDeleteObjectByPtr
<ScDPDataMember
>());
3576 void ScDPDataDimension::InitFrom( const ScDPResultDimension
* pDim
)
3581 pResultDimension
= pDim
;
3582 bIsDataLayout
= pDim
->IsDataLayout();
3584 // Go through all result members under the given result dimension, and
3585 // create a new data member instance for each result member.
3586 long nCount
= pDim
->GetMemberCount();
3587 for (long i
=0; i
<nCount
; i
++)
3589 const ScDPResultMember
* pResMem
= pDim
->GetMember(i
);
3591 ScDPDataMember
* pNew
= new ScDPDataMember( pResultData
, pResMem
);
3592 maMembers
.push_back( pNew
);
3594 if ( !pResultData
->IsLateInit() )
3596 // with LateInit, pResMem hasn't necessarily been initialized yet,
3597 // so InitFrom for the new result member is called from its ProcessData method
3599 const ScDPResultDimension
* pChildDim
= pResMem
->GetChildDimension();
3601 pNew
->InitFrom( pChildDim
);
3606 void ScDPDataDimension::ProcessData( const vector
< SCROW
>& aDataMembers
, const vector
<ScDPValue
>& aValues
,
3607 const ScDPSubTotalState
& rSubState
)
3609 // the ScDPItemData array must contain enough entries for all dimensions - this isn't checked
3611 long nCount
= maMembers
.size();
3612 for (long i
=0; i
<nCount
; i
++)
3614 ScDPDataMember
* pMember
= maMembers
[(sal_uInt16
)i
];
3616 // always first member for data layout dim
3617 if ( bIsDataLayout
|| ( !aDataMembers
.empty() && pMember
->IsNamedItem(aDataMembers
[0]) ) )
3619 vector
<SCROW
> aChildDataMembers
;
3620 if (aDataMembers
.size() > 1)
3622 vector
<SCROW
>::const_iterator itr
= aDataMembers
.begin();
3623 aChildDataMembers
.insert(aChildDataMembers
.begin(), ++itr
, aDataMembers
.end());
3625 pMember
->ProcessData( aChildDataMembers
, aValues
, rSubState
);
3630 OSL_FAIL("ProcessData: Member not found");
3633 void ScDPDataDimension::FillDataRow(
3634 const ScDPResultDimension
* pRefDim
, ScDPResultFilterContext
& rFilterCxt
,
3635 uno::Sequence
<sheet::DataResult
>& rSequence
, long nMeasure
, bool bIsSubTotalRow
,
3636 const ScDPSubTotalState
& rSubState
) const
3639 bool bDataLayout
= false;
3640 if (pResultDimension
)
3642 aDimName
= pResultDimension
->GetName();
3643 bDataLayout
= pResultDimension
->IsDataLayout();
3646 FilterStack
aFilterStack(rFilterCxt
.maFilters
);
3647 aFilterStack
.pushDimName(aDimName
, bDataLayout
);
3649 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3650 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3652 const ScMemberSortOrder
& rMemberOrder
= pRefDim
->GetMemberOrder();
3654 long nMemberMeasure
= nMeasure
;
3655 long nCount
= maMembers
.size();
3656 for (long i
=0; i
<nCount
; i
++)
3658 long nSorted
= rMemberOrder
.empty() ? i
: rMemberOrder
[i
];
3660 long nMemberPos
= nSorted
;
3663 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3664 "DataLayout dimension twice?");
3666 nMemberMeasure
= nSorted
;
3669 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(nMemberPos
);
3670 if ( pRefMember
->IsVisible() ) //! here or in ScDPDataMember::FillDataRow ???
3672 const ScDPDataMember
* pDataMember
= maMembers
[(sal_uInt16
)nMemberPos
];
3673 pDataMember
->FillDataRow(pRefMember
, rFilterCxt
, rSequence
, nMemberMeasure
, bIsSubTotalRow
, rSubState
);
3678 void ScDPDataDimension::UpdateDataRow( const ScDPResultDimension
* pRefDim
,
3679 long nMeasure
, bool bIsSubTotalRow
,
3680 const ScDPSubTotalState
& rSubState
) const
3682 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3683 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3685 long nMemberMeasure
= nMeasure
;
3686 long nCount
= maMembers
.size();
3687 for (long i
=0; i
<nCount
; i
++)
3689 long nMemberPos
= i
;
3692 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3693 "DataLayout dimension twice?");
3698 // Calculate must be called even if the member is not visible (for use as reference value)
3699 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(nMemberPos
);
3700 ScDPDataMember
* pDataMember
= maMembers
[(sal_uInt16
)nMemberPos
];
3701 pDataMember
->UpdateDataRow( pRefMember
, nMemberMeasure
, bIsSubTotalRow
, rSubState
);
3705 void ScDPDataDimension::SortMembers( ScDPResultDimension
* pRefDim
)
3707 long nCount
= maMembers
.size();
3709 if ( pRefDim
->IsSortByData() )
3713 ScMemberSortOrder
& rMemberOrder
= pRefDim
->GetMemberOrder();
3714 OSL_ENSURE( rMemberOrder
.empty(), "sort twice?" );
3715 rMemberOrder
.resize( nCount
);
3716 for (long nPos
=0; nPos
<nCount
; nPos
++)
3717 rMemberOrder
[nPos
] = nPos
;
3719 ScDPColMembersOrder
aComp( *this, pRefDim
->GetSortMeasure(), pRefDim
->IsSortAscending() );
3720 ::std::sort( rMemberOrder
.begin(), rMemberOrder
.end(), aComp
);
3725 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3726 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3728 // for data layout, call only once - sorting measure is always taken from settings
3729 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3730 for (long i
=0; i
<nLoopCount
; i
++)
3732 ScDPResultMember
* pRefMember
= pRefDim
->GetMember(i
);
3733 if ( pRefMember
->IsVisible() ) //! here or in ScDPDataMember ???
3735 ScDPDataMember
* pDataMember
= maMembers
[(sal_uInt16
)i
];
3736 pDataMember
->SortMembers( pRefMember
);
3741 void ScDPDataDimension::DoAutoShow( ScDPResultDimension
* pRefDim
)
3743 long nCount
= maMembers
.size();
3745 // handle children first, before changing the visible state
3747 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3748 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3750 // for data layout, call only once - sorting measure is always taken from settings
3751 long nLoopCount
= bIsDataLayout
? 1 : nCount
;
3752 for (long i
=0; i
<nLoopCount
; i
++)
3754 ScDPResultMember
* pRefMember
= pRefDim
->GetMember(i
);
3755 if ( pRefMember
->IsVisible() ) //! here or in ScDPDataMember ???
3757 ScDPDataMember
* pDataMember
= maMembers
[i
];
3758 pDataMember
->DoAutoShow( pRefMember
);
3762 if ( pRefDim
->IsAutoShow() && pRefDim
->GetAutoCount() > 0 && pRefDim
->GetAutoCount() < nCount
)
3764 // establish temporary order, hide remaining members
3766 ScMemberSortOrder aAutoOrder
;
3767 aAutoOrder
.resize( nCount
);
3769 for (nPos
=0; nPos
<nCount
; nPos
++)
3770 aAutoOrder
[nPos
] = nPos
;
3772 ScDPColMembersOrder
aComp( *this, pRefDim
->GetAutoMeasure(), !pRefDim
->IsAutoTopItems() );
3773 ::std::sort( aAutoOrder
.begin(), aAutoOrder
.end(), aComp
);
3775 // look for equal values to the last included one
3777 long nIncluded
= pRefDim
->GetAutoCount();
3778 ScDPDataMember
* pDataMember1
= maMembers
[aAutoOrder
[nIncluded
- 1]];
3779 if ( !pDataMember1
->IsVisible() )
3780 pDataMember1
= NULL
;
3781 bool bContinue
= true;
3785 if ( nIncluded
< nCount
)
3787 ScDPDataMember
* pDataMember2
= maMembers
[aAutoOrder
[nIncluded
]];
3788 if ( !pDataMember2
->IsVisible() )
3789 pDataMember2
= NULL
;
3791 if ( lcl_IsEqual( pDataMember1
, pDataMember2
, pRefDim
->GetAutoMeasure() ) )
3793 ++nIncluded
; // include more members if values are equal
3799 // hide the remaining members
3801 for (nPos
= nIncluded
; nPos
< nCount
; nPos
++)
3803 ScDPResultMember
* pMember
= pRefDim
->GetMember(aAutoOrder
[nPos
]);
3804 pMember
->SetAutoHidden();
3809 void ScDPDataDimension::ResetResults()
3811 long nCount
= maMembers
.size();
3812 for (long i
=0; i
<nCount
; i
++)
3814 // sort order doesn't matter
3816 long nMemberPos
= bIsDataLayout
? 0 : i
;
3817 ScDPDataMember
* pDataMember
= maMembers
[nMemberPos
];
3818 pDataMember
->ResetResults();
3822 long ScDPDataDimension::GetSortedIndex( long nUnsorted
) const
3824 if (!pResultDimension
)
3827 const ScMemberSortOrder
& rMemberOrder
= pResultDimension
->GetMemberOrder();
3828 return rMemberOrder
.empty() ? nUnsorted
: rMemberOrder
[nUnsorted
];
3831 void ScDPDataDimension::UpdateRunningTotals( const ScDPResultDimension
* pRefDim
,
3832 long nMeasure
, bool bIsSubTotalRow
,
3833 const ScDPSubTotalState
& rSubState
, ScDPRunningTotalState
& rRunning
,
3834 ScDPRowTotals
& rTotals
, const ScDPResultMember
& rRowParent
) const
3836 OSL_ENSURE( pRefDim
&& static_cast<size_t>(pRefDim
->GetMemberCount()) == maMembers
.size(), "dimensions don't match" );
3837 OSL_ENSURE( pRefDim
== pResultDimension
, "wrong dim" );
3839 long nMemberMeasure
= nMeasure
;
3840 long nCount
= maMembers
.size();
3841 for (long i
=0; i
<nCount
; i
++)
3843 const ScMemberSortOrder
& rMemberOrder
= pRefDim
->GetMemberOrder();
3844 long nSorted
= rMemberOrder
.empty() ? i
: rMemberOrder
[i
];
3846 long nMemberPos
= nSorted
;
3849 OSL_ENSURE(nMeasure
== SC_DPMEASURE_ALL
|| pResultData
->GetMeasureCount() == 1,
3850 "DataLayout dimension twice?");
3852 nMemberMeasure
= nSorted
;
3855 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(nMemberPos
);
3856 if ( pRefMember
->IsVisible() )
3858 if ( bIsDataLayout
)
3859 rRunning
.AddColIndex( 0, 0 );
3861 rRunning
.AddColIndex( i
, nSorted
);
3863 ScDPDataMember
* pDataMember
= maMembers
[nMemberPos
];
3864 pDataMember
->UpdateRunningTotals(
3865 pRefMember
, nMemberMeasure
, bIsSubTotalRow
, rSubState
, rRunning
, rTotals
, rRowParent
);
3867 rRunning
.RemoveColIndex();
3872 #if DEBUG_PIVOT_TABLE
3873 void ScDPDataDimension::DumpState( const ScDPResultDimension
* pRefDim
, ScDocument
* pDoc
, ScAddress
& rPos
) const
3875 OUString aDimName
= bIsDataLayout
? OUString("(data layout)") : OUString("(unknown)");
3876 lcl_DumpRow( OUString("ScDPDataDimension"), aDimName
, NULL
, pDoc
, rPos
);
3878 SCROW nStartRow
= rPos
.Row();
3880 long nCount
= bIsDataLayout
? 1 : maMembers
.size();
3881 for (long i
=0; i
<nCount
; i
++)
3883 const ScDPResultMember
* pRefMember
= pRefDim
->GetMember(i
);
3884 const ScDPDataMember
* pDataMember
= maMembers
[i
];
3885 pDataMember
->DumpState( pRefMember
, pDoc
, rPos
);
3888 lcl_Indent( pDoc
, nStartRow
, rPos
);
3891 void ScDPDataDimension::Dump(int nIndent
) const
3893 std::string
aIndent(nIndent
*2, ' ');
3894 std::cout
<< aIndent
<< "-- data dimension '"
3895 << (pResultDimension
? pResultDimension
->GetName() : OUString()) << "'" << std::endl
;
3896 ScDPDataMembers::const_iterator it
= maMembers
.begin(), itEnd
= maMembers
.end();
3897 for (; it
!= itEnd
; ++it
)
3898 (*it
)->Dump(nIndent
+1);
3902 long ScDPDataDimension::GetMemberCount() const
3904 return maMembers
.size();
3907 const ScDPDataMember
* ScDPDataDimension::GetMember(long n
) const
3909 return maMembers
[n
];
3912 ScDPDataMember
* ScDPDataDimension::GetMember(long n
)
3914 return maMembers
[n
];
3917 // ----------------------------------------------------------------------------
3919 ScDPResultVisibilityData::ScDPResultVisibilityData(
3920 ScDPSource
* pSource
) :
3925 ScDPResultVisibilityData::~ScDPResultVisibilityData()
3929 void ScDPResultVisibilityData::addVisibleMember(const OUString
& rDimName
, const ScDPItemData
& rMemberItem
)
3931 DimMemberType::iterator itr
= maDimensions
.find(rDimName
);
3932 if (itr
== maDimensions
.end())
3934 pair
<DimMemberType::iterator
, bool> r
= maDimensions
.insert(
3935 DimMemberType::value_type(rDimName
, VisibleMemberType()));
3938 // insertion failed.
3943 VisibleMemberType
& rMem
= itr
->second
;
3944 VisibleMemberType::iterator itrMem
= rMem
.find(rMemberItem
);
3945 if (itrMem
== rMem
.end())
3946 rMem
.insert(rMemberItem
);
3949 void ScDPResultVisibilityData::fillFieldFilters(vector
<ScDPFilteredCache::Criterion
>& rFilters
) const
3951 typedef boost::unordered_map
<OUString
, long, OUStringHash
> FieldNameMapType
;
3952 FieldNameMapType aFieldNames
;
3953 ScDPTableData
* pData
= mpSource
->GetData();
3954 long nColumnCount
= pData
->GetColumnCount();
3955 for (long i
= 0; i
< nColumnCount
; ++i
)
3958 FieldNameMapType::value_type(pData
->getDimensionName(i
), i
));
3961 const ScDPDimensions
* pDims
= mpSource
->GetDimensionsObject();
3962 for (DimMemberType::const_iterator itr
= maDimensions
.begin(), itrEnd
= maDimensions
.end();
3963 itr
!= itrEnd
; ++itr
)
3965 const OUString
& rDimName
= itr
->first
;
3966 ScDPFilteredCache::Criterion aCri
;
3967 FieldNameMapType::const_iterator itrField
= aFieldNames
.find(rDimName
);
3968 if (itrField
== aFieldNames
.end())
3969 // This should never happen!
3972 long nDimIndex
= itrField
->second
;
3973 aCri
.mnFieldIndex
= static_cast<sal_Int32
>(nDimIndex
);
3974 aCri
.mpFilter
.reset(new ScDPFilteredCache::GroupFilter
);
3976 ScDPFilteredCache::GroupFilter
* pGrpFilter
=
3977 static_cast<ScDPFilteredCache::GroupFilter
*>(aCri
.mpFilter
.get());
3979 const VisibleMemberType
& rMem
= itr
->second
;
3980 for (VisibleMemberType::const_iterator itrMem
= rMem
.begin(), itrMemEnd
= rMem
.end();
3981 itrMem
!= itrMemEnd
; ++itrMem
)
3983 const ScDPItemData
& rMemItem
= *itrMem
;
3984 pGrpFilter
->addMatchItem(rMemItem
);
3987 ScDPDimension
* pDim
= pDims
->getByIndex(nDimIndex
);
3988 ScDPMembers
* pMembers
= pDim
->GetHierarchiesObject()->getByIndex(0)->
3989 GetLevelsObject()->getByIndex(0)->GetMembersObject();
3990 if (pGrpFilter
->getMatchItemCount() < static_cast<size_t>(pMembers
->getCount()))
3991 rFilters
.push_back(aCri
);
3995 size_t ScDPResultVisibilityData::MemberHash::operator() (const ScDPItemData
& r
) const
3998 return static_cast<size_t>(::rtl::math::approxFloor(r
.GetValue()));
4000 return r
.GetString().hashCode();
4002 SCROW
ScDPResultMember::GetDataId( ) const
4004 const ScDPMember
* pMemberDesc
= GetDPMember();
4006 return pMemberDesc
->GetItemDataId();
4010 ScDPResultMember
* ScDPResultDimension::AddMember(const ScDPParentDimData
&aData
)
4012 ScDPResultMember
* pMember
= new ScDPResultMember( pResultData
, aData
, false );
4013 SCROW nDataIndex
= pMember
->GetDataId();
4014 maMemberArray
.push_back( pMember
);
4016 if ( maMemberHash
.end() == maMemberHash
.find( nDataIndex
) )
4017 maMemberHash
.insert( std::pair
< SCROW
, ScDPResultMember
*>( nDataIndex
, pMember
) );
4021 ScDPResultMember
* ScDPResultDimension::InsertMember(ScDPParentDimData
*pMemberData
)
4024 if ( !lcl_SearchMember( maMemberArray
, pMemberData
->mnOrder
, nInsert
) )
4026 ScDPResultMember
* pNew
= new ScDPResultMember( pResultData
, *pMemberData
, false );
4027 maMemberArray
.insert( maMemberArray
.begin()+nInsert
, pNew
);
4029 SCROW nDataIndex
= pMemberData
->mpMemberDesc
->GetItemDataId();
4030 if ( maMemberHash
.end() == maMemberHash
.find( nDataIndex
) )
4031 maMemberHash
.insert( std::pair
< SCROW
, ScDPResultMember
*>( nDataIndex
, pNew
) );
4034 return maMemberArray
[ nInsert
];
4037 void ScDPResultDimension::InitWithMembers(
4038 LateInitParams
& rParams
, const std::vector
<SCROW
>& pItemData
, size_t nPos
,
4039 ScDPInitState
& rInitState
)
4041 if ( rParams
.IsEnd( nPos
) )
4043 ScDPDimension
* pThisDim
= rParams
.GetDim( nPos
);
4044 ScDPLevel
* pThisLevel
= rParams
.GetLevel( nPos
);
4045 SCROW nDataID
= pItemData
[nPos
];
4047 if (pThisDim
&& pThisLevel
)
4049 long nDimSource
= pThisDim
->GetDimension(); //! check GetSourceDim?
4051 // create all members at the first call (preserve order)
4052 ResultMembers
* pMembers
= pResultData
->GetDimResultMembers(nDimSource
, pThisDim
, pThisLevel
);
4053 ScDPGroupCompare
aCompare( pResultData
, rInitState
, nDimSource
);
4054 // initialize only specific member (or all if "show empty" flag is set)
4055 ScDPResultMember
* pResultMember
= NULL
;
4057 pResultMember
= FindMember( nDataID
);
4059 bInitialized
= true;
4061 if ( pResultMember
== NULL
)
4062 { //only insert found item
4063 ScDPParentDimData
* pMemberData
= pMembers
->FindMember( nDataID
);
4064 if ( pMemberData
&& aCompare
.IsIncluded( *( pMemberData
->mpMemberDesc
) ) )
4065 pResultMember
= InsertMember( pMemberData
);
4067 if ( pResultMember
)
4069 rInitState
.AddMember( nDimSource
, pResultMember
->GetDataId() );
4070 pResultMember
->LateInitFrom(rParams
, pItemData
, nPos
+1, rInitState
);
4071 rInitState
.RemoveMember();
4076 ScDPParentDimData::ScDPParentDimData() :
4077 mnOrder(-1), mpParentDim(NULL
), mpParentLevel(NULL
), mpMemberDesc(NULL
) {}
4079 ScDPParentDimData::ScDPParentDimData(
4080 SCROW nIndex
, const ScDPDimension
* pDim
, const ScDPLevel
* pLev
, const ScDPMember
* pMember
) :
4081 mnOrder(nIndex
), mpParentDim(pDim
), mpParentLevel(pLev
), mpMemberDesc(pMember
) {}
4083 ScDPParentDimData
* ResultMembers::FindMember( SCROW nIndex
) const
4085 DimMemberHash::const_iterator aRes
= maMemberHash
.find( nIndex
);
4086 if( aRes
!= maMemberHash
.end()) {
4087 if ( aRes
->second
->mpMemberDesc
&& aRes
->second
->mpMemberDesc
->GetItemDataId()==nIndex
)
4088 return aRes
->second
;
4092 void ResultMembers::InsertMember( ScDPParentDimData
* pNew
)
4094 if ( !pNew
->mpMemberDesc
->getShowDetails() )
4095 mbHasHideDetailsMember
= true;
4096 maMemberHash
.insert( std::pair
< const SCROW
, ScDPParentDimData
*>( pNew
->mpMemberDesc
->GetItemDataId(), pNew
) );
4099 ResultMembers::ResultMembers():
4100 mbHasHideDetailsMember( false )
4103 ResultMembers::~ResultMembers()
4105 for ( DimMemberHash::const_iterator iter
= maMemberHash
.begin(); iter
!= maMemberHash
.end(); ++iter
)
4106 delete iter
->second
;
4108 // -----------------------------------------------------------------------
4109 LateInitParams::LateInitParams(
4110 const vector
<ScDPDimension
*>& ppDim
, const vector
<ScDPLevel
*>& ppLev
, bool bRow
, bool bInitChild
, bool bAllChildren
) :
4114 mbInitChild( bInitChild
),
4115 mbAllChildren( bAllChildren
)
4119 LateInitParams::~LateInitParams()
4123 bool LateInitParams::IsEnd( size_t nPos
) const
4125 return nPos
>= mppDim
.size();
4128 void ScDPResultDimension::CheckShowEmpty( bool bShow
)
4130 long nCount
= maMemberArray
.size();
4132 ScDPResultMember
* pMember
= NULL
;
4133 for (long i
=0; i
<nCount
; i
++)
4135 pMember
= maMemberArray
.at(i
);
4136 pMember
->CheckShowEmpty(bShow
);
4141 void ScDPResultMember::CheckShowEmpty( bool bShow
)
4145 ScDPResultDimension
* pChildDim
= GetChildDimension();
4147 pChildDim
->CheckShowEmpty();
4149 else if (IsValid() && bInitialized
)
4151 bShow
= bShow
|| (GetParentLevel() && GetParentLevel()->getShowEmpty());
4155 ScDPResultDimension
* pChildDim
= GetChildDimension();
4157 pChildDim
->CheckShowEmpty(true);
4162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */