LCOV - code coverage report
Current view: top level - sc/source/core/data - dpgroup.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 260 485 53.6 %
Date: 2014-11-03 Functions: 51 77 66.2 %
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 "dpgroup.hxx"
      21             : 
      22             : #include "global.hxx"
      23             : #include "document.hxx"
      24             : #include "dpfilteredcache.hxx"
      25             : #include "dptabsrc.hxx"
      26             : #include "dptabres.hxx"
      27             : #include "dpobject.hxx"
      28             : #include "dpglobal.hxx"
      29             : #include "dputil.hxx"
      30             : #include "globalnames.hxx"
      31             : 
      32             : #include <rtl/math.hxx>
      33             : 
      34             : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
      35             : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
      36             : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
      37             : 
      38             : #include <vector>
      39             : #include <boost/unordered_map.hpp>
      40             : #include <boost/unordered_set.hpp>
      41             : 
      42             : using namespace ::com::sun::star;
      43             : using ::com::sun::star::uno::Any;
      44             : using ::com::sun::star::uno::Reference;
      45             : using ::com::sun::star::uno::Sequence;
      46             : using ::com::sun::star::uno::UNO_QUERY;
      47             : using ::com::sun::star::uno::UNO_QUERY_THROW;
      48             : 
      49             : using ::std::vector;
      50             : using ::boost::shared_ptr;
      51             : 
      52             : const sal_uInt16 SC_DP_LEAPYEAR = 1648;     // arbitrary leap year for date calculations
      53             : 
      54             : class ScDPGroupNumFilter : public ScDPFilteredCache::FilterBase
      55             : {
      56             : public:
      57             :     ScDPGroupNumFilter(const std::vector<ScDPItemData>& rValues, const ScDPNumGroupInfo& rInfo);
      58           0 :     virtual ~ScDPGroupNumFilter() {}
      59             :     virtual bool match(const ScDPItemData &rCellData) const SAL_OVERRIDE;
      60             :     virtual std::vector<ScDPItemData> getMatchValues() const SAL_OVERRIDE;
      61             : private:
      62             :     std::vector<ScDPItemData> maValues;
      63             :     ScDPNumGroupInfo maNumInfo;
      64             : };
      65             : 
      66           0 : ScDPGroupNumFilter::ScDPGroupNumFilter(const std::vector<ScDPItemData>& rValues, const ScDPNumGroupInfo& rInfo) :
      67           0 :     maValues(rValues), maNumInfo(rInfo) {}
      68             : 
      69           0 : bool ScDPGroupNumFilter::match(const ScDPItemData& rCellData) const
      70             : {
      71           0 :     if (rCellData.GetType() != ScDPItemData::Value)
      72           0 :         return false;
      73             : 
      74           0 :     std::vector<ScDPItemData>::const_iterator it = maValues.begin(), itEnd = maValues.end();
      75           0 :     for (; it != itEnd; ++it)
      76             :     {
      77           0 :         double fVal = it->GetValue();
      78           0 :         if (rtl::math::isInf(fVal))
      79             :         {
      80           0 :             if (rtl::math::isSignBitSet(fVal))
      81             :             {
      82             :                 // Less than the min value.
      83           0 :                 if (rCellData.GetValue() < maNumInfo.mfStart)
      84           0 :                     return true;
      85             :             }
      86             : 
      87             :             // Greater than the max value.
      88           0 :             if (maNumInfo.mfEnd < rCellData.GetValue())
      89           0 :                 return true;
      90             : 
      91           0 :             continue;
      92             :         }
      93             : 
      94           0 :         double low = fVal;
      95           0 :         double high = low + maNumInfo.mfStep;
      96           0 :         if (maNumInfo.mbIntegerOnly)
      97           0 :             high += 1.0;
      98             : 
      99           0 :         if (low <= rCellData.GetValue() && rCellData.GetValue() < high)
     100           0 :             return true;
     101             :     }
     102             : 
     103           0 :     return false;
     104             : }
     105             : 
     106           0 : std::vector<ScDPItemData> ScDPGroupNumFilter::getMatchValues() const
     107             : {
     108           0 :     return std::vector<ScDPItemData>();
     109             : }
     110             : 
     111             : class ScDPGroupDateFilter : public ScDPFilteredCache::FilterBase
     112             : {
     113             : public:
     114           0 :     virtual ~ScDPGroupDateFilter() {}
     115             :     ScDPGroupDateFilter(
     116             :         const std::vector<ScDPItemData>& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo);
     117             : 
     118             :     virtual bool match(const ScDPItemData & rCellData) const SAL_OVERRIDE;
     119             :     virtual std::vector<ScDPItemData> getMatchValues() const SAL_OVERRIDE;
     120             : 
     121             : private:
     122             :     std::vector<ScDPItemData> maValues;
     123             :     Date             maNullDate;
     124             :     ScDPNumGroupInfo maNumInfo;
     125             : };
     126             : 
     127           0 : ScDPGroupDateFilter::ScDPGroupDateFilter(
     128             :     const std::vector<ScDPItemData>& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo) :
     129             :     maValues(rValues),
     130             :     maNullDate(rNullDate),
     131           0 :     maNumInfo(rNumInfo)
     132             : {
     133           0 : }
     134             : 
     135           0 : bool ScDPGroupDateFilter::match( const ScDPItemData & rCellData ) const
     136             : {
     137             :     using namespace ::com::sun::star::sheet;
     138             :     using ::rtl::math::approxFloor;
     139             :     using ::rtl::math::approxEqual;
     140             : 
     141           0 :     if ( !rCellData.IsValue() )
     142           0 :         return false;
     143             : 
     144           0 :     std::vector<ScDPItemData>::const_iterator it = maValues.begin(), itEnd = maValues.end();
     145           0 :     for (; it != itEnd; ++it)
     146             :     {
     147           0 :         const ScDPItemData& rValue = *it;
     148           0 :         if (rValue.GetType() != ScDPItemData::GroupValue)
     149           0 :             continue;
     150             : 
     151           0 :         sal_Int32 nGroupType = rValue.GetGroupValue().mnGroupType;
     152           0 :         sal_Int32 nValue = rValue.GetGroupValue().mnValue;
     153             : 
     154             :         // Start and end dates are inclusive.  (An end date without a time value
     155             :         // is included, while an end date with a time value is not.)
     156             : 
     157           0 :         if (rCellData.GetValue() < maNumInfo.mfStart && !approxEqual(rCellData.GetValue(), maNumInfo.mfStart))
     158             :         {
     159           0 :             if (nValue == ScDPItemData::DateFirst)
     160           0 :                 return true;
     161           0 :             continue;
     162             :         }
     163             : 
     164           0 :         if (rCellData.GetValue() > maNumInfo.mfEnd && !approxEqual(rCellData.GetValue(), maNumInfo.mfEnd))
     165             :         {
     166           0 :             if (nValue == ScDPItemData::DateLast)
     167           0 :                 return true;
     168           0 :             continue;
     169             :         }
     170             : 
     171           0 :         if (nGroupType == DataPilotFieldGroupBy::HOURS || nGroupType == DataPilotFieldGroupBy::MINUTES ||
     172             :             nGroupType == DataPilotFieldGroupBy::SECONDS)
     173             :         {
     174             :             // handle time
     175             :             // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
     176             : 
     177           0 :             double time = rCellData.GetValue() - approxFloor(rCellData.GetValue());
     178           0 :             long seconds = static_cast<long>(approxFloor(time*DATE_TIME_FACTOR + 0.5));
     179             : 
     180           0 :             switch (nGroupType)
     181             :             {
     182             :                 case DataPilotFieldGroupBy::HOURS:
     183             :                 {
     184           0 :                     sal_Int32 hrs = seconds / 3600;
     185           0 :                     if (hrs == nValue)
     186           0 :                         return true;
     187             :                 }
     188           0 :                 break;
     189             :                 case DataPilotFieldGroupBy::MINUTES:
     190             :                 {
     191           0 :                     sal_Int32 minutes = (seconds % 3600) / 60;
     192           0 :                     if (minutes == nValue)
     193           0 :                         return true;
     194             :                 }
     195           0 :                 break;
     196             :                 case DataPilotFieldGroupBy::SECONDS:
     197             :                 {
     198           0 :                     sal_Int32 sec = seconds % 60;
     199           0 :                     if (sec == nValue)
     200           0 :                         return true;
     201             :                 }
     202           0 :                 break;
     203             :                 default:
     204             :                     OSL_FAIL("invalid time part");
     205             :             }
     206             : 
     207           0 :             continue;
     208             :         }
     209             : 
     210           0 :         Date date = maNullDate + static_cast<long>(approxFloor(rCellData.GetValue()));
     211           0 :         switch (nGroupType)
     212             :         {
     213             :             case DataPilotFieldGroupBy::YEARS:
     214             :             {
     215           0 :                 sal_Int32 year = static_cast<sal_Int32>(date.GetYear());
     216           0 :                 if (year == nValue)
     217           0 :                     return true;
     218             :             }
     219           0 :             break;
     220             :             case DataPilotFieldGroupBy::QUARTERS:
     221             :             {
     222           0 :                 sal_Int32 qtr =  1 + (static_cast<sal_Int32>(date.GetMonth()) - 1) / 3;
     223           0 :                 if (qtr == nValue)
     224           0 :                     return true;
     225             :             }
     226           0 :             break;
     227             :             case DataPilotFieldGroupBy::MONTHS:
     228             :             {
     229           0 :                 sal_Int32 month = static_cast<sal_Int32>(date.GetMonth());
     230           0 :                 if (month == nValue)
     231           0 :                     return true;
     232             :             }
     233           0 :             break;
     234             :             case DataPilotFieldGroupBy::DAYS:
     235             :             {
     236           0 :                 Date yearStart(1, 1, date.GetYear());
     237           0 :                 sal_Int32 days = (date - yearStart) + 1;       // Jan 01 has value 1
     238           0 :                 if (days >= 60 && !date.IsLeapYear())
     239             :                 {
     240             :                     // This is not a leap year.  Adjust the value accordingly.
     241           0 :                     ++days;
     242             :                 }
     243           0 :                 if (days == nValue)
     244           0 :                     return true;
     245             :             }
     246           0 :             break;
     247             :             default:
     248             :                 OSL_FAIL("invalid date part");
     249             :         }
     250             :     }
     251             : 
     252           0 :     return false;
     253             : }
     254             : 
     255           0 : std::vector<ScDPItemData> ScDPGroupDateFilter::getMatchValues() const
     256             : {
     257           0 :     return std::vector<ScDPItemData>();
     258             : }
     259             : 
     260             : namespace {
     261             : 
     262          72 : bool isDateInGroup(const ScDPItemData& rGroupItem, const ScDPItemData& rChildItem)
     263             : {
     264          72 :     if (rGroupItem.GetType() != ScDPItemData::GroupValue || rChildItem.GetType() != ScDPItemData::GroupValue)
     265           0 :         return false;
     266             : 
     267          72 :     sal_Int32 nGroupPart = rGroupItem.GetGroupValue().mnGroupType;
     268          72 :     sal_Int32 nGroupValue = rGroupItem.GetGroupValue().mnValue;
     269          72 :     sal_Int32 nChildPart = rChildItem.GetGroupValue().mnGroupType;
     270          72 :     sal_Int32 nChildValue = rChildItem.GetGroupValue().mnValue;
     271             : 
     272         144 :     if (nGroupValue == ScDPItemData::DateFirst || nGroupValue == ScDPItemData::DateLast ||
     273         144 :         nChildValue == ScDPItemData::DateFirst || nChildValue == ScDPItemData::DateLast)
     274             :     {
     275             :         // first/last entry matches only itself
     276           0 :         return nGroupValue == nChildValue;
     277             :     }
     278             : 
     279          72 :     switch (nChildPart)        // inner part
     280             :     {
     281             :         case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
     282             :             // a month is only contained in its quarter
     283          56 :             if (nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS)
     284             :                 // months and quarters are both 1-based
     285          28 :                 return (nGroupValue - 1 == (nChildValue - 1) / 3);
     286          28 :             break;
     287             :         case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
     288             :             // a day is only contained in its quarter or month
     289           0 :             if (nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS ||
     290             :                 nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS)
     291             :             {
     292           0 :                 Date aDate(1, 1, SC_DP_LEAPYEAR);
     293           0 :                 aDate += (nChildValue - 1);            // days are 1-based
     294           0 :                 sal_Int32 nCompare = aDate.GetMonth();
     295           0 :                 if (nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS)
     296           0 :                     nCompare = ( ( nCompare - 1 ) / 3 ) + 1;    // get quarter from date
     297             : 
     298           0 :                 return nGroupValue == nCompare;
     299             :             }
     300           0 :             break;
     301             :         default:
     302             :             ;
     303             :     }
     304             : 
     305          44 :     return true;
     306             : }
     307             : 
     308             : }
     309             : 
     310          14 : ScDPGroupItem::ScDPGroupItem( const ScDPItemData& rName ) :
     311          14 :     aGroupName( rName )
     312             : {
     313          14 : }
     314             : 
     315          58 : ScDPGroupItem::~ScDPGroupItem()
     316             : {
     317          58 : }
     318             : 
     319          46 : void ScDPGroupItem::AddElement( const ScDPItemData& rName )
     320             : {
     321          46 :     aElements.push_back( rName );
     322          46 : }
     323             : 
     324         146 : bool ScDPGroupItem::HasElement( const ScDPItemData& rData ) const
     325             : {
     326         444 :     for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
     327         384 :         if ( aIter->IsCaseInsEqual( rData ) )
     328          86 :             return true;
     329             : 
     330          60 :     return false;
     331             : }
     332             : 
     333           0 : bool ScDPGroupItem::HasCommonElement( const ScDPGroupItem& rOther ) const
     334             : {
     335           0 :     for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
     336           0 :         if ( rOther.HasElement( *aIter ) )
     337           0 :             return true;
     338             : 
     339           0 :     return false;
     340             : }
     341             : 
     342           0 : void ScDPGroupItem::FillGroupFilter( ScDPFilteredCache::GroupFilter& rFilter ) const
     343             : {
     344           0 :     ScDPItemDataVec::const_iterator itrEnd = aElements.end();
     345           0 :     for (ScDPItemDataVec::const_iterator itr = aElements.begin(); itr != itrEnd; ++itr)
     346           0 :         rFilter.addMatchItem(*itr);
     347           0 : }
     348             : 
     349          24 : ScDPGroupDimension::ScDPGroupDimension( long nSource, const OUString& rNewName ) :
     350             :     nSourceDim( nSource ),
     351             :     nGroupDim( -1 ),
     352             :     aGroupName( rNewName ),
     353          24 :     mbDateDimension(false)
     354             : {
     355          24 : }
     356             : 
     357         156 : ScDPGroupDimension::~ScDPGroupDimension()
     358             : {
     359          78 :     maMemberEntries.clear();
     360          78 : }
     361             : 
     362          54 : ScDPGroupDimension::ScDPGroupDimension( const ScDPGroupDimension& rOther ) :
     363             :     nSourceDim( rOther.nSourceDim ),
     364             :     nGroupDim( rOther.nGroupDim ),
     365             :     aGroupName( rOther.aGroupName ),
     366             :     aItems( rOther.aItems ),
     367          54 :     mbDateDimension(rOther.mbDateDimension)
     368             : {
     369          54 : }
     370             : 
     371           0 : ScDPGroupDimension& ScDPGroupDimension::operator=( const ScDPGroupDimension& rOther )
     372             : {
     373           0 :     nSourceDim = rOther.nSourceDim;
     374           0 :     nGroupDim  = rOther.nGroupDim;
     375           0 :     aGroupName = rOther.aGroupName;
     376           0 :     aItems     = rOther.aItems;
     377           0 :     mbDateDimension = rOther.mbDateDimension;
     378           0 :     return *this;
     379             : }
     380             : 
     381          14 : void ScDPGroupDimension::AddItem( const ScDPGroupItem& rItem )
     382             : {
     383          14 :     aItems.push_back( rItem );
     384          14 : }
     385             : 
     386          24 : void ScDPGroupDimension::SetGroupDim( long nDim )
     387             : {
     388          24 :     nGroupDim = nDim;
     389          24 : }
     390             : 
     391         108 : const std::vector<SCROW>& ScDPGroupDimension::GetColumnEntries(
     392             :     const ScDPFilteredCache& rCacheTable) const
     393             : {
     394         108 :     if (!maMemberEntries.empty())
     395          84 :         return maMemberEntries;
     396             : 
     397          24 :     rCacheTable.getCache().GetGroupDimMemberIds(nGroupDim, maMemberEntries);
     398          24 :     return maMemberEntries;
     399             : }
     400             : 
     401         130 : const ScDPGroupItem* ScDPGroupDimension::GetGroupForData( const ScDPItemData& rData ) const
     402             : {
     403         190 :     for (ScDPGroupItemVec::const_iterator aIter = aItems.begin(); aIter != aItems.end(); ++aIter)
     404         146 :         if (aIter->HasElement(rData))
     405          86 :             return &*aIter;
     406             : 
     407          44 :     return NULL;
     408             : }
     409             : 
     410           0 : const ScDPGroupItem* ScDPGroupDimension::GetGroupForName( const ScDPItemData& rName ) const
     411             : {
     412           0 :     for ( ScDPGroupItemVec::const_iterator aIter(aItems.begin()); aIter != aItems.end(); ++aIter )
     413           0 :         if ( aIter->GetName().IsCaseInsEqual( rName ) )
     414           0 :             return &*aIter;
     415             : 
     416           0 :     return NULL;
     417             : }
     418             : 
     419           0 : const ScDPGroupItem* ScDPGroupDimension::GetGroupByIndex( size_t nIndex ) const
     420             : {
     421           0 :     if (nIndex >= aItems.size())
     422           0 :         return NULL;
     423             : 
     424           0 :     return &aItems[nIndex];
     425             : }
     426             : 
     427           0 : void ScDPGroupDimension::DisposeData()
     428             : {
     429           0 :     maMemberEntries.clear();
     430           0 : }
     431             : 
     432          12 : void ScDPGroupDimension::SetDateDimension()
     433             : {
     434          12 :     mbDateDimension = true;
     435          12 : }
     436             : 
     437          96 : ScDPNumGroupDimension::ScDPNumGroupDimension() : mbDateDimension(false) {}
     438             : 
     439          10 : ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) :
     440          10 :     aGroupInfo(rInfo), mbDateDimension(false) {}
     441             : 
     442           0 : ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) :
     443           0 :     aGroupInfo(rOther.aGroupInfo), mbDateDimension(rOther.mbDateDimension) {}
     444             : 
     445          10 : ScDPNumGroupDimension& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimension& rOther )
     446             : {
     447          10 :     aGroupInfo = rOther.aGroupInfo;
     448          10 :     mbDateDimension = rOther.mbDateDimension;
     449          10 :     return *this;
     450             : }
     451             : 
     452           0 : void ScDPNumGroupDimension::DisposeData()
     453             : {
     454           0 :     aGroupInfo = ScDPNumGroupInfo();
     455           0 :     maMemberEntries.clear();
     456           0 : }
     457             : 
     458         106 : ScDPNumGroupDimension::~ScDPNumGroupDimension()
     459             : {
     460         106 : }
     461             : 
     462           8 : void ScDPNumGroupDimension::SetDateDimension()
     463             : {
     464           8 :     aGroupInfo.mbEnable = true;   //! or query both?
     465           8 :     mbDateDimension = true;
     466           8 : }
     467             : 
     468          76 : const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries(
     469             :     SCCOL nSourceDim, const ScDPCache* pCache) const
     470             : {
     471          76 :     if (!maMemberEntries.empty())
     472          66 :         return maMemberEntries;
     473             : 
     474          10 :     pCache->GetGroupDimMemberIds(nSourceDim, maMemberEntries);
     475          10 :     return maMemberEntries;
     476             : }
     477             : 
     478          22 : ScDPGroupTableData::ScDPGroupTableData( const shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ) :
     479             :     ScDPTableData(pDocument),
     480             :     pSourceData( pSource ),
     481          22 :     pDoc( pDocument )
     482             : {
     483             :     OSL_ENSURE( pSource, "ScDPGroupTableData: pSource can't be NULL" );
     484             : 
     485          22 :     CreateCacheTable();
     486          22 :     nSourceCount = pSource->GetColumnCount();               // real columns, excluding data layout
     487          22 :     pNumGroups = new ScDPNumGroupDimension[nSourceCount];
     488          22 : }
     489             : 
     490          66 : ScDPGroupTableData::~ScDPGroupTableData()
     491             : {
     492          22 :     delete[] pNumGroups;
     493          44 : }
     494             : 
     495          24 : void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
     496             : {
     497          24 :     ScDPGroupDimension aNewGroup( rGroup );
     498          24 :     aNewGroup.SetGroupDim( GetColumnCount() );      // new dimension will be at the end
     499          24 :     aGroups.push_back( aNewGroup );
     500          24 :     aGroupNames.insert(aNewGroup.GetName());
     501          24 : }
     502             : 
     503          10 : void ScDPGroupTableData::SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup )
     504             : {
     505          10 :     if ( nIndex < nSourceCount )
     506             :     {
     507          10 :         pNumGroups[nIndex] = rGroup;
     508             : 
     509             :         // automatic minimum / maximum is handled in GetNumEntries
     510             :     }
     511          10 : }
     512             : 
     513          34 : long ScDPGroupTableData::GetDimensionIndex( const OUString& rName )
     514             : {
     515          66 :     for (long i = 0; i < nSourceCount; ++i)                         // nSourceCount excludes data layout
     516          66 :         if (pSourceData->getDimensionName(i).equals(rName))        //! ignore case?
     517          34 :             return i;
     518           0 :     return -1;  // none
     519             : }
     520             : 
     521        8412 : long ScDPGroupTableData::GetColumnCount()
     522             : {
     523        8412 :     return nSourceCount + aGroups.size();
     524             : }
     525             : 
     526         454 : bool ScDPGroupTableData::IsNumGroupDimension( long nDimension ) const
     527             : {
     528         454 :     return ( nDimension < nSourceCount && pNumGroups[nDimension].GetInfo().mbEnable );
     529             : }
     530             : 
     531          36 : void ScDPGroupTableData::GetNumGroupInfo(long nDimension, ScDPNumGroupInfo& rInfo)
     532             : {
     533          36 :     if ( nDimension < nSourceCount )
     534          36 :         rInfo = pNumGroups[nDimension].GetInfo();
     535          36 : }
     536          50 : long  ScDPGroupTableData::GetMembersCount( long nDim )
     537             : {
     538          50 :     const std::vector< SCROW >&  members = GetColumnEntries( nDim );
     539          50 :     return members.size();
     540             : }
     541         376 : const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( long  nColumn )
     542             : {
     543         376 :     if ( nColumn >= nSourceCount )
     544             :     {
     545         108 :         if ( getIsDataLayoutDimension( nColumn) )     // data layout dimension?
     546           0 :             nColumn = nSourceCount;                         // index of data layout in source data
     547             :         else
     548             :         {
     549         108 :             const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
     550         108 :             return rGroupDim.GetColumnEntries( GetCacheTable() );
     551             :         }
     552             :     }
     553             : 
     554         268 :     if ( IsNumGroupDimension( nColumn ) )
     555             :     {
     556             :         // dimension number is unchanged for numerical groups
     557             :         return pNumGroups[nColumn].GetNumEntries(
     558          76 :             static_cast<SCCOL>(nColumn), &GetCacheTable().getCache());
     559             :     }
     560             : 
     561         192 :     return pSourceData->GetColumnEntries( nColumn );
     562             : }
     563             : 
     564        3612 : const ScDPItemData* ScDPGroupTableData::GetMemberById( long nDim, long nId )
     565             : {
     566        3612 :     return pSourceData->GetMemberById( nDim, nId );
     567             : }
     568             : 
     569        4094 : OUString ScDPGroupTableData::getDimensionName(long nColumn)
     570             : {
     571        4094 :     if ( nColumn >= nSourceCount )
     572             :     {
     573         806 :         if ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )     // data layout dimension?
     574         254 :             nColumn = nSourceCount;                         // index of data layout in source data
     575             :         else
     576         552 :             return aGroups[nColumn - nSourceCount].GetName();
     577             :     }
     578             : 
     579        3542 :     return pSourceData->getDimensionName( nColumn );
     580             : }
     581             : 
     582        1496 : bool ScDPGroupTableData::getIsDataLayoutDimension(long nColumn)
     583             : {
     584             :     // position of data layout dimension is moved from source data
     585        1496 :     return ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) );    // data layout dimension?
     586             : }
     587             : 
     588         468 : bool ScDPGroupTableData::IsDateDimension(long nDim)
     589             : {
     590         468 :     if ( nDim >= nSourceCount )
     591             :     {
     592         192 :         if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )        // data layout dimension?
     593          72 :             nDim = nSourceCount;                            // index of data layout in source data
     594             :         else
     595         120 :             nDim = aGroups[nDim - nSourceCount].GetSourceDim();  // look at original dimension
     596             :     }
     597             : 
     598         468 :     return pSourceData->IsDateDimension( nDim );
     599             : }
     600             : 
     601         116 : sal_uLong ScDPGroupTableData::GetNumberFormat(long nDim)
     602             : {
     603         116 :     if ( nDim >= nSourceCount )
     604             :     {
     605          38 :         if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )        // data layout dimension?
     606          18 :             nDim = nSourceCount;                            // index of data layout in source data
     607             :         else
     608          20 :             nDim = aGroups[nDim - nSourceCount].GetSourceDim();  // look at original dimension
     609             :     }
     610             : 
     611         116 :     return pSourceData->GetNumberFormat( nDim );
     612             : }
     613             : 
     614           0 : void ScDPGroupTableData::DisposeData()
     615             : {
     616           0 :     for ( ScDPGroupDimensionVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     617           0 :         aIter->DisposeData();
     618             : 
     619           0 :     for ( long i=0; i<nSourceCount; i++ )
     620           0 :         pNumGroups[i].DisposeData();
     621             : 
     622           0 :     pSourceData->DisposeData();
     623           0 : }
     624             : 
     625          80 : void ScDPGroupTableData::SetEmptyFlags( bool bIgnoreEmptyRows, bool bRepeatIfEmpty )
     626             : {
     627          80 :     pSourceData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
     628          80 : }
     629             : 
     630         318 : bool ScDPGroupTableData::IsRepeatIfEmpty()
     631             : {
     632         318 :     return pSourceData->IsRepeatIfEmpty();
     633             : }
     634             : 
     635          22 : void ScDPGroupTableData::CreateCacheTable()
     636             : {
     637          22 :     pSourceData->CreateCacheTable();
     638          22 : }
     639             : 
     640             : namespace {
     641             : 
     642           0 : class FindCaseInsensitive : std::unary_function<ScDPItemData, bool>
     643             : {
     644             :     ScDPItemData maValue;
     645             : public:
     646           0 :     FindCaseInsensitive(const ScDPItemData& rVal) : maValue(rVal) {}
     647             : 
     648           0 :     bool operator() (const ScDPItemData& rItem) const
     649             :     {
     650           0 :         return maValue.IsCaseInsEqual(rItem);
     651             :     }
     652             : };
     653             : 
     654             : }
     655             : 
     656           0 : void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPFilteredCache::Criterion>& rCriteria)
     657             : {
     658             :     // Build dimension ID to object map for group dimensions.
     659             :     typedef boost::unordered_map<long, const ScDPGroupDimension*> GroupFieldMapType;
     660           0 :     GroupFieldMapType aGroupFieldIds;
     661             :     {
     662           0 :         ScDPGroupDimensionVec::const_iterator itr = aGroups.begin(), itrEnd = aGroups.end();
     663           0 :         for (; itr != itrEnd; ++itr)
     664             :         {
     665             :             aGroupFieldIds.insert(
     666           0 :                 GroupFieldMapType::value_type(itr->GetGroupDim(), &(*itr)));
     667             :         }
     668             :     }
     669             : 
     670           0 :     vector<ScDPFilteredCache::Criterion> aNewCriteria;
     671           0 :     aNewCriteria.reserve(rCriteria.size() + aGroups.size());
     672             : 
     673             :     // Go through all the filtered field names and process them appropriately.
     674             : 
     675           0 :     const ScDPCache& rCache = GetCacheTable().getCache();
     676           0 :     vector<ScDPFilteredCache::Criterion>::const_iterator itrEnd = rCriteria.end();
     677           0 :     GroupFieldMapType::const_iterator itrGrpEnd = aGroupFieldIds.end();
     678           0 :     for (vector<ScDPFilteredCache::Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
     679             :     {
     680           0 :         std::vector<ScDPItemData> aMatchValues = itr->mpFilter->getMatchValues();
     681             : 
     682           0 :         GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(itr->mnFieldIndex);
     683           0 :         if (itrGrp == itrGrpEnd)
     684             :         {
     685           0 :             if (IsNumGroupDimension(itr->mnFieldIndex))
     686             :             {
     687             :                 // internal number group field
     688           0 :                 const ScDPNumGroupInfo* pNumInfo = rCache.GetNumGroupInfo(itr->mnFieldIndex);
     689           0 :                 if (!pNumInfo)
     690             :                     // Number group dimension without num info?  Something is wrong...
     691           0 :                     continue;
     692             : 
     693           0 :                 ScDPFilteredCache::Criterion aCri;
     694           0 :                 aCri.mnFieldIndex = itr->mnFieldIndex;
     695           0 :                 const ScDPNumGroupDimension& rNumGrpDim = pNumGroups[itr->mnFieldIndex];
     696             : 
     697           0 :                 if (rNumGrpDim.IsDateDimension())
     698             :                 {
     699             :                     // grouped by dates.
     700             :                     aCri.mpFilter.reset(
     701             :                         new ScDPGroupDateFilter(
     702           0 :                             aMatchValues, *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
     703             :                 }
     704             :                 else
     705             :                 {
     706             :                     // This dimension is grouped by numeric ranges.
     707             :                     aCri.mpFilter.reset(
     708           0 :                         new ScDPGroupNumFilter(aMatchValues, *pNumInfo));
     709             :                 }
     710             : 
     711           0 :                 aNewCriteria.push_back(aCri);
     712             :             }
     713             :             else
     714             :             {
     715             :                 // This is a regular source field.
     716           0 :                 aNewCriteria.push_back(*itr);
     717             :             }
     718             :         }
     719             :         else
     720             :         {
     721             :             // This is an ordinary group field or external number group field.
     722             : 
     723           0 :             const ScDPGroupDimension* pGrpDim = itrGrp->second;
     724           0 :             long nSrcDim = pGrpDim->GetSourceDim();
     725           0 :             long nGrpDim = pGrpDim->GetGroupDim();
     726           0 :             const ScDPNumGroupInfo* pNumInfo = rCache.GetNumGroupInfo(nGrpDim);
     727             : 
     728           0 :             if (pGrpDim->IsDateDimension() && pNumInfo)
     729             :             {
     730             :                 // external number group
     731           0 :                 ScDPFilteredCache::Criterion aCri;
     732           0 :                 aCri.mnFieldIndex = nSrcDim;  // use the source dimension, not the group dimension.
     733             :                 aCri.mpFilter.reset(
     734             :                     new ScDPGroupDateFilter(
     735           0 :                         aMatchValues, *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
     736             : 
     737           0 :                 aNewCriteria.push_back(aCri);
     738             :             }
     739             :             else
     740             :             {
     741             :                 // normal group
     742             : 
     743           0 :                 ScDPFilteredCache::Criterion aCri;
     744           0 :                 aCri.mnFieldIndex = nSrcDim;
     745           0 :                 aCri.mpFilter.reset(new ScDPFilteredCache::GroupFilter());
     746             :                 ScDPFilteredCache::GroupFilter* pGrpFilter =
     747           0 :                     static_cast<ScDPFilteredCache::GroupFilter*>(aCri.mpFilter.get());
     748             : 
     749           0 :                 size_t nGroupItemCount = pGrpDim->GetItemCount();
     750           0 :                 for (size_t i = 0; i < nGroupItemCount; ++i)
     751             :                 {
     752           0 :                     const ScDPGroupItem* pGrpItem = pGrpDim->GetGroupByIndex(i);
     753           0 :                     if (!pGrpItem)
     754           0 :                         continue;
     755             : 
     756             :                     // Make sure this group name equals one of the match values.
     757             :                     std::vector<ScDPItemData>::iterator it =
     758             :                         std::find_if(
     759           0 :                             aMatchValues.begin(), aMatchValues.end(), FindCaseInsensitive(pGrpItem->GetName()));
     760             : 
     761           0 :                     if (it == aMatchValues.end())
     762           0 :                         continue;
     763             : 
     764           0 :                     pGrpItem->FillGroupFilter(*pGrpFilter);
     765             :                 }
     766             : 
     767           0 :                 aNewCriteria.push_back(aCri);
     768             :             }
     769             :         }
     770           0 :     }
     771           0 :     rCriteria.swap(aNewCriteria);
     772           0 : }
     773             : 
     774           0 : void ScDPGroupTableData::FilterCacheTable(const vector<ScDPFilteredCache::Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rCatDims)
     775             : {
     776           0 :     vector<ScDPFilteredCache::Criterion> aNewCriteria(rCriteria);
     777           0 :     ModifyFilterCriteria(aNewCriteria);
     778           0 :     pSourceData->FilterCacheTable(aNewCriteria, rCatDims);
     779           0 : }
     780             : 
     781           0 : void ScDPGroupTableData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
     782             : {
     783           0 :     vector<ScDPFilteredCache::Criterion> aNewCriteria(rCriteria);
     784           0 :     ModifyFilterCriteria(aNewCriteria);
     785           0 :     pSourceData->GetDrillDownData(aNewCriteria, rCatDims, rData);
     786           0 : }
     787             : 
     788          18 : void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
     789             : {
     790             :     // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods
     791             :     // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called
     792             :     // with original rInfo, containing dimension indexes of the grouped data.
     793             : 
     794          18 :     const ScDPFilteredCache& rCacheTable = pSourceData->GetCacheTable();
     795          18 :     sal_Int32 nRowSize = rCacheTable.getRowSize();
     796         154 :     for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
     797             :     {
     798             :         sal_Int32 nLastRow;
     799         136 :         if (!rCacheTable.isRowActive(nRow, &nLastRow))
     800             :         {
     801           0 :             nRow = nLastRow;
     802           0 :             continue;
     803             :         }
     804             : 
     805         136 :         CalcRowData aData;
     806         136 :         FillRowDataFromCacheTable(nRow, rCacheTable, rInfo, aData);
     807             : 
     808         136 :         if ( !rInfo.aColLevelDims.empty() )
     809          40 :             FillGroupValues(aData.aColData, rInfo.aColLevelDims);
     810         136 :         if ( !rInfo.aRowLevelDims.empty() )
     811         136 :             FillGroupValues(aData.aRowData, rInfo.aRowLevelDims);
     812         136 :         if ( !rInfo.aPageDims.empty() )
     813          10 :             FillGroupValues(aData.aPageData, rInfo.aPageDims);
     814             : 
     815         136 :         ProcessRowData(rInfo, aData, bAutoShow);
     816         136 :     }
     817          18 : }
     818             : 
     819        2898 : const ScDPFilteredCache& ScDPGroupTableData::GetCacheTable() const
     820             : {
     821        2898 :     return pSourceData->GetCacheTable();
     822             : }
     823             : 
     824          26 : void ScDPGroupTableData::ReloadCacheTable()
     825             : {
     826          26 :     pSourceData->ReloadCacheTable();
     827          26 : }
     828             : 
     829         186 : void ScDPGroupTableData::FillGroupValues(vector<SCROW>& rItems, const vector<long>& rDims)
     830             : {
     831         186 :     long nGroupedColumns = aGroups.size();
     832             : 
     833         186 :     const ScDPCache& rCache = GetCacheTable().getCache();
     834         186 :     vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
     835         504 :     for (size_t i = 0; it != itEnd; ++it, ++i)
     836             :     {
     837         318 :         long nColumn = *it;
     838         318 :         bool bDateDim = false;
     839             : 
     840         318 :         long nSourceDim = nColumn;
     841         318 :         if ( nColumn >= nSourceCount && nColumn < nSourceCount + nGroupedColumns )
     842             :         {
     843         132 :             const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
     844         132 :             nSourceDim= rGroupDim.GetSourceDim();
     845         132 :             bDateDim = rGroupDim.IsDateDimension();
     846         132 :             if (!bDateDim)                         // date is handled below
     847             :             {
     848          68 :                 const ScDPItemData& rItem = *GetMemberById(nSourceDim, rItems[i]);
     849          68 :                 const ScDPGroupItem* pGroupItem = rGroupDim.GetGroupForData(rItem);
     850          68 :                 if (pGroupItem)
     851             :                 {
     852          46 :                     rItems[i] =
     853          46 :                         rCache.GetIdByItemData(nColumn, pGroupItem->GetName());
     854             :                 }
     855             :                 else
     856          22 :                     rItems[i] = rCache.GetIdByItemData(nColumn, rItem);
     857         132 :             }
     858             :         }
     859         186 :         else if ( IsNumGroupDimension( nColumn ) )
     860             :         {
     861          68 :             bDateDim = pNumGroups[nColumn].IsDateDimension();
     862          68 :             if (!bDateDim)                         // date is handled below
     863             :             {
     864          36 :                 const ScDPItemData* pData = rCache.GetItemDataById(nSourceDim, rItems[i]);
     865          36 :                 if (pData->GetType() == ScDPItemData::Value)
     866             :                 {
     867          36 :                     ScDPNumGroupInfo aNumInfo;
     868          36 :                     GetNumGroupInfo(nColumn, aNumInfo);
     869          36 :                     double fGroupValue = ScDPUtil::getNumGroupStartValue(pData->GetValue(), aNumInfo);
     870          36 :                     ScDPItemData aItemData;
     871          36 :                     aItemData.SetRangeStart(fGroupValue);
     872          36 :                     rItems[i] = rCache.GetIdByItemData(nSourceDim, aItemData);
     873             :                 }
     874             :                 // else (textual) keep original value
     875             :             }
     876             :         }
     877             : 
     878         318 :         const ScDPNumGroupInfo* pNumInfo = rCache.GetNumGroupInfo(nColumn);
     879             : 
     880         318 :         if (bDateDim && pNumInfo)
     881             :         {
     882             :             // This is a date group dimension.
     883          96 :             sal_Int32 nDatePart = rCache.GetGroupType(nColumn);
     884          96 :             const ScDPItemData* pData = rCache.GetItemDataById(nSourceDim, rItems[i]);
     885          96 :             if (pData->GetType() == ScDPItemData::Value)
     886             :             {
     887          96 :                 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
     888             :                 sal_Int32 nPartValue = ScDPUtil::getDatePartValue(
     889          96 :                     pData->GetValue(), pNumInfo, nDatePart, pFormatter);
     890             : 
     891          96 :                 ScDPItemData aItem(nDatePart, nPartValue);
     892          96 :                 rItems[i] = rCache.GetIdByItemData(nColumn, aItem);
     893             :             }
     894             :         }
     895             :     }
     896         186 : }
     897             : 
     898         150 : bool ScDPGroupTableData::IsBaseForGroup(long nDim) const
     899             : {
     900         242 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     901             :     {
     902         184 :         const ScDPGroupDimension& rDim = *aIter;
     903         184 :         if ( rDim.GetSourceDim() == nDim )
     904          92 :             return true;
     905             :     }
     906             : 
     907          58 :     return false;
     908             : }
     909             : 
     910         284 : long ScDPGroupTableData::GetGroupBase(long nGroupDim) const
     911             : {
     912         464 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     913             :     {
     914         362 :         const ScDPGroupDimension& rDim = *aIter;
     915         362 :         if ( rDim.GetGroupDim() == nGroupDim )
     916         182 :             return rDim.GetSourceDim();
     917             :     }
     918             : 
     919         102 :     return -1;      // none
     920             : }
     921             : 
     922          88 : bool ScDPGroupTableData::IsNumOrDateGroup(long nDimension) const
     923             : {
     924             :     // Virtual method from ScDPTableData, used in result data to force text labels.
     925             : 
     926          88 :     if ( nDimension < nSourceCount )
     927             :     {
     928         120 :         return pNumGroups[nDimension].GetInfo().mbEnable ||
     929         120 :                pNumGroups[nDimension].IsDateDimension();
     930             :     }
     931             : 
     932          24 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     933             :     {
     934          24 :         const ScDPGroupDimension& rDim = *aIter;
     935          24 :         if ( rDim.GetGroupDim() == nDimension )
     936          18 :             return rDim.IsDateDimension();
     937             :     }
     938             : 
     939           0 :     return false;
     940             : }
     941             : 
     942         118 : bool ScDPGroupTableData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
     943             :                                     const ScDPItemData& rBaseData, long nBaseIndex ) const
     944             : {
     945         146 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     946             :     {
     947         146 :         const ScDPGroupDimension& rDim = *aIter;
     948         146 :         if ( rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex )
     949             :         {
     950         118 :             if (rDim.IsDateDimension())
     951             :             {
     952         174 :                 return isDateInGroup(rGroupData, rBaseData);
     953             :             }
     954             :             else
     955             :             {
     956             :                 // If the item is in a group, only that group is valid.
     957             :                 // If the item is not in any group, its own name is valid.
     958             : 
     959          62 :                 const ScDPGroupItem* pGroup = rDim.GetGroupForData( rBaseData );
     960          40 :                 return pGroup ? pGroup->GetName().IsCaseInsEqual( rGroupData ) :
     961         102 :                                 rGroupData.IsCaseInsEqual( rBaseData );
     962             :             }
     963             :         }
     964             :     }
     965             : 
     966             :     OSL_FAIL("IsInGroup: no group dimension found");
     967           0 :     return true;
     968             : }
     969             : 
     970          16 : bool ScDPGroupTableData::HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex,
     971             :                                          const ScDPItemData& rSecondData, long nSecondIndex ) const
     972             : {
     973          16 :     const ScDPGroupDimension* pFirstDim = NULL;
     974          16 :     const ScDPGroupDimension* pSecondDim = NULL;
     975          48 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     976             :     {
     977          32 :         const ScDPGroupDimension* pDim = &(*aIter);
     978          32 :         if ( pDim->GetGroupDim() == nFirstIndex )
     979          16 :             pFirstDim = pDim;
     980          16 :         else if ( pDim->GetGroupDim() == nSecondIndex )
     981          16 :             pSecondDim = pDim;
     982             :     }
     983          16 :     if ( pFirstDim && pSecondDim )
     984             :     {
     985          16 :         bool bFirstDate = pFirstDim->IsDateDimension();
     986          16 :         bool bSecondDate = pSecondDim->IsDateDimension();
     987          16 :         if (bFirstDate || bSecondDate)
     988             :         {
     989             :             // If one is a date group dimension, the other one must be, too.
     990          16 :             if (!bFirstDate || !bSecondDate)
     991             :             {
     992             :                 OSL_FAIL( "mix of date and non-date groups" );
     993           0 :                 return true;
     994             :             }
     995             : 
     996          16 :             return isDateInGroup(rFirstData, rSecondData);
     997             :         }
     998             : 
     999           0 :         const ScDPGroupItem* pFirstItem = pFirstDim->GetGroupForName( rFirstData );
    1000           0 :         const ScDPGroupItem* pSecondItem = pSecondDim->GetGroupForName( rSecondData );
    1001           0 :         if ( pFirstItem && pSecondItem )
    1002             :         {
    1003             :             // two existing groups -> sal_True if they have a common element
    1004           0 :             return pFirstItem->HasCommonElement( *pSecondItem );
    1005             :         }
    1006           0 :         else if ( pFirstItem )
    1007             :         {
    1008             :             // "automatic" group contains only its own name
    1009           0 :             return pFirstItem->HasElement( rSecondData );
    1010             :         }
    1011           0 :         else if ( pSecondItem )
    1012             :         {
    1013             :             // "automatic" group contains only its own name
    1014           0 :             return pSecondItem->HasElement( rFirstData );
    1015             :         }
    1016             :         else
    1017             :         {
    1018             :             // no groups -> sal_True if equal
    1019           0 :             return rFirstData.IsCaseInsEqual( rSecondData );
    1020             :         }
    1021             :     }
    1022             : 
    1023             :     OSL_FAIL("HasCommonElement: no group dimension found");
    1024           0 :     return true;
    1025             : }
    1026             : 
    1027         318 : long ScDPGroupTableData::GetSourceDim( long nDim )
    1028             : {
    1029         318 :     if ( getIsDataLayoutDimension( nDim ) )
    1030           0 :         return nSourceCount;
    1031         318 :     if (  nDim >= nSourceCount && nDim < nSourceCount +(long) aGroups.size()  )
    1032             :     {
    1033         132 :          const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
    1034         132 :             return  rGroupDim.GetSourceDim();
    1035             :     }
    1036         186 :     return nDim;
    1037             : }
    1038             : 
    1039         378 : long ScDPGroupTableData::Compare(long nDim, long nDataId1, long nDataId2)
    1040             : {
    1041         378 :     if ( getIsDataLayoutDimension(nDim) )
    1042           0 :         return 0;
    1043         378 :     return ScDPItemData::Compare( *GetMemberById(nDim,  nDataId1),*GetMemberById(nDim,  nDataId2) );
    1044         228 : }
    1045             : 
    1046             : #if DEBUG_PIVOT_TABLE
    1047             : using std::cout;
    1048             : using std::endl;
    1049             : 
    1050             : void ScDPGroupTableData::Dump() const
    1051             : {
    1052             :     cout << "--- ScDPGroupTableData" << endl;
    1053             :     for (long i = 0; i < nSourceCount; ++i)
    1054             :     {
    1055             :         cout << "* dimension: " << i << endl;
    1056             :         const ScDPNumGroupDimension& rGrp = pNumGroups[i];
    1057             :         rGrp.GetInfo().Dump();
    1058             :     }
    1059             :     cout << "---" << endl;
    1060             : }
    1061             : #endif
    1062             : 
    1063             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10