1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef _UNOTOOLS_LOCALEDATAWRAPPER_HXX
25 #define _UNOTOOLS_LOCALEDATAWRAPPER_HXX
26 
27 #include <tools/string.hxx>
28 #include <com/sun/star/i18n/XLocaleData2.hpp>
29 #include <com/sun/star/i18n/LocaleItem.hpp>
30 #include <com/sun/star/i18n/reservedWords.hpp>
31 #include <unotools/readwritemutexguard.hxx>
32 #include "unotools/unotoolsdllapi.h"
33 
34 #ifndef BOOST_SHARED_PTR_HPP_INCLUDED
35 #include <boost/shared_ptr.hpp>
36 #endif
37 
38 
39 namespace com { namespace sun { namespace star {
40 	namespace lang {
41 		class XMultiServiceFactory;
42 	}
43 }}}
44 class Date;
45 class Time;
46 class CalendarWrapper;
47 
48 
49 enum DateFormat {
50     MDY,
51     DMY,
52     YMD
53 };
54 
55 
56 enum MeasurementSystem {
57     MEASURE_METRIC,
58     MEASURE_US
59 };
60 
61 
62 class UNOTOOLS_DLLPUBLIC LocaleDataWrapper
63 {
64     static  sal_uInt8                nLocaleDataChecking;    // 0:=dontknow, 1:=yes, 2:=no
65 
66     ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >    xSMgr;
67     ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XLocaleData2 >            xLD;
68     ::com::sun::star::lang::Locale                                                      aLocale;
69     ::boost::shared_ptr< ::com::sun::star::i18n::Calendar >                             xDefaultCalendar;
70     ::com::sun::star::i18n::LocaleDataItem                                              aLocaleDataItem;
71     ::com::sun::star::uno::Sequence< ::rtl::OUString >                                  aReservedWordSeq;
72     ::com::sun::star::uno::Sequence< sal_Int32 >                                        aGrouping;
73 	// cached items
74 	String						aLocaleItem[::com::sun::star::i18n::LocaleItem::COUNT];
75 	String						aReservedWord[::com::sun::star::i18n::reservedWords::COUNT];
76 	String						aCurrSymbol;
77 	String						aCurrBankSymbol;
78 	int							nDateFormat;
79 	int							nLongDateFormat;
80 	sal_uInt16						nCurrPositiveFormat;
81 	sal_uInt16						nCurrNegativeFormat;
82 	sal_uInt16						nCurrDigits;
83 	sal_Bool						bLocaleDataItemValid;
84 	sal_Bool						bReservedWordValid;
85     mutable ::utl::ReadWriteMutex   aMutex;
86 
87 	// dummies, to be implemented or provided by XML locale data
88 	sal_Unicode					cCurrZeroChar;
89 
90 
91 								// not implemented, prevent usage
92 								LocaleDataWrapper( const LocaleDataWrapper& );
93 			LocaleDataWrapper&	operator=( const LocaleDataWrapper& );
94 
95 								// whenever Locale changes
96 			void				invalidateData();
97 
98 			void				getOneLocaleItemImpl( sal_Int16 nItem );
99 			const String&		getOneLocaleItem( sal_Int16 nItem ) const;
100 
101 			void				getOneReservedWordImpl( sal_Int16 nWord );
102 			const String&		getOneReservedWord( sal_Int16 nWord ) const;
103 
104 			void				getCurrSymbolsImpl();
105 			void				getCurrFormatsImpl();
106 
107             void                scanCurrFormatImpl( const String& rCode,
108 									xub_StrLen nStart, xub_StrLen& nSign,
109 									xub_StrLen& nPar, xub_StrLen& nNum,
110 									xub_StrLen& nBlank, xub_StrLen& nSym );
111 
112 			void				getDateFormatsImpl();
113             DateFormat          scanDateFormatImpl( const String& rCode );
114 
115             void                getDefaultCalendarImpl();
116 
117 			sal_Unicode*		ImplAddFormatNum( sal_Unicode* pBuf,
118                                     sal_Int64 nNumber, sal_uInt16 nDecimals,
119                                     sal_Bool bUseThousandSep, sal_Bool bTrailingZeros ) const;
120 
121             void                getDigitGroupingImpl();
122 
123 public:
124 								LocaleDataWrapper(
125 									const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xSF,
126 									const ::com::sun::star::lang::Locale& rLocale
127 									);
128 								~LocaleDataWrapper();
129 
130     /** Get the service factory, meant to be able to create a CalendarWrapper
131         from a LocaleDataWrapper. Note that the service factory may be
132         non-existent if this LocaleDataWrapper was created without one and
133         lives "on the grassland". The CalendarWrapper ctor can handle that
134         though. */
135     const ::com::sun::star::uno::Reference<
getServiceFactory() const136         ::com::sun::star::lang::XMultiServiceFactory > & getServiceFactory()
137         const { return xSMgr; }
138 
139 	/// set a new Locale to request
140 			void				setLocale( const ::com::sun::star::lang::Locale& rLocale );
141 
142 	/// get current requested Locale
143     const ::com::sun::star::lang::Locale& getLocale() const;
144 
145 	/// get current loaded Locale, which might differ from the requested Locale
146 	::com::sun::star::lang::Locale getLoadedLocale() const;
147 
148 
149 	// Wrapper implementations of service LocaleData
150 
151     ::com::sun::star::i18n::LanguageCountryInfo getLanguageCountryInfo() const;
152     ::com::sun::star::i18n::LocaleDataItem getLocaleItem() const;
153     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Calendar > getAllCalendars() const;
154     /// NOTE: this wraps XLocaleData2::getAllCurrencies2() in fact.
155     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 > getAllCurrencies() const;
156     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::FormatElement > getAllFormats() const;
157     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Implementation > getCollatorImplementations() const;
158     ::com::sun::star::uno::Sequence< ::rtl::OUString > getTransliterations() const;
159 	::com::sun::star::i18n::ForbiddenCharacters getForbiddenCharacters() const;
160 	::com::sun::star::uno::Sequence< ::rtl::OUString > getReservedWord() const;
161 	::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > getAllInstalledLocaleNames() const;
162 
163 	/// same as the wrapper implementation but static
164 	static ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > getInstalledLocaleNames();
165 
166 	/** Get LanguageTypes for all installed locales which are unambiguous
167 		convertible back and forth between locale ISO strings and MS-LCID
168 		LanguageType. Upon the first time the function is called when
169         locale data checking is enabled, messages are shown for locales not
170         matching, excluding already known problems.
171 		(e.g. used in number formatter dialog init)
172 	 */
173 	static ::com::sun::star::uno::Sequence< sal_uInt16 > getInstalledLanguageTypes();
174 
175 	/// maps the LocaleData string to the International enum
176 			MeasurementSystem	mapMeasurementStringToEnum( const String& rMS ) const;
177 
178     /// Convenience method to obtain the default calendar.
179     const ::boost::shared_ptr< ::com::sun::star::i18n::Calendar > getDefaultCalendar() const;
180 
181     /// Convenience method to obtain the day names of the default calendar.
182     const ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > getDefaultCalendarDays() const;
183 
184     /// Convenience method to obtain the month names of the default calendar.
185     const ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > getDefaultCalendarMonths() const;
186 
187     /** Obtain digit grouping. The usually known grouping by thousands (#,###)
188         is actually only one of possible groupings. Another one, for example,
189         used in India is group by 3 and then by 2 indefinitely (#,##,###). The
190         integer sequence returned here specifies grouping from right to left
191         (!), with a 0 entry designating the end of rules and the previous value
192         to be repeated indefinitely. Hence the sequence {3,0} specifies the
193         usual grouping by thousands, whereas the sequence {3,2,0} specifies
194         Indian grouping. The sal_Int32* getConstArray() can be passed directly
195         to the ::rtl::math::doubleToString() methods as argument for the
196         pGroups parameter. */
197     const ::com::sun::star::uno::Sequence< sal_Int32 > getDigitGrouping() const;
198 
199 	// Functionality of class International methods, LocaleItem
200 
getDateSep() const201 	inline	const String&		getDateSep() const
202 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::DATE_SEPARATOR ); }
getNumThousandSep() const203 	inline	const String&		getNumThousandSep() const
204 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::THOUSAND_SEPARATOR ); }
getNumDecimalSep() const205 	inline	const String&		getNumDecimalSep() const
206 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::DECIMAL_SEPARATOR ); }
getTimeSep() const207 	inline	const String&		getTimeSep() const
208 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::TIME_SEPARATOR ); }
getTime100SecSep() const209 	inline	const String&		getTime100SecSep() const
210 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::TIME_100SEC_SEPARATOR ); }
getListSep() const211 	inline	const String&		getListSep() const
212 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::LIST_SEPARATOR ); }
getQuotationMarkStart() const213 	inline	const String&		getQuotationMarkStart() const
214 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::SINGLE_QUOTATION_START ); }
getQuotationMarkEnd() const215 	inline	const String&		getQuotationMarkEnd() const
216 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::SINGLE_QUOTATION_END ); }
getDoubleQuotationMarkStart() const217 	inline	const String&		getDoubleQuotationMarkStart() const
218 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::DOUBLE_QUOTATION_START ); }
getDoubleQuotationMarkEnd() const219 	inline	const String&		getDoubleQuotationMarkEnd() const
220 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::DOUBLE_QUOTATION_END ); }
getMeasurementSystem() const221 	inline	const String&		getMeasurementSystem() const
222 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::MEASUREMENT_SYSTEM ); }
getMeasurementSystemEnum() const223 	inline	MeasurementSystem	getMeasurementSystemEnum() const
224 									{ return mapMeasurementStringToEnum( getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::MEASUREMENT_SYSTEM ) ); }
getTimeAM() const225 	inline	const String&		getTimeAM() const
226 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::TIME_AM ); }
getTimePM() const227 	inline	const String&		getTimePM() const
228 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::TIME_PM ); }
getLongDateDayOfWeekSep() const229 	inline	const String&		getLongDateDayOfWeekSep() const
230 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::LONG_DATE_DAY_OF_WEEK_SEPARATOR ); }
getLongDateDaySep() const231 	inline	const String&		getLongDateDaySep() const
232 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::LONG_DATE_DAY_SEPARATOR ); }
getLongDateMonthSep() const233 	inline	const String&		getLongDateMonthSep() const
234 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::LONG_DATE_MONTH_SEPARATOR ); }
getLongDateYearSep() const235 	inline	const String&		getLongDateYearSep() const
236 									{ return getOneLocaleItem( ::com::sun::star::i18n::LocaleItem::LONG_DATE_YEAR_SEPARATOR ); }
237 
238 	// currency
239 			const String&		getCurrSymbol() const;
240 			const String&		getCurrBankSymbol() const;
241 			sal_uInt16				getCurrPositiveFormat() const;
242 			sal_uInt16				getCurrNegativeFormat() const;
243 			sal_uInt16				getCurrDigits() const;
244 
245     // simple date and time formatting
246 			DateFormat			getDateFormat() const;
247 			DateFormat			getLongDateFormat() const;
248                                 /// only numerical values of Gregorian calendar
249 			String				getDate( const Date& rDate ) const;
250 			String				getTime( const Time& rTime, sal_Bool bSec = sal_True,
251 									sal_Bool b100Sec = sal_False ) const;
252             String              getDuration( const Time& rTime,
253                                     sal_Bool bSec = sal_True, sal_Bool b100Sec = sal_False ) const;
254 
255                                 /** The CalendarWrapper already <b>MUST</b>
256                                     have loaded a calendar.
257                                     @param nDisplayDayOfWeek
258                                         0 := abbreviated name
259                                         1 := full name
260                                     @param bDayOfMonthWithLeadingZero
261                                         <FALSE/> := without leading zero
262                                         <TRUE/>  := with leading zero if <10
263                                     @param nDisplayMonth
264                                         0 := abbreviated name
265                                         1 := full name
266                                     @param bTwoDigitYear
267                                         <FALSE/> := full year
268                                         <TRUE/>  := year % 100
269                                  */
270             String              getLongDate( const Date& rDate,
271                                     CalendarWrapper& rCal,
272                                     sal_Int16 nDisplayDayOfWeek = 1,
273                                     sal_Bool bDayOfMonthWithLeadingZero = sal_False,
274                                     sal_Int16 nDisplayMonth = 1,
275                                     sal_Bool bTwoDigitYear = sal_False
276                                     ) const;
277 
278                                 /** Simple number formatting
279                                     @param nNumber
280                                         value * 10**nDecimals
281                                     @param bTrailingZeros
282                                     </sal_True>  := always display trailing zeros in
283                                         decimal places, even if integer value.
284                                     </sal_False> := trailing zeros are only displayed
285                                         if the value is not an integer value.
286                                  */
287             String              getNum( sal_Int64 nNumber, sal_uInt16 nDecimals,
288                                     sal_Bool bUseThousandSep = sal_True,
289                                     sal_Bool bTrailingZeros = sal_True ) const;
290 
291                                 /// "Secure" currency formatted string.
292             String              getCurr( sal_Int64 nNumber, sal_uInt16 nDecimals,
293                                     const String& rCurrencySymbol,
294                                     sal_Bool bUseThousandSep = sal_True ) const;
295                                 /** Default currency formatted string, use with
296                                     care as default currency may change in any
297                                     locale, for example, DEM -> EUR */
getCurr(sal_Int64 nNumber,sal_uInt16 nDecimals,sal_Bool bUseThousandSep=sal_True) const298             String              getCurr( sal_Int64 nNumber, sal_uInt16 nDecimals,
299                                         sal_Bool bUseThousandSep = sal_True ) const
300                                     { return getCurr( nNumber, nDecimals,
301                                         getCurrSymbol(), bUseThousandSep ); }
302 
303     // dummy returns, to be implemented
getCurrZeroChar() const304 	inline	sal_Unicode			getCurrZeroChar() const
305 									{ return cCurrZeroChar; }
isNumLeadingZero() const306     inline  sal_Bool                isNumLeadingZero() const
307                                     { return sal_True; }
308                                 /// standard decimal places
getNumDigits() const309     inline  sal_uInt16              getNumDigits() const
310                                     { return 2; }
isNumTrailingZeros() const311     inline  sal_Bool                isNumTrailingZeros() const
312                                     { return sal_True; }
313 
314 
315 	// reserved words
316 
getTrueWord() const317 	inline	const String&		getTrueWord() const
318 									{ return getOneReservedWord( ::com::sun::star::i18n::reservedWords::TRUE_WORD ); }
getFalseWord() const319 	inline	const String&		getFalseWord() const
320 									{ return getOneReservedWord( ::com::sun::star::i18n::reservedWords::FALSE_WORD ); }
321     /// return a quarter string matching nQuarter (0..3) => "1st quarter" .. "4th quarter"
getQuarterWord(sal_Int16 nQuarter) const322     inline  const String&       getQuarterWord( sal_Int16 nQuarter ) const
323                                     { return getOneReservedWord( ::com::sun::star::i18n::reservedWords::QUARTER1_WORD + nQuarter ); }
getAboveWord() const324 	inline	const String&		getAboveWord() const
325 									{ return getOneReservedWord( ::com::sun::star::i18n::reservedWords::ABOVE_WORD ); }
getBelowWord() const326 	inline	const String&		getBelowWord() const
327 									{ return getOneReservedWord( ::com::sun::star::i18n::reservedWords::BELOW_WORD ); }
328     /// return a quarter abbreviation string matching nQuarter (0..3) => "Q1" .. "Q2"
getQuarterAbbreviation(sal_Int16 nQuarter) const329     inline  const String&       getQuarterAbbreviation( sal_Int16 nQuarter ) const
330                                     { return getOneReservedWord( ::com::sun::star::i18n::reservedWords::QUARTER1_ABBREVIATION + nQuarter ); }
331 
332     /** Return whether locale data checks are enabled.
333         Checks are enabled if the environment variable
334         OOO_ENABLE_LOCALE_DATA_CHECKS is set to 'Y' or 'Yes' (or any other
335         string starting with 'Y') or '1'.
336         Also used in conjunction with the number formatter. */
areChecksEnabled()337     static  inline  bool        areChecksEnabled()
338                                     {
339                                         if (nLocaleDataChecking == 0)
340                                             evaluateLocaleDataChecking();
341                                         return nLocaleDataChecking == 1;
342                                     }
343 
344     /** Append locale info to string, used with locale data checking.
345         A string similar to "de_DE requested\n en_US loaded" is appended. */
346 			String&			    appendLocaleInfo( String& rDebugMsg ) const;
347 
348     /** Ouput a message during locale data checking. The (UTF-8) string is
349         written to stderr and in a non-product build or if DBG_UTIL is enabled
350         also raised as an assertion message box. */
351     static  void                outputCheckMessage( const String& rMsg );
352     static  void                outputCheckMessage( const char* pStr);
353 
354 private:
355     static  void                evaluateLocaleDataChecking();
356 };
357 
358 
359 #endif // _UNOTOOLS_LOCALEDATAWRAPPER_HXX
360