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

Generated by: LCOV version 1.11