LCOV - code coverage report
Current view: top level - sc/source/core/data - dpdimsave.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 298 398 74.9 %
Date: 2014-04-11 Functions: 60 78 76.9 %
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             : 
      21             : #include "dpdimsave.hxx"
      22             : #include "dpgroup.hxx"
      23             : #include "dpobject.hxx"
      24             : #include "dputil.hxx"
      25             : #include "document.hxx"
      26             : 
      27             : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
      28             : 
      29             : #include <svl/zforlist.hxx>
      30             : #include <rtl/math.hxx>
      31             : #include <algorithm>
      32             : 
      33             : #include "global.hxx"
      34             : #include "scresid.hxx"
      35             : #include "globstr.hrc"
      36             : 
      37             : using namespace com::sun::star;
      38             : 
      39           6 : ScDPSaveGroupItem::ScDPSaveGroupItem( const OUString& rName ) :
      40           6 :     aGroupName(rName) {}
      41             : 
      42          26 : ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
      43             : 
      44          17 : void ScDPSaveGroupItem::AddElement( const OUString& rName )
      45             : {
      46          17 :     aElements.push_back(rName);
      47          17 : }
      48             : 
      49           0 : void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
      50             : {
      51             :     // add all elements of the other group (used for nested grouping)
      52             : 
      53           0 :     for ( std::vector<OUString>::const_iterator aIter(rGroup.aElements.begin());
      54           0 :                                 aIter != rGroup.aElements.end(); ++aIter )
      55           0 :         aElements.push_back( *aIter );
      56           0 : }
      57             : 
      58           0 : bool ScDPSaveGroupItem::RemoveElement( const OUString& rName )
      59             : {
      60           0 :     for (std::vector<OUString>::iterator aIter = aElements.begin(); aIter != aElements.end(); ++aIter)
      61           0 :         if (*aIter == rName)          //! ignore case
      62             :         {
      63           0 :             aElements.erase(aIter);   // found -> remove
      64           0 :             return true;                // don't have to look further
      65             :         }
      66             : 
      67           0 :     return false;   // not found
      68             : }
      69             : 
      70           0 : bool ScDPSaveGroupItem::IsEmpty() const
      71             : {
      72           0 :     return aElements.empty();
      73             : }
      74             : 
      75           3 : size_t ScDPSaveGroupItem::GetElementCount() const
      76             : {
      77           3 :     return aElements.size();
      78             : }
      79             : 
      80           6 : const OUString* ScDPSaveGroupItem::GetElementByIndex(size_t nIndex) const
      81             : {
      82           6 :     return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0;
      83             : }
      84             : 
      85           0 : void ScDPSaveGroupItem::Rename( const OUString& rNewName )
      86             : {
      87           0 :     aGroupName = rNewName;
      88           0 : }
      89             : 
      90           0 : void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const
      91             : {
      92             :     // remove this group's elements from their groups in rDimension
      93             :     // (rDimension must be a different dimension from the one which contains this)
      94             : 
      95           0 :     for ( std::vector<OUString>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); ++aIter )
      96           0 :         rDimension.RemoveFromGroups( *aIter );
      97           0 : }
      98             : 
      99           7 : void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const
     100             : {
     101           7 :     maItems.reserve(aElements.size());
     102           7 :     std::vector<OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end();
     103          27 :     for (; it != itEnd; ++it)
     104             :     {
     105          20 :         sal_uInt32 nFormat = 0;
     106             :         double fValue;
     107          20 :         ScDPItemData aData;
     108          20 :         if (pFormatter->IsNumberFormat(*it, nFormat, fValue))
     109           5 :             aData.SetValue(fValue);
     110             :         else
     111          15 :             aData.SetString(*it);
     112             : 
     113          20 :         maItems.push_back(aData);
     114          20 :     }
     115           7 : }
     116             : 
     117          35 : bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const
     118             : {
     119          35 :     return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
     120             : }
     121             : 
     122           7 : void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
     123             : {
     124           7 :     ScDPGroupItem aGroup(aGroupName);
     125           7 :     std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
     126          30 :     for (; it != itEnd; ++it)
     127          23 :         aGroup.AddElement(*it);
     128             : 
     129           7 :     rDataDim.AddItem(aGroup);
     130           7 : }
     131             : 
     132           9 : ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName ) :
     133             :     aSourceDim( rSource ),
     134             :     aGroupDimName( rName ),
     135           9 :     nDatePart( 0 )
     136             : {
     137           9 : }
     138             : 
     139           0 : ScDPSaveGroupDimension::ScDPSaveGroupDimension( const OUString& rSource, const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
     140             :     aSourceDim( rSource ),
     141             :     aGroupDimName( rName ),
     142             :     aDateInfo( rDateInfo ),
     143           0 :     nDatePart( nPart )
     144             : {
     145           0 : }
     146             : 
     147          32 : ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
     148             : {
     149          32 : }
     150             : 
     151           4 : void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
     152             : {
     153           4 :     aDateInfo = rInfo;
     154           4 :     nDatePart = nPart;
     155           4 : }
     156             : 
     157           6 : void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
     158             : {
     159           6 :     aGroups.push_back( rItem );
     160           6 : }
     161             : 
     162           6 : OUString ScDPSaveGroupDimension::CreateGroupName(const OUString& rPrefix)
     163             : {
     164             :     // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
     165             : 
     166             :     //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
     167             :     //! (only dimensions for the same base)
     168             : 
     169           6 :     sal_Int32 nAdd = 1;                                 // first try is "Group1"
     170           6 :     const sal_Int32 nMaxAdd = nAdd + aGroups.size();    // limit the loop
     171          13 :     while ( nAdd <= nMaxAdd )
     172             :     {
     173           7 :         OUString aGroupName = rPrefix + OUString::number( nAdd );
     174           7 :         bool bExists = false;
     175             : 
     176             :         // look for existing groups
     177          27 :         for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
     178          27 :                                     aIter != aGroups.end() && !bExists; ++aIter )
     179           2 :             if (aIter->GetGroupName().equals(aGroupName))         //! ignore case
     180           1 :                 bExists = true;
     181             : 
     182           7 :         if ( !bExists )
     183           6 :             return aGroupName;          // found a new name
     184             : 
     185           1 :         ++nAdd;                         // continue with higher number
     186           1 :     }
     187             : 
     188             :     OSL_FAIL("CreateGroupName: no valid name found");
     189           0 :     return OUString();
     190             : }
     191             : 
     192           0 : const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const OUString& rGroupName ) const
     193             : {
     194           0 :     return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
     195             : }
     196             : 
     197           0 : ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const OUString& rGroupName )
     198             : {
     199           0 :     for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
     200           0 :         if (aIter->GetGroupName().equals(rGroupName))         //! ignore case
     201           0 :             return &*aIter;
     202             : 
     203           0 :     return NULL;        // none found
     204             : }
     205             : 
     206           3 : long ScDPSaveGroupDimension::GetGroupCount() const
     207             : {
     208           3 :     return aGroups.size();
     209             : }
     210             : 
     211           3 : const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
     212             : {
     213           3 :     return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
     214             : }
     215             : 
     216           3 : ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
     217             : {
     218           3 :     return &aGroups[nIndex];
     219             : }
     220             : 
     221           0 : void ScDPSaveGroupDimension::RemoveFromGroups( const OUString& rItemName )
     222             : {
     223             :     //  if the item is in any group, remove it from the group,
     224             :     //  also remove the group if it is empty afterwards
     225             : 
     226           0 :     for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter )
     227           0 :         if ( aIter->RemoveElement( rItemName ) )
     228             :         {
     229           0 :             if ( aIter->IsEmpty() )         // removed last item from the group?
     230           0 :                 aGroups.erase( aIter );     // then remove the group
     231             : 
     232           0 :             return;     // don't have to look further
     233             :         }
     234             : }
     235             : 
     236           0 : void ScDPSaveGroupDimension::RemoveGroup(const OUString& rGroupName)
     237             : {
     238           0 :     for (ScDPSaveGroupItemVec::iterator aIter = aGroups.begin(); aIter != aGroups.end(); ++aIter)
     239           0 :         if (aIter->GetGroupName().equals(rGroupName))          //! ignore case
     240             :         {
     241           0 :             aGroups.erase( aIter );
     242           0 :             return;                     // don't have to look further
     243             :         }
     244             : }
     245             : 
     246           0 : bool ScDPSaveGroupDimension::IsEmpty() const
     247             : {
     248           0 :     return aGroups.empty();
     249             : }
     250             : 
     251           0 : bool ScDPSaveGroupDimension::HasOnlyHidden(const ScDPUniqueStringSet& rVisible)
     252             : {
     253             :     // check if there are only groups that don't appear in the list of visible names
     254             : 
     255           0 :     bool bAllHidden = true;
     256           0 :     for (ScDPSaveGroupItemVec::const_iterator aIter = aGroups.begin(); aIter != aGroups.end() && bAllHidden; ++aIter)
     257             :     {
     258           0 :         if (rVisible.count(aIter->GetGroupName()) > 0)
     259           0 :             bAllHidden = false;
     260             :     }
     261           0 :     return bAllHidden;
     262             : }
     263             : 
     264           0 : void ScDPSaveGroupDimension::Rename( const OUString& rNewName )
     265             : {
     266           0 :     aGroupDimName = rNewName;
     267           0 : }
     268             : 
     269          31 : bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const
     270             : {
     271          31 :     ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
     272          46 :     for (; it != itEnd; ++it)
     273             :     {
     274          35 :         if (it->HasInGroup(rItem))
     275          20 :             return true;
     276             :     }
     277          11 :     return false;
     278             : }
     279             : 
     280             : namespace {
     281             : 
     282          36 : inline bool isInteger(double fValue)
     283             : {
     284          36 :     return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
     285             : }
     286             : 
     287          10 : void fillDateGroupDimension(
     288             :     ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, long nSourceDim, long nGroupDim,
     289             :     sal_Int32 nDatePart, SvNumberFormatter* pFormatter)
     290             : {
     291             :     // Auto min/max is only used for "Years" part, but the loop is always
     292             :     // needed.
     293          10 :     double fSourceMin = 0.0;
     294          10 :     double fSourceMax = 0.0;
     295          10 :     bool bFirst = true;
     296             : 
     297          10 :     const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
     298          10 :     ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
     299         358 :     for (; it != itEnd; ++it)
     300             :     {
     301         348 :         const ScDPItemData& rItem = *it;
     302         348 :         if (rItem.GetType() != ScDPItemData::Value)
     303           0 :             continue;
     304             : 
     305         348 :         double fVal = rItem.GetValue();
     306         348 :         if (bFirst)
     307             :         {
     308          10 :             fSourceMin = fSourceMax = fVal;
     309          10 :             bFirst = false;
     310             :         }
     311             :         else
     312             :         {
     313         338 :             if (fVal < fSourceMin)
     314           0 :                 fSourceMin = fVal;
     315         338 :             if ( fVal > fSourceMax )
     316         338 :                 fSourceMax = fVal;
     317             :         }
     318             :     }
     319             : 
     320             :     // For the start/end values, use the same date rounding as in
     321             :     // ScDPNumGroupDimension::GetNumEntries (but not for the list of
     322             :     // available years).
     323          10 :     if (rDateInfo.mbAutoStart)
     324           6 :         rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
     325          10 :     if (rDateInfo.mbAutoEnd)
     326          10 :         rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
     327             : 
     328             :     //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
     329             : 
     330          10 :     long nStart = 0, nEnd = 0; // end is inclusive
     331             : 
     332          10 :     switch (nDatePart)
     333             :     {
     334             :         case sheet::DataPilotFieldGroupBy::YEARS:
     335             :             nStart = ScDPUtil::getDatePartValue(
     336           3 :                 fSourceMin, NULL, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
     337           3 :             nEnd = ScDPUtil::getDatePartValue(fSourceMax, NULL, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
     338           3 :             break;
     339           2 :         case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4;   break;
     340           3 :         case sheet::DataPilotFieldGroupBy::MONTHS:   nStart = 1; nEnd = 12;  break;
     341           2 :         case sheet::DataPilotFieldGroupBy::DAYS:     nStart = 1; nEnd = 366; break;
     342           0 :         case sheet::DataPilotFieldGroupBy::HOURS:    nStart = 0; nEnd = 23;  break;
     343           0 :         case sheet::DataPilotFieldGroupBy::MINUTES:  nStart = 0; nEnd = 59;  break;
     344           0 :         case sheet::DataPilotFieldGroupBy::SECONDS:  nStart = 0; nEnd = 59;  break;
     345             :         default:
     346             :             OSL_FAIL("invalid date part");
     347             :     }
     348             : 
     349             :     // Now, populate the group items in the cache.
     350          10 :     rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
     351             : 
     352         792 :     for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue)
     353         782 :         rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
     354             : 
     355             :     // add first/last entry (min/max)
     356          10 :     rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
     357          10 :     rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
     358          10 : }
     359             : 
     360             : }
     361             : 
     362          12 : void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
     363             : {
     364          12 :     long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
     365          12 :     if ( nSourceIndex >= 0 )
     366             :     {
     367          12 :         ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
     368          12 :         if ( nDatePart )
     369             :         {
     370             :             // date grouping
     371             : 
     372           6 :             aDim.SetDateDimension();
     373             :         }
     374             :         else
     375             :         {
     376             :             // normal (manual) grouping
     377             : 
     378          13 :             for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter)
     379           7 :                 aIter->AddToData(aDim);
     380             :         }
     381             : 
     382          12 :         rData.AddGroupDimension( aDim );
     383             :     }
     384          12 : }
     385             : 
     386          12 : void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
     387             : {
     388          12 :     long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
     389          12 :     if (nSourceDim < 0)
     390           0 :         return;
     391             : 
     392          12 :     long nDim = rCache.AppendGroupField();
     393          12 :     SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
     394             : 
     395          12 :     if (nDatePart)
     396             :     {
     397           6 :         fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
     398           6 :         return;
     399             :     }
     400             : 
     401           6 :     rCache.ResetGroupItems(nDim, aDateInfo, 0);
     402             :     {
     403           6 :         ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
     404          13 :         for (; it != itEnd; ++it)
     405             :         {
     406           7 :             const ScDPSaveGroupItem& rGI = *it;
     407           7 :             rGI.ConvertElementsToItems(pFormatter);
     408           7 :             rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
     409             :         }
     410             :     }
     411             : 
     412           6 :     const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
     413             :     {
     414           6 :         ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
     415          37 :         for (; it != itEnd; ++it)
     416             :         {
     417          31 :             const ScDPItemData& rItem = *it;
     418          31 :             if (!IsInGroup(rItem))
     419             :                 // Not in any group.  Add as its own group.
     420          11 :                 rCache.SetGroupItem(nDim, rItem);
     421             :         }
     422             :     }
     423             : }
     424             : 
     425           3 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rInfo ) :
     426             :     aDimensionName( rName ),
     427             :     aGroupInfo( rInfo ),
     428           3 :     nDatePart( 0 )
     429             : {
     430           3 : }
     431             : 
     432           1 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
     433             :     aDimensionName( rName ),
     434             :     aDateInfo( rDateInfo ),
     435           1 :     nDatePart( nPart )
     436             : {
     437           1 : }
     438             : 
     439          16 : ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
     440             : {
     441          16 : }
     442             : 
     443           5 : void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
     444             : {
     445           5 :     long nSource = rData.GetDimensionIndex( aDimensionName );
     446           5 :     if ( nSource >= 0 )
     447             :     {
     448           5 :         ScDPNumGroupDimension aDim( aGroupInfo );           // aGroupInfo: value grouping
     449           5 :         if ( nDatePart )
     450           4 :             aDim.SetDateDimension();
     451             : 
     452           5 :         rData.SetNumGroupDimension( nSource, aDim );
     453             :     }
     454           5 : }
     455             : 
     456           6 : void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
     457             : {
     458           6 :     long nDim = rCache.GetDimensionIndex(aDimensionName);
     459           6 :     if (nDim < 0)
     460           6 :         return;
     461             : 
     462           6 :     if (aDateInfo.mbEnable)
     463             :     {
     464             :         // Date grouping
     465           4 :         SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
     466           4 :         fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
     467             :     }
     468           2 :     else if (aGroupInfo.mbEnable)
     469             :     {
     470             :         // Number-range grouping
     471             : 
     472             :         // Look through the source entries for non-integer numbers, minimum
     473             :         // and maximum.
     474             : 
     475             :         // non-integer GroupInfo values count, too
     476             :         aGroupInfo.mbIntegerOnly =
     477           2 :             (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
     478           6 :             (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
     479           4 :             isInteger(aGroupInfo.mfStep);
     480             : 
     481           2 :         double fSourceMin = 0.0;
     482           2 :         double fSourceMax = 0.0;
     483           2 :         bool bFirst = true;
     484             : 
     485           2 :         const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nDim);
     486           2 :         ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
     487          34 :         for (; it != itEnd; ++it)
     488             :         {
     489          32 :             const ScDPItemData& rItem = *it;
     490          32 :             if (rItem.GetType() != ScDPItemData::Value)
     491           0 :                 continue;
     492             : 
     493          32 :             double fValue = rItem.GetValue();
     494          32 :             if (bFirst)
     495             :             {
     496           2 :                 fSourceMin = fSourceMax = fValue;
     497           2 :                 bFirst = false;
     498           2 :                 continue;
     499             :             }
     500             : 
     501          30 :             if (fValue < fSourceMin)
     502           0 :                 fSourceMin = fValue;
     503          30 :             if (fValue > fSourceMax)
     504          30 :                 fSourceMax = fValue;
     505             : 
     506          30 :             if (aGroupInfo.mbIntegerOnly && !isInteger(fValue))
     507             :             {
     508             :                 // If any non-integer numbers are involved, the group labels
     509             :                 // are shown including their upper limit.
     510           0 :                 aGroupInfo.mbIntegerOnly = false;
     511             :             }
     512             :         }
     513             : 
     514           2 :         if (aGroupInfo.mbDateValues)
     515             :         {
     516             :             // special handling for dates: always integer, round down limits
     517           0 :             aGroupInfo.mbIntegerOnly = true;
     518           0 :             fSourceMin = rtl::math::approxFloor(fSourceMin);
     519           0 :             fSourceMax = rtl::math::approxFloor(fSourceMax) + 1;
     520             :         }
     521             : 
     522           2 :         if (aGroupInfo.mbAutoStart)
     523           0 :             aGroupInfo.mfStart = fSourceMin;
     524           2 :         if (aGroupInfo.mbAutoEnd)
     525           0 :             aGroupInfo.mfEnd = fSourceMax;
     526             : 
     527             :         //! limit number of entries?
     528             : 
     529           2 :         long nLoopCount = 0;
     530           2 :         double fLoop = aGroupInfo.mfStart;
     531             : 
     532           2 :         rCache.ResetGroupItems(nDim, aGroupInfo, 0);
     533             : 
     534             :         // Use "less than" instead of "less or equal" for the loop - don't
     535             :         // create a group that consists only of the end value. Instead, the
     536             :         // end value is then included in the last group (last group is bigger
     537             :         // than the others). The first group has to be created nonetheless.
     538             :         // GetNumGroupForValue has corresponding logic.
     539             : 
     540           2 :         bool bFirstGroup = true;
     541          10 :         while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
     542             :         {
     543           6 :             ScDPItemData aItem;
     544           6 :             aItem.SetRangeStart(fLoop);
     545           6 :             rCache.SetGroupItem(nDim, aItem);
     546           6 :             ++nLoopCount;
     547           6 :             fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
     548           6 :             bFirstGroup = false;
     549             : 
     550             :             // ScDPItemData values are compared with approxEqual
     551           6 :         }
     552             : 
     553           2 :         ScDPItemData aItem;
     554           2 :         aItem.SetRangeFirst();
     555           2 :         rCache.SetGroupItem(nDim, aItem);
     556             : 
     557           2 :         aItem.SetRangeLast();
     558           2 :         rCache.SetGroupItem(nDim, aItem);
     559             :     }
     560             : }
     561             : 
     562           0 : void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
     563             : {
     564           0 :     aGroupInfo = rNew;
     565           0 : }
     566             : 
     567           2 : void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
     568             : {
     569           2 :     aDateInfo = rInfo;
     570           2 :     nDatePart = nPart;
     571           2 : }
     572             : 
     573             : namespace {
     574             : 
     575          87 : struct ScDPSaveGroupDimNameFunc
     576             : {
     577             :     OUString       maDimName;
     578          29 :     inline explicit     ScDPSaveGroupDimNameFunc( const OUString& rDimName ) : maDimName( rDimName ) {}
     579          13 :     inline bool         operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
     580             : };
     581             : 
     582          24 : struct ScDPSaveGroupSourceNameFunc
     583             : {
     584             :     OUString       maSrcDimName;
     585           8 :     inline explicit     ScDPSaveGroupSourceNameFunc( const OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
     586           3 :     inline bool         operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
     587             : };
     588             : 
     589             : } // namespace
     590             : 
     591           9 : ScDPDimensionSaveData::ScDPDimensionSaveData()
     592             : {
     593           9 : }
     594             : 
     595          21 : ScDPDimensionSaveData::~ScDPDimensionSaveData()
     596             : {
     597          21 : }
     598             : 
     599           0 : bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
     600             : {
     601           0 :     return false;
     602             : }
     603             : 
     604           9 : void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
     605             : {
     606             :     OSL_ENSURE( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(),
     607             :         "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
     608             :     // ReplaceGroupDimension() adds new or replaces existing
     609           9 :     ReplaceGroupDimension( rGroupDim );
     610           9 : }
     611             : 
     612           9 : void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
     613             : {
     614             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     615           9 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
     616           9 :     if( aIt == maGroupDims.end() )
     617           9 :         maGroupDims.push_back( rGroupDim );
     618             :     else
     619           0 :         *aIt = rGroupDim;
     620           9 : }
     621             : 
     622           2 : void ScDPDimensionSaveData::RemoveGroupDimension( const OUString& rGroupDimName )
     623             : {
     624             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     625           2 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
     626           2 :     if( aIt != maGroupDims.end() )
     627           2 :         maGroupDims.erase( aIt );
     628           2 : }
     629             : 
     630           4 : void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
     631             : {
     632             :     OSL_ENSURE( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
     633             :         "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
     634             :     // ReplaceNumGroupDimension() adds new or replaces existing
     635           4 :     ReplaceNumGroupDimension( rGroupDim );
     636           4 : }
     637             : 
     638           4 : void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
     639             : {
     640           4 :     ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
     641           4 :     if( aIt == maNumGroupDims.end() )
     642           4 :         maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
     643             :     else
     644           0 :         aIt->second = rGroupDim;
     645           4 : }
     646             : 
     647           1 : void ScDPDimensionSaveData::RemoveNumGroupDimension( const OUString& rGroupDimName )
     648             : {
     649           1 :     maNumGroupDims.erase( rGroupDimName );
     650           1 : }
     651             : 
     652          11 : void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
     653             : {
     654             :     //  rData is assumed to be empty
     655             :     //  AddToData also handles date grouping
     656             : 
     657          23 :     for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
     658          12 :         aIt->AddToData( rData );
     659             : 
     660          16 :     for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
     661           5 :         aIt->second.AddToData( rData );
     662          11 : }
     663             : 
     664             : namespace {
     665             : 
     666             : class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void>
     667             : {
     668             :     ScDPCache& mrCache;
     669             : public:
     670          12 :     AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {}
     671          12 :     void operator() (const ScDPSaveGroupDimension& rDim)
     672             :     {
     673          12 :         rDim.AddToCache(mrCache);
     674          12 :     }
     675             : };
     676             : 
     677             : }
     678             : 
     679          12 : void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const
     680             : {
     681          12 :     std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache));
     682          12 :     ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end();
     683          18 :     for (; it != itEnd; ++it)
     684           6 :         it->second.AddToCache(rCache);
     685          12 : }
     686             : 
     687           3 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const OUString& rBaseDimName ) const
     688             : {
     689           3 :     return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
     690             : }
     691             : 
     692          13 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const OUString& rGroupDimName ) const
     693             : {
     694          13 :     return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
     695             : }
     696             : 
     697           0 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const OUString& rBaseDimName ) const
     698             : {
     699           0 :     return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
     700             : }
     701             : 
     702           0 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const OUString& rGroupDimName ) const
     703             : {
     704           0 :     return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
     705             : }
     706             : 
     707           3 : const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const OUString& rGroupDimName ) const
     708             : {
     709           3 :     return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
     710             : }
     711             : 
     712           8 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const OUString& rBaseDimName )
     713             : {
     714           8 :     ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
     715           8 :     return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
     716             : }
     717             : 
     718          13 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const OUString& rGroupDimName )
     719             : {
     720             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     721          13 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
     722          13 :     return (aIt == maGroupDims.end()) ? 0 : &*aIt;
     723             : }
     724             : 
     725           8 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const OUString& rBaseDimName )
     726             : {
     727             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     728           8 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
     729           8 :     return (aIt == maGroupDims.end()) ? 0 : &*aIt;
     730             : }
     731             : 
     732           5 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const OUString& rGroupDimName )
     733             : {
     734             :     // find the group dimension with the passed name
     735             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     736           5 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
     737             :     // find next group dimension based on the same source dimension name
     738           5 :     if( aIt != maGroupDims.end() )
     739           0 :         aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
     740           5 :     return (aIt == maGroupDims.end()) ? 0 : &*aIt;
     741             : }
     742             : 
     743           3 : ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const OUString& rGroupDimName )
     744             : {
     745           3 :     ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
     746           3 :     return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
     747             : }
     748             : 
     749           8 : bool ScDPDimensionSaveData::HasGroupDimensions() const
     750             : {
     751           8 :     return !maGroupDims.empty() || !maNumGroupDims.empty();
     752             : }
     753             : 
     754           0 : sal_Int32 ScDPDimensionSaveData::CollectDateParts( const OUString& rBaseDimName ) const
     755             : {
     756           0 :     sal_Int32 nParts = 0;
     757             :     // start with part of numeric group
     758           0 :     if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
     759           0 :         nParts |= pNumDim->GetDatePart();
     760             :     // collect parts from all matching group dimensions
     761           0 :     for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
     762           0 :         nParts |= pGroupDim->GetDatePart();
     763             : 
     764           0 :     return nParts;
     765             : }
     766             : 
     767           7 : OUString ScDPDimensionSaveData::CreateGroupDimName(
     768             :     const OUString& rSourceName, const ScDPObject& rObject, bool bAllowSource,
     769             :     const std::vector<OUString>* pDeletedNames )
     770             : {
     771             :     // create a name for the new dimension by appending a number to the original
     772             :     // dimension's name
     773             : 
     774           7 :     bool bUseSource = bAllowSource;     // if set, try the unchanged original name first
     775             : 
     776           7 :     sal_Int32 nAdd = 2;                 // first try is "Name2"
     777           7 :     const sal_Int32 nMaxAdd = 1000;     // limit the loop
     778          14 :     while ( nAdd <= nMaxAdd )
     779             :     {
     780           7 :         OUString aDimName( rSourceName );
     781           7 :         if ( !bUseSource )
     782           5 :             aDimName += OUString::number(nAdd);
     783           7 :         bool bExists = false;
     784             : 
     785             :         // look for existing group dimensions
     786           8 :         for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
     787           1 :             if( aIt->GetGroupDimName() == aDimName )         //! ignore case
     788           0 :                 bExists = true;
     789             : 
     790             :         // look for base dimensions that happen to have that name
     791           7 :         if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
     792             :         {
     793           0 :             if ( pDeletedNames &&
     794           0 :                  std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
     795             :             {
     796             :                 // allow the name anyway if the name is in pDeletedNames
     797             :             }
     798             :             else
     799           0 :                 bExists = true;
     800             :         }
     801             : 
     802           7 :         if ( !bExists )
     803           7 :             return aDimName;            // found a new name
     804             : 
     805           0 :         if ( bUseSource )
     806           0 :             bUseSource = false;
     807             :         else
     808           0 :             ++nAdd;                     // continue with higher number
     809           0 :     }
     810             :     OSL_FAIL("CreateGroupDimName: no valid name found");
     811           0 :     return OUString();
     812             : }
     813             : 
     814             : namespace
     815             : {
     816             :     static const sal_uInt16 nDatePartIds[] =
     817             :     {
     818             :         STR_DPFIELD_GROUP_BY_SECONDS,
     819             :         STR_DPFIELD_GROUP_BY_MINUTES,
     820             :         STR_DPFIELD_GROUP_BY_HOURS,
     821             :         STR_DPFIELD_GROUP_BY_DAYS,
     822             :         STR_DPFIELD_GROUP_BY_MONTHS,
     823             :         STR_DPFIELD_GROUP_BY_QUARTERS,
     824             :         STR_DPFIELD_GROUP_BY_YEARS
     825             :     };
     826             : }
     827             : 
     828           2 : OUString ScDPDimensionSaveData::CreateDateGroupDimName(
     829             :     sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource,
     830             :     const std::vector<OUString>* pDeletedNames )
     831             : {
     832             :     using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
     833           2 :     OUString aPartName;
     834           2 :     switch( nDatePart )
     835             :     {
     836           0 :         case SECONDS:  aPartName = ScGlobal::GetRscString( nDatePartIds[0] ); break;
     837           0 :         case MINUTES:  aPartName = ScGlobal::GetRscString( nDatePartIds[1] ); break;
     838           0 :         case HOURS:    aPartName = ScGlobal::GetRscString( nDatePartIds[2] ); break;
     839           0 :         case DAYS:     aPartName = ScGlobal::GetRscString( nDatePartIds[3] ); break;
     840           0 :         case MONTHS:   aPartName = ScGlobal::GetRscString( nDatePartIds[4] ); break;
     841           1 :         case QUARTERS: aPartName = ScGlobal::GetRscString( nDatePartIds[5] ); break;
     842           1 :         case YEARS:    aPartName = ScGlobal::GetRscString( nDatePartIds[6] ); break;
     843             :     }
     844             :     OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
     845           2 :     return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
     846         102 : }
     847             : 
     848             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10