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_shell.hxx" 30 31 #include "localebackend.hxx" 32 #include <com/sun/star/beans/Optional.hpp> 33 #include <osl/time.h> 34 35 #include <stdio.h> 36 37 #if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(OS2) 38 39 #include <rtl/ustrbuf.hxx> 40 #include <locale.h> 41 #include <string.h> 42 43 /* 44 * Note: setlocale is not at all thread safe, so is this code. It could 45 * especially interfere with the stuff VCL is doing, so make sure this 46 * is called from the main thread only. 47 */ 48 49 static rtl::OUString ImplGetLocale(int category) 50 { 51 const char *locale = setlocale(category, ""); 52 53 // Return "en-US" for C locales 54 if( (locale == NULL) || ( locale[0] == 'C' && locale[1] == '\0' ) ) 55 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en-US" ) ); 56 57 58 const char *cp; 59 const char *uscore = NULL; 60 61 // locale string have the format lang[_ctry][.encoding][@modifier] 62 // we are only interested in the first two items, so we handle 63 // '.' and '@' as string end. 64 for (cp = locale; *cp; cp++) 65 { 66 if (*cp == '_') 67 uscore = cp; 68 if (*cp == '.' || *cp == '@') 69 break; 70 } 71 72 rtl::OUStringBuffer aLocaleBuffer; 73 if( uscore != NULL ) 74 { 75 aLocaleBuffer.appendAscii(locale, uscore++ - locale); 76 aLocaleBuffer.appendAscii("-"); 77 aLocaleBuffer.appendAscii(uscore, cp - uscore); 78 } 79 else 80 { 81 aLocaleBuffer.appendAscii(locale, cp - locale); 82 } 83 84 return aLocaleBuffer.makeStringAndClear(); 85 } 86 87 #elif defined(MACOSX) 88 89 #include <rtl/ustrbuf.hxx> 90 #include <locale.h> 91 #include <string.h> 92 93 #include <premac.h> 94 #include <CoreServices/CoreServices.h> 95 #include <CoreFoundation/CoreFoundation.h> 96 #include <postmac.h> 97 98 namespace /* private */ 99 { 100 101 void OUStringBufferAppendCFString(rtl::OUStringBuffer& buffer, const CFStringRef s) 102 { 103 CFIndex lstr = CFStringGetLength(s); 104 for (CFIndex i = 0; i < lstr; i++) 105 buffer.append(CFStringGetCharacterAtIndex(s, i)); 106 } 107 108 template <typename T> 109 class CFGuard 110 { 111 public: 112 explicit CFGuard(T& rT) : rT_(rT) {} 113 ~CFGuard() { if (rT_) CFRelease(rT_); } 114 private: 115 T& rT_; 116 }; 117 118 typedef CFGuard<CFArrayRef> CFArrayGuard; 119 typedef CFGuard<CFStringRef> CFStringGuard; 120 typedef CFGuard<CFTypeRef> CFTypeRefGuard; 121 122 /* For more information on the Apple locale concept please refer to 123 http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFLocales/Articles/CFLocaleConcepts.html 124 According to this documentation a locale identifier has the format: language[_country][_variant]* 125 e.g. es_ES_PREEURO -> spain prior Euro support 126 Note: The calling code should be able to handle locales with only language information e.g. 'en' for certain 127 UI languages just the language code will be returned. 128 */ 129 130 CFStringRef ImplGetAppPreference(const char* pref) 131 { 132 CFStringRef csPref = CFStringCreateWithCString(NULL, pref, kCFStringEncodingASCII); 133 CFStringGuard csRefGuard(csPref); 134 135 CFTypeRef ref = CFPreferencesCopyAppValue(csPref, kCFPreferencesCurrentApplication); 136 CFTypeRefGuard refGuard(ref); 137 138 if (ref == NULL) 139 return NULL; 140 141 CFStringRef sref = (CFGetTypeID(ref) == CFArrayGetTypeID()) ? (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)ref, 0) : (CFStringRef)ref; 142 143 // NOTE: this API is only available with Mac OS X >=10.3. We need to use it because 144 // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't 145 // upgrade those values during upgrade to newer Mac OS X versions. See also #i54337# 146 return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref); 147 } 148 149 rtl::OUString ImplGetLocale(const char* pref) 150 { 151 CFStringRef sref = ImplGetAppPreference(pref); 152 CFStringGuard srefGuard(sref); 153 154 rtl::OUStringBuffer aLocaleBuffer; 155 aLocaleBuffer.appendAscii("en-US"); // initialize with fallback value 156 157 if (sref != NULL) 158 { 159 // split the string into substrings; the first two (if there are two) substrings 160 // are language and country 161 CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(NULL, sref, CFSTR("_")); 162 CFArrayGuard subsGuard(subs); 163 164 if (subs != NULL) 165 { 166 aLocaleBuffer.setLength(0); // clear buffer which still contains fallback value 167 168 CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(subs, 0); 169 OUStringBufferAppendCFString(aLocaleBuffer, lang); 170 171 // country also available? Assumption: if the array contains more than one 172 // value the second value is always the country! 173 if (CFArrayGetCount(subs) > 1) 174 { 175 aLocaleBuffer.appendAscii("-"); 176 CFStringRef country = (CFStringRef)CFArrayGetValueAtIndex(subs, 1); 177 OUStringBufferAppendCFString(aLocaleBuffer, country); 178 } 179 } 180 } 181 return aLocaleBuffer.makeStringAndClear(); 182 } 183 184 } // namespace /* private */ 185 186 #endif 187 188 // ------------------------------------------------------------------------------- 189 190 #ifdef WNT 191 192 #ifdef WINVER 193 #undef WINVER 194 #endif 195 #define WINVER 0x0501 196 197 #if defined _MSC_VER 198 #pragma warning(push, 1) 199 #endif 200 #include <windows.h> 201 #if defined _MSC_VER 202 #pragma warning(pop) 203 #endif 204 205 rtl::OUString ImplGetLocale(LCID lcid) 206 { 207 TCHAR buffer[8]; 208 LPTSTR cp = buffer; 209 210 cp += GetLocaleInfo( lcid, LOCALE_SISO639LANGNAME , buffer, 4 ); 211 if( cp > buffer ) 212 { 213 if( 0 < GetLocaleInfo( lcid, LOCALE_SISO3166CTRYNAME, cp, buffer + 8 - cp) ) 214 // #i50822# minus character must be written before cp 215 *(cp - 1) = '-'; 216 217 return rtl::OUString::createFromAscii(buffer); 218 } 219 220 return rtl::OUString(); 221 } 222 223 #endif // WNT 224 225 // ------------------------------------------------------------------------------- 226 227 LocaleBackend::LocaleBackend() 228 { 229 } 230 231 //------------------------------------------------------------------------------ 232 233 LocaleBackend::~LocaleBackend(void) 234 { 235 } 236 237 //------------------------------------------------------------------------------ 238 239 LocaleBackend* LocaleBackend::createInstance() 240 { 241 return new LocaleBackend; 242 } 243 244 // --------------------------------------------------------------------------------------- 245 246 rtl::OUString LocaleBackend::getLocale(void) 247 { 248 #if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(OS2) 249 return ImplGetLocale(LC_CTYPE); 250 #elif defined (MACOSX) 251 return ImplGetLocale("AppleLocale"); 252 #elif defined WNT 253 return ImplGetLocale( GetUserDefaultLCID() ); 254 #endif 255 } 256 257 //------------------------------------------------------------------------------ 258 259 rtl::OUString LocaleBackend::getUILocale(void) 260 { 261 #if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(OS2) 262 return ImplGetLocale(LC_MESSAGES); 263 #elif defined(MACOSX) 264 return ImplGetLocale("AppleLanguages"); 265 #elif defined WNT 266 return ImplGetLocale( MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT) ); 267 #endif 268 } 269 270 // --------------------------------------------------------------------------------------- 271 272 rtl::OUString LocaleBackend::getSystemLocale(void) 273 { 274 // note: the implementation differs from getLocale() only on Windows 275 #if defined WNT 276 return ImplGetLocale( GetSystemDefaultLCID() ); 277 #else 278 return getLocale(); 279 #endif 280 } 281 //------------------------------------------------------------------------------ 282 283 void LocaleBackend::setPropertyValue( 284 rtl::OUString const &, css::uno::Any const &) 285 throw ( 286 css::beans::UnknownPropertyException, css::beans::PropertyVetoException, 287 css::lang::IllegalArgumentException, css::lang::WrappedTargetException, 288 css::uno::RuntimeException) 289 { 290 throw css::lang::IllegalArgumentException( 291 rtl::OUString( 292 RTL_CONSTASCII_USTRINGPARAM("setPropertyValue not supported")), 293 static_cast< cppu::OWeakObject * >(this), -1); 294 } 295 296 css::uno::Any LocaleBackend::getPropertyValue( 297 rtl::OUString const & PropertyName) 298 throw ( 299 css::beans::UnknownPropertyException, css::lang::WrappedTargetException, 300 css::uno::RuntimeException) 301 { 302 if (PropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Locale"))) { 303 return css::uno::makeAny( 304 css::beans::Optional< css::uno::Any >( 305 true, css::uno::makeAny(getLocale()))); 306 } else if (PropertyName.equalsAsciiL( 307 RTL_CONSTASCII_STRINGPARAM("SystemLocale"))) 308 { 309 return css::uno::makeAny( 310 css::beans::Optional< css::uno::Any >( 311 true, css::uno::makeAny(getSystemLocale()))); 312 } else if (PropertyName.equalsAsciiL( 313 RTL_CONSTASCII_STRINGPARAM("UILocale"))) 314 { 315 return css::uno::makeAny( 316 css::beans::Optional< css::uno::Any >( 317 true, css::uno::makeAny(getUILocale()))); 318 } else { 319 throw css::beans::UnknownPropertyException( 320 PropertyName, static_cast< cppu::OWeakObject * >(this)); 321 } 322 } 323 324 //------------------------------------------------------------------------------ 325 326 rtl::OUString SAL_CALL LocaleBackend::getBackendName(void) { 327 return rtl::OUString::createFromAscii("com.sun.star.comp.configuration.backend.LocaleBackend") ; 328 } 329 330 //------------------------------------------------------------------------------ 331 332 rtl::OUString SAL_CALL LocaleBackend::getImplementationName(void) 333 throw (uno::RuntimeException) 334 { 335 return getBackendName() ; 336 } 337 338 //------------------------------------------------------------------------------ 339 340 uno::Sequence<rtl::OUString> SAL_CALL LocaleBackend::getBackendServiceNames(void) 341 { 342 uno::Sequence<rtl::OUString> aServiceNameList(1); 343 aServiceNameList[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.LocaleBackend")) ; 344 return aServiceNameList ; 345 } 346 347 //------------------------------------------------------------------------------ 348 349 sal_Bool SAL_CALL LocaleBackend::supportsService(const rtl::OUString& aServiceName) 350 throw (uno::RuntimeException) 351 { 352 uno::Sequence< rtl::OUString > const svc = getBackendServiceNames(); 353 354 for(sal_Int32 i = 0; i < svc.getLength(); ++i ) 355 if(svc[i] == aServiceName) 356 return true; 357 358 return false; 359 } 360 361 //------------------------------------------------------------------------------ 362 363 uno::Sequence<rtl::OUString> SAL_CALL LocaleBackend::getSupportedServiceNames(void) 364 throw (uno::RuntimeException) 365 { 366 return getBackendServiceNames() ; 367 } 368