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

Generated by: LCOV version 1.10