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

Generated by: LCOV version 1.10