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: 280 399 70.2 %
Date: 2012-12-17 Functions: 52 78 66.7 %
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           6 : ScDPSaveGroupItem::ScDPSaveGroupItem( const rtl::OUString& rName ) :
      38           6 :     aGroupName(rName) {}
      39             : 
      40          20 : ScDPSaveGroupItem::~ScDPSaveGroupItem() {}
      41             : 
      42          22 : void ScDPSaveGroupItem::AddElement( const rtl::OUString& rName )
      43             : {
      44          22 :     aElements.push_back(rName);
      45          22 : }
      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           8 : void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const
      98             : {
      99           8 :     maItems.reserve(aElements.size());
     100           8 :     std::vector<rtl::OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end();
     101          36 :     for (; it != itEnd; ++it)
     102             :     {
     103          28 :         sal_uInt32 nFormat = 0;
     104             :         double fValue;
     105          28 :         ScDPItemData aData;
     106          28 :         if (pFormatter->IsNumberFormat(*it, nFormat, fValue))
     107          10 :             aData.SetValue(fValue);
     108             :         else
     109          18 :             aData.SetString(*it);
     110             : 
     111          28 :         maItems.push_back(aData);
     112          28 :     }
     113           8 : }
     114             : 
     115          46 : bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const
     116             : {
     117          46 :     return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end();
     118             : }
     119             : 
     120           8 : void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const
     121             : {
     122           8 :     ScDPGroupItem aGroup(aGroupName);
     123           8 :     std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
     124          42 :     for (; it != itEnd; ++it)
     125          34 :         aGroup.AddElement(*it);
     126             : 
     127           8 :     rDataDim.AddItem(aGroup);
     128           8 : }
     129             : 
     130             : // ============================================================================
     131             : 
     132           8 : ScDPSaveGroupDimension::ScDPSaveGroupDimension( const rtl::OUString& rSource, const rtl::OUString& rName ) :
     133             :     aSourceDim( rSource ),
     134             :     aGroupDimName( rName ),
     135           8 :     nDatePart( 0 )
     136             : {
     137           8 : }
     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          20 : ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
     148             : {
     149          20 : }
     150             : 
     151           4 : void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
     152             : {
     153           4 :     aDateInfo = rInfo;
     154           4 :     nDatePart = nPart;
     155           4 : }
     156             : 
     157           6 : void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
     158             : {
     159           6 :     aGroups.push_back( rItem );
     160           6 : }
     161             : 
     162           6 : 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           6 :     sal_Int32 nAdd = 1;                                 // first try is "Group1"
     170           6 :     const sal_Int32 nMaxAdd = nAdd + aGroups.size();    // limit the loop
     171          14 :     while ( nAdd <= nMaxAdd )
     172             :     {
     173           8 :         String aGroupName( rPrefix );
     174           8 :         aGroupName.Append( String::CreateFromInt32( nAdd ) );
     175           8 :         bool bExists = false;
     176             : 
     177             :         // look for existing groups
     178          52 :         for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
     179          40 :                                     aIter != aGroups.end() && !bExists; ++aIter )
     180           4 :             if (aIter->GetGroupName().equals(aGroupName))         //! ignore case
     181           2 :                 bExists = true;
     182             : 
     183           8 :         if ( !bExists )
     184           6 :             return aGroupName;          // found a new name
     185             : 
     186           2 :         ++nAdd;                         // continue with higher number
     187           8 :     }
     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          38 : bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const
     271             : {
     272          38 :     ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
     273          56 :     for (; it != itEnd; ++it)
     274             :     {
     275          46 :         if (it->HasInGroup(rItem))
     276          28 :             return true;
     277             :     }
     278          10 :     return false;
     279             : }
     280             : 
     281             : namespace {
     282             : 
     283          36 : inline bool isInteger(double fValue)
     284             : {
     285          36 :     return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue));
     286             : }
     287             : 
     288           6 : 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           6 :     double fSourceMin = 0.0;
     295           6 :     double fSourceMax = 0.0;
     296           6 :     bool bFirst = true;
     297             : 
     298           6 :     const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
     299           6 :     ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
     300          54 :     for (; it != itEnd; ++it)
     301             :     {
     302          48 :         const ScDPItemData& rItem = *it;
     303          48 :         if (rItem.GetType() != ScDPItemData::Value)
     304           0 :             continue;
     305             : 
     306          48 :         double fVal = rItem.GetValue();
     307          48 :         if (bFirst)
     308             :         {
     309           6 :             fSourceMin = fSourceMax = fVal;
     310           6 :             bFirst = false;
     311             :         }
     312             :         else
     313             :         {
     314          42 :             if (fVal < fSourceMin)
     315           0 :                 fSourceMin = fVal;
     316          42 :             if ( fVal > fSourceMax )
     317          42 :                 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           6 :     if (rDateInfo.mbAutoStart)
     325           6 :         rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin);
     326           6 :     if (rDateInfo.mbAutoEnd)
     327           6 :         rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1;
     328             : 
     329             :     //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
     330             : 
     331           6 :     long nStart = 0, nEnd = 0; // end is inclusive
     332             : 
     333           6 :     switch (nDatePart)
     334             :     {
     335             :         case sheet::DataPilotFieldGroupBy::YEARS:
     336             :             nStart = ScDPUtil::getDatePartValue(
     337           2 :                 fSourceMin, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
     338           2 :             nEnd = ScDPUtil::getDatePartValue(fSourceMax, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter);
     339           2 :             break;
     340           2 :         case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4;   break;
     341           2 :         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           6 :     rCache.ResetGroupItems(nGroupDim, rDateInfo, nDatePart);
     352             : 
     353          42 :     for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue)
     354          36 :         rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue));
     355             : 
     356             :     // add first/last entry (min/max)
     357           6 :     rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst));
     358           6 :     rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast));
     359           6 : }
     360             : 
     361             : }
     362             : 
     363          14 : void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
     364             : {
     365          14 :     long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
     366          14 :     if ( nSourceIndex >= 0 )
     367             :     {
     368          14 :         ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
     369          14 :         if ( nDatePart )
     370             :         {
     371             :             // date grouping
     372             : 
     373           8 :             aDim.SetDateDimension();
     374             :         }
     375             :         else
     376             :         {
     377             :             // normal (manual) grouping
     378             : 
     379          14 :             for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter)
     380           8 :                 aIter->AddToData(aDim);
     381             :         }
     382             : 
     383          14 :         rData.AddGroupDimension( aDim );
     384             :     }
     385          14 : }
     386             : 
     387          10 : void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const
     388             : {
     389          10 :     long nSourceDim = rCache.GetDimensionIndex(aSourceDim);
     390          10 :     if (nSourceDim < 0)
     391           0 :         return;
     392             : 
     393          10 :     long nDim = rCache.AppendGroupField();
     394          10 :     SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
     395             : 
     396          10 :     if (nDatePart)
     397             :     {
     398           4 :         fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter);
     399           4 :         return;
     400             :     }
     401             : 
     402           6 :     rCache.ResetGroupItems(nDim, aDateInfo, 0);
     403             :     {
     404           6 :         ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end();
     405          14 :         for (; it != itEnd; ++it)
     406             :         {
     407           8 :             const ScDPSaveGroupItem& rGI = *it;
     408           8 :             rGI.ConvertElementsToItems(pFormatter);
     409           8 :             rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName()));
     410             :         }
     411             :     }
     412             : 
     413           6 :     const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nSourceDim);
     414             :     {
     415           6 :         ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
     416          44 :         for (; it != itEnd; ++it)
     417             :         {
     418          38 :             const ScDPItemData& rItem = *it;
     419          38 :             if (!IsInGroup(rItem))
     420             :                 // Not in any group.  Add as its own group.
     421          10 :                 rCache.SetGroupItem(nDim, rItem);
     422             :         }
     423             :     }
     424             : }
     425             : 
     426             : // ============================================================================
     427             : 
     428           2 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const rtl::OUString& rName, const ScDPNumGroupInfo& rInfo ) :
     429             :     aDimensionName( rName ),
     430             :     aGroupInfo( rInfo ),
     431           2 :     nDatePart( 0 )
     432             : {
     433           2 : }
     434             : 
     435           2 : ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const rtl::OUString& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
     436             :     aDimensionName( rName ),
     437             :     aDateInfo( rDateInfo ),
     438           2 :     nDatePart( nPart )
     439             : {
     440           2 : }
     441             : 
     442          12 : ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
     443             : {
     444          12 : }
     445             : 
     446           6 : void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
     447             : {
     448           6 :     long nSource = rData.GetDimensionIndex( aDimensionName );
     449           6 :     if ( nSource >= 0 )
     450             :     {
     451           6 :         ScDPNumGroupDimension aDim( aGroupInfo );           // aGroupInfo: value grouping
     452           6 :         if ( nDatePart )
     453           4 :             aDim.SetDateDimension();
     454             : 
     455           6 :         rData.SetNumGroupDimension( nSource, aDim );
     456             :     }
     457           6 : }
     458             : 
     459           4 : void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const
     460             : {
     461           4 :     long nDim = rCache.GetDimensionIndex(aDimensionName);
     462           4 :     if (nDim < 0)
     463           4 :         return;
     464             : 
     465           4 :     if (aDateInfo.mbEnable)
     466             :     {
     467             :         // Date grouping
     468           2 :         SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable();
     469           2 :         fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter);
     470             :     }
     471           2 :     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           2 :             (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) &&
     481           2 :             (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) &&
     482           6 :             isInteger(aGroupInfo.mfStep);
     483             : 
     484           2 :         double fSourceMin = 0.0;
     485           2 :         double fSourceMax = 0.0;
     486           2 :         bool bFirst = true;
     487             : 
     488           2 :         const ScDPCache::ItemsType& rItems = rCache.GetDimMemberValues(nDim);
     489           2 :         ScDPCache::ItemsType::const_iterator it = rItems.begin(), itEnd = rItems.end();
     490          34 :         for (; it != itEnd; ++it)
     491             :         {
     492          32 :             const ScDPItemData& rItem = *it;
     493          32 :             if (rItem.GetType() != ScDPItemData::Value)
     494           0 :                 continue;
     495             : 
     496          32 :             double fValue = rItem.GetValue();
     497          32 :             if (bFirst)
     498             :             {
     499           2 :                 fSourceMin = fSourceMax = fValue;
     500           2 :                 bFirst = false;
     501           2 :                 continue;
     502             :             }
     503             : 
     504          30 :             if (fValue < fSourceMin)
     505           0 :                 fSourceMin = fValue;
     506          30 :             if (fValue > fSourceMax)
     507          30 :                 fSourceMax = fValue;
     508             : 
     509          30 :             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           2 :         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           2 :         if (aGroupInfo.mbAutoStart)
     526           0 :             aGroupInfo.mfStart = fSourceMin;
     527           2 :         if (aGroupInfo.mbAutoEnd)
     528           0 :             aGroupInfo.mfEnd = fSourceMax;
     529             : 
     530             :         //! limit number of entries?
     531             : 
     532           2 :         long nLoopCount = 0;
     533           2 :         double fLoop = aGroupInfo.mfStart;
     534             : 
     535           2 :         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           2 :         bool bFirstGroup = true;
     544          10 :         while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd)))
     545             :         {
     546           6 :             ScDPItemData aItem;
     547           6 :             aItem.SetRangeStart(fLoop);
     548           6 :             rCache.SetGroupItem(nDim, aItem);
     549           6 :             ++nLoopCount;
     550           6 :             fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep;
     551           6 :             bFirstGroup = false;
     552             : 
     553             :             // ScDPItemData values are compared with approxEqual
     554           6 :         }
     555             : 
     556           2 :         ScDPItemData aItem;
     557           2 :         aItem.SetRangeFirst();
     558           2 :         rCache.SetGroupItem(nDim, aItem);
     559             : 
     560           2 :         aItem.SetRangeLast();
     561           2 :         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          54 : struct ScDPSaveGroupDimNameFunc
     581             : {
     582             :     rtl::OUString       maDimName;
     583          18 :     inline explicit     ScDPSaveGroupDimNameFunc( const rtl::OUString& rDimName ) : maDimName( rDimName ) {}
     584           6 :     inline bool         operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
     585             : };
     586             : 
     587          30 : struct ScDPSaveGroupSourceNameFunc
     588             : {
     589             :     rtl::OUString       maSrcDimName;
     590          10 :     inline explicit     ScDPSaveGroupSourceNameFunc( const rtl::OUString& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
     591           6 :     inline bool         operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
     592             : };
     593             : 
     594             : } // namespace
     595             : 
     596             : // ----------------------------------------------------------------------------
     597             : 
     598           8 : ScDPDimensionSaveData::ScDPDimensionSaveData()
     599             : {
     600           8 : }
     601             : 
     602          10 : ScDPDimensionSaveData::~ScDPDimensionSaveData()
     603             : {
     604          10 : }
     605             : 
     606           0 : bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
     607             : {
     608           0 :     return false;
     609             : }
     610             : 
     611           8 : 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           8 :     ReplaceGroupDimension( rGroupDim );
     617           8 : }
     618             : 
     619           8 : void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
     620             : {
     621             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     622           8 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
     623           8 :     if( aIt == maGroupDims.end() )
     624           8 :         maGroupDims.push_back( rGroupDim );
     625             :     else
     626           0 :         *aIt = rGroupDim;
     627           8 : }
     628             : 
     629           4 : void ScDPDimensionSaveData::RemoveGroupDimension( const rtl::OUString& rGroupDimName )
     630             : {
     631             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     632           4 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
     633           4 :     if( aIt != maGroupDims.end() )
     634           4 :         maGroupDims.erase( aIt );
     635           4 : }
     636             : 
     637           4 : 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           4 :     ReplaceNumGroupDimension( rGroupDim );
     643           4 : }
     644             : 
     645           4 : void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
     646             : {
     647           4 :     ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
     648           4 :     if( aIt == maNumGroupDims.end() )
     649           4 :         maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
     650             :     else
     651           0 :         aIt->second = rGroupDim;
     652           4 : }
     653             : 
     654           2 : void ScDPDimensionSaveData::RemoveNumGroupDimension( const rtl::OUString& rGroupDimName )
     655             : {
     656           2 :     maNumGroupDims.erase( rGroupDimName );
     657           2 : }
     658             : 
     659          12 : void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
     660             : {
     661             :     //  rData is assumed to be empty
     662             :     //  AddToData also handles date grouping
     663             : 
     664          26 :     for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
     665          14 :         aIt->AddToData( rData );
     666             : 
     667          18 :     for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
     668           6 :         aIt->second.AddToData( rData );
     669          12 : }
     670             : 
     671             : namespace {
     672             : 
     673             : class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void>
     674             : {
     675             :     ScDPCache& mrCache;
     676             : public:
     677          10 :     AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {}
     678          10 :     void operator() (const ScDPSaveGroupDimension& rDim)
     679             :     {
     680          10 :         rDim.AddToCache(mrCache);
     681          10 :     }
     682             : };
     683             : 
     684             : }
     685             : 
     686          10 : void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const
     687             : {
     688          10 :     std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache));
     689          10 :     ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end();
     690          14 :     for (; it != itEnd; ++it)
     691           4 :         it->second.AddToCache(rCache);
     692          10 : }
     693             : 
     694           6 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const rtl::OUString& rBaseDimName ) const
     695             : {
     696           6 :     return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
     697             : }
     698             : 
     699           2 : const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const rtl::OUString& rGroupDimName ) const
     700             : {
     701           2 :     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          10 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const rtl::OUString& rBaseDimName )
     720             : {
     721          10 :     ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
     722          10 :     return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
     723             : }
     724             : 
     725           2 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const rtl::OUString& rGroupDimName )
     726             : {
     727             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     728           2 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
     729           2 :     return (aIt == maGroupDims.end()) ? 0 : &*aIt;
     730             : }
     731             : 
     732          10 : ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const rtl::OUString& rBaseDimName )
     733             : {
     734             :     ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
     735          10 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
     736          10 :     return (aIt == maGroupDims.end()) ? 0 : &*aIt;
     737             : }
     738             : 
     739           4 : 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           4 :         maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
     744             :     // find next group dimension based on the same source dimension name
     745           4 :     if( aIt != maGroupDims.end() )
     746           0 :         aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
     747           4 :     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          10 : bool ScDPDimensionSaveData::HasGroupDimensions() const
     757             : {
     758          10 :     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           8 : 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           8 :     bool bUseSource = bAllowSource;     // if set, try the unchanged original name first
     782             : 
     783           8 :     sal_Int32 nAdd = 2;                 // first try is "Name2"
     784           8 :     const sal_Int32 nMaxAdd = 1000;     // limit the loop
     785          16 :     while ( nAdd <= nMaxAdd )
     786             :     {
     787           8 :         rtl::OUString aDimName( rSourceName );
     788           8 :         if ( !bUseSource )
     789           4 :             aDimName += rtl::OUString::valueOf(static_cast<sal_Int32>(nAdd));
     790           8 :         bool bExists = false;
     791             : 
     792             :         // look for existing group dimensions
     793          10 :         for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
     794           2 :             if( aIt->GetGroupDimName() == aDimName )         //! ignore case
     795           0 :                 bExists = true;
     796             : 
     797             :         // look for base dimensions that happen to have that name
     798           8 :         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           8 :         if ( !bExists )
     810           8 :             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           8 :     }
     817             :     OSL_FAIL("CreateGroupDimName: no valid name found");
     818           0 :     return rtl::OUString();
     819             : }
     820             : 
     821           4 : 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           4 :     rtl::OUString aPartName;
     827           4 :     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           2 :         case QUARTERS: aPartName = rtl::OUString::createFromAscii( "Quarters" );   break;
     836           2 :         case YEARS:    aPartName = rtl::OUString::createFromAscii( "Years" );      break;
     837             :     }
     838             :     OSL_ENSURE(!aPartName.isEmpty(), "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part");
     839           4 :     return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
     840         102 : }
     841             : 
     842             : // ============================================================================
     843             : 
     844             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10