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