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

Generated by: LCOV version 1.10