LCOV - code coverage report
Current view: top level - sc/source/core/data - dpgroup.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 267 490 54.5 %
Date: 2014-04-11 Functions: 54 80 67.5 %
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             :     ScDPGroupDateFilter(); // disabled
     123             : 
     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             : 
     289             :         case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
     290             :             // a day is only contained in its quarter or month
     291          14 :             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          14 :             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         150 : bool ScDPGroupDimension::IsDateDimension() const
     440             : {
     441         150 :     return mbDateDimension;
     442             : }
     443             : 
     444          48 : ScDPNumGroupDimension::ScDPNumGroupDimension() : mbDateDimension(false) {}
     445             : 
     446           5 : ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) :
     447           5 :     aGroupInfo(rInfo), mbDateDimension(false) {}
     448             : 
     449           0 : ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) :
     450           0 :     aGroupInfo(rOther.aGroupInfo), mbDateDimension(rOther.mbDateDimension) {}
     451             : 
     452           5 : ScDPNumGroupDimension& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimension& rOther )
     453             : {
     454           5 :     aGroupInfo = rOther.aGroupInfo;
     455           5 :     mbDateDimension = rOther.mbDateDimension;
     456           5 :     return *this;
     457             : }
     458             : 
     459           0 : void ScDPNumGroupDimension::DisposeData()
     460             : {
     461           0 :     aGroupInfo = ScDPNumGroupInfo();
     462           0 :     maMemberEntries.clear();
     463           0 : }
     464             : 
     465          59 : bool ScDPNumGroupDimension::IsDateDimension() const
     466             : {
     467          59 :     return mbDateDimension;
     468             : }
     469             : 
     470          53 : ScDPNumGroupDimension::~ScDPNumGroupDimension()
     471             : {
     472          53 : }
     473             : 
     474           4 : void ScDPNumGroupDimension::SetDateDimension()
     475             : {
     476           4 :     aGroupInfo.mbEnable = true;   //! or query both?
     477           4 :     mbDateDimension = true;
     478           4 : }
     479             : 
     480          38 : const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries(
     481             :     SCCOL nSourceDim, const ScDPCache* pCache) const
     482             : {
     483          38 :     if (!maMemberEntries.empty())
     484          33 :         return maMemberEntries;
     485             : 
     486           5 :     pCache->GetGroupDimMemberIds(nSourceDim, maMemberEntries);
     487           5 :     return maMemberEntries;
     488             : }
     489             : 
     490          11 : ScDPGroupTableData::ScDPGroupTableData( const shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ) :
     491             :     ScDPTableData(pDocument),
     492             :     pSourceData( pSource ),
     493          11 :     pDoc( pDocument )
     494             : {
     495             :     OSL_ENSURE( pSource, "ScDPGroupTableData: pSource can't be NULL" );
     496             : 
     497          11 :     CreateCacheTable();
     498          11 :     nSourceCount = pSource->GetColumnCount();               // real columns, excluding data layout
     499          11 :     pNumGroups = new ScDPNumGroupDimension[nSourceCount];
     500          11 : }
     501             : 
     502          33 : ScDPGroupTableData::~ScDPGroupTableData()
     503             : {
     504          11 :     delete[] pNumGroups;
     505          22 : }
     506             : 
     507           3 : boost::shared_ptr<ScDPTableData> ScDPGroupTableData::GetSourceTableData()
     508             : {
     509           3 :     return pSourceData;
     510             : }
     511             : 
     512          12 : void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
     513             : {
     514          12 :     ScDPGroupDimension aNewGroup( rGroup );
     515          12 :     aNewGroup.SetGroupDim( GetColumnCount() );      // new dimension will be at the end
     516          12 :     aGroups.push_back( aNewGroup );
     517          12 :     aGroupNames.insert(aNewGroup.GetName());
     518          12 : }
     519             : 
     520           5 : void ScDPGroupTableData::SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup )
     521             : {
     522           5 :     if ( nIndex < nSourceCount )
     523             :     {
     524           5 :         pNumGroups[nIndex] = rGroup;
     525             : 
     526             :         // automatic minimum / maximum is handled in GetNumEntries
     527             :     }
     528           5 : }
     529             : 
     530          17 : long ScDPGroupTableData::GetDimensionIndex( const OUString& rName )
     531             : {
     532          33 :     for (long i = 0; i < nSourceCount; ++i)                         // nSourceCount excludes data layout
     533          33 :         if (pSourceData->getDimensionName(i).equals(rName))        //! ignore case?
     534          17 :             return i;
     535           0 :     return -1;  // none
     536             : }
     537             : 
     538        4206 : long ScDPGroupTableData::GetColumnCount()
     539             : {
     540        4206 :     return nSourceCount + aGroups.size();
     541             : }
     542             : 
     543         227 : bool ScDPGroupTableData::IsNumGroupDimension( long nDimension ) const
     544             : {
     545         227 :     return ( nDimension < nSourceCount && pNumGroups[nDimension].GetInfo().mbEnable );
     546             : }
     547             : 
     548          18 : void ScDPGroupTableData::GetNumGroupInfo(long nDimension, ScDPNumGroupInfo& rInfo)
     549             : {
     550          18 :     if ( nDimension < nSourceCount )
     551          18 :         rInfo = pNumGroups[nDimension].GetInfo();
     552          18 : }
     553          25 : long  ScDPGroupTableData::GetMembersCount( long nDim )
     554             : {
     555          25 :     const std::vector< SCROW >&  members = GetColumnEntries( nDim );
     556          25 :     return members.size();
     557             : }
     558         188 : const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( long  nColumn )
     559             : {
     560         188 :     if ( nColumn >= nSourceCount )
     561             :     {
     562          54 :         if ( getIsDataLayoutDimension( nColumn) )     // data layout dimension?
     563           0 :             nColumn = nSourceCount;                         // index of data layout in source data
     564             :         else
     565             :         {
     566          54 :             const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
     567          54 :             return rGroupDim.GetColumnEntries( GetCacheTable() );
     568             :         }
     569             :     }
     570             : 
     571         134 :     if ( IsNumGroupDimension( nColumn ) )
     572             :     {
     573             :         // dimension number is unchanged for numerical groups
     574             :         return pNumGroups[nColumn].GetNumEntries(
     575          38 :             static_cast<SCCOL>(nColumn), GetCacheTable().getCache());
     576             :     }
     577             : 
     578          96 :     return pSourceData->GetColumnEntries( nColumn );
     579             : }
     580             : 
     581        1806 : const ScDPItemData* ScDPGroupTableData::GetMemberById( long nDim, long nId )
     582             : {
     583        1806 :     return pSourceData->GetMemberById( nDim, nId );
     584             : }
     585             : 
     586        2047 : OUString ScDPGroupTableData::getDimensionName(long nColumn)
     587             : {
     588        2047 :     if ( nColumn >= nSourceCount )
     589             :     {
     590         403 :         if ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )     // data layout dimension?
     591         127 :             nColumn = nSourceCount;                         // index of data layout in source data
     592             :         else
     593         276 :             return aGroups[nColumn - nSourceCount].GetName();
     594             :     }
     595             : 
     596        1771 :     return pSourceData->getDimensionName( nColumn );
     597             : }
     598             : 
     599         748 : bool ScDPGroupTableData::getIsDataLayoutDimension(long nColumn)
     600             : {
     601             :     // position of data layout dimension is moved from source data
     602         748 :     return ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) );    // data layout dimension?
     603             : }
     604             : 
     605         234 : bool ScDPGroupTableData::IsDateDimension(long nDim)
     606             : {
     607         234 :     if ( nDim >= nSourceCount )
     608             :     {
     609          96 :         if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )        // data layout dimension?
     610          36 :             nDim = nSourceCount;                            // index of data layout in source data
     611             :         else
     612          60 :             nDim = aGroups[nDim - nSourceCount].GetSourceDim();  // look at original dimension
     613             :     }
     614             : 
     615         234 :     return pSourceData->IsDateDimension( nDim );
     616             : }
     617             : 
     618          58 : sal_uLong ScDPGroupTableData::GetNumberFormat(long nDim)
     619             : {
     620          58 :     if ( nDim >= nSourceCount )
     621             :     {
     622          19 :         if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )        // data layout dimension?
     623           9 :             nDim = nSourceCount;                            // index of data layout in source data
     624             :         else
     625          10 :             nDim = aGroups[nDim - nSourceCount].GetSourceDim();  // look at original dimension
     626             :     }
     627             : 
     628          58 :     return pSourceData->GetNumberFormat( nDim );
     629             : }
     630             : 
     631           0 : void ScDPGroupTableData::DisposeData()
     632             : {
     633           0 :     for ( ScDPGroupDimensionVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     634           0 :         aIter->DisposeData();
     635             : 
     636           0 :     for ( long i=0; i<nSourceCount; i++ )
     637           0 :         pNumGroups[i].DisposeData();
     638             : 
     639           0 :     pSourceData->DisposeData();
     640           0 : }
     641             : 
     642          40 : void ScDPGroupTableData::SetEmptyFlags( bool bIgnoreEmptyRows, bool bRepeatIfEmpty )
     643             : {
     644          40 :     pSourceData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
     645          40 : }
     646             : 
     647         159 : bool ScDPGroupTableData::IsRepeatIfEmpty()
     648             : {
     649         159 :     return pSourceData->IsRepeatIfEmpty();
     650             : }
     651             : 
     652          11 : void ScDPGroupTableData::CreateCacheTable()
     653             : {
     654          11 :     pSourceData->CreateCacheTable();
     655          11 : }
     656             : 
     657             : namespace {
     658             : 
     659           0 : class FindCaseInsensitive : std::unary_function<ScDPItemData, bool>
     660             : {
     661             :     ScDPItemData maValue;
     662             : public:
     663           0 :     FindCaseInsensitive(const ScDPItemData& rVal) : maValue(rVal) {}
     664             : 
     665           0 :     bool operator() (const ScDPItemData& rItem) const
     666             :     {
     667           0 :         return maValue.IsCaseInsEqual(rItem);
     668             :     }
     669             : };
     670             : 
     671             : }
     672             : 
     673           0 : void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPFilteredCache::Criterion>& rCriteria)
     674             : {
     675             :     // Build dimension ID to object map for group dimensions.
     676             :     typedef boost::unordered_map<long, const ScDPGroupDimension*> GroupFieldMapType;
     677           0 :     GroupFieldMapType aGroupFieldIds;
     678             :     {
     679           0 :         ScDPGroupDimensionVec::const_iterator itr = aGroups.begin(), itrEnd = aGroups.end();
     680           0 :         for (; itr != itrEnd; ++itr)
     681             :         {
     682             :             aGroupFieldIds.insert(
     683           0 :                 GroupFieldMapType::value_type(itr->GetGroupDim(), &(*itr)));
     684             :         }
     685             :     }
     686             : 
     687           0 :     vector<ScDPFilteredCache::Criterion> aNewCriteria;
     688           0 :     aNewCriteria.reserve(rCriteria.size() + aGroups.size());
     689             : 
     690             :     // Go through all the filtered field names and process them appropriately.
     691             : 
     692           0 :     const ScDPCache* pCache = GetCacheTable().getCache();
     693           0 :     vector<ScDPFilteredCache::Criterion>::const_iterator itrEnd = rCriteria.end();
     694           0 :     GroupFieldMapType::const_iterator itrGrpEnd = aGroupFieldIds.end();
     695           0 :     for (vector<ScDPFilteredCache::Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
     696             :     {
     697           0 :         std::vector<ScDPItemData> aMatchValues = itr->mpFilter->getMatchValues();
     698             : 
     699           0 :         GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(itr->mnFieldIndex);
     700           0 :         if (itrGrp == itrGrpEnd)
     701             :         {
     702           0 :             if (IsNumGroupDimension(itr->mnFieldIndex))
     703             :             {
     704             :                 // internal number group field
     705           0 :                 const ScDPNumGroupInfo* pNumInfo = pCache->GetNumGroupInfo(itr->mnFieldIndex);
     706           0 :                 if (!pNumInfo)
     707             :                     // Number group dimension without num info?  Something is wrong...
     708           0 :                     continue;
     709             : 
     710           0 :                 ScDPFilteredCache::Criterion aCri;
     711           0 :                 aCri.mnFieldIndex = itr->mnFieldIndex;
     712           0 :                 const ScDPNumGroupDimension& rNumGrpDim = pNumGroups[itr->mnFieldIndex];
     713             : 
     714           0 :                 if (rNumGrpDim.IsDateDimension())
     715             :                 {
     716             :                     // grouped by dates.
     717             :                     aCri.mpFilter.reset(
     718             :                         new ScDPGroupDateFilter(
     719           0 :                             aMatchValues, *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
     720             :                 }
     721             :                 else
     722             :                 {
     723             :                     // This dimension is grouped by numeric ranges.
     724             :                     aCri.mpFilter.reset(
     725           0 :                         new ScDPGroupNumFilter(aMatchValues, *pNumInfo));
     726             :                 }
     727             : 
     728           0 :                 aNewCriteria.push_back(aCri);
     729             :             }
     730             :             else
     731             :             {
     732             :                 // This is a regular source field.
     733           0 :                 aNewCriteria.push_back(*itr);
     734             :             }
     735             :         }
     736             :         else
     737             :         {
     738             :             // This is an ordinary group field or external number group field.
     739             : 
     740           0 :             const ScDPGroupDimension* pGrpDim = itrGrp->second;
     741           0 :             long nSrcDim = pGrpDim->GetSourceDim();
     742           0 :             long nGrpDim = pGrpDim->GetGroupDim();
     743           0 :             const ScDPNumGroupInfo* pNumInfo = pCache->GetNumGroupInfo(nGrpDim);
     744             : 
     745           0 :             if (pGrpDim->IsDateDimension() && pNumInfo)
     746             :             {
     747             :                 // external number group
     748           0 :                 ScDPFilteredCache::Criterion aCri;
     749           0 :                 aCri.mnFieldIndex = nSrcDim;  // use the source dimension, not the group dimension.
     750             :                 aCri.mpFilter.reset(
     751             :                     new ScDPGroupDateFilter(
     752           0 :                         aMatchValues, *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
     753             : 
     754           0 :                 aNewCriteria.push_back(aCri);
     755             :             }
     756             :             else
     757             :             {
     758             :                 // normal group
     759             : 
     760           0 :                 ScDPFilteredCache::Criterion aCri;
     761           0 :                 aCri.mnFieldIndex = nSrcDim;
     762           0 :                 aCri.mpFilter.reset(new ScDPFilteredCache::GroupFilter());
     763             :                 ScDPFilteredCache::GroupFilter* pGrpFilter =
     764           0 :                     static_cast<ScDPFilteredCache::GroupFilter*>(aCri.mpFilter.get());
     765             : 
     766           0 :                 size_t nGroupItemCount = pGrpDim->GetItemCount();
     767           0 :                 for (size_t i = 0; i < nGroupItemCount; ++i)
     768             :                 {
     769           0 :                     const ScDPGroupItem* pGrpItem = pGrpDim->GetGroupByIndex(i);
     770           0 :                     if (!pGrpItem)
     771           0 :                         continue;
     772             : 
     773             :                     // Make sure this group name equals one of the match values.
     774             :                     std::vector<ScDPItemData>::iterator it =
     775             :                         std::find_if(
     776           0 :                             aMatchValues.begin(), aMatchValues.end(), FindCaseInsensitive(pGrpItem->GetName()));
     777             : 
     778           0 :                     if (it == aMatchValues.end())
     779           0 :                         continue;
     780             : 
     781           0 :                     pGrpItem->FillGroupFilter(*pGrpFilter);
     782             :                 }
     783             : 
     784           0 :                 aNewCriteria.push_back(aCri);
     785             :             }
     786             :         }
     787           0 :     }
     788           0 :     rCriteria.swap(aNewCriteria);
     789           0 : }
     790             : 
     791           0 : void ScDPGroupTableData::FilterCacheTable(const vector<ScDPFilteredCache::Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rCatDims)
     792             : {
     793           0 :     vector<ScDPFilteredCache::Criterion> aNewCriteria(rCriteria);
     794           0 :     ModifyFilterCriteria(aNewCriteria);
     795           0 :     pSourceData->FilterCacheTable(aNewCriteria, rCatDims);
     796           0 : }
     797             : 
     798           0 : void ScDPGroupTableData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
     799             : {
     800           0 :     vector<ScDPFilteredCache::Criterion> aNewCriteria(rCriteria);
     801           0 :     ModifyFilterCriteria(aNewCriteria);
     802           0 :     pSourceData->GetDrillDownData(aNewCriteria, rCatDims, rData);
     803           0 : }
     804             : 
     805           9 : void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
     806             : {
     807             :     // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods
     808             :     // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called
     809             :     // with original rInfo, containing dimension indexes of the grouped data.
     810             : 
     811           9 :     const ScDPFilteredCache& rCacheTable = pSourceData->GetCacheTable();
     812           9 :     sal_Int32 nRowSize = rCacheTable.getRowSize();
     813          77 :     for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
     814             :     {
     815             :         sal_Int32 nLastRow;
     816          68 :         if (!rCacheTable.isRowActive(nRow, &nLastRow))
     817             :         {
     818           0 :             nRow = nLastRow;
     819           0 :             continue;
     820             :         }
     821             : 
     822          68 :         CalcRowData aData;
     823          68 :         FillRowDataFromCacheTable(nRow, rCacheTable, rInfo, aData);
     824             : 
     825          68 :         if ( !rInfo.aColLevelDims.empty() )
     826          20 :             FillGroupValues(aData.aColData, rInfo.aColLevelDims);
     827          68 :         if ( !rInfo.aRowLevelDims.empty() )
     828          68 :             FillGroupValues(aData.aRowData, rInfo.aRowLevelDims);
     829          68 :         if ( !rInfo.aPageDims.empty() )
     830           5 :             FillGroupValues(aData.aPageData, rInfo.aPageDims);
     831             : 
     832          68 :         ProcessRowData(rInfo, aData, bAutoShow);
     833          68 :     }
     834           9 : }
     835             : 
     836        1449 : const ScDPFilteredCache& ScDPGroupTableData::GetCacheTable() const
     837             : {
     838        1449 :     return pSourceData->GetCacheTable();
     839             : }
     840             : 
     841          13 : void ScDPGroupTableData::ReloadCacheTable()
     842             : {
     843          13 :     pSourceData->ReloadCacheTable();
     844          13 : }
     845             : 
     846          93 : void ScDPGroupTableData::FillGroupValues(vector<SCROW>& rItems, const vector<long>& rDims)
     847             : {
     848          93 :     long nGroupedColumns = aGroups.size();
     849             : 
     850          93 :     const ScDPCache* pCache = GetCacheTable().getCache();
     851          93 :     vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
     852         252 :     for (size_t i = 0; it != itEnd; ++it, ++i)
     853             :     {
     854         159 :         long nColumn = *it;
     855         159 :         bool bDateDim = false;
     856             : 
     857         159 :         long nSourceDim = nColumn;
     858         159 :         if ( nColumn >= nSourceCount && nColumn < nSourceCount + nGroupedColumns )
     859             :         {
     860          66 :             const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
     861          66 :             nSourceDim= rGroupDim.GetSourceDim();
     862          66 :             bDateDim = rGroupDim.IsDateDimension();
     863          66 :             if (!bDateDim)                         // date is handled below
     864             :             {
     865          34 :                 const ScDPItemData& rItem = *GetMemberById(nSourceDim, rItems[i]);
     866          34 :                 const ScDPGroupItem* pGroupItem = rGroupDim.GetGroupForData(rItem);
     867          34 :                 if (pGroupItem)
     868             :                 {
     869          23 :                     rItems[i] =
     870          23 :                         pCache->GetIdByItemData(nColumn, pGroupItem->GetName());
     871             :                 }
     872             :                 else
     873          11 :                     rItems[i] = pCache->GetIdByItemData(nColumn, rItem);
     874          66 :             }
     875             :         }
     876          93 :         else if ( IsNumGroupDimension( nColumn ) )
     877             :         {
     878          34 :             bDateDim = pNumGroups[nColumn].IsDateDimension();
     879          34 :             if (!bDateDim)                         // date is handled below
     880             :             {
     881          18 :                 const ScDPItemData* pData = pCache->GetItemDataById(nSourceDim, rItems[i]);
     882          18 :                 if (pData->GetType() == ScDPItemData::Value)
     883             :                 {
     884          18 :                     ScDPNumGroupInfo aNumInfo;
     885          18 :                     GetNumGroupInfo(nColumn, aNumInfo);
     886          18 :                     double fGroupValue = ScDPUtil::getNumGroupStartValue(pData->GetValue(), aNumInfo);
     887          18 :                     ScDPItemData aItemData;
     888          18 :                     aItemData.SetRangeStart(fGroupValue);
     889          18 :                     rItems[i] = pCache->GetIdByItemData(nSourceDim, aItemData);
     890             :                 }
     891             :                 // else (textual) keep original value
     892             :             }
     893             :         }
     894             : 
     895         159 :         const ScDPNumGroupInfo* pNumInfo = pCache->GetNumGroupInfo(nColumn);
     896             : 
     897         159 :         if (bDateDim && pNumInfo)
     898             :         {
     899             :             // This is a date group dimension.
     900          48 :             sal_Int32 nDatePart = pCache->GetGroupType(nColumn);
     901          48 :             const ScDPItemData* pData = pCache->GetItemDataById(nSourceDim, rItems[i]);
     902          48 :             if (pData->GetType() == ScDPItemData::Value)
     903             :             {
     904          48 :                 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
     905             :                 sal_Int32 nPartValue = ScDPUtil::getDatePartValue(
     906          48 :                     pData->GetValue(), pNumInfo, nDatePart, pFormatter);
     907             : 
     908          48 :                 ScDPItemData aItem(nDatePart, nPartValue);
     909          48 :                 rItems[i] = pCache->GetIdByItemData(nColumn, aItem);
     910             :             }
     911             :         }
     912             :     }
     913          93 : }
     914             : 
     915          75 : bool ScDPGroupTableData::IsBaseForGroup(long nDim) const
     916             : {
     917         121 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     918             :     {
     919          92 :         const ScDPGroupDimension& rDim = *aIter;
     920          92 :         if ( rDim.GetSourceDim() == nDim )
     921          46 :             return true;
     922             :     }
     923             : 
     924          29 :     return false;
     925             : }
     926             : 
     927         142 : long ScDPGroupTableData::GetGroupBase(long nGroupDim) const
     928             : {
     929         232 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     930             :     {
     931         181 :         const ScDPGroupDimension& rDim = *aIter;
     932         181 :         if ( rDim.GetGroupDim() == nGroupDim )
     933          91 :             return rDim.GetSourceDim();
     934             :     }
     935             : 
     936          51 :     return -1;      // none
     937             : }
     938             : 
     939          44 : bool ScDPGroupTableData::IsNumOrDateGroup(long nDimension) const
     940             : {
     941             :     // Virtual method from ScDPTableData, used in result data to force text labels.
     942             : 
     943          44 :     if ( nDimension < nSourceCount )
     944             :     {
     945          60 :         return pNumGroups[nDimension].GetInfo().mbEnable ||
     946          60 :                pNumGroups[nDimension].IsDateDimension();
     947             :     }
     948             : 
     949          12 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     950             :     {
     951          12 :         const ScDPGroupDimension& rDim = *aIter;
     952          12 :         if ( rDim.GetGroupDim() == nDimension )
     953           9 :             return rDim.IsDateDimension();
     954             :     }
     955             : 
     956           0 :     return false;
     957             : }
     958             : 
     959          59 : bool ScDPGroupTableData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
     960             :                                     const ScDPItemData& rBaseData, long nBaseIndex ) const
     961             : {
     962          73 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     963             :     {
     964          73 :         const ScDPGroupDimension& rDim = *aIter;
     965          73 :         if ( rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex )
     966             :         {
     967          59 :             if (rDim.IsDateDimension())
     968             :             {
     969          87 :                 return isDateInGroup(rGroupData, rBaseData);
     970             :             }
     971             :             else
     972             :             {
     973             :                 // If the item is in a group, only that group is valid.
     974             :                 // If the item is not in any group, its own name is valid.
     975             : 
     976          31 :                 const ScDPGroupItem* pGroup = rDim.GetGroupForData( rBaseData );
     977          20 :                 return pGroup ? pGroup->GetName().IsCaseInsEqual( rGroupData ) :
     978          51 :                                 rGroupData.IsCaseInsEqual( rBaseData );
     979             :             }
     980             :         }
     981             :     }
     982             : 
     983             :     OSL_FAIL("IsInGroup: no group dimension found");
     984           0 :     return true;
     985             : }
     986             : 
     987           8 : bool ScDPGroupTableData::HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex,
     988             :                                          const ScDPItemData& rSecondData, long nSecondIndex ) const
     989             : {
     990           8 :     const ScDPGroupDimension* pFirstDim = NULL;
     991           8 :     const ScDPGroupDimension* pSecondDim = NULL;
     992          24 :     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     993             :     {
     994          16 :         const ScDPGroupDimension* pDim = &(*aIter);
     995          16 :         if ( pDim->GetGroupDim() == nFirstIndex )
     996           8 :             pFirstDim = pDim;
     997           8 :         else if ( pDim->GetGroupDim() == nSecondIndex )
     998           8 :             pSecondDim = pDim;
     999             :     }
    1000           8 :     if ( pFirstDim && pSecondDim )
    1001             :     {
    1002           8 :         bool bFirstDate = pFirstDim->IsDateDimension();
    1003           8 :         bool bSecondDate = pSecondDim->IsDateDimension();
    1004           8 :         if (bFirstDate || bSecondDate)
    1005             :         {
    1006             :             // If one is a date group dimension, the other one must be, too.
    1007           8 :             if (!bFirstDate || !bSecondDate)
    1008             :             {
    1009             :                 OSL_FAIL( "mix of date and non-date groups" );
    1010           0 :                 return true;
    1011             :             }
    1012             : 
    1013           8 :             return isDateInGroup(rFirstData, rSecondData);
    1014             :         }
    1015             : 
    1016           0 :         const ScDPGroupItem* pFirstItem = pFirstDim->GetGroupForName( rFirstData );
    1017           0 :         const ScDPGroupItem* pSecondItem = pSecondDim->GetGroupForName( rSecondData );
    1018           0 :         if ( pFirstItem && pSecondItem )
    1019             :         {
    1020             :             // two existing groups -> sal_True if they have a common element
    1021           0 :             return pFirstItem->HasCommonElement( *pSecondItem );
    1022             :         }
    1023           0 :         else if ( pFirstItem )
    1024             :         {
    1025             :             // "automatic" group contains only its own name
    1026           0 :             return pFirstItem->HasElement( rSecondData );
    1027             :         }
    1028           0 :         else if ( pSecondItem )
    1029             :         {
    1030             :             // "automatic" group contains only its own name
    1031           0 :             return pSecondItem->HasElement( rFirstData );
    1032             :         }
    1033             :         else
    1034             :         {
    1035             :             // no groups -> sal_True if equal
    1036           0 :             return rFirstData.IsCaseInsEqual( rSecondData );
    1037             :         }
    1038             :     }
    1039             : 
    1040             :     OSL_FAIL("HasCommonElement: no group dimension found");
    1041           0 :     return true;
    1042             : }
    1043             : 
    1044         159 : long ScDPGroupTableData::GetSourceDim( long nDim )
    1045             : {
    1046         159 :     if ( getIsDataLayoutDimension( nDim ) )
    1047           0 :         return nSourceCount;
    1048         159 :     if (  nDim >= nSourceCount && nDim < nSourceCount +(long) aGroups.size()  )
    1049             :     {
    1050          66 :          const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
    1051          66 :             return  rGroupDim.GetSourceDim();
    1052             :     }
    1053          93 :     return nDim;
    1054             : }
    1055             : 
    1056         189 : long ScDPGroupTableData::Compare(long nDim, long nDataId1, long nDataId2)
    1057             : {
    1058         189 :     if ( getIsDataLayoutDimension(nDim) )
    1059           0 :         return 0;
    1060         189 :     return ScDPItemData::Compare( *GetMemberById(nDim,  nDataId1),*GetMemberById(nDim,  nDataId2) );
    1061         102 : }
    1062             : 
    1063             : #if DEBUG_PIVOT_TABLE
    1064             : using std::cout;
    1065             : using std::endl;
    1066             : 
    1067             : void ScDPGroupTableData::Dump() const
    1068             : {
    1069             :     cout << "--- ScDPGroupTableData" << endl;
    1070             :     for (long i = 0; i < nSourceCount; ++i)
    1071             :     {
    1072             :         cout << "* dimension: " << i << endl;
    1073             :         const ScDPNumGroupDimension& rGrp = pNumGroups[i];
    1074             :         rGrp.GetInfo().Dump();
    1075             :     }
    1076             :     cout << "---" << endl;
    1077             : }
    1078             : #endif
    1079             : 
    1080             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10