1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_unotools.hxx"
30 
31 #include <unotools/calendarwrapper.hxx>
32 #include <tools/string.hxx>
33 #include <tools/debug.hxx>
34 
35 #ifndef _COMPHELPER_COMPONENTFACTORY_HXX_
36 #include <comphelper/componentfactory.hxx>
37 #endif
38 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
39 #include <com/sun/star/i18n/XExtendedCalendar.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 
42 #define CALENDAR_LIBRARYNAME "i18n"
43 #define CALENDAR_SERVICENAME "com.sun.star.i18n.LocaleCalendar"
44 
45 
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::i18n;
48 using namespace ::com::sun::star::uno;
49 
50 
51 const double MILLISECONDS_PER_DAY = 1000.0 * 60.0 * 60.0 * 24.0;
52 
53 
54 CalendarWrapper::CalendarWrapper(
55 			const Reference< lang::XMultiServiceFactory > & xSF
56 			)
57 		:
58 		xSMgr( xSF ),
59 		aEpochStart( Date( 1, 1, 1970 ) )
60 {
61 	if ( xSMgr.is() )
62 	{
63 		try
64 		{
65 			xC = Reference< XExtendedCalendar > ( xSMgr->createInstance(
66 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CALENDAR_SERVICENAME ) ) ),
67 				uno::UNO_QUERY );
68 		}
69 		catch ( Exception& e )
70 		{
71 #ifdef DBG_UTIL
72 			ByteString aMsg( "CalendarWrapper ctor: Exception caught\n" );
73 			aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
74 			DBG_ERRORFILE( aMsg.GetBuffer() );
75 #else
76 			(void)e;
77 #endif
78 		}
79 	}
80 	else
81 	{	// try to get an instance somehow
82 		DBG_ERRORFILE( "CalendarWrapper: no service manager, trying own" );
83 		try
84 		{
85 			Reference< XInterface > xI = ::comphelper::getComponentInstance(
86 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( CALENDAR_LIBRARYNAME ) ) ),
87 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CALENDAR_SERVICENAME ) ) );
88 			if ( xI.is() )
89 			{
90 				Any x = xI->queryInterface( ::getCppuType((const Reference< XExtendedCalendar >*)0) );
91 				x >>= xC;
92 			}
93 		}
94 		catch ( Exception& e )
95 		{
96 #ifdef DBG_UTIL
97 			ByteString aMsg( "getComponentInstance: Exception caught\n" );
98 			aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
99 			DBG_ERRORFILE( aMsg.GetBuffer() );
100 #else
101 			(void)e;
102 #endif
103 		}
104 	}
105 }
106 
107 
108 CalendarWrapper::~CalendarWrapper()
109 {
110 }
111 
112 
113 void CalendarWrapper::loadDefaultCalendar( const ::com::sun::star::lang::Locale& rLocale )
114 {
115 	try
116 	{
117 		if ( xC.is() )
118 			xC->loadDefaultCalendar( rLocale );
119 	}
120 	catch ( Exception& e )
121 	{
122 #ifdef DBG_UTIL
123 		ByteString aMsg( "loadDefaultCalendar: Exception caught\n" );
124 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
125 		DBG_ERRORFILE( aMsg.GetBuffer() );
126 #else
127 		(void)e;
128 #endif
129 	}
130 }
131 
132 
133 void CalendarWrapper::loadCalendar( const ::rtl::OUString& rUniqueID, const ::com::sun::star::lang::Locale& rLocale )
134 {
135 	try
136 	{
137 		if ( xC.is() )
138 			xC->loadCalendar( rUniqueID, rLocale );
139 	}
140 	catch ( Exception& e )
141 	{
142 #ifdef DBG_UTIL
143 		ByteString aMsg( "loadCalendar: Exception caught\nrequested: " );
144 		aMsg += ByteString( String( rUniqueID ), RTL_TEXTENCODING_UTF8 );
145 		aMsg += "   Locale: ";
146 		aMsg += ByteString( String( rLocale.Language ), RTL_TEXTENCODING_UTF8 );
147 		aMsg += '_';
148 		aMsg += ByteString( String( rLocale.Country ), RTL_TEXTENCODING_UTF8 );
149 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
150 		DBG_ERRORFILE( aMsg.GetBuffer() );
151 #else
152 		(void)e;
153 #endif
154 	}
155 }
156 
157 
158 ::com::sun::star::i18n::Calendar CalendarWrapper::getLoadedCalendar() const
159 {
160 	try
161 	{
162 		if ( xC.is() )
163 			return xC->getLoadedCalendar();
164 	}
165 	catch ( Exception& e )
166 	{
167 #ifdef DBG_UTIL
168 		ByteString aMsg( "getLoadedCalendar: Exception caught\n" );
169 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
170 		DBG_ERRORFILE( aMsg.GetBuffer() );
171 #else
172         (void)e;
173 #endif
174 	}
175 	return ::com::sun::star::i18n::Calendar();
176 }
177 
178 
179 ::com::sun::star::uno::Sequence< ::rtl::OUString > CalendarWrapper::getAllCalendars( const ::com::sun::star::lang::Locale& rLocale ) const
180 {
181 	try
182 	{
183 		if ( xC.is() )
184 			return xC->getAllCalendars( rLocale );
185 	}
186 	catch ( Exception& e )
187 	{
188 #ifdef DBG_UTIL
189 		ByteString aMsg( "getAllCalendars: Exception caught\n" );
190 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
191 		DBG_ERRORFILE( aMsg.GetBuffer() );
192 #else
193         (void)e;
194 #endif
195 	}
196 	return ::com::sun::star::uno::Sequence< ::rtl::OUString > (0);
197 }
198 
199 
200 ::rtl::OUString CalendarWrapper::getUniqueID() const
201 {
202 	try
203 	{
204 		if ( xC.is() )
205 			return xC->getUniqueID();
206 	}
207 	catch ( Exception& e )
208 	{
209 #ifdef DBG_UTIL
210 		ByteString aMsg( "getUniqueID: Exception caught\n" );
211 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
212 		DBG_ERRORFILE( aMsg.GetBuffer() );
213 #else
214         (void)e;
215 #endif
216 	}
217 	return ::rtl::OUString();
218 }
219 
220 
221 void CalendarWrapper::setDateTime( double nTimeInDays )
222 {
223 	try
224 	{
225 		if ( xC.is() )
226 			xC->setDateTime( nTimeInDays );
227 	}
228 	catch ( Exception& e )
229 	{
230 #ifdef DBG_UTIL
231 		ByteString aMsg( "setDateTime: Exception caught\n" );
232 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
233 		DBG_ERRORFILE( aMsg.GetBuffer() );
234 #else
235         (void)e;
236 #endif
237 	}
238 }
239 
240 
241 double CalendarWrapper::getDateTime() const
242 {
243 	try
244 	{
245 		if ( xC.is() )
246 			return xC->getDateTime();
247 	}
248 	catch ( Exception& e )
249 	{
250 #ifdef DBG_UTIL
251 		ByteString aMsg( "getDateTime: Exception caught\n" );
252 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
253 		DBG_ERRORFILE( aMsg.GetBuffer() );
254 #else
255         (void)e;
256 #endif
257 	}
258 	return 0.0;
259 }
260 
261 
262 sal_Int32 CalendarWrapper::getCombinedOffsetInMillis(
263         sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex ) const
264 {
265     sal_Int32 nOffset = 0;
266     try
267     {
268         if ( xC.is() )
269         {
270             nOffset = static_cast<sal_Int32>( xC->getValue( nParentFieldIndex )) * 60000;
271             sal_Int16 nSecondMillis = xC->getValue( nChildFieldIndex );
272             if (nOffset < 0)
273                 nOffset -= static_cast<sal_uInt16>( nSecondMillis);
274             else
275                 nOffset += static_cast<sal_uInt16>( nSecondMillis);
276         }
277     }
278     catch ( Exception& e )
279     {
280 #ifdef DBG_UTIL
281         ByteString aMsg( "setLocalDateTime: Exception caught\n" );
282         aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
283         DBG_ERRORFILE( aMsg.GetBuffer() );
284 #else
285         (void)e;
286 #endif
287     }
288     return nOffset;
289 }
290 
291 
292 sal_Int32 CalendarWrapper::getZoneOffsetInMillis() const
293 {
294     return getCombinedOffsetInMillis( CalendarFieldIndex::ZONE_OFFSET,
295             CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS);
296 }
297 
298 
299 sal_Int32 CalendarWrapper::getDSTOffsetInMillis() const
300 {
301     return getCombinedOffsetInMillis( CalendarFieldIndex::DST_OFFSET,
302             CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS);
303 }
304 
305 
306 void CalendarWrapper::setLocalDateTime( double nTimeInDays )
307 {
308     try
309     {
310         if ( xC.is() )
311         {
312             // First set a nearby value to obtain the timezone and DST offset.
313             // This is necessary to let ICU choose the corresponding
314             // OlsonTimeZone transitions. Since ICU incorporates also
315             // historical data even the timezone may differ for different
316             // dates! (Which was the cause for #i76623# when the timezone of a
317             // previously set date was used.) Timezone may also include
318             // seconds, so use milliseconds field as well.
319             xC->setDateTime( nTimeInDays );
320             sal_Int32 nZone1 = getZoneOffsetInMillis();
321             sal_Int32 nDST1  = getDSTOffsetInMillis();
322             double nLoc = nTimeInDays - (double)(nZone1 + nDST1) / MILLISECONDS_PER_DAY;
323             xC->setDateTime( nLoc );
324             sal_Int32 nZone2 = getZoneOffsetInMillis();
325             sal_Int32 nDST2  = getDSTOffsetInMillis();
326             // If DSTs differ after calculation, we crossed boundaries. Do it
327             // again, this time using the DST corrected initial value for the
328             // real local time.
329             // See also localtime/gmtime conversion pitfalls at
330             // http://www.erack.de/download/timetest.c
331             if ( nDST1 != nDST2 )
332             {
333                 nLoc = nTimeInDays - (double)(nZone2 + nDST2) / MILLISECONDS_PER_DAY;
334                 xC->setDateTime( nLoc );
335                 // #i17222# If the DST onset rule says to switch from 00:00 to
336                 // 01:00 and we tried to set onsetDay 00:00 with DST, the
337                 // result was onsetDay-1 23:00 and no DST, which is not what we
338                 // want. So once again without DST, resulting in onsetDay
339                 // 01:00 and DST. Yes, this seems to be weird, but logically
340                 // correct.
341                 sal_Int32 nDST3 = getDSTOffsetInMillis();
342                 if ( nDST2 != nDST3 && !nDST3 )
343                 {
344                     nLoc = nTimeInDays - (double)(nZone2 + nDST3) / MILLISECONDS_PER_DAY;
345                     xC->setDateTime( nLoc );
346                 }
347             }
348         }
349     }
350     catch ( Exception& e )
351     {
352 #ifdef DBG_UTIL
353         ByteString aMsg( "setLocalDateTime: Exception caught\n" );
354         aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
355         DBG_ERRORFILE( aMsg.GetBuffer() );
356 #else
357         (void)e;
358 #endif
359     }
360 }
361 
362 
363 double CalendarWrapper::getLocalDateTime() const
364 {
365     try
366     {
367         if ( xC.is() )
368         {
369             double nTimeInDays = xC->getDateTime();
370             sal_Int32 nZone = getZoneOffsetInMillis();
371             sal_Int32 nDST = getDSTOffsetInMillis();
372             nTimeInDays += (double)(nZone + nDST) / MILLISECONDS_PER_DAY;
373             return nTimeInDays;
374         }
375     }
376     catch ( Exception& e )
377     {
378 #ifdef DBG_UTIL
379         ByteString aMsg( "getLocalDateTime: Exception caught\n" );
380         aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
381         DBG_ERRORFILE( aMsg.GetBuffer() );
382 #else
383         (void)e;
384 #endif
385     }
386     return 0.0;
387 }
388 
389 
390 void CalendarWrapper::setValue( sal_Int16 nFieldIndex, sal_Int16 nValue )
391 {
392 	try
393 	{
394 		if ( xC.is() )
395 			xC->setValue( nFieldIndex, nValue );
396 	}
397 	catch ( Exception& e )
398 	{
399 #ifdef DBG_UTIL
400 		ByteString aMsg( "setValue: Exception caught\n" );
401 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
402 		DBG_ERRORFILE( aMsg.GetBuffer() );
403 #else
404         (void)e;
405 #endif
406 	}
407 }
408 
409 
410 sal_Bool CalendarWrapper::isValid() const
411 {
412 	try
413 	{
414 		if ( xC.is() )
415             return xC->isValid();
416 	}
417 	catch ( Exception& e )
418 	{
419 #ifdef DBG_UTIL
420         ByteString aMsg( "isValid: Exception caught\n" );
421 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
422 		DBG_ERRORFILE( aMsg.GetBuffer() );
423 #else
424         (void)e;
425 #endif
426 	}
427     return sal_False;
428 }
429 
430 
431 sal_Int16 CalendarWrapper::getValue( sal_Int16 nFieldIndex ) const
432 {
433 	try
434 	{
435 		if ( xC.is() )
436 			return xC->getValue( nFieldIndex );
437 	}
438 	catch ( Exception& e )
439 	{
440 #ifdef DBG_UTIL
441 		ByteString aMsg( "getValue: Exception caught\n" );
442 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
443 		DBG_ERRORFILE( aMsg.GetBuffer() );
444 #else
445         (void)e;
446 #endif
447 	}
448 	return 0;
449 }
450 
451 
452 void CalendarWrapper::addValue( sal_Int16 nFieldIndex, sal_Int32 nAmount )
453 {
454 	try
455 	{
456 		if ( xC.is() )
457 			xC->addValue( nFieldIndex, nAmount );
458 	}
459 	catch ( Exception& e )
460 	{
461 #ifdef DBG_UTIL
462 		ByteString aMsg( "addValue: Exception caught\n" );
463 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
464 		DBG_ERRORFILE( aMsg.GetBuffer() );
465 #else
466         (void)e;
467 #endif
468 	}
469 }
470 
471 
472 sal_Int16 CalendarWrapper::getFirstDayOfWeek() const
473 {
474 	try
475 	{
476 		if ( xC.is() )
477 			return xC->getFirstDayOfWeek();
478 	}
479 	catch ( Exception& e )
480 	{
481 #ifdef DBG_UTIL
482 		ByteString aMsg( "getFirstDayOfWeek: Exception caught\n" );
483 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
484 		DBG_ERRORFILE( aMsg.GetBuffer() );
485 #else
486         (void)e;
487 #endif
488 	}
489 	return 0;
490 }
491 
492 
493 void CalendarWrapper::setFirstDayOfWeek( sal_Int16 nDay )
494 {
495 	try
496 	{
497 		if ( xC.is() )
498 			xC->setFirstDayOfWeek( nDay );
499 	}
500 	catch ( Exception& e )
501 	{
502 #ifdef DBG_UTIL
503 		ByteString aMsg( "setFirstDayOfWeek: Exception caught\n" );
504 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
505 		DBG_ERRORFILE( aMsg.GetBuffer() );
506 #else
507         (void)e;
508 #endif
509 	}
510 }
511 
512 
513 void CalendarWrapper::setMinimumNumberOfDaysForFirstWeek( sal_Int16 nDays )
514 {
515 	try
516 	{
517 		if ( xC.is() )
518 			xC->setMinimumNumberOfDaysForFirstWeek( nDays );
519 	}
520 	catch ( Exception& e )
521 	{
522 #ifdef DBG_UTIL
523 		ByteString aMsg( "setMinimumNumberOfDaysForFirstWeek: Exception caught\n" );
524 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
525 		DBG_ERRORFILE( aMsg.GetBuffer() );
526 #else
527         (void)e;
528 #endif
529 	}
530 }
531 
532 
533 sal_Int16 CalendarWrapper::getMinimumNumberOfDaysForFirstWeek() const
534 {
535 	try
536 	{
537 		if ( xC.is() )
538 			return xC->getMinimumNumberOfDaysForFirstWeek();
539 	}
540 	catch ( Exception& e )
541 	{
542 #ifdef DBG_UTIL
543 		ByteString aMsg( "getMinimumNumberOfDaysForFirstWeek: Exception caught\n" );
544 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
545 		DBG_ERRORFILE( aMsg.GetBuffer() );
546 #else
547         (void)e;
548 #endif
549 	}
550 	return 0;
551 }
552 
553 
554 sal_Int16 CalendarWrapper::getNumberOfMonthsInYear() const
555 {
556 	try
557 	{
558 		if ( xC.is() )
559 			return xC->getNumberOfMonthsInYear();
560 	}
561 	catch ( Exception& e )
562 	{
563 #ifdef DBG_UTIL
564 		ByteString aMsg( "getNumberOfMonthsInYear: Exception caught\n" );
565 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
566 		DBG_ERRORFILE( aMsg.GetBuffer() );
567 #else
568         (void)e;
569 #endif
570 	}
571 	return 0;
572 }
573 
574 
575 sal_Int16 CalendarWrapper::getNumberOfDaysInWeek() const
576 {
577 	try
578 	{
579 		if ( xC.is() )
580 			return xC->getNumberOfDaysInWeek();
581 	}
582 	catch ( Exception& e )
583 	{
584 #ifdef DBG_UTIL
585 		ByteString aMsg( "getNumberOfDaysInWeek: Exception caught\n" );
586 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
587 		DBG_ERRORFILE( aMsg.GetBuffer() );
588 #else
589         (void)e;
590 #endif
591 	}
592 	return 0;
593 }
594 
595 
596 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > CalendarWrapper::getMonths() const
597 {
598 	try
599 	{
600 		if ( xC.is() )
601 			return xC->getMonths();
602 	}
603 	catch ( Exception& e )
604 	{
605 #ifdef DBG_UTIL
606 		ByteString aMsg( "getMonths: Exception caught\n" );
607 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
608 		DBG_ERRORFILE( aMsg.GetBuffer() );
609 #else
610         (void)e;
611 #endif
612 	}
613 	return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > (0);
614 }
615 
616 
617 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > CalendarWrapper::getDays() const
618 {
619 	try
620 	{
621 		if ( xC.is() )
622 			return xC->getDays();
623 	}
624 	catch ( Exception& e )
625 	{
626 #ifdef DBG_UTIL
627 		ByteString aMsg( "getDays: Exception caught\n" );
628 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
629 		DBG_ERRORFILE( aMsg.GetBuffer() );
630 #else
631         (void)e;
632 #endif
633 	}
634 	return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > (0);
635 }
636 
637 
638 String CalendarWrapper::getDisplayName( sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType ) const
639 {
640 	try
641 	{
642 		if ( xC.is() )
643 			return xC->getDisplayName( nCalendarDisplayIndex, nIdx, nNameType );
644 	}
645 	catch ( Exception& e )
646 	{
647 #ifdef DBG_UTIL
648 		ByteString aMsg( "getDisplayName: Exception caught\n" );
649 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
650 		DBG_ERRORFILE( aMsg.GetBuffer() );
651 #else
652         (void)e;
653 #endif
654 	}
655 	return String();
656 }
657 
658 
659 // --- XExtendedCalendar -----------------------------------------------------
660 
661 String CalendarWrapper::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) const
662 {
663 	try
664 	{
665 		if ( xC.is() )
666 			return xC->getDisplayString( nCalendarDisplayCode, nNativeNumberMode );
667 	}
668 	catch ( Exception& e )
669 	{
670 #ifdef DBG_UTIL
671 		ByteString aMsg( "getDisplayString: Exception caught\n" );
672 		aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 );
673 		DBG_ERRORFILE( aMsg.GetBuffer() );
674 #else
675         (void)e;
676 #endif
677 	}
678 	return String();
679 }
680 
681