LCOV - code coverage report
Current view: top level - sc/source/core/data - dptabsrc.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 995 1338 74.4 %
Date: 2015-06-13 12:38:46 Functions: 128 201 63.7 %
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 "dptabsrc.hxx"
      21             : 
      22             : #include <algorithm>
      23             : #include <set>
      24             : #include <unordered_set>
      25             : #include <vector>
      26             : 
      27             : #include <rtl/math.hxx>
      28             : #include <svl/itemprop.hxx>
      29             : #include <svl/intitem.hxx>
      30             : #include <vcl/svapp.hxx>
      31             : 
      32             : #include "scitems.hxx"
      33             : #include "document.hxx"
      34             : #include "docpool.hxx"
      35             : #include "patattr.hxx"
      36             : #include "formulacell.hxx"
      37             : 
      38             : #include "dptabres.hxx"
      39             : #include "dptabdat.hxx"
      40             : #include "global.hxx"
      41             : #include "datauno.hxx"
      42             : #include "miscuno.hxx"
      43             : #include "unonames.hxx"
      44             : #include "dpitemdata.hxx"
      45             : #include "dputil.hxx"
      46             : #include "dpresfilter.hxx"
      47             : #include "calcmacros.hxx"
      48             : 
      49             : #include <com/sun/star/beans/PropertyAttribute.hpp>
      50             : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
      51             : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
      52             : #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
      53             : #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
      54             : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
      55             : #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
      56             : #include <com/sun/star/table/CellAddress.hpp>
      57             : 
      58             : #include <comphelper/string.hxx>
      59             : #include <unotools/collatorwrapper.hxx>
      60             : #include <unotools/calendarwrapper.hxx>
      61             : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
      62             : 
      63             : using namespace com::sun::star;
      64             : using ::std::vector;
      65             : using ::std::set;
      66             : using ::com::sun::star::uno::Reference;
      67             : using ::com::sun::star::uno::Sequence;
      68             : using ::com::sun::star::uno::Any;
      69             : using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
      70             : 
      71             : #define SC_MINCOUNT_LIMIT   1000000
      72             : 
      73           0 : SC_SIMPLE_SERVICE_INFO( ScDPSource,      "ScDPSource",      "com.sun.star.sheet.DataPilotSource" )
      74           0 : SC_SIMPLE_SERVICE_INFO( ScDPDimensions,  "ScDPDimensions",  "com.sun.star.sheet.DataPilotSourceDimensions" )
      75           0 : SC_SIMPLE_SERVICE_INFO( ScDPDimension,   "ScDPDimension",   "com.sun.star.sheet.DataPilotSourceDimension" )
      76           0 : SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" )
      77           0 : SC_SIMPLE_SERVICE_INFO( ScDPHierarchy,   "ScDPHierarchy",   "com.sun.star.sheet.DataPilotSourceHierarcy" )
      78           0 : SC_SIMPLE_SERVICE_INFO( ScDPLevels,      "ScDPLevels",      "com.sun.star.sheet.DataPilotSourceLevels" )
      79           0 : SC_SIMPLE_SERVICE_INFO( ScDPLevel,       "ScDPLevel",       "com.sun.star.sheet.DataPilotSourceLevel" )
      80           0 : SC_SIMPLE_SERVICE_INFO( ScDPMembers,     "ScDPMembers",     "com.sun.star.sheet.DataPilotSourceMembers" )
      81           0 : SC_SIMPLE_SERVICE_INFO( ScDPMember,      "ScDPMember",      "com.sun.star.sheet.DataPilotSourceMember" )
      82             : 
      83             : // property maps for PropertySetInfo
      84             : //  DataDescription / NumberFormat are internal
      85             : 
      86             : //TODO: move to a header?
      87        1539 : static bool lcl_GetBoolFromAny( const uno::Any& aAny )
      88             : {
      89        1539 :     if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN )
      90        1539 :         return *static_cast<sal_Bool const *>(aAny.getValue());
      91           0 :     return false;
      92             : }
      93             : 
      94        3754 : static void lcl_SetBoolInAny( uno::Any& rAny, bool bValue )
      95             : {
      96        3754 :     rAny.setValue( &bValue, cppu::UnoType<bool>::get() );
      97        3754 : }
      98             : 
      99         122 : ScDPSource::ScDPSource( ScDPTableData* pD ) :
     100             :     pData( pD ),
     101             :     pDimensions( NULL ),
     102             :     bColumnGrand( true ),       // default is true
     103             :     bRowGrand( true ),
     104             :     bIgnoreEmptyRows( false ),
     105             :     bRepeatIfEmpty( false ),
     106             :     nDupCount( 0 ),
     107             :     pResData( NULL ),
     108             :     pColResRoot( NULL ),
     109             :     pRowResRoot( NULL ),
     110             :     pColResults( NULL ),
     111             :     pRowResults( NULL ),
     112             :     bResultOverflow( false ),
     113         122 :     bPageFiltered( false )
     114             : {
     115         122 :     pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
     116         122 : }
     117             : 
     118         360 : ScDPSource::~ScDPSource()
     119             : {
     120         120 :     if (pDimensions)
     121         120 :         pDimensions->release();     // ref-counted
     122             : 
     123             :     // free lists
     124             : 
     125         120 :     delete[] pColResults;
     126         120 :     delete[] pRowResults;
     127             : 
     128         120 :     delete pColResRoot;
     129         120 :     delete pRowResRoot;
     130         120 :     delete pResData;
     131         240 : }
     132             : 
     133         109 : const OUString* ScDPSource::GetGrandTotalName() const
     134             : {
     135         109 :     return mpGrandTotalName.get();
     136             : }
     137             : 
     138        3294 : sal_uInt16 ScDPSource::GetOrientation(long nColumn)
     139             : {
     140        3294 :     if (std::find(maColDims.begin(), maColDims.end(), nColumn) != maColDims.end())
     141         800 :         return sheet::DataPilotFieldOrientation_COLUMN;
     142             : 
     143        2494 :     if (std::find(maRowDims.begin(), maRowDims.end(), nColumn) != maRowDims.end())
     144        1127 :         return sheet::DataPilotFieldOrientation_ROW;
     145             : 
     146        1367 :     if (std::find(maDataDims.begin(), maDataDims.end(), nColumn) != maDataDims.end())
     147         560 :         return sheet::DataPilotFieldOrientation_DATA;
     148             : 
     149         807 :     if (std::find(maPageDims.begin(), maPageDims.end(), nColumn) != maPageDims.end())
     150          64 :         return sheet::DataPilotFieldOrientation_PAGE;
     151             : 
     152         743 :     return sheet::DataPilotFieldOrientation_HIDDEN;
     153             : }
     154             : 
     155          10 : long ScDPSource::GetDataDimensionCount()
     156             : {
     157          10 :     return maDataDims.size();
     158             : }
     159             : 
     160         132 : ScDPDimension* ScDPSource::GetDataDimension(long nIndex)
     161             : {
     162         132 :     if (nIndex < 0 || static_cast<size_t>(nIndex) >= maDataDims.size())
     163          11 :         return NULL;
     164             : 
     165         121 :     long nDimIndex = maDataDims[nIndex];
     166         121 :     return GetDimensionsObject()->getByIndex(nDimIndex);
     167             : }
     168             : 
     169          27 : OUString ScDPSource::GetDataDimName(long nIndex)
     170             : {
     171          27 :     OUString aRet;
     172          27 :     ScDPDimension* pDim = GetDataDimension(nIndex);
     173          27 :     if (pDim)
     174          27 :         aRet = pDim->getName();
     175          27 :     return aRet;
     176             : }
     177             : 
     178         452 : long ScDPSource::GetPosition(long nColumn)
     179             : {
     180         452 :     std::vector<long>::const_iterator it, itBeg = maColDims.begin(), itEnd = maColDims.end();
     181         452 :     it = std::find(itBeg, itEnd, nColumn);
     182         452 :     if (it != itEnd)
     183          49 :         return std::distance(itBeg, it);
     184             : 
     185         403 :     itBeg = maRowDims.begin();
     186         403 :     itEnd = maRowDims.end();
     187         403 :     it = std::find(itBeg, itEnd, nColumn);
     188         403 :     if (it != itEnd)
     189         130 :         return std::distance(itBeg, it);
     190             : 
     191         273 :     itBeg = maDataDims.begin();
     192         273 :     itEnd = maDataDims.end();
     193         273 :     it = std::find(itBeg, itEnd, nColumn);
     194         273 :     if (it != itEnd)
     195          86 :         return std::distance(itBeg, it);
     196             : 
     197         187 :     itBeg = maPageDims.begin();
     198         187 :     itEnd = maPageDims.end();
     199         187 :     it = std::find(itBeg, itEnd, nColumn);
     200         187 :     if (it != itEnd)
     201          27 :         return std::distance(itBeg, it);
     202             : 
     203         160 :     return 0;
     204             : }
     205             : 
     206             : namespace {
     207             : 
     208       10076 : bool testSubTotal( bool& rAllowed, long nColumn, const std::vector<long>& rDims, ScDPSource* pSource )
     209             : {
     210       10076 :     rAllowed = true;
     211       10076 :     std::vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
     212       12778 :     for (; it != itEnd; ++it)
     213             :     {
     214       10275 :         if (*it != nColumn)
     215        2702 :             continue;
     216             : 
     217        7573 :         if ( pSource->IsDataLayoutDimension(nColumn) )
     218             :         {
     219             :             //  no subtotals for data layout dim, no matter where
     220         290 :             rAllowed = false;
     221         290 :             return true;
     222             :         }
     223             : 
     224             :         //  no subtotals if no other dim but data layout follows
     225        7283 :         ++it;
     226        7283 :         if (it != itEnd && pSource->IsDataLayoutDimension(*it))
     227        1087 :             ++it;
     228        7283 :         if (it == itEnd)
     229        5835 :             rAllowed = false;
     230             : 
     231        7283 :         return true;    // found
     232             :     }
     233             : 
     234        2503 :     return false;
     235             : }
     236             : 
     237        3740 : void removeDim( long nRemove, std::vector<long>& rDims )
     238             : {
     239        3740 :     std::vector<long>::iterator it = std::find(rDims.begin(), rDims.end(), nRemove);
     240        3740 :     if (it != rDims.end())
     241           0 :         rDims.erase(it);
     242        3740 : }
     243             : 
     244             : }
     245             : 
     246        7573 : bool ScDPSource::SubTotalAllowed(long nColumn)
     247             : {
     248             :     //TODO: cache this at ScDPResultData
     249        7573 :     bool bAllowed = true;
     250        7573 :     if ( testSubTotal(bAllowed, nColumn, maColDims, this) )
     251        5070 :         return bAllowed;
     252        2503 :     if ( testSubTotal(bAllowed, nColumn, maRowDims, this) )
     253        2503 :         return bAllowed;
     254           0 :     return bAllowed;
     255             : }
     256             : 
     257         935 : void ScDPSource::SetOrientation(long nColumn, sal_uInt16 nNew)
     258             : {
     259             :     //TODO: change to no-op if new orientation is equal to old?
     260             : 
     261             :     // remove from old list
     262         935 :     removeDim(nColumn, maColDims);
     263         935 :     removeDim(nColumn, maRowDims);
     264         935 :     removeDim(nColumn, maDataDims);
     265         935 :     removeDim(nColumn, maPageDims);
     266             : 
     267             :     // add to new list
     268         935 :     switch (nNew)
     269             :     {
     270             :         case sheet::DataPilotFieldOrientation_COLUMN:
     271          51 :             maColDims.push_back(nColumn);
     272          51 :             break;
     273             :         case sheet::DataPilotFieldOrientation_ROW:
     274         139 :             maRowDims.push_back(nColumn);
     275         139 :             break;
     276             :         case sheet::DataPilotFieldOrientation_DATA:
     277          90 :             maDataDims.push_back(nColumn);
     278          90 :             break;
     279             :         case sheet::DataPilotFieldOrientation_PAGE:
     280          28 :             maPageDims.push_back(nColumn);
     281          28 :             break;
     282             :             // DataPilot Migration - Cache&&Performance
     283             :         case sheet::DataPilotFieldOrientation_HIDDEN:
     284         627 :             break;
     285             :         default:
     286             :             OSL_FAIL( "ScDPSource::SetOrientation: unexpected orientation" );
     287           0 :             break;
     288             :     }
     289         935 : }
     290             : 
     291       11736 : bool ScDPSource::IsDataLayoutDimension(long nDim)
     292             : {
     293       11736 :     return nDim == pData->GetColumnCount();
     294             : }
     295             : 
     296         182 : sal_uInt16 ScDPSource::GetDataLayoutOrientation()
     297             : {
     298         182 :     return GetOrientation(pData->GetColumnCount());
     299             : }
     300             : 
     301        2137 : bool ScDPSource::IsDateDimension(long nDim)
     302             : {
     303        2137 :     return pData->IsDateDimension(nDim);
     304             : }
     305             : 
     306        4658 : ScDPDimensions* ScDPSource::GetDimensionsObject()
     307             : {
     308        4658 :     if (!pDimensions)
     309             :     {
     310         131 :         pDimensions = new ScDPDimensions(this);
     311         131 :         pDimensions->acquire();                     // ref-counted
     312             :     }
     313        4658 :     return pDimensions;
     314             : }
     315             : 
     316        1219 : uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException, std::exception)
     317             : {
     318        1219 :     return GetDimensionsObject();
     319             : }
     320             : 
     321          14 : void ScDPSource::SetDupCount( long nNew )
     322             : {
     323          14 :     nDupCount = nNew;
     324          14 : }
     325             : 
     326           5 : ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const OUString& rNewName)
     327             : {
     328             :     OSL_ENSURE( pDimensions, "AddDuplicated without dimensions?" );
     329             : 
     330             :     //  re-use
     331             : 
     332           5 :     long nOldDimCount = pDimensions->getCount();
     333          20 :     for (long i=0; i<nOldDimCount; i++)
     334             :     {
     335          15 :         ScDPDimension* pDim = pDimensions->getByIndex(i);
     336          15 :         if (pDim && pDim->getName().equals(rNewName))
     337             :         {
     338             :             //TODO: test if pDim is a duplicate of source
     339           0 :             return pDim;
     340             :         }
     341             :     }
     342             : 
     343           5 :     SetDupCount( nDupCount + 1 );
     344           5 :     pDimensions->CountChanged();        // uses nDupCount
     345             : 
     346           5 :     return pDimensions->getByIndex( pDimensions->getCount() - 1 );
     347             : }
     348             : 
     349       16411 : long ScDPSource::GetSourceDim(long nDim)
     350             : {
     351             :     //  original source dimension or data layout dimension?
     352       16411 :     if ( nDim <= pData->GetColumnCount() )
     353       16374 :         return nDim;
     354             : 
     355          37 :     if ( nDim < pDimensions->getCount() )
     356             :     {
     357          37 :         ScDPDimension* pDimObj = pDimensions->getByIndex( nDim );
     358          37 :         if ( pDimObj )
     359             :         {
     360          37 :             long nSource = pDimObj->GetSourceDim();
     361          37 :             if ( nSource >= 0 )
     362          37 :                 return nSource;
     363             :         }
     364             :     }
     365             : 
     366             :     OSL_FAIL("GetSourceDim: wrong dim");
     367           0 :     return nDim;
     368             : }
     369             : 
     370          91 : uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
     371             :                                                             throw(uno::RuntimeException, std::exception)
     372             : {
     373          91 :     CreateRes_Impl();       // create pColResRoot and pRowResRoot
     374             : 
     375          91 :     if ( bResultOverflow )      // set in CreateRes_Impl
     376             :     {
     377             :         //  no results available
     378           0 :         throw uno::RuntimeException();
     379             :     }
     380             : 
     381          91 :     long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure());
     382          91 :     long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
     383             : 
     384             :     //  allocate full sequence
     385             :     //TODO: leave out empty rows???
     386             : 
     387          91 :     uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount );
     388          91 :     uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray();
     389         520 :     for (long nRow = 0; nRow < nRowCount; nRow++)
     390             :     {
     391         429 :         uno::Sequence<sheet::DataResult> aColSeq( nColCount );
     392             :         //  use default values of DataResult
     393         429 :         pRowAry[nRow] = aColSeq;
     394         429 :     }
     395             : 
     396         182 :     ScDPResultFilterContext aFilterCxt;
     397             :     pRowResRoot->FillDataResults(
     398          91 :         pColResRoot, aFilterCxt, aSeq, pResData->GetRowStartMeasure());
     399             : 
     400          91 :     maResFilterSet.swap(aFilterCxt.maFilterSet); // Keep this data for GETPIVOTDATA.
     401             : 
     402         182 :     return aSeq;
     403             : }
     404             : 
     405          43 : uno::Sequence<double> ScDPSource::getFilteredResults(
     406             :             const uno::Sequence<sheet::DataPilotFieldFilter>& aFilters )
     407             :                 throw (uno::RuntimeException, std::exception)
     408             : {
     409          43 :     if (maResFilterSet.empty())
     410           3 :         getResults(); // Build result tree first.
     411             : 
     412             :     // Get result values from the tree.
     413          43 :     const ScDPResultTree::ValuesType* pVals = maResFilterSet.getResults(aFilters);
     414          43 :     if (pVals)
     415             :     {
     416          19 :         size_t n = pVals->size();
     417          19 :         uno::Sequence<double> aRet(n);
     418          44 :         for (size_t i = 0; i < n; ++i)
     419          25 :             aRet[i] = (*pVals)[i];
     420             : 
     421          19 :         return aRet;
     422             :     }
     423             : 
     424          24 :     if (aFilters.getLength() == 1)
     425             :     {
     426             :         // Try to get result from the leaf nodes.
     427          24 :         double fVal = maResFilterSet.getLeafResult(aFilters[0]);
     428          24 :         if (!rtl::math::isNan(fVal))
     429             :         {
     430          24 :             uno::Sequence<double> aRet(1);
     431          24 :             aRet[0] = fVal;
     432          24 :             return aRet;
     433             :         }
     434             :     }
     435             : 
     436           0 :     return uno::Sequence<double>();
     437             : }
     438             : 
     439           9 : void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException, std::exception)
     440             : {
     441           9 :     disposeData();
     442           9 : }
     443             : 
     444           0 : void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& )
     445             :                                                 throw(uno::RuntimeException, std::exception)
     446             : {
     447             :     OSL_FAIL("not implemented");    //TODO: exception?
     448           0 : }
     449             : 
     450           0 : void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& )
     451             :                                                 throw(uno::RuntimeException, std::exception)
     452             : {
     453             :     OSL_FAIL("not implemented");    //TODO: exception?
     454           0 : }
     455             : 
     456         133 : Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters)
     457             :     throw (uno::RuntimeException, std::exception)
     458             : {
     459         133 :     long nColumnCount = GetData()->GetColumnCount();
     460             : 
     461         133 :     vector<ScDPFilteredCache::Criterion> aFilterCriteria;
     462         133 :     sal_Int32 nFilterCount = aFilters.getLength();
     463         593 :     for (sal_Int32 i = 0; i < nFilterCount; ++i)
     464             :     {
     465         460 :         const sheet::DataPilotFieldFilter& rFilter = aFilters[i];
     466         460 :         const OUString& aFieldName = rFilter.FieldName;
     467        2760 :         for (long nCol = 0; nCol < nColumnCount; ++nCol)
     468             :         {
     469        2300 :             if (aFieldName.equals(pData->getDimensionName(nCol)))
     470             :             {
     471         460 :                 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol );
     472             :                 ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
     473         460 :                                         GetLevelsObject()->getByIndex(0)->GetMembersObject();
     474         460 :                 sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue );
     475         460 :                 if ( nIndex >= 0 )
     476             :                 {
     477         460 :                     ScDPItemData aItem;
     478         460 :                     pMembers->getByIndex(nIndex)->FillItemData( aItem );
     479         460 :                     aFilterCriteria.push_back( ScDPFilteredCache::Criterion() );
     480         460 :                     aFilterCriteria.back().mnFieldIndex = nCol;
     481         460 :                     aFilterCriteria.back().mpFilter.reset(
     482         920 :                         new ScDPFilteredCache::SingleFilter(aItem));
     483             :                 }
     484             :             }
     485             :         }
     486             :     }
     487             : 
     488             :     // Take into account the visibilities of field members.
     489         266 :     ScDPResultVisibilityData aResVisData(this);
     490         133 :     pRowResRoot->FillVisibilityData(aResVisData);
     491         133 :     pColResRoot->FillVisibilityData(aResVisData);
     492         133 :     aResVisData.fillFieldFilters(aFilterCriteria);
     493             : 
     494         133 :     Sequence< Sequence<Any> > aTabData;
     495         266 :     std::unordered_set<sal_Int32> aCatDims;
     496         133 :     GetCategoryDimensionIndices(aCatDims);
     497         133 :     pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData);
     498         266 :     return aTabData;
     499             : }
     500             : 
     501          88 : OUString ScDPSource::getDataDescription()
     502             : {
     503          88 :     CreateRes_Impl();       // create pResData
     504             : 
     505          88 :     OUString aRet;
     506          88 :     if ( pResData->GetMeasureCount() == 1 )
     507             :     {
     508          79 :         bool bTotalResult = false;
     509          79 :         aRet = pResData->GetMeasureString(0, true, SUBTOTAL_FUNC_NONE, bTotalResult);
     510             :     }
     511             : 
     512             :     //  empty for more than one measure
     513             : 
     514          88 :     return aRet;
     515             : }
     516             : 
     517         130 : void ScDPSource::setIgnoreEmptyRows(bool bSet)
     518             : {
     519         130 :     bIgnoreEmptyRows = bSet;
     520         130 :     pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
     521         130 : }
     522             : 
     523         130 : void ScDPSource::setRepeatIfEmpty(bool bSet)
     524             : {
     525         130 :     bRepeatIfEmpty = bSet;
     526         130 :     pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
     527         130 : }
     528             : 
     529           9 : void ScDPSource::disposeData()
     530             : {
     531           9 :     maResFilterSet.clear();
     532             : 
     533           9 :     if ( pResData )
     534             :     {
     535             :         //  reset all data...
     536             : 
     537           9 :         DELETEZ(pColResRoot);
     538           9 :         DELETEZ(pRowResRoot);
     539           9 :         DELETEZ(pResData);
     540           9 :         delete[] pColResults;
     541           9 :         delete[] pRowResults;
     542           9 :         pColResults = NULL;
     543           9 :         pRowResults = NULL;
     544           9 :         aColLevelList.clear();
     545           9 :         aRowLevelList.clear();
     546             :     }
     547             : 
     548           9 :     if ( pDimensions )
     549             :     {
     550           9 :         pDimensions->release(); // ref-counted
     551           9 :         pDimensions = NULL;     //  settings have to be applied (from SaveData) again!
     552             :     }
     553           9 :     SetDupCount( 0 );
     554             : 
     555           9 :     maColDims.clear();
     556           9 :     maRowDims.clear();
     557           9 :     maDataDims.clear();
     558           9 :     maPageDims.clear();
     559             : 
     560           9 :     pData->DisposeData();   // cached entries etc.
     561           9 :     bPageFiltered = false;
     562           9 :     bResultOverflow = false;
     563           9 : }
     564             : 
     565         182 : static long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels )
     566             : {
     567             :     //  Calculate the product of the member count for those consecutive levels that
     568             :     //  have the "show all" flag, one following level, and the data layout dimension.
     569             : 
     570         182 :     long nTotal = 1;
     571         182 :     long nDataCount = 1;
     572         182 :     bool bWasShowAll = true;
     573         182 :     long nPos = nLevels;
     574         509 :     while ( nPos > 0 )
     575             :     {
     576         145 :         --nPos;
     577             : 
     578         145 :         if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] )
     579             :         {
     580             :             OSL_FAIL("lcl_CountMinMembers: multiple levels from one dimension not implemented");
     581           0 :             return 0;
     582             :         }
     583             : 
     584         145 :         bool bDo = false;
     585         145 :         if ( ppDim[nPos]->getIsDataLayoutDimension() )
     586             :         {
     587             :             //  data layout dim doesn't interfere with "show all" flags
     588           9 :             nDataCount = ppLevel[nPos]->GetMembersObject()->getCount();
     589           9 :             if ( nDataCount == 0 )
     590           0 :                 nDataCount = 1;
     591             :         }
     592         136 :         else if ( bWasShowAll )     // "show all" set for all following levels?
     593             :         {
     594         115 :             bDo = true;
     595         115 :             if ( !ppLevel[nPos]->getShowEmpty() )
     596             :             {
     597             :                 //  this level is counted, following ones are not
     598         115 :                 bWasShowAll = false;
     599             :             }
     600             :         }
     601         145 :         if ( bDo )
     602             :         {
     603         115 :             long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers();
     604         115 :             if ( nThisCount == 0 )
     605             :             {
     606           0 :                 nTotal = 1;         //  empty level -> start counting from here
     607             :                                     //TODO: start with visible elements in this level?
     608             :             }
     609             :             else
     610             :             {
     611         115 :                 if ( nTotal >= LONG_MAX / nThisCount )
     612           0 :                     return LONG_MAX;                        //  overflow
     613         115 :                 nTotal *= nThisCount;
     614             :             }
     615             :         }
     616             :     }
     617             : 
     618             :     //  always include data layout dim, even after restarting
     619         182 :     if ( nTotal >= LONG_MAX / nDataCount )
     620           0 :         return LONG_MAX;                        //  overflow
     621         182 :     nTotal *= nDataCount;
     622             : 
     623         182 :     return nTotal;
     624             : }
     625             : 
     626           4 : static long lcl_GetIndexFromName( const OUString& rName, const uno::Sequence<OUString>& rElements )
     627             : {
     628           4 :     long nCount = rElements.getLength();
     629           4 :     const OUString* pArray = rElements.getConstArray();
     630           4 :     for (long nPos=0; nPos<nCount; nPos++)
     631           4 :         if (pArray[nPos] == rName)
     632           4 :             return nPos;
     633             : 
     634           0 :     return -1;  // not found
     635             : }
     636             : 
     637         182 : void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow)
     638             : {
     639         182 :     const std::vector<long>& rDims = bIsRow ? maRowDims : maColDims;
     640         182 :     std::vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
     641         369 :     for (; it != itEnd; ++it)
     642             :     {
     643         187 :         ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
     644         187 :         long nHierarchy = pDim->getUsedHierarchy();
     645         187 :         if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
     646           0 :             nHierarchy = 0;
     647         187 :         ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
     648         187 :         long nCount = pLevels->getCount();
     649             : 
     650             :         //TODO: Test
     651         187 :         if (pDim->getIsDataLayoutDimension() && maDataDims.size() < 2)
     652          42 :             nCount = 0;
     653             :         //TODO: Test
     654             : 
     655         332 :         for (long j = 0; j < nCount; ++j)
     656             :         {
     657         145 :             ScDPLevel* pLevel = pLevels->getByIndex(j);
     658         145 :             pLevel->EvaluateSortOrder();
     659             : 
     660             :             // no layout flags for column fields, only for row fields
     661         145 :             pLevel->SetEnableLayout( bIsRow );
     662             : 
     663         145 :             if ( pLevel->GetAutoShow().IsEnabled )
     664           1 :                 rHasAutoShow = true;
     665             : 
     666         145 :             if (bIsRow)
     667             :             {
     668          95 :                 rInfo.aRowLevelDims.push_back(*it);
     669          95 :                 rInfo.aRowDims.push_back(pDim);
     670          95 :                 rInfo.aRowLevels.push_back(pLevel);
     671             :             }
     672             :             else
     673             :             {
     674          50 :                 rInfo.aColLevelDims.push_back(*it);
     675          50 :                 rInfo.aColDims.push_back(pDim);
     676          50 :                 rInfo.aColLevels.push_back(pLevel);
     677             :             }
     678             : 
     679         145 :             pLevel->GetMembersObject();                 // initialize for groups
     680             :         }
     681             :     }
     682         182 : }
     683             : 
     684             : namespace {
     685             : 
     686             : class CategoryDimInserter : std::unary_function<long, void>
     687             : {
     688             :     ScDPSource& mrSource;
     689             :     std::unordered_set<sal_Int32>& mrCatDims;
     690             : public:
     691         137 :     CategoryDimInserter(ScDPSource& rSource, std::unordered_set<sal_Int32>& rCatDims) :
     692             :         mrSource(rSource),
     693         137 :         mrCatDims(rCatDims) {}
     694             : 
     695         541 :     void operator() (long nDim)
     696             :     {
     697         541 :         if (!mrSource.IsDataLayoutDimension(nDim))
     698         537 :             mrCatDims.insert(nDim);
     699         541 :     }
     700             : };
     701             : 
     702             : }
     703             : 
     704         137 : void ScDPSource::GetCategoryDimensionIndices(std::unordered_set<sal_Int32>& rCatDims)
     705             : {
     706         137 :     std::unordered_set<sal_Int32> aCatDims;
     707             : 
     708         137 :     CategoryDimInserter aInserter(*this, aCatDims);
     709         137 :     std::for_each(maColDims.begin(), maColDims.end(), aInserter);
     710         137 :     std::for_each(maRowDims.begin(), maRowDims.end(), aInserter);
     711         137 :     std::for_each(maPageDims.begin(), maPageDims.end(), aInserter);
     712             : 
     713         137 :     rCatDims.swap(aCatDims);
     714         137 : }
     715             : 
     716          91 : void ScDPSource::FilterCacheByPageDimensions()
     717             : {
     718             :     // #i117661# Repeated calls to ScDPFilteredCache::filterByPageDimension
     719             :     // are invalid because rows are only hidden, never shown again. If
     720             :     // FilterCacheByPageDimensions is called again, the cache table must
     721             :     // be re-initialized. Currently, CreateRes_Impl always uses a fresh cache
     722             :     // because ScDBDocFunc::DataPilotUpdate calls InvalidateData.
     723             : 
     724          91 :     if (bPageFiltered)
     725             :     {
     726             :         SAL_WARN( "sc.core","tried to apply page field filters several times");
     727             : 
     728           0 :         pData->DisposeData();
     729           0 :         pData->CreateCacheTable();  // re-initialize the cache table
     730           0 :         bPageFiltered = false;
     731             :     }
     732             : 
     733             :     // filter table by page dimensions.
     734          91 :     vector<ScDPFilteredCache::Criterion> aCriteria;
     735          91 :     vector<long>::const_iterator it = maPageDims.begin(), itEnd = maPageDims.end();
     736         118 :     for (; it != itEnd; ++it)
     737             :     {
     738          27 :         ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
     739          27 :         long nField = pDim->GetDimension();
     740             : 
     741             :         ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)->
     742          27 :             GetLevelsObject()->getByIndex(0)->GetMembersObject();
     743             : 
     744          27 :         long nMemCount = pMems->getCount();
     745          27 :         ScDPFilteredCache::Criterion aFilter;
     746          27 :         aFilter.mnFieldIndex = static_cast<sal_Int32>(nField);
     747          27 :         aFilter.mpFilter.reset(new ScDPFilteredCache::GroupFilter);
     748             :         ScDPFilteredCache::GroupFilter* pGrpFilter =
     749          27 :             static_cast<ScDPFilteredCache::GroupFilter*>(aFilter.mpFilter.get());
     750         138 :         for (long j = 0; j < nMemCount; ++j)
     751             :         {
     752         111 :             ScDPMember* pMem = pMems->getByIndex(j);
     753         111 :             if (pMem->isVisible())
     754             :             {
     755         103 :                 ScDPItemData aData;
     756         103 :                 pMem->FillItemData(aData);
     757         103 :                 pGrpFilter->addMatchItem(aData);
     758             :             }
     759             :         }
     760          27 :         if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount))
     761             :             // there is at least one invisible item.  Add this filter criterion to the mix.
     762           4 :             aCriteria.push_back(aFilter);
     763             : 
     764          27 :         if (!pDim->HasSelectedPage())
     765          27 :             continue;
     766             : 
     767           0 :         const ScDPItemData& rData = pDim->GetSelectedData();
     768           0 :         aCriteria.push_back(ScDPFilteredCache::Criterion());
     769           0 :         ScDPFilteredCache::Criterion& r = aCriteria.back();
     770           0 :         r.mnFieldIndex = static_cast<sal_Int32>(nField);
     771           0 :         r.mpFilter.reset(new ScDPFilteredCache::SingleFilter(rData));
     772           0 :     }
     773          91 :     if (!aCriteria.empty())
     774             :     {
     775           4 :         std::unordered_set<sal_Int32> aCatDims;
     776           4 :         GetCategoryDimensionIndices(aCatDims);
     777           4 :         pData->FilterCacheTable(aCriteria, aCatDims);
     778           4 :         bPageFiltered = true;
     779          91 :     }
     780          91 : }
     781             : 
     782         255 : void ScDPSource::CreateRes_Impl()
     783             : {
     784         255 :     if (pResData)
     785         328 :         return;
     786             : 
     787          91 :     sal_uInt16 nDataOrient = GetDataLayoutOrientation();
     788          91 :     if (maDataDims.size() > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN &&
     789             :                                 nDataOrient != sheet::DataPilotFieldOrientation_ROW ) )
     790             :     {
     791             :         //  if more than one data dimension, data layout orientation must be set
     792           0 :         SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW );
     793           0 :         nDataOrient = sheet::DataPilotFieldOrientation_ROW;
     794             :     }
     795             : 
     796             :     // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and
     797             :     // eDataFunctions into a structure and use vector instead of static
     798             :     // or pointer arrays.
     799          91 :     vector<OUString> aDataNames;
     800         182 :     vector<sheet::DataPilotFieldReference> aDataRefValues;
     801         182 :     vector<ScSubTotalFunc> aDataFunctions;
     802         182 :     vector<sal_uInt16> aDataRefOrient;
     803             : 
     804         182 :     ScDPTableData::CalcInfo aInfo;
     805             : 
     806             :     //  LateInit (initialize only those rows/children that are used) can be used unless
     807             :     //  any data dimension needs reference values from column/row dimensions
     808          91 :     bool bLateInit = true;
     809             : 
     810             :     // Go through all data dimensions (i.e. fields) and build their meta data
     811             :     // so that they can be passed on to ScDPResultData instance later.
     812             :     // TODO: aggregate all of data dimension info into a structure.
     813          91 :     vector<long>::const_iterator it = maDataDims.begin(), itEnd = maDataDims.end();
     814         180 :     for (; it != itEnd; ++it)
     815             :     {
     816             :         // Get function for each data field.
     817          89 :         long nDimIndex = *it;
     818          89 :         ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex);
     819          89 :         sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction();
     820          89 :         if (eUser == sheet::GeneralFunction_AUTO)
     821             :         {
     822             :             //TODO: test for numeric data
     823          27 :             eUser = sheet::GeneralFunction_SUM;
     824             :         }
     825             : 
     826             :         // Map UNO's enum to internal enum ScSubTotalFunc.
     827          89 :         aDataFunctions.push_back(ScDPUtil::toSubTotalFunc(eUser));
     828             : 
     829             :         // Get reference field/item information.
     830          89 :         aDataRefValues.push_back(pDim->GetReferenceValue());
     831          89 :         sal_uInt16 nDataRefOrient = sheet::DataPilotFieldOrientation_HIDDEN;    // default if not used
     832          89 :         sal_Int32 eRefType = aDataRefValues.back().ReferenceType;
     833          89 :         if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
     834          87 :              eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
     835          86 :              eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE ||
     836             :              eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL )
     837             :         {
     838             :             long nColumn = lcl_GetIndexFromName(
     839           4 :                 aDataRefValues.back().ReferenceField, GetDimensionsObject()->getElementNames());
     840           4 :             if ( nColumn >= 0 )
     841             :             {
     842           4 :                 nDataRefOrient = GetOrientation(nColumn);
     843             :                 //  need fully initialized results to find reference values
     844             :                 //  (both in column or row dimensions), so updated values or
     845             :                 //  differences to 0 can be displayed even for empty results.
     846           4 :                 bLateInit = false;
     847             :             }
     848             :         }
     849             : 
     850          89 :         aDataRefOrient.push_back(nDataRefOrient);
     851             : 
     852          89 :         aDataNames.push_back(pDim->getName());
     853             : 
     854             :         //TODO: modify user visible strings as in ScDPResultData::GetMeasureString instead!
     855             : 
     856          89 :         aDataNames.back() = ScDPUtil::getSourceDimensionName(aDataNames.back());
     857             : 
     858             :         //TODO: if the name is overridden by user, a flag must be set
     859             :         //TODO: so the user defined name replaces the function string and field name.
     860             : 
     861             :         //TODO: the complete name (function and field) must be stored at the dimension
     862             : 
     863          89 :         long nSource = pDim->GetSourceDim();
     864          89 :         if (nSource >= 0)
     865           5 :             aInfo.aDataSrcCols.push_back(nSource);
     866             :         else
     867          84 :             aInfo.aDataSrcCols.push_back(nDimIndex);
     868             :     }
     869             : 
     870          91 :     pResData = new ScDPResultData(*this);
     871          91 :     pResData->SetMeasureData(aDataFunctions, aDataRefValues, aDataRefOrient, aDataNames);
     872          91 :     pResData->SetDataLayoutOrientation(nDataOrient);
     873          91 :     pResData->SetLateInit( bLateInit );
     874             : 
     875          91 :     bool bHasAutoShow = false;
     876             : 
     877         182 :     ScDPInitState aInitState;
     878             : 
     879             :     // Page field selections restrict the members shown in related fields
     880             :     // (both in column and row fields). aInitState is filled with the page
     881             :     // field selections, they are kept across the data iterator loop.
     882             : 
     883         118 :     for (it = maPageDims.begin(), itEnd = maPageDims.end(); it != itEnd; ++it)
     884             :     {
     885          27 :         ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
     886          27 :         if ( pDim->HasSelectedPage() )
     887           0 :             aInitState.AddMember(*it, GetMemberId(*it, pDim->GetSelectedData()));
     888             :     }
     889             : 
     890             :     // Show grand total columns only when the option is set *and* there is at
     891             :     // least one column field.  Same for the grand total rows.
     892          91 :     sal_uInt16 nDataLayoutOrient = GetDataLayoutOrientation();
     893          91 :     long nColDimCount2 = maColDims.size() - (nDataLayoutOrient == sheet::DataPilotFieldOrientation_COLUMN ? 1 : 0);
     894          91 :     long nRowDimCount2 = maRowDims.size() - (nDataLayoutOrient == sheet::DataPilotFieldOrientation_ROW ? 1 : 0);
     895          91 :     bool bShowColGrand = bColumnGrand && nColDimCount2 > 0;
     896          91 :     bool bShowRowGrand = bRowGrand && nRowDimCount2 > 0;
     897          91 :     pColResRoot = new ScDPResultMember(pResData, bShowColGrand);
     898          91 :     pRowResRoot = new ScDPResultMember(pResData, bShowRowGrand);
     899             : 
     900          91 :     FillCalcInfo(false, aInfo, bHasAutoShow);
     901          91 :     long nColLevelCount = aInfo.aColLevels.size();
     902             : 
     903          91 :     pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
     904          91 :     pColResRoot->SetHasElements();
     905             : 
     906          91 :     FillCalcInfo(true, aInfo, bHasAutoShow);
     907          91 :     long nRowLevelCount = aInfo.aRowLevels.size();
     908             : 
     909          91 :     if ( nRowLevelCount > 0 )
     910             :     {
     911             :         // disable layout flags for the innermost row field (level)
     912          76 :         aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( false );
     913             :     }
     914             : 
     915          91 :     pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
     916          91 :     pRowResRoot->SetHasElements();
     917             : 
     918             :     // initialize members object also for all page dimensions (needed for numeric groups)
     919         118 :     for (it = maPageDims.begin(), itEnd = maPageDims.end(); it != itEnd; ++it)
     920             :     {
     921          27 :         ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
     922          27 :         long nHierarchy = pDim->getUsedHierarchy();
     923          27 :         if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
     924           0 :             nHierarchy = 0;
     925             : 
     926          27 :         ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
     927          27 :         long nCount = pLevels->getCount();
     928          54 :         for (long j=0; j<nCount; j++)
     929          27 :             pLevels->getByIndex(j)->GetMembersObject();             // initialize for groups
     930             :     }
     931             : 
     932             :     //  pre-check: calculate minimum number of result columns / rows from
     933             :     //  levels that have the "show all" flag set
     934             : 
     935          91 :     long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount );
     936          91 :     long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount );
     937             : 
     938          91 :     if ( nMinColMembers > MAXCOLCOUNT/*SC_MINCOUNT_LIMIT*/ || nMinRowMembers > SC_MINCOUNT_LIMIT )
     939             :     {
     940             :         //  resulting table is too big -> abort before calculating
     941             :         //  (this relies on late init, so no members are allocated in InitFrom above)
     942             : 
     943           0 :         bResultOverflow = true;
     944           0 :         return;
     945             :     }
     946             : 
     947          91 :     FilterCacheByPageDimensions();
     948             : 
     949          91 :     aInfo.aPageDims.reserve(maPageDims.size());
     950         118 :     for (it = maPageDims.begin(), itEnd = maPageDims.end(); it != itEnd; ++it)
     951          27 :         aInfo.aPageDims.push_back(*it);
     952             : 
     953          91 :     aInfo.pInitState = &aInitState;
     954          91 :     aInfo.pColRoot   = pColResRoot;
     955          91 :     aInfo.pRowRoot   = pRowResRoot;
     956          91 :     pData->CalcResults(aInfo, false);
     957             : 
     958          91 :     pColResRoot->CheckShowEmpty();
     959          91 :     pRowResRoot->CheckShowEmpty();
     960             : 
     961             :     //  With all data processed, calculate the final results:
     962             : 
     963             :     //  UpdateDataResults calculates all original results from the collected values,
     964             :     //  and stores them as reference values if needed.
     965          91 :     pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
     966             : 
     967          91 :     if ( bHasAutoShow )     // do the double calculation only if AutoShow is used
     968             :     {
     969             :         //  Find the desired members and set bAutoHidden flag for the others
     970           1 :         pRowResRoot->DoAutoShow( pColResRoot );
     971             : 
     972             :         //  Reset all results to empty, so they can be built again with data for the
     973             :         //  desired members only.
     974           1 :         pColResRoot->ResetResults();
     975           1 :         pRowResRoot->ResetResults();
     976           1 :         pData->CalcResults(aInfo, true);
     977             : 
     978             :         //  Call UpdateDataResults again, with the new (limited) values.
     979           1 :         pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
     980             :     }
     981             : 
     982             :     //  SortMembers does the sorting by a result dimension, using the original results,
     983             :     //  but not running totals etc.
     984          91 :     pRowResRoot->SortMembers( pColResRoot );
     985             : 
     986             :     //  UpdateRunningTotals calculates running totals along column/row dimensions,
     987             :     //  differences from other members (named or relative), and column/row percentages
     988             :     //  or index values.
     989             :     //  Running totals and relative differences need to be done using the sorted values.
     990             :     //  Column/row percentages and index values must be done after sorting, because the
     991             :     //  results may no longer be in the right order (row total for percentage of row is
     992             :     //  always 1).
     993         182 :     ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot );
     994         182 :     ScDPRowTotals aTotals;
     995         182 :     pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals );
     996             : }
     997             : 
     998         152 : void ScDPSource::FillLevelList( sal_uInt16 nOrientation, std::vector<ScDPLevel*> &rList )
     999             : {
    1000         152 :     rList.clear();
    1001             : 
    1002         152 :     std::vector<long>* pDimIndex = NULL;
    1003         152 :     switch (nOrientation)
    1004             :     {
    1005             :         case sheet::DataPilotFieldOrientation_COLUMN:
    1006          76 :             pDimIndex = &maColDims;
    1007          76 :             break;
    1008             :         case sheet::DataPilotFieldOrientation_ROW:
    1009          76 :             pDimIndex = &maRowDims;
    1010          76 :             break;
    1011             :         case sheet::DataPilotFieldOrientation_DATA:
    1012           0 :             pDimIndex = &maDataDims;
    1013           0 :             break;
    1014             :         case sheet::DataPilotFieldOrientation_PAGE:
    1015           0 :             pDimIndex = &maPageDims;
    1016           0 :             break;
    1017             :         default:
    1018             :             OSL_FAIL( "ScDPSource::FillLevelList: unexpected orientation" );
    1019           0 :             break;
    1020             :     }
    1021         152 :     if (!pDimIndex)
    1022             :     {
    1023             :         OSL_FAIL("invalid orientation");
    1024         152 :         return;
    1025             :     }
    1026             : 
    1027         152 :     ScDPDimensions* pDims = GetDimensionsObject();
    1028         152 :     std::vector<long>::const_iterator it = pDimIndex->begin(), itEnd = pDimIndex->end();
    1029         331 :     for (; it != itEnd; ++it)
    1030             :     {
    1031         179 :         ScDPDimension* pDim = pDims->getByIndex(*it);
    1032             :         OSL_ENSURE( pDim->getOrientation() == nOrientation, "orientations are wrong" );
    1033             : 
    1034         179 :         ScDPHierarchies* pHiers = pDim->GetHierarchiesObject();
    1035         179 :         long nHierarchy = pDim->getUsedHierarchy();
    1036         179 :         if ( nHierarchy >= pHiers->getCount() )
    1037           0 :             nHierarchy = 0;
    1038         179 :         ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy);
    1039         179 :         ScDPLevels* pLevels = pHier->GetLevelsObject();
    1040         179 :         long nLevCount = pLevels->getCount();
    1041         358 :         for (long nLev=0; nLev<nLevCount; nLev++)
    1042             :         {
    1043         179 :             ScDPLevel* pLevel = pLevels->getByIndex(nLev);
    1044         179 :             rList.push_back(pLevel);
    1045             :         }
    1046             :     }
    1047             : }
    1048             : 
    1049         228 : void ScDPSource::FillMemberResults()
    1050             : {
    1051         228 :     if ( !pColResults && !pRowResults )
    1052             :     {
    1053          76 :         CreateRes_Impl();
    1054             : 
    1055          76 :         if ( bResultOverflow )      // set in CreateRes_Impl
    1056             :         {
    1057             :             //  no results available -> abort (leave empty)
    1058             :             //  exception is thrown in ScDPSource::getResults
    1059         228 :             return;
    1060             :         }
    1061             : 
    1062          76 :         FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList );
    1063          76 :         long nColLevelCount = aColLevelList.size();
    1064          76 :         if (nColLevelCount)
    1065             :         {
    1066          45 :             long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure());
    1067          45 :             pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount];
    1068          94 :             for (long i=0; i<nColLevelCount; i++)
    1069          49 :                 pColResults[i].realloc(nColDimSize);
    1070             : 
    1071          45 :             long nPos = 0;
    1072             :             pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(),
    1073          45 :                                             true, NULL, NULL );
    1074             :         }
    1075             : 
    1076          76 :         FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList );
    1077          76 :         long nRowLevelCount = aRowLevelList.size();
    1078          76 :         if (nRowLevelCount)
    1079             :         {
    1080          74 :             long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
    1081          74 :             pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount];
    1082         204 :             for (long i=0; i<nRowLevelCount; i++)
    1083         130 :                 pRowResults[i].realloc(nRowDimSize);
    1084             : 
    1085          74 :             long nPos = 0;
    1086             :             pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(),
    1087          74 :                                             true, NULL, NULL );
    1088             :         }
    1089             :     }
    1090             : }
    1091             : 
    1092         228 : const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel )
    1093             : {
    1094         228 :     FillMemberResults();
    1095             : 
    1096         228 :     long i = 0;
    1097         228 :     long nColCount = aColLevelList.size();
    1098         320 :     for (i=0; i<nColCount; i++)
    1099             :     {
    1100         144 :         ScDPLevel* pColLevel = aColLevelList[i];
    1101         144 :         if ( pColLevel == pLevel )
    1102          52 :             return pColResults+i;
    1103             :     }
    1104         176 :     long nRowCount = aRowLevelList.size();
    1105         294 :     for (i=0; i<nRowCount; i++)
    1106             :     {
    1107         294 :         ScDPLevel* pRowLevel = aRowLevelList[i];
    1108         294 :         if ( pRowLevel == pLevel )
    1109         176 :             return pRowResults+i;
    1110             :     }
    1111           0 :     return NULL;
    1112             : }
    1113             : 
    1114             : // XPropertySet
    1115             : 
    1116           0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo()
    1117             :                                                         throw(uno::RuntimeException, std::exception)
    1118             : {
    1119           0 :     SolarMutexGuard aGuard;
    1120             :     using beans::PropertyAttribute::READONLY;
    1121             : 
    1122             :     static const SfxItemPropertyMapEntry aDPSourceMap_Impl[] =
    1123             :     {
    1124           0 :         { OUString(SC_UNO_DP_COLGRAND), 0,  cppu::UnoType<bool>::get(),              0, 0 },
    1125           0 :         { OUString(SC_UNO_DP_DATADESC), 0,  cppu::UnoType<OUString>::get(),    beans::PropertyAttribute::READONLY, 0 },
    1126           0 :         { OUString(SC_UNO_DP_IGNOREEMPTY), 0,  cppu::UnoType<bool>::get(),              0, 0 },     // for sheet data only
    1127           0 :         { OUString(SC_UNO_DP_REPEATEMPTY), 0,  cppu::UnoType<bool>::get(),              0, 0 },     // for sheet data only
    1128           0 :         { OUString(SC_UNO_DP_ROWGRAND), 0,  cppu::UnoType<bool>::get(),              0, 0 },
    1129           0 :         { OUString(SC_UNO_DP_ROWFIELDCOUNT),    0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
    1130           0 :         { OUString(SC_UNO_DP_COLUMNFIELDCOUNT), 0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
    1131           0 :         { OUString(SC_UNO_DP_DATAFIELDCOUNT),   0, cppu::UnoType<sal_Int32>::get(), READONLY, 0 },
    1132           0 :         { OUString(SC_UNO_DP_GRANDTOTAL_NAME),  0, cppu::UnoType<OUString>::get(), 0, 0 },
    1133             :         { OUString(), 0, css::uno::Type(), 0, 0 }
    1134           0 :     };
    1135             :     static uno::Reference<beans::XPropertySetInfo> aRef =
    1136           0 :         new SfxItemPropertySetInfo( aDPSourceMap_Impl );
    1137           0 :     return aRef;
    1138             : }
    1139             : 
    1140         522 : void SAL_CALL ScDPSource::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
    1141             :                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
    1142             :                         lang::IllegalArgumentException, lang::WrappedTargetException,
    1143             :                         uno::RuntimeException, std::exception)
    1144             : {
    1145         522 :     if (aPropertyName == SC_UNO_DP_COLGRAND)
    1146         131 :         bColumnGrand = lcl_GetBoolFromAny(aValue);
    1147         391 :     else if (aPropertyName == SC_UNO_DP_ROWGRAND)
    1148         131 :         bRowGrand = lcl_GetBoolFromAny(aValue);
    1149         260 :     else if (aPropertyName == SC_UNO_DP_IGNOREEMPTY)
    1150         130 :         setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) );
    1151         130 :     else if (aPropertyName == SC_UNO_DP_REPEATEMPTY)
    1152         130 :         setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) );
    1153           0 :     else if (aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME)
    1154             :     {
    1155           0 :         OUString aName;
    1156           0 :         if (aValue >>= aName)
    1157           0 :             mpGrandTotalName.reset(new OUString(aName));
    1158             :     }
    1159             :     else
    1160             :     {
    1161             :         OSL_FAIL("unknown property");
    1162             :         //TODO: THROW( UnknownPropertyException() );
    1163             :     }
    1164         522 : }
    1165             : 
    1166        1263 : uno::Any SAL_CALL ScDPSource::getPropertyValue( const OUString& aPropertyName )
    1167             :                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
    1168             :                         uno::RuntimeException, std::exception)
    1169             : {
    1170        1263 :     uno::Any aRet;
    1171        1263 :     if ( aPropertyName == SC_UNO_DP_COLGRAND )
    1172         327 :         lcl_SetBoolInAny(aRet, bColumnGrand);
    1173         936 :     else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
    1174         327 :         lcl_SetBoolInAny(aRet, bRowGrand);
    1175         609 :     else if ( aPropertyName == SC_UNO_DP_IGNOREEMPTY )
    1176           0 :         lcl_SetBoolInAny(aRet, bIgnoreEmptyRows);
    1177         609 :     else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
    1178           0 :         lcl_SetBoolInAny(aRet, bRepeatIfEmpty);
    1179         609 :     else if ( aPropertyName == SC_UNO_DP_DATADESC )             // read-only
    1180          88 :         aRet <<= getDataDescription();
    1181         521 :     else if ( aPropertyName == SC_UNO_DP_ROWFIELDCOUNT )        // read-only
    1182           0 :         aRet <<= static_cast<sal_Int32>(maRowDims.size());
    1183         521 :     else if ( aPropertyName == SC_UNO_DP_COLUMNFIELDCOUNT )     // read-only
    1184           0 :         aRet <<= static_cast<sal_Int32>(maColDims.size());
    1185         521 :     else if ( aPropertyName == SC_UNO_DP_DATAFIELDCOUNT )       // read-only
    1186         521 :         aRet <<= static_cast<sal_Int32>(maDataDims.size());
    1187           0 :     else if (aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME)
    1188             :     {
    1189           0 :         if (mpGrandTotalName.get())
    1190           0 :             aRet <<= *mpGrandTotalName;
    1191             :     }
    1192             :     else
    1193             :     {
    1194             :         OSL_FAIL("unknown property");
    1195             :         //TODO: THROW( UnknownPropertyException() );
    1196             :     }
    1197        1263 :     return aRet;
    1198             : }
    1199             : 
    1200             : #if DEBUG_PIVOT_TABLE
    1201             : void ScDPSource::DumpResults() const
    1202             : {
    1203             :     std::cout << "+++++ column root" << std::endl;
    1204             :     pColResRoot->Dump(1);
    1205             :     std::cout << "+++++ row root" << std::endl;
    1206             :     pRowResRoot->Dump(1);
    1207             : }
    1208             : #endif
    1209             : 
    1210           0 : SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource )
    1211             : 
    1212         131 : ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) :
    1213             :     pSource( pSrc ),
    1214         131 :     ppDims( NULL )
    1215             : {
    1216             :     //TODO: hold pSource
    1217             : 
    1218             :     // include data layout dimension and duplicated dimensions
    1219         131 :     nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
    1220         131 : }
    1221             : 
    1222         387 : ScDPDimensions::~ScDPDimensions()
    1223             : {
    1224             :     //TODO: release pSource
    1225             : 
    1226         129 :     if (ppDims)
    1227             :     {
    1228         724 :         for (long i=0; i<nDimCount; i++)
    1229         595 :             if ( ppDims[i] )
    1230         595 :                 ppDims[i]->release();           // ref-counted
    1231         129 :         delete[] ppDims;
    1232             :     }
    1233         258 : }
    1234             : 
    1235           5 : void ScDPDimensions::CountChanged()
    1236             : {
    1237             :     // include data layout dimension and duplicated dimensions
    1238           5 :     long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
    1239           5 :     if ( ppDims )
    1240             :     {
    1241             :         long i;
    1242           5 :         long nCopy = std::min( nNewCount, nDimCount );
    1243           5 :         ScDPDimension** ppNew = new ScDPDimension*[nNewCount];
    1244             : 
    1245          20 :         for (i=0; i<nCopy; i++)             // copy existing dims
    1246          15 :             ppNew[i] = ppDims[i];
    1247          10 :         for (i=nCopy; i<nNewCount; i++)     // clear additional pointers
    1248           5 :             ppNew[i] = NULL;
    1249           5 :         for (i=nCopy; i<nDimCount; i++)     // delete old dims if count is decreased
    1250           0 :             if ( ppDims[i] )
    1251           0 :                 ppDims[i]->release();       // ref-counted
    1252             : 
    1253           5 :         delete[] ppDims;
    1254           5 :         ppDims = ppNew;
    1255             :     }
    1256           5 :     nDimCount = nNewCount;
    1257           5 : }
    1258             : 
    1259             : // very simple XNameAccess implementation using getCount/getByIndex
    1260             : 
    1261        5746 : uno::Any SAL_CALL ScDPDimensions::getByName( const OUString& aName )
    1262             :             throw(container::NoSuchElementException,
    1263             :                     lang::WrappedTargetException, uno::RuntimeException, std::exception)
    1264             : {
    1265        5746 :     long nCount = getCount();
    1266       17831 :     for (long i=0; i<nCount; i++)
    1267       17831 :         if ( getByIndex(i)->getName() == aName )
    1268             :         {
    1269        5746 :             uno::Reference<container::XNamed> xNamed = getByIndex(i);
    1270       11492 :             uno::Any aRet;
    1271        5746 :             aRet <<= xNamed;
    1272       17238 :             return aRet;
    1273             :         }
    1274             : 
    1275           0 :     throw container::NoSuchElementException();
    1276             : //    return uno::Any();
    1277             : }
    1278             : 
    1279        1187 : uno::Sequence<OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException, std::exception)
    1280             : {
    1281        1187 :     long nCount = getCount();
    1282        1187 :     uno::Sequence<OUString> aSeq(nCount);
    1283        1187 :     OUString* pArr = aSeq.getArray();
    1284        7989 :     for (long i=0; i<nCount; i++)
    1285        6802 :         pArr[i] = getByIndex(i)->getName();
    1286        1187 :     return aSeq;
    1287             : }
    1288             : 
    1289           0 : sal_Bool SAL_CALL ScDPDimensions::hasByName( const OUString& aName ) throw(uno::RuntimeException, std::exception)
    1290             : {
    1291           0 :     long nCount = getCount();
    1292           0 :     for (long i=0; i<nCount; i++)
    1293           0 :         if ( getByIndex(i)->getName() == aName )
    1294           0 :             return sal_True;
    1295           0 :     return false;
    1296             : }
    1297             : 
    1298           0 : uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException, std::exception)
    1299             : {
    1300           0 :     return cppu::UnoType<container::XNamed>::get();
    1301             : }
    1302             : 
    1303           0 : sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException, std::exception)
    1304             : {
    1305           0 :     return ( getCount() > 0 );
    1306             : }
    1307             : 
    1308             : // end of XNameAccess implementation
    1309             : 
    1310        6980 : long ScDPDimensions::getCount() const
    1311             : {
    1312             :     //  in tabular data, every column of source data is a dimension
    1313             : 
    1314        6980 :     return nDimCount;
    1315             : }
    1316             : 
    1317       34297 : ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const
    1318             : {
    1319       34297 :     if ( nIndex >= 0 && nIndex < nDimCount )
    1320             :     {
    1321       34297 :         if ( !ppDims )
    1322             :         {
    1323         131 :             const_cast<ScDPDimensions*>(this)->ppDims = new ScDPDimension*[nDimCount];
    1324         729 :             for (long i=0; i<nDimCount; i++)
    1325         598 :                 ppDims[i] = NULL;
    1326             :         }
    1327       34297 :         if ( !ppDims[nIndex] )
    1328             :         {
    1329         603 :             ppDims[nIndex] = new ScDPDimension( pSource, nIndex );
    1330         603 :             ppDims[nIndex]->acquire();      // ref-counted
    1331             :         }
    1332             : 
    1333       34297 :         return ppDims[nIndex];
    1334             :     }
    1335             : 
    1336           0 :     return NULL;    //TODO: exception?
    1337             : }
    1338             : 
    1339         603 : ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) :
    1340             :     pSource( pSrc ),
    1341             :     nDim( nD ),
    1342             :     pHierarchies( NULL ),
    1343             :     nUsedHier( 0 ),
    1344             :     nFunction( SUBTOTAL_FUNC_SUM ),     // sum is default
    1345             :     mpLayoutName(NULL),
    1346             :     mpSubtotalName(NULL),
    1347             :     nSourceDim( -1 ),
    1348             :     bHasSelectedPage( false ),
    1349             :     pSelectedData( NULL ),
    1350         603 :     mbHasHiddenMember(false)
    1351             : {
    1352             :     //TODO: hold pSource
    1353         603 : }
    1354             : 
    1355        1785 : ScDPDimension::~ScDPDimension()
    1356             : {
    1357             :     //TODO: release pSource
    1358             : 
    1359         595 :     if ( pHierarchies )
    1360         333 :         pHierarchies->release();    // ref-counted
    1361             : 
    1362         595 :     delete pSelectedData;
    1363        1190 : }
    1364             : 
    1365        2486 : ScDPHierarchies* ScDPDimension::GetHierarchiesObject()
    1366             : {
    1367        2486 :     if (!pHierarchies)
    1368             :     {
    1369         341 :         pHierarchies = new ScDPHierarchies( pSource, nDim );
    1370         341 :         pHierarchies->acquire();        // ref-counted
    1371             :     }
    1372        2486 :     return pHierarchies;
    1373             : }
    1374             : 
    1375         386 : const OUString* ScDPDimension::GetLayoutName() const
    1376             : {
    1377         386 :     return mpLayoutName.get();
    1378             : }
    1379             : 
    1380           0 : const OUString* ScDPDimension::GetSubtotalName() const
    1381             : {
    1382           0 :     return mpSubtotalName.get();
    1383             : }
    1384             : 
    1385         736 : uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies()
    1386             :                                                     throw(uno::RuntimeException, std::exception)
    1387             : {
    1388         736 :     return GetHierarchiesObject();
    1389             : }
    1390             : 
    1391       28117 : OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException, std::exception)
    1392             : {
    1393       28117 :     if (!aName.isEmpty())
    1394          46 :         return aName;
    1395             :     else
    1396       28071 :         return pSource->GetData()->getDimensionName( nDim );
    1397             : }
    1398             : 
    1399           5 : void SAL_CALL ScDPDimension::setName( const OUString& rNewName ) throw(uno::RuntimeException, std::exception)
    1400             : {
    1401             :     //  used after cloning
    1402           5 :     aName = rNewName;
    1403           5 : }
    1404             : 
    1405        3108 : sal_uInt16 ScDPDimension::getOrientation() const
    1406             : {
    1407        3108 :     return pSource->GetOrientation( nDim );
    1408             : }
    1409             : 
    1410         935 : void ScDPDimension::setOrientation(sal_uInt16 nNew)
    1411             : {
    1412         935 :     pSource->SetOrientation( nDim, nNew );
    1413         935 : }
    1414             : 
    1415         452 : long ScDPDimension::getPosition() const
    1416             : {
    1417         452 :     return pSource->GetPosition( nDim );
    1418             : }
    1419             : 
    1420        3450 : bool ScDPDimension::getIsDataLayoutDimension() const
    1421             : {
    1422        3450 :     return pSource->GetData()->getIsDataLayoutDimension( nDim );
    1423             : }
    1424             : 
    1425         337 : void ScDPDimension::setFunction(sal_uInt16 nNew)
    1426             : {
    1427         337 :     nFunction = nNew;
    1428         337 : }
    1429             : 
    1430           5 : ScDPDimension* ScDPDimension::CreateCloneObject()
    1431             : {
    1432             :     OSL_ENSURE( nSourceDim < 0, "recursive duplicate - not implemented" );
    1433             : 
    1434             :     //TODO: set new name here, or temporary name ???
    1435           5 :     OUString aNewName = aName;
    1436             : 
    1437           5 :     ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName );
    1438             : 
    1439           5 :     pNew->aName = aNewName;             //TODO: here or in source?
    1440           5 :     pNew->nSourceDim = nDim;            //TODO: recursive?
    1441             : 
    1442           5 :     return pNew;
    1443             : }
    1444             : 
    1445           5 : uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException, std::exception)
    1446             : {
    1447           5 :     return CreateCloneObject();
    1448             : }
    1449             : 
    1450           0 : const ScDPItemData& ScDPDimension::GetSelectedData()
    1451             : {
    1452           0 :     if ( !pSelectedData )
    1453             :     {
    1454             :         // find the named member to initialize pSelectedData from it, with name and value
    1455             : 
    1456           0 :         long nLevel = 0;
    1457             : 
    1458           0 :         long nHierarchy = getUsedHierarchy();
    1459           0 :         if ( nHierarchy >= GetHierarchiesObject()->getCount() )
    1460           0 :             nHierarchy = 0;
    1461           0 :         ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
    1462           0 :         long nLevCount = pLevels->getCount();
    1463           0 :         if ( nLevel < nLevCount )
    1464             :         {
    1465           0 :             ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject();
    1466             : 
    1467             :             //TODO: merge with ScDPMembers::getByName
    1468           0 :             long nCount = pMembers->getCount();
    1469           0 :             for (long i=0; i<nCount && !pSelectedData; i++)
    1470             :             {
    1471           0 :                 ScDPMember* pMember = pMembers->getByIndex(i);
    1472           0 :                 if (aSelectedPage.equals(pMember->GetNameStr()))
    1473             :                 {
    1474           0 :                     pSelectedData = new ScDPItemData();
    1475           0 :                     pMember->FillItemData( *pSelectedData );
    1476             :                 }
    1477             :             }
    1478             :         }
    1479             : 
    1480           0 :         if ( !pSelectedData )
    1481           0 :             pSelectedData = new ScDPItemData(aSelectedPage);      // default - name only
    1482             :     }
    1483             : 
    1484           0 :     return *pSelectedData;
    1485             : }
    1486             : 
    1487             : // XPropertySet
    1488             : 
    1489           0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
    1490             :                                                         throw(uno::RuntimeException, std::exception)
    1491             : {
    1492           0 :     SolarMutexGuard aGuard;
    1493             : 
    1494             :     static const SfxItemPropertyMapEntry aDPDimensionMap_Impl[] =
    1495             :     {
    1496           0 :         { OUString(SC_UNO_DP_FILTER),   0,  cppu::UnoType<uno::Sequence<sheet::TableFilterField>>::get(), 0, 0 },
    1497           0 :         { OUString(SC_UNO_DP_FLAGS),    0,  cppu::UnoType<sal_Int32>::get(),                beans::PropertyAttribute::READONLY, 0 },
    1498           0 :         { OUString(SC_UNO_DP_FUNCTION), 0,  cppu::UnoType<sheet::GeneralFunction>::get(),   0, 0 },
    1499           0 :         { OUString(SC_UNO_DP_ISDATALAYOUT), 0,  cppu::UnoType<bool>::get(),                      beans::PropertyAttribute::READONLY, 0 },
    1500           0 :         { OUString(SC_UNO_DP_NUMBERFO), 0,  cppu::UnoType<sal_Int32>::get(),                beans::PropertyAttribute::READONLY, 0 },
    1501           0 :         { OUString(SC_UNO_DP_ORIENTATION), 0,  cppu::UnoType<sheet::DataPilotFieldOrientation>::get(), 0, 0 },
    1502           0 :         { OUString(SC_UNO_DP_ORIGINAL), 0,  cppu::UnoType<container::XNamed>::get(), beans::PropertyAttribute::READONLY, 0 },
    1503           0 :         { OUString(SC_UNO_DP_ORIGINAL_POS), 0, cppu::UnoType<sal_Int32>::get(),             0, 0 },
    1504           0 :         { OUString(SC_UNO_DP_POSITION), 0,  cppu::UnoType<sal_Int32>::get(),                0, 0 },
    1505           0 :         { OUString(SC_UNO_DP_REFVALUE), 0,  cppu::UnoType<sheet::DataPilotFieldReference>::get(), 0, 0 },
    1506           0 :         { OUString(SC_UNO_DP_USEDHIERARCHY), 0,  cppu::UnoType<sal_Int32>::get(),                0, 0 },
    1507           0 :         { OUString(SC_UNO_DP_LAYOUTNAME), 0, cppu::UnoType<OUString>::get(), 0, 0 },
    1508           0 :         { OUString(SC_UNO_DP_FIELD_SUBTOTALNAME), 0, cppu::UnoType<OUString>::get(), 0, 0 },
    1509           0 :         { OUString(SC_UNO_DP_HAS_HIDDEN_MEMBER), 0, cppu::UnoType<bool>::get(), 0, 0 },
    1510             :         { OUString(), 0, css::uno::Type(), 0, 0 }
    1511           0 :     };
    1512             :     static uno::Reference<beans::XPropertySetInfo> aRef =
    1513           0 :         new SfxItemPropertySetInfo( aDPDimensionMap_Impl );
    1514           0 :     return aRef;
    1515             : }
    1516             : 
    1517        1764 : void SAL_CALL ScDPDimension::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
    1518             :                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
    1519             :                         lang::IllegalArgumentException, lang::WrappedTargetException,
    1520             :                         uno::RuntimeException, std::exception)
    1521             : {
    1522        1764 :     if ( aPropertyName == SC_UNO_DP_USEDHIERARCHY )
    1523             :     {
    1524             :         // #i52547# don't use the incomplete date hierarchy implementation - ignore the call
    1525             :     }
    1526        1618 :     else if ( aPropertyName == SC_UNO_DP_ORIENTATION )
    1527             :     {
    1528             :         sheet::DataPilotFieldOrientation eEnum;
    1529         935 :         if (aValue >>= eEnum)
    1530         935 :             setOrientation( sal::static_int_cast<sal_uInt16>(eEnum) );
    1531             :     }
    1532         683 :     else if ( aPropertyName == SC_UNO_DP_FUNCTION )
    1533             :     {
    1534             :         sheet::GeneralFunction eEnum;
    1535         337 :         if (aValue >>= eEnum)
    1536         337 :             setFunction( sal::static_int_cast<sal_uInt16>(eEnum) );
    1537             :     }
    1538         346 :     else if ( aPropertyName == SC_UNO_DP_REFVALUE )
    1539           7 :         aValue >>= aReferenceValue;
    1540         339 :     else if ( aPropertyName == SC_UNO_DP_FILTER )
    1541             :     {
    1542           0 :         bool bDone = false;
    1543           0 :         uno::Sequence<sheet::TableFilterField> aSeq;
    1544           0 :         if (aValue >>= aSeq)
    1545             :         {
    1546           0 :             sal_Int32 nLength = aSeq.getLength();
    1547           0 :             if ( nLength == 0 )
    1548             :             {
    1549           0 :                 aSelectedPage.clear();
    1550           0 :                 bHasSelectedPage = false;
    1551           0 :                 bDone = true;
    1552             :             }
    1553           0 :             else if ( nLength == 1 )
    1554             :             {
    1555           0 :                 const sheet::TableFilterField& rField = aSeq[0];
    1556           0 :                 if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric )
    1557             :                 {
    1558           0 :                     aSelectedPage = rField.StringValue;
    1559           0 :                     bHasSelectedPage = true;
    1560           0 :                     bDone = true;
    1561             :                 }
    1562             :             }
    1563             :         }
    1564           0 :         if ( !bDone )
    1565             :         {
    1566             :             OSL_FAIL("Filter property is not a single string");
    1567           0 :             throw lang::IllegalArgumentException();
    1568             :         }
    1569           0 :         DELETEZ( pSelectedData );       // invalid after changing aSelectedPage
    1570             :     }
    1571         339 :     else if (aPropertyName == SC_UNO_DP_LAYOUTNAME)
    1572             :     {
    1573           2 :         OUString aTmpName;
    1574           2 :         if (aValue >>= aTmpName)
    1575           2 :             mpLayoutName.reset(new OUString(aTmpName));
    1576             :     }
    1577         337 :     else if (aPropertyName == SC_UNO_DP_FIELD_SUBTOTALNAME)
    1578             :     {
    1579           0 :         OUString aTmpName;
    1580           0 :         if (aValue >>= aTmpName)
    1581           0 :             mpSubtotalName.reset(new OUString(aTmpName));
    1582             :     }
    1583         337 :     else if (aPropertyName == SC_UNO_DP_HAS_HIDDEN_MEMBER)
    1584             :     {
    1585         337 :         bool b = false;
    1586         337 :         aValue >>= b;
    1587         337 :         mbHasHiddenMember = b;
    1588             :     }
    1589             :     else
    1590             :     {
    1591             :         OSL_FAIL("unknown property");
    1592             :         //TODO: THROW( UnknownPropertyException() );
    1593             :     }
    1594        1764 : }
    1595             : 
    1596        9454 : uno::Any SAL_CALL ScDPDimension::getPropertyValue( const OUString& aPropertyName )
    1597             :                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
    1598             :                         uno::RuntimeException, std::exception)
    1599             : {
    1600        9454 :     uno::Any aRet;
    1601        9454 :     if ( aPropertyName == SC_UNO_DP_POSITION )
    1602         452 :         aRet <<= (sal_Int32) getPosition();
    1603        9002 :     else if ( aPropertyName == SC_UNO_DP_USEDHIERARCHY )
    1604         396 :         aRet <<= (sal_Int32) getUsedHierarchy();
    1605        8606 :     else if ( aPropertyName == SC_UNO_DP_ORIENTATION )
    1606             :     {
    1607        3108 :         sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation();
    1608        3108 :         aRet <<= eVal;
    1609             :     }
    1610        5498 :     else if ( aPropertyName == SC_UNO_DP_FUNCTION )
    1611             :     {
    1612         346 :         sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction();
    1613         346 :         aRet <<= eVal;
    1614             :     }
    1615        5152 :     else if ( aPropertyName == SC_UNO_DP_REFVALUE )
    1616           0 :         aRet <<= aReferenceValue;
    1617        5152 :     else if ( aPropertyName == SC_UNO_DP_ISDATALAYOUT )                 // read-only properties
    1618        2917 :         lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() );
    1619        2235 :     else if ( aPropertyName == SC_UNO_DP_NUMBERFO )
    1620             :     {
    1621         618 :         sal_Int32 nFormat = 0;
    1622         618 :         sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction();
    1623             :         // #i63745# don't use source format for "count"
    1624         618 :         if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS )
    1625         608 :             nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim );
    1626             : 
    1627         618 :         switch ( aReferenceValue.ReferenceType )
    1628             :         {
    1629             :         case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
    1630             :         case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
    1631             :         case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
    1632             :         case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
    1633             :         case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
    1634           6 :             nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_PERCENT_DEC2 );
    1635           6 :             break;
    1636             :         case sheet::DataPilotFieldReferenceType::INDEX:
    1637           0 :             nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_NUMBER_SYSTEM );
    1638           0 :             break;
    1639             :         default:
    1640         612 :             break;
    1641             :         }
    1642             : 
    1643         618 :         aRet <<= nFormat;
    1644             :     }
    1645        1617 :     else if ( aPropertyName == SC_UNO_DP_ORIGINAL )
    1646             :     {
    1647         648 :         uno::Reference<container::XNamed> xOriginal;
    1648         648 :         if (nSourceDim >= 0)
    1649           0 :             xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim);
    1650         648 :         aRet <<= xOriginal;
    1651             :     }
    1652         969 :     else if (aPropertyName == SC_UNO_DP_ORIGINAL_POS)
    1653             :     {
    1654           4 :         sal_Int32 nPos = static_cast<sal_Int32>(nSourceDim);
    1655           4 :         aRet <<= nPos;
    1656             :     }
    1657         965 :     else if ( aPropertyName == SC_UNO_DP_FILTER )
    1658             :     {
    1659           0 :         if ( bHasSelectedPage )
    1660             :         {
    1661             :             // single filter field: first field equal to selected string
    1662             :             sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
    1663           0 :                     sheet::FilterOperator_EQUAL, false, 0.0, aSelectedPage );
    1664           0 :             aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
    1665             :         }
    1666             :         else
    1667           0 :             aRet <<= uno::Sequence<sheet::TableFilterField>(0);
    1668             :     }
    1669         965 :     else if (aPropertyName == SC_UNO_DP_LAYOUTNAME)
    1670         506 :         aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString("");
    1671         459 :     else if (aPropertyName == SC_UNO_DP_FIELD_SUBTOTALNAME)
    1672           4 :         aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString("");
    1673         455 :     else if (aPropertyName == SC_UNO_DP_HAS_HIDDEN_MEMBER)
    1674         452 :         aRet <<= mbHasHiddenMember;
    1675           3 :     else if (aPropertyName == SC_UNO_DP_FLAGS)
    1676             :     {
    1677           3 :         sal_Int32 nFlags = 0;       // tabular data: all orientations are possible
    1678           3 :         aRet <<= nFlags;
    1679             :     }
    1680             :     else
    1681             :     {
    1682             :         OSL_FAIL("unknown property");
    1683             :         //TODO: THROW( UnknownPropertyException() );
    1684             :     }
    1685        9454 :     return aRet;
    1686             : }
    1687             : 
    1688           0 : SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension )
    1689             : 
    1690         341 : ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) :
    1691             :     pSource( pSrc ),
    1692             :     nDim( nD ),
    1693         341 :     ppHiers( NULL )
    1694             : {
    1695             :     //TODO: hold pSource
    1696             : 
    1697             :     //  date columns have 3 hierarchies (flat/quarter/week), other columns only one
    1698             : 
    1699             :     // #i52547# don't offer the incomplete date hierarchy implementation
    1700         341 :     nHierCount = 1;
    1701         341 : }
    1702             : 
    1703         999 : ScDPHierarchies::~ScDPHierarchies()
    1704             : {
    1705             :     //TODO: release pSource
    1706             : 
    1707         333 :     if (ppHiers)
    1708             :     {
    1709         666 :         for (long i=0; i<nHierCount; i++)
    1710         333 :             if ( ppHiers[i] )
    1711         333 :                 ppHiers[i]->release();      // ref-counted
    1712         333 :         delete[] ppHiers;
    1713             :     }
    1714         666 : }
    1715             : 
    1716             : // very simple XNameAccess implementation using getCount/getByIndex
    1717             : 
    1718         733 : uno::Any SAL_CALL ScDPHierarchies::getByName( const OUString& aName )
    1719             :             throw(container::NoSuchElementException,
    1720             :                     lang::WrappedTargetException, uno::RuntimeException, std::exception)
    1721             : {
    1722         733 :     long nCount = getCount();
    1723         733 :     for (long i=0; i<nCount; i++)
    1724         733 :         if ( getByIndex(i)->getName() == aName )
    1725             :         {
    1726         733 :             uno::Reference<container::XNamed> xNamed = getByIndex(i);
    1727        1466 :             uno::Any aRet;
    1728         733 :             aRet <<= xNamed;
    1729        2199 :             return aRet;
    1730             :         }
    1731             : 
    1732           0 :     throw container::NoSuchElementException();
    1733             : }
    1734             : 
    1735         736 : uno::Sequence<OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException, std::exception)
    1736             : {
    1737         736 :     long nCount = getCount();
    1738         736 :     uno::Sequence<OUString> aSeq(nCount);
    1739         736 :     OUString* pArr = aSeq.getArray();
    1740        1472 :     for (long i=0; i<nCount; i++)
    1741         736 :         pArr[i] = getByIndex(i)->getName();
    1742         736 :     return aSeq;
    1743             : }
    1744             : 
    1745           0 : sal_Bool SAL_CALL ScDPHierarchies::hasByName( const OUString& aName ) throw(uno::RuntimeException, std::exception)
    1746             : {
    1747           0 :     long nCount = getCount();
    1748           0 :     for (long i=0; i<nCount; i++)
    1749           0 :         if ( getByIndex(i)->getName() == aName )
    1750           0 :             return sal_True;
    1751           0 :     return false;
    1752             : }
    1753             : 
    1754           0 : uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException, std::exception)
    1755             : {
    1756           0 :     return cppu::UnoType<container::XNamed>::get();
    1757             : }
    1758             : 
    1759           0 : sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException, std::exception)
    1760             : {
    1761           0 :     return ( getCount() > 0 );
    1762             : }
    1763             : 
    1764             : // end of XNameAccess implementation
    1765             : 
    1766        1862 : long ScDPHierarchies::getCount() const
    1767             : {
    1768        1862 :     return nHierCount;
    1769             : }
    1770             : 
    1771        3738 : ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const
    1772             : {
    1773             :     //  pass hierarchy index to new object in case the implementation
    1774             :     //  will be extended to more than one hierarchy
    1775             : 
    1776        3738 :     if ( nIndex >= 0 && nIndex < nHierCount )
    1777             :     {
    1778        3738 :         if ( !ppHiers )
    1779             :         {
    1780         341 :             const_cast<ScDPHierarchies*>(this)->ppHiers = new ScDPHierarchy*[nHierCount];
    1781         682 :             for (long i=0; i<nHierCount; i++)
    1782         341 :                 ppHiers[i] = NULL;
    1783             :         }
    1784        3738 :         if ( !ppHiers[nIndex] )
    1785             :         {
    1786         341 :             ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex );
    1787         341 :             ppHiers[nIndex]->acquire();         // ref-counted
    1788             :         }
    1789             : 
    1790        3738 :         return ppHiers[nIndex];
    1791             :     }
    1792             : 
    1793           0 :     return NULL;    //TODO: exception?
    1794             : }
    1795             : 
    1796         341 : ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) :
    1797             :     pSource( pSrc ),
    1798             :     nDim( nD ),
    1799             :     nHier( nH ),
    1800         341 :     pLevels( NULL )
    1801             : {
    1802             :     //TODO: hold pSource
    1803         341 : }
    1804             : 
    1805         999 : ScDPHierarchy::~ScDPHierarchy()
    1806             : {
    1807             :     //TODO: release pSource
    1808             : 
    1809         333 :     if (pLevels)
    1810         333 :         pLevels->release();     // ref-counted
    1811         666 : }
    1812             : 
    1813        2269 : ScDPLevels* ScDPHierarchy::GetLevelsObject()
    1814             : {
    1815        2269 :     if (!pLevels)
    1816             :     {
    1817         341 :         pLevels = new ScDPLevels( pSource, nDim, nHier );
    1818         341 :         pLevels->acquire();     // ref-counted
    1819             :     }
    1820        2269 :     return pLevels;
    1821             : }
    1822             : 
    1823         733 : uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels()
    1824             :                                                     throw(uno::RuntimeException, std::exception)
    1825             : {
    1826         733 :     return GetLevelsObject();
    1827             : }
    1828             : 
    1829        1469 : OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException, std::exception)
    1830             : {
    1831        1469 :     OUString aRet;        //TODO: globstr-ID !!!!
    1832        1469 :     switch (nHier)
    1833             :     {
    1834             :         case SC_DAPI_HIERARCHY_FLAT:
    1835        1469 :             aRet = "flat";
    1836        1469 :             break;  //TODO: name ???????
    1837             :         case SC_DAPI_HIERARCHY_QUARTER:
    1838           0 :             aRet = "Quarter";
    1839           0 :             break;  //TODO: name ???????
    1840             :         case SC_DAPI_HIERARCHY_WEEK:
    1841           0 :             aRet = "Week";
    1842           0 :             break;  //TODO: name ???????
    1843             :         default:
    1844             :             OSL_FAIL( "ScDPHierarchy::getName: unexpected hierarchy" );
    1845           0 :             break;
    1846             :     }
    1847        1469 :     return aRet;
    1848             : }
    1849             : 
    1850           0 : void SAL_CALL ScDPHierarchy::setName( const OUString& /* rNewName */ ) throw(uno::RuntimeException, std::exception)
    1851             : {
    1852             :     OSL_FAIL("not implemented");        //TODO: exception?
    1853           0 : }
    1854             : 
    1855         341 : ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) :
    1856             :     pSource( pSrc ),
    1857             :     nDim( nD ),
    1858             :     nHier( nH ),
    1859         341 :     ppLevs( NULL )
    1860             : {
    1861             :     //TODO: hold pSource
    1862             : 
    1863             :     //  text columns have only one level
    1864             : 
    1865         341 :     long nSrcDim = pSource->GetSourceDim( nDim );
    1866         341 :     if ( pSource->IsDateDimension( nSrcDim ) )
    1867             :     {
    1868           8 :         switch ( nHier )
    1869             :         {
    1870           8 :             case SC_DAPI_HIERARCHY_FLAT:    nLevCount = SC_DAPI_FLAT_LEVELS;    break;
    1871           0 :             case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break;
    1872           0 :             case SC_DAPI_HIERARCHY_WEEK:    nLevCount = SC_DAPI_WEEK_LEVELS;    break;
    1873             :             default:
    1874             :                 OSL_FAIL("wrong hierarchy");
    1875           0 :                 nLevCount = 0;
    1876             :         }
    1877             :     }
    1878             :     else
    1879         333 :         nLevCount = 1;
    1880         341 : }
    1881             : 
    1882         999 : ScDPLevels::~ScDPLevels()
    1883             : {
    1884             :     //TODO: release pSource
    1885             : 
    1886         333 :     if (ppLevs)
    1887             :     {
    1888         666 :         for (long i=0; i<nLevCount; i++)
    1889         333 :             if ( ppLevs[i] )
    1890         333 :                 ppLevs[i]->release();   // ref-counted
    1891         333 :         delete[] ppLevs;
    1892             :     }
    1893         666 : }
    1894             : 
    1895             : // very simple XNameAccess implementation using getCount/getByIndex
    1896             : 
    1897         733 : uno::Any SAL_CALL ScDPLevels::getByName( const OUString& aName )
    1898             :             throw(container::NoSuchElementException,
    1899             :                     lang::WrappedTargetException, uno::RuntimeException, std::exception)
    1900             : {
    1901         733 :     long nCount = getCount();
    1902         733 :     for (long i=0; i<nCount; i++)
    1903         733 :         if ( getByIndex(i)->getName() == aName )
    1904             :         {
    1905         733 :             uno::Reference<container::XNamed> xNamed = getByIndex(i);
    1906        1466 :             uno::Any aRet;
    1907         733 :             aRet <<= xNamed;
    1908        2199 :             return aRet;
    1909             :         }
    1910             : 
    1911           0 :     throw container::NoSuchElementException();
    1912             : }
    1913             : 
    1914         733 : uno::Sequence<OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException, std::exception)
    1915             : {
    1916         733 :     long nCount = getCount();
    1917         733 :     uno::Sequence<OUString> aSeq(nCount);
    1918         733 :     OUString* pArr = aSeq.getArray();
    1919        1466 :     for (long i=0; i<nCount; i++)
    1920         733 :         pArr[i] = getByIndex(i)->getName();
    1921         733 :     return aSeq;
    1922             : }
    1923             : 
    1924           0 : sal_Bool SAL_CALL ScDPLevels::hasByName( const OUString& aName ) throw(uno::RuntimeException, std::exception)
    1925             : {
    1926           0 :     long nCount = getCount();
    1927           0 :     for (long i=0; i<nCount; i++)
    1928           0 :         if ( getByIndex(i)->getName() == aName )
    1929           0 :             return sal_True;
    1930           0 :     return false;
    1931             : }
    1932             : 
    1933           0 : uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException, std::exception)
    1934             : {
    1935           0 :     return cppu::UnoType<container::XNamed>::get();
    1936             : }
    1937             : 
    1938           0 : sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException, std::exception)
    1939             : {
    1940           0 :     return ( getCount() > 0 );
    1941             : }
    1942             : 
    1943             : // end of XNameAccess implementation
    1944             : 
    1945        1859 : long ScDPLevels::getCount() const
    1946             : {
    1947        1859 :     return nLevCount;
    1948             : }
    1949             : 
    1950        3693 : ScDPLevel* ScDPLevels::getByIndex(long nIndex) const
    1951             : {
    1952        3693 :     if ( nIndex >= 0 && nIndex < nLevCount )
    1953             :     {
    1954        3693 :         if ( !ppLevs )
    1955             :         {
    1956         341 :             const_cast<ScDPLevels*>(this)->ppLevs = new ScDPLevel*[nLevCount];
    1957         682 :             for (long i=0; i<nLevCount; i++)
    1958         341 :                 ppLevs[i] = NULL;
    1959             :         }
    1960        3693 :         if ( !ppLevs[nIndex] )
    1961             :         {
    1962         341 :             ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex );
    1963         341 :             ppLevs[nIndex]->acquire();      // ref-counted
    1964             :         }
    1965             : 
    1966        3693 :         return ppLevs[nIndex];
    1967             :     }
    1968             : 
    1969           0 :     return NULL;    //TODO: exception?
    1970             : }
    1971             : 
    1972             : class ScDPGlobalMembersOrder
    1973             : {
    1974             :     ScDPLevel&  rLevel;
    1975             :     bool        bAscending;
    1976             : 
    1977             : public:
    1978         269 :             ScDPGlobalMembersOrder( ScDPLevel& rLev, bool bAsc ) :
    1979             :                 rLevel(rLev),
    1980         269 :                 bAscending(bAsc)
    1981         269 :             {}
    1982        2239 :             ~ScDPGlobalMembersOrder() {}
    1983             : 
    1984             :     bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
    1985             : };
    1986             : 
    1987        1801 : bool ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
    1988             : {
    1989        1801 :     sal_Int32 nCompare = 0;
    1990             :     // seems that some ::std::sort() implementations pass the same index twice
    1991        1801 :     if( nIndex1 != nIndex2 )
    1992             :     {
    1993        1801 :         ScDPMembers* pMembers = rLevel.GetMembersObject();
    1994        1801 :         ScDPMember* pMember1 = pMembers->getByIndex(nIndex1);
    1995        1801 :         ScDPMember* pMember2 = pMembers->getByIndex(nIndex2);
    1996        1801 :         nCompare = pMember1->Compare( *pMember2 );
    1997             :     }
    1998        1801 :     return bAscending ? (nCompare < 0) : (nCompare > 0);
    1999             : }
    2000             : 
    2001         341 : ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) :
    2002             :     pSource( pSrc ),
    2003             :     nDim( nD ),
    2004             :     nHier( nH ),
    2005             :     nLev( nL ),
    2006             :     pMembers( NULL ),
    2007         341 :     aSortInfo( EMPTY_OUSTRING, sal_True, sheet::DataPilotFieldSortMode::NAME ),   // default: sort by name
    2008             :     nSortMeasure( 0 ),
    2009             :     nAutoMeasure( 0 ),
    2010             :     bShowEmpty( false ),
    2011             :     bEnableLayout( false ),
    2012         682 :     bRepeatItemLabels( false )
    2013             : {
    2014             :     //TODO: hold pSource
    2015             :     //  aSubTotals is empty
    2016         341 : }
    2017             : 
    2018         999 : ScDPLevel::~ScDPLevel()
    2019             : {
    2020             :     //TODO: release pSource
    2021             : 
    2022         333 :     if ( pMembers )
    2023         199 :         pMembers->release();    // ref-counted
    2024         666 : }
    2025             : 
    2026         269 : void ScDPLevel::EvaluateSortOrder()
    2027             : {
    2028         269 :     switch (aSortInfo.Mode)
    2029             :     {
    2030             :         case sheet::DataPilotFieldSortMode::DATA:
    2031             :             {
    2032             :                 // find index of measure (index among data dimensions)
    2033             : 
    2034           0 :                 long nMeasureCount = pSource->GetDataDimensionCount();
    2035           0 :                 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
    2036             :                 {
    2037           0 :                     if (pSource->GetDataDimName(nMeasure).equals(aSortInfo.Field))
    2038             :                     {
    2039           0 :                         nSortMeasure = nMeasure;
    2040           0 :                         break;
    2041             :                     }
    2042             :                 }
    2043             : 
    2044             :                 //TODO: error if not found?
    2045             :             }
    2046           0 :             break;
    2047             :         case sheet::DataPilotFieldSortMode::MANUAL:
    2048             :         case sheet::DataPilotFieldSortMode::NAME:
    2049             :             {
    2050         269 :                 ScDPMembers* pLocalMembers = GetMembersObject();
    2051         269 :                 long nCount = pLocalMembers->getCount();
    2052             : 
    2053         269 :                 aGlobalOrder.resize( nCount );
    2054        1441 :                 for (long nPos=0; nPos<nCount; nPos++)
    2055        1172 :                     aGlobalOrder[nPos] = nPos;
    2056             : 
    2057             :                 // allow manual or name (manual is always ascending)
    2058         269 :                 bool bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending );
    2059         269 :                 ScDPGlobalMembersOrder aComp( *this, bAscending );
    2060         269 :                 ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp );
    2061             :             }
    2062         269 :             break;
    2063             :     }
    2064             : 
    2065         269 :     if ( aAutoShowInfo.IsEnabled )
    2066             :     {
    2067             :         // find index of measure (index among data dimensions)
    2068             : 
    2069           1 :         long nMeasureCount = pSource->GetDataDimensionCount();
    2070           2 :         for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
    2071             :         {
    2072           1 :             if (pSource->GetDataDimName(nMeasure).equals(aAutoShowInfo.DataField))
    2073             :             {
    2074           0 :                 nAutoMeasure = nMeasure;
    2075           0 :                 break;
    2076             :             }
    2077             :         }
    2078             : 
    2079             :         //TODO: error if not found?
    2080             :     }
    2081         269 : }
    2082             : 
    2083         221 : void ScDPLevel::SetEnableLayout(bool bSet)
    2084             : {
    2085         221 :     bEnableLayout = bSet;
    2086         221 : }
    2087             : 
    2088        3892 : ScDPMembers* ScDPLevel::GetMembersObject()
    2089             : {
    2090        3892 :     if (!pMembers)
    2091             :     {
    2092         205 :         pMembers = new ScDPMembers( pSource, nDim, nHier, nLev );
    2093         205 :         pMembers->acquire();    // ref-counted
    2094             :     }
    2095        3892 :     return pMembers;
    2096             : }
    2097             : 
    2098         201 : uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException, std::exception)
    2099             : {
    2100         201 :     return GetMembersObject();
    2101             : }
    2102             : 
    2103         228 : uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException, std::exception)
    2104             : {
    2105         228 :     const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this );
    2106         228 :     if (pRes)
    2107         228 :         return *pRes;
    2108             : 
    2109           0 :     return uno::Sequence<sheet::MemberResult>(0);       //TODO: Error?
    2110             : }
    2111             : 
    2112        1796 : OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException, std::exception)
    2113             : {
    2114        1796 :     long nSrcDim = pSource->GetSourceDim( nDim );
    2115        1796 :     if ( pSource->IsDateDimension( nSrcDim ) )
    2116             :     {
    2117          40 :         OUString aRet;        //TODO: globstr-ID !!!!
    2118             : 
    2119          40 :         if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
    2120             :         {
    2121           0 :             switch ( nLev )
    2122             :             {
    2123             :                 case SC_DAPI_LEVEL_YEAR:
    2124           0 :                     aRet = "Year";
    2125           0 :                     break;
    2126             :                 case SC_DAPI_LEVEL_QUARTER:
    2127           0 :                     aRet = "Quarter";
    2128           0 :                     break;
    2129             :                 case SC_DAPI_LEVEL_MONTH:
    2130           0 :                     aRet = "Month";
    2131           0 :                     break;
    2132             :                 case SC_DAPI_LEVEL_DAY:
    2133           0 :                     aRet = "Day";
    2134           0 :                     break;
    2135             :                 default:
    2136             :                     OSL_FAIL( "ScDPLevel::getName: unexpected level" );
    2137           0 :                     break;
    2138             :             }
    2139             :         }
    2140          40 :         else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
    2141             :         {
    2142           0 :             switch ( nLev )
    2143             :             {
    2144             :                 case SC_DAPI_LEVEL_YEAR:
    2145           0 :                     aRet = "Year";
    2146           0 :                     break;
    2147             :                 case SC_DAPI_LEVEL_WEEK:
    2148           0 :                     aRet = "Week";
    2149           0 :                     break;
    2150             :                 case SC_DAPI_LEVEL_WEEKDAY:
    2151           0 :                     aRet = "Weekday";
    2152           0 :                     break;
    2153             :                 default:
    2154             :                     OSL_FAIL( "ScDPLevel::getName: unexpected level" );
    2155           0 :                     break;
    2156             :             }
    2157             :         }
    2158          40 :         if (!aRet.isEmpty())
    2159           0 :             return aRet;
    2160             :     }
    2161             : 
    2162        1796 :     ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
    2163        1796 :     if (!pDim)
    2164           0 :         return OUString();
    2165             : 
    2166        1796 :     return pDim->getName();
    2167             : }
    2168             : 
    2169           0 : void SAL_CALL ScDPLevel::setName( const OUString& /* rNewName */ ) throw(uno::RuntimeException, std::exception)
    2170             : {
    2171             :     OSL_FAIL("not implemented");        //TODO: exception?
    2172           0 : }
    2173             : 
    2174        7573 : uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const
    2175             : {
    2176             :     //TODO: separate functions for settings and evaluation?
    2177             : 
    2178        7573 :     long nSrcDim = pSource->GetSourceDim( nDim );
    2179        7573 :     if ( !pSource->SubTotalAllowed( nSrcDim ) )
    2180        6125 :         return uno::Sequence<sheet::GeneralFunction>(0);
    2181             : 
    2182        1448 :     return aSubTotals;
    2183             : }
    2184             : 
    2185             : // XPropertySet
    2186             : 
    2187           0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
    2188             :                                                         throw(uno::RuntimeException, std::exception)
    2189             : {
    2190           0 :     SolarMutexGuard aGuard;
    2191             : 
    2192             :     static const SfxItemPropertyMapEntry aDPLevelMap_Impl[] =
    2193             :     {
    2194             :         //TODO: change type of AutoShow/Layout/Sorting to API struct when available
    2195           0 :         { OUString(SC_UNO_DP_AUTOSHOW), 0,  cppu::UnoType<sheet::DataPilotFieldAutoShowInfo>::get(),     0, 0 },
    2196           0 :         { OUString(SC_UNO_DP_LAYOUT),   0,  cppu::UnoType<sheet::DataPilotFieldLayoutInfo>::get(),       0, 0 },
    2197           0 :         { OUString(SC_UNO_DP_SHOWEMPTY), 0, cppu::UnoType<bool>::get(),                                   0, 0 },
    2198           0 :         { OUString(SC_UNO_DP_REPEATITEMLABELS), 0, cppu::UnoType<bool>::get(),                                   0, 0 },
    2199           0 :         { OUString(SC_UNO_DP_SORTING),  0,  cppu::UnoType<sheet::DataPilotFieldSortInfo>::get(),         0, 0 },
    2200           0 :         { OUString(SC_UNO_DP_SUBTOTAL), 0,  cppu::UnoType<uno::Sequence<sheet::GeneralFunction>>::get(), 0, 0 },
    2201             :         { OUString(), 0, css::uno::Type(), 0, 0 }
    2202           0 :     };
    2203             :     static uno::Reference<beans::XPropertySetInfo> aRef =
    2204           0 :         new SfxItemPropertySetInfo( aDPLevelMap_Impl );
    2205           0 :     return aRef;
    2206             : }
    2207             : 
    2208         879 : void SAL_CALL ScDPLevel::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
    2209             :                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
    2210             :                         lang::IllegalArgumentException, lang::WrappedTargetException,
    2211             :                         uno::RuntimeException, std::exception)
    2212             : {
    2213         879 :     if ( aPropertyName == SC_UNO_DP_SHOWEMPTY )
    2214         127 :         bShowEmpty = lcl_GetBoolFromAny(aValue);
    2215         752 :     else if ( aPropertyName == SC_UNO_DP_REPEATITEMLABELS )
    2216         337 :         bRepeatItemLabels = lcl_GetBoolFromAny(aValue);
    2217         415 :     else if ( aPropertyName == SC_UNO_DP_SUBTOTAL )
    2218          69 :         aValue >>= aSubTotals;
    2219         346 :     else if ( aPropertyName == SC_UNO_DP_SORTING )
    2220         122 :         aValue >>= aSortInfo;
    2221         224 :     else if ( aPropertyName == SC_UNO_DP_AUTOSHOW )
    2222         100 :         aValue >>= aAutoShowInfo;
    2223         124 :     else if ( aPropertyName == SC_UNO_DP_LAYOUT )
    2224         124 :         aValue >>= aLayoutInfo;
    2225             :     else
    2226             :     {
    2227             :         OSL_FAIL("unknown property");
    2228             :     }
    2229         879 : }
    2230             : 
    2231         307 : uno::Any SAL_CALL ScDPLevel::getPropertyValue( const OUString& aPropertyName )
    2232             :                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
    2233             :                         uno::RuntimeException, std::exception)
    2234             : {
    2235         307 :     uno::Any aRet;
    2236         307 :     if ( aPropertyName == SC_UNO_DP_SHOWEMPTY )
    2237           3 :         lcl_SetBoolInAny(aRet, bShowEmpty);
    2238         307 :     if ( aPropertyName == SC_UNO_DP_REPEATITEMLABELS )
    2239           3 :         lcl_SetBoolInAny(aRet, bRepeatItemLabels);
    2240         304 :     else if ( aPropertyName == SC_UNO_DP_SUBTOTAL )
    2241             :     {
    2242           0 :         uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals();        //TODO: avoid extra copy?
    2243           0 :         aRet <<= aSeq;
    2244             :     }
    2245         304 :     else if ( aPropertyName == SC_UNO_DP_SORTING )
    2246           3 :         aRet <<= aSortInfo;
    2247         301 :     else if ( aPropertyName == SC_UNO_DP_AUTOSHOW )
    2248           3 :         aRet <<= aAutoShowInfo;
    2249         298 :     else if ( aPropertyName == SC_UNO_DP_LAYOUT )
    2250           3 :         aRet <<= aLayoutInfo;
    2251         295 :     else if (aPropertyName == SC_UNO_DP_LAYOUTNAME)
    2252             :     {
    2253             :         // read only property
    2254         292 :         long nSrcDim = pSource->GetSourceDim(nDim);
    2255         292 :         ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
    2256         292 :         if (!pDim)
    2257           0 :             return aRet;
    2258             : 
    2259         292 :         const OUString* pLayoutName = pDim->GetLayoutName();
    2260         292 :         if (!pLayoutName)
    2261         292 :             return aRet;
    2262             : 
    2263           0 :         aRet <<= *pLayoutName;
    2264             :     }
    2265             :     else
    2266             :     {
    2267             :         OSL_FAIL("unknown property");
    2268             :     }
    2269          15 :     return aRet;
    2270             : }
    2271             : 
    2272           0 : SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel )
    2273             : 
    2274         205 : ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) :
    2275             :     pSource( pSrc ),
    2276             :     nDim( nD ),
    2277             :     nHier( nH ),
    2278         205 :     nLev( nL )
    2279             : {
    2280             :     //TODO: hold pSource
    2281             : 
    2282         205 :     long nSrcDim = pSource->GetSourceDim( nDim );
    2283         205 :     if ( pSource->IsDataLayoutDimension(nSrcDim) )
    2284           9 :         nMbrCount = pSource->GetDataDimensionCount();
    2285         196 :     else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
    2286             :     {
    2287           0 :         nMbrCount = 0;
    2288           0 :         if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
    2289             :         {
    2290           0 :             switch (nLev)
    2291             :             {
    2292             :                 case SC_DAPI_LEVEL_YEAR:
    2293             :                     {
    2294           0 :                         const ScDPItemData* pLastNumData = NULL;
    2295           0 :                         for ( SCROW n = 0 ;n <GetSrcItemsCount() ; n-- )
    2296             :                         {
    2297           0 :                             const ScDPItemData* pData  = GetSrcItemDataByIndex( n );
    2298           0 :                             if ( pData && pData->HasStringData() )
    2299           0 :                                 break;
    2300             :                             else
    2301           0 :                                 pLastNumData = pData;
    2302             :                         }
    2303             : 
    2304           0 :                         if ( pLastNumData )
    2305             :                         {
    2306           0 :                             const ScDPItemData*  pFirstData = GetSrcItemDataByIndex( 0 );
    2307           0 :                             double fFirstVal = pFirstData->GetValue();
    2308           0 :                             double fLastVal = pLastNumData->GetValue();
    2309             : 
    2310             :                             long nFirstYear = pSource->GetData()->GetDatePart(
    2311           0 :                                         (long)::rtl::math::approxFloor( fFirstVal ),
    2312           0 :                                         nHier, nLev );
    2313             :                             long nLastYear = pSource->GetData()->GetDatePart(
    2314           0 :                                         (long)::rtl::math::approxFloor( fLastVal ),
    2315           0 :                                         nHier, nLev );
    2316             : 
    2317           0 :                             nMbrCount = nLastYear + 1 - nFirstYear;
    2318             :                         }
    2319             :                         else
    2320           0 :                             nMbrCount = 0;      // no values
    2321             :                     }
    2322           0 :                     break;
    2323           0 :                 case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4;  break;
    2324           0 :                 case SC_DAPI_LEVEL_MONTH:   nMbrCount = 12; break;
    2325           0 :                 case SC_DAPI_LEVEL_DAY:     nMbrCount = 31; break;
    2326             :                 default:
    2327             :                     OSL_FAIL( "ScDPMembers::ScDPMembers: unexpected level" );
    2328           0 :                     break;
    2329             :             }
    2330             :         }
    2331           0 :         else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
    2332             :         {
    2333           0 :             switch (nLev)
    2334             :             {
    2335           0 :                 case SC_DAPI_LEVEL_YEAR:    nMbrCount = 1;  break;      //TODO: get years from source
    2336           0 :                 case SC_DAPI_LEVEL_WEEK:    nMbrCount = 53; break;
    2337           0 :                 case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7;  break;
    2338             :                 default:
    2339             :                     OSL_FAIL( "ScDPMembers::ScDPMembers: unexpected level" );
    2340           0 :                     break;
    2341             :             }
    2342             :         }
    2343             :     }
    2344             :     else
    2345         196 :         nMbrCount = pSource->GetData()->GetMembersCount( nSrcDim );
    2346         205 : }
    2347             : 
    2348         398 : ScDPMembers::~ScDPMembers()
    2349             : {
    2350         398 : }
    2351             : 
    2352             : // XNameAccess implementation using getCount/getByIndex
    2353             : 
    2354        1365 : sal_Int32 ScDPMembers::GetIndexFromName( const OUString& rName ) const
    2355             : {
    2356        1365 :     if ( aHashMap.empty() )
    2357             :     {
    2358             :         // store the index for each name
    2359             : 
    2360          99 :         sal_Int32 nCount = getCount();
    2361         519 :         for (sal_Int32 i=0; i<nCount; i++)
    2362         420 :             aHashMap[ getByIndex(i)->getName() ] = i;
    2363             :     }
    2364             : 
    2365        1365 :     ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName );
    2366        1365 :     if ( aIter != aHashMap.end() )
    2367        1354 :         return aIter->second;           // found index
    2368             :     else
    2369          11 :         return -1;                      // not found
    2370             : }
    2371             : 
    2372         586 : uno::Any SAL_CALL ScDPMembers::getByName( const OUString& aName )
    2373             :             throw(container::NoSuchElementException,
    2374             :                     lang::WrappedTargetException, uno::RuntimeException, std::exception)
    2375             : {
    2376         586 :     sal_Int32 nIndex = GetIndexFromName( aName );
    2377         586 :     if ( nIndex >= 0 )
    2378             :     {
    2379         586 :         uno::Reference<container::XNamed> xNamed = getByIndex(nIndex);
    2380        1172 :         uno::Any aRet;
    2381         586 :         aRet <<= xNamed;
    2382        1758 :         return aRet;
    2383             :     }
    2384             : 
    2385           0 :     throw container::NoSuchElementException();
    2386             : }
    2387             : 
    2388         124 : uno::Sequence<OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException, std::exception)
    2389             : {
    2390             :     // Return list of names in sorted order,
    2391             :     // so it's displayed in that order in the field options dialog.
    2392             :     // Sorting is done at the level object (parent of this).
    2393             : 
    2394             :     ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)->
    2395         124 :         GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev);
    2396         124 :     pLevel->EvaluateSortOrder();
    2397         124 :     const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder();
    2398         124 :     bool bSort = !rGlobalOrder.empty();
    2399             : 
    2400         124 :     long nCount = getCount();
    2401         124 :     uno::Sequence<OUString> aSeq(nCount);
    2402         124 :     OUString* pArr = aSeq.getArray();
    2403         658 :     for (long i=0; i<nCount; i++)
    2404         534 :         pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName();
    2405         124 :     return aSeq;
    2406             : }
    2407             : 
    2408         319 : sal_Bool SAL_CALL ScDPMembers::hasByName( const OUString& aName ) throw(uno::RuntimeException, std::exception)
    2409             : {
    2410         319 :     return ( GetIndexFromName( aName ) >= 0 );
    2411             : }
    2412             : 
    2413           0 : uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException, std::exception)
    2414             : {
    2415           0 :     return cppu::UnoType<container::XNamed>::get();
    2416             : }
    2417             : 
    2418           0 : sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException, std::exception)
    2419             : {
    2420           0 :     return ( getCount() > 0 );
    2421             : }
    2422             : 
    2423             : // end of XNameAccess implementation
    2424             : 
    2425         115 : long ScDPMembers::getMinMembers() const
    2426             : {
    2427             :     // used in lcl_CountMinMembers
    2428             : 
    2429         115 :     long nVisCount = 0;
    2430         115 :     if (!maMembers.empty())
    2431             :     {
    2432         113 :         MembersType::const_iterator it = maMembers.begin(), itEnd = maMembers.end();
    2433         648 :         for (; it != itEnd; ++it)
    2434             :         {
    2435             :             //  count only visible with details (default is true for both)
    2436         535 :             const rtl::Reference<ScDPMember>& pMbr = *it;
    2437         535 :             if (!pMbr.get() || (pMbr->isVisible() && pMbr->getShowDetails()))
    2438         535 :                 ++nVisCount;
    2439             :         }
    2440             :     }
    2441             :     else
    2442           2 :         nVisCount = nMbrCount;      // default for all
    2443             : 
    2444         115 :     return nVisCount;
    2445             : }
    2446             : 
    2447        7042 : ScDPMember* ScDPMembers::getByIndex(long nIndex) const
    2448             : {
    2449             :     //  result of GetColumnEntries must not change between ScDPMembers ctor
    2450             :     //  and all calls to getByIndex
    2451             : 
    2452        7042 :     if ( nIndex >= 0 && nIndex < nMbrCount )
    2453             :     {
    2454        7042 :         if (maMembers.empty())
    2455         205 :             maMembers.resize(nMbrCount);
    2456             : 
    2457        7042 :         if (!maMembers[nIndex].get())
    2458             :         {
    2459         882 :             rtl::Reference<ScDPMember> pNew;
    2460         882 :             long nSrcDim = pSource->GetSourceDim( nDim );
    2461         882 :             if ( pSource->IsDataLayoutDimension(nSrcDim) )
    2462             :             {
    2463             :                 // empty name (never shown, not used for lookup)
    2464          18 :                 pNew.set(new ScDPMember(pSource, nDim, nHier, nLev, 0));
    2465             :             }
    2466         864 :             else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
    2467             :             {
    2468           0 :                 sal_Int32 nGroupBy = 0;
    2469           0 :                 sal_Int32 nVal = 0;
    2470           0 :                 OUString aName;
    2471             : 
    2472           0 :                 if ( nLev == SC_DAPI_LEVEL_YEAR )   // YEAR is in both hierarchies
    2473             :                 {
    2474             :                     //TODO: cache year range here!
    2475             : 
    2476           0 :                     double fFirstVal = pSource->GetData()->GetMemberByIndex( nSrcDim, 0 )->GetValue();
    2477             :                     long nFirstYear = pSource->GetData()->GetDatePart(
    2478           0 :                                         (long)::rtl::math::approxFloor( fFirstVal ),
    2479           0 :                                         nHier, nLev );
    2480             : 
    2481           0 :                     nVal = nFirstYear + nIndex;
    2482             :                 }
    2483           0 :                 else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
    2484             :                 {
    2485           0 :                     nVal = nIndex;              // DayOfWeek is 0-based
    2486           0 :                     aName = ScGlobal::GetCalendar()->getDisplayName(
    2487             :                         ::com::sun::star::i18n::CalendarDisplayIndex::DAY,
    2488           0 :                         sal::static_int_cast<sal_Int16>(nVal), 0 );
    2489             :                 }
    2490           0 :                 else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH )
    2491             :                 {
    2492           0 :                     nVal = nIndex;              // Month is 0-based
    2493           0 :                     aName = ScGlobal::GetCalendar()->getDisplayName(
    2494             :                         ::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
    2495           0 :                         sal::static_int_cast<sal_Int16>(nVal), 0 );
    2496             :                 }
    2497             :                 else
    2498           0 :                     nVal = nIndex + 1;          // Quarter, Day, Week are 1-based
    2499             : 
    2500           0 :                 switch (nLev)
    2501             :                 {
    2502             :                     case SC_DAPI_LEVEL_YEAR:
    2503           0 :                         nGroupBy = sheet::DataPilotFieldGroupBy::YEARS;
    2504           0 :                     break;
    2505             :                     case SC_DAPI_LEVEL_QUARTER:
    2506             :                     case SC_DAPI_LEVEL_WEEK:
    2507           0 :                         nGroupBy = sheet::DataPilotFieldGroupBy::QUARTERS;
    2508           0 :                     break;
    2509             :                     case SC_DAPI_LEVEL_MONTH:
    2510             :                     case SC_DAPI_LEVEL_WEEKDAY:
    2511           0 :                         nGroupBy = sheet::DataPilotFieldGroupBy::MONTHS;
    2512           0 :                     break;
    2513             :                     case SC_DAPI_LEVEL_DAY:
    2514           0 :                         nGroupBy = sheet::DataPilotFieldGroupBy::DAYS;
    2515           0 :                     break;
    2516             :                     default:
    2517             :                         ;
    2518             :                 }
    2519           0 :                 if (aName.isEmpty())
    2520           0 :                     aName = OUString::number(nVal);
    2521             : 
    2522           0 :                 ScDPItemData aData(nGroupBy, nVal);
    2523           0 :                 SCROW nId = pSource->GetCache()->GetIdByItemData(nDim, aData);
    2524           0 :                 pNew.set(new ScDPMember(pSource, nDim, nHier, nLev, nId));
    2525             :             }
    2526             :             else
    2527             :             {
    2528         864 :                 const std::vector<SCROW>& memberIndexs = pSource->GetData()->GetColumnEntries(nSrcDim);
    2529         864 :                 pNew.set(new ScDPMember(pSource, nDim, nHier, nLev, memberIndexs[nIndex]));
    2530             :             }
    2531         882 :             maMembers[nIndex] = pNew;
    2532             :         }
    2533             : 
    2534        7042 :         return maMembers[nIndex].get();
    2535             :     }
    2536             : 
    2537           0 :     return NULL;    //TODO: exception?
    2538             : }
    2539             : 
    2540         882 : ScDPMember::ScDPMember(
    2541             :     ScDPSource* pSrc, long nD, long nH, long nL, SCROW nIndex) :
    2542             :     pSource( pSrc ),
    2543             :     nDim( nD ),
    2544             :     nHier( nH ),
    2545             :     nLev( nL ),
    2546             :     mnDataId( nIndex ),
    2547             :     mpLayoutName(NULL),
    2548             :     nPosition( -1 ),
    2549             :     bVisible( true ),
    2550         882 :     bShowDet( true )
    2551             : {
    2552             :     //TODO: hold pSource
    2553         882 : }
    2554             : 
    2555        1720 : ScDPMember::~ScDPMember()
    2556             : {
    2557             :     //TODO: release pSource
    2558        1720 : }
    2559             : 
    2560        3705 : bool ScDPMember::IsNamedItem(SCROW nIndex) const
    2561             : {
    2562        3705 :     long nSrcDim = pSource->GetSourceDim( nDim );
    2563        3705 :     if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
    2564             :     {
    2565           0 :         const ScDPItemData* pData = pSource->GetCache()->GetItemDataById(nDim, nIndex);
    2566           0 :         if (pData->IsValue())
    2567             :         {
    2568             :             long nComp = pSource->GetData()->GetDatePart(
    2569           0 :                 (long)::rtl::math::approxFloor( pData->GetValue() ),
    2570           0 :                 nHier, nLev );
    2571             :             //  fValue is converted from integer, so simple comparison works
    2572           0 :             const ScDPItemData* pData2 = GetItemData();
    2573           0 :             return pData2 && nComp == pData2->GetValue();
    2574             :         }
    2575             :     }
    2576             : 
    2577        3705 :     return  nIndex == mnDataId;
    2578             : }
    2579             : 
    2580        1801 : sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const
    2581             : {
    2582        1801 :     if ( nPosition >= 0 )
    2583             :     {
    2584         181 :         if ( rOther.nPosition >= 0 )
    2585             :         {
    2586             :             OSL_ENSURE( nPosition != rOther.nPosition, "same position for two members" );
    2587         180 :             return ( nPosition < rOther.nPosition ) ? -1 : 1;
    2588             :         }
    2589             :         else
    2590             :         {
    2591             :             // only this has a position - members with specified positions come before those without
    2592           1 :             return -1;
    2593             :         }
    2594             :     }
    2595        1620 :     else if ( rOther.nPosition >= 0 )
    2596             :     {
    2597             :         // only rOther has a position
    2598           3 :         return 1;
    2599             :     }
    2600             : 
    2601             :     // no positions set - compare names
    2602        1617 :    return pSource->GetData()->Compare( pSource->GetSourceDim(nDim),mnDataId,rOther.GetItemDataId());
    2603             : }
    2604             : 
    2605        8031 : void ScDPMember::FillItemData( ScDPItemData& rData ) const
    2606             : {
    2607             :     //TODO: handle date hierarchy...
    2608             : 
    2609        8031 :     const ScDPItemData* pData = GetItemData();
    2610        8031 :     rData = (pData ? *pData : ScDPItemData());
    2611        8031 : }
    2612             : 
    2613         590 : const OUString* ScDPMember::GetLayoutName() const
    2614             : {
    2615         590 :     return mpLayoutName.get();
    2616             : }
    2617             : 
    2618        1033 : OUString ScDPMember::GetNameStr() const
    2619             : {
    2620        1033 :     const ScDPItemData* pData = GetItemData();
    2621        1033 :     if (pData)
    2622        1033 :         return pSource->GetData()->GetFormattedString(nDim, *pData);
    2623           0 :     return OUString();
    2624             : }
    2625             : 
    2626        1021 : OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException, std::exception)
    2627             : {
    2628        1021 :     return GetNameStr();
    2629             : }
    2630             : 
    2631           0 : void SAL_CALL ScDPMember::setName( const OUString& /* rNewName */ ) throw(uno::RuntimeException, std::exception)
    2632             : {
    2633             :     OSL_FAIL("not implemented");        //TODO: exception?
    2634           0 : }
    2635             : 
    2636             : // XPropertySet
    2637             : 
    2638           0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo()
    2639             :                                                         throw(uno::RuntimeException, std::exception)
    2640             : {
    2641           0 :     SolarMutexGuard aGuard;
    2642             : 
    2643             :     static const SfxItemPropertyMapEntry aDPMemberMap_Impl[] =
    2644             :     {
    2645           0 :         { OUString(SC_UNO_DP_ISVISIBLE), 0,  cppu::UnoType<bool>::get(),              0, 0 },
    2646           0 :         { OUString(SC_UNO_DP_POSITION), 0,  cppu::UnoType<sal_Int32>::get(),        0, 0 },
    2647           0 :         { OUString(SC_UNO_DP_SHOWDETAILS), 0,  cppu::UnoType<bool>::get(),              0, 0 },
    2648           0 :         { OUString(SC_UNO_DP_LAYOUTNAME), 0, cppu::UnoType<OUString>::get(), 0, 0 },
    2649             :         { OUString(), 0, css::uno::Type(), 0, 0 }
    2650           0 :     };
    2651             :     static uno::Reference<beans::XPropertySetInfo> aRef =
    2652           0 :         new SfxItemPropertySetInfo( aDPMemberMap_Impl );
    2653           0 :     return aRef;
    2654             : }
    2655             : 
    2656         630 : void SAL_CALL ScDPMember::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
    2657             :                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
    2658             :                         lang::IllegalArgumentException, lang::WrappedTargetException,
    2659             :                         uno::RuntimeException, std::exception)
    2660             : {
    2661         630 :     if ( aPropertyName == SC_UNO_DP_ISVISIBLE )
    2662         297 :         bVisible = lcl_GetBoolFromAny(aValue);
    2663         333 :     else if ( aPropertyName == SC_UNO_DP_SHOWDETAILS )
    2664         256 :         bShowDet = lcl_GetBoolFromAny(aValue);
    2665          77 :     else if ( aPropertyName == SC_UNO_DP_POSITION )
    2666          77 :         aValue >>= nPosition;
    2667           0 :     else if (aPropertyName == SC_UNO_DP_LAYOUTNAME)
    2668             :     {
    2669           0 :         OUString aName;
    2670           0 :         if (aValue >>= aName)
    2671           0 :             mpLayoutName.reset(new OUString(aName));
    2672             :     }
    2673             :     else
    2674             :     {
    2675             :         OSL_FAIL("unknown property");
    2676             :     }
    2677         630 : }
    2678             : 
    2679         320 : uno::Any SAL_CALL ScDPMember::getPropertyValue( const OUString& aPropertyName )
    2680             :                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
    2681             :                         uno::RuntimeException, std::exception)
    2682             : {
    2683         320 :     uno::Any aRet;
    2684         320 :     if ( aPropertyName == SC_UNO_DP_ISVISIBLE )
    2685         144 :         lcl_SetBoolInAny(aRet, bVisible);
    2686         176 :     else if ( aPropertyName == SC_UNO_DP_SHOWDETAILS )
    2687          33 :         lcl_SetBoolInAny(aRet, bShowDet);
    2688         143 :     else if ( aPropertyName == SC_UNO_DP_POSITION )
    2689           0 :         aRet <<= nPosition;
    2690         143 :     else if (aPropertyName == SC_UNO_DP_LAYOUTNAME)
    2691         143 :         aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString();
    2692             :     else
    2693             :     {
    2694             :         OSL_FAIL("unknown property");
    2695             :     }
    2696         320 :     return aRet;
    2697             : }
    2698             : 
    2699           0 : SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember )
    2700             : 
    2701           0 : const ScDPCache* ScDPSource::GetCache()
    2702             : {
    2703             :     OSL_ENSURE( GetData() , "empty ScDPTableData pointer");
    2704           0 :     return ( GetData()!=NULL ) ? &GetData()->GetCacheTable().getCache() : NULL ;
    2705             : }
    2706             : 
    2707        9064 : const ScDPItemData* ScDPMember::GetItemData() const
    2708             : {
    2709        9064 :     const ScDPItemData* pData = pSource->GetItemDataById(nDim, mnDataId);
    2710             :     SAL_WARN_IF( !pData, "sc", "ScDPMember::GetItemData: what data? nDim " << nDim << ", mnDataId " << mnDataId);
    2711        9064 :     return pData;
    2712             : }
    2713             : 
    2714        9131 : const ScDPItemData* ScDPSource::GetItemDataById(long nDim, long nId)
    2715             : {
    2716        9131 :     return GetData()->GetMemberById(nDim, nId);
    2717             : }
    2718             : 
    2719           0 : SCROW ScDPSource::GetMemberId(long nDim, const ScDPItemData& rData)
    2720             : {
    2721           0 :     return GetCache()->GetIdByItemData(nDim, rData);
    2722             : }
    2723             : 
    2724           0 : const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex(SCROW nIndex)
    2725             : {
    2726           0 :     const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim );
    2727           0 :     if ( nIndex >= (long )(memberIds.size()) || nIndex < 0 )
    2728           0 :         return NULL;
    2729           0 :     SCROW nId =  memberIds[ nIndex ];
    2730           0 :     return pSource->GetItemDataById( nDim, nId );
    2731             : }
    2732             : 
    2733           0 : SCROW ScDPMembers::GetSrcItemsCount()
    2734             : {
    2735           0 :     return pSource->GetData()->GetColumnEntries(nDim).size();
    2736         156 : }
    2737             : 
    2738             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11