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

Generated by: LCOV version 1.10