LCOV - code coverage report
Current view: top level - scaddins/source/datefunc - datefunc.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 270 321 84.1 %
Date: 2014-11-03 Functions: 47 56 83.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 "datefunc.hxx"
      21             : #include "datefunc.hrc"
      22             : #include <com/sun/star/util/Date.hpp>
      23             : #include <cppuhelper/factory.hxx>
      24             : #include <cppuhelper/supportsservice.hxx>
      25             : #include <osl/diagnose.h>
      26             : #include <rtl/ustrbuf.hxx>
      27             : #include <tools/rcid.h>
      28             : #include <tools/resmgr.hxx>
      29             : 
      30             : using namespace ::com::sun::star;
      31             : 
      32             : #define ADDIN_SERVICE           "com.sun.star.sheet.AddIn"
      33             : #define MY_SERVICE              "com.sun.star.sheet.addin.DateFunctions"
      34             : #define MY_IMPLNAME             "com.sun.star.sheet.addin.DateFunctionsImpl"
      35             : 
      36             : #define STR_FROM_ANSI( s )      OUString( s, strlen( s ), RTL_TEXTENCODING_MS_1252 )
      37             : 
      38             : const sal_uInt32 ScaList::nStartSize = 16;
      39             : const sal_uInt32 ScaList::nIncrSize = 16;
      40             : 
      41         198 : ScaList::ScaList() :
      42         198 :     pData( new void*[ nStartSize ] ),
      43             :     nSize( nStartSize ),
      44             :     nCount( 0 ),
      45         396 :     nCurr( 0 )
      46             : {
      47         198 : }
      48             : 
      49          90 : ScaList::~ScaList()
      50             : {
      51          90 :     delete[] pData;
      52          90 : }
      53             : 
      54           0 : void ScaList::_Grow()
      55             : {
      56           0 :     nSize += nIncrSize;
      57             : 
      58           0 :     void** pNewData = new void*[ nSize ];
      59           0 :     memcpy( pNewData, pData, nCount * sizeof( void* ) );
      60             : 
      61           0 :     delete[] pData;
      62           0 :     pData = pNewData;
      63           0 : }
      64             : 
      65         160 : ScaStringList::~ScaStringList()
      66             : {
      67         240 :     for( OUString* pStr = First(); pStr; pStr = Next() )
      68         160 :         delete pStr;
      69          80 : }
      70             : 
      71        3080 : ScaResId::ScaResId( sal_uInt16 nId, ResMgr& rResMgr ) :
      72        3080 :     ResId( nId, rResMgr )
      73             : {
      74        3080 : }
      75             : 
      76             : #define UNIQUE              false   // function name does not exist in Calc
      77             : 
      78             : #define STDPAR              false   // all parameters are described
      79             : #define INTPAR              true    // first parameter is internal
      80             : 
      81             : #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar )  \
      82             :     { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
      83             : 
      84             : const ScaFuncDataBase pFuncDataArr[] =
      85             : {
      86             :     FUNCDATA( DiffWeeks,    3, ScaCat_DateTime, UNIQUE, INTPAR ),
      87             :     FUNCDATA( DiffMonths,   3, ScaCat_DateTime, UNIQUE, INTPAR ),
      88             :     FUNCDATA( DiffYears,    3, ScaCat_DateTime, UNIQUE, INTPAR ),
      89             :     FUNCDATA( IsLeapYear,   1, ScaCat_DateTime, UNIQUE, INTPAR ),
      90             :     FUNCDATA( DaysInMonth,  1, ScaCat_DateTime, UNIQUE, INTPAR ),
      91             :     FUNCDATA( DaysInYear,   1, ScaCat_DateTime, UNIQUE, INTPAR ),
      92             :     FUNCDATA( WeeksInYear,  1, ScaCat_DateTime, UNIQUE, INTPAR ),
      93             :     FUNCDATA( Rot13,        1, ScaCat_Text,     UNIQUE, STDPAR )
      94             : };
      95             : 
      96             : #undef FUNCDATA
      97             : 
      98         176 : ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rResMgr ) :
      99             :     aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
     100             :     nUINameID( rBaseData.nUINameID ),
     101             :     nDescrID( rBaseData.nDescrID ),
     102             :     nCompListID( rBaseData.nCompListID ),
     103             :     nParamCount( rBaseData.nParamCount ),
     104             :     eCat( rBaseData.eCat ),
     105             :     bDouble( rBaseData.bDouble ),
     106         176 :     bWithOpt( rBaseData.bWithOpt )
     107             : {
     108         176 :     ScaResStringArrLoader aArrLoader( RID_DATE_DEFFUNCTION_NAMES, nCompListID, rResMgr );
     109         176 :     const ResStringArray& rArr = aArrLoader.GetStringArray();
     110             : 
     111         528 :     for( sal_uInt16 nIndex = 0; nIndex < rArr.Count(); nIndex++ )
     112         528 :         aCompList.Append( rArr.GetString( nIndex ) );
     113         176 : }
     114             : 
     115         160 : ScaFuncData::~ScaFuncData()
     116             : {
     117         160 : }
     118             : 
     119         616 : sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
     120             : {
     121         616 :     if( !bWithOpt )
     122          44 :         nParam++;
     123         616 :     return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
     124             : }
     125             : 
     126             : 
     127          22 : ScaFuncDataList::ScaFuncDataList( ResMgr& rResMgr ) :
     128          22 :     nLast( 0xFFFFFFFF )
     129             : {
     130         198 :     for( sal_uInt16 nIndex = 0; nIndex < SAL_N_ELEMENTS(pFuncDataArr); nIndex++ )
     131         176 :         Append( new ScaFuncData( pFuncDataArr[ nIndex ], rResMgr ) );
     132          22 : }
     133             : 
     134          30 : ScaFuncDataList::~ScaFuncDataList()
     135             : {
     136          90 :     for( ScaFuncData* pFData = First(); pFData; pFData = Next() )
     137          80 :         delete pFData;
     138          20 : }
     139             : 
     140        1224 : const ScaFuncData* ScaFuncDataList::Get( const OUString& rProgrammaticName ) const
     141             : {
     142        1224 :     if( aLastName == rProgrammaticName )
     143         968 :         return Get( nLast );
     144             : 
     145        1152 :     for( sal_uInt32 nIndex = 0; nIndex < Count(); nIndex++ )
     146             :     {
     147        1152 :         const ScaFuncData* pCurr = Get( nIndex );
     148        1152 :         if( pCurr->Is( rProgrammaticName ) )
     149             :         {
     150         256 :             const_cast< ScaFuncDataList* >( this )->aLastName = rProgrammaticName;
     151         256 :             const_cast< ScaFuncDataList* >( this )->nLast = nIndex;
     152         256 :             return pCurr;
     153             :         }
     154             :     }
     155           0 :     return NULL;
     156             : }
     157             : 
     158         792 : ScaFuncRes::ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, OUString& rRet ) :
     159         792 :     Resource( rResId )
     160             : {
     161         792 :     rRet = ScaResId(nIndex, rResMgr).toString();
     162         792 :     FreeResource();
     163         792 : }
     164             : 
     165             : //  entry points for service registration / instantiation
     166          22 : uno::Reference< uno::XInterface > SAL_CALL ScaDateAddIn_CreateInstance(
     167             :         const uno::Reference< lang::XMultiServiceFactory >& )
     168             : {
     169          22 :     static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new ScaDateAddIn();
     170          22 :     return xInst;
     171             : }
     172             : 
     173             : extern "C" {
     174             : 
     175          22 : SAL_DLLPUBLIC_EXPORT void * SAL_CALL date_component_getFactory(
     176             :     const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
     177             : {
     178          22 :     void* pRet = 0;
     179             : 
     180         110 :     if ( pServiceManager &&
     181         110 :             OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() )
     182             :     {
     183             :         uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
     184             :                 reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ),
     185             :                 ScaDateAddIn::getImplementationName_Static(),
     186             :                 ScaDateAddIn_CreateInstance,
     187          22 :                 ScaDateAddIn::getSupportedServiceNames_Static() ) );
     188             : 
     189          22 :         if (xFactory.is())
     190             :         {
     191          22 :             xFactory->acquire();
     192          22 :             pRet = xFactory.get();
     193          22 :         }
     194             :     }
     195             : 
     196          22 :     return pRet;
     197             : }
     198             : 
     199             : }   // extern C
     200             : 
     201             : //  "normal" service implementation
     202          22 : ScaDateAddIn::ScaDateAddIn() :
     203             :     pDefLocales( NULL ),
     204             :     pResMgr( NULL ),
     205          22 :     pFuncDataList( NULL )
     206             : {
     207          22 : }
     208             : 
     209          30 : ScaDateAddIn::~ScaDateAddIn()
     210             : {
     211          10 :     if( pFuncDataList )
     212          10 :         delete pFuncDataList;
     213          10 :     if( pDefLocales )
     214           2 :         delete[] pDefLocales;
     215             : 
     216             :     // pResMgr already deleted (_all_ resource managers are deleted _before_ this dtor is called)
     217          20 : }
     218             : 
     219             : static const sal_Char*  pLang[] = { "de", "en" };
     220             : static const sal_Char*  pCoun[] = { "DE", "US" };
     221             : static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
     222             : 
     223          10 : void ScaDateAddIn::InitDefLocales()
     224             : {
     225          10 :     pDefLocales = new lang::Locale[ nNumOfLoc ];
     226             : 
     227          30 :     for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
     228             :     {
     229          20 :         pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
     230          20 :         pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
     231             :     }
     232          10 : }
     233             : 
     234         160 : const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
     235             : {
     236         160 :     if( !pDefLocales )
     237          10 :         InitDefLocales();
     238             : 
     239         160 :     return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc;
     240             : }
     241             : 
     242        2552 : ResMgr& ScaDateAddIn::GetResMgr() throw( uno::RuntimeException )
     243             : {
     244        2552 :     if( !pResMgr )
     245             :     {
     246           0 :         InitData();     // try to get resource manager
     247           0 :         if( !pResMgr )
     248           0 :             throw uno::RuntimeException();
     249             :     }
     250        2552 :     return *pResMgr;
     251             : }
     252             : 
     253          22 : void ScaDateAddIn::InitData()
     254             : {
     255          22 :     if( pResMgr )
     256           0 :         delete pResMgr;
     257             : 
     258          22 :     OString aModName( "date" );
     259          22 :     pResMgr = ResMgr::CreateResMgr( aModName.getStr(), LanguageTag( aFuncLoc) );
     260             : 
     261          22 :     if( pFuncDataList )
     262           0 :         delete pFuncDataList;
     263             : 
     264          22 :     pFuncDataList = pResMgr ? new ScaFuncDataList( *pResMgr ) : NULL;
     265             : 
     266          22 :     if( pDefLocales )
     267             :     {
     268           0 :         delete pDefLocales;
     269           0 :         pDefLocales = NULL;
     270          22 :     }
     271          22 : }
     272             : 
     273         176 : OUString ScaDateAddIn::GetDisplFuncStr( sal_uInt16 nResId ) throw( uno::RuntimeException )
     274             : {
     275         176 :     return ScaResStringLoader( RID_DATE_FUNCTION_NAMES, nResId, GetResMgr() ).GetString();
     276             : }
     277             : 
     278         792 : OUString ScaDateAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( uno::RuntimeException )
     279             : {
     280         792 :     OUString aRet;
     281             : 
     282        1584 :     ScaResPublisher aResPubl( ScaResId( RID_DATE_FUNCTION_DESCRIPTIONS, GetResMgr() ) );
     283         792 :     ScaResId aResId( nResId, GetResMgr() );
     284         792 :     aResId.SetRT( RSC_RESOURCE );
     285             : 
     286         792 :     if( aResPubl.IsAvailableRes( aResId ) )
     287         792 :         ScaFuncRes aSubRes( aResId, GetResMgr(), nStrIndex, aRet );
     288             : 
     289         792 :     aResPubl.FreeResource();
     290        1584 :     return aRet;
     291             : }
     292             : 
     293          44 : OUString ScaDateAddIn::getImplementationName_Static()
     294             : {
     295          44 :     return OUString( MY_IMPLNAME );
     296             : }
     297             : 
     298          22 : uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static()
     299             : {
     300          22 :     uno::Sequence< OUString > aRet( 2 );
     301          22 :     OUString* pArray = aRet.getArray();
     302          22 :     pArray[0] = OUString( ADDIN_SERVICE );
     303          22 :     pArray[1] = OUString( MY_SERVICE );
     304          22 :     return aRet;
     305             : }
     306             : 
     307             : // XServiceName
     308          22 : OUString SAL_CALL ScaDateAddIn::getServiceName() throw( uno::RuntimeException, std::exception )
     309             : {
     310             :     // name of specific AddIn service
     311          22 :     return OUString( MY_SERVICE );
     312             : }
     313             : 
     314             : // XServiceInfo
     315           0 : OUString SAL_CALL ScaDateAddIn::getImplementationName() throw( uno::RuntimeException, std::exception )
     316             : {
     317           0 :     return getImplementationName_Static();
     318             : }
     319             : 
     320           0 : sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) throw( uno::RuntimeException, std::exception )
     321             : {
     322           0 :     return cppu::supportsService(this, aServiceName);
     323             : }
     324             : 
     325           0 : uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() throw( uno::RuntimeException, std::exception )
     326             : {
     327           0 :     return getSupportedServiceNames_Static();
     328             : }
     329             : 
     330             : // XLocalizable
     331          22 : void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) throw( uno::RuntimeException, std::exception )
     332             : {
     333          22 :     aFuncLoc = eLocale;
     334          22 :     InitData();     // change of locale invalidates resources!
     335          22 : }
     336             : 
     337           0 : lang::Locale SAL_CALL ScaDateAddIn::getLocale() throw( uno::RuntimeException, std::exception )
     338             : {
     339           0 :     return aFuncLoc;
     340             : }
     341             : 
     342           0 : OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) throw( uno::RuntimeException, std::exception )
     343             : {
     344             :     //  not used by calc
     345             :     //  (but should be implemented for other uses of the AddIn service)
     346           0 :     return OUString();
     347             : }
     348             : 
     349         176 : OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
     350             : {
     351         176 :     OUString aRet;
     352             : 
     353         176 :     const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
     354         176 :     if( pFData )
     355             :     {
     356         176 :         aRet = GetDisplFuncStr( pFData->GetUINameID() );
     357         176 :         if( pFData->IsDouble() )
     358           0 :             aRet += STR_FROM_ANSI( "_ADD" );
     359             :     }
     360             :     else
     361             :     {
     362           0 :         aRet = STR_FROM_ANSI( "UNKNOWNFUNC_" );
     363           0 :         aRet += aProgrammaticName;
     364             :     }
     365             : 
     366         176 :     return aRet;
     367             : }
     368             : 
     369         176 : OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
     370             : {
     371         176 :     OUString aRet;
     372             : 
     373         176 :     const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
     374         176 :     if( pFData )
     375         176 :         aRet = GetFuncDescrStr( pFData->GetDescrID(), 1 );
     376             : 
     377         176 :     return aRet;
     378             : }
     379             : 
     380         308 : OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
     381             :         const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException, std::exception )
     382             : {
     383         308 :     OUString aRet;
     384             : 
     385         308 :     const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
     386         308 :     if( pFData && (nArgument <= 0xFFFF) )
     387             :     {
     388         308 :         sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
     389         308 :         if( nStr )
     390         308 :             aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr );
     391             :         else
     392           0 :             aRet = STR_FROM_ANSI( "internal" );
     393             :     }
     394             : 
     395         308 :     return aRet;
     396             : }
     397             : 
     398         308 : OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
     399             :         const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException, std::exception )
     400             : {
     401         308 :     OUString aRet;
     402             : 
     403         308 :     const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
     404         308 :     if( pFData && (nArgument <= 0xFFFF) )
     405             :     {
     406         308 :         sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
     407         308 :         if( nStr )
     408         308 :             aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr + 1 );
     409             :         else
     410           0 :             aRet = STR_FROM_ANSI( "for internal use only" );
     411             :     }
     412             : 
     413         308 :     return aRet;
     414             : }
     415             : 
     416         176 : OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
     417             :         const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
     418             : {
     419         176 :     OUString aRet;
     420             : 
     421         176 :     const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
     422         176 :     if( pFData )
     423             :     {
     424         176 :         switch( pFData->GetCategory() )
     425             :         {
     426         154 :             case ScaCat_DateTime:   aRet = STR_FROM_ANSI( "Date&Time" );    break;
     427          22 :             case ScaCat_Text:       aRet = STR_FROM_ANSI( "Text" );         break;
     428           0 :             case ScaCat_Finance:    aRet = STR_FROM_ANSI( "Financial" );    break;
     429           0 :             case ScaCat_Inf:        aRet = STR_FROM_ANSI( "Information" );  break;
     430           0 :             case ScaCat_Math:       aRet = STR_FROM_ANSI( "Mathematical" ); break;
     431           0 :             case ScaCat_Tech:       aRet = STR_FROM_ANSI( "Technical" );    break;
     432             :             default:    // to prevent compiler warnings
     433           0 :                 break;
     434             :         }
     435             :     }
     436             : 
     437         176 :     if( aRet.isEmpty() )
     438           0 :         aRet = STR_FROM_ANSI( "Add-In" );
     439         176 :     return aRet;
     440             : }
     441             : 
     442           0 : OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
     443             :         const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
     444             : {
     445           0 :     return getProgrammaticCategoryName( aProgrammaticName );
     446             : }
     447             : 
     448             : // XCompatibilityNames
     449          80 : uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
     450             :         const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
     451             : {
     452          80 :     const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
     453          80 :     if( !pFData )
     454           0 :         return uno::Sequence< sheet::LocalizedName >( 0 );
     455             : 
     456          80 :     const ScaStringList& rStrList = pFData->GetCompNameList();
     457          80 :     sal_uInt32 nCount = rStrList.Count();
     458             : 
     459          80 :     uno::Sequence< sheet::LocalizedName > aRet( nCount );
     460          80 :     sheet::LocalizedName* pArray = aRet.getArray();
     461             : 
     462         240 :     for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
     463         160 :         pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), *rStrList.Get( nIndex ) );
     464             : 
     465          80 :     return aRet;
     466             : }
     467             : 
     468             : namespace {
     469             : 
     470             : // auxiliary functions
     471          78 : bool IsLeapYear( sal_uInt16 nYear )
     472             : {
     473          78 :     return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
     474             : }
     475             : 
     476         472 : sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
     477             : {
     478             :     static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
     479             :                                         31, 31, 30, 31, 30, 31 };
     480             : 
     481         472 :     if ( nMonth != 2 )
     482         402 :         return aDaysInMonth[nMonth-1];
     483             :     else
     484             :     {
     485          70 :         if ( IsLeapYear(nYear) )
     486          12 :             return aDaysInMonth[nMonth-1] + 1;
     487             :         else
     488          58 :             return aDaysInMonth[nMonth-1];
     489             :     }
     490             : }
     491             : 
     492             : /**
     493             :  * Convert a date to a count of days starting from 01/01/0001
     494             :  *
     495             :  * The internal representation of a Date used in this Addin
     496             :  * is the number of days between 01/01/0001 and the date
     497             :  * this function converts a Day , Month, Year representation
     498             :  * to this internal Date value.
     499             :  */
     500             : 
     501          36 : sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
     502             : {
     503          36 :     sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
     504          36 :     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
     505             : 
     506         366 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
     507         330 :         nDays += DaysInMonth(i,nYear);
     508          36 :     nDays += nDay;
     509             : 
     510          36 :     return nDays;
     511             : }
     512             : 
     513             : /**
     514             :  * Convert a count of days starting from 01/01/0001 to a date
     515             :  *
     516             :  * The internal representation of a Date used in this Addin
     517             :  * is the number of days between 01/01/0001 and the date
     518             :  * this function converts this internal Date value
     519             :  * to a Day , Month, Year representation of a Date.
     520             :  */
     521             : 
     522          36 : void DaysToDate( sal_Int32 nDays,
     523             :                 sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
     524             :         throw( lang::IllegalArgumentException )
     525             : {
     526          36 :     if( nDays < 0 )
     527           0 :         throw lang::IllegalArgumentException();
     528             : 
     529             :     sal_Int32   nTempDays;
     530          36 :     sal_Int32   i = 0;
     531             :     bool    bCalc;
     532             : 
     533          36 :     do
     534             :     {
     535          36 :         nTempDays = nDays;
     536          36 :         rYear = (sal_uInt16)((nTempDays / 365) - i);
     537          36 :         nTempDays -= ((sal_Int32) rYear -1) * 365;
     538          36 :         nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
     539          36 :         bCalc = false;
     540          36 :         if ( nTempDays < 1 )
     541             :         {
     542           0 :             i++;
     543           0 :             bCalc = true;
     544             :         }
     545             :         else
     546             :         {
     547          36 :             if ( nTempDays > 365 )
     548             :             {
     549           0 :                 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
     550             :                 {
     551           0 :                     i--;
     552           0 :                     bCalc = true;
     553             :                 }
     554             :             }
     555             :         }
     556             :     }
     557             :     while ( bCalc );
     558             : 
     559          36 :     rMonth = 1;
     560         122 :     while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
     561             :     {
     562          50 :         nTempDays -= DaysInMonth( rMonth, rYear );
     563          50 :         rMonth++;
     564             :     }
     565          36 :     rDay = (sal_uInt16)nTempDays;
     566          36 : }
     567             : 
     568             : /**
     569             :  * Get the null date used by the spreadsheet document
     570             :  *
     571             :  * The internal representation of a Date used in this Addin
     572             :  * is the number of days between 01/01/0001 and the date
     573             :  * this function returns this internal Date value for the document null date
     574             :  *
     575             :  */
     576          30 : sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
     577             :         throw( uno::RuntimeException )
     578             : {
     579          30 :     if (xOptions.is())
     580             :     {
     581             :         try
     582             :         {
     583          30 :             uno::Any aAny = xOptions->getPropertyValue(
     584          30 :                                         OUString( "NullDate" ) );
     585          30 :             util::Date aDate;
     586          30 :             if ( aAny >>= aDate )
     587          60 :                 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
     588             :         }
     589           0 :         catch (uno::Exception&)
     590             :         {
     591             :         }
     592             :     }
     593             : 
     594             :     // no null date available -> no calculations possible
     595           0 :     throw uno::RuntimeException();
     596             : }
     597             : 
     598             : }
     599             : // XDateFunctions
     600             : 
     601             : /**
     602             :  * Get week difference between 2 dates
     603             :  *
     604             :  * new Weeks(date1,date2,mode) function for StarCalc
     605             :  *
     606             :  * Two modes of operation are provided.
     607             :  * The first is just a simple division by 7 calculation.
     608             :  *
     609             :  * The second calculates the diffence by week of year.
     610             :  *
     611             :  * The International Standard IS-8601 has decreed that Monday
     612             :  * shall be the first day of the week.
     613             :  *
     614             :  * A week that lies partly in one year and partly in annother
     615             :  * is assigned a number in the year in which most of its days lie.
     616             :  *
     617             :  * That means that week 1 of any year is the week that contains the 4. January
     618             :  *
     619             :  * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
     620             :  *
     621             :  * A WeekDay can be then calculated by subtracting 1 and calculating the rest of
     622             :  * a division by 7, which gives a 0 - 6 value for Monday - Sunday
     623             :  *
     624             :  * Using the 4. January rule explained above the formula
     625             :  *
     626             :  *  nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
     627             :  *
     628             :  * calculates a number between 0-53 for each day which is in the same year as nJan4
     629             :  * where 0 means that this week belonged to the year before.
     630             :  *
     631             :  * If a day in the same or another year is used in this formula this calculates
     632             :  * an calendar week offset from a given 4. January
     633             :  *
     634             :  *  nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
     635             :  *
     636             :  * The 4.January of first Date Argument can thus be used to calculate
     637             :  * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
     638             :  *
     639             :  * which can be optimized to
     640             :  *
     641             :  * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
     642             :  *
     643             :  * Note: All calculations are operating on the long integer data type
     644             :  * % is the modulo operator in C which calculates the rest of an Integer division
     645             :  *
     646             :  *
     647             :  * mode 0 is the interval between the dates in month, that is days / 7
     648             :  *
     649             :  * mode 1 is the difference by week of year
     650             :  *
     651             :  */
     652             : 
     653           4 : sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
     654             :         const uno::Reference< beans::XPropertySet >& xOptions,
     655             :         sal_Int32 nStartDate, sal_Int32 nEndDate,
     656             :         sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     657             : {
     658           4 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     659             : 
     660           4 :     sal_Int32 nDays1 = nStartDate + nNullDate;
     661           4 :     sal_Int32 nDays2 = nEndDate + nNullDate;
     662             : 
     663             :     sal_Int32 nRet;
     664             : 
     665           4 :     if ( nMode == 1 )
     666             :     {
     667             :         sal_uInt16 nDay,nMonth,nYear;
     668           2 :         DaysToDate( nDays1, nDay, nMonth, nYear );
     669           2 :         sal_Int32 nJan4 = DateToDays( 4, 1, nYear );
     670             : 
     671           2 :         nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 );
     672             :     }
     673             :     else
     674             :     {
     675           2 :         nRet = (nDays2 - nDays1) / 7;
     676             :     }
     677           4 :     return nRet;
     678             : }
     679             : 
     680             : /**
     681             :  * Get month difference between 2 dates
     682             :  * =Month(start, end, mode) Function for StarCalc
     683             :  *
     684             :  * two modes are provided
     685             :  *
     686             :  * mode 0 is the interval between the dates in month
     687             :  *
     688             :  * mode 1 is the difference in calendar month
     689             :  */
     690           6 : sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
     691             :         const uno::Reference< beans::XPropertySet >& xOptions,
     692             :         sal_Int32 nStartDate, sal_Int32 nEndDate,
     693             :         sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     694             : {
     695           6 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     696             : 
     697           6 :     sal_Int32 nDays1 = nStartDate + nNullDate;
     698           6 :     sal_Int32 nDays2 = nEndDate + nNullDate;
     699             : 
     700             :     sal_uInt16 nDay1,nMonth1,nYear1;
     701             :     sal_uInt16 nDay2,nMonth2,nYear2;
     702           6 :     DaysToDate(nDays1,nDay1,nMonth1,nYear1);
     703           6 :     DaysToDate(nDays2,nDay2,nMonth2,nYear2);
     704             : 
     705           6 :     sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
     706           6 :     if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
     707             : 
     708           4 :     if ( nDays1 < nDays2 )
     709             :     {
     710           4 :         if ( nDay1 > nDay2 )
     711             :         {
     712           2 :             nRet -= 1;
     713             :         }
     714             :     }
     715             :     else
     716             :     {
     717           0 :         if ( nDay1 < nDay2 )
     718             :         {
     719           0 :             nRet += 1;
     720             :         }
     721             :     }
     722             : 
     723           4 :     return nRet;
     724             : }
     725             : 
     726             : /**
     727             :  * Get Year difference between 2 dates
     728             :  *
     729             :  * two modes are provided
     730             :  *
     731             :  * mode 0 is the interval between the dates in years
     732             :  *
     733             :  * mode 1 is the difference in calendar years
     734             :  */
     735           4 : sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
     736             :         const uno::Reference< beans::XPropertySet >& xOptions,
     737             :         sal_Int32 nStartDate, sal_Int32 nEndDate,
     738             :         sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     739             : {
     740           4 :     if ( nMode != 1 )
     741           2 :         return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
     742             : 
     743           2 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     744             : 
     745           2 :     sal_Int32 nDays1 = nStartDate + nNullDate;
     746           2 :     sal_Int32 nDays2 = nEndDate + nNullDate;
     747             : 
     748             :     sal_uInt16 nDay1,nMonth1,nYear1;
     749             :     sal_uInt16 nDay2,nMonth2,nYear2;
     750           2 :     DaysToDate(nDays1,nDay1,nMonth1,nYear1);
     751           2 :     DaysToDate(nDays2,nDay2,nMonth2,nYear2);
     752             : 
     753           2 :     return nYear2 - nYear1;
     754             : }
     755             : 
     756             : /**
     757             :  * Check if a Date is in a leap year in the Gregorian calendar
     758             :  */
     759           4 : sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
     760             :         const uno::Reference< beans::XPropertySet >& xOptions,
     761             :         sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     762             : {
     763           4 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     764           4 :     sal_Int32 nDays = nDate + nNullDate;
     765             : 
     766             :     sal_uInt16 nDay, nMonth, nYear;
     767           4 :     DaysToDate(nDays,nDay,nMonth,nYear);
     768             : 
     769           4 :     return (sal_Int32)IsLeapYear(nYear);
     770             : }
     771             : 
     772             : /**
     773             :  * Get the Number of Days in the month for a date
     774             :  */
     775           6 : sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
     776             :         const uno::Reference<beans::XPropertySet>& xOptions,
     777             :         sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     778             : {
     779           6 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     780           6 :     sal_Int32 nDays = nDate + nNullDate;
     781             : 
     782             :     sal_uInt16 nDay, nMonth, nYear;
     783           6 :     DaysToDate(nDays,nDay,nMonth,nYear);
     784             : 
     785           6 :     return DaysInMonth( nMonth, nYear );
     786             : }
     787             : 
     788             : /**
     789             :  * Get number of days in the year of a date specified
     790             :  */
     791           4 : sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
     792             :         const uno::Reference< beans::XPropertySet >& xOptions,
     793             :         sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     794             : {
     795           4 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     796           4 :     sal_Int32 nDays = nDate + nNullDate;
     797             : 
     798             :     sal_uInt16 nDay, nMonth, nYear;
     799           4 :     DaysToDate(nDays,nDay,nMonth,nYear);
     800             : 
     801           4 :     return ( IsLeapYear(nYear) ? 366 : 365 );
     802             : }
     803             : 
     804             : /**
     805             :  * Get number of weeks in the year for a date
     806             :  *
     807             :  * Most years have 52 weeks, but years that start on a Thursday
     808             :  * and leep years that start on a Wednesday have 53 weeks
     809             :  *
     810             :  * The International Standard IS-8601 has decreed that Monday
     811             :  * shall be the first day of the week.
     812             :  *
     813             :  * A WeekDay can be calculated by subtracting 1 and calculating the rest of
     814             :  * a division by 7 from the internal date represention
     815             :  * which gives a 0 - 6 value for Monday - Sunday
     816             :  *
     817             :  * @see #IsLeapYear #WeekNumber
     818             :  */
     819           4 : sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
     820             :         const uno::Reference< beans::XPropertySet >& xOptions,
     821             :         sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     822             : {
     823           4 :     sal_Int32 nNullDate = GetNullDate( xOptions );
     824           4 :     sal_Int32 nDays = nDate + nNullDate;
     825             : 
     826             :     sal_uInt16 nDay, nMonth, nYear;
     827           4 :     DaysToDate(nDays,nDay,nMonth,nYear);
     828             : 
     829           4 :     sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
     830             : 
     831             :     sal_Int32 nRet;
     832           4 :     if ( nJan1WeekDay == 3 )        /* Thursday */
     833           0 :         nRet = 53;
     834           4 :     else if ( nJan1WeekDay == 2 )   /* Wednesday */
     835           0 :         nRet = ( IsLeapYear(nYear) ? 53 : 52 );
     836             :     else
     837           4 :         nRet = 52;
     838             : 
     839           4 :     return nRet;
     840             : }
     841             : 
     842             : /**
     843             :  * Encrypt or decrypt a string using ROT13 algorithm
     844             :  *
     845             :  * This function rotates each character by 13 in the alphabet.
     846             :  * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
     847             :  */
     848           4 : OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
     849             : {
     850           4 :     OUStringBuffer aBuffer( aSrcString );
     851          24 :     for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
     852             :     {
     853          20 :         sal_Unicode cChar = aBuffer[nIndex];
     854          28 :         if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) ||
     855          12 :             ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) )
     856           8 :             cChar -= 26;
     857          20 :         aBuffer[nIndex] = cChar;
     858             :     }
     859           4 :     return aBuffer.makeStringAndClear();
     860             : }
     861             : 
     862             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10