LCOV - code coverage report
Current view: top level - sc/source/core/data - dpsave.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 556 751 74.0 %
Date: 2014-04-11 Functions: 69 94 73.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "dpsave.hxx"
      21             : #include "dpdimsave.hxx"
      22             : #include "miscuno.hxx"
      23             : #include "scerrors.hxx"
      24             : #include "unonames.hxx"
      25             : #include "global.hxx"
      26             : #include "dptabsrc.hxx"
      27             : #include "dputil.hxx"
      28             : 
      29             : #include <sal/types.h>
      30             : #include "comphelper/string.hxx"
      31             : 
      32             : #include <com/sun/star/sheet/GeneralFunction.hpp>
      33             : #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
      34             : #include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
      35             : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
      36             : #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
      37             : #include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
      38             : #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
      39             : #include <com/sun/star/sheet/TableFilterField.hpp>
      40             : #include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
      41             : #include <com/sun/star/sheet/XLevelsSupplier.hpp>
      42             : #include <com/sun/star/sheet/XMembersSupplier.hpp>
      43             : #include <com/sun/star/container/XNamed.hpp>
      44             : #include <com/sun/star/util/XCloneable.hpp>
      45             : 
      46             : #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
      47             : #include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
      48             : 
      49             : #include <boost/unordered_map.hpp>
      50             : #include <boost/unordered_set.hpp>
      51             : 
      52             : using namespace com::sun::star;
      53             : using namespace com::sun::star::sheet;
      54             : using ::com::sun::star::uno::Reference;
      55             : using ::com::sun::star::uno::Any;
      56             : using ::std::auto_ptr;
      57             : 
      58             : #define SC_DPSAVEMODE_DONTKNOW 2
      59             : 
      60        1035 : static void lcl_SetBoolProperty( const uno::Reference<beans::XPropertySet>& xProp,
      61             :                             const OUString& rName, sal_Bool bValue )
      62             : {
      63             :     //! move to ScUnoHelpFunctions?
      64             : 
      65        1035 :     xProp->setPropertyValue( rName, uno::Any( &bValue, getBooleanCppuType() ) );
      66        1035 : }
      67             : 
      68        3717 : ScDPSaveMember::ScDPSaveMember(const OUString& rName) :
      69             :     aName( rName ),
      70             :     mpLayoutName(NULL),
      71             :     nVisibleMode( SC_DPSAVEMODE_DONTKNOW ),
      72        3717 :     nShowDetailsMode( SC_DPSAVEMODE_DONTKNOW )
      73             : {
      74        3717 : }
      75             : 
      76        3521 : ScDPSaveMember::ScDPSaveMember(const ScDPSaveMember& r) :
      77             :     aName( r.aName ),
      78             :     mpLayoutName(NULL),
      79             :     nVisibleMode( r.nVisibleMode ),
      80        3521 :     nShowDetailsMode( r.nShowDetailsMode )
      81             : {
      82        3521 :     if (r.mpLayoutName)
      83           0 :         mpLayoutName.reset(new OUString(*r.mpLayoutName));
      84        3521 : }
      85             : 
      86        7238 : ScDPSaveMember::~ScDPSaveMember()
      87             : {
      88        7238 : }
      89             : 
      90           0 : bool ScDPSaveMember::operator== ( const ScDPSaveMember& r ) const
      91             : {
      92           0 :     if ( aName            != r.aName           ||
      93           0 :          nVisibleMode     != r.nVisibleMode    ||
      94           0 :          nShowDetailsMode != r.nShowDetailsMode )
      95           0 :         return false;
      96             : 
      97           0 :     return true;
      98             : }
      99             : 
     100           7 : bool ScDPSaveMember::HasIsVisible() const
     101             : {
     102           7 :     return nVisibleMode != SC_DPSAVEMODE_DONTKNOW;
     103             : }
     104             : 
     105        3755 : void ScDPSaveMember::SetIsVisible(bool bSet)
     106             : {
     107        3755 :     nVisibleMode = sal_uInt16(bSet);
     108        3755 : }
     109             : 
     110           6 : bool ScDPSaveMember::HasShowDetails() const
     111             : {
     112           6 :     return nShowDetailsMode != SC_DPSAVEMODE_DONTKNOW;
     113             : }
     114             : 
     115        2926 : void ScDPSaveMember::SetShowDetails(bool bSet)
     116             : {
     117        2926 :     nShowDetailsMode = sal_uInt16(bSet);
     118        2926 : }
     119             : 
     120           0 : void ScDPSaveMember::SetName( const OUString& rNew )
     121             : {
     122             :     // Used only if the source member was renamed (groups).
     123             :     // For UI renaming of members, a layout name must be used.
     124             : 
     125           0 :     aName = rNew;
     126           0 : }
     127             : 
     128           0 : void ScDPSaveMember::SetLayoutName( const OUString& rName )
     129             : {
     130           0 :     mpLayoutName.reset(new OUString(rName));
     131           0 : }
     132             : 
     133           0 : const OUString* ScDPSaveMember::GetLayoutName() const
     134             : {
     135           0 :     return mpLayoutName.get();
     136             : }
     137             : 
     138           0 : void ScDPSaveMember::RemoveLayoutName()
     139             : {
     140           0 :     mpLayoutName.reset();
     141           0 : }
     142             : 
     143         261 : void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMember, sal_Int32 nPosition )
     144             : {
     145         261 :     uno::Reference<beans::XPropertySet> xMembProp( xMember, uno::UNO_QUERY );
     146             :     OSL_ENSURE( xMembProp.is(), "no properties at member" );
     147         261 :     if ( xMembProp.is() )
     148             :     {
     149             :         // exceptions are caught at ScDPSaveData::WriteToSource
     150             : 
     151         261 :         if ( nVisibleMode != SC_DPSAVEMODE_DONTKNOW )
     152             :             lcl_SetBoolProperty( xMembProp,
     153         261 :                     OUString(SC_UNO_DP_ISVISIBLE), (bool)nVisibleMode );
     154             : 
     155         261 :         if ( nShowDetailsMode != SC_DPSAVEMODE_DONTKNOW )
     156             :             lcl_SetBoolProperty( xMembProp,
     157         220 :                     OUString(SC_UNO_DP_SHOWDETAILS), (bool)nShowDetailsMode );
     158             : 
     159         261 :         if (mpLayoutName)
     160           0 :             ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, SC_UNO_DP_LAYOUTNAME, *mpLayoutName);
     161             : 
     162         261 :         if ( nPosition >= 0 )
     163          62 :             ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, SC_UNO_DP_POSITION, nPosition);
     164         261 :     }
     165         261 : }
     166             : 
     167             : #if DEBUG_PIVOT_TABLE
     168             : 
     169             : void ScDPSaveMember::Dump(int nIndent) const
     170             : {
     171             :     std::string aIndent(nIndent*4, ' ');
     172             :     cout << aIndent << "* member name: '" << aName << "'" << endl;
     173             : 
     174             :     cout << aIndent << "    + layout name: ";
     175             :     if (mpLayoutName)
     176             :         cout << "'" << *mpLayoutName << "'";
     177             :     else
     178             :         cout << "(none)";
     179             :     cout << endl;
     180             : 
     181             :     cout << aIndent << "    + visibility: ";
     182             :     if (nVisibleMode == SC_DPSAVEMODE_DONTKNOW)
     183             :         cout << "(unknown)";
     184             :     else
     185             :         cout << (nVisibleMode ? "visible" : "hidden");
     186             :     cout << endl;
     187             : }
     188             : 
     189             : #endif
     190             : 
     191         167 : ScDPSaveDimension::ScDPSaveDimension(const OUString& rName, bool bDataLayout) :
     192             :     aName( rName ),
     193             :     mpLayoutName(NULL),
     194             :     mpSubtotalName(NULL),
     195             :     bIsDataLayout( bDataLayout ),
     196             :     bDupFlag( false ),
     197             :     nOrientation( sheet::DataPilotFieldOrientation_HIDDEN ),
     198             :     nFunction( sheet::GeneralFunction_AUTO ),
     199             :     nUsedHierarchy( -1 ),
     200             :     nShowEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
     201             :     bSubTotalDefault( true ),
     202             :     nSubTotalCount( 0 ),
     203             :     pSubTotalFuncs( NULL ),
     204             :     pReferenceValue( NULL ),
     205             :     pSortInfo( NULL ),
     206             :     pAutoShowInfo( NULL ),
     207         167 :     pLayoutInfo( NULL )
     208             : {
     209         167 : }
     210             : 
     211         538 : ScDPSaveDimension::ScDPSaveDimension(const ScDPSaveDimension& r) :
     212             :     aName( r.aName ),
     213             :     mpLayoutName(NULL),
     214             :     mpSubtotalName(NULL),
     215             :     bIsDataLayout( r.bIsDataLayout ),
     216             :     bDupFlag( r.bDupFlag ),
     217             :     nOrientation( r.nOrientation ),
     218             :     nFunction( r.nFunction ),
     219             :     nUsedHierarchy( r.nUsedHierarchy ),
     220             :     nShowEmptyMode( r.nShowEmptyMode ),
     221             :     bSubTotalDefault( r.bSubTotalDefault ),
     222             :     nSubTotalCount( r.nSubTotalCount ),
     223         538 :     pSubTotalFuncs( NULL )
     224             : {
     225         538 :     if ( nSubTotalCount && r.pSubTotalFuncs )
     226             :     {
     227         108 :         pSubTotalFuncs = new sal_uInt16[nSubTotalCount];
     228         216 :         for (long nSub=0; nSub<nSubTotalCount; nSub++)
     229         108 :             pSubTotalFuncs[nSub] = r.pSubTotalFuncs[nSub];
     230             :     }
     231             : 
     232        4059 :     for (MemberList::const_iterator i=r.maMemberList.begin(); i != r.maMemberList.end() ; ++i)
     233             :     {
     234        3521 :         const OUString& rName =  (*i)->GetName();
     235        3521 :         ScDPSaveMember* pNew = new ScDPSaveMember( **i );
     236        3521 :         maMemberHash[rName] = pNew;
     237        3521 :         maMemberList.push_back( pNew );
     238             :     }
     239         538 :     if (r.pReferenceValue)
     240           9 :         pReferenceValue = new sheet::DataPilotFieldReference( *(r.pReferenceValue) );
     241             :     else
     242         529 :         pReferenceValue = NULL;
     243         538 :     if (r.pSortInfo)
     244         160 :         pSortInfo = new sheet::DataPilotFieldSortInfo( *(r.pSortInfo) );
     245             :     else
     246         378 :         pSortInfo = NULL;
     247         538 :     if (r.pAutoShowInfo)
     248         172 :         pAutoShowInfo = new sheet::DataPilotFieldAutoShowInfo( *(r.pAutoShowInfo) );
     249             :     else
     250         366 :         pAutoShowInfo = NULL;
     251         538 :     if (r.pLayoutInfo)
     252         166 :         pLayoutInfo = new sheet::DataPilotFieldLayoutInfo( *(r.pLayoutInfo) );
     253             :     else
     254         372 :         pLayoutInfo = NULL;
     255         538 :     if (r.mpLayoutName)
     256           2 :         mpLayoutName.reset(new OUString(*r.mpLayoutName));
     257         538 :     if (r.mpSubtotalName)
     258           0 :         mpSubtotalName.reset(new OUString(*r.mpSubtotalName));
     259         538 : }
     260             : 
     261        1404 : ScDPSaveDimension::~ScDPSaveDimension()
     262             : {
     263        7940 :     for (MemberHash::const_iterator i=maMemberHash.begin(); i != maMemberHash.end() ; ++i)
     264        7238 :         delete i->second;
     265         702 :     delete pReferenceValue;
     266         702 :     delete pSortInfo;
     267         702 :     delete pAutoShowInfo;
     268         702 :     delete pLayoutInfo;
     269         702 :     delete [] pSubTotalFuncs;
     270         702 : }
     271             : 
     272           0 : bool ScDPSaveDimension::operator== ( const ScDPSaveDimension& r ) const
     273             : {
     274           0 :     if ( aName            != r.aName            ||
     275           0 :          bIsDataLayout    != r.bIsDataLayout    ||
     276           0 :          bDupFlag         != r.bDupFlag         ||
     277           0 :          nOrientation     != r.nOrientation     ||
     278           0 :          nFunction        != r.nFunction        ||
     279           0 :          nUsedHierarchy   != r.nUsedHierarchy   ||
     280           0 :          nShowEmptyMode   != r.nShowEmptyMode   ||
     281           0 :          bSubTotalDefault != r.bSubTotalDefault ||
     282           0 :          nSubTotalCount   != r.nSubTotalCount    )
     283           0 :         return false;
     284             : 
     285           0 :     if ( nSubTotalCount && ( !pSubTotalFuncs || !r.pSubTotalFuncs ) ) // should not happen
     286           0 :         return false;
     287             : 
     288             :     long i;
     289           0 :     for (i=0; i<nSubTotalCount; i++)
     290           0 :         if ( pSubTotalFuncs[i] != r.pSubTotalFuncs[i] )
     291           0 :             return false;
     292             : 
     293           0 :     if (maMemberHash.size() != r.maMemberHash.size() )
     294           0 :         return false;
     295             : 
     296           0 :     MemberList::const_iterator a=maMemberList.begin();
     297           0 :     MemberList::const_iterator b=r.maMemberList.begin();
     298           0 :     for (; a != maMemberList.end() ; ++a, ++b)
     299           0 :         if (!(**a == **b))
     300           0 :             return false;
     301             : 
     302           0 :     if( pReferenceValue && r.pReferenceValue )
     303             :     {
     304           0 :         if ( !(*pReferenceValue == *r.pReferenceValue) )
     305             :         {
     306           0 :             return false;
     307             :         }
     308             :     }
     309           0 :     else if ( pReferenceValue || r.pReferenceValue )
     310             :     {
     311           0 :         return false;
     312             :     }
     313           0 :     if( this->pSortInfo && r.pSortInfo )
     314             :     {
     315           0 :         if ( !(*this->pSortInfo == *r.pSortInfo) )
     316             :         {
     317           0 :             return false;
     318             :         }
     319             :     }
     320           0 :     else if ( this->pSortInfo || r.pSortInfo )
     321             :     {
     322           0 :         return false;
     323             :     }
     324           0 :     if( this->pAutoShowInfo && r.pAutoShowInfo )
     325             :     {
     326           0 :         if ( !(*this->pAutoShowInfo == *r.pAutoShowInfo) )
     327             :         {
     328           0 :             return false;
     329             :         }
     330             :     }
     331           0 :     else if ( this->pAutoShowInfo || r.pAutoShowInfo )
     332             :     {
     333           0 :         return false;
     334             :     }
     335             : 
     336           0 :     return true;
     337             : }
     338             : 
     339        3708 : void ScDPSaveDimension::AddMember(ScDPSaveMember* pMember)
     340             : {
     341        3708 :     const OUString & rName = pMember->GetName();
     342        3708 :     MemberHash::iterator aExisting = maMemberHash.find( rName );
     343        3708 :     if ( aExisting == maMemberHash.end() )
     344             :     {
     345        3708 :         std::pair< const OUString, ScDPSaveMember *> key( rName, pMember );
     346        3708 :         maMemberHash.insert ( key );
     347             :     }
     348             :     else
     349             :     {
     350           0 :         maMemberList.remove( aExisting->second );
     351           0 :         delete aExisting->second;
     352           0 :         aExisting->second = pMember;
     353             :     }
     354        3708 :     maMemberList.push_back( pMember );
     355        3708 : }
     356             : 
     357           2 : void ScDPSaveDimension::SetName( const OUString& rNew )
     358             : {
     359             :     // Used only if the source dim was renamed (groups).
     360             :     // For UI renaming of dimensions, the layout name must be used.
     361             : 
     362           2 :     aName = rNew;
     363           2 : }
     364             : 
     365         175 : void ScDPSaveDimension::SetOrientation(sal_uInt16 nNew)
     366             : {
     367         175 :     nOrientation = nNew;
     368         175 : }
     369             : 
     370          21 : void ScDPSaveDimension::SetSubTotals(long nCount, const sal_uInt16* pFuncs)
     371             : {
     372          21 :     if (pSubTotalFuncs)
     373           3 :         delete [] pSubTotalFuncs;
     374          21 :     nSubTotalCount = nCount;
     375          21 :     if ( nCount && pFuncs )
     376             :     {
     377          20 :         pSubTotalFuncs = new sal_uInt16[nCount];
     378          40 :         for (long i=0; i<nCount; i++)
     379          40 :             pSubTotalFuncs[i] = pFuncs[i];
     380             :     }
     381             :     else
     382           1 :         pSubTotalFuncs = NULL;
     383             : 
     384          21 :     bSubTotalDefault = false;
     385          21 : }
     386             : 
     387           0 : bool ScDPSaveDimension::HasShowEmpty() const
     388             : {
     389           0 :     return nShowEmptyMode != SC_DPSAVEMODE_DONTKNOW;
     390             : }
     391             : 
     392          57 : void ScDPSaveDimension::SetShowEmpty(bool bSet)
     393             : {
     394          57 :     nShowEmptyMode = sal_uInt16(bSet);
     395          57 : }
     396             : 
     397          62 : void ScDPSaveDimension::SetFunction(sal_uInt16 nNew)
     398             : {
     399          62 :     nFunction = nNew;
     400          62 : }
     401             : 
     402          87 : void ScDPSaveDimension::SetUsedHierarchy(long nNew)
     403             : {
     404          87 :     nUsedHierarchy = nNew;
     405          87 : }
     406             : 
     407           0 : void ScDPSaveDimension::SetSubtotalName(const OUString& rName)
     408             : {
     409           0 :     mpSubtotalName.reset(new OUString(rName));
     410           0 : }
     411             : 
     412         296 : const OUString* ScDPSaveDimension::GetSubtotalName() const
     413             : {
     414         296 :     return mpSubtotalName.get();
     415             : }
     416             : 
     417           0 : void ScDPSaveDimension::RemoveSubtotalName()
     418             : {
     419           0 :     mpSubtotalName.reset();
     420           0 : }
     421             : 
     422           0 : bool ScDPSaveDimension::IsMemberNameInUse(const OUString& rName) const
     423             : {
     424           0 :     MemberList::const_iterator itr = maMemberList.begin(), itrEnd = maMemberList.end();
     425           0 :     for (; itr != itrEnd; ++itr)
     426             :     {
     427           0 :         const ScDPSaveMember* pMem = *itr;
     428           0 :         if (rName.equalsIgnoreAsciiCase(pMem->GetName()))
     429           0 :             return true;
     430             : 
     431           0 :         const OUString* pLayoutName = pMem->GetLayoutName();
     432           0 :         if (pLayoutName && rName.equalsIgnoreAsciiCase(*pLayoutName))
     433           0 :             return true;
     434             :     }
     435           0 :     return false;
     436             : }
     437             : 
     438           6 : void ScDPSaveDimension::SetLayoutName(const OUString& rName)
     439             : {
     440           6 :     mpLayoutName.reset(new OUString(rName));
     441           6 : }
     442             : 
     443          89 : const OUString* ScDPSaveDimension::GetLayoutName() const
     444             : {
     445          89 :     return mpLayoutName.get();
     446             : }
     447             : 
     448           0 : void ScDPSaveDimension::RemoveLayoutName()
     449             : {
     450           0 :     mpLayoutName.reset();
     451           0 : }
     452             : 
     453          30 : void ScDPSaveDimension::SetReferenceValue(const sheet::DataPilotFieldReference* pNew)
     454             : {
     455          30 :     delete pReferenceValue;
     456          30 :     if (pNew)
     457           7 :         pReferenceValue = new sheet::DataPilotFieldReference(*pNew);
     458             :     else
     459          23 :         pReferenceValue = NULL;
     460          30 : }
     461             : 
     462          58 : void ScDPSaveDimension::SetSortInfo(const sheet::DataPilotFieldSortInfo* pNew)
     463             : {
     464          58 :     delete pSortInfo;
     465          58 :     if (pNew)
     466          57 :         pSortInfo = new sheet::DataPilotFieldSortInfo(*pNew);
     467             :     else
     468           1 :         pSortInfo = NULL;
     469          58 : }
     470             : 
     471          58 : void ScDPSaveDimension::SetAutoShowInfo(const sheet::DataPilotFieldAutoShowInfo* pNew)
     472             : {
     473          58 :     delete pAutoShowInfo;
     474          58 :     if (pNew)
     475          57 :         pAutoShowInfo = new sheet::DataPilotFieldAutoShowInfo(*pNew);
     476             :     else
     477           1 :         pAutoShowInfo = NULL;
     478          58 : }
     479             : 
     480          58 : void ScDPSaveDimension::SetLayoutInfo(const sheet::DataPilotFieldLayoutInfo* pNew)
     481             : {
     482          58 :     delete pLayoutInfo;
     483          58 :     if (pNew)
     484          57 :         pLayoutInfo = new sheet::DataPilotFieldLayoutInfo(*pNew);
     485             :     else
     486           1 :         pLayoutInfo = NULL;
     487          58 : }
     488             : 
     489           9 : void ScDPSaveDimension::SetCurrentPage( const OUString* pPage )
     490             : {
     491             :     // We use member's visibility attribute to filter by page dimension.
     492             : 
     493             :     // pPage == NULL -> all members visible.
     494           9 :     MemberList::iterator it = maMemberList.begin(), itEnd = maMemberList.end();
     495          45 :     for (; it != itEnd; ++it)
     496             :     {
     497          36 :         ScDPSaveMember* pMem = *it;
     498          36 :         bool bVisible = !pPage || pMem->GetName() == *pPage;
     499          36 :         pMem->SetIsVisible(bVisible);
     500             :     }
     501           9 : }
     502             : 
     503         903 : ScDPSaveMember* ScDPSaveDimension::GetExistingMemberByName(const OUString& rName)
     504             : {
     505         903 :     MemberHash::const_iterator res = maMemberHash.find (rName);
     506         903 :     if (res != maMemberHash.end())
     507         110 :         return res->second;
     508         793 :     return NULL;
     509             : }
     510             : 
     511          15 : ScDPSaveMember* ScDPSaveDimension::GetMemberByName(const OUString& rName)
     512             : {
     513          15 :     MemberHash::const_iterator res = maMemberHash.find (rName);
     514          15 :     if (res != maMemberHash.end())
     515           6 :         return res->second;
     516             : 
     517           9 :     ScDPSaveMember* pNew = new ScDPSaveMember( rName );
     518           9 :     maMemberHash[rName] = pNew;
     519           9 :     maMemberList.push_back( pNew );
     520           9 :     return pNew;
     521             : }
     522             : 
     523           0 : void ScDPSaveDimension::SetMemberPosition( const OUString& rName, sal_Int32 nNewPos )
     524             : {
     525           0 :     ScDPSaveMember* pMember = GetMemberByName( rName ); // make sure it exists and is in the hash
     526             : 
     527           0 :     maMemberList.remove( pMember );
     528             : 
     529           0 :     MemberList::iterator aIter = maMemberList.begin();
     530           0 :     for (sal_Int32 i=0; i<nNewPos && aIter != maMemberList.end(); i++)
     531           0 :         ++aIter;
     532           0 :     maMemberList.insert( aIter, pMember );
     533           0 : }
     534             : 
     535         296 : void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xDim )
     536             : {
     537         296 :     uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
     538             :     OSL_ENSURE( xDimProp.is(), "no properties at dimension" );
     539         296 :     if ( xDimProp.is() )
     540             :     {
     541             :         // exceptions are caught at ScDPSaveData::WriteToSource
     542         296 :         uno::Any aAny;
     543             : 
     544         296 :         sheet::DataPilotFieldOrientation eOrient = (sheet::DataPilotFieldOrientation)nOrientation;
     545         296 :         aAny <<= eOrient;
     546         296 :         xDimProp->setPropertyValue( OUString(SC_UNO_DP_ORIENTATION), aAny );
     547             : 
     548         296 :         sheet::GeneralFunction eFunc = (sheet::GeneralFunction)nFunction;
     549         296 :         aAny <<= eFunc;
     550         296 :         xDimProp->setPropertyValue( OUString(SC_UNO_DP_FUNCTION), aAny );
     551             : 
     552         296 :         if ( nUsedHierarchy >= 0 )
     553             :         {
     554         136 :             aAny <<= (sal_Int32)nUsedHierarchy;
     555         136 :             xDimProp->setPropertyValue( OUString(SC_UNO_DP_USEDHIERARCHY), aAny );
     556             :         }
     557             : 
     558         296 :         if ( pReferenceValue )
     559             :         {
     560           7 :             aAny <<= *pReferenceValue;
     561           7 :             xDimProp->setPropertyValue( OUString(SC_UNO_DP_REFVALUE), aAny );
     562             :         }
     563             : 
     564         296 :         if (mpLayoutName)
     565           2 :             ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_DP_LAYOUTNAME, *mpLayoutName);
     566             : 
     567         296 :         const OUString* pSubTotalName = GetSubtotalName();
     568         296 :         if (pSubTotalName)
     569             :             // Custom subtotal name, with '?' being replaced by the visible field name later.
     570           0 :             ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_DP_FIELD_SUBTOTALNAME, *pSubTotalName);
     571             :     }
     572             : 
     573             :     // Level loop outside of maMemberList loop
     574             :     // because SubTotals have to be set independently of known members
     575             : 
     576         296 :     long nCount = maMemberHash.size();
     577             : 
     578         296 :     long nHierCount = 0;
     579         592 :     uno::Reference<container::XIndexAccess> xHiers;
     580         592 :     uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
     581         296 :     if ( xHierSupp.is() )
     582             :     {
     583         296 :         uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
     584         296 :         xHiers = new ScNameToIndexAccess( xHiersName );
     585         296 :         nHierCount = xHiers->getCount();
     586             :     }
     587             : 
     588         296 :     bool bHasHiddenMember = false;
     589             : 
     590         592 :     for (long nHier=0; nHier<nHierCount; nHier++)
     591             :     {
     592         296 :         uno::Reference<uno::XInterface> xHierarchy = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHier) );
     593             : 
     594         296 :         long nLevCount = 0;
     595         592 :         uno::Reference<container::XIndexAccess> xLevels;
     596         592 :         uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHierarchy, uno::UNO_QUERY );
     597         296 :         if ( xLevSupp.is() )
     598             :         {
     599         296 :             uno::Reference<container::XNameAccess> xLevelsName = xLevSupp->getLevels();
     600         296 :             xLevels = new ScNameToIndexAccess( xLevelsName );
     601         296 :             nLevCount = xLevels->getCount();
     602             :         }
     603             : 
     604         592 :         for (long nLev=0; nLev<nLevCount; nLev++)
     605             :         {
     606         296 :             uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLev) );
     607         592 :             uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
     608             :             OSL_ENSURE( xLevProp.is(), "no properties at level" );
     609         296 :             if ( xLevProp.is() )
     610             :             {
     611         296 :                 uno::Any aAny;
     612         296 :                 if ( !bSubTotalDefault )
     613             :                 {
     614          43 :                     if ( !pSubTotalFuncs )
     615           0 :                         nSubTotalCount = 0;
     616             : 
     617          43 :                     uno::Sequence<sheet::GeneralFunction> aSeq(nSubTotalCount);
     618          43 :                     sheet::GeneralFunction* pArray = aSeq.getArray();
     619          86 :                     for (long i=0; i<nSubTotalCount; i++)
     620          43 :                         pArray[i] = (sheet::GeneralFunction)pSubTotalFuncs[i];
     621          43 :                     aAny <<= aSeq;
     622          43 :                     xLevProp->setPropertyValue( OUString(SC_UNO_DP_SUBTOTAL), aAny );
     623             :                 }
     624         296 :                 if ( nShowEmptyMode != SC_DPSAVEMODE_DONTKNOW )
     625             :                     lcl_SetBoolProperty( xLevProp,
     626          92 :                         OUString(SC_UNO_DP_SHOWEMPTY), (bool)nShowEmptyMode );
     627             : 
     628         296 :                 if ( pSortInfo )
     629          87 :                     ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_DP_SORTING, *pSortInfo);
     630             : 
     631         296 :                 if ( pAutoShowInfo )
     632          91 :                     ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_DP_AUTOSHOW, *pAutoShowInfo);
     633             : 
     634         296 :                 if ( pLayoutInfo )
     635          89 :                     ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_DP_LAYOUT, *pLayoutInfo);
     636             : 
     637             :                 // exceptions are caught at ScDPSaveData::WriteToSource
     638             :             }
     639             : 
     640         296 :             if ( nCount > 0 )
     641             :             {
     642          62 :                 uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevel, uno::UNO_QUERY );
     643          62 :                 if ( xMembSupp.is() )
     644             :                 {
     645          62 :                     uno::Reference<container::XNameAccess> xMembers = xMembSupp->getMembers();
     646          62 :                     if ( xMembers.is() )
     647             :                     {
     648          62 :                         sal_Int32 nPosition = -1; // set position only in manual mode
     649          62 :                         if ( !pSortInfo || pSortInfo->Mode == sheet::DataPilotFieldSortMode::MANUAL )
     650          19 :                             nPosition = 0;
     651             : 
     652         334 :                         for (MemberList::const_iterator i=maMemberList.begin(); i != maMemberList.end() ; ++i)
     653             :                         {
     654         272 :                             ScDPSaveMember* pMember = *i;
     655         272 :                             if (!pMember->GetIsVisible())
     656           9 :                                 bHasHiddenMember = true;
     657         272 :                             OUString aMemberName = pMember->GetName();
     658         272 :                             if ( xMembers->hasByName( aMemberName ) )
     659             :                             {
     660             :                                 uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
     661         261 :                                     xMembers->getByName( aMemberName ) );
     662         261 :                                 pMember->WriteToSource( xMemberInt, nPosition );
     663             : 
     664         261 :                                 if ( nPosition >= 0 )
     665          62 :                                     ++nPosition; // increase if initialized
     666             :                             }
     667             :                             // missing member is no error
     668         272 :                         }
     669          62 :                     }
     670          62 :                 }
     671             :             }
     672         296 :         }
     673         296 :     }
     674             : 
     675         296 :     if (xDimProp.is())
     676         592 :         ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER, bHasHiddenMember);
     677         296 : }
     678             : 
     679           0 : void ScDPSaveDimension::UpdateMemberVisibility(const boost::unordered_map<OUString, bool, OUStringHash>& rData)
     680             : {
     681             :     typedef boost::unordered_map<OUString, bool, OUStringHash> DataMap;
     682           0 :     MemberList::iterator itrMem = maMemberList.begin(), itrMemEnd = maMemberList.end();
     683           0 :     for (; itrMem != itrMemEnd; ++itrMem)
     684             :     {
     685           0 :         ScDPSaveMember* pMem = *itrMem;
     686           0 :         const OUString& rMemName = pMem->GetName();
     687           0 :         DataMap::const_iterator itr = rData.find(rMemName);
     688           0 :         if (itr != rData.end())
     689           0 :             pMem->SetIsVisible(itr->second);
     690             :     }
     691           0 : }
     692             : 
     693          28 : bool ScDPSaveDimension::HasInvisibleMember() const
     694             : {
     695          28 :     MemberList::const_iterator itrMem = maMemberList.begin(), itrMemEnd = maMemberList.end();
     696        2511 :     for (; itrMem != itrMemEnd; ++itrMem)
     697             :     {
     698        2485 :         const ScDPSaveMember* pMem = *itrMem;
     699        2485 :         if (!pMem->GetIsVisible())
     700           2 :             return true;
     701             :     }
     702          26 :     return false;
     703             : }
     704             : 
     705         141 : void ScDPSaveDimension::RemoveObsoleteMembers(const MemberSetType& rMembers)
     706             : {
     707         141 :     maMemberHash.clear();
     708         141 :     MemberList aNew;
     709         141 :     MemberList::iterator it = maMemberList.begin(), itEnd = maMemberList.end();
     710         321 :     for (; it != itEnd; ++it)
     711             :     {
     712         180 :         ScDPSaveMember* pMem = *it;
     713         180 :         if (rMembers.count(pMem->GetName()))
     714             :         {
     715             :             // This member still exists.
     716         180 :             maMemberHash.insert(MemberHash::value_type(pMem->GetName(), pMem));
     717         180 :             aNew.push_back(pMem);
     718             :         }
     719             :         else
     720             :         {
     721             :             // This member no longer exists.
     722           0 :             delete pMem;
     723             :         }
     724             :     }
     725             : 
     726         141 :     maMemberList.swap(aNew);
     727         141 : }
     728             : 
     729             : #if DEBUG_PIVOT_TABLE
     730             : 
     731             : void ScDPSaveDimension::Dump(int nIndent) const
     732             : {
     733             :     static const char* pOrientNames[] = { "hidden", "column", "row", "page", "data" };
     734             :     std::string aIndent(nIndent*4, ' ');
     735             : 
     736             :     cout << aIndent << "* dimension name: '" << aName << "'" << endl;
     737             : 
     738             :     cout << aIndent << "    + orientation: ";
     739             :     if (nOrientation <= 4)
     740             :         cout << pOrientNames[nOrientation];
     741             :     else
     742             :         cout << "(invalid)";
     743             :     cout << endl;
     744             : 
     745             :     cout << aIndent << "    + layout name: ";
     746             :     if (mpLayoutName)
     747             :         cout << "'" << *mpLayoutName << "'";
     748             :     else
     749             :         cout << "(none)";
     750             :     cout << endl;
     751             : 
     752             :     cout << aIndent << "    + subtotal name: ";
     753             :     if (mpSubtotalName)
     754             :         cout << "'" << *mpSubtotalName << "'";
     755             :     else
     756             :         cout << "(none)";
     757             :     cout << endl;
     758             : 
     759             :     cout << aIndent << "    + is data layout: " << (bIsDataLayout ? "yes" : "no") << endl;
     760             :     cout << aIndent << "    + is duplicate: " << (bDupFlag ? "yes" : "no") << endl;
     761             : 
     762             :     MemberList::const_iterator itMem = maMemberList.begin(), itMemEnd = maMemberList.end();
     763             :     for (; itMem != itMemEnd; ++itMem)
     764             :     {
     765             :         ScDPSaveMember* pMem = *itMem;
     766             :         pMem->Dump(nIndent+1);
     767             :     }
     768             : 
     769             :     cout << endl; // blank line
     770             : }
     771             : 
     772             : #endif
     773             : 
     774          78 : ScDPSaveData::ScDPSaveData() :
     775             :     pDimensionData( NULL ),
     776             :     nColumnGrandMode( SC_DPSAVEMODE_DONTKNOW ),
     777             :     nRowGrandMode( SC_DPSAVEMODE_DONTKNOW ),
     778             :     nIgnoreEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
     779             :     nRepeatEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
     780             :     bFilterButton( true ),
     781             :     bDrillDown( true ),
     782             :     mbDimensionMembersBuilt(false),
     783          78 :     mpGrandTotalName(NULL)
     784             : {
     785          78 : }
     786             : 
     787         172 : ScDPSaveData::ScDPSaveData(const ScDPSaveData& r) :
     788             :     nColumnGrandMode( r.nColumnGrandMode ),
     789             :     nRowGrandMode( r.nRowGrandMode ),
     790             :     nIgnoreEmptyMode( r.nIgnoreEmptyMode ),
     791             :     nRepeatEmptyMode( r.nRepeatEmptyMode ),
     792             :     bFilterButton( r.bFilterButton ),
     793             :     bDrillDown( r.bDrillDown ),
     794             :     mbDimensionMembersBuilt(r.mbDimensionMembersBuilt),
     795             :     mpGrandTotalName(NULL),
     796         172 :     mpDimOrder(NULL)
     797             : {
     798         172 :     if ( r.pDimensionData )
     799          10 :         pDimensionData = new ScDPDimensionSaveData( *r.pDimensionData );
     800             :     else
     801         162 :         pDimensionData = NULL;
     802             : 
     803         172 :     aDimList = r.aDimList.clone();
     804             : 
     805         172 :     if (r.mpGrandTotalName)
     806           0 :         mpGrandTotalName.reset(new OUString(*r.mpGrandTotalName));
     807         172 : }
     808             : 
     809           0 : ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r )
     810             : {
     811           0 :     if ( &r != this )
     812             :     {
     813           0 :         this->~ScDPSaveData();
     814           0 :         new( this ) ScDPSaveData ( r );
     815             :     }
     816           0 :     return *this;
     817             : }
     818             : 
     819           0 : bool ScDPSaveData::operator== ( const ScDPSaveData& r ) const
     820             : {
     821           0 :     if ( nColumnGrandMode != r.nColumnGrandMode ||
     822           0 :          nRowGrandMode    != r.nRowGrandMode    ||
     823           0 :          nIgnoreEmptyMode != r.nIgnoreEmptyMode ||
     824           0 :          nRepeatEmptyMode != r.nRepeatEmptyMode ||
     825           0 :          bFilterButton    != r.bFilterButton    ||
     826           0 :          bDrillDown       != r.bDrillDown       ||
     827           0 :          mbDimensionMembersBuilt != r.mbDimensionMembersBuilt)
     828           0 :         return false;
     829             : 
     830           0 :     if ( pDimensionData || r.pDimensionData )
     831           0 :         if ( !pDimensionData || !r.pDimensionData || !( *pDimensionData == *r.pDimensionData ) )
     832           0 :             return false;
     833             : 
     834           0 :     if ( aDimList.size() != r.aDimList.size() )
     835           0 :         return false;
     836             : 
     837           0 :     if (aDimList != r.aDimList)
     838           0 :         return false;
     839             : 
     840           0 :     if (mpGrandTotalName)
     841             :     {
     842           0 :         if (!r.mpGrandTotalName)
     843           0 :             return false;
     844           0 :         if (!mpGrandTotalName->equals(*r.mpGrandTotalName))
     845           0 :             return false;
     846             :     }
     847           0 :     else if (r.mpGrandTotalName)
     848           0 :         return false;
     849             : 
     850           0 :     return true;
     851             : }
     852             : 
     853         446 : ScDPSaveData::~ScDPSaveData()
     854             : {
     855         223 :     delete pDimensionData;
     856         223 : }
     857             : 
     858           0 : void ScDPSaveData::SetGrandTotalName(const OUString& rName)
     859             : {
     860           0 :     mpGrandTotalName.reset(new OUString(rName));
     861           0 : }
     862             : 
     863         116 : const OUString* ScDPSaveData::GetGrandTotalName() const
     864             : {
     865         116 :     return mpGrandTotalName.get();
     866             : }
     867             : 
     868          58 : const ScDPSaveData::DimsType& ScDPSaveData::GetDimensions() const
     869             : {
     870          58 :     return aDimList;
     871             : }
     872             : 
     873             : namespace {
     874             : 
     875             : class DimOrderInserter : std::unary_function<const ScDPSaveDimension*, void>
     876             : {
     877             :     ScDPSaveData::DimOrderType& mrNames;
     878             : public:
     879           8 :     DimOrderInserter(ScDPSaveData::DimOrderType& rNames) : mrNames(rNames) {}
     880             : 
     881           9 :     void operator() (const ScDPSaveDimension* pDim)
     882             :     {
     883           9 :         size_t nRank = mrNames.size();
     884             :         mrNames.insert(
     885           9 :             ScDPSaveData::DimOrderType::value_type(pDim->GetName(), nRank));
     886           9 :     }
     887             : };
     888             : 
     889             : }
     890             : 
     891          31 : const ScDPSaveData::DimOrderType& ScDPSaveData::GetDimensionSortOrder() const
     892             : {
     893          31 :     if (!mpDimOrder)
     894             :     {
     895           4 :         mpDimOrder.reset(new DimOrderType);
     896           8 :         std::vector<const ScDPSaveDimension*> aRowDims, aColDims;
     897           4 :         GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_ROW, aRowDims);
     898           4 :         GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_COLUMN, aColDims);
     899             : 
     900           4 :         std::for_each(aRowDims.begin(), aRowDims.end(), DimOrderInserter(*mpDimOrder));
     901           8 :         std::for_each(aColDims.begin(), aColDims.end(), DimOrderInserter(*mpDimOrder));
     902             :     }
     903          31 :     return *mpDimOrder;
     904             : }
     905             : 
     906          66 : void ScDPSaveData::GetAllDimensionsByOrientation(
     907             :     sheet::DataPilotFieldOrientation eOrientation, std::vector<const ScDPSaveDimension*>& rDims) const
     908             : {
     909          66 :     std::vector<const ScDPSaveDimension*> aDims;
     910          66 :     DimsType::const_iterator it = aDimList.begin(), itEnd = aDimList.end();
     911         371 :     for (; it != itEnd; ++it)
     912             :     {
     913         305 :         const ScDPSaveDimension& rDim = *it;
     914         305 :         if (rDim.GetOrientation() != static_cast<sal_uInt16>(eOrientation))
     915         217 :             continue;
     916             : 
     917          88 :         aDims.push_back(&rDim);
     918             :     }
     919             : 
     920          66 :     rDims.swap(aDims);
     921          66 : }
     922             : 
     923          40 : void ScDPSaveData::AddDimension(ScDPSaveDimension* pDim)
     924             : {
     925          40 :     if (!pDim)
     926          40 :         return;
     927             : 
     928          40 :     CheckDuplicateName(*pDim);
     929          40 :     aDimList.push_back(pDim);
     930             : 
     931          40 :     DimensionsChanged();
     932             : }
     933             : 
     934         266 : ScDPSaveDimension* ScDPSaveData::GetDimensionByName(const OUString& rName)
     935             : {
     936         266 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
     937         527 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
     938             :     {
     939         470 :         if (iter->GetName() == rName && !iter->IsDataLayout() )
     940         209 :             return const_cast<ScDPSaveDimension*>(&(*iter));
     941             :     }
     942             : 
     943          57 :     return AppendNewDimension(rName, false);
     944             : }
     945             : 
     946          40 : ScDPSaveDimension* ScDPSaveData::GetExistingDimensionByName(const OUString& rName) const
     947             : {
     948          40 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
     949         127 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
     950             :     {
     951          94 :         if (iter->GetName() == rName && !iter->IsDataLayout() )
     952           7 :             return const_cast<ScDPSaveDimension*>(&(*iter));
     953             :     }
     954          33 :     return NULL; // don't create new
     955             : }
     956             : 
     957          52 : ScDPSaveDimension* ScDPSaveData::GetNewDimensionByName(const OUString& rName)
     958             : {
     959          52 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
     960          97 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
     961             :     {
     962          47 :         if (iter->GetName() == rName && !iter->IsDataLayout() )
     963           2 :             return DuplicateDimension(rName);
     964             :     }
     965             : 
     966          50 :     return AppendNewDimension(rName, false);
     967             : }
     968             : 
     969          23 : ScDPSaveDimension* ScDPSaveData::GetDataLayoutDimension()
     970             : {
     971          23 :     ScDPSaveDimension* pDim = GetExistingDataLayoutDimension();
     972          23 :     if (pDim)
     973           1 :         return pDim;
     974             : 
     975          22 :     return AppendNewDimension(OUString(), true);
     976             : }
     977             : 
     978          24 : ScDPSaveDimension* ScDPSaveData::GetExistingDataLayoutDimension() const
     979             : {
     980          24 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
     981          95 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
     982             :     {
     983          73 :         if ( iter->IsDataLayout() )
     984           2 :             return const_cast<ScDPSaveDimension*>(&(*iter));
     985             :     }
     986          22 :     return NULL;
     987             : }
     988             : 
     989           2 : ScDPSaveDimension* ScDPSaveData::DuplicateDimension(const OUString& rName)
     990             : {
     991             :     // always insert new
     992             : 
     993           2 :     ScDPSaveDimension* pOld = GetExistingDimensionByName(rName);
     994           2 :     if (!pOld)
     995           0 :         return NULL;
     996             : 
     997           2 :     ScDPSaveDimension* pNew = new ScDPSaveDimension( *pOld );
     998           2 :     AddDimension(pNew);
     999           2 :     return pNew;
    1000             : }
    1001             : 
    1002           2 : void ScDPSaveData::RemoveDimensionByName(const OUString& rName)
    1003             : {
    1004           2 :     boost::ptr_vector<ScDPSaveDimension>::iterator iter;
    1005           3 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
    1006             :     {
    1007           3 :         if (iter->GetName() != rName || iter->IsDataLayout())
    1008           1 :             continue;
    1009             : 
    1010           2 :         aDimList.erase(iter);
    1011           2 :         RemoveDuplicateNameCount(rName);
    1012           2 :         DimensionsChanged();
    1013           4 :         return;
    1014             :     }
    1015             : }
    1016             : 
    1017           0 : ScDPSaveDimension& ScDPSaveData::DuplicateDimension( const ScDPSaveDimension& rDim )
    1018             : {
    1019           0 :     ScDPSaveDimension* pNew = new ScDPSaveDimension( rDim );
    1020           0 :     AddDimension(pNew);
    1021           0 :     return *pNew;
    1022             : }
    1023             : 
    1024           0 : ScDPSaveDimension* ScDPSaveData::GetInnermostDimension(sal_uInt16 nOrientation)
    1025             : {
    1026             :     // return the innermost dimension for the given orientation,
    1027             :     // excluding data layout dimension
    1028             : 
    1029           0 :     boost::ptr_vector<ScDPSaveDimension>::const_reverse_iterator iter;
    1030           0 :     for (iter = aDimList.rbegin(); iter != aDimList.rend(); ++iter)
    1031             :     {
    1032           0 :         if (iter->GetOrientation() == nOrientation && !iter->IsDataLayout())
    1033           0 :             return const_cast<ScDPSaveDimension*>(&(*iter));
    1034             :     }
    1035             : 
    1036           0 :     return NULL;
    1037             : }
    1038             : 
    1039           0 : ScDPSaveDimension* ScDPSaveData::GetFirstDimension(sheet::DataPilotFieldOrientation eOrientation)
    1040             : {
    1041           0 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
    1042           0 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
    1043             :     {
    1044           0 :         if (iter->GetOrientation() == eOrientation && !iter->IsDataLayout())
    1045           0 :             return const_cast<ScDPSaveDimension*>(&(*iter));
    1046             :     }
    1047           0 :     return NULL;
    1048             : }
    1049             : 
    1050           0 : long ScDPSaveData::GetDataDimensionCount() const
    1051             : {
    1052           0 :     long nDataCount = 0;
    1053             : 
    1054           0 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
    1055           0 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
    1056             :     {
    1057           0 :         if (iter->GetOrientation() == sheet::DataPilotFieldOrientation_DATA)
    1058           0 :             ++nDataCount;
    1059             :     }
    1060             : 
    1061           0 :     return nDataCount;
    1062             : }
    1063             : 
    1064          64 : void ScDPSaveData::SetPosition( ScDPSaveDimension* pDim, long nNew )
    1065             : {
    1066             :     // position (nNew) is counted within dimensions of the same orientation
    1067             : 
    1068          64 :     sal_uInt16 nOrient = pDim->GetOrientation();
    1069             : 
    1070          64 :     boost::ptr_vector<ScDPSaveDimension>::iterator it;
    1071         177 :     for ( it = aDimList.begin(); it != aDimList.end(); ++it)
    1072             :     {
    1073         177 :         if (pDim == &(*it))
    1074             :         {
    1075             :             // Tell ptr_vector to give up ownership of this element.  Don't
    1076             :             // delete this instance as it is re-inserted into the container
    1077             :             // later.
    1078          64 :             aDimList.release(it).release();
    1079          64 :             break;
    1080             :         }
    1081             :     }
    1082             : 
    1083          64 :     boost::ptr_vector<ScDPSaveDimension>::iterator iterInsert = aDimList.begin();
    1084         217 :     while ( nNew > 0 && iterInsert != aDimList.end())
    1085             :     {
    1086          89 :         if (iterInsert->GetOrientation() == nOrient )
    1087           2 :             --nNew;
    1088             : 
    1089          89 :         ++iterInsert;
    1090             :     }
    1091             : 
    1092          64 :     aDimList.insert(iterInsert,pDim);
    1093          64 :     DimensionsChanged();
    1094          64 : }
    1095             : 
    1096          44 : void ScDPSaveData::SetColumnGrand(bool bSet)
    1097             : {
    1098          44 :     nColumnGrandMode = sal_uInt16(bSet);
    1099          44 : }
    1100             : 
    1101          44 : void ScDPSaveData::SetRowGrand(bool bSet)
    1102             : {
    1103          44 :     nRowGrandMode = sal_uInt16(bSet);
    1104          44 : }
    1105             : 
    1106          44 : void ScDPSaveData::SetIgnoreEmptyRows(bool bSet)
    1107             : {
    1108          44 :     nIgnoreEmptyMode = sal_uInt16(bSet);
    1109          44 : }
    1110             : 
    1111          43 : void ScDPSaveData::SetRepeatIfEmpty(bool bSet)
    1112             : {
    1113          43 :     nRepeatEmptyMode = sal_uInt16(bSet);
    1114          43 : }
    1115             : 
    1116          27 : void ScDPSaveData::SetFilterButton(bool bSet)
    1117             : {
    1118          27 :     bFilterButton = bSet;
    1119          27 : }
    1120             : 
    1121          27 : void ScDPSaveData::SetDrillDown(bool bSet)
    1122             : {
    1123          27 :     bDrillDown = bSet;
    1124          27 : }
    1125             : 
    1126         116 : static void lcl_ResetOrient( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
    1127             : {
    1128         116 :     sheet::DataPilotFieldOrientation eOrient = sheet::DataPilotFieldOrientation_HIDDEN;
    1129             : 
    1130         116 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1131         232 :     uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
    1132         116 :     long nIntCount = xIntDims->getCount();
    1133         641 :     for (long nIntDim=0; nIntDim<nIntCount; nIntDim++)
    1134             :     {
    1135         525 :         uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
    1136        1050 :         uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
    1137         525 :         if (xDimProp.is())
    1138             :         {
    1139         525 :             uno::Any aAny;
    1140         525 :             aAny <<= eOrient;
    1141         525 :             xDimProp->setPropertyValue( OUString(SC_UNO_DP_ORIENTATION), aAny );
    1142             :         }
    1143         641 :     }
    1144         116 : }
    1145             : 
    1146         116 : void ScDPSaveData::WriteToSource( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
    1147             : {
    1148         116 :     if (!xSource.is())
    1149         116 :         return;
    1150             : 
    1151             :     // source options must be first!
    1152             : 
    1153         116 :     uno::Reference<beans::XPropertySet> xSourceProp( xSource, uno::UNO_QUERY );
    1154             :     OSL_ENSURE( xSourceProp.is(), "no properties at source" );
    1155         116 :     if ( xSourceProp.is() )
    1156             :     {
    1157             :         // source options are not available for external sources
    1158             :         //! use XPropertySetInfo to test for availability?
    1159             : 
    1160             :         try
    1161             :         {
    1162         116 :             if ( nIgnoreEmptyMode != SC_DPSAVEMODE_DONTKNOW )
    1163             :                 lcl_SetBoolProperty( xSourceProp,
    1164         115 :                     OUString(SC_UNO_DP_IGNOREEMPTY), (bool)nIgnoreEmptyMode );
    1165         116 :             if ( nRepeatEmptyMode != SC_DPSAVEMODE_DONTKNOW )
    1166             :                 lcl_SetBoolProperty( xSourceProp,
    1167         115 :                     OUString(SC_UNO_DP_REPEATEMPTY), (bool)nRepeatEmptyMode );
    1168             :         }
    1169           0 :         catch(uno::Exception&)
    1170             :         {
    1171             :             // no error
    1172             :         }
    1173             : 
    1174         116 :         const OUString* pGrandTotalName = GetGrandTotalName();
    1175         116 :         if (pGrandTotalName)
    1176           0 :             ScUnoHelpFunctions::SetOptionalPropertyValue(xSourceProp, SC_UNO_DP_GRANDTOTAL_NAME, *pGrandTotalName);
    1177             :     }
    1178             : 
    1179             :     // exceptions in the other calls are errors
    1180             :     try
    1181             :     {
    1182             :         // reset all orientations
    1183             :         //! "forgetSettings" or similar at source ?????
    1184             :         //! reset all duplicated dimensions, or reuse them below !!!
    1185             :         OSL_FAIL( "ScDPSaveData::WriteToSource" );
    1186             : 
    1187         116 :         lcl_ResetOrient( xSource );
    1188             : 
    1189         116 :         uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1190         232 :         uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
    1191         116 :         long nIntCount = xIntDims->getCount();
    1192             : 
    1193         116 :         boost::ptr_vector<ScDPSaveDimension>::iterator iter = aDimList.begin();
    1194         413 :         for (long i = 0; iter != aDimList.end(); ++iter, ++i)
    1195             :         {
    1196         297 :             OUString aName = iter->GetName();
    1197         594 :             OUString aCoreName = ScDPUtil::getSourceDimensionName(aName);
    1198             : 
    1199             :             OSL_TRACE( "%s", aName.getStr() );
    1200             : 
    1201         297 :             bool bData = iter->IsDataLayout();
    1202             : 
    1203             :             //! getByName for ScDPSource, including DataLayoutDimension !!!!!!!!
    1204             : 
    1205         297 :             bool bFound = false;
    1206        1106 :             for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
    1207             :             {
    1208         809 :                 uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
    1209         809 :                 if ( bData )
    1210             :                 {
    1211         203 :                     uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
    1212         203 :                     if ( xDimProp.is() )
    1213             :                     {
    1214             :                         bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
    1215         203 :                                     OUString(SC_UNO_DP_ISDATALAYOUT) );
    1216             :                         //! error checking -- is "IsDataLayoutDimension" property required??
    1217         203 :                     }
    1218             :                 }
    1219             :                 else
    1220             :                 {
    1221         606 :                     uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
    1222         606 :                     if (xDimName.is() && xDimName->getName() == aCoreName)
    1223         248 :                         bFound = true;
    1224             :                 }
    1225             : 
    1226         809 :                 if (bFound)
    1227             :                 {
    1228         296 :                     if (iter->GetDupFlag())
    1229             :                     {
    1230           3 :                         uno::Reference<util::XCloneable> xCloneable(xIntDim, uno::UNO_QUERY);
    1231             :                         OSL_ENSURE(xCloneable.is(), "cannot clone dimension");
    1232           3 :                         if (xCloneable.is())
    1233             :                         {
    1234           3 :                             uno::Reference<util::XCloneable> xNew = xCloneable->createClone();
    1235           6 :                             uno::Reference<container::XNamed> xNewName(xNew, uno::UNO_QUERY);
    1236           3 :                             if (xNewName.is())
    1237             :                             {
    1238           3 :                                 xNewName->setName(aName);
    1239           3 :                                 iter->WriteToSource(xNew);
    1240           3 :                             }
    1241           3 :                         }
    1242             :                     }
    1243             :                     else
    1244         293 :                         iter->WriteToSource( xIntDim );
    1245             :                 }
    1246         809 :             }
    1247             :             OSL_ENSURE(bFound, "WriteToSource: Dimension not found");
    1248         297 :         }
    1249             : 
    1250         116 :         if ( xSourceProp.is() )
    1251             :         {
    1252         116 :             if ( nColumnGrandMode != SC_DPSAVEMODE_DONTKNOW )
    1253             :                 lcl_SetBoolProperty( xSourceProp,
    1254         116 :                     OUString(SC_UNO_DP_COLGRAND), (bool)nColumnGrandMode );
    1255         116 :             if ( nRowGrandMode != SC_DPSAVEMODE_DONTKNOW )
    1256             :                 lcl_SetBoolProperty( xSourceProp,
    1257         116 :                     OUString(SC_UNO_DP_ROWGRAND), (bool)nRowGrandMode );
    1258         116 :         }
    1259             :     }
    1260           0 :     catch(uno::Exception&)
    1261             :     {
    1262             :         OSL_FAIL("exception in WriteToSource");
    1263         116 :     }
    1264             : }
    1265             : 
    1266           0 : bool ScDPSaveData::IsEmpty() const
    1267             : {
    1268           0 :     boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
    1269           0 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
    1270             :     {
    1271           0 :         if (iter->GetOrientation() != sheet::DataPilotFieldOrientation_HIDDEN && !iter->IsDataLayout())
    1272           0 :             return false;
    1273             :     }
    1274           0 :     return true; // no entries that are not hidden
    1275             : }
    1276             : 
    1277           1 : void ScDPSaveData::RemoveAllGroupDimensions( const OUString& rSrcDimName, std::vector<OUString>* pDeletedNames )
    1278             : {
    1279           1 :     if (!pDimensionData)
    1280             :         // No group dimensions exist.  Nothing to do.
    1281           1 :         return;
    1282             : 
    1283             :     // Remove numeric group dimension (exists once at most). No need to delete
    1284             :     // anything in save data (grouping was done inplace in an existing base
    1285             :     // dimension).
    1286           1 :     pDimensionData->RemoveNumGroupDimension(rSrcDimName);
    1287             : 
    1288             :     // Remove named group dimension(s). Dimensions have to be removed from
    1289             :     // dimension save data and from save data too.
    1290           1 :     const ScDPSaveGroupDimension* pExistingGroup = pDimensionData->GetGroupDimForBase(rSrcDimName);
    1291           4 :     while ( pExistingGroup )
    1292             :     {
    1293           2 :         OUString aGroupDimName = pExistingGroup->GetGroupDimName();
    1294           2 :         pDimensionData->RemoveGroupDimension(aGroupDimName);     // pExistingGroup is deleted
    1295             : 
    1296             :         // also remove SaveData settings for the dimension that no longer exists
    1297           2 :         RemoveDimensionByName(aGroupDimName);
    1298             : 
    1299           2 :         if (pDeletedNames)
    1300           0 :             pDeletedNames->push_back(aGroupDimName);
    1301             : 
    1302             :         // see if there are more group dimensions
    1303           2 :         pExistingGroup = pDimensionData->GetGroupDimForBase(rSrcDimName);
    1304             : 
    1305           2 :         if ( pExistingGroup && pExistingGroup->GetGroupDimName() == aGroupDimName )
    1306             :         {
    1307             :             // still get the same group dimension?
    1308             :             OSL_FAIL("couldn't remove group dimension");
    1309           0 :             pExistingGroup = NULL;      // avoid endless loop
    1310             :         }
    1311           2 :     }
    1312             : }
    1313             : 
    1314           8 : ScDPDimensionSaveData* ScDPSaveData::GetDimensionData()
    1315             : {
    1316           8 :     if (!pDimensionData)
    1317           7 :         pDimensionData = new ScDPDimensionSaveData;
    1318           8 :     return pDimensionData;
    1319             : }
    1320             : 
    1321           2 : void ScDPSaveData::SetDimensionData( const ScDPDimensionSaveData* pNew )
    1322             : {
    1323           2 :     delete pDimensionData;
    1324           2 :     if ( pNew )
    1325           2 :         pDimensionData = new ScDPDimensionSaveData( *pNew );
    1326             :     else
    1327           0 :         pDimensionData = NULL;
    1328           2 : }
    1329             : 
    1330           4 : void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData* pData)
    1331             : {
    1332           4 :     if (mbDimensionMembersBuilt)
    1333           4 :         return;
    1334             : 
    1335             :     // First, build a dimension name-to-index map.
    1336             :     typedef boost::unordered_map<OUString, long, OUStringHash> NameIndexMap;
    1337           4 :     NameIndexMap aMap;
    1338           4 :     long nColCount = pData->GetColumnCount();
    1339          31 :     for (long i = 0; i < nColCount; ++i)
    1340          27 :         aMap.insert( NameIndexMap::value_type(pData->getDimensionName(i), i));
    1341             : 
    1342           4 :     NameIndexMap::const_iterator itrEnd = aMap.end();
    1343             : 
    1344           4 :     boost::ptr_vector<ScDPSaveDimension>::iterator iter;
    1345          29 :     for (iter = aDimList.begin(); iter != aDimList.end(); ++iter)
    1346             :     {
    1347          25 :         const OUString& rDimName = iter->GetName();
    1348          25 :         if (rDimName.isEmpty())
    1349             :             // empty dimension name. It must be data layout.
    1350           8 :             continue;
    1351             : 
    1352          21 :         NameIndexMap::const_iterator itr = aMap.find(rDimName);
    1353          21 :         if (itr == itrEnd)
    1354             :             // dimension name not in the data. This should never happen!
    1355           0 :             continue;
    1356             : 
    1357          21 :         long nDimIndex = itr->second;
    1358          21 :         const std::vector<SCROW>& rMembers = pData->GetColumnEntries(nDimIndex);
    1359          21 :         size_t mMemberCount = rMembers.size();
    1360         909 :         for (size_t j = 0; j < mMemberCount; ++j)
    1361             :         {
    1362         888 :             const ScDPItemData* pMemberData = pData->GetMemberById( nDimIndex, rMembers[j] );
    1363         888 :             OUString aMemName = pData->GetFormattedString(nDimIndex, *pMemberData);
    1364         888 :             if (iter->GetExistingMemberByName(aMemName))
    1365             :                 // this member instance already exists. nothing to do.
    1366          96 :                 continue;
    1367             : 
    1368        1584 :             auto_ptr<ScDPSaveMember> pNewMember(new ScDPSaveMember(aMemName));
    1369         792 :             pNewMember->SetIsVisible(true);
    1370         792 :             iter->AddMember(pNewMember.release());
    1371         792 :         }
    1372             :     }
    1373             : 
    1374           4 :     mbDimensionMembersBuilt = true;
    1375             : }
    1376             : 
    1377          47 : void ScDPSaveData::SyncAllDimensionMembers(ScDPTableData* pData)
    1378             : {
    1379             :     typedef boost::unordered_map<OUString, long, OUStringHash> NameIndexMap;
    1380             : 
    1381             :     // First, build a dimension name-to-index map.
    1382          47 :     NameIndexMap aMap;
    1383          47 :     long nColCount = pData->GetColumnCount();
    1384         279 :     for (long i = 0; i < nColCount; ++i)
    1385         232 :         aMap.insert(NameIndexMap::value_type(pData->getDimensionName(i), i));
    1386             : 
    1387          47 :     NameIndexMap::const_iterator itMapEnd = aMap.end();
    1388             : 
    1389          47 :     DimsType::iterator it = aDimList.begin(), itEnd = aDimList.end();
    1390         199 :     for (it = aDimList.begin(); it != itEnd; ++it)
    1391             :     {
    1392         152 :         const OUString& rDimName = it->GetName();
    1393         152 :         if (rDimName.isEmpty())
    1394             :             // empty dimension name. It must be data layout.
    1395          21 :             continue;
    1396             : 
    1397         142 :         NameIndexMap::const_iterator itMap = aMap.find(rDimName);
    1398         142 :         if (itMap == itMapEnd)
    1399             :             // dimension name not in the data. This should never happen!
    1400           1 :             continue;
    1401             : 
    1402         141 :         ScDPSaveDimension::MemberSetType aMemNames;
    1403         141 :         long nDimIndex = itMap->second;
    1404         141 :         const std::vector<SCROW>& rMembers = pData->GetColumnEntries(nDimIndex);
    1405         141 :         size_t nMemberCount = rMembers.size();
    1406         812 :         for (size_t j = 0; j < nMemberCount; ++j)
    1407             :         {
    1408         671 :             const ScDPItemData* pMemberData = pData->GetMemberById(nDimIndex, rMembers[j]);
    1409         671 :             OUString aMemName = pData->GetFormattedString(nDimIndex, *pMemberData);
    1410         671 :             aMemNames.insert(aMemName);
    1411         671 :         }
    1412             : 
    1413         141 :         it->RemoveObsoleteMembers(aMemNames);
    1414         188 :     }
    1415          47 : }
    1416             : 
    1417           0 : bool ScDPSaveData::HasInvisibleMember(const OUString& rDimName) const
    1418             : {
    1419           0 :     ScDPSaveDimension* pDim = GetExistingDimensionByName(rDimName);
    1420           0 :     if (!pDim)
    1421           0 :         return false;
    1422             : 
    1423           0 :     return pDim->HasInvisibleMember();
    1424             : }
    1425             : 
    1426             : #if DEBUG_PIVOT_TABLE
    1427             : 
    1428             : void ScDPSaveData::Dump() const
    1429             : {
    1430             :     DimsType::const_iterator itDim = aDimList.begin(), itDimEnd = aDimList.end();
    1431             :     for (; itDim != itDimEnd; ++itDim)
    1432             :     {
    1433             :         const ScDPSaveDimension& rDim = *itDim;
    1434             :         rDim.Dump();
    1435             :     }
    1436             : }
    1437             : 
    1438             : #endif
    1439             : 
    1440          40 : void ScDPSaveData::CheckDuplicateName(ScDPSaveDimension& rDim)
    1441             : {
    1442          40 :     const OUString aName = ScDPUtil::getSourceDimensionName(rDim.GetName());
    1443          40 :     DupNameCountType::iterator it = maDupNameCounts.find(aName);
    1444          40 :     if (it != maDupNameCounts.end())
    1445             :     {
    1446           2 :         rDim.SetName(ScDPUtil::createDuplicateDimensionName(aName, ++it->second));
    1447           2 :         rDim.SetDupFlag(true);
    1448             :     }
    1449             :     else
    1450             :         // New name.
    1451          38 :         maDupNameCounts.insert(DupNameCountType::value_type(aName, 0));
    1452          40 : }
    1453             : 
    1454           2 : void ScDPSaveData::RemoveDuplicateNameCount(const OUString& rName)
    1455             : {
    1456           2 :     OUString aCoreName = rName;
    1457           2 :     if (ScDPUtil::isDuplicateDimension(rName))
    1458           0 :         aCoreName = ScDPUtil::getSourceDimensionName(rName);
    1459             : 
    1460           2 :     DupNameCountType::iterator it = maDupNameCounts.find(aCoreName);
    1461           2 :     if (it == maDupNameCounts.end())
    1462           0 :         return;
    1463             : 
    1464           2 :     if (!it->second)
    1465             :     {
    1466           2 :         maDupNameCounts.erase(it);
    1467           2 :         return;
    1468             :     }
    1469             : 
    1470           0 :     --it->second;
    1471           0 :     return;
    1472             : }
    1473             : 
    1474         129 : ScDPSaveDimension* ScDPSaveData::AppendNewDimension(const OUString& rName, bool bDataLayout)
    1475             : {
    1476         129 :     if (ScDPUtil::isDuplicateDimension(rName))
    1477             :         // This call is for original dimensions only.
    1478           0 :         return NULL;
    1479             : 
    1480         129 :     ScDPSaveDimension* pNew = new ScDPSaveDimension(rName, bDataLayout);
    1481         129 :     aDimList.push_back(pNew);
    1482         129 :     if (!maDupNameCounts.count(rName))
    1483         129 :         maDupNameCounts.insert(DupNameCountType::value_type(rName, 0));
    1484             : 
    1485         129 :     DimensionsChanged();
    1486         129 :     return pNew;
    1487             : }
    1488             : 
    1489         235 : void ScDPSaveData::DimensionsChanged()
    1490             : {
    1491         235 :     mpDimOrder.reset();
    1492         235 : }
    1493             : 
    1494           0 : bool operator == (const ::com::sun::star::sheet::DataPilotFieldSortInfo &l, const ::com::sun::star::sheet::DataPilotFieldSortInfo &r )
    1495             : {
    1496           0 :     return l.Field == r.Field && l.IsAscending == r.IsAscending && l.Mode == r.Mode;
    1497             : }
    1498           0 : bool operator == (const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo &l, const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo &r )
    1499             : {
    1500           0 :     return l.IsEnabled == r.IsEnabled &&
    1501           0 :         l.ShowItemsMode == r.ShowItemsMode &&
    1502           0 :         l.ItemCount == r.ItemCount &&
    1503           0 :         l.DataField == r.DataField;
    1504             : }
    1505           0 : bool operator == (const ::com::sun::star::sheet::DataPilotFieldReference &l, const ::com::sun::star::sheet::DataPilotFieldReference &r )
    1506             : {
    1507           0 :     return l.ReferenceType == r.ReferenceType &&
    1508           0 :         l.ReferenceField == r.ReferenceField &&
    1509           0 :         l.ReferenceItemType == r.ReferenceItemType &&
    1510           0 :         l.ReferenceItemName == r.ReferenceItemName;
    1511         102 : }
    1512             : 
    1513             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10