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