xref: /trunk/main/unotools/source/i18n/calendarwrapper.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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