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