LCOV - code coverage report
Current view: top level - sc/source/core/data - dpobject.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 931 1898 49.1 %
Date: 2015-06-13 12:38:46 Functions: 107 179 59.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 "dpobject.hxx"
      21             : #include "dptabsrc.hxx"
      22             : #include "dpsave.hxx"
      23             : #include "dpdimsave.hxx"
      24             : #include "dpoutput.hxx"
      25             : #include "dpshttab.hxx"
      26             : #include "dpsdbtab.hxx"
      27             : #include "dpgroup.hxx"
      28             : #include "document.hxx"
      29             : #include "rechead.hxx"
      30             : #include "pivot.hxx"
      31             : #include "dapiuno.hxx"
      32             : #include "miscuno.hxx"
      33             : #include "scerrors.hxx"
      34             : #include "refupdat.hxx"
      35             : #include "scresid.hxx"
      36             : #include "sc.hrc"
      37             : #include "attrib.hxx"
      38             : #include "scitems.hxx"
      39             : #include "unonames.hxx"
      40             : #include "dpglobal.hxx"
      41             : #include "globstr.hrc"
      42             : #include "queryentry.hxx"
      43             : #include "dputil.hxx"
      44             : 
      45             : #include <com/sun/star/beans/XPropertySet.hpp>
      46             : #include <com/sun/star/sdb/XCompletedExecution.hpp>
      47             : #include <com/sun/star/sdbc/DataType.hpp>
      48             : #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
      49             : #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
      50             : #include <com/sun/star/sdbc/XRow.hpp>
      51             : #include <com/sun/star/sdbc/XRowSet.hpp>
      52             : #include <com/sun/star/sheet/GeneralFunction.hpp>
      53             : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
      54             : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
      55             : #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
      56             : #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
      57             : #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
      58             : #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
      59             : #include <com/sun/star/sheet/DimensionFlags.hpp>
      60             : #include <com/sun/star/task/InteractionHandler.hpp>
      61             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      62             : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
      63             : #include <com/sun/star/lang/XSingleComponentFactory.hpp>
      64             : #include <com/sun/star/lang/XInitialization.hpp>
      65             : #include <com/sun/star/container/XContentEnumerationAccess.hpp>
      66             : #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
      67             : 
      68             : #include <comphelper/processfactory.hxx>
      69             : #include <comphelper/string.hxx>
      70             : #include <comphelper/types.hxx>
      71             : #include <o3tl/ptr_container.hxx>
      72             : #include <sal/macros.h>
      73             : #include <tools/debug.hxx>
      74             : #include <tools/diagnose_ex.h>
      75             : #include <svl/zforlist.hxx>
      76             : #include <vcl/msgbox.hxx>
      77             : 
      78             : #include <utility>
      79             : #include <vector>
      80             : #include <memory>
      81             : #include <algorithm>
      82             : 
      83             : using namespace com::sun::star;
      84             : using ::std::vector;
      85             : using ::std::unary_function;
      86             : using ::boost::shared_ptr;
      87             : using ::com::sun::star::uno::Sequence;
      88             : using ::com::sun::star::uno::Reference;
      89             : using ::com::sun::star::uno::UNO_QUERY;
      90             : using ::com::sun::star::uno::Any;
      91             : using ::com::sun::star::uno::Exception;
      92             : using ::com::sun::star::lang::XComponent;
      93             : using ::com::sun::star::sheet::DataPilotTableHeaderData;
      94             : using ::com::sun::star::sheet::DataPilotTablePositionData;
      95             : using ::com::sun::star::sheet::XDimensionsSupplier;
      96             : using ::com::sun::star::beans::XPropertySet;
      97             : 
      98             : #define SC_SERVICE_ROWSET           "com.sun.star.sdb.RowSet"
      99             : 
     100             : #define SC_DBPROP_DATASOURCENAME    "DataSourceName"
     101             : #define SC_DBPROP_COMMAND           "Command"
     102             : #define SC_DBPROP_COMMANDTYPE       "CommandType"
     103             : 
     104             : #define SCDPSOURCE_SERVICE  "com.sun.star.sheet.DataPilotSource"
     105             : 
     106             : namespace {
     107             : 
     108             : /**
     109             :  * Database connection implementation for UNO database API.  Note that in
     110             :  * the UNO database API, column index is 1-based, whereas the interface
     111             :  * requires that column index be 0-based.
     112             :  */
     113           0 : class DBConnector : public ScDPCache::DBConnector
     114             : {
     115             :     ScDPCache& mrCache;
     116             : 
     117             :     uno::Reference<sdbc::XRowSet> mxRowSet;
     118             :     uno::Reference<sdbc::XRow> mxRow;
     119             :     uno::Reference<sdbc::XResultSetMetaData> mxMetaData;
     120             :     Date maNullDate;
     121             : 
     122             : public:
     123             :     DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate);
     124             : 
     125             :     bool isValid() const;
     126             : 
     127             :     virtual void getValue(long nCol, ScDPItemData &rData, short& rNumType) const SAL_OVERRIDE;
     128             :     virtual OUString getColumnLabel(long nCol) const SAL_OVERRIDE;
     129             :     virtual long getColumnCount() const SAL_OVERRIDE;
     130             :     virtual bool first() SAL_OVERRIDE;
     131             :     virtual bool next() SAL_OVERRIDE;
     132             :     virtual void finish() SAL_OVERRIDE;
     133             : };
     134             : 
     135           0 : DBConnector::DBConnector(ScDPCache& rCache, const uno::Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate) :
     136           0 :     mrCache(rCache), mxRowSet(xRowSet), maNullDate(rNullDate)
     137             : {
     138           0 :     Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(mxRowSet, UNO_QUERY);
     139           0 :     if (xMetaSupp.is())
     140           0 :         mxMetaData = xMetaSupp->getMetaData();
     141             : 
     142           0 :     mxRow.set(mxRowSet, UNO_QUERY);
     143           0 : }
     144             : 
     145           0 : bool DBConnector::isValid() const
     146             : {
     147           0 :     return mxRowSet.is() && mxRow.is() && mxMetaData.is();
     148             : }
     149             : 
     150           0 : bool DBConnector::first()
     151             : {
     152           0 :     return mxRowSet->first();
     153             : }
     154             : 
     155           0 : bool DBConnector::next()
     156             : {
     157           0 :     return mxRowSet->next();
     158             : }
     159             : 
     160           0 : void DBConnector::finish()
     161             : {
     162           0 :     mxRowSet->beforeFirst();
     163           0 : }
     164             : 
     165           0 : long DBConnector::getColumnCount() const
     166             : {
     167           0 :     return mxMetaData->getColumnCount();
     168             : }
     169             : 
     170           0 : OUString DBConnector::getColumnLabel(long nCol) const
     171             : {
     172           0 :     return mxMetaData->getColumnLabel(nCol+1);
     173             : }
     174             : 
     175           0 : void DBConnector::getValue(long nCol, ScDPItemData &rData, short& rNumType) const
     176             : {
     177           0 :     rNumType = css::util::NumberFormat::NUMBER;
     178           0 :     sal_Int32 nType = mxMetaData->getColumnType(nCol+1);
     179             : 
     180             :     try
     181             :     {
     182           0 :         double fValue = 0.0;
     183           0 :         switch (nType)
     184             :         {
     185             :             case sdbc::DataType::BIT:
     186             :             case sdbc::DataType::BOOLEAN:
     187             :             {
     188           0 :                 rNumType = css::util::NumberFormat::LOGICAL;
     189           0 :                 fValue  = mxRow->getBoolean(nCol+1) ? 1 : 0;
     190           0 :                 rData.SetValue(fValue);
     191           0 :                 break;
     192             :             }
     193             :             case sdbc::DataType::TINYINT:
     194             :             case sdbc::DataType::SMALLINT:
     195             :             case sdbc::DataType::INTEGER:
     196             :             case sdbc::DataType::BIGINT:
     197             :             case sdbc::DataType::FLOAT:
     198             :             case sdbc::DataType::REAL:
     199             :             case sdbc::DataType::DOUBLE:
     200             :             case sdbc::DataType::NUMERIC:
     201             :             case sdbc::DataType::DECIMAL:
     202             :             {
     203             :                 //TODO: do the conversion here?
     204           0 :                 fValue = mxRow->getDouble(nCol+1);
     205           0 :                 rData.SetValue(fValue);
     206           0 :                 break;
     207             :             }
     208             :             case sdbc::DataType::DATE:
     209             :             {
     210           0 :                 rNumType = css::util::NumberFormat::DATE;
     211             : 
     212           0 :                 util::Date aDate = mxRow->getDate(nCol+1);
     213           0 :                 fValue = Date(aDate.Day, aDate.Month, aDate.Year) - maNullDate;
     214           0 :                 rData.SetValue(fValue);
     215           0 :                 break;
     216             :             }
     217             :             case sdbc::DataType::TIME:
     218             :             {
     219           0 :                 rNumType = css::util::NumberFormat::TIME;
     220             : 
     221           0 :                 util::Time aTime = mxRow->getTime(nCol+1);
     222           0 :                 fValue = aTime.Hours       / static_cast<double>(::tools::Time::hourPerDay)   +
     223           0 :                          aTime.Minutes     / static_cast<double>(::tools::Time::minutePerDay) +
     224           0 :                          aTime.Seconds     / static_cast<double>(::tools::Time::secondPerDay) +
     225           0 :                          aTime.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay);
     226           0 :                 rData.SetValue(fValue);
     227           0 :                 break;
     228             :             }
     229             :             case sdbc::DataType::TIMESTAMP:
     230             :             {
     231           0 :                 rNumType = css::util::NumberFormat::DATETIME;
     232             : 
     233           0 :                 util::DateTime aStamp = mxRow->getTimestamp(nCol+1);
     234           0 :                 fValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - maNullDate ) +
     235           0 :                          aStamp.Hours       / static_cast<double>(::tools::Time::hourPerDay)   +
     236           0 :                          aStamp.Minutes     / static_cast<double>(::tools::Time::minutePerDay) +
     237           0 :                          aStamp.Seconds     / static_cast<double>(::tools::Time::secondPerDay) +
     238           0 :                          aStamp.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay);
     239           0 :                 rData.SetValue(fValue);
     240           0 :                 break;
     241             :             }
     242             :             case sdbc::DataType::CHAR:
     243             :             case sdbc::DataType::VARCHAR:
     244             :             case sdbc::DataType::LONGVARCHAR:
     245             :             case sdbc::DataType::SQLNULL:
     246             :             case sdbc::DataType::BINARY:
     247             :             case sdbc::DataType::VARBINARY:
     248             :             case sdbc::DataType::LONGVARBINARY:
     249             :             default:
     250           0 :                 rData.SetString(mrCache.InternString(mxRow->getString(nCol+1)));
     251             :         }
     252             :     }
     253           0 :     catch (uno::Exception&)
     254             :     {
     255           0 :         rData.SetEmpty();
     256             :     }
     257           0 : }
     258             : 
     259             : }
     260             : 
     261           0 : sal_uInt16 lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
     262             : {
     263           0 :     long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
     264           0 :     if ( xSource.is() )
     265             :     {
     266           0 :         uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
     267           0 :         uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
     268           0 :         long nIntCount = xIntDims->getCount();
     269           0 :         bool bFound = false;
     270           0 :         for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
     271             :         {
     272             :             uno::Reference<uno::XInterface> xIntDim =
     273           0 :                 ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
     274           0 :             uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
     275           0 :             if ( xDimProp.is() )
     276             :             {
     277             :                 bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
     278           0 :                     OUString(SC_UNO_DP_ISDATALAYOUT) );
     279             :                 //TODO: error checking -- is "IsDataLayoutDimension" property required??
     280           0 :                 if (bFound)
     281             :                     nRet = ScUnoHelpFunctions::GetEnumProperty(
     282             :                             xDimProp, OUString(SC_UNO_DP_ORIENTATION),
     283           0 :                             sheet::DataPilotFieldOrientation_HIDDEN );
     284             :             }
     285           0 :         }
     286             :     }
     287           0 :     return static_cast< sal_uInt16 >( nRet );
     288             : }
     289             : 
     290           0 : ScDPServiceDesc::ScDPServiceDesc(
     291             :     const OUString& rServ, const OUString& rSrc, const OUString& rNam,
     292             :     const OUString& rUser, const OUString& rPass ) :
     293             :     aServiceName( rServ ),
     294             :     aParSource( rSrc ),
     295             :     aParName( rNam ),
     296             :     aParUser( rUser ),
     297           0 :     aParPass( rPass ) {}
     298             : 
     299           0 : bool ScDPServiceDesc::operator== ( const ScDPServiceDesc& rOther ) const
     300             : {
     301           0 :     return aServiceName == rOther.aServiceName &&
     302           0 :         aParSource == rOther.aParSource &&
     303           0 :         aParName == rOther.aParName &&
     304           0 :         aParUser == rOther.aParUser &&
     305           0 :         aParPass == rOther.aParPass;
     306             : }
     307             : 
     308          53 : ScDPObject::ScDPObject( ScDocument* pD ) :
     309             :     pDoc( pD ),
     310             :     pSaveData( NULL ),
     311             :     pSheetDesc( NULL ),
     312             :     pImpDesc( NULL ),
     313             :     pServDesc( NULL ),
     314             :     mpTableData(static_cast<ScDPTableData*>(NULL)),
     315             :     pOutput( NULL ),
     316             :     mnAutoFormatIndex( 65535 ),
     317             :     nHeaderRows( 0 ),
     318             :     mbHeaderLayout(false),
     319             :     bAllowMove(false),
     320             :     bSettingsChanged(false),
     321          53 :     mbEnableGetPivotData(true)
     322             : {
     323          53 : }
     324             : 
     325         113 : ScDPObject::ScDPObject(const ScDPObject& r) :
     326             :     pDoc( r.pDoc ),
     327             :     pSaveData( NULL ),
     328             :     aTableName( r.aTableName ),
     329             :     aTableTag( r.aTableTag ),
     330             :     aOutRange( r.aOutRange ),
     331             :     pSheetDesc( NULL ),
     332             :     pImpDesc( NULL ),
     333             :     pServDesc( NULL ),
     334             :     mpTableData(static_cast<ScDPTableData*>(NULL)),
     335             :     pOutput( NULL ),
     336             :     mnAutoFormatIndex( r.mnAutoFormatIndex ),
     337             :     nHeaderRows( r.nHeaderRows ),
     338             :     mbHeaderLayout( r.mbHeaderLayout ),
     339             :     bAllowMove(false),
     340             :     bSettingsChanged(false),
     341         113 :     mbEnableGetPivotData(r.mbEnableGetPivotData)
     342             : {
     343         113 :     if (r.pSaveData)
     344         113 :         pSaveData = new ScDPSaveData(*r.pSaveData);
     345         113 :     if (r.pSheetDesc)
     346         113 :         pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
     347         113 :     if (r.pImpDesc)
     348           0 :         pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
     349         113 :     if (r.pServDesc)
     350           0 :         pServDesc = new ScDPServiceDesc(*r.pServDesc);
     351             :     // xSource (and pOutput) is not copied
     352         113 : }
     353             : 
     354         324 : ScDPObject::~ScDPObject()
     355             : {
     356         162 :     Clear();
     357         162 : }
     358             : 
     359           0 : ScDPObject& ScDPObject::operator= (const ScDPObject& r)
     360             : {
     361           0 :     Clear();
     362             : 
     363           0 :     pDoc = r.pDoc;
     364           0 :     aTableName = r.aTableName;
     365           0 :     aTableTag = r.aTableTag;
     366           0 :     aOutRange = r.aOutRange;
     367           0 :     mnAutoFormatIndex = r.mnAutoFormatIndex;
     368           0 :     nHeaderRows = r.nHeaderRows;
     369           0 :     mbHeaderLayout = r.mbHeaderLayout;
     370           0 :     bAllowMove = false;
     371           0 :     bSettingsChanged = false;
     372           0 :     mbEnableGetPivotData = r.mbEnableGetPivotData;
     373             : 
     374           0 :     if (r.pSaveData)
     375           0 :         pSaveData = new ScDPSaveData(*r.pSaveData);
     376           0 :     if (r.pSheetDesc)
     377           0 :         pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
     378           0 :     if (r.pImpDesc)
     379           0 :         pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
     380           0 :     if (r.pServDesc)
     381           0 :         pServDesc = new ScDPServiceDesc(*r.pServDesc);
     382             : 
     383           0 :     return *this;
     384             : }
     385             : 
     386         192 : void ScDPObject::EnableGetPivotData(bool b)
     387             : {
     388         192 :     mbEnableGetPivotData = b;
     389         192 : }
     390             : 
     391          29 : void ScDPObject::SetAllowMove(bool bSet)
     392             : {
     393          29 :     bAllowMove = bSet;
     394          29 : }
     395             : 
     396          88 : void ScDPObject::SetSaveData(const ScDPSaveData& rData)
     397             : {
     398          88 :     if ( pSaveData != &rData )      // API implementation modifies the original SaveData object
     399             :     {
     400          81 :         delete pSaveData;
     401          81 :         pSaveData = new ScDPSaveData( rData );
     402             :     }
     403             : 
     404          88 :     InvalidateData();       // re-init source from SaveData
     405          88 : }
     406             : 
     407          12 : void ScDPObject::SetHeaderLayout (bool bUseGrid)
     408             : {
     409          12 :     mbHeaderLayout = bUseGrid;
     410          12 : }
     411             : 
     412         119 : void ScDPObject::SetOutRange(const ScRange& rRange)
     413             : {
     414         119 :     aOutRange = rRange;
     415             : 
     416         119 :     if ( pOutput )
     417          66 :         pOutput->SetPosition( rRange.aStart );
     418         119 : }
     419             : 
     420        1762 : const ScRange& ScDPObject::GetOutRange() const
     421             : {
     422        1762 :     return aOutRange;
     423             : }
     424             : 
     425          78 : void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool /*bFromRefUpdate*/)
     426             : {
     427          78 :     if ( pSheetDesc && rDesc == *pSheetDesc )
     428          78 :         return;             // nothing to do
     429             : 
     430          78 :     DELETEZ( pImpDesc );
     431          78 :     DELETEZ( pServDesc );
     432             : 
     433          78 :     delete pSheetDesc;
     434          78 :     pSheetDesc = new ScSheetSourceDesc(rDesc);
     435             : 
     436             :     //  make valid QueryParam
     437             : 
     438          78 :     const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
     439          78 :     ScQueryParam aParam = pSheetDesc->GetQueryParam();
     440          78 :     aParam.nCol1 = rSrcRange.aStart.Col();
     441          78 :     aParam.nRow1 = rSrcRange.aStart.Row();
     442          78 :     aParam.nCol2 = rSrcRange.aEnd.Col();
     443          78 :     aParam.nRow2 = rSrcRange.aEnd.Row();
     444          78 :     aParam.bHasHeader = true;
     445          78 :     pSheetDesc->SetQueryParam(aParam);
     446             : 
     447          78 :     ClearTableData();      // new source must be created
     448             : }
     449             : 
     450           0 : void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
     451             : {
     452           0 :     if ( pImpDesc && rDesc == *pImpDesc )
     453           0 :         return;             // nothing to do
     454             : 
     455           0 :     DELETEZ( pSheetDesc );
     456           0 :     DELETEZ( pServDesc );
     457             : 
     458           0 :     delete pImpDesc;
     459           0 :     pImpDesc = new ScImportSourceDesc(rDesc);
     460             : 
     461           0 :     ClearTableData();      // new source must be created
     462             : }
     463             : 
     464           0 : void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
     465             : {
     466           0 :     if ( pServDesc && rDesc == *pServDesc )
     467           0 :         return;             // nothing to do
     468             : 
     469           0 :     DELETEZ( pSheetDesc );
     470           0 :     DELETEZ( pImpDesc );
     471             : 
     472           0 :     delete pServDesc;
     473           0 :     pServDesc = new ScDPServiceDesc(rDesc);
     474             : 
     475           0 :     ClearTableData();      // new source must be created
     476             : }
     477             : 
     478           0 : void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
     479             : {
     480           0 :     if ( pSheetDesc )
     481           0 :         rDest.SetSheetDesc( *pSheetDesc );
     482           0 :     else if ( pImpDesc )
     483           0 :         rDest.SetImportDesc( *pImpDesc );
     484           0 :     else if ( pServDesc )
     485           0 :         rDest.SetServiceData( *pServDesc );
     486             : 
     487             :     //  name/tag are not source data, but needed along with source data
     488             : 
     489           0 :     rDest.aTableName = aTableName;
     490           0 :     rDest.aTableTag  = aTableTag;
     491           0 : }
     492             : 
     493           0 : void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
     494             : {
     495           0 :     rDest.nHeaderRows = nHeaderRows;
     496           0 : }
     497             : 
     498         141 : bool ScDPObject::IsSheetData() const
     499             : {
     500         141 :     return ( pSheetDesc != NULL );
     501             : }
     502             : 
     503          56 : void ScDPObject::SetName(const OUString& rNew)
     504             : {
     505          56 :     aTableName = rNew;
     506          56 : }
     507             : 
     508          38 : void ScDPObject::SetTag(const OUString& rNew)
     509             : {
     510          38 :     aTableTag = rNew;
     511          38 : }
     512             : 
     513           0 : bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
     514             : {
     515           0 :     if (!pSaveData)
     516           0 :         return false;
     517             : 
     518           0 :     long nDataDimCount = pSaveData->GetDataDimensionCount();
     519           0 :     if (nDataDimCount != 1)
     520             :         // There has to be exactly one data dimension for the description to
     521             :         // appear at top-left corner.
     522           0 :         return false;
     523             : 
     524           0 :     CreateOutput();
     525           0 :     ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE);
     526           0 :     return (rPos == aTabRange.aStart);
     527             : }
     528             : 
     529         418 : uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
     530             : {
     531         418 :     CreateObjects();
     532         418 :     return xSource;
     533             : }
     534             : 
     535         684 : void ScDPObject::CreateOutput()
     536             : {
     537         684 :     CreateObjects();
     538         684 :     if (!pOutput)
     539             :     {
     540          88 :         bool bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
     541          88 :         pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
     542          88 :         pOutput->SetHeaderLayout ( mbHeaderLayout );
     543             : 
     544          88 :         long nOldRows = nHeaderRows;
     545          88 :         nHeaderRows = pOutput->GetHeaderRows();
     546             : 
     547          88 :         if ( bAllowMove && nHeaderRows != nOldRows )
     548             :         {
     549           0 :             long nDiff = nOldRows - nHeaderRows;
     550           0 :             if ( nOldRows == 0 )
     551           0 :                 --nDiff;
     552           0 :             if ( nHeaderRows == 0 )
     553           0 :                 ++nDiff;
     554             : 
     555           0 :             long nNewRow = aOutRange.aStart.Row() + nDiff;
     556           0 :             if ( nNewRow < 0 )
     557           0 :                 nNewRow = 0;
     558             : 
     559           0 :             ScAddress aStart( aOutRange.aStart );
     560           0 :             aStart.SetRow(nNewRow);
     561           0 :             pOutput->SetPosition( aStart );
     562             : 
     563             :             //TODO: modify aOutRange?
     564             : 
     565           0 :             bAllowMove = false;     // use only once
     566             :         }
     567             :     }
     568         684 : }
     569             : 
     570             : namespace {
     571             : 
     572             : class DisableGetPivotData
     573             : {
     574             :     ScDPObject& mrDPObj;
     575             :     bool mbOldState;
     576             : public:
     577          96 :     DisableGetPivotData(ScDPObject& rObj, bool bOld) : mrDPObj(rObj), mbOldState(bOld)
     578             :     {
     579          96 :         mrDPObj.EnableGetPivotData(false);
     580          96 :     }
     581             : 
     582          96 :     ~DisableGetPivotData()
     583             :     {
     584          96 :         mrDPObj.EnableGetPivotData(mbOldState);
     585          96 :     }
     586             : };
     587             : 
     588           0 : class FindIntersectingTable : std::unary_function<ScDPObject, bool>
     589             : {
     590             :     ScRange maRange;
     591             : public:
     592           0 :     FindIntersectingTable(const ScRange& rRange) : maRange(rRange) {}
     593             : 
     594           0 :     bool operator() (const ScDPObject& rObj) const
     595             :     {
     596           0 :         return maRange.Intersects(rObj.GetOutRange());
     597             :     }
     598             : };
     599             : 
     600             : class FindIntersetingTableByColumns : std::unary_function<ScDPObject, bool>
     601             : {
     602             :     SCCOL mnCol1;
     603             :     SCCOL mnCol2;
     604             :     SCROW mnRow;
     605             :     SCTAB mnTab;
     606             : public:
     607           0 :     FindIntersetingTableByColumns(SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab) :
     608           0 :         mnCol1(nCol1), mnCol2(nCol2), mnRow(nRow), mnTab(nTab) {}
     609             : 
     610           0 :     bool operator() (const ScDPObject& rObj) const
     611             :     {
     612           0 :         const ScRange& rRange = rObj.GetOutRange();
     613           0 :         if (mnTab != rRange.aStart.Tab())
     614             :             // Not on this sheet.
     615           0 :             return false;
     616             : 
     617           0 :         if (rRange.aEnd.Row() < mnRow)
     618             :             // This table is above the row.  It's safe.
     619           0 :             return false;
     620             : 
     621           0 :         if (mnCol1 <= rRange.aStart.Col() && rRange.aEnd.Col() <= mnCol2)
     622             :             // This table is fully enclosed in this column range.
     623           0 :             return false;
     624             : 
     625           0 :         if (rRange.aEnd.Col() < mnCol1 || mnCol2 < rRange.aStart.Col())
     626             :             // This table is entirely outside this column range.
     627           0 :             return false;
     628             : 
     629             :         // This table must be intersected by this column range.
     630           0 :         return true;
     631             :     }
     632             : };
     633             : 
     634             : class FindIntersectingTableByRows : std::unary_function<ScDPObject, bool>
     635             : {
     636             :     SCCOL mnCol;
     637             :     SCROW mnRow1;
     638             :     SCROW mnRow2;
     639             :     SCTAB mnTab;
     640             : public:
     641           0 :     FindIntersectingTableByRows(SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab) :
     642           0 :         mnCol(nCol), mnRow1(nRow1), mnRow2(nRow2), mnTab(nTab) {}
     643             : 
     644           0 :     bool operator() (const ScDPObject& rObj) const
     645             :     {
     646           0 :         const ScRange& rRange = rObj.GetOutRange();
     647           0 :         if (mnTab != rRange.aStart.Tab())
     648             :             // Not on this sheet.
     649           0 :             return false;
     650             : 
     651           0 :         if (rRange.aEnd.Col() < mnCol)
     652             :             // This table is to the left of the column.  It's safe.
     653           0 :             return false;
     654             : 
     655           0 :         if (mnRow1 <= rRange.aStart.Row() && rRange.aEnd.Row() <= mnRow2)
     656             :             // This table is fully enclosed in this row range.
     657           0 :             return false;
     658             : 
     659           0 :         if (rRange.aEnd.Row() < mnRow1 || mnRow2 < rRange.aStart.Row())
     660             :             // This table is entirely outside this row range.
     661           0 :             return false;
     662             : 
     663             :         // This table must be intersected by this row range.
     664           0 :         return true;
     665             :     }
     666             : };
     667             : 
     668         192 : class AccumulateOutputRanges : std::unary_function<ScDPObject, void>
     669             : {
     670             :     ScRangeList maRanges;
     671             :     SCTAB mnTab;
     672             : public:
     673          96 :     AccumulateOutputRanges(SCTAB nTab) : mnTab(nTab) {}
     674          96 :     AccumulateOutputRanges(const AccumulateOutputRanges& r) : maRanges(r.maRanges), mnTab(r.mnTab) {}
     675             : 
     676         192 :     void operator() (const ScDPObject& rObj)
     677             :     {
     678         192 :         const ScRange& rRange = rObj.GetOutRange();
     679         192 :         if (mnTab != rRange.aStart.Tab())
     680             :             // Not on this sheet.
     681         384 :             return;
     682             : 
     683           0 :         maRanges.Join(rRange);
     684             :     }
     685             : 
     686          96 :     ScRangeList getRanges() const { return maRanges; }
     687             : };
     688             : 
     689             : }
     690             : 
     691         177 : ScDPTableData* ScDPObject::GetTableData()
     692             : {
     693         177 :     if (!mpTableData)
     694             :     {
     695          96 :         shared_ptr<ScDPTableData> pData;
     696          96 :         const ScDPDimensionSaveData* pDimData = pSaveData ? pSaveData->GetExistingDimensionData() : NULL;
     697             : 
     698          96 :         if ( pImpDesc )
     699             :         {
     700             :             // database data
     701           0 :             const ScDPCache* pCache = pImpDesc->CreateCache(pDimData);
     702           0 :             if (pCache)
     703             :             {
     704           0 :                 pCache->AddReference(this);
     705           0 :                 pData.reset(new ScDatabaseDPData(pDoc, *pCache));
     706             :             }
     707             :         }
     708             :         else
     709             :         {
     710             :             // cell data
     711          96 :             if (!pSheetDesc)
     712             :             {
     713             :                 OSL_FAIL("no source descriptor");
     714           0 :                 pSheetDesc = new ScSheetSourceDesc(pDoc);     // dummy defaults
     715             :             }
     716             : 
     717             :             {
     718             :                 // Temporarily disable GETPIVOTDATA to avoid having
     719             :                 // GETPIVOTDATA called onto itself from within the source
     720             :                 // range.
     721          96 :                 DisableGetPivotData aSwitch(*this, mbEnableGetPivotData);
     722          96 :                 const ScDPCache* pCache = pSheetDesc->CreateCache(pDimData);
     723          96 :                 if (pCache)
     724             :                 {
     725          96 :                     pCache->AddReference(this);
     726          96 :                     pData.reset(new ScSheetDPData(pDoc, *pSheetDesc, *pCache));
     727          96 :                 }
     728             :             }
     729             :         }
     730             : 
     731             :         // grouping (for cell or database data)
     732          96 :         if (pData && pDimData)
     733             :         {
     734           4 :             shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pData, pDoc));
     735           4 :             pDimData->WriteToData(*pGroupData);
     736           4 :             pData = pGroupData;
     737             :         }
     738             : 
     739          96 :         mpTableData = pData;                        // after SetCacheId
     740             :     }
     741             : 
     742         177 :     return mpTableData.get();
     743             : }
     744             : 
     745        1165 : void ScDPObject::CreateObjects()
     746             : {
     747        1165 :     if (!xSource.is())
     748             :     {
     749         122 :         DELETEZ( pOutput );     // not valid when xSource is changed
     750             : 
     751         122 :         if ( pServDesc )
     752             :         {
     753           0 :             xSource = CreateSource( *pServDesc );
     754             :         }
     755             : 
     756         122 :         if ( !xSource.is() )    // database or sheet data, or error in CreateSource
     757             :         {
     758             :             OSL_ENSURE( !pServDesc, "DPSource could not be created" );
     759         122 :             ScDPTableData* pData = GetTableData();
     760         122 :             if (pData)
     761             :             {
     762         122 :                 if (pSaveData)
     763             :                     // Make sure to transfer these flags to the table data
     764             :                     // since they may have changed.
     765         122 :                     pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
     766             : 
     767         122 :                 pData->ReloadCacheTable();
     768         122 :                 ScDPSource* pSource = new ScDPSource( pData );
     769         122 :                 xSource = pSource;
     770             :             }
     771             :         }
     772             : 
     773         122 :         if (pSaveData)
     774         122 :             pSaveData->WriteToSource( xSource );
     775             :     }
     776        1043 :     else if (bSettingsChanged)
     777             :     {
     778           9 :         DELETEZ( pOutput );     // not valid when xSource is changed
     779             : 
     780           9 :         uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
     781           9 :         if (xRef.is())
     782             :         {
     783             :             try
     784             :             {
     785           9 :                 xRef->refresh();
     786             :             }
     787           0 :             catch(uno::Exception&)
     788             :             {
     789             :                 OSL_FAIL("exception in refresh");
     790             :             }
     791             :         }
     792             : 
     793           9 :         if (pSaveData)
     794           9 :             pSaveData->WriteToSource( xSource );
     795             :     }
     796        1165 :     bSettingsChanged = false;
     797        1165 : }
     798             : 
     799         161 : void ScDPObject::InvalidateData()
     800             : {
     801         161 :     bSettingsChanged = true;
     802         161 : }
     803             : 
     804         162 : void ScDPObject::Clear()
     805             : {
     806         162 :     delete pOutput;
     807         162 :     delete pSaveData;
     808         162 :     delete pSheetDesc;
     809         162 :     delete pImpDesc;
     810         162 :     delete pServDesc;
     811         162 :     pOutput = NULL;
     812         162 :     pSaveData = NULL;
     813         162 :     pSheetDesc = NULL;
     814         162 :     pImpDesc = NULL;
     815         162 :     pServDesc = NULL;
     816         162 :     ClearTableData();
     817         162 : }
     818             : 
     819         257 : void ScDPObject::ClearTableData()
     820             : {
     821         257 :     ClearSource();
     822             : 
     823         257 :     if (mpTableData)
     824          94 :         mpTableData->GetCacheTable().getCache().RemoveReference(this);
     825         257 :     mpTableData.reset();
     826         257 : }
     827             : 
     828          57 : void ScDPObject::ReloadGroupTableData()
     829             : {
     830          57 :     ClearSource();
     831             : 
     832          57 :     if (!mpTableData)
     833             :         // Table data not built yet.  No need to reload the group data.
     834          29 :         return;
     835             : 
     836          28 :     if (!pSaveData)
     837             :         // How could it not have the save data... but whatever.
     838           0 :         return;
     839             : 
     840          28 :     const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
     841          28 :     if (!pDimData || !pDimData->HasGroupDimensions())
     842             :     {
     843             :         // No group dimensions exist.  Check if it currently has group
     844             :         // dimensions, and if so, remove all of them.
     845          21 :         ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
     846          21 :         if (pData)
     847             :         {
     848             :             // Replace the existing group table data with the source data.
     849           1 :             shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
     850           1 :             mpTableData = pSource;
     851             :         }
     852          21 :         return;
     853             :     }
     854             : 
     855           7 :     ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
     856           7 :     if (pData)
     857             :     {
     858             :         // This is already a group table data. Salvage the source data and
     859             :         // re-create a new group data.
     860           2 :         shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
     861           4 :         shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pSource, pDoc));
     862           2 :         pDimData->WriteToData(*pGroupData);
     863           4 :         mpTableData = pGroupData;
     864             :     }
     865             :     else
     866             :     {
     867             :         // This is a source data.  Create a group data based on it.
     868           5 :         shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
     869           5 :         pDimData->WriteToData(*pGroupData);
     870           5 :         mpTableData = pGroupData;
     871             :     }
     872             : 
     873           7 :     bSettingsChanged = true;
     874             : }
     875             : 
     876         314 : void ScDPObject::ClearSource()
     877             : {
     878         314 :     Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
     879         314 :     if (xObjectComp.is())
     880             :     {
     881             :         try
     882             :         {
     883           0 :             xObjectComp->dispose();
     884             :         }
     885           0 :         catch( const Exception& )
     886             :         {
     887             :             DBG_UNHANDLED_EXCEPTION();
     888             :         }
     889             :     }
     890         314 :     xSource = NULL;
     891         314 : }
     892             : 
     893          85 : ScRange ScDPObject::GetNewOutputRange( bool& rOverflow )
     894             : {
     895          85 :     CreateOutput();             // create xSource and pOutput if not already done
     896             : 
     897          85 :     rOverflow = pOutput->HasError();        // range overflow or exception from source
     898          85 :     if ( rOverflow )
     899           0 :         return ScRange( aOutRange.aStart );
     900             :     else
     901             :     {
     902             :         //  don't store the result in aOutRange, because nothing has been output yet
     903          85 :         return pOutput->GetOutputRange();
     904             :     }
     905             : }
     906             : 
     907          87 : void ScDPObject::Output( const ScAddress& rPos )
     908             : {
     909             :     //  clear old output area
     910          87 :     pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
     911          87 :                          aOutRange.aEnd.Col(),   aOutRange.aEnd.Row(),
     912         261 :                          aOutRange.aStart.Tab(), IDF_ALL );
     913          87 :     pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
     914          87 :                           aOutRange.aEnd.Col(),   aOutRange.aEnd.Row(),
     915         261 :                           aOutRange.aStart.Tab(), SC_MF_AUTO );
     916             : 
     917          87 :     CreateOutput();             // create xSource and pOutput if not already done
     918             : 
     919          87 :     pOutput->SetPosition( rPos );
     920             : 
     921          87 :     pOutput->Output();
     922             : 
     923             :     //  aOutRange is always the range that was last output to the document
     924          87 :     aOutRange = pOutput->GetOutputRange();
     925          87 :     const ScAddress& s = aOutRange.aStart;
     926          87 :     const ScAddress& e = aOutRange.aEnd;
     927          87 :     pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
     928          87 : }
     929             : 
     930          15 : ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
     931             : {
     932          15 :     CreateOutput();
     933             : 
     934          15 :     if (pOutput->HasError())
     935           0 :         return ScRange(aOutRange.aStart);
     936             : 
     937          15 :     return pOutput->GetOutputRange(nType);
     938             : }
     939             : 
     940           4 : ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) const
     941             : {
     942           4 :     if (!pOutput || pOutput->HasError())
     943           0 :         return ScRange(ScAddress::INITIALIZE_INVALID);
     944             : 
     945           4 :     return pOutput->GetOutputRange(nType);
     946             : }
     947             : 
     948          28 : static bool lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
     949             : {
     950          28 :     return static_cast<const ScMergeFlagAttr*>(pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasPivotButton();
     951             : }
     952             : 
     953          11 : void ScDPObject::RefreshAfterLoad()
     954             : {
     955             :     // apply drop-down attribute, initialize nHeaderRows, without accessing the source
     956             :     // (button attribute must be present)
     957             : 
     958             :     // simple test: block of button cells at the top, followed by an empty cell
     959             : 
     960          11 :     SCCOL nFirstCol = aOutRange.aStart.Col();
     961          11 :     SCROW nFirstRow = aOutRange.aStart.Row();
     962          11 :     SCTAB nTab = aOutRange.aStart.Tab();
     963             : 
     964          11 :     SCROW nInitial = 0;
     965          11 :     SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
     966          39 :     while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
     967          17 :         ++nInitial;
     968             : 
     969          33 :     if ( nInitial + 1 < nOutRows &&
     970          20 :         pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
     971           9 :         aOutRange.aEnd.Col() > nFirstCol )
     972             :     {
     973           8 :         nHeaderRows = nInitial;
     974             :     }
     975             :     else
     976           3 :         nHeaderRows = 0;        // nothing found, no drop-down lists
     977          11 : }
     978             : 
     979           4 : void ScDPObject::BuildAllDimensionMembers()
     980             : {
     981           4 :     if (!pSaveData)
     982           0 :         return;
     983             : 
     984             :     // #i111857# don't always create empty mpTableData for external service.
     985           4 :     if (pServDesc)
     986           0 :         return;
     987             : 
     988           4 :     ScDPTableData* pTableData = GetTableData();
     989           4 :     if(pTableData)
     990           4 :         pSaveData->BuildAllDimensionMembers(pTableData);
     991             : }
     992             : 
     993          51 : bool ScDPObject::SyncAllDimensionMembers()
     994             : {
     995          51 :     if (!pSaveData)
     996           0 :         return false;
     997             : 
     998             :     // #i111857# don't always create empty mpTableData for external service.
     999             :     // Ideally, xSource should be used instead of mpTableData.
    1000          51 :     if (pServDesc)
    1001           0 :         return false;
    1002             : 
    1003          51 :     ScDPTableData* pData = GetTableData();
    1004          51 :     if (!pData)
    1005             :         // No table data exists.  This can happen when refreshing from an
    1006             :         // external source which doesn't exist.
    1007           0 :         return false;
    1008             : 
    1009             :     // Refresh the cache wrapper since the cache may have changed.
    1010          51 :     pData->SetEmptyFlags(pSaveData->GetIgnoreEmptyRows(), pSaveData->GetRepeatIfEmpty());
    1011          51 :     pData->ReloadCacheTable();
    1012          51 :     pSaveData->SyncAllDimensionMembers(pData);
    1013          51 :     return true;
    1014             : }
    1015             : 
    1016           2 : bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames )
    1017             : {
    1018           2 :     vector<ScDPLabelData::Member> aMembers;
    1019           2 :     if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers))
    1020           0 :         return false;
    1021             : 
    1022           2 :     size_t n = aMembers.size();
    1023           2 :     rNames.realloc(n);
    1024          12 :     for (size_t i = 0; i < n; ++i)
    1025          10 :         rNames[i] = aMembers[i].maName;
    1026             : 
    1027           2 :     return true;
    1028             : }
    1029             : 
    1030           5 : bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers )
    1031             : {
    1032           5 :     Reference< container::XNameAccess > xMembersNA;
    1033           5 :     if (!GetMembersNA( nDim, nHier, xMembersNA ))
    1034           0 :         return false;
    1035             : 
    1036          10 :     Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) );
    1037           5 :     sal_Int32 nCount = xMembersIA->getCount();
    1038          10 :     vector<ScDPLabelData::Member> aMembers;
    1039           5 :     aMembers.reserve(nCount);
    1040             : 
    1041          37 :     for (sal_Int32 i = 0; i < nCount; ++i)
    1042             :     {
    1043          32 :         Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY);
    1044          64 :         ScDPLabelData::Member aMem;
    1045             : 
    1046          32 :         if (xMember.is())
    1047          32 :             aMem.maName = xMember->getName();
    1048             : 
    1049          64 :         Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY);
    1050          32 :         if (xMemProp.is())
    1051             :         {
    1052          32 :             aMem.mbVisible     = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString(SC_UNO_DP_ISVISIBLE));
    1053          32 :             aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString(SC_UNO_DP_SHOWDETAILS));
    1054             : 
    1055          64 :             aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty(
    1056          32 :                 xMemProp, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
    1057             :         }
    1058             : 
    1059          32 :         aMembers.push_back(aMem);
    1060          32 :     }
    1061           5 :     rMembers.swap(aMembers);
    1062          10 :     return true;
    1063             : }
    1064             : 
    1065          66 : void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
    1066             :                                      const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
    1067             : {
    1068             :     // Output area
    1069             : 
    1070          66 :     SCCOL nCol1 = aOutRange.aStart.Col();
    1071          66 :     SCROW nRow1 = aOutRange.aStart.Row();
    1072          66 :     SCTAB nTab1 = aOutRange.aStart.Tab();
    1073          66 :     SCCOL nCol2 = aOutRange.aEnd.Col();
    1074          66 :     SCROW nRow2 = aOutRange.aEnd.Row();
    1075          66 :     SCTAB nTab2 = aOutRange.aEnd.Tab();
    1076             : 
    1077             :     ScRefUpdateRes eRes =
    1078             :         ScRefUpdate::Update( pDoc, eUpdateRefMode,
    1079         132 :             rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
    1080         132 :             rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
    1081         330 :             nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    1082          66 :     if ( eRes != UR_NOTHING )
    1083          66 :         SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
    1084             : 
    1085             :     // sheet source data
    1086             : 
    1087          66 :     if ( pSheetDesc )
    1088             :     {
    1089          66 :         const OUString& rRangeName = pSheetDesc->GetRangeName();
    1090          66 :         if (!rRangeName.isEmpty())
    1091             :             // Source range is a named range.  No need to update.
    1092           2 :             return;
    1093             : 
    1094          65 :         const ScRange& rSrcRange = pSheetDesc->GetSourceRange();
    1095          65 :         nCol1 = rSrcRange.aStart.Col();
    1096          65 :         nRow1 = rSrcRange.aStart.Row();
    1097          65 :         nTab1 = rSrcRange.aStart.Tab();
    1098          65 :         nCol2 = rSrcRange.aEnd.Col();
    1099          65 :         nRow2 = rSrcRange.aEnd.Row();
    1100          65 :         nTab2 = rSrcRange.aEnd.Tab();
    1101             : 
    1102             :         eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
    1103         130 :                 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
    1104         130 :                 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
    1105         325 :                 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    1106          65 :         if ( eRes != UR_NOTHING )
    1107             :         {
    1108          65 :             SCsCOL nDiffX = nCol1 - pSheetDesc->GetSourceRange().aStart.Col();
    1109          65 :             SCsROW nDiffY = nRow1 - pSheetDesc->GetSourceRange().aStart.Row();
    1110             : 
    1111          65 :             ScQueryParam aParam = pSheetDesc->GetQueryParam();
    1112          65 :             aParam.nCol1 = sal::static_int_cast<SCCOL>( aParam.nCol1 + nDiffX );
    1113          65 :             aParam.nCol2 = sal::static_int_cast<SCCOL>( aParam.nCol2 + nDiffX );
    1114          65 :             aParam.nRow1 += nDiffY; //TODO: used?
    1115          65 :             aParam.nRow2 += nDiffY; //TODO: used?
    1116          65 :             SCSIZE nEC = aParam.GetEntryCount();
    1117         585 :             for (SCSIZE i=0; i<nEC; i++)
    1118         520 :                 if (aParam.GetEntry(i).bDoQuery)
    1119          64 :                     aParam.GetEntry(i).nField += nDiffX;
    1120             : 
    1121          65 :             pSheetDesc->SetQueryParam(aParam);
    1122          65 :             pSheetDesc->SetSourceRange(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
    1123             :         }
    1124             :     }
    1125             : }
    1126             : 
    1127           0 : bool ScDPObject::RefsEqual( const ScDPObject& r ) const
    1128             : {
    1129           0 :     if ( aOutRange != r.aOutRange )
    1130           0 :         return false;
    1131             : 
    1132           0 :     if ( pSheetDesc && r.pSheetDesc )
    1133             :     {
    1134           0 :         if ( pSheetDesc->GetSourceRange() != r.pSheetDesc->GetSourceRange() )
    1135           0 :             return false;
    1136             :     }
    1137           0 :     else if ( pSheetDesc || r.pSheetDesc )
    1138             :     {
    1139             :         OSL_FAIL("RefsEqual: SheetDesc set at only one object");
    1140           0 :         return false;
    1141             :     }
    1142             : 
    1143           0 :     return true;
    1144             : }
    1145             : 
    1146           0 : void ScDPObject::WriteRefsTo( ScDPObject& r ) const
    1147             : {
    1148           0 :     r.SetOutRange( aOutRange );
    1149           0 :     if ( pSheetDesc )
    1150           0 :         r.SetSheetDesc( *pSheetDesc, true );
    1151           0 : }
    1152             : 
    1153         266 : void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
    1154             : {
    1155         266 :     CreateOutput();
    1156         266 :     pOutput->GetPositionData(rPos, rPosData);
    1157         266 : }
    1158             : 
    1159         133 : bool ScDPObject::GetDataFieldPositionData(
    1160             :     const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
    1161             : {
    1162         133 :     CreateOutput();
    1163             : 
    1164         133 :     vector<sheet::DataPilotFieldFilter> aFilters;
    1165         133 :     if (!pOutput->GetDataResultPositionData(aFilters, rPos))
    1166           0 :         return false;
    1167             : 
    1168         133 :     sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
    1169         133 :     rFilters.realloc(n);
    1170         593 :     for (sal_Int32 i = 0; i < n; ++i)
    1171         460 :         rFilters[i] = aFilters[i];
    1172             : 
    1173         133 :     return true;
    1174             : }
    1175             : 
    1176          97 : void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
    1177             : {
    1178          97 :     CreateOutput();
    1179             : 
    1180          97 :     Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
    1181          97 :     if (!xDrillDownData.is())
    1182           0 :         return;
    1183             : 
    1184         194 :     Sequence<sheet::DataPilotFieldFilter> filters;
    1185          97 :     if (!GetDataFieldPositionData(rPos, filters))
    1186           0 :         return;
    1187             : 
    1188         194 :     rTableData = xDrillDownData->getDrillDownData(filters);
    1189             : }
    1190             : 
    1191          48 : bool ScDPObject::IsDimNameInUse(const OUString& rName) const
    1192             : {
    1193          48 :     if (!xSource.is())
    1194           2 :         return false;
    1195             : 
    1196          46 :     Reference<container::XNameAccess> xDims = xSource->getDimensions();
    1197          92 :     Sequence<OUString> aDimNames = xDims->getElementNames();
    1198          46 :     sal_Int32 n = aDimNames.getLength();
    1199         219 :     for (sal_Int32 i = 0; i < n; ++i)
    1200             :     {
    1201         212 :         const OUString& rDimName = aDimNames[i];
    1202         212 :         if (rDimName.equalsIgnoreAsciiCase(rName))
    1203          76 :             return true;
    1204             : 
    1205         175 :         Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY);
    1206         175 :         if (!xPropSet.is())
    1207           0 :             continue;
    1208             : 
    1209             :         OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
    1210         348 :             xPropSet, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
    1211         175 :         if (aLayoutName.equalsIgnoreAsciiCase(rName))
    1212           2 :             return true;
    1213         173 :     }
    1214          53 :     return false;
    1215             : }
    1216             : 
    1217          60 : OUString ScDPObject::GetDimName( long nDim, bool& rIsDataLayout, sal_Int32* pFlags )
    1218             : {
    1219          60 :     rIsDataLayout = false;
    1220          60 :     OUString aRet;
    1221             : 
    1222          60 :     if ( xSource.is() )
    1223             :     {
    1224          60 :         uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1225         120 :         uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
    1226          60 :         long nDimCount = xDims->getCount();
    1227          60 :         if ( nDim < nDimCount )
    1228             :         {
    1229             :             uno::Reference<uno::XInterface> xIntDim =
    1230          60 :                 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
    1231         120 :             uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
    1232         120 :             uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
    1233          60 :             if ( xDimName.is() && xDimProp.is() )
    1234             :             {
    1235             :                 bool bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
    1236          60 :                                 OUString(SC_UNO_DP_ISDATALAYOUT) );
    1237             :                 //TODO: error checking -- is "IsDataLayoutDimension" property required??
    1238             : 
    1239          60 :                 OUString aName;
    1240             :                 try
    1241             :                 {
    1242          60 :                     aName = xDimName->getName();
    1243             :                 }
    1244           0 :                 catch(uno::Exception&)
    1245             :                 {
    1246             :                 }
    1247          60 :                 if ( bData )
    1248           0 :                     rIsDataLayout = true;
    1249             :                 else
    1250          60 :                     aRet = aName;
    1251             : 
    1252          60 :                 if (pFlags)
    1253             :                     *pFlags = ScUnoHelpFunctions::GetLongProperty( xDimProp,
    1254           0 :                                 OUString(SC_UNO_DP_FLAGS), 0 );
    1255          60 :             }
    1256          60 :         }
    1257             :     }
    1258             : 
    1259          60 :     return aRet;
    1260             : }
    1261             : 
    1262           0 : bool ScDPObject::IsDuplicated( long nDim )
    1263             : {
    1264           0 :     bool bDuplicated = false;
    1265           0 :     if ( xSource.is() )
    1266             :     {
    1267           0 :         uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1268           0 :         uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
    1269           0 :         long nDimCount = xDims->getCount();
    1270           0 :         if ( nDim < nDimCount )
    1271             :         {
    1272             :             uno::Reference<uno::XInterface> xIntDim =
    1273           0 :                 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
    1274           0 :             uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
    1275           0 :             if ( xDimProp.is() )
    1276             :             {
    1277             :                 try
    1278             :                 {
    1279           0 :                     uno::Any aOrigAny = xDimProp->getPropertyValue(
    1280           0 :                                 OUString(SC_UNO_DP_ORIGINAL) );
    1281           0 :                     uno::Reference<uno::XInterface> xIntOrig;
    1282           0 :                     if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
    1283           0 :                         bDuplicated = true;
    1284             :                 }
    1285           0 :                 catch(uno::Exception&)
    1286             :                 {
    1287             :                 }
    1288           0 :             }
    1289           0 :         }
    1290             :     }
    1291           0 :     return bDuplicated;
    1292             : }
    1293             : 
    1294          60 : long ScDPObject::GetDimCount()
    1295             : {
    1296          60 :     long nRet = 0;
    1297          60 :     if ( xSource.is() )
    1298             :     {
    1299             :         try
    1300             :         {
    1301          60 :             uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1302          60 :             if ( xDimsName.is() )
    1303          60 :                 nRet = xDimsName->getElementNames().getLength();
    1304             :         }
    1305           0 :         catch(uno::Exception&)
    1306             :         {
    1307             :         }
    1308             :     }
    1309          60 :     return nRet;
    1310             : }
    1311             : 
    1312           0 : void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
    1313             : {
    1314             :     using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
    1315             : 
    1316           0 :     CreateOutput();             // create xSource and pOutput if not already done
    1317             : 
    1318             :     // Reset member values to invalid state.
    1319           0 :     rData.Dimension = rData.Hierarchy = rData.Level = -1;
    1320           0 :     rData.Flags = 0;
    1321             : 
    1322           0 :     DataPilotTablePositionData aPosData;
    1323           0 :     pOutput->GetPositionData(rPos, aPosData);
    1324           0 :     const sal_Int32 nPosType = aPosData.PositionType;
    1325           0 :     if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
    1326           0 :         aPosData.PositionData >>= rData;
    1327           0 : }
    1328             : 
    1329             : namespace {
    1330             : 
    1331         129 : class FindByName : std::unary_function<const ScDPSaveDimension*, bool>
    1332             : {
    1333             :     OUString maName; // must be all uppercase.
    1334             : public:
    1335          43 :     FindByName(const OUString& rName) : maName(rName) {}
    1336          46 :     bool operator() (const ScDPSaveDimension* pDim) const
    1337             :     {
    1338             :         // Layout name takes precedence.
    1339          46 :         const OUString* pLayoutName = pDim->GetLayoutName();
    1340          46 :         if (pLayoutName && ScGlobal::pCharClass->uppercase(*pLayoutName) == maName)
    1341           2 :             return true;
    1342             : 
    1343          44 :         sheet::GeneralFunction eGenFunc = static_cast<sheet::GeneralFunction>(pDim->GetFunction());
    1344          44 :         ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(eGenFunc);
    1345          44 :         OUString aSrcName = ScDPUtil::getSourceDimensionName(pDim->GetName());
    1346          88 :         OUString aFuncName = ScDPUtil::getDisplayedMeasureName(aSrcName, eFunc);
    1347          44 :         if (maName == ScGlobal::pCharClass->uppercase(aFuncName))
    1348           6 :             return true;
    1349             : 
    1350          82 :         return maName == ScGlobal::pCharClass->uppercase(aSrcName);
    1351             :     }
    1352             : };
    1353             : 
    1354             : class LessByDimOrder : std::binary_function<sheet::DataPilotFieldFilter, sheet::DataPilotFieldFilter, bool>
    1355             : {
    1356             :     const ScDPSaveData::DimOrderType& mrDimOrder;
    1357             : 
    1358             : public:
    1359          43 :     LessByDimOrder(const ScDPSaveData::DimOrderType& rDimOrder) : mrDimOrder(rDimOrder) {}
    1360             : 
    1361          10 :     bool operator() (const sheet::DataPilotFieldFilter& r1, const sheet::DataPilotFieldFilter& r2) const
    1362             :     {
    1363          10 :         size_t nRank1 = mrDimOrder.size();
    1364          10 :         size_t nRank2 = mrDimOrder.size();
    1365          10 :         ScDPSaveData::DimOrderType::const_iterator it1 = mrDimOrder.find(r1.FieldName);
    1366          10 :         if (it1 != mrDimOrder.end())
    1367          10 :             nRank1 = it1->second;
    1368             : 
    1369          10 :         ScDPSaveData::DimOrderType::const_iterator it2 = mrDimOrder.find(r2.FieldName);
    1370          10 :         if (it2 != mrDimOrder.end())
    1371          10 :             nRank2 = it2->second;
    1372             : 
    1373          10 :         return nRank1 < nRank2;
    1374             :     }
    1375             : };
    1376             : 
    1377             : }
    1378             : 
    1379          43 : double ScDPObject::GetPivotData(const OUString& rDataFieldName, std::vector<sheet::DataPilotFieldFilter>& rFilters)
    1380             : {
    1381             :     double fRet;
    1382          43 :     rtl::math::setNan(&fRet);
    1383          43 :     if (!mbEnableGetPivotData)
    1384           0 :         return fRet;
    1385             : 
    1386          43 :     CreateObjects();
    1387             : 
    1388          43 :     std::vector<const ScDPSaveDimension*> aDataDims;
    1389          43 :     pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDataDims);
    1390          43 :     if (aDataDims.empty())
    1391           0 :         return fRet;
    1392             : 
    1393             :     std::vector<const ScDPSaveDimension*>::iterator it = std::find_if(
    1394             :         aDataDims.begin(), aDataDims.end(),
    1395          43 :         FindByName(ScGlobal::pCharClass->uppercase(rDataFieldName)));
    1396             : 
    1397          43 :     if (it == aDataDims.end())
    1398           0 :         return fRet;
    1399             : 
    1400          43 :     size_t nDataIndex = std::distance(aDataDims.begin(), it);
    1401             : 
    1402          86 :     uno::Reference<sheet::XDataPilotResults> xDPResults(xSource, uno::UNO_QUERY);
    1403          43 :     if (!xDPResults.is())
    1404           0 :         return fRet;
    1405             : 
    1406             :     // Dimensions must be sorted in order of appearance, and row dimensions
    1407             :     // must come before column dimensions.
    1408          43 :     std::sort(rFilters.begin(), rFilters.end(), LessByDimOrder(pSaveData->GetDimensionSortOrder()));
    1409             : 
    1410          43 :     size_t n = rFilters.size();
    1411          86 :     uno::Sequence<sheet::DataPilotFieldFilter> aFilters(n);
    1412          88 :     for (size_t i = 0; i < n; ++i)
    1413          45 :         aFilters[i] = rFilters[i];
    1414             : 
    1415          86 :     uno::Sequence<double> aRes = xDPResults->getFilteredResults(aFilters);
    1416          43 :     if (static_cast<sal_Int32>(nDataIndex) >= aRes.getLength())
    1417           0 :         return fRet;
    1418             : 
    1419          86 :     return aRes[nDataIndex];
    1420             : }
    1421             : 
    1422           0 : bool ScDPObject::IsFilterButton( const ScAddress& rPos )
    1423             : {
    1424           0 :     CreateOutput();             // create xSource and pOutput if not already done
    1425             : 
    1426           0 :     return pOutput->IsFilterButton( rPos );
    1427             : }
    1428             : 
    1429           1 : long ScDPObject::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
    1430             : {
    1431           1 :     CreateOutput();             // create xSource and pOutput if not already done
    1432             : 
    1433           1 :     return pOutput->GetHeaderDim( rPos, rOrient );
    1434             : }
    1435             : 
    1436           0 : bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop, long nDragDim,
    1437             :                                 Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos )
    1438             : {
    1439           0 :     CreateOutput();             // create xSource and pOutput if not already done
    1440             : 
    1441           0 :     return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
    1442             : }
    1443             : 
    1444           0 : void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet& rNames, long nDimension)
    1445             : {
    1446           0 :     CreateOutput();             // create xSource and pOutput if not already done
    1447             : 
    1448           0 :     pOutput->GetMemberResultNames(rNames, nDimension);    // used only with table data -> level not needed
    1449           0 : }
    1450             : 
    1451             : namespace {
    1452             : 
    1453           0 : bool dequote( const OUString& rSource, sal_Int32 nStartPos, sal_Int32& rEndPos, OUString& rResult )
    1454             : {
    1455             :     // nStartPos has to point to opening quote
    1456             : 
    1457           0 :     bool bRet = false;
    1458           0 :     const sal_Unicode cQuote = '\'';
    1459             : 
    1460           0 :     if (rSource[nStartPos] == cQuote)
    1461             :     {
    1462           0 :         OUStringBuffer aBuffer;
    1463           0 :         sal_Int32 nPos = nStartPos + 1;
    1464           0 :         const sal_Int32 nLen = rSource.getLength();
    1465             : 
    1466           0 :         while ( nPos < nLen )
    1467             :         {
    1468           0 :             const sal_Unicode cNext = rSource[nPos];
    1469           0 :             if ( cNext == cQuote )
    1470             :             {
    1471           0 :                 if (nPos+1 < nLen && rSource[nPos+1] == cQuote)
    1472             :                 {
    1473             :                     // double quote is used for an embedded quote
    1474           0 :                     aBuffer.append( cNext );    // append one quote
    1475           0 :                     ++nPos;                     // skip the next one
    1476             :                 }
    1477             :                 else
    1478             :                 {
    1479             :                     // end of quoted string
    1480           0 :                     rResult = aBuffer.makeStringAndClear();
    1481           0 :                     rEndPos = nPos + 1;         // behind closing quote
    1482           0 :                     return true;
    1483             :                 }
    1484             :             }
    1485             :             else
    1486           0 :                 aBuffer.append( cNext );
    1487             : 
    1488           0 :             ++nPos;
    1489           0 :         }
    1490             :         // no closing quote before the end of the string -> error (bRet still false)
    1491             :     }
    1492             : 
    1493           0 :     return bRet;
    1494             : }
    1495             : 
    1496             : struct ScGetPivotDataFunctionEntry
    1497             : {
    1498             :     const sal_Char*         pName;
    1499             :     sheet::GeneralFunction  eFunc;
    1500             : };
    1501             : 
    1502           0 : bool parseFunction( const OUString& rList, sal_Int32 nStartPos, sal_Int32& rEndPos, sheet::GeneralFunction& rFunc )
    1503             : {
    1504             :     static const ScGetPivotDataFunctionEntry aFunctions[] =
    1505             :     {
    1506             :         // our names
    1507             :         { "Sum",        sheet::GeneralFunction_SUM       },
    1508             :         { "Count",      sheet::GeneralFunction_COUNT     },
    1509             :         { "Average",    sheet::GeneralFunction_AVERAGE   },
    1510             :         { "Max",        sheet::GeneralFunction_MAX       },
    1511             :         { "Min",        sheet::GeneralFunction_MIN       },
    1512             :         { "Product",    sheet::GeneralFunction_PRODUCT   },
    1513             :         { "CountNums",  sheet::GeneralFunction_COUNTNUMS },
    1514             :         { "StDev",      sheet::GeneralFunction_STDEV     },
    1515             :         { "StDevp",     sheet::GeneralFunction_STDEVP    },
    1516             :         { "Var",        sheet::GeneralFunction_VAR       },
    1517             :         { "VarP",       sheet::GeneralFunction_VARP      },
    1518             :         // compatibility names
    1519             :         { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
    1520             :         { "StdDev",     sheet::GeneralFunction_STDEV     },
    1521             :         { "StdDevp",    sheet::GeneralFunction_STDEVP    }
    1522             :     };
    1523             : 
    1524           0 :     const sal_Int32 nListLen = rList.getLength();
    1525           0 :     while (nStartPos < nListLen && rList[nStartPos] == ' ')
    1526           0 :         ++nStartPos;
    1527             : 
    1528           0 :     bool bParsed = false;
    1529           0 :     bool bFound = false;
    1530           0 :     OUString aFuncStr;
    1531           0 :     sal_Int32 nFuncEnd = 0;
    1532           0 :     if (nStartPos < nListLen && rList[nStartPos] == '\'')
    1533           0 :         bParsed = dequote( rList, nStartPos, nFuncEnd, aFuncStr );
    1534             :     else
    1535             :     {
    1536           0 :         nFuncEnd = rList.indexOf(']', nStartPos);
    1537           0 :         if (nFuncEnd >= 0)
    1538             :         {
    1539           0 :             aFuncStr = rList.copy(nStartPos, nFuncEnd - nStartPos);
    1540           0 :             bParsed = true;
    1541             :         }
    1542             :     }
    1543             : 
    1544           0 :     if ( bParsed )
    1545             :     {
    1546           0 :         aFuncStr = comphelper::string::strip(aFuncStr, ' ');
    1547             : 
    1548           0 :         const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
    1549           0 :         for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
    1550             :         {
    1551           0 :             if (aFuncStr.equalsIgnoreAsciiCaseAscii(aFunctions[nFunc].pName))
    1552             :             {
    1553           0 :                 rFunc = aFunctions[nFunc].eFunc;
    1554           0 :                 bFound = true;
    1555             : 
    1556           0 :                 while (nFuncEnd < nListLen && rList[nFuncEnd] == ' ')
    1557           0 :                     ++nFuncEnd;
    1558           0 :                 rEndPos = nFuncEnd;
    1559             :             }
    1560             :         }
    1561             :     }
    1562             : 
    1563           0 :     return bFound;
    1564             : }
    1565             : 
    1566         176 : bool isAtStart(
    1567             :     const OUString& rList, const OUString& rSearch, sal_Int32& rMatched,
    1568             :     bool bAllowBracket, sheet::GeneralFunction* pFunc )
    1569             : {
    1570         176 :     sal_Int32 nMatchList = 0;
    1571         176 :     sal_Int32 nMatchSearch = 0;
    1572         176 :     sal_Unicode cFirst = rList[0];
    1573         176 :     if ( cFirst == '\'' || cFirst == '[' )
    1574             :     {
    1575             :         // quoted string or string in brackets must match completely
    1576             : 
    1577          88 :         OUString aDequoted;
    1578          88 :         sal_Int32 nQuoteEnd = 0;
    1579          88 :         bool bParsed = false;
    1580             : 
    1581          88 :         if ( cFirst == '\'' )
    1582           0 :             bParsed = dequote( rList, 0, nQuoteEnd, aDequoted );
    1583          88 :         else if ( cFirst == '[' )
    1584             :         {
    1585             :             // skip spaces after the opening bracket
    1586             : 
    1587          88 :             sal_Int32 nStartPos = 1;
    1588          88 :             const sal_Int32 nListLen = rList.getLength();
    1589         176 :             while (nStartPos < nListLen && rList[nStartPos] == ' ')
    1590           0 :                 ++nStartPos;
    1591             : 
    1592          88 :             if (nStartPos < nListLen && rList[nStartPos] == '\'')         // quoted within the brackets?
    1593             :             {
    1594           0 :                 if ( dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
    1595             :                 {
    1596             :                     // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
    1597             :                     // and/or a function name
    1598           0 :                     while (nQuoteEnd < nListLen && rList[nQuoteEnd] == ' ')
    1599           0 :                         ++nQuoteEnd;
    1600             : 
    1601             :                     // semicolon separates function name
    1602           0 :                     if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ';' && pFunc)
    1603             :                     {
    1604           0 :                         sal_Int32 nFuncEnd = 0;
    1605           0 :                         if ( parseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
    1606           0 :                             nQuoteEnd = nFuncEnd;
    1607             :                     }
    1608           0 :                     if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ']')
    1609             :                     {
    1610           0 :                         ++nQuoteEnd;        // include the closing bracket for the matched length
    1611           0 :                         bParsed = true;
    1612             :                     }
    1613             :                 }
    1614             :             }
    1615             :             else
    1616             :             {
    1617             :                 // implicit quoting to the closing bracket
    1618             : 
    1619          88 :                 sal_Int32 nClosePos = rList.indexOf(']', nStartPos);
    1620          88 :                 if (nClosePos >= 0)
    1621             :                 {
    1622          88 :                     sal_Int32 nNameEnd = nClosePos;
    1623          88 :                     sal_Int32 nSemiPos = rList.indexOf(';', nStartPos);
    1624          88 :                     if (nSemiPos >= 0 && nSemiPos < nClosePos && pFunc)
    1625             :                     {
    1626           0 :                         sal_Int32 nFuncEnd = 0;
    1627           0 :                         if (parseFunction(rList, nSemiPos+1, nFuncEnd, *pFunc))
    1628           0 :                             nNameEnd = nSemiPos;
    1629             :                     }
    1630             : 
    1631          88 :                     aDequoted = rList.copy(nStartPos, nNameEnd - nStartPos);
    1632             :                     // spaces before the closing bracket or semicolon
    1633          88 :                     aDequoted = comphelper::string::stripEnd(aDequoted, ' ');
    1634          88 :                     nQuoteEnd = nClosePos + 1;
    1635          88 :                     bParsed = true;
    1636             :                 }
    1637             :             }
    1638             :         }
    1639             : 
    1640          88 :         if ( bParsed && ScGlobal::GetpTransliteration()->isEqual( aDequoted, rSearch ) )
    1641             :         {
    1642          23 :             nMatchList = nQuoteEnd;             // match count in the list string, including quotes
    1643          23 :             nMatchSearch = rSearch.getLength();
    1644          88 :         }
    1645             :     }
    1646             :     else
    1647             :     {
    1648             :         // otherwise look for search string at the start of rList
    1649             :         ScGlobal::GetpTransliteration()->equals(
    1650          88 :             rList, 0, rList.getLength(), nMatchList, rSearch, 0, rSearch.getLength(), nMatchSearch);
    1651             :     }
    1652             : 
    1653         176 :     if (nMatchSearch == rSearch.getLength())
    1654             :     {
    1655             :         // search string is at start of rList - look for following space or end of string
    1656             : 
    1657          46 :         bool bValid = false;
    1658          46 :         if ( sal::static_int_cast<sal_Int32>(nMatchList) >= rList.getLength() )
    1659          19 :             bValid = true;
    1660             :         else
    1661             :         {
    1662          27 :             sal_Unicode cNext = rList[nMatchList];
    1663          27 :             if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
    1664          27 :                 bValid = true;
    1665             :         }
    1666             : 
    1667          46 :         if ( bValid )
    1668             :         {
    1669          46 :             rMatched = nMatchList;
    1670          46 :             return true;
    1671             :         }
    1672             :     }
    1673             : 
    1674         130 :     return false;
    1675             : }
    1676             : 
    1677             : } // anonymous namespace
    1678             : 
    1679          19 : bool ScDPObject::ParseFilters(
    1680             :     OUString& rDataFieldName,
    1681             :     std::vector<sheet::DataPilotFieldFilter>& rFilters,
    1682             :     std::vector<sheet::GeneralFunction>& rFilterFuncs, const OUString& rFilterList )
    1683             : {
    1684             :     // parse the string rFilterList into parameters for GetPivotData
    1685             : 
    1686          19 :     CreateObjects();            // create xSource if not already done
    1687             : 
    1688          19 :     std::vector<OUString> aDataNames;     // data fields (source name)
    1689          38 :     std::vector<OUString> aGivenNames;    // data fields (compound name)
    1690          38 :     std::vector<OUString> aFieldNames;    // column/row/data fields
    1691          38 :     std::vector< uno::Sequence<OUString> > aFieldValues;
    1692             : 
    1693             :     // get all the field and item names
    1694             : 
    1695          38 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1696          38 :     uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
    1697          19 :     sal_Int32 nDimCount = xIntDims->getCount();
    1698          95 :     for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
    1699             :     {
    1700          76 :         uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
    1701         152 :         uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
    1702         152 :         uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
    1703         152 :         uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
    1704             :         bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
    1705          76 :                             OUString(SC_UNO_DP_ISDATALAYOUT) );
    1706             :         sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
    1707             :                             xDimProp, OUString(SC_UNO_DP_ORIENTATION),
    1708          76 :                             sheet::DataPilotFieldOrientation_HIDDEN );
    1709          76 :         if ( !bDataLayout )
    1710             :         {
    1711          57 :             if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
    1712             :             {
    1713          19 :                 OUString aSourceName;
    1714          38 :                 OUString aGivenName;
    1715          19 :                 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
    1716          19 :                 aDataNames.push_back( aSourceName );
    1717          38 :                 aGivenNames.push_back( aGivenName );
    1718             :             }
    1719          38 :             else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
    1720             :             {
    1721             :                 // get level names, as in ScDPOutput
    1722             : 
    1723          38 :                 uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
    1724             :                 sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
    1725          38 :                                                     OUString(SC_UNO_DP_USEDHIERARCHY) );
    1726          38 :                 if ( nHierarchy >= xHiers->getCount() )
    1727           0 :                     nHierarchy = 0;
    1728             : 
    1729             :                 uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
    1730          76 :                                                     xHiers->getByIndex(nHierarchy) );
    1731          76 :                 uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
    1732          38 :                 if ( xHierSupp.is() )
    1733             :                 {
    1734          38 :                     uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
    1735          38 :                     sal_Int32 nLevCount = xLevels->getCount();
    1736          76 :                     for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
    1737             :                     {
    1738             :                         uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
    1739          38 :                                                             xLevels->getByIndex(nLev) );
    1740          76 :                         uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
    1741          76 :                         uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
    1742          38 :                         if ( xLevNam.is() && xLevSupp.is() )
    1743             :                         {
    1744          38 :                             uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
    1745             : 
    1746          76 :                             OUString aFieldName( xLevNam->getName() );
    1747          76 :                             uno::Sequence<OUString> aMemberNames( xMembers->getElementNames() );
    1748             : 
    1749          38 :                             aFieldNames.push_back( aFieldName );
    1750          76 :                             aFieldValues.push_back( aMemberNames );
    1751             :                         }
    1752          76 :                     }
    1753          38 :                 }
    1754             :             }
    1755             :         }
    1756          76 :     }
    1757             : 
    1758             :     // compare and build filters
    1759             : 
    1760          19 :     SCSIZE nDataFields = aDataNames.size();
    1761          19 :     SCSIZE nFieldCount = aFieldNames.size();
    1762             :     OSL_ENSURE( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
    1763             : 
    1764          19 :     bool bError = false;
    1765          19 :     bool bHasData = false;
    1766          38 :     OUString aRemaining(comphelper::string::strip(rFilterList, ' '));
    1767          61 :     while (!aRemaining.isEmpty() && !bError)
    1768             :     {
    1769          23 :         bool bUsed = false;
    1770             : 
    1771             :         // look for data field name
    1772             : 
    1773          46 :         for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
    1774             :         {
    1775          23 :             OUString aFound;
    1776          23 :             sal_Int32 nMatched = 0;
    1777          23 :             if (isAtStart(aRemaining, aDataNames[nDataPos], nMatched, false, NULL))
    1778           0 :                 aFound = aDataNames[nDataPos];
    1779          23 :             else if (isAtStart(aRemaining, aGivenNames[nDataPos], nMatched, false, NULL))
    1780           0 :                 aFound = aGivenNames[nDataPos];
    1781             : 
    1782          23 :             if (!aFound.isEmpty())
    1783             :             {
    1784           0 :                 rDataFieldName = aFound;
    1785           0 :                 aRemaining = aRemaining.copy(nMatched);
    1786           0 :                 bHasData = true;
    1787           0 :                 bUsed = true;
    1788             :             }
    1789          23 :         }
    1790             : 
    1791             :         // look for field name
    1792             : 
    1793          23 :         OUString aSpecField;
    1794          23 :         bool bHasFieldName = false;
    1795          23 :         if ( !bUsed )
    1796             :         {
    1797          23 :             sal_Int32 nMatched = 0;
    1798          65 :             for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
    1799             :             {
    1800          42 :                 if (isAtStart(aRemaining, aFieldNames[nField], nMatched, true, NULL))
    1801             :                 {
    1802          23 :                     aSpecField = aFieldNames[nField];
    1803          23 :                     aRemaining = aRemaining.copy(nMatched);
    1804          23 :                     aRemaining = comphelper::string::stripStart(aRemaining, ' ');
    1805             : 
    1806             :                     // field name has to be followed by item name in brackets
    1807          23 :                     if (aRemaining.startsWith("["))
    1808             :                     {
    1809          23 :                         bHasFieldName = true;
    1810             :                         // bUsed remains false - still need the item
    1811             :                     }
    1812             :                     else
    1813             :                     {
    1814           0 :                         bUsed = true;
    1815           0 :                         bError = true;
    1816             :                     }
    1817             :                 }
    1818             :             }
    1819             :         }
    1820             : 
    1821             :         // look for field item
    1822             : 
    1823          23 :         if ( !bUsed )
    1824             :         {
    1825          23 :             bool bItemFound = false;
    1826          23 :             sal_Int32 nMatched = 0;
    1827          23 :             OUString aFoundName;
    1828          46 :             OUString aFoundValue;
    1829          23 :             sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
    1830          23 :             sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
    1831             : 
    1832          69 :             for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
    1833             :             {
    1834             :                 // If a field name is given, look in that field only, otherwise in all fields.
    1835             :                 // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
    1836          46 :                 if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
    1837             :                 {
    1838          23 :                     const uno::Sequence<OUString>& rItems = aFieldValues[nField];
    1839          23 :                     sal_Int32 nItemCount = rItems.getLength();
    1840          23 :                     const OUString* pItemArr = rItems.getConstArray();
    1841         111 :                     for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
    1842             :                     {
    1843          88 :                         if ( isAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
    1844             :                         {
    1845          23 :                             if ( bItemFound )
    1846           0 :                                 bError = true;      // duplicate (also across fields)
    1847             :                             else
    1848             :                             {
    1849          23 :                                 aFoundName = aFieldNames[nField];
    1850          23 :                                 aFoundValue = pItemArr[nItem];
    1851          23 :                                 eFoundFunc = eFunc;
    1852          23 :                                 bItemFound = true;
    1853          23 :                                 bUsed = true;
    1854             :                             }
    1855             :                         }
    1856             :                     }
    1857             :                 }
    1858             :             }
    1859             : 
    1860          23 :             if ( bItemFound && !bError )
    1861             :             {
    1862          23 :                 sheet::DataPilotFieldFilter aField;
    1863          23 :                 aField.FieldName = aFoundName;
    1864          23 :                 aField.MatchValue = aFoundValue;
    1865          23 :                 rFilters.push_back(aField);
    1866          23 :                 rFilterFuncs.push_back(eFoundFunc);
    1867          23 :                 aRemaining = aRemaining.copy(nMatched);
    1868          23 :             }
    1869             :         }
    1870             : 
    1871          23 :         if ( !bUsed )
    1872           0 :             bError = true;
    1873             : 
    1874             :         // remove any number of spaces between entries
    1875          23 :         aRemaining = comphelper::string::stripStart(aRemaining, ' ');
    1876          23 :     }
    1877             : 
    1878          19 :     if ( !bError && !bHasData && aDataNames.size() == 1 )
    1879             :     {
    1880             :         // if there's only one data field, its name need not be specified
    1881          19 :         rDataFieldName = aDataNames[0];
    1882          19 :         bHasData = true;
    1883             :     }
    1884             : 
    1885          38 :     return bHasData && !bError;
    1886             : }
    1887             : 
    1888           0 : void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
    1889             : {
    1890           0 :     CreateObjects();            // create xSource if not already done
    1891             : 
    1892             :     //  find dimension name
    1893             : 
    1894           0 :     uno::Reference<container::XNamed> xDim;
    1895           0 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    1896           0 :     uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
    1897           0 :     long nIntCount = xIntDims->getCount();
    1898           0 :     if ( rElemDesc.Dimension < nIntCount )
    1899             :     {
    1900             :         uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
    1901           0 :                                     xIntDims->getByIndex(rElemDesc.Dimension) );
    1902           0 :         xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
    1903             :     }
    1904             :     OSL_ENSURE( xDim.is(), "dimension not found" );
    1905           0 :     if ( !xDim.is() ) return;
    1906           0 :     OUString aDimName = xDim->getName();
    1907             : 
    1908           0 :     uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
    1909             :     bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
    1910           0 :                         OUString(SC_UNO_DP_ISDATALAYOUT) );
    1911           0 :     if (bDataLayout)
    1912             :     {
    1913             :         //  the elements of the data layout dimension can't be found by their names
    1914             :         //  -> don't change anything
    1915           0 :         return;
    1916             :     }
    1917             : 
    1918             :     //  query old state
    1919             : 
    1920           0 :     long nHierCount = 0;
    1921           0 :     uno::Reference<container::XIndexAccess> xHiers;
    1922           0 :     uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
    1923           0 :     if ( xHierSupp.is() )
    1924             :     {
    1925           0 :         uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
    1926           0 :         xHiers = new ScNameToIndexAccess( xHiersName );
    1927           0 :         nHierCount = xHiers->getCount();
    1928             :     }
    1929           0 :     uno::Reference<uno::XInterface> xHier;
    1930           0 :     if ( rElemDesc.Hierarchy < nHierCount )
    1931           0 :         xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
    1932             :     OSL_ENSURE( xHier.is(), "hierarchy not found" );
    1933           0 :     if ( !xHier.is() ) return;
    1934             : 
    1935           0 :     long nLevCount = 0;
    1936           0 :     uno::Reference<container::XIndexAccess> xLevels;
    1937           0 :     uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
    1938           0 :     if ( xLevSupp.is() )
    1939             :     {
    1940           0 :         uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
    1941           0 :         xLevels = new ScNameToIndexAccess( xLevsName );
    1942           0 :         nLevCount = xLevels->getCount();
    1943             :     }
    1944           0 :     uno::Reference<uno::XInterface> xLevel;
    1945           0 :     if ( rElemDesc.Level < nLevCount )
    1946           0 :         xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
    1947             :     OSL_ENSURE( xLevel.is(), "level not found" );
    1948           0 :     if ( !xLevel.is() ) return;
    1949             : 
    1950           0 :     uno::Reference<container::XNameAccess> xMembers;
    1951           0 :     uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
    1952           0 :     if ( xMbrSupp.is() )
    1953           0 :         xMembers = xMbrSupp->getMembers();
    1954             : 
    1955           0 :     bool bFound = false;
    1956           0 :     bool bShowDetails = true;
    1957             : 
    1958           0 :     if ( xMembers.is() )
    1959             :     {
    1960           0 :         if ( xMembers->hasByName(rElemDesc.MemberName) )
    1961             :         {
    1962             :             uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
    1963           0 :                                             xMembers->getByName(rElemDesc.MemberName) );
    1964           0 :             uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
    1965           0 :             if ( xMbrProp.is() )
    1966             :             {
    1967             :                 bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
    1968           0 :                                     OUString(SC_UNO_DP_SHOWDETAILS) );
    1969             :                 //TODO: don't set bFound if property is unknown?
    1970           0 :                 bFound = true;
    1971           0 :             }
    1972             :         }
    1973             :     }
    1974             : 
    1975             :     OSL_ENSURE( bFound, "member not found" );
    1976             :     (void)bFound;
    1977             : 
    1978             :     //TODO: use Hierarchy and Level in SaveData !!!!
    1979             : 
    1980             :     //  modify pDestObj if set, this object otherwise
    1981           0 :     ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
    1982             :     OSL_ENSURE( pModifyData, "no data?" );
    1983           0 :     if ( pModifyData )
    1984             :     {
    1985           0 :         const OUString aName = rElemDesc.MemberName;
    1986             :         pModifyData->GetDimensionByName(aDimName)->
    1987           0 :             GetMemberByName(aName)->SetShowDetails( !bShowDetails );    // toggle
    1988             : 
    1989           0 :         if ( pDestObj )
    1990           0 :             pDestObj->InvalidateData();     // re-init source from SaveData
    1991             :         else
    1992           0 :             InvalidateData();               // re-init source from SaveData
    1993           0 :     }
    1994             : }
    1995             : 
    1996           0 : static sal_uInt16 lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp )     // PIVOT_FUNC mask
    1997             : {
    1998           0 :     uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
    1999           0 :     if ( xDimProp.is() && xDimSupp.is() )
    2000             :     {
    2001           0 :         uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
    2002             :         long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
    2003           0 :                                 OUString(SC_UNO_DP_USEDHIERARCHY) );
    2004           0 :         if ( nHierarchy >= xHiers->getCount() )
    2005           0 :             nHierarchy = 0;
    2006             : 
    2007             :         uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
    2008           0 :                                     xHiers->getByIndex(nHierarchy) );
    2009           0 :         uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
    2010           0 :         if ( xHierSupp.is() )
    2011             :         {
    2012           0 :             uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
    2013             :             uno::Reference<uno::XInterface> xLevel =
    2014           0 :                 ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
    2015           0 :             uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
    2016           0 :             if ( xLevProp.is() )
    2017             :             {
    2018           0 :                 uno::Any aSubAny;
    2019             :                 try
    2020             :                 {
    2021           0 :                     aSubAny = xLevProp->getPropertyValue(
    2022           0 :                             OUString(SC_UNO_DP_SUBTOTAL) );
    2023             :                 }
    2024           0 :                 catch(uno::Exception&)
    2025             :                 {
    2026             :                 }
    2027           0 :                 uno::Sequence<sheet::GeneralFunction> aSeq;
    2028           0 :                 if ( aSubAny >>= aSeq )
    2029             :                 {
    2030           0 :                     sal_uInt16 nMask = 0;
    2031           0 :                     const sheet::GeneralFunction* pArray = aSeq.getConstArray();
    2032           0 :                     long nCount = aSeq.getLength();
    2033           0 :                     for (long i=0; i<nCount; i++)
    2034           0 :                         nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
    2035           0 :                     return nMask;
    2036           0 :                 }
    2037           0 :             }
    2038           0 :         }
    2039             :     }
    2040             : 
    2041             :     OSL_FAIL("FirstSubTotal: NULL");
    2042           0 :     return 0;
    2043             : }
    2044             : 
    2045             : namespace {
    2046             : 
    2047             : class FindByColumn : public std::unary_function<ScPivotField, bool>
    2048             : {
    2049             :     SCsCOL mnCol;
    2050             :     sal_uInt16 mnMask;
    2051             : public:
    2052           0 :     FindByColumn(SCsCOL nCol, sal_uInt16 nMask) : mnCol(nCol), mnMask(nMask) {}
    2053           0 :     bool operator() (const ScPivotField& r) const
    2054             :     {
    2055           0 :         return r.nCol == mnCol && r.nFuncMask == mnMask;
    2056             :     }
    2057             : };
    2058             : 
    2059             : }
    2060             : 
    2061           0 : void lcl_FillOldFields( ScPivotFieldVector& rFields,
    2062             :     const uno::Reference<sheet::XDimensionsSupplier>& xSource,
    2063             :     sal_uInt16 nOrient, bool bAddData )
    2064             : {
    2065           0 :     ScPivotFieldVector aFields;
    2066             : 
    2067           0 :     bool bDataFound = false;
    2068             : 
    2069             :     //TODO: merge multiple occurrences (data field with different functions)
    2070             :     //TODO: force data field in one dimension
    2071             : 
    2072           0 :     vector<long> aPos;
    2073             : 
    2074           0 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    2075           0 :     uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
    2076           0 :     long nDimCount = xDims->getCount();
    2077           0 :     for (long nDim = 0; nDim < nDimCount; ++nDim)
    2078             :     {
    2079             :         // Get dimension object.
    2080             :         uno::Reference<uno::XInterface> xIntDim =
    2081           0 :             ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
    2082             : 
    2083             :         // dimension properties
    2084           0 :         uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
    2085             : 
    2086             :         // dimension orientation, hidden by default.
    2087             :         long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
    2088             :                             xDimProp, OUString(SC_UNO_DP_ORIENTATION),
    2089           0 :                             sheet::DataPilotFieldOrientation_HIDDEN );
    2090             : 
    2091           0 :         if ( xDimProp.is() && nDimOrient == nOrient )
    2092             :         {
    2093             :             // Let's take this dimension.
    2094             : 
    2095             :             // function mask.
    2096           0 :             sal_uInt16 nMask = 0;
    2097           0 :             if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
    2098             :             {
    2099             :                 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
    2100             :                                             xDimProp, OUString(SC_UNO_DP_FUNCTION),
    2101           0 :                                             sheet::GeneralFunction_NONE );
    2102           0 :                 if ( eFunc == sheet::GeneralFunction_AUTO )
    2103             :                 {
    2104             :                     //TODO: test for numeric data
    2105           0 :                     eFunc = sheet::GeneralFunction_SUM;
    2106             :                 }
    2107           0 :                 nMask = ScDataPilotConversion::FunctionBit(eFunc);
    2108             :             }
    2109             :             else
    2110           0 :                 nMask = lcl_FirstSubTotal( xDimProp );      // from first hierarchy
    2111             : 
    2112             :             // is this data layout dimension?
    2113             :             bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty(
    2114           0 :                 xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
    2115             : 
    2116             :             // is this dimension cloned?
    2117           0 :             long nDupSource = -1;
    2118             :             try
    2119             :             {
    2120           0 :                 uno::Any aOrigAny = xDimProp->getPropertyValue(
    2121           0 :                     OUString(SC_UNO_DP_ORIGINAL_POS));
    2122           0 :                 sal_Int32 nTmp = 0;
    2123           0 :                 if (aOrigAny >>= nTmp)
    2124           0 :                     nDupSource = static_cast<sal_Int32>(nTmp);
    2125             :             }
    2126           0 :             catch(uno::Exception&)
    2127             :             {
    2128             :             }
    2129             : 
    2130           0 :             sal_uInt8 nDupCount = 0;
    2131           0 :             if (nDupSource >= 0)
    2132             :             {
    2133             :                 // this dimension is cloned.
    2134             : 
    2135             :                 SCsCOL nCompCol; // ID of the original dimension.
    2136           0 :                 if ( bDataLayout )
    2137           0 :                     nCompCol = PIVOT_DATA_FIELD;
    2138             :                 else
    2139           0 :                     nCompCol = static_cast<SCsCOL>(nDupSource);     //TODO: seek source column from name
    2140             : 
    2141           0 :                 ScPivotFieldVector::iterator it = std::find_if(aFields.begin(), aFields.end(), FindByColumn(nCompCol, nMask));
    2142           0 :                 if (it != aFields.end())
    2143           0 :                     nDupCount = it->mnDupCount + 1;
    2144             :             }
    2145             : 
    2146           0 :             aFields.push_back(ScPivotField());
    2147           0 :             ScPivotField& rField = aFields.back();
    2148           0 :             if (bDataLayout)
    2149             :             {
    2150           0 :                 rField.nCol = PIVOT_DATA_FIELD;
    2151           0 :                 bDataFound = true;
    2152             :             }
    2153             :             else
    2154             :             {
    2155           0 :                 rField.mnOriginalDim = nDupSource;
    2156           0 :                 rField.nCol = static_cast<SCCOL>(nDim);    //TODO: seek source column from name
    2157             :             }
    2158             : 
    2159           0 :             rField.nFuncMask = nMask;
    2160           0 :             rField.mnDupCount = nDupCount;
    2161             :             long nPos = ScUnoHelpFunctions::GetLongProperty(
    2162           0 :                 xDimProp, OUString(SC_UNO_DP_POSITION));
    2163           0 :             aPos.push_back(nPos);
    2164             : 
    2165             :             try
    2166             :             {
    2167           0 :                 if (nOrient == sheet::DataPilotFieldOrientation_DATA)
    2168           0 :                     xDimProp->getPropertyValue(OUString(SC_UNO_DP_REFVALUE))
    2169           0 :                         >>= rField.maFieldRef;
    2170             :             }
    2171           0 :             catch (uno::Exception&)
    2172             :             {
    2173             :             }
    2174             :         }
    2175           0 :     }
    2176             : 
    2177             :     //  sort by getPosition() value
    2178             : 
    2179           0 :     size_t nOutCount = aFields.size();
    2180           0 :     if (nOutCount >= 1)
    2181             :     {
    2182           0 :         for (size_t i = 0; i < nOutCount - 1; ++i)
    2183             :         {
    2184           0 :             for (size_t j = 0; j + i < nOutCount - 1; ++j)
    2185             :             {
    2186           0 :                 if ( aPos[j+1] < aPos[j] )
    2187             :                 {
    2188           0 :                     std::swap( aPos[j], aPos[j+1] );
    2189           0 :                     std::swap( aFields[j], aFields[j+1] );
    2190             :                 }
    2191             :             }
    2192             :         }
    2193             :     }
    2194             : 
    2195           0 :     if (bAddData && !bDataFound)
    2196           0 :         aFields.push_back(ScPivotField(PIVOT_DATA_FIELD, 0));
    2197             : 
    2198           0 :     rFields.swap(aFields);
    2199           0 : }
    2200             : 
    2201           0 : bool ScDPObject::FillOldParam(ScPivotParam& rParam) const
    2202             : {
    2203           0 :     const_cast<ScDPObject*>(this)->CreateObjects();       // xSource is needed for field numbers
    2204             : 
    2205           0 :     if (!xSource.is())
    2206           0 :         return false;
    2207             : 
    2208           0 :     rParam.nCol = aOutRange.aStart.Col();
    2209           0 :     rParam.nRow = aOutRange.aStart.Row();
    2210           0 :     rParam.nTab = aOutRange.aStart.Tab();
    2211             :     // ppLabelArr / nLabels is not changed
    2212             : 
    2213           0 :     bool bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
    2214             :     lcl_FillOldFields(
    2215           0 :         rParam.maPageFields, xSource, sheet::DataPilotFieldOrientation_PAGE, false);
    2216             :     lcl_FillOldFields(
    2217           0 :         rParam.maColFields, xSource, sheet::DataPilotFieldOrientation_COLUMN, bAddData);
    2218             :     lcl_FillOldFields(
    2219           0 :         rParam.maRowFields, xSource, sheet::DataPilotFieldOrientation_ROW, false);
    2220             :     lcl_FillOldFields(
    2221           0 :         rParam.maDataFields, xSource, sheet::DataPilotFieldOrientation_DATA, false);
    2222             : 
    2223           0 :     uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
    2224           0 :     if (xProp.is())
    2225             :     {
    2226             :         try
    2227             :         {
    2228             :             rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
    2229           0 :                         OUString(SC_UNO_DP_COLGRAND), true );
    2230             :             rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
    2231           0 :                         OUString(SC_UNO_DP_ROWGRAND), true );
    2232             : 
    2233             :             // following properties may be missing for external sources
    2234             :             rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
    2235           0 :                         OUString(SC_UNO_DP_IGNOREEMPTY) );
    2236             :             rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
    2237           0 :                         OUString(SC_UNO_DP_REPEATEMPTY) );
    2238             :         }
    2239           0 :         catch(uno::Exception&)
    2240             :         {
    2241             :             // no error
    2242             :         }
    2243             :     }
    2244           0 :     return true;
    2245             : }
    2246             : 
    2247           3 : static void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
    2248             : {
    2249           3 :     uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
    2250           3 :     if (!xDimProp.is() || !xDimSupp.is())
    2251           0 :         return;
    2252             : 
    2253           6 :     uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
    2254             :     long nHierarchy = ScUnoHelpFunctions::GetLongProperty(
    2255           3 :         xDimProp, OUString(SC_UNO_DP_USEDHIERARCHY));
    2256           3 :     if ( nHierarchy >= xHiers->getCount() )
    2257           0 :         nHierarchy = 0;
    2258           3 :     rData.mnUsedHier = nHierarchy;
    2259             : 
    2260             :     uno::Reference<uno::XInterface> xHier =
    2261           6 :         ScUnoHelpFunctions::AnyToInterface(xHiers->getByIndex(nHierarchy));
    2262             : 
    2263           6 :     uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
    2264           3 :     if (!xHierSupp.is())
    2265           0 :         return;
    2266             : 
    2267             :     uno::Reference<container::XIndexAccess> xLevels =
    2268           6 :         new ScNameToIndexAccess( xHierSupp->getLevels() );
    2269             : 
    2270             :     uno::Reference<uno::XInterface> xLevel =
    2271           6 :         ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(0) );
    2272           6 :     uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
    2273           3 :     if (!xLevProp.is())
    2274           0 :         return;
    2275             : 
    2276             :     rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty(
    2277           3 :         xLevProp, OUString(SC_UNO_DP_SHOWEMPTY));
    2278             : 
    2279             :     rData.mbRepeatItemLabels = ScUnoHelpFunctions::GetBoolProperty(
    2280           3 :         xLevProp, OUString(SC_UNO_DP_REPEATITEMLABELS));
    2281             : 
    2282             :     try
    2283             :     {
    2284           3 :         xLevProp->getPropertyValue( OUString( SC_UNO_DP_SORTING ) )
    2285           6 :             >>= rData.maSortInfo;
    2286           3 :         xLevProp->getPropertyValue( OUString( SC_UNO_DP_LAYOUT ) )
    2287           6 :             >>= rData.maLayoutInfo;
    2288           3 :         xLevProp->getPropertyValue( OUString( SC_UNO_DP_AUTOSHOW ) )
    2289           6 :             >>= rData.maShowInfo;
    2290             :     }
    2291           0 :     catch(uno::Exception&)
    2292             :     {
    2293           3 :     }
    2294             : }
    2295             : 
    2296           4 : bool ScDPObject::FillLabelDataForDimension(
    2297             :     const uno::Reference<container::XIndexAccess>& xDims, sal_Int32 nDim, ScDPLabelData& rLabelData)
    2298             : {
    2299             :     uno::Reference<uno::XInterface> xIntDim =
    2300           4 :         ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
    2301           8 :     uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
    2302           8 :     uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
    2303             : 
    2304           4 :     if (!xDimName.is() || !xDimProp.is())
    2305           0 :         return false;
    2306             : 
    2307             :     bool bData = ScUnoHelpFunctions::GetBoolProperty(
    2308           4 :         xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
    2309             :     //TODO: error checking -- is "IsDataLayoutDimension" property required??
    2310             : 
    2311           4 :     sal_Int32 nOrigPos = -1;
    2312           8 :     OUString aFieldName;
    2313             :     try
    2314             :     {
    2315           4 :         aFieldName = xDimName->getName();
    2316           4 :         uno::Any aOrigAny = xDimProp->getPropertyValue(
    2317           4 :                     OUString(SC_UNO_DP_ORIGINAL_POS));
    2318           4 :         aOrigAny >>= nOrigPos;
    2319             :     }
    2320           0 :     catch(uno::Exception&)
    2321             :     {
    2322             :     }
    2323             : 
    2324             :     OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty(
    2325           8 :         xDimProp, OUString(SC_UNO_DP_LAYOUTNAME), OUString());
    2326             : 
    2327             :     OUString aSubtotalName = ScUnoHelpFunctions::GetStringProperty(
    2328           8 :         xDimProp, OUString(SC_UNO_DP_FIELD_SUBTOTALNAME), OUString());
    2329             : 
    2330           4 :     bool bIsValue = true;                               //TODO: check
    2331             : 
    2332             :     // Name from the UNO dimension object may have trailing '*'s in which
    2333             :     // case it's a duplicate dimension. Convert that to a duplicate index.
    2334             : 
    2335           4 :     sal_uInt8 nDupCount = ScDPUtil::getDuplicateIndex(aFieldName);
    2336           4 :     aFieldName = ScDPUtil::getSourceDimensionName(aFieldName);
    2337             : 
    2338           4 :     rLabelData.maName = aFieldName;
    2339           4 :     rLabelData.mnCol = static_cast<SCCOL>(nDim);
    2340           4 :     rLabelData.mnDupCount = nDupCount;
    2341           4 :     rLabelData.mbDataLayout = bData;
    2342           4 :     rLabelData.mbIsValue = bIsValue;
    2343             : 
    2344           4 :     if (!bData)
    2345             :     {
    2346           3 :         rLabelData.mnOriginalDim = static_cast<long>(nOrigPos);
    2347           3 :         rLabelData.maLayoutName = aLayoutName;
    2348           3 :         rLabelData.maSubtotalName = aSubtotalName;
    2349           3 :         if (nOrigPos >= 0)
    2350             :             // This is a duplicated dimension. Use the original dimension index.
    2351           1 :             nDim = nOrigPos;
    2352           3 :         GetHierarchies(nDim, rLabelData.maHiers);
    2353           3 :         GetMembers(nDim, GetUsedHierarchy(nDim), rLabelData.maMembers);
    2354           3 :         lcl_FillLabelData(rLabelData, xDimProp);
    2355             :         rLabelData.mnFlags = ScUnoHelpFunctions::GetLongProperty(
    2356           3 :             xDimProp, OUString(SC_UNO_DP_FLAGS), 0);
    2357             :     }
    2358           8 :     return true;
    2359             : }
    2360             : 
    2361           0 : bool ScDPObject::FillLabelData(sal_Int32 nDim, ScDPLabelData& rLabels)
    2362             : {
    2363           0 :     CreateObjects();
    2364           0 :     if (!xSource.is())
    2365           0 :         return false;
    2366             : 
    2367           0 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    2368           0 :     uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
    2369           0 :     sal_Int32 nDimCount = xDims->getCount();
    2370           0 :     if (nDimCount <= 0 || nDim >= nDimCount)
    2371           0 :         return false;
    2372             : 
    2373           0 :     return FillLabelDataForDimension(xDims, nDim, rLabels);
    2374             : }
    2375             : 
    2376           1 : bool ScDPObject::FillLabelData(ScPivotParam& rParam)
    2377             : {
    2378           1 :     rParam.maLabelArray.clear();
    2379             : 
    2380           1 :     CreateObjects();
    2381           1 :     if (!xSource.is())
    2382           0 :         return false;
    2383             : 
    2384           1 :     uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    2385           2 :     uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
    2386           1 :     sal_Int32 nDimCount = xDims->getCount();
    2387           1 :     if (nDimCount <= 0)
    2388           0 :         return false;
    2389             : 
    2390           5 :     for (sal_Int32 nDim = 0; nDim < nDimCount; ++nDim)
    2391             :     {
    2392           4 :         std::unique_ptr<ScDPLabelData> pNewLabel(new ScDPLabelData);
    2393           4 :         FillLabelDataForDimension(xDims, nDim, *pNewLabel);
    2394           4 :         o3tl::ptr_container::push_back(rParam.maLabelArray, std::move(pNewLabel));
    2395           4 :     }
    2396             : 
    2397           2 :     return true;
    2398             : }
    2399             : 
    2400           3 : bool ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
    2401             : {
    2402           3 :     bool bRet = false;
    2403           3 :     uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
    2404           6 :     uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
    2405           3 :     if( xIntDims.is() )
    2406             :     {
    2407           3 :         uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
    2408           3 :         if (xHierSup.is())
    2409             :         {
    2410           3 :             xHiers.set( xHierSup->getHierarchies() );
    2411           3 :             bRet = xHiers.is();
    2412           3 :         }
    2413             :     }
    2414           6 :     return bRet;
    2415             : }
    2416             : 
    2417           3 : bool ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< OUString >& rHiers )
    2418             : {
    2419           3 :     bool bRet = false;
    2420           3 :     uno::Reference< container::XNameAccess > xHiersNA;
    2421           3 :     if( GetHierarchiesNA( nDim, xHiersNA ) )
    2422             :     {
    2423           3 :         rHiers = xHiersNA->getElementNames();
    2424           3 :         bRet = true;
    2425             :     }
    2426           3 :     return bRet;
    2427             : }
    2428             : 
    2429          63 : sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
    2430             : {
    2431          63 :     sal_Int32 nHier = 0;
    2432          63 :     uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
    2433         126 :     uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
    2434         126 :     uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
    2435          63 :     if (xDim.is())
    2436          63 :         nHier = ScUnoHelpFunctions::GetLongProperty( xDim, OUString( SC_UNO_DP_USEDHIERARCHY ) );
    2437         126 :     return nHier;
    2438             : }
    2439             : 
    2440          58 : bool ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
    2441             : {
    2442          58 :     return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
    2443             : }
    2444             : 
    2445          63 : bool ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
    2446             : {
    2447          63 :     bool bRet = false;
    2448          63 :     uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
    2449         126 :     uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
    2450         126 :     uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
    2451          63 :     if (xDim.is())
    2452             :     {
    2453          63 :         uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
    2454          63 :         if (xHierSup.is())
    2455             :         {
    2456          63 :             uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
    2457         126 :             uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
    2458          63 :             if ( xLevSupp.is() )
    2459             :             {
    2460          63 :                 uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
    2461          63 :                 if (xLevels.is())
    2462             :                 {
    2463          63 :                     sal_Int32 nLevCount = xLevels->getCount();
    2464          63 :                     if (nLevCount > 0)
    2465             :                     {
    2466          63 :                         uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
    2467          63 :                         if ( xMembSupp.is() )
    2468             :                         {
    2469          63 :                             xMembers.set(xMembSupp->getMembers());
    2470          63 :                             bRet = true;
    2471          63 :                         }
    2472             :                     }
    2473          63 :                 }
    2474          63 :             }
    2475          63 :         }
    2476             :     }
    2477         126 :     return bRet;
    2478             : }
    2479             : 
    2480             : //  convert old pivot tables into new datapilot tables
    2481             : 
    2482             : namespace {
    2483             : 
    2484           0 : OUString lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
    2485             : {
    2486           0 :     OUString aName;
    2487           0 :     if ( xSource.is() )
    2488             :     {
    2489           0 :         uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
    2490           0 :         uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
    2491           0 :         long nDimCount = xDims->getCount();
    2492           0 :         if ( nDim < nDimCount )
    2493             :         {
    2494             :             uno::Reference<uno::XInterface> xIntDim =
    2495           0 :                 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
    2496           0 :             uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
    2497           0 :             if (xDimName.is())
    2498             :             {
    2499             :                 try
    2500             :                 {
    2501           0 :                     aName = xDimName->getName();
    2502             :                 }
    2503           0 :                 catch(uno::Exception&)
    2504             :                 {
    2505             :                 }
    2506           0 :             }
    2507           0 :         }
    2508             :     }
    2509           0 :     return aName;
    2510             : }
    2511             : 
    2512           0 : bool hasFieldColumn(const vector<ScPivotField>* pRefFields, SCCOL nCol)
    2513             : {
    2514           0 :     if (!pRefFields)
    2515           0 :         return false;
    2516             : 
    2517           0 :     vector<ScPivotField>::const_iterator itr = pRefFields->begin(), itrEnd = pRefFields->end();
    2518           0 :     for (; itr != itrEnd; ++itr)
    2519             :     {
    2520           0 :         if (itr->nCol == nCol)
    2521             :             // This array of fields contains the specified column.
    2522           0 :             return true;
    2523             :     }
    2524           0 :     return false;
    2525             : }
    2526             : 
    2527             : class FindByOriginalDim : public std::unary_function<ScPivotField, bool>
    2528             : {
    2529             :     long mnDim;
    2530             : public:
    2531           0 :     FindByOriginalDim(long nDim) : mnDim(nDim) {}
    2532           0 :     bool operator() (const ScPivotField& r) const
    2533             :     {
    2534           0 :         return mnDim == r.getOriginalDim();
    2535             :     }
    2536             : };
    2537             : 
    2538             : }
    2539             : 
    2540           0 : void ScDPObject::ConvertOrientation(
    2541             :     ScDPSaveData& rSaveData, const ScPivotFieldVector& rFields, sal_uInt16 nOrient,
    2542             :     const Reference<XDimensionsSupplier>& xSource,
    2543             :     const ScDPLabelDataVector& rLabels,
    2544             :     const ScPivotFieldVector* pRefColFields,
    2545             :     const ScPivotFieldVector* pRefRowFields,
    2546             :     const ScPivotFieldVector* pRefPageFields )
    2547             : {
    2548           0 :     ScPivotFieldVector::const_iterator itr, itrBeg = rFields.begin(), itrEnd = rFields.end();
    2549           0 :     for (itr = itrBeg; itr != itrEnd; ++itr)
    2550             :     {
    2551           0 :         const ScPivotField& rField = *itr;
    2552             : 
    2553           0 :         long nCol = rField.getOriginalDim();
    2554           0 :         sal_uInt16 nFuncs = rField.nFuncMask;
    2555           0 :         const sheet::DataPilotFieldReference& rFieldRef = rField.maFieldRef;
    2556             : 
    2557           0 :         ScDPSaveDimension* pDim = NULL;
    2558           0 :         if ( nCol == PIVOT_DATA_FIELD )
    2559           0 :             pDim = rSaveData.GetDataLayoutDimension();
    2560             :         else
    2561             :         {
    2562           0 :             OUString aDocStr = lcl_GetDimName( xSource, nCol );   // cols must start at 0
    2563           0 :             if (!aDocStr.isEmpty())
    2564           0 :                 pDim = rSaveData.GetDimensionByName(aDocStr);
    2565             :             else
    2566           0 :                 pDim = NULL;
    2567             :         }
    2568             : 
    2569           0 :         if (!pDim)
    2570           0 :             continue;
    2571             : 
    2572           0 :         if ( nOrient == sheet::DataPilotFieldOrientation_DATA )     // set summary function
    2573             :         {
    2574             :             //  generate an individual entry for each function
    2575           0 :             bool bFirst = true;
    2576             : 
    2577             :             //  if a dimension is used for column/row/page and data,
    2578             :             //  use duplicated dimensions for all data occurrences
    2579           0 :             if (hasFieldColumn(pRefColFields, nCol))
    2580           0 :                 bFirst = false;
    2581             : 
    2582           0 :             if (bFirst && hasFieldColumn(pRefRowFields, nCol))
    2583           0 :                 bFirst = false;
    2584             : 
    2585           0 :             if (bFirst && hasFieldColumn(pRefPageFields, nCol))
    2586           0 :                 bFirst = false;
    2587             : 
    2588           0 :             if (bFirst)
    2589             :             {
    2590             :                 //  if set via api, a data column may occur several times
    2591             :                 //  (if the function hasn't been changed yet) -> also look for duplicate data column
    2592           0 :                 bFirst = std::none_of(itrBeg, itr, FindByOriginalDim(nCol));
    2593             :             }
    2594             : 
    2595           0 :             sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc(rField.nFuncMask);
    2596           0 :             if (!bFirst)
    2597           0 :                 pDim = rSaveData.DuplicateDimension(pDim->GetName());
    2598           0 :             pDim->SetOrientation(nOrient);
    2599           0 :             pDim->SetFunction(sal::static_int_cast<sal_uInt16>(eFunc));
    2600             : 
    2601           0 :             if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
    2602           0 :                 pDim->SetReferenceValue(0);
    2603             :             else
    2604           0 :                 pDim->SetReferenceValue(&rFieldRef);
    2605             :         }
    2606             :         else                                            // set SubTotals
    2607             :         {
    2608           0 :             pDim->SetOrientation( nOrient );
    2609             : 
    2610             :             sal_uInt16 nFuncArray[16];
    2611           0 :             sal_uInt16 nFuncCount = 0;
    2612           0 :             sal_uInt16 nMask = 1;
    2613           0 :             for (sal_uInt16 nBit=0; nBit<16; nBit++)
    2614             :             {
    2615           0 :                 if ( nFuncs & nMask )
    2616           0 :                     nFuncArray[nFuncCount++] = sal::static_int_cast<sal_uInt16>(ScDataPilotConversion::FirstFunc( nMask ));
    2617           0 :                 nMask *= 2;
    2618             :             }
    2619           0 :             pDim->SetSubTotals( nFuncCount, nFuncArray );
    2620             : 
    2621             :             //  ShowEmpty was implicit in old tables,
    2622             :             //  must be set for data layout dimension (not accessible in dialog)
    2623           0 :             if ( nCol == PIVOT_DATA_FIELD )
    2624           0 :                 pDim->SetShowEmpty( true );
    2625             :         }
    2626             : 
    2627           0 :         size_t nDimIndex = rField.nCol;
    2628           0 :         pDim->RemoveLayoutName();
    2629           0 :         pDim->RemoveSubtotalName();
    2630           0 :         if (nDimIndex < rLabels.size())
    2631             :         {
    2632           0 :             const ScDPLabelData& rLabel = rLabels[nDimIndex];
    2633           0 :             if (!rLabel.maLayoutName.isEmpty())
    2634           0 :                 pDim->SetLayoutName(rLabel.maLayoutName);
    2635           0 :             if (!rLabel.maSubtotalName.isEmpty())
    2636           0 :                 pDim->SetSubtotalName(rLabel.maSubtotalName);
    2637             :         }
    2638             :     }
    2639           0 : }
    2640             : 
    2641           0 : bool ScDPObject::IsOrientationAllowed( sal_uInt16 nOrient, sal_Int32 nDimFlags )
    2642             : {
    2643           0 :     bool bAllowed = true;
    2644           0 :     switch (nOrient)
    2645             :     {
    2646             :         case sheet::DataPilotFieldOrientation_PAGE:
    2647           0 :             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_PAGE_ORIENTATION ) == 0;
    2648           0 :             break;
    2649             :         case sheet::DataPilotFieldOrientation_COLUMN:
    2650           0 :             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_COLUMN_ORIENTATION ) == 0;
    2651           0 :             break;
    2652             :         case sheet::DataPilotFieldOrientation_ROW:
    2653           0 :             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_ROW_ORIENTATION ) == 0;
    2654           0 :             break;
    2655             :         case sheet::DataPilotFieldOrientation_DATA:
    2656           0 :             bAllowed = ( nDimFlags & sheet::DimensionFlags::NO_DATA_ORIENTATION ) == 0;
    2657           0 :             break;
    2658             :         default:
    2659             :             {
    2660             :                 // allowed to remove from previous orientation
    2661             :             }
    2662             :     }
    2663           0 :     return bAllowed;
    2664             : }
    2665             : 
    2666           0 : bool ScDPObject::HasRegisteredSources()
    2667             : {
    2668           0 :     bool bFound = false;
    2669             : 
    2670           0 :     uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
    2671           0 :     uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
    2672           0 :     if ( xEnAc.is() )
    2673             :     {
    2674           0 :         uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
    2675           0 :                                         OUString( SCDPSOURCE_SERVICE ) );
    2676           0 :         if ( xEnum.is() && xEnum->hasMoreElements() )
    2677           0 :             bFound = true;
    2678             :     }
    2679             : 
    2680           0 :     return bFound;
    2681             : }
    2682             : 
    2683           0 : uno::Sequence<OUString> ScDPObject::GetRegisteredSources()
    2684             : {
    2685           0 :     uno::Sequence<OUString> aSeq(0);
    2686             : 
    2687             :     //  use implementation names...
    2688             : 
    2689           0 :     uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
    2690           0 :     uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
    2691           0 :     if ( xEnAc.is() )
    2692             :     {
    2693           0 :         uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
    2694           0 :                                         OUString( SCDPSOURCE_SERVICE ) );
    2695           0 :         if ( xEnum.is() )
    2696             :         {
    2697           0 :             long nCount = 0;
    2698           0 :             while ( xEnum->hasMoreElements() )
    2699             :             {
    2700           0 :                 uno::Any aAddInAny = xEnum->nextElement();
    2701             : //              if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
    2702             :                 {
    2703           0 :                     uno::Reference<uno::XInterface> xIntFac;
    2704           0 :                     aAddInAny >>= xIntFac;
    2705           0 :                     if ( xIntFac.is() )
    2706             :                     {
    2707           0 :                         uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
    2708           0 :                         if ( xInfo.is() )
    2709             :                         {
    2710           0 :                             OUString sName = xInfo->getImplementationName();
    2711             : 
    2712           0 :                             aSeq.realloc( nCount+1 );
    2713           0 :                             aSeq.getArray()[nCount] = sName;
    2714           0 :                             ++nCount;
    2715           0 :                         }
    2716           0 :                     }
    2717             :                 }
    2718           0 :             }
    2719           0 :         }
    2720             :     }
    2721             : 
    2722           0 :     return aSeq;
    2723             : }
    2724             : 
    2725           0 : uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
    2726             : {
    2727           0 :     OUString aImplName = rDesc.aServiceName;
    2728           0 :     uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
    2729             : 
    2730           0 :     uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
    2731           0 :     uno::Reference<container::XContentEnumerationAccess> xEnAc(xManager, uno::UNO_QUERY);
    2732           0 :     if (!xEnAc.is())
    2733           0 :         return xRet;
    2734             : 
    2735             :     uno::Reference<container::XEnumeration> xEnum =
    2736           0 :         xEnAc->createContentEnumeration(OUString(SCDPSOURCE_SERVICE));
    2737           0 :     if (!xEnum.is())
    2738           0 :         return xRet;
    2739             : 
    2740           0 :     while (xEnum->hasMoreElements() && !xRet.is())
    2741             :     {
    2742           0 :         uno::Any aAddInAny = xEnum->nextElement();
    2743           0 :         uno::Reference<uno::XInterface> xIntFac;
    2744           0 :         aAddInAny >>= xIntFac;
    2745           0 :         if (!xIntFac.is())
    2746           0 :             continue;
    2747             : 
    2748           0 :         uno::Reference<lang::XServiceInfo> xInfo(xIntFac, uno::UNO_QUERY);
    2749           0 :         if (!xInfo.is() || xInfo->getImplementationName() != aImplName)
    2750           0 :             continue;
    2751             : 
    2752             :         try
    2753             :         {
    2754             :             // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
    2755             :             // passing the context to the component (see ScUnoAddInCollection::Initialize)
    2756             : 
    2757           0 :             uno::Reference<uno::XInterface> xInterface;
    2758             :             uno::Reference<uno::XComponentContext> xCtx(
    2759           0 :                 comphelper::getComponentContext(xManager));
    2760           0 :             uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
    2761           0 :             if (xCFac.is())
    2762           0 :                 xInterface = xCFac->createInstanceWithContext(xCtx);
    2763             : 
    2764           0 :             if (!xInterface.is())
    2765             :             {
    2766           0 :                 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
    2767           0 :                 if ( xFac.is() )
    2768           0 :                     xInterface = xFac->createInstance();
    2769             :             }
    2770             : 
    2771           0 :             uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
    2772           0 :             if (xInit.is())
    2773             :             {
    2774             :                 //  initialize
    2775           0 :                 uno::Sequence<uno::Any> aSeq(4);
    2776           0 :                 uno::Any* pArray = aSeq.getArray();
    2777           0 :                 pArray[0] <<= OUString( rDesc.aParSource );
    2778           0 :                 pArray[1] <<= OUString( rDesc.aParName );
    2779           0 :                 pArray[2] <<= OUString( rDesc.aParUser );
    2780           0 :                 pArray[3] <<= OUString( rDesc.aParPass );
    2781           0 :                 xInit->initialize( aSeq );
    2782             :             }
    2783           0 :             xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
    2784             :         }
    2785           0 :         catch(uno::Exception&)
    2786             :         {
    2787             :         }
    2788           0 :     }
    2789             : 
    2790           0 :     return xRet;
    2791             : }
    2792             : 
    2793             : #if DEBUG_PIVOT_TABLE
    2794             : void ScDPObject::DumpCache() const
    2795             : {
    2796             :     if (!mpTableData)
    2797             :         return;
    2798             : 
    2799             :     const ScDPCache* pCache = mpTableData->GetCacheTable().getCache();
    2800             :     if (!pCache)
    2801             :         return;
    2802             : 
    2803             :     pCache->Dump();
    2804             : }
    2805             : #endif
    2806             : 
    2807         267 : ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
    2808             : 
    2809             : namespace {
    2810             : 
    2811             : struct FindInvalidRange : public std::unary_function<ScRange, bool>
    2812             : {
    2813          28 :     bool operator() (const ScRange& r) const
    2814             :     {
    2815          28 :         return !r.IsValid();
    2816             :     }
    2817             : };
    2818             : 
    2819           3 : void setGroupItemsToCache( ScDPCache& rCache, const std::set<ScDPObject*>& rRefs )
    2820             : {
    2821             :     // Go through all referencing pivot tables, and re-fill the group dimension info.
    2822           3 :     std::set<ScDPObject*>::const_iterator itRef = rRefs.begin(), itRefEnd = rRefs.end();
    2823           7 :     for (; itRef != itRefEnd; ++itRef)
    2824             :     {
    2825           4 :         const ScDPObject* pObj = *itRef;
    2826           4 :         const ScDPSaveData* pSave = pObj->GetSaveData();
    2827           4 :         if (!pSave)
    2828           0 :             continue;
    2829             : 
    2830           4 :         const ScDPDimensionSaveData* pGroupDims = pSave->GetExistingDimensionData();
    2831           4 :         if (!pGroupDims)
    2832           4 :             continue;
    2833             : 
    2834           0 :         pGroupDims->WriteToCache(rCache);
    2835             :     }
    2836           3 : }
    2837             : 
    2838             : }
    2839             : 
    2840          16 : bool ScDPCollection::SheetCaches::hasCache(const ScRange& rRange) const
    2841             : {
    2842          16 :     RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
    2843          16 :     if (it == maRanges.end())
    2844           5 :         return false;
    2845             : 
    2846             :     // Already cached.
    2847          11 :     size_t nIndex = std::distance(maRanges.begin(), it);
    2848          11 :     CachesType::const_iterator itCache = maCaches.find(nIndex);
    2849          11 :     return itCache != maCaches.end();
    2850             : }
    2851             : 
    2852          95 : const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
    2853             : {
    2854          95 :     RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
    2855          95 :     if (it != maRanges.end())
    2856             :     {
    2857             :         // Already cached.
    2858          26 :         size_t nIndex = std::distance(maRanges.begin(), it);
    2859          26 :         CachesType::iterator itCache = maCaches.find(nIndex);
    2860          26 :         if (itCache == maCaches.end())
    2861             :         {
    2862             :             OSL_FAIL("Cache pool and index pool out-of-sync !!!");
    2863           0 :             return NULL;
    2864             :         }
    2865             : 
    2866          26 :         if (pDimData)
    2867           3 :             pDimData->WriteToCache(*itCache->second);
    2868             : 
    2869          26 :         return itCache->second;
    2870             :     }
    2871             : 
    2872             :     // Not cached.  Create a new cache.
    2873          69 :     ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
    2874          69 :     pCache->InitFromDoc(mpDoc, rRange);
    2875          69 :     if (pDimData)
    2876           1 :         pDimData->WriteToCache(*pCache);
    2877             : 
    2878             :     // Get the smallest available range index.
    2879          69 :     it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange());
    2880             : 
    2881          69 :     size_t nIndex = maRanges.size();
    2882          69 :     if (it == maRanges.end())
    2883             :     {
    2884             :         // All range indices are valid.  Append a new index.
    2885          45 :         maRanges.push_back(rRange);
    2886             :     }
    2887             :     else
    2888             :     {
    2889             :         // Slot with invalid range.  Re-use this slot.
    2890          24 :         *it = rRange;
    2891          24 :         nIndex = std::distance(maRanges.begin(), it);
    2892             :     }
    2893             : 
    2894          69 :     const ScDPCache* p = pCache.get();
    2895          69 :     o3tl::ptr_container::insert(maCaches, nIndex, std::move(pCache));
    2896          69 :     return p;
    2897             : }
    2898             : 
    2899           7 : ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
    2900             : {
    2901           7 :     RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
    2902           7 :     if (it == maRanges.end())
    2903             :         // Not cached.
    2904           0 :         return NULL;
    2905             : 
    2906             :     // Already cached.
    2907           7 :     size_t nIndex = std::distance(maRanges.begin(), it);
    2908           7 :     CachesType::iterator itCache = maCaches.find(nIndex);
    2909           7 :     if (itCache == maCaches.end())
    2910             :     {
    2911             :         OSL_FAIL("Cache pool and index pool out-of-sync !!!");
    2912           0 :         return NULL;
    2913             :     }
    2914             : 
    2915           7 :     return itCache->second;
    2916             : }
    2917             : 
    2918           6 : const ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange) const
    2919             : {
    2920           6 :     RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
    2921           6 :     if (it == maRanges.end())
    2922             :         // Not cached.
    2923           0 :         return NULL;
    2924             : 
    2925             :     // Already cached.
    2926           6 :     size_t nIndex = std::distance(maRanges.begin(), it);
    2927           6 :     CachesType::const_iterator itCache = maCaches.find(nIndex);
    2928           6 :     if (itCache == maCaches.end())
    2929             :     {
    2930             :         OSL_FAIL("Cache pool and index pool out-of-sync !!!");
    2931           0 :         return NULL;
    2932             :     }
    2933             : 
    2934           6 :     return itCache->second;
    2935             : }
    2936             : 
    2937          24 : size_t ScDPCollection::SheetCaches::size() const
    2938             : {
    2939          24 :     return maCaches.size();
    2940             : }
    2941             : 
    2942          66 : void ScDPCollection::SheetCaches::updateReference(
    2943             :     UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
    2944             : {
    2945          66 :     if (maRanges.empty())
    2946             :         // No caches.
    2947          82 :         return;
    2948             : 
    2949          50 :     RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end();
    2950         132 :     for (; it != itEnd; ++it)
    2951             :     {
    2952          82 :         const ScRange& rKeyRange = *it;
    2953          82 :         SCCOL nCol1 = rKeyRange.aStart.Col();
    2954          82 :         SCROW nRow1 = rKeyRange.aStart.Row();
    2955          82 :         SCTAB nTab1 = rKeyRange.aStart.Tab();
    2956          82 :         SCCOL nCol2 = rKeyRange.aEnd.Col();
    2957          82 :         SCROW nRow2 = rKeyRange.aEnd.Row();
    2958          82 :         SCTAB nTab2 = rKeyRange.aEnd.Tab();
    2959             : 
    2960             :         ScRefUpdateRes eRes = ScRefUpdate::Update(
    2961             :             mpDoc, eMode,
    2962         164 :             r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(),
    2963         164 :             r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz,
    2964         410 :             nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    2965             : 
    2966          82 :         if (eRes != UR_NOTHING)
    2967             :         {
    2968             :             // range updated.
    2969          33 :             ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    2970          33 :             *it = aNew;
    2971             :         }
    2972             :     }
    2973             : }
    2974             : 
    2975           3 : void ScDPCollection::SheetCaches::updateCache(const ScRange& rRange, std::set<ScDPObject*>& rRefs)
    2976             : {
    2977           3 :     RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
    2978           3 :     if (it == maRanges.end())
    2979             :     {
    2980             :         // Not cached.  Nothing to do.
    2981           0 :         rRefs.clear();
    2982           0 :         return;
    2983             :     }
    2984             : 
    2985           3 :     size_t nIndex = std::distance(maRanges.begin(), it);
    2986           3 :     CachesType::iterator itCache = maCaches.find(nIndex);
    2987           3 :     if (itCache == maCaches.end())
    2988             :     {
    2989             :         OSL_FAIL("Cache pool and index pool out-of-sync !!!");
    2990           0 :         rRefs.clear();
    2991           0 :         return;
    2992             :     }
    2993             : 
    2994           3 :     ScDPCache& rCache = *itCache->second;
    2995             : 
    2996             :     // Update the cache with new cell values. This will clear all group dimension info.
    2997           3 :     rCache.InitFromDoc(mpDoc, rRange);
    2998             : 
    2999           3 :     std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
    3000           3 :     rRefs.swap(aRefs);
    3001             : 
    3002             :     // Make sure to re-populate the group dimension info.
    3003           3 :     setGroupItemsToCache(rCache, rRefs);
    3004             : }
    3005             : 
    3006          57 : bool ScDPCollection::SheetCaches::remove(const ScDPCache* p)
    3007             : {
    3008          57 :     CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
    3009          60 :     for (; it != itEnd; ++it)
    3010             :     {
    3011          58 :         if (it->second == p)
    3012             :         {
    3013          55 :             size_t idx = it->first;
    3014          55 :             maCaches.erase(it);
    3015          55 :             maRanges[idx].SetInvalid();
    3016          55 :             return true;
    3017             :         }
    3018             :     }
    3019           2 :     return false;
    3020             : }
    3021             : 
    3022           2 : const std::vector<ScRange>& ScDPCollection::SheetCaches::getAllRanges() const
    3023             : {
    3024           2 :     return maRanges;
    3025             : }
    3026             : 
    3027         267 : ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
    3028             : 
    3029           1 : bool ScDPCollection::NameCaches::hasCache(const OUString& rName) const
    3030             : {
    3031           1 :     return maCaches.count(rName) != 0;
    3032             : }
    3033             : 
    3034           3 : const ScDPCache* ScDPCollection::NameCaches::getCache(
    3035             :     const OUString& rName, const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
    3036             : {
    3037           3 :     CachesType::const_iterator itr = maCaches.find(rName);
    3038           3 :     if (itr != maCaches.end())
    3039             :         // already cached.
    3040           0 :         return itr->second;
    3041             : 
    3042           3 :     ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
    3043           3 :     pCache->InitFromDoc(mpDoc, rRange);
    3044           3 :     if (pDimData)
    3045           0 :         pDimData->WriteToCache(*pCache);
    3046             : 
    3047           3 :     const ScDPCache* p = pCache.get();
    3048           3 :     o3tl::ptr_container::insert(maCaches, rName, std::move(pCache));
    3049           3 :     return p;
    3050             : }
    3051             : 
    3052           0 : ScDPCache* ScDPCollection::NameCaches::getExistingCache(const OUString& rName)
    3053             : {
    3054           0 :     CachesType::iterator itr = maCaches.find(rName);
    3055           0 :     return itr != maCaches.end() ? itr->second : NULL;
    3056             : }
    3057             : 
    3058           3 : size_t ScDPCollection::NameCaches::size() const
    3059             : {
    3060           3 :     return maCaches.size();
    3061             : }
    3062             : 
    3063           0 : void ScDPCollection::NameCaches::updateCache(
    3064             :     const OUString& rName, const ScRange& rRange, std::set<ScDPObject*>& rRefs)
    3065             : {
    3066           0 :     CachesType::iterator itr = maCaches.find(rName);
    3067           0 :     if (itr == maCaches.end())
    3068             :     {
    3069           0 :         rRefs.clear();
    3070           0 :         return;
    3071             :     }
    3072             : 
    3073           0 :     ScDPCache& rCache = *itr->second;
    3074             :     // Update the cache with new cell values. This will clear all group dimension info.
    3075           0 :     rCache.InitFromDoc(mpDoc, rRange);
    3076             : 
    3077           0 :     std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
    3078           0 :     rRefs.swap(aRefs);
    3079             : 
    3080             :     // Make sure to re-populate the group dimension info.
    3081           0 :     setGroupItemsToCache(rCache, rRefs);
    3082             : }
    3083             : 
    3084           2 : bool ScDPCollection::NameCaches::remove(const ScDPCache* p)
    3085             : {
    3086           2 :     CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
    3087           2 :     for (; it != itEnd; ++it)
    3088             :     {
    3089           2 :         if (it->second == p)
    3090             :         {
    3091           2 :             maCaches.erase(it);
    3092           2 :             return true;
    3093             :         }
    3094             :     }
    3095           0 :     return false;
    3096             : }
    3097             : 
    3098           0 : ScDPCollection::DBType::DBType(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) :
    3099           0 :     mnSdbType(nSdbType), maDBName(rDBName), maCommand(rCommand) {}
    3100             : 
    3101           0 : bool ScDPCollection::DBType::less::operator() (const DBType& left, const DBType& right) const
    3102             : {
    3103           0 :     return left < right;
    3104             : }
    3105             : 
    3106         267 : ScDPCollection::DBCaches::DBCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
    3107             : 
    3108           0 : bool ScDPCollection::DBCaches::hasCache(sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand) const
    3109             : {
    3110           0 :     DBType aType(nSdbType, rDBName, rCommand);
    3111           0 :     CachesType::const_iterator itr = maCaches.find(aType);
    3112           0 :     return itr != maCaches.end();
    3113             : }
    3114             : 
    3115           0 : const ScDPCache* ScDPCollection::DBCaches::getCache(
    3116             :     sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
    3117             :     const ScDPDimensionSaveData* pDimData)
    3118             : {
    3119           0 :     DBType aType(nSdbType, rDBName, rCommand);
    3120           0 :     CachesType::const_iterator itr = maCaches.find(aType);
    3121           0 :     if (itr != maCaches.end())
    3122             :         // already cached.
    3123           0 :         return itr->second;
    3124             : 
    3125           0 :     uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
    3126           0 :     if (!xRowSet.is())
    3127           0 :         return NULL;
    3128             : 
    3129           0 :     ::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mpDoc));
    3130           0 :     SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
    3131           0 :     DBConnector aDB(*pCache, xRowSet, *aFormat.GetNullDate());
    3132           0 :     if (!aDB.isValid())
    3133           0 :         return NULL;
    3134             : 
    3135           0 :     if (!pCache->InitFromDataBase(aDB))
    3136             :     {
    3137             :         // initialization failed.
    3138           0 :         comphelper::disposeComponent(xRowSet);
    3139           0 :         return NULL;
    3140             :     }
    3141             : 
    3142           0 :     if (pDimData)
    3143           0 :         pDimData->WriteToCache(*pCache);
    3144             : 
    3145           0 :     ::comphelper::disposeComponent(xRowSet);
    3146           0 :     const ScDPCache* p = pCache.get();
    3147           0 :     o3tl::ptr_container::insert(maCaches, aType, std::move(pCache));
    3148           0 :     return p;
    3149             : }
    3150             : 
    3151           0 : ScDPCache* ScDPCollection::DBCaches::getExistingCache(
    3152             :     sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
    3153             : {
    3154           0 :     DBType aType(nSdbType, rDBName, rCommand);
    3155           0 :     CachesType::iterator itr = maCaches.find(aType);
    3156           0 :     return itr != maCaches.end() ? itr->second : NULL;
    3157             : }
    3158             : 
    3159           0 : uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
    3160             :     sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
    3161             : {
    3162           0 :     uno::Reference<sdbc::XRowSet> xRowSet;
    3163             :     try
    3164             :     {
    3165           0 :         xRowSet = uno::Reference<sdbc::XRowSet>(
    3166           0 :             comphelper::getProcessServiceFactory()->createInstance(
    3167           0 :                 OUString(SC_SERVICE_ROWSET)),
    3168           0 :             UNO_QUERY);
    3169             : 
    3170           0 :         uno::Reference<beans::XPropertySet> xRowProp(xRowSet, UNO_QUERY);
    3171             :         OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
    3172           0 :         if (!xRowProp.is())
    3173             :         {
    3174           0 :             xRowSet.set(NULL);
    3175           0 :             return xRowSet;
    3176             :         }
    3177             : 
    3178             :         //  set source parameters
    3179             : 
    3180           0 :         uno::Any aAny;
    3181           0 :         aAny <<= rDBName;
    3182           0 :         xRowProp->setPropertyValue(
    3183           0 :             OUString(SC_DBPROP_DATASOURCENAME), aAny );
    3184             : 
    3185           0 :         aAny <<= rCommand;
    3186           0 :         xRowProp->setPropertyValue(
    3187           0 :             OUString(SC_DBPROP_COMMAND), aAny );
    3188             : 
    3189           0 :         aAny <<= nSdbType;
    3190           0 :         xRowProp->setPropertyValue(
    3191           0 :             OUString(SC_DBPROP_COMMANDTYPE), aAny );
    3192             : 
    3193           0 :         uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY );
    3194           0 :         if ( xExecute.is() )
    3195             :         {
    3196             :             uno::Reference<task::XInteractionHandler> xHandler(
    3197             :                 task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), 0),
    3198           0 :                 uno::UNO_QUERY_THROW);
    3199           0 :             xExecute->executeWithCompletion( xHandler );
    3200             :         }
    3201             :         else
    3202           0 :             xRowSet->execute();
    3203             : 
    3204           0 :         return xRowSet;
    3205             :     }
    3206           0 :     catch ( const sdbc::SQLException& rError )
    3207             :     {
    3208             :         //! store error message
    3209           0 :         ScopedVclPtrInstance< InfoBox > aInfoBox( nullptr, OUString(rError.Message) );
    3210           0 :         aInfoBox->Execute();
    3211             :     }
    3212           0 :     catch ( uno::Exception& )
    3213             :     {
    3214             :         OSL_FAIL("Unexpected exception in database");
    3215             :     }
    3216             : 
    3217           0 :     xRowSet.set(NULL);
    3218           0 :     return xRowSet;
    3219             : }
    3220             : 
    3221           0 : void ScDPCollection::DBCaches::updateCache(
    3222             :     sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
    3223             :     std::set<ScDPObject*>& rRefs)
    3224             : {
    3225           0 :     DBType aType(nSdbType, rDBName, rCommand);
    3226           0 :     CachesType::iterator it = maCaches.find(aType);
    3227           0 :     if (it == maCaches.end())
    3228             :     {
    3229             :         // not cached.
    3230           0 :         rRefs.clear();
    3231           0 :         return;
    3232             :     }
    3233             : 
    3234           0 :     ScDPCache& rCache = *it->second;
    3235             : 
    3236           0 :     uno::Reference<sdbc::XRowSet> xRowSet = createRowSet(nSdbType, rDBName, rCommand);
    3237           0 :     if (!xRowSet.is())
    3238             :     {
    3239           0 :         rRefs.clear();
    3240           0 :         return;
    3241             :     }
    3242             : 
    3243           0 :     SvNumberFormatter aFormat( comphelper::getProcessComponentContext(), ScGlobal::eLnge);
    3244           0 :     DBConnector aDB(rCache, xRowSet, *aFormat.GetNullDate());
    3245           0 :     if (!aDB.isValid())
    3246           0 :         return;
    3247             : 
    3248           0 :     if (!rCache.InitFromDataBase(aDB))
    3249             :     {
    3250             :         // initialization failed.
    3251           0 :         rRefs.clear();
    3252           0 :         comphelper::disposeComponent(xRowSet);
    3253           0 :         return;
    3254             :     }
    3255             : 
    3256           0 :     comphelper::disposeComponent(xRowSet);
    3257           0 :     std::set<ScDPObject*> aRefs(rCache.GetAllReferences());
    3258           0 :     aRefs.swap(rRefs);
    3259             : 
    3260             :     // Make sure to re-populate the group dimension info.
    3261           0 :     setGroupItemsToCache(rCache, rRefs);
    3262             : }
    3263             : 
    3264           0 : bool ScDPCollection::DBCaches::remove(const ScDPCache* p)
    3265             : {
    3266           0 :     CachesType::iterator it = maCaches.begin(), itEnd = maCaches.end();
    3267           0 :     for (; it != itEnd; ++it)
    3268             :     {
    3269           0 :         if (it->second == p)
    3270             :         {
    3271           0 :             maCaches.erase(it);
    3272           0 :             return true;
    3273             :         }
    3274             :     }
    3275           0 :     return false;
    3276             : }
    3277             : 
    3278         251 : ScDPCollection::ScDPCollection(ScDocument* pDocument) :
    3279             :     mpDoc( pDocument ),
    3280             :     maSheetCaches(pDocument),
    3281             :     maNameCaches(pDocument),
    3282         251 :     maDBCaches(pDocument)
    3283             : {
    3284         251 : }
    3285             : 
    3286          16 : ScDPCollection::ScDPCollection(const ScDPCollection& r) :
    3287             :     mpDoc(r.mpDoc),
    3288             :     maSheetCaches(r.mpDoc),
    3289             :     maNameCaches(r.mpDoc),
    3290          16 :     maDBCaches(r.mpDoc)
    3291             : {
    3292          16 : }
    3293             : 
    3294         526 : ScDPCollection::~ScDPCollection()
    3295             : {
    3296         263 :     maTables.clear();
    3297         263 : }
    3298             : 
    3299             : namespace {
    3300             : 
    3301             : /**
    3302             :  * Unary predicate to match DP objects by the table ID.
    3303             :  */
    3304             : class MatchByTable : public unary_function<ScDPObject, bool>
    3305             : {
    3306             :     SCTAB mnTab;
    3307             : public:
    3308          36 :     MatchByTable(SCTAB nTab) : mnTab(nTab) {}
    3309             : 
    3310          32 :     bool operator() (const ScDPObject& rObj) const
    3311             :     {
    3312          32 :         return rObj.GetOutRange().aStart.Tab() == mnTab;
    3313             :     }
    3314             : };
    3315             : 
    3316             : }
    3317             : 
    3318           5 : sal_uLong ScDPCollection::ReloadCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
    3319             : {
    3320           5 :     if (!pDPObj)
    3321           0 :         return STR_ERR_DATAPILOTSOURCE;
    3322             : 
    3323           5 :     if (pDPObj->IsSheetData())
    3324             :     {
    3325             :         // data source is internal sheet.
    3326           5 :         const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
    3327           5 :         if (!pDesc)
    3328           0 :             return STR_ERR_DATAPILOTSOURCE;
    3329             : 
    3330           5 :         sal_uLong nErrId = pDesc->CheckSourceRange();
    3331           5 :         if (nErrId)
    3332           0 :             return nErrId;
    3333             : 
    3334           5 :         if (pDesc->HasRangeName())
    3335             :         {
    3336             :             // cache by named range
    3337           0 :             ScDPCollection::NameCaches& rCaches = GetNameCaches();
    3338           0 :             if (rCaches.hasCache(pDesc->GetRangeName()))
    3339           0 :                 rCaches.updateCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), rRefs);
    3340             :             else
    3341             :             {
    3342             :                 // Not cached yet.  Collect all tables that use this named
    3343             :                 // range as data source.
    3344           0 :                 GetAllTables(pDesc->GetRangeName(), rRefs);
    3345             :             }
    3346             :         }
    3347             :         else
    3348             :         {
    3349             :             // cache by cell range
    3350           5 :             ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
    3351           5 :             if (rCaches.hasCache(pDesc->GetSourceRange()))
    3352           3 :                 rCaches.updateCache(pDesc->GetSourceRange(), rRefs);
    3353             :             else
    3354             :             {
    3355             :                 // Not cached yet.  Collect all tables that use this range as
    3356             :                 // data source.
    3357           2 :                 GetAllTables(pDesc->GetSourceRange(), rRefs);
    3358             :             }
    3359             :         }
    3360             :     }
    3361           0 :     else if (pDPObj->IsImportData())
    3362             :     {
    3363             :         // data source is external database.
    3364           0 :         const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
    3365           0 :         if (!pDesc)
    3366           0 :             return STR_ERR_DATAPILOTSOURCE;
    3367             : 
    3368           0 :         ScDPCollection::DBCaches& rCaches = GetDBCaches();
    3369           0 :         if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
    3370             :             rCaches.updateCache(
    3371           0 :                 pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
    3372             :         else
    3373             :         {
    3374             :             // Not cached yet.  Collect all tables that use this range as
    3375             :             // data source.
    3376           0 :             GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
    3377             :         }
    3378             :     }
    3379           5 :     return 0;
    3380             : }
    3381             : 
    3382           8 : bool ScDPCollection::ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
    3383             : {
    3384           8 :     if (!pDPObj)
    3385           0 :         return false;
    3386             : 
    3387           8 :     const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    3388           8 :     if (!pSaveData)
    3389           0 :         return false;
    3390             : 
    3391             :     // Note: Unlike reloading cache, when modifying the group dimensions the
    3392             :     // cache may not have all its references when this method is called.
    3393             :     // Therefore, we need to always call GetAllTables to get its correct
    3394             :     // references even when the cache exists.  This may become a non-issue
    3395             :     // if/when we implement loading and saving of pivot caches.
    3396             : 
    3397           8 :     ScDPCache* pCache = NULL;
    3398             : 
    3399           8 :     if (pDPObj->IsSheetData())
    3400             :     {
    3401             :         // data source is internal sheet.
    3402           8 :         const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
    3403           8 :         if (!pDesc)
    3404           0 :             return false;
    3405             : 
    3406           8 :         if (pDesc->HasRangeName())
    3407             :         {
    3408             :             // cache by named range
    3409           0 :             ScDPCollection::NameCaches& rCaches = GetNameCaches();
    3410           0 :             if (rCaches.hasCache(pDesc->GetRangeName()))
    3411           0 :                 pCache = rCaches.getExistingCache(pDesc->GetRangeName());
    3412             :             else
    3413             :             {
    3414             :                 // Not cached yet.  Cache the source dimensions.  Groups will
    3415             :                 // be added below.
    3416             :                 pCache = const_cast<ScDPCache*>(
    3417           0 :                     rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), NULL));
    3418             :             }
    3419           0 :             GetAllTables(pDesc->GetRangeName(), rRefs);
    3420             :         }
    3421             :         else
    3422             :         {
    3423             :             // cache by cell range
    3424           8 :             ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
    3425           8 :             if (rCaches.hasCache(pDesc->GetSourceRange()))
    3426           6 :                 pCache = rCaches.getExistingCache(pDesc->GetSourceRange());
    3427             :             else
    3428             :             {
    3429             :                 // Not cached yet.  Cache the source dimensions.  Groups will
    3430             :                 // be added below.
    3431             :                 pCache = const_cast<ScDPCache*>(
    3432           2 :                     rCaches.getCache(pDesc->GetSourceRange(), NULL));
    3433             :             }
    3434           8 :             GetAllTables(pDesc->GetSourceRange(), rRefs);
    3435             :         }
    3436             :     }
    3437           0 :     else if (pDPObj->IsImportData())
    3438             :     {
    3439             :         // data source is external database.
    3440           0 :         const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
    3441           0 :         if (!pDesc)
    3442           0 :             return false;
    3443             : 
    3444           0 :         ScDPCollection::DBCaches& rCaches = GetDBCaches();
    3445           0 :         if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
    3446             :             pCache = rCaches.getExistingCache(
    3447           0 :                 pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject);
    3448             :         else
    3449             :         {
    3450             :             // Not cached yet.  Cache the source dimensions.  Groups will
    3451             :             // be added below.
    3452             :             pCache = const_cast<ScDPCache*>(
    3453           0 :                 rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, NULL));
    3454             :         }
    3455           0 :         GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
    3456             :     }
    3457             : 
    3458           8 :     if (!pCache)
    3459           0 :         return false;
    3460             : 
    3461             :     // Clear the existing group data from the cache, and rebuild it from the
    3462             :     // dimension data.
    3463           8 :     pCache->ClearGroupFields();
    3464           8 :     const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
    3465           8 :     if (pDimData)
    3466           8 :         pDimData->WriteToCache(*pCache);
    3467           8 :     return true;
    3468             : }
    3469             : 
    3470          36 : void ScDPCollection::DeleteOnTab( SCTAB nTab )
    3471             : {
    3472          36 :     maTables.erase_if(MatchByTable(nTab));
    3473          36 : }
    3474             : 
    3475          66 : void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
    3476             :                                          const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
    3477             : {
    3478          66 :     TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
    3479         132 :     for (; itr != itrEnd; ++itr)
    3480          66 :         itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz);
    3481             : 
    3482             :     // Update the source ranges of the caches.
    3483          66 :     maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz);
    3484          66 : }
    3485             : 
    3486           0 : void ScDPCollection::CopyToTab( SCTAB nOld, SCTAB nNew )
    3487             : {
    3488           0 :     TablesType aAdded;
    3489           0 :     TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
    3490           0 :     for (; it != itEnd; ++it)
    3491             :     {
    3492           0 :         const ScDPObject& rObj = *it;
    3493           0 :         ScRange aOutRange = rObj.GetOutRange();
    3494           0 :         if (aOutRange.aStart.Tab() != nOld)
    3495           0 :             continue;
    3496             : 
    3497           0 :         ScAddress& s = aOutRange.aStart;
    3498           0 :         ScAddress& e = aOutRange.aEnd;
    3499           0 :         s.SetTab(nNew);
    3500           0 :         e.SetTab(nNew);
    3501           0 :         std::unique_ptr<ScDPObject> pNew(new ScDPObject(rObj));
    3502           0 :         pNew->SetOutRange(aOutRange);
    3503           0 :         mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
    3504           0 :         o3tl::ptr_container::push_back(aAdded, std::move(pNew));
    3505           0 :     }
    3506             : 
    3507           0 :     maTables.transfer(maTables.end(), aAdded.begin(), aAdded.end(), aAdded);
    3508           0 : }
    3509             : 
    3510          16 : bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const
    3511             : {
    3512          16 :     if (maTables.size() != r.maTables.size())
    3513          16 :         return false;
    3514             : 
    3515           0 :     TablesType::const_iterator itr = maTables.begin(), itr2 = r.maTables.begin(), itrEnd = maTables.end();
    3516           0 :     for (; itr != itrEnd; ++itr, ++itr2)
    3517           0 :         if (!itr->RefsEqual(*itr2))
    3518           0 :             return false;
    3519             : 
    3520           0 :     return true;
    3521             : }
    3522             : 
    3523           0 : void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
    3524             : {
    3525           0 :     if ( maTables.size() == r.maTables.size() )
    3526             :     {
    3527             :         //TODO: assert equal names?
    3528           0 :         TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
    3529           0 :         TablesType::iterator itr2 = r.maTables.begin();
    3530           0 :         for (; itr != itrEnd; ++itr, ++itr2)
    3531           0 :             itr->WriteRefsTo(*itr2);
    3532             :     }
    3533             :     else
    3534             :     {
    3535             :         // #i8180# If data pilot tables were deleted with their sheet,
    3536             :         // this collection contains extra entries that must be restored.
    3537             :         // Matching objects are found by their names.
    3538           0 :         size_t nSrcSize = maTables.size();
    3539           0 :         size_t nDestSize = r.maTables.size();
    3540             :         OSL_ENSURE( nSrcSize >= nDestSize, "WriteRefsTo: missing entries in document" );
    3541           0 :         for (size_t nSrcPos = 0; nSrcPos < nSrcSize; ++nSrcPos)
    3542             :         {
    3543           0 :             const ScDPObject& rSrcObj = maTables[nSrcPos];
    3544           0 :             const OUString& aName = rSrcObj.GetName();
    3545           0 :             bool bFound = false;
    3546           0 :             for (size_t nDestPos = 0; nDestPos < nDestSize && !bFound; ++nDestPos)
    3547             :             {
    3548           0 :                 ScDPObject& rDestObj = r.maTables[nDestPos];
    3549           0 :                 if (rDestObj.GetName() == aName)
    3550             :                 {
    3551           0 :                     rSrcObj.WriteRefsTo(rDestObj);     // found object, copy refs
    3552           0 :                     bFound = true;
    3553             :                 }
    3554             :             }
    3555             : 
    3556           0 :             if (!bFound)
    3557             :             {
    3558             :                 // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
    3559             : 
    3560           0 :                 ScDPObject* pDestObj = new ScDPObject(rSrcObj);
    3561           0 :                 r.InsertNewTable(pDestObj);
    3562             :             }
    3563             :         }
    3564             :         OSL_ENSURE( maTables.size() == r.maTables.size(), "WriteRefsTo: couldn't restore all entries" );
    3565             :     }
    3566           0 : }
    3567             : 
    3568        1339 : size_t ScDPCollection::GetCount() const
    3569             : {
    3570        1339 :     return maTables.size();
    3571             : }
    3572             : 
    3573        1401 : ScDPObject* ScDPCollection::operator [](size_t nIndex)
    3574             : {
    3575        1401 :     return &maTables[nIndex];
    3576             : }
    3577             : 
    3578           2 : const ScDPObject* ScDPCollection::operator [](size_t nIndex) const
    3579             : {
    3580           2 :     return &maTables[nIndex];
    3581             : }
    3582             : 
    3583          33 : const ScDPObject* ScDPCollection::GetByName(const OUString& rName) const
    3584             : {
    3585          33 :     TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
    3586          39 :     for (; itr != itrEnd; ++itr)
    3587           6 :         if (itr->GetName() == rName)
    3588           0 :             return &(*itr);
    3589             : 
    3590          33 :     return NULL;
    3591             : }
    3592             : 
    3593          19 : OUString ScDPCollection::CreateNewName( sal_uInt16 nMin ) const
    3594             : {
    3595          19 :     OUString aBase("DataPilot");
    3596             : 
    3597          19 :     size_t n = maTables.size();
    3598          19 :     for (size_t nAdd = 0; nAdd <= n; ++nAdd)   //  nCount+1 tries
    3599             :     {
    3600          19 :         OUStringBuffer aBuf;
    3601          19 :         aBuf.append(aBase);
    3602          19 :         aBuf.append(static_cast<sal_Int32>(nMin + nAdd));
    3603          19 :         OUString aNewName = aBuf.makeStringAndClear();
    3604          19 :         bool bFound = false;
    3605          19 :         TablesType::const_iterator itr = maTables.begin(), itrEnd = maTables.end();
    3606          38 :         for (; itr != itrEnd; ++itr)
    3607             :         {
    3608          19 :             if (itr->GetName() == aNewName)
    3609             :             {
    3610           0 :                 bFound = true;
    3611           0 :                 break;
    3612             :             }
    3613             :         }
    3614          19 :         if (!bFound)
    3615          19 :             return aNewName;            // found unused Name
    3616           0 :     }
    3617           0 :     return OUString();                    // should not happen
    3618             : }
    3619             : 
    3620          22 : void ScDPCollection::FreeTable(ScDPObject* pDPObj)
    3621             : {
    3622          22 :     const ScRange& rOutRange = pDPObj->GetOutRange();
    3623          22 :     const ScAddress& s = rOutRange.aStart;
    3624          22 :     const ScAddress& e = rOutRange.aEnd;
    3625          22 :     mpDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
    3626          22 :     TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end();
    3627          23 :     for (; itr != itrEnd; ++itr)
    3628             :     {
    3629          23 :         ScDPObject* p = &(*itr);
    3630          23 :         if (p == pDPObj)
    3631             :         {
    3632          22 :             maTables.erase(itr);
    3633          22 :             break;
    3634             :         }
    3635             :     }
    3636          22 : }
    3637             : 
    3638          54 : bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj)
    3639             : {
    3640          54 :     const ScRange& rOutRange = pDPObj->GetOutRange();
    3641          54 :     const ScAddress& s = rOutRange.aStart;
    3642          54 :     const ScAddress& e = rOutRange.aEnd;
    3643          54 :     mpDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE);
    3644             : 
    3645          54 :     maTables.push_back(pDPObj);
    3646          54 :     return true;
    3647             : }
    3648             : 
    3649         133 : ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches()
    3650             : {
    3651         133 :     return maSheetCaches;
    3652             : }
    3653             : 
    3654           6 : const ScDPCollection::SheetCaches& ScDPCollection::GetSheetCaches() const
    3655             : {
    3656           6 :     return maSheetCaches;
    3657             : }
    3658             : 
    3659           7 : ScDPCollection::NameCaches& ScDPCollection::GetNameCaches()
    3660             : {
    3661           7 :     return maNameCaches;
    3662             : }
    3663             : 
    3664           0 : const ScDPCollection::NameCaches& ScDPCollection::GetNameCaches() const
    3665             : {
    3666           0 :     return maNameCaches;
    3667             : }
    3668             : 
    3669           0 : ScDPCollection::DBCaches& ScDPCollection::GetDBCaches()
    3670             : {
    3671           0 :     return maDBCaches;
    3672             : }
    3673             : 
    3674           0 : const ScDPCollection::DBCaches& ScDPCollection::GetDBCaches() const
    3675             : {
    3676           0 :     return maDBCaches;
    3677             : }
    3678             : 
    3679          96 : ScRangeList ScDPCollection::GetAllTableRanges( SCTAB nTab ) const
    3680             : {
    3681          96 :     return std::for_each(maTables.begin(), maTables.end(), AccumulateOutputRanges(nTab)).getRanges();
    3682             : }
    3683             : 
    3684           0 : bool ScDPCollection::IntersectsTableByColumns( SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCTAB nTab ) const
    3685             : {
    3686           0 :     return std::any_of(maTables.begin(), maTables.end(), FindIntersetingTableByColumns(nCol1, nCol2, nRow, nTab));
    3687             : }
    3688             : 
    3689           0 : bool ScDPCollection::IntersectsTableByRows( SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab ) const
    3690             : {
    3691           0 :     return std::any_of(maTables.begin(), maTables.end(), FindIntersectingTableByRows(nCol, nRow1, nRow2, nTab));
    3692             : }
    3693             : 
    3694           0 : bool ScDPCollection::HasTable( const ScRange& rRange ) const
    3695             : {
    3696           0 :     return std::any_of(maTables.begin(), maTables.end(), FindIntersectingTable(rRange));
    3697             : }
    3698             : 
    3699             : #if DEBUG_PIVOT_TABLE
    3700             : 
    3701             : namespace {
    3702             : 
    3703             : struct DumpTable : std::unary_function<ScDPObject, void>
    3704             : {
    3705             :     void operator() (const ScDPObject& rObj) const
    3706             :     {
    3707             :         cout << "-- '" << rObj.GetName() << "'" << endl;
    3708             :         ScDPSaveData* pSaveData = rObj.GetSaveData();
    3709             :         if (!pSaveData)
    3710             :             return;
    3711             : 
    3712             :         pSaveData->Dump();
    3713             : 
    3714             :         cout << endl; // blank line
    3715             :     }
    3716             : };
    3717             : 
    3718             : }
    3719             : 
    3720             : void ScDPCollection::DumpTables() const
    3721             : {
    3722             :     std::for_each(maTables.begin(), maTables.end(), DumpTable());
    3723             : }
    3724             : 
    3725             : #endif
    3726             : 
    3727          57 : void ScDPCollection::RemoveCache(const ScDPCache* pCache)
    3728             : {
    3729          57 :     if (maSheetCaches.remove(pCache))
    3730             :         // sheet cache removed.
    3731          55 :         return;
    3732             : 
    3733           2 :     if (maNameCaches.remove(pCache))
    3734             :         // named range cache removed.
    3735           2 :         return;
    3736             : 
    3737           0 :     if (maDBCaches.remove(pCache))
    3738             :         // database cache removed.
    3739           0 :         return;
    3740             : }
    3741             : 
    3742          10 : void ScDPCollection::GetAllTables(const ScRange& rSrcRange, std::set<ScDPObject*>& rRefs) const
    3743             : {
    3744          10 :     std::set<ScDPObject*> aRefs;
    3745          10 :     TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
    3746          21 :     for (; it != itEnd; ++it)
    3747             :     {
    3748          11 :         const ScDPObject& rObj = *it;
    3749          11 :         if (!rObj.IsSheetData())
    3750             :             // Source is not a sheet range.
    3751           0 :             continue;
    3752             : 
    3753          11 :         const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
    3754          11 :         if (!pDesc)
    3755           0 :             continue;
    3756             : 
    3757          11 :         if (pDesc->HasRangeName())
    3758             :             // This table has a range name as its source.
    3759           0 :             continue;
    3760             : 
    3761          11 :         if (pDesc->GetSourceRange() != rSrcRange)
    3762             :             // Different source range.
    3763           0 :             continue;
    3764             : 
    3765          11 :         aRefs.insert(const_cast<ScDPObject*>(&rObj));
    3766             :     }
    3767             : 
    3768          10 :     rRefs.swap(aRefs);
    3769          10 : }
    3770             : 
    3771           0 : void ScDPCollection::GetAllTables(const OUString& rSrcName, std::set<ScDPObject*>& rRefs) const
    3772             : {
    3773           0 :     std::set<ScDPObject*> aRefs;
    3774           0 :     TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
    3775           0 :     for (; it != itEnd; ++it)
    3776             :     {
    3777           0 :         const ScDPObject& rObj = *it;
    3778           0 :         if (!rObj.IsSheetData())
    3779             :             // Source is not a sheet range.
    3780           0 :             continue;
    3781             : 
    3782           0 :         const ScSheetSourceDesc* pDesc = rObj.GetSheetDesc();
    3783           0 :         if (!pDesc)
    3784           0 :             continue;
    3785             : 
    3786           0 :         if (!pDesc->HasRangeName())
    3787             :             // This table probably has a sheet range as its source.
    3788           0 :             continue;
    3789             : 
    3790           0 :         if (pDesc->GetRangeName() != rSrcName)
    3791             :             // Different source name.
    3792           0 :             continue;
    3793             : 
    3794           0 :         aRefs.insert(const_cast<ScDPObject*>(&rObj));
    3795             :     }
    3796             : 
    3797           0 :     rRefs.swap(aRefs);
    3798           0 : }
    3799             : 
    3800           0 : void ScDPCollection::GetAllTables(
    3801             :     sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand,
    3802             :     std::set<ScDPObject*>& rRefs) const
    3803             : {
    3804           0 :     std::set<ScDPObject*> aRefs;
    3805           0 :     TablesType::const_iterator it = maTables.begin(), itEnd = maTables.end();
    3806           0 :     for (; it != itEnd; ++it)
    3807             :     {
    3808           0 :         const ScDPObject& rObj = *it;
    3809           0 :         if (!rObj.IsImportData())
    3810             :             // Source data is not a database.
    3811           0 :             continue;
    3812             : 
    3813           0 :         const ScImportSourceDesc* pDesc = rObj.GetImportSourceDesc();
    3814           0 :         if (!pDesc)
    3815           0 :             continue;
    3816             : 
    3817           0 :         if (!pDesc->aDBName.equals(rDBName) || !pDesc->aObject.equals(rCommand) || pDesc->GetCommandType() != nSdbType)
    3818             :             // Different database source.
    3819           0 :             continue;
    3820             : 
    3821           0 :         aRefs.insert(const_cast<ScDPObject*>(&rObj));
    3822             :     }
    3823             : 
    3824           0 :     rRefs.swap(aRefs);
    3825           0 : }
    3826             : 
    3827           0 : bool operator<(const ScDPCollection::DBType& left, const ScDPCollection::DBType& right)
    3828             : {
    3829           0 :     if (left.mnSdbType != right.mnSdbType)
    3830           0 :         return left.mnSdbType < right.mnSdbType;
    3831             : 
    3832           0 :     if (!left.maDBName.equals(right.maDBName))
    3833           0 :         return left.maDBName < right.maDBName;
    3834             : 
    3835           0 :     return left.maCommand < right.maCommand;
    3836         156 : }
    3837             : 
    3838             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11