diff options
Diffstat (limited to 'scaddins/source/datefunc')
-rw-r--r-- | scaddins/source/datefunc/date.component | 26 | ||||
-rw-r--r-- | scaddins/source/datefunc/datefunc.cxx | 760 | ||||
-rw-r--r-- | scaddins/source/datefunc/datefunc.hxx | 198 | ||||
-rw-r--r-- | scaddins/source/datefunc/deffuncname.hxx | 73 |
4 files changed, 1057 insertions, 0 deletions
diff --git a/scaddins/source/datefunc/date.component b/scaddins/source/datefunc/date.component new file mode 100644 index 000000000..7bbf766a5 --- /dev/null +++ b/scaddins/source/datefunc/date.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="date" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.sheet.addin.DateFunctionsImpl"> + <service name="com.sun.star.sheet.AddIn"/> + <service name="com.sun.star.sheet.addin.DateFunctions"/> + </implementation> +</component> diff --git a/scaddins/source/datefunc/datefunc.cxx b/scaddins/source/datefunc/datefunc.cxx new file mode 100644 index 000000000..f47b9b74a --- /dev/null +++ b/scaddins/source/datefunc/datefunc.cxx @@ -0,0 +1,760 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "datefunc.hxx" +#include <datefunc.hrc> +#include <strings.hrc> +#include <com/sun/star/util/Date.hpp> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <rtl/ustrbuf.hxx> +#include <unotools/resmgr.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <algorithm> +#include "deffuncname.hxx" + +using namespace ::com::sun::star; + +#define ADDIN_SERVICE "com.sun.star.sheet.AddIn" +#define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions" +#define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl" + +#define UNIQUE false // function name does not exist in Calc + +#define STDPAR false // all parameters are described +#define INTPAR true // first parameter is internal + +#define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \ + { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar } + +const ScaFuncDataBase pFuncDataArr[] = +{ + FUNCDATA( DiffWeeks, 3, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( DiffMonths, 3, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( DiffYears, 3, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( IsLeapYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( DaysInMonth, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( DaysInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( WeeksInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), + FUNCDATA( Rot13, 1, ScaCategory::Text, UNIQUE, STDPAR ) +}; + +#undef FUNCDATA + +ScaFuncData::ScaFuncData(const ScaFuncDataBase& rBaseData) : + aIntName( OUString::createFromAscii( rBaseData.pIntName ) ), + pUINameID( rBaseData.pUINameID ), + pDescrID( rBaseData.pDescrID ), + nParamCount( rBaseData.nParamCount ), + eCat( rBaseData.eCat ), + bDouble( rBaseData.bDouble ), + bWithOpt( rBaseData.bWithOpt ) +{ + aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[0])); + aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[1])); +} + +sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const +{ + if( !bWithOpt ) + nParam++; + return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2); +} + +static void InitScaFuncDataList(ScaFuncDataList& rList) +{ + for (const auto & nIndex : pFuncDataArr) + rList.push_back(ScaFuncData(nIndex)); +} + +// entry points for service registration / instantiation +static uno::Reference< uno::XInterface > ScaDateAddIn_CreateInstance( + const uno::Reference< lang::XMultiServiceFactory >& ) +{ + return static_cast<cppu::OWeakObject*>(new ScaDateAddIn()); +} + +extern "C" { + +SAL_DLLPUBLIC_EXPORT void * date_component_getFactory( + const char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void* pRet = nullptr; + + if ( pServiceManager && + OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() ) + { + uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory( + static_cast< lang::XMultiServiceFactory* >( pServiceManager ), + ScaDateAddIn::getImplementationName_Static(), + ScaDateAddIn_CreateInstance, + ScaDateAddIn::getSupportedServiceNames_Static() ) ); + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern C + +// "normal" service implementation +ScaDateAddIn::ScaDateAddIn() +{ +} + +static const char* pLang[] = { "de", "en" }; +static const char* pCoun[] = { "DE", "US" }; +static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang ); + +void ScaDateAddIn::InitDefLocales() +{ + pDefLocales.reset(new lang::Locale[ nNumOfLoc ]); + + for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ ) + { + pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] ); + pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] ); + } +} + +const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex ) +{ + if( !pDefLocales ) + InitDefLocales(); + + return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc; +} + +void ScaDateAddIn::InitData() +{ + aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc)); + pFuncDataList.reset(); + + pFuncDataList.reset(new ScaFuncDataList); + InitScaFuncDataList(*pFuncDataList); + + if( pDefLocales ) + { + pDefLocales.reset(); + } +} + +OUString ScaDateAddIn::GetFuncDescrStr(const char** pResId, sal_uInt16 nStrIndex) +{ + return ScaResId(pResId[nStrIndex - 1]); +} + +OUString ScaDateAddIn::getImplementationName_Static() +{ + return MY_IMPLNAME; +} + +uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static() +{ + return { ADDIN_SERVICE, MY_SERVICE }; +} + +// XServiceName +OUString SAL_CALL ScaDateAddIn::getServiceName() +{ + // name of specific AddIn service + return MY_SERVICE; +} + +// XServiceInfo +OUString SAL_CALL ScaDateAddIn::getImplementationName() +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) +{ + return cppu::supportsService(this, aServiceName); +} + +uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +// XLocalizable +void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) +{ + aFuncLoc = eLocale; + InitData(); // change of locale invalidates resources! +} + +lang::Locale SAL_CALL ScaDateAddIn::getLocale() +{ + return aFuncLoc; +} + +OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) +{ + // not used by calc + // (but should be implemented for other uses of the AddIn service) + return OUString(); +} + +OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) +{ + OUString aRet; + + auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), + FindScaFuncData( aProgrammaticName ) ); + if( fDataIt != pFuncDataList->end() ) + { + aRet = ScaResId(fDataIt->GetUINameID()); + if( fDataIt->IsDouble() ) + aRet += "_ADD"; + } + else + { + aRet = "UNKNOWNFUNC_" + aProgrammaticName; + } + + return aRet; +} + +OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) +{ + OUString aRet; + + auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), + FindScaFuncData( aProgrammaticName ) ); + if( fDataIt != pFuncDataList->end() ) + aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 ); + + return aRet; +} + +OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName( + const OUString& aProgrammaticName, sal_Int32 nArgument ) +{ + OUString aRet; + + auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), + FindScaFuncData( aProgrammaticName ) ); + if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) ) + { + sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); + if( nStr ) + aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr ); + else + aRet = "internal"; + } + + return aRet; +} + +OUString SAL_CALL ScaDateAddIn::getArgumentDescription( + const OUString& aProgrammaticName, sal_Int32 nArgument ) +{ + OUString aRet; + + auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), + FindScaFuncData( aProgrammaticName ) ); + if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) ) + { + sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); + if( nStr ) + aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 ); + else + aRet = "for internal use only"; + } + + return aRet; +} + +OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName( + const OUString& aProgrammaticName ) +{ + OUString aRet; + + auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), + FindScaFuncData( aProgrammaticName ) ); + if( fDataIt != pFuncDataList->end() ) + { + switch( fDataIt->GetCategory() ) + { + case ScaCategory::DateTime: aRet = "Date&Time"; break; + case ScaCategory::Text: aRet = "Text"; break; + case ScaCategory::Finance: aRet = "Financial"; break; + case ScaCategory::Inf: aRet = "Information"; break; + case ScaCategory::Math: aRet = "Mathematical"; break; + case ScaCategory::Tech: aRet = "Technical"; break; + } + } + + if( aRet.isEmpty() ) + aRet = "Add-In"; + return aRet; +} + +OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName( + const OUString& aProgrammaticName ) +{ + return getProgrammaticCategoryName( aProgrammaticName ); +} + +// XCompatibilityNames +uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames( + const OUString& aProgrammaticName ) +{ + auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), + FindScaFuncData( aProgrammaticName ) ); + if( fDataIt == pFuncDataList->end() ) + return uno::Sequence< sheet::LocalizedName >( 0 ); + + const std::vector<OUString>& rStrList = fDataIt->GetCompNameList(); + sal_uInt32 nCount = rStrList.size(); + + uno::Sequence< sheet::LocalizedName > aRet( nCount ); + sheet::LocalizedName* pArray = aRet.getArray(); + + for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ ) + pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), rStrList.at( nIndex ) ); + + return aRet; +} + +namespace { + +// auxiliary functions +bool IsLeapYear( sal_uInt16 nYear ) +{ + return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0)); +} + +sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear ) +{ + static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; + + if ( nMonth != 2 ) + return aDaysInMonth[nMonth-1]; + else + { + if ( IsLeapYear(nYear) ) + return aDaysInMonth[nMonth-1] + 1; + else + return aDaysInMonth[nMonth-1]; + } +} + +/** + * Convert a date to a count of days starting from 01/01/0001 + * + * The internal representation of a Date used in this Addin + * is the number of days between 01/01/0001 and the date + * this function converts a Day , Month, Year representation + * to this internal Date value. + */ + +sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear ) +{ + sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365; + nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400); + + for( sal_uInt16 i = 1; i < nMonth; i++ ) + nDays += DaysInMonth(i,nYear); + nDays += nDay; + + return nDays; +} + +/** + * Convert a count of days starting from 01/01/0001 to a date + * + * The internal representation of a Date used in this Addin + * is the number of days between 01/01/0001 and the date + * this function converts this internal Date value + * to a Day , Month, Year representation of a Date. + * + * @throws lang::IllegalArgumentException + */ + +void DaysToDate( sal_Int32 nDays, + sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear ) +{ + if( nDays < 0 ) + throw lang::IllegalArgumentException(); + + sal_Int32 nTempDays; + sal_Int32 i = 0; + bool bCalc; + + do + { + nTempDays = nDays; + rYear = static_cast<sal_uInt16>((nTempDays / 365) - i); + nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365; + nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400); + bCalc = false; + if ( nTempDays < 1 ) + { + i++; + bCalc = true; + } + else + { + if ( nTempDays > 365 ) + { + if ( (nTempDays != 366) || !IsLeapYear( rYear ) ) + { + i--; + bCalc = true; + } + } + } + } + while ( bCalc ); + + rMonth = 1; + while ( nTempDays > DaysInMonth( rMonth, rYear ) ) + { + nTempDays -= DaysInMonth( rMonth, rYear ); + rMonth++; + } + rDay = static_cast<sal_uInt16>(nTempDays); +} + +/** + * Get the null date used by the spreadsheet document + * + * The internal representation of a Date used in this Addin + * is the number of days between 01/01/0001 and the date + * this function returns this internal Date value for the document null date + * + * @throws uno::RuntimeException + */ +sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions ) +{ + if (xOptions.is()) + { + try + { + uno::Any aAny = xOptions->getPropertyValue( "NullDate" ); + util::Date aDate; + if ( aAny >>= aDate ) + return DateToDays( aDate.Day, aDate.Month, aDate.Year ); + } + catch (uno::Exception&) + { + } + } + + // no null date available -> no calculations possible + throw uno::RuntimeException(); +} + +} +// XDateFunctions + +/** + * Get week difference between 2 dates + * + * new Weeks(date1,date2,mode) function for StarCalc + * + * Two modes of operation are provided. + * The first is just a simple division by 7 calculation. + * + * The second calculates the difference by week of year. + * + * The International Standard IS-8601 has decreed that Monday + * shall be the first day of the week. + * + * A week that lies partly in one year and partly in another + * is assigned a number in the year in which most of its days lie. + * + * That means that week 1 of any year is the week that contains the 4. January + * + * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001 + * + * A WeekDay can be then calculated by subtracting 1 and calculating the rest of + * a division by 7, which gives a 0 - 6 value for Monday - Sunday + * + * Using the 4. January rule explained above the formula + * + * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1; + * + * calculates a number between 0-53 for each day which is in the same year as nJan4 + * where 0 means that this week belonged to the year before. + * + * If a day in the same or another year is used in this formula this calculates + * a calendar week offset from a given 4. January + * + * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1; + * + * The 4.January of first Date Argument can thus be used to calculate + * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1 + * + * which can be optimized to + * + * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ) + * + * Note: All calculations are operating on the long integer data type + * % is the modulo operator in C which calculates the rest of an Integer division + * + * + * mode 0 is the interval between the dates in month, that is days / 7 + * + * mode 1 is the difference by week of year + * + */ + +sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks( + const uno::Reference< beans::XPropertySet >& xOptions, + sal_Int32 nStartDate, sal_Int32 nEndDate, + sal_Int32 nMode ) +{ + if (nMode != 0 && nMode != 1) + throw lang::IllegalArgumentException(); + + sal_Int32 nNullDate = GetNullDate( xOptions ); + + sal_Int32 nDays1 = nStartDate + nNullDate; + sal_Int32 nDays2 = nEndDate + nNullDate; + + sal_Int32 nRet; + + if ( nMode == 1 ) + { + sal_uInt16 nDay,nMonth,nYear; + DaysToDate( nDays1, nDay, nMonth, nYear ); + sal_Int32 nJan4 = DateToDays( 4, 1, nYear ); + + nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ); + } + else + { + nRet = (nDays2 - nDays1) / 7; + } + return nRet; +} + +/** + * Get month difference between 2 dates + * =Month(start, end, mode) Function for StarCalc + * + * two modes are provided + * + * mode 0 is the interval between the dates in month + * + * mode 1 is the difference in calendar month + */ +sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths( + const uno::Reference< beans::XPropertySet >& xOptions, + sal_Int32 nStartDate, sal_Int32 nEndDate, + sal_Int32 nMode ) +{ + if (nMode != 0 && nMode != 1) + throw lang::IllegalArgumentException(); + + sal_Int32 nNullDate = GetNullDate( xOptions ); + + sal_Int32 nDays1 = nStartDate + nNullDate; + sal_Int32 nDays2 = nEndDate + nNullDate; + + sal_uInt16 nDay1,nMonth1,nYear1; + sal_uInt16 nDay2,nMonth2,nYear2; + DaysToDate(nDays1,nDay1,nMonth1,nYear1); + DaysToDate(nDays2,nDay2,nMonth2,nYear2); + + sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12; + if ( nMode == 1 || nDays1 == nDays2 ) return nRet; + + if ( nDays1 < nDays2 ) + { + if ( nDay1 > nDay2 ) + { + nRet -= 1; + } + } + else + { + if ( nDay1 < nDay2 ) + { + nRet += 1; + } + } + + return nRet; +} + +/** + * Get Year difference between 2 dates + * + * two modes are provided + * + * mode 0 is the interval between the dates in years + * + * mode 1 is the difference in calendar years + */ +sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears( + const uno::Reference< beans::XPropertySet >& xOptions, + sal_Int32 nStartDate, sal_Int32 nEndDate, + sal_Int32 nMode ) +{ + if (nMode != 0 && nMode != 1) + throw lang::IllegalArgumentException(); + + if ( nMode != 1 ) + return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12; + + sal_Int32 nNullDate = GetNullDate( xOptions ); + + sal_Int32 nDays1 = nStartDate + nNullDate; + sal_Int32 nDays2 = nEndDate + nNullDate; + + sal_uInt16 nDay1,nMonth1,nYear1; + sal_uInt16 nDay2,nMonth2,nYear2; + DaysToDate(nDays1,nDay1,nMonth1,nYear1); + DaysToDate(nDays2,nDay2,nMonth2,nYear2); + + return nYear2 - nYear1; +} + +/** + * Check if a Date is in a leap year in the Gregorian calendar + */ +sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear( + const uno::Reference< beans::XPropertySet >& xOptions, + sal_Int32 nDate ) +{ + sal_Int32 nNullDate = GetNullDate( xOptions ); + sal_Int32 nDays = nDate + nNullDate; + + sal_uInt16 nDay, nMonth, nYear; + DaysToDate(nDays,nDay,nMonth,nYear); + + return static_cast<sal_Int32>(IsLeapYear(nYear)); +} + +/** + * Get the Number of Days in the month for a date + */ +sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth( + const uno::Reference<beans::XPropertySet>& xOptions, + sal_Int32 nDate ) +{ + sal_Int32 nNullDate = GetNullDate( xOptions ); + sal_Int32 nDays = nDate + nNullDate; + + sal_uInt16 nDay, nMonth, nYear; + DaysToDate(nDays,nDay,nMonth,nYear); + + return DaysInMonth( nMonth, nYear ); +} + +/** + * Get number of days in the year of a date specified + */ +sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear( + const uno::Reference< beans::XPropertySet >& xOptions, + sal_Int32 nDate ) +{ + sal_Int32 nNullDate = GetNullDate( xOptions ); + sal_Int32 nDays = nDate + nNullDate; + + sal_uInt16 nDay, nMonth, nYear; + DaysToDate(nDays,nDay,nMonth,nYear); + + return ( IsLeapYear(nYear) ? 366 : 365 ); +} + +/** + * Get number of weeks in the year for a date + * + * Most years have 52 weeks, but years that start on a Thursday + * and leap years that start on a Wednesday have 53 weeks + * + * The International Standard IS-8601 has decreed that Monday + * shall be the first day of the week. + * + * A WeekDay can be calculated by subtracting 1 and calculating the rest of + * a division by 7 from the internal date representation + * which gives a 0 - 6 value for Monday - Sunday + * + * @see #IsLeapYear #WeekNumber + */ +sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear( + const uno::Reference< beans::XPropertySet >& xOptions, + sal_Int32 nDate ) +{ + sal_Int32 nNullDate = GetNullDate( xOptions ); + sal_Int32 nDays = nDate + nNullDate; + + sal_uInt16 nDay, nMonth, nYear; + DaysToDate(nDays,nDay,nMonth,nYear); + + sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7; + + sal_Int32 nRet; + if ( nJan1WeekDay == 3 ) /* Thursday */ + nRet = 53; + else if ( nJan1WeekDay == 2 ) /* Wednesday */ + nRet = ( IsLeapYear(nYear) ? 53 : 52 ); + else + nRet = 52; + + return nRet; +} + +/** + * Encrypt or decrypt a string using ROT13 algorithm + * + * This function rotates each character by 13 in the alphabet. + * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified. + */ +OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) +{ + OUStringBuffer aBuffer( aSrcString ); + for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ ) + { + sal_Unicode cChar = aBuffer[nIndex]; + if( (cChar >= 'a') && (cChar <= 'z')) + { + cChar += 13; + if (cChar > 'z') + cChar -= 26; + } + else if( (cChar >= 'A') && (cChar <= 'Z') ) + { + cChar += 13; + if (cChar > 'Z') + cChar -= 26; + } + aBuffer[nIndex] = cChar; + } + return aBuffer.makeStringAndClear(); +} + +OUString ScaDateAddIn::ScaResId(const char* pId) +{ + return Translate::get(pId, aResLocale); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/scaddins/source/datefunc/datefunc.hxx b/scaddins/source/datefunc/datefunc.hxx new file mode 100644 index 000000000..528a6d2f0 --- /dev/null +++ b/scaddins/source/datefunc/datefunc.hxx @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// date functions add in + +#ifndef INCLUDED_SCADDINS_SOURCE_DATEFUNC_DATEFUNC_HXX +#define INCLUDED_SCADDINS_SOURCE_DATEFUNC_DATEFUNC_HXX + +#include <vector> +#include <memory> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sheet/XAddIn.hpp> +#include <com/sun/star/sheet/XCompatibilityNames.hpp> +#include <com/sun/star/sheet/addin/XDateFunctions.hpp> +#include <com/sun/star/sheet/addin/XMiscFunctions.hpp> +#include <cppuhelper/implbase.hxx> + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +enum class ScaCategory +{ + DateTime, + Text, + Finance, + Inf, + Math, + Tech +}; + +struct ScaFuncDataBase +{ + const char* pIntName; // internal name (get***) + const char* pUINameID; // resource ID to UI name + const char** pDescrID; // resource ID to description, parameter names and ~ description + const char** pCompListID; // list of valid names + sal_uInt16 nParamCount; // number of named / described parameters + ScaCategory eCat; // function category + bool bDouble; // name already exist in Calc + bool bWithOpt; // first parameter is internal +}; + +class ScaFuncData final +{ +private: + OUString aIntName; // internal name (get***) + const char* pUINameID; // resource ID to UI name + const char** pDescrID; // leads also to parameter descriptions! + sal_uInt16 nParamCount; // num of parameters + std::vector<OUString> aCompList; // list of all valid names + ScaCategory eCat; // function category + bool bDouble; // name already exist in Calc + bool bWithOpt; // first parameter is internal + +public: + ScaFuncData(const ScaFuncDataBase& rBaseData); + + const char* GetUINameID() const { return pUINameID; } + const char** GetDescrID() const { return pDescrID; } + ScaCategory GetCategory() const { return eCat; } + bool IsDouble() const { return bDouble; } + + sal_uInt16 GetStrIndex( sal_uInt16 nParam ) const; + bool Is( const OUString& rCompare ) const + { return aIntName == rCompare; } + + const std::vector<OUString>& GetCompNameList() const { return aCompList; } +}; + +typedef std::vector<ScaFuncData> ScaFuncDataList; + +// Predicate for use with std::find_if +struct FindScaFuncData +{ + const OUString& m_rId; + explicit FindScaFuncData( const OUString& rId ) : m_rId(rId) {} + bool operator() ( ScaFuncData const & rCandidate ) const { return rCandidate.Is(m_rId); } +}; + + +css::uno::Reference< css::uno::XInterface > SAL_CALL DateFunctionAddIn_CreateInstance( + const css::uno::Reference< css::lang::XMultiServiceFactory >& ); + + +// THE AddIn class for date functions + +class ScaDateAddIn : public ::cppu::WeakImplHelper< + css::sheet::XAddIn, + css::sheet::XCompatibilityNames, + css::sheet::addin::XDateFunctions, + css::sheet::addin::XMiscFunctions, + css::lang::XServiceName, + css::lang::XServiceInfo > +{ +private: + css::lang::Locale aFuncLoc; + std::unique_ptr< css::lang::Locale[] > pDefLocales; + std::locale aResLocale; + std::unique_ptr< ScaFuncDataList > pFuncDataList; + + + void InitDefLocales(); + const css::lang::Locale& GetLocale( sal_uInt32 nIndex ); + void InitData(); + + /// @throws css::uno::RuntimeException + OUString GetFuncDescrStr(const char** pResId, sal_uInt16 nStrIndex); + +public: + ScaDateAddIn(); + + OUString ScaResId(const char* pId); + + static OUString getImplementationName_Static(); + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + + // XAddIn + virtual OUString SAL_CALL getProgrammaticFuntionName( const OUString& aDisplayName ) override; + virtual OUString SAL_CALL getDisplayFunctionName( const OUString& aProgrammaticName ) override; + virtual OUString SAL_CALL getFunctionDescription( const OUString& aProgrammaticName ) override; + virtual OUString SAL_CALL getDisplayArgumentName( const OUString& aProgrammaticName, sal_Int32 nArgument ) override; + virtual OUString SAL_CALL getArgumentDescription( const OUString& aProgrammaticName, sal_Int32 nArgument ) override; + virtual OUString SAL_CALL getProgrammaticCategoryName( const OUString& aProgrammaticName ) override; + virtual OUString SAL_CALL getDisplayCategoryName( const OUString& aProgrammaticName ) override; + + // XCompatibilityNames + virtual css::uno::Sequence< css::sheet::LocalizedName > SAL_CALL getCompatibilityNames( const OUString& aProgrammaticName ) override; + + // XLocalizable + virtual void SAL_CALL setLocale( const css::lang::Locale& eLocale ) override; + virtual css::lang::Locale SAL_CALL getLocale() override; + + // XServiceName + virtual OUString SAL_CALL getServiceName() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // methods from own interfaces start here + + // XDateFunctions + virtual sal_Int32 SAL_CALL getDiffWeeks( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nEndDate, sal_Int32 nStartDate, + sal_Int32 nMode ) override; + + virtual sal_Int32 SAL_CALL getDiffMonths( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nEndDate, sal_Int32 nStartDate, + sal_Int32 nMode ) override; + + virtual sal_Int32 SAL_CALL getDiffYears( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nEndDate, sal_Int32 nStartDate, + sal_Int32 nMode ) override; + + virtual sal_Int32 SAL_CALL getIsLeapYear( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nDate ) override; + + virtual sal_Int32 SAL_CALL getDaysInMonth( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nDate ) override; + + virtual sal_Int32 SAL_CALL getDaysInYear( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nDate ) override; + + virtual sal_Int32 SAL_CALL getWeeksInYear( + const css::uno::Reference< css::beans::XPropertySet >& xOptions, + sal_Int32 nDate ) override; + + // XMiscFunctions + virtual OUString SAL_CALL getRot13( + const OUString& aSrcText ) override; +}; + +#endif // INCLUDED_SCADDINS_SOURCE_DATEFUNC_DATEFUNC_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/scaddins/source/datefunc/deffuncname.hxx b/scaddins/source/datefunc/deffuncname.hxx new file mode 100644 index 000000000..d1d807e3d --- /dev/null +++ b/scaddins/source/datefunc/deffuncname.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SCADDINS_SOURCE_DATEFUNC_DEFFUNCTIONNAME_HXX +#define INCLUDED_SCADDINS_SOURCE_DATEFUNC_DEFFUNCTIONNAME_HXX + +static const char* DATE_DEFFUNCNAME_DiffWeeks[2] = +{ + "WOCHEN", + "WEEKS" +}; + +static const char* DATE_DEFFUNCNAME_DiffMonths[2] = +{ + "MONATE", + "MONTHS" +}; + +static const char* DATE_DEFFUNCNAME_DiffYears[2] = +{ + "JAHRE", + "YEARS" +}; + +static const char* DATE_DEFFUNCNAME_IsLeapYear[2] = +{ + "ISTSCHALTJAHR", + "ISLEAPYEAR" +}; + +static const char* DATE_DEFFUNCNAME_DaysInMonth[2] = +{ + "TAGEIMMONAT", + "DAYSINMONTH" +}; + +static const char* DATE_DEFFUNCNAME_DaysInYear[2] = +{ + "TAGEIMJAHR", + "DAYSINYEAR" +}; + +static const char* DATE_DEFFUNCNAME_WeeksInYear[2] = +{ + "WOCHENIMJAHR", + "WEEKSINYEAR" +}; + +static const char* DATE_DEFFUNCNAME_Rot13[2] = +{ + "ROT13", + "ROT13" +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |