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

Generated by: LCOV version 1.11