LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sc/source/core/data - dptabres.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1440 1917 75.1 %
Date: 2013-07-09 Functions: 157 175 89.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10