LCOV - code coverage report
Current view: top level - sc/source/core/data - dpdimsave.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 298 398 74.9 %
Date: 2015-06-13 12:38:46 Functions: 60 78 76.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11