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

Generated by: LCOV version 1.10