LCOV - code coverage report
Current view: top level - sc/source/core/data - dputil.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 90 143 62.9 %
Date: 2012-08-25 Functions: 11 13 84.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 75 196 38.3 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*
       3                 :            :  * Version: MPL 1.1 / GPLv3+ / LGPLv3+
       4                 :            :  *
       5                 :            :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :            :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :            :  * the License or as specified alternatively below. You may obtain a copy of
       8                 :            :  * the License at http://www.mozilla.org/MPL/
       9                 :            :  *
      10                 :            :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :            :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :            :  * for the specific language governing rights and limitations under the
      13                 :            :  * License.
      14                 :            :  *
      15                 :            :  * Major Contributor(s):
      16                 :            :  *   Copyright (C) 2012 Kohei Yoshida <kohei.yoshida@suse.com>
      17                 :            :  *
      18                 :            :  * All Rights Reserved.
      19                 :            :  *
      20                 :            :  * For minor contributions see the git repository.
      21                 :            :  *
      22                 :            :  * Alternatively, the contents of this file may be used under the terms of
      23                 :            :  * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
      24                 :            :  * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
      25                 :            :  * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
      26                 :            :  * instead of those above.
      27                 :            :  */
      28                 :            : 
      29                 :            : #include "dputil.hxx"
      30                 :            : #include "global.hxx"
      31                 :            : #include "dpitemdata.hxx"
      32                 :            : #include "dpnumgroupinfo.hxx"
      33                 :            : 
      34                 :            : #include "comphelper/string.hxx"
      35                 :            : #include "unotools/localedatawrapper.hxx"
      36                 :            : #include "unotools/calendarwrapper.hxx"
      37                 :            : #include "svl/zforlist.hxx"
      38                 :            : #include "rtl/math.hxx"
      39                 :            : 
      40                 :            : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
      41                 :            : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
      42                 :            : 
      43                 :            : #define D_TIMEFACTOR 86400.0
      44                 :            : 
      45                 :            : using namespace com::sun::star;
      46                 :            : 
      47                 :            : namespace {
      48                 :            : 
      49                 :            : const sal_uInt16 SC_DP_LEAPYEAR = 1648;     // arbitrary leap year for date calculations
      50                 :            : 
      51                 :          0 : rtl::OUString getTwoDigitString(sal_Int32 nValue)
      52                 :            : {
      53         [ #  # ]:          0 :     String aRet = String::CreateFromInt32( nValue );
      54         [ #  # ]:          0 :     if ( aRet.Len() < 2 )
      55         [ #  # ]:          0 :         aRet.Insert( (sal_Unicode)'0', 0 );
      56 [ #  # ][ #  # ]:          0 :     return aRet;
      57                 :            : }
      58                 :            : 
      59                 :          6 : void appendDateStr(rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter)
      60                 :            : {
      61         [ +  - ]:          6 :     sal_uLong nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge );
      62                 :          6 :     rtl::OUString aString;
      63         [ +  - ]:          6 :     pFormatter->GetInputLineString(fValue, nFormat, aString);
      64         [ +  - ]:          6 :     rBuffer.append(aString);
      65                 :          6 : }
      66                 :            : 
      67                 :          6 : rtl::OUString getSpecialDateName(double fValue, bool bFirst, SvNumberFormatter* pFormatter)
      68                 :            : {
      69                 :          6 :     rtl::OUStringBuffer aBuffer;
      70 [ +  - ][ +  + ]:          6 :     aBuffer.append(sal_Unicode(bFirst ? '<' : '>'));
      71         [ +  - ]:          6 :     appendDateStr(aBuffer, fValue, pFormatter);
      72         [ +  - ]:          6 :     return aBuffer.makeStringAndClear();
      73                 :            : }
      74                 :            : 
      75                 :            : }
      76                 :            : 
      77                 :        218 : bool ScDPUtil::isDuplicateDimension(const rtl::OUString& rName)
      78                 :            : {
      79         [ +  + ]:        218 :     if (rName.isEmpty())
      80                 :         42 :         return false;
      81                 :            : 
      82                 :        176 :     sal_Unicode cLast = rName[rName.getLength()-1];
      83                 :        218 :     return cLast == sal_Unicode('*');
      84                 :            : }
      85                 :            : 
      86                 :       1138 : rtl::OUString ScDPUtil::getSourceDimensionName(const rtl::OUString& rName)
      87                 :            : {
      88                 :       1138 :     return comphelper::string::stripEnd(rName, '*');
      89                 :            : }
      90                 :            : 
      91                 :          3 : rtl::OUString ScDPUtil::createDuplicateDimensionName(const rtl::OUString& rOriginal, size_t nDupCount)
      92                 :            : {
      93         [ -  + ]:          3 :     if (!nDupCount)
      94                 :          0 :         return rOriginal;
      95                 :            : 
      96         [ +  - ]:          3 :     rtl::OUStringBuffer aBuf(rOriginal);
      97         [ +  + ]:          6 :     for (size_t i = 0; i < nDupCount; ++i)
      98         [ +  - ]:          3 :         aBuf.append(sal_Unicode('*'));
      99                 :            : 
     100         [ +  - ]:          3 :     return aBuf.makeStringAndClear();
     101                 :            : }
     102                 :            : 
     103                 :        213 : rtl::OUString ScDPUtil::getDateGroupName(
     104                 :            :         sal_Int32 nDatePart, sal_Int32 nValue, SvNumberFormatter* pFormatter,
     105                 :            :         double fStart, double fEnd)
     106                 :            : {
     107         [ +  + ]:        213 :     if (nValue == ScDPItemData::DateFirst)
     108                 :          3 :         return getSpecialDateName(fStart, true, pFormatter);
     109         [ +  + ]:        210 :     if (nValue == ScDPItemData::DateLast)
     110                 :          3 :         return getSpecialDateName(fEnd, false, pFormatter);
     111                 :            : 
     112   [ +  +  +  -  :        207 :     switch ( nDatePart )
                -  -  - ]
     113                 :            :     {
     114                 :            :         case sheet::DataPilotFieldGroupBy::YEARS:
     115                 :         63 :             return rtl::OUString::valueOf(nValue);
     116                 :            :         case sheet::DataPilotFieldGroupBy::QUARTERS:
     117                 :         66 :             return ScGlobal::pLocaleData->getQuarterAbbreviation(sal_Int16(nValue-1));    // nValue is 1-based
     118                 :            :         case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
     119                 :            :             return ScGlobal::GetCalendar()->getDisplayName(
     120         [ +  - ]:         78 :                         i18n::CalendarDisplayIndex::MONTH, sal_Int16(nValue-1), 0);    // 0-based, get short name
     121                 :            :         case sheet::DataPilotFieldGroupBy::DAYS:
     122                 :            :         {
     123                 :          0 :             Date aDate(1, 1, SC_DP_LEAPYEAR);
     124         [ #  # ]:          0 :             aDate += (nValue - 1);            // nValue is 1-based
     125         [ #  # ]:          0 :             Date aNullDate = *pFormatter->GetNullDate();
     126         [ #  # ]:          0 :             long nDays = aDate - aNullDate;
     127                 :            : 
     128         [ #  # ]:          0 :             sal_uLong nFormat = pFormatter->GetFormatIndex(NF_DATE_SYS_DDMMM, ScGlobal::eLnge);
     129                 :            :             Color* pColor;
     130         [ #  # ]:          0 :             String aStr;
     131         [ #  # ]:          0 :             pFormatter->GetOutputString(nDays, nFormat, aStr, &pColor);
     132 [ #  # ][ #  # ]:          0 :             return aStr;
     133                 :            :         }
     134                 :            :         case sheet::DataPilotFieldGroupBy::HOURS:
     135                 :            :         {
     136                 :            :             //! allow am/pm format?
     137                 :          0 :             return getTwoDigitString(nValue);
     138                 :            :         }
     139                 :            :         break;
     140                 :            :         case sheet::DataPilotFieldGroupBy::MINUTES:
     141                 :            :         case sheet::DataPilotFieldGroupBy::SECONDS:
     142                 :            :         {
     143 [ #  # ][ #  # ]:          0 :             rtl::OUStringBuffer aBuf(ScGlobal::pLocaleData->getTimeSep());
     144 [ #  # ][ #  # ]:          0 :             aBuf.append(getTwoDigitString(nValue));
     145         [ #  # ]:          0 :             return aBuf.makeStringAndClear();
     146                 :            :         }
     147                 :            :         break;
     148                 :            :         default:
     149                 :            :             OSL_FAIL("invalid date part");
     150                 :            :     }
     151                 :            : 
     152                 :        213 :     return rtl::OUString::createFromAscii("FIXME: unhandled value");
     153                 :            : }
     154                 :            : 
     155                 :         54 : double ScDPUtil::getNumGroupStartValue(double fValue, const ScDPNumGroupInfo& rInfo)
     156                 :            : {
     157 [ +  + ][ +  - ]:         54 :     if (fValue < rInfo.mfStart && !rtl::math::approxEqual(fValue, rInfo.mfStart))
                 [ +  + ]
     158                 :            :     {
     159                 :         18 :         rtl::math::setInf(&fValue, true);
     160                 :         18 :         return fValue;
     161                 :            :     }
     162                 :            : 
     163 [ +  + ][ +  - ]:         36 :     if (fValue > rInfo.mfEnd && !rtl::math::approxEqual(fValue, rInfo.mfEnd))
                 [ +  + ]
     164                 :            :     {
     165                 :         18 :         rtl::math::setInf(&fValue, false);
     166                 :         18 :         return fValue;
     167                 :            :     }
     168                 :            : 
     169                 :         18 :     double fDiff = fValue - rInfo.mfStart;
     170                 :         18 :     double fDiv = rtl::math::approxFloor( fDiff / rInfo.mfStep );
     171                 :         18 :     double fGroupStart = rInfo.mfStart + fDiv * rInfo.mfStep;
     172                 :            : 
     173         [ -  + ]:         18 :     if (rtl::math::approxEqual(fGroupStart, rInfo.mfEnd) &&
           [ -  +  #  # ]
     174                 :          0 :         !rtl::math::approxEqual(fGroupStart, rInfo.mfStart))
     175                 :            :     {
     176         [ #  # ]:          0 :         if (!rInfo.mbDateValues)
     177                 :            :         {
     178                 :            :             // A group that would consist only of the end value is not
     179                 :            :             // created, instead the value is included in the last group
     180                 :            :             // before. So the previous group is used if the calculated group
     181                 :            :             // start value is the selected end value.
     182                 :            : 
     183                 :          0 :             fDiv -= 1.0;
     184                 :          0 :             return rInfo.mfStart + fDiv * rInfo.mfStep;
     185                 :            :         }
     186                 :            : 
     187                 :            :         // For date values, the end value is instead treated as above the
     188                 :            :         // limit if it would be a group of its own.
     189                 :            : 
     190                 :          0 :         return rInfo.mfEnd + rInfo.mfStep;
     191                 :            :     }
     192                 :            : 
     193                 :         54 :     return fGroupStart;
     194                 :            : }
     195                 :            : 
     196                 :            : namespace {
     197                 :            : 
     198                 :          0 : void lcl_AppendDateStr( rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter )
     199                 :            : {
     200         [ #  # ]:          0 :     sal_uLong nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge );
     201                 :          0 :     rtl::OUString aString;
     202         [ #  # ]:          0 :     pFormatter->GetInputLineString( fValue, nFormat, aString );
     203         [ #  # ]:          0 :     rBuffer.append( aString );
     204                 :          0 : }
     205                 :            : 
     206                 :          6 : rtl::OUString lcl_GetSpecialNumGroupName( double fValue, bool bFirst, sal_Unicode cDecSeparator,
     207                 :            :     bool bDateValues, SvNumberFormatter* pFormatter )
     208                 :            : {
     209                 :            :     OSL_ENSURE( cDecSeparator != 0, "cDecSeparator not initialized" );
     210                 :            : 
     211                 :          6 :     rtl::OUStringBuffer aBuffer;
     212 [ +  - ][ +  + ]:          6 :     aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' ));
     213         [ -  + ]:          6 :     if ( bDateValues )
     214         [ #  # ]:          0 :         lcl_AppendDateStr( aBuffer, fValue, pFormatter );
     215                 :            :     else
     216                 :            :         rtl::math::doubleToUStringBuffer( aBuffer, fValue, rtl_math_StringFormat_Automatic,
     217                 :          6 :         rtl_math_DecimalPlaces_Max, cDecSeparator, true );
     218         [ +  - ]:          6 :     return aBuffer.makeStringAndClear();
     219                 :            : }
     220                 :            : 
     221                 :          9 : rtl::OUString lcl_GetNumGroupName(
     222                 :            :     double fStartValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep,
     223                 :            :     SvNumberFormatter* pFormatter)
     224                 :            : {
     225                 :            :     OSL_ENSURE( cDecSep != 0, "cDecSeparator not initialized" );
     226                 :            : 
     227                 :          9 :     double fStep = rInfo.mfStep;
     228                 :          9 :     double fEndValue = fStartValue + fStep;
     229 [ +  - ][ +  - ]:          9 :     if (rInfo.mbIntegerOnly && (rInfo.mbDateValues || !rtl::math::approxEqual(fEndValue, rInfo.mfEnd)))
         [ +  + ][ +  + ]
     230                 :            :     {
     231                 :            :         //  The second number of the group label is
     232                 :            :         //  (first number + size - 1) if there are only integer numbers,
     233                 :            :         //  (first number + size) if any non-integer numbers are involved.
     234                 :            :         //  Exception: The last group (containing the end value) is always
     235                 :            :         //  shown as including the end value (but not for dates).
     236                 :            : 
     237                 :          6 :         fEndValue -= 1.0;
     238                 :            :     }
     239                 :            : 
     240 [ -  + ][ #  # ]:          9 :     if ( fEndValue > rInfo.mfEnd && !rInfo.mbAutoEnd )
     241                 :            :     {
     242                 :            :         // limit the last group to the end value
     243                 :            : 
     244                 :          0 :         fEndValue = rInfo.mfEnd;
     245                 :            :     }
     246                 :            : 
     247                 :          9 :     rtl::OUStringBuffer aBuffer;
     248         [ -  + ]:          9 :     if ( rInfo.mbDateValues )
     249                 :            :     {
     250         [ #  # ]:          0 :         lcl_AppendDateStr( aBuffer, fStartValue, pFormatter );
     251         [ #  # ]:          0 :         aBuffer.appendAscii( " - " );   // with spaces
     252         [ #  # ]:          0 :         lcl_AppendDateStr( aBuffer, fEndValue, pFormatter );
     253                 :            :     }
     254                 :            :     else
     255                 :            :     {
     256                 :            :         rtl::math::doubleToUStringBuffer( aBuffer, fStartValue, rtl_math_StringFormat_Automatic,
     257                 :          9 :             rtl_math_DecimalPlaces_Max, cDecSep, true );
     258         [ +  - ]:          9 :         aBuffer.append( (sal_Unicode) '-' );
     259                 :            :         rtl::math::doubleToUStringBuffer( aBuffer, fEndValue, rtl_math_StringFormat_Automatic,
     260                 :          9 :             rtl_math_DecimalPlaces_Max, cDecSep, true );
     261                 :            :     }
     262                 :            : 
     263         [ +  - ]:          9 :     return aBuffer.makeStringAndClear();
     264                 :            : }
     265                 :            : 
     266                 :            : }
     267                 :            : 
     268                 :         15 : rtl::OUString ScDPUtil::getNumGroupName(
     269                 :            :     double fValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep, SvNumberFormatter* pFormatter)
     270                 :            : {
     271 [ +  + ][ +  - ]:         15 :     if ( fValue < rInfo.mfStart && !rtl::math::approxEqual( fValue, rInfo.mfStart ) )
                 [ +  + ]
     272                 :          3 :         return lcl_GetSpecialNumGroupName( rInfo.mfStart, true, cDecSep, rInfo.mbDateValues, pFormatter );
     273                 :            : 
     274 [ +  + ][ +  - ]:         12 :     if ( fValue > rInfo.mfEnd && !rtl::math::approxEqual( fValue, rInfo.mfEnd ) )
                 [ +  + ]
     275                 :          3 :         return lcl_GetSpecialNumGroupName( rInfo.mfEnd, false, cDecSep, rInfo.mbDateValues, pFormatter );
     276                 :            : 
     277                 :          9 :     double fDiff = fValue - rInfo.mfStart;
     278                 :          9 :     double fDiv = rtl::math::approxFloor( fDiff / rInfo.mfStep );
     279                 :          9 :     double fGroupStart = rInfo.mfStart + fDiv * rInfo.mfStep;
     280                 :            : 
     281         [ -  + ]:          9 :     if ( rtl::math::approxEqual( fGroupStart, rInfo.mfEnd ) &&
           [ -  +  #  # ]
     282                 :          0 :         !rtl::math::approxEqual( fGroupStart, rInfo.mfStart ) )
     283                 :            :     {
     284         [ #  # ]:          0 :         if (rInfo.mbDateValues)
     285                 :            :         {
     286                 :            :             //  For date values, the end value is instead treated as above the limit
     287                 :            :             //  if it would be a group of its own.
     288                 :          0 :             return lcl_GetSpecialNumGroupName( rInfo.mfEnd, false, cDecSep, rInfo.mbDateValues, pFormatter );
     289                 :            :         }
     290                 :            :     }
     291                 :            : 
     292                 :         15 :     return lcl_GetNumGroupName(fGroupStart, rInfo, cDecSep, pFormatter);
     293                 :            : }
     294                 :            : 
     295                 :        150 : sal_Int32 ScDPUtil::getDatePartValue(
     296                 :            :     double fValue, const ScDPNumGroupInfo& rInfo, sal_Int32 nDatePart,
     297                 :            :     SvNumberFormatter* pFormatter)
     298                 :            : {
     299                 :            :     // Start and end are inclusive
     300                 :            :     // (End date without a time value is included, with a time value it's not)
     301                 :            : 
     302 [ -  + ][ #  # ]:        150 :     if (fValue < rInfo.mfStart && !rtl::math::approxEqual(fValue, rInfo.mfStart))
                 [ -  + ]
     303                 :          0 :         return ScDPItemData::DateFirst;
     304 [ -  + ][ #  # ]:        150 :     if (fValue > rInfo.mfEnd && !rtl::math::approxEqual(fValue, rInfo.mfEnd))
                 [ -  + ]
     305                 :          0 :         return ScDPItemData::DateLast;
     306                 :            : 
     307                 :        150 :     sal_Int32 nResult = 0;
     308                 :            : 
     309 [ +  - ][ +  - ]:        150 :     if (nDatePart == sheet::DataPilotFieldGroupBy::HOURS ||
                 [ -  + ]
     310                 :            :         nDatePart == sheet::DataPilotFieldGroupBy::MINUTES ||
     311                 :            :         nDatePart == sheet::DataPilotFieldGroupBy::SECONDS)
     312                 :            :     {
     313                 :            :         // handle time
     314                 :            :         // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
     315                 :            : 
     316                 :          0 :         double fTime = fValue - rtl::math::approxFloor(fValue);
     317                 :          0 :         long nSeconds = (long)rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5);
     318                 :            : 
     319   [ #  #  #  # ]:          0 :         switch (nDatePart)
     320                 :            :         {
     321                 :            :             case sheet::DataPilotFieldGroupBy::HOURS:
     322                 :          0 :                 nResult = nSeconds / 3600;
     323                 :          0 :                 break;
     324                 :            :             case sheet::DataPilotFieldGroupBy::MINUTES:
     325                 :          0 :                 nResult = ( nSeconds % 3600 ) / 60;
     326                 :          0 :                 break;
     327                 :            :             case sheet::DataPilotFieldGroupBy::SECONDS:
     328                 :          0 :                 nResult = nSeconds % 60;
     329                 :          0 :                 break;
     330                 :          0 :         }
     331                 :            :     }
     332                 :            :     else
     333                 :            :     {
     334         [ +  - ]:        150 :         Date aDate = *(pFormatter->GetNullDate());
     335         [ +  - ]:        150 :         aDate += (long)::rtl::math::approxFloor(fValue);
     336                 :            : 
     337   [ +  +  +  -  :        150 :         switch ( nDatePart )
                      - ]
     338                 :            :         {
     339                 :            :             case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
     340                 :         54 :                 nResult = aDate.GetYear();
     341                 :         54 :                 break;
     342                 :            :             case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS:
     343                 :         48 :                 nResult = 1 + (aDate.GetMonth() - 1) / 3;     // 1..4
     344                 :         48 :                 break;
     345                 :            :             case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
     346                 :         48 :                 nResult = aDate.GetMonth();     // 1..12
     347                 :         48 :                 break;
     348                 :            :             case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
     349                 :            :                 {
     350                 :          0 :                     Date aYearStart(1, 1, aDate.GetYear());
     351         [ #  # ]:          0 :                     nResult = (aDate - aYearStart) + 1;       // Jan 01 has value 1
     352 [ #  # ][ #  # ]:          0 :                     if (nResult >= 60 && !aDate.IsLeapYear())
         [ #  # ][ #  # ]
     353                 :            :                     {
     354                 :            :                         // days are counted from 1 to 366 - if not from a leap year, adjust
     355                 :          0 :                         ++nResult;
     356                 :            :                     }
     357                 :            :                 }
     358                 :        150 :                 break;
     359                 :            :             default:
     360                 :            :                 OSL_FAIL("invalid date part");
     361                 :            :         }
     362                 :            :     }
     363                 :            : 
     364                 :        150 :     return nResult;
     365                 :            : }
     366                 :            : 
     367                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10