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