calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / shell / source / backends / localebe / localebackend.cxx
blob558926d8febd3431b18ea03bb0681a523e553773
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <cassert>
24 #include <limits>
26 #include "localebackend.hxx"
27 #include <com/sun/star/beans/Optional.hpp>
28 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <rtl/character.hxx>
31 #include <o3tl/char16_t2wchar_t.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <i18nlangtag/mslangid.hxx>
35 #ifdef _WIN32
36 #if !defined WIN32_LEAN_AND_MEAN
37 # define WIN32_LEAN_AND_MEAN
38 #endif
39 #include <windows.h>
41 static css::beans::Optional<css::uno::Any> ImplGetLocale(LCID lcid)
43 WCHAR buffer[8];
44 PWSTR cp = buffer;
46 cp += GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME, buffer, 4 );
47 if( cp > buffer )
49 if( 0 < GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME, cp, buffer + 8 - cp) )
50 // #i50822# minus character must be written before cp
51 *(cp - 1) = '-';
53 return {true, css::uno::Any(OUString(o3tl::toU(buffer)))};
56 return {false, {}};
59 #elif defined(MACOSX)
61 #include <rtl/ustrbuf.hxx>
62 #include <locale.h>
63 #include <string.h>
65 #include <premac.h>
66 #include <CoreServices/CoreServices.h>
67 #include <CoreFoundation/CoreFoundation.h>
68 #include <postmac.h>
70 namespace /* private */
73 void OUStringBufferAppendCFString(OUStringBuffer& buffer, const CFStringRef s)
75 CFIndex lstr = CFStringGetLength(s);
76 for (CFIndex i = 0; i < lstr; i++)
77 buffer.append(sal_Unicode(CFStringGetCharacterAtIndex(s, i)));
80 template <typename T>
81 class CFGuard
83 public:
84 explicit CFGuard(T& rT) : rT_(rT) {}
85 ~CFGuard() { if (rT_) CFRelease(rT_); }
86 private:
87 T& rT_;
90 typedef CFGuard<CFArrayRef> CFArrayGuard;
91 typedef CFGuard<CFStringRef> CFStringGuard;
92 typedef CFGuard<CFTypeRef> CFTypeRefGuard;
94 /* For more information on the Apple locale concept please refer to
95 http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFLocales/Articles/CFLocaleConcepts.html
96 According to this documentation a locale identifier has the format: language[_country][_variant]*
97 e.g. es_ES_PREEURO -> spain prior Euro support
98 Note: The calling code should be able to handle locales with only language information e.g. 'en' for certain
99 UI languages just the language code will be returned.
102 CFStringRef ImplGetAppPreference(const char* pref)
104 CFStringRef csPref = CFStringCreateWithCString(nullptr, pref, kCFStringEncodingASCII);
105 CFStringGuard csRefGuard(csPref);
107 CFTypeRef ref = CFPreferencesCopyAppValue(csPref, kCFPreferencesCurrentApplication);
108 CFTypeRefGuard refGuard(ref);
110 if (ref == nullptr)
111 return nullptr;
113 CFStringRef sref = (CFGetTypeID(ref) == CFArrayGetTypeID()) ? static_cast<CFStringRef>(CFArrayGetValueAtIndex(static_cast<CFArrayRef>(ref), 0)) : static_cast<CFStringRef>(ref);
115 // NOTE: this API is only available with macOS >=10.3. We need to use it because
116 // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't
117 // upgrade those values during upgrade to newer macOS versions. See also #i54337#
118 return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref);
121 css::beans::Optional<css::uno::Any> ImplGetLocale(const char* pref)
123 CFStringRef sref = ImplGetAppPreference(pref);
124 CFStringGuard srefGuard(sref);
126 OUStringBuffer aLocaleBuffer;
127 aLocaleBuffer.append("en-US"); // initialize with fallback value
129 if (sref != nullptr)
131 // split the string into substrings; the first two (if there are two) substrings
132 // are language and country
133 CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(nullptr, sref, CFSTR("_"));
134 CFArrayGuard subsGuard(subs);
136 if (subs != nullptr)
138 aLocaleBuffer.setLength(0); // clear buffer which still contains fallback value
140 CFStringRef lang = static_cast<CFStringRef>(CFArrayGetValueAtIndex(subs, 0));
141 OUStringBufferAppendCFString(aLocaleBuffer, lang);
143 // country also available? Assumption: if the array contains more than one
144 // value the second value is always the country!
145 if (CFArrayGetCount(subs) > 1)
147 aLocaleBuffer.append("-");
148 CFStringRef country = static_cast<CFStringRef>(CFArrayGetValueAtIndex(subs, 1));
149 OUStringBufferAppendCFString(aLocaleBuffer, country);
153 return {true, css::uno::Any(aLocaleBuffer.makeStringAndClear())};
156 } // namespace /* private */
158 #else
160 #include <rtl/ustrbuf.hxx>
161 #include <cstdlib>
162 #include <cstring>
164 static css::beans::Optional<css::uno::Any> ImplGetLocale(char const * category)
166 const char *locale = std::getenv("LC_ALL");
167 if (locale == nullptr || *locale == '\0') {
168 locale = std::getenv(category);
169 if (locale == nullptr || *locale == '\0') {
170 locale = std::getenv("LANG");
174 // Return "en-US" for C locales
175 if( (locale == nullptr) || *locale == '\0' || std::strcmp(locale, "C") == 0
176 || std::strcmp(locale, "POSIX") == 0 )
177 return {true, css::uno::Any(OUString("en-US"))};
180 const char *cp;
181 const char *uscore = nullptr;
182 const char *end = nullptr;
184 // locale string have the format lang[_ctry][.encoding][@modifier]
185 // Let LanguageTag handle all conversion, but do a sanity and length check
186 // first.
187 // For the fallback we are only interested in the first two items, so we
188 // handle '.' and '@' as string end for that.
189 for (cp = locale; *cp; cp++)
191 if (*cp == '_' && !uscore)
192 uscore = cp;
193 if ((*cp == '.' || *cp == '@') && !end)
194 end = cp;
195 if (!rtl::isAscii(static_cast<unsigned char>(*cp))) {
196 SAL_INFO("shell", "locale env var with non-ASCII content");
197 return {false, {}};
200 assert(cp >= locale);
201 if (cp - locale > std::numeric_limits<sal_Int32>::max()) {
202 SAL_INFO("shell", "locale env var content too long");
203 return {false, {}};
206 // This is a tad awkward... but the easiest way to obtain what we're
207 // actually interested in. For example this also converts
208 // "ca_ES.UTF-8@valencia" to "ca-ES-valencia".
209 const OString aLocaleStr(locale);
210 const LanguageType nLang = MsLangId::convertUnxByteStringToLanguage( aLocaleStr);
211 if (nLang != LANGUAGE_DONTKNOW)
213 const OUString aLangTagStr( LanguageTag::convertToBcp47( nLang));
214 return {true, css::uno::Any(aLangTagStr)};
217 // As a fallback, strip encoding and modifier and return just a
218 // language-country combination and let the caller handle unknowns.
219 OUStringBuffer aLocaleBuffer;
220 if (!end)
221 end = cp;
222 if( uscore != nullptr )
224 aLocaleBuffer.appendAscii(locale, uscore++ - locale);
225 aLocaleBuffer.append("-");
226 aLocaleBuffer.appendAscii(uscore, end - uscore);
228 else
230 aLocaleBuffer.appendAscii(locale, end - locale);
233 return {true, css::uno::Any(aLocaleBuffer.makeStringAndClear())};
236 #endif
239 LocaleBackend::LocaleBackend()
244 LocaleBackend::~LocaleBackend()
250 css::beans::Optional<css::uno::Any> LocaleBackend::getLocale()
252 #if defined(_WIN32)
253 return ImplGetLocale( GetUserDefaultLCID() );
254 #elif defined (MACOSX)
255 return ImplGetLocale("AppleLocale");
256 #else
257 return ImplGetLocale("LC_CTYPE");
258 #endif
262 css::beans::Optional<css::uno::Any> LocaleBackend::getUILocale()
264 #if defined(_WIN32)
265 return ImplGetLocale( MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT) );
266 #elif defined(MACOSX)
267 return ImplGetLocale("AppleLanguages");
268 #else
269 return ImplGetLocale("LC_MESSAGES");
270 #endif
274 css::beans::Optional<css::uno::Any> LocaleBackend::getSystemLocale()
276 // note: the implementation differs from getLocale() only on Windows
277 #if defined(_WIN32)
278 return ImplGetLocale( GetSystemDefaultLCID() );
279 #else
280 return getLocale();
281 #endif
285 void LocaleBackend::setPropertyValue(
286 OUString const &, css::uno::Any const &)
288 throw css::lang::IllegalArgumentException(
289 "setPropertyValue not supported",
290 static_cast< cppu::OWeakObject * >(this), -1);
293 css::uno::Any LocaleBackend::getPropertyValue(
294 OUString const & PropertyName)
296 if ( PropertyName == "Locale" ) {
297 return css::uno::Any(getLocale());
298 } else if (PropertyName == "SystemLocale")
300 return css::uno::Any(getSystemLocale());
301 } else if (PropertyName == "UILocale")
303 return css::uno::Any(getUILocale());
304 } else {
305 throw css::beans::UnknownPropertyException(
306 PropertyName, static_cast< cppu::OWeakObject * >(this));
311 OUString SAL_CALL LocaleBackend::getImplementationName()
313 return "com.sun.star.comp.configuration.backend.LocaleBackend" ;
316 sal_Bool SAL_CALL LocaleBackend::supportsService(const OUString& aServiceName)
318 return cppu::supportsService(this, aServiceName);
321 uno::Sequence<OUString> SAL_CALL LocaleBackend::getSupportedServiceNames()
323 return { "com.sun.star.configuration.backend.LocaleBackend" };
326 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
327 shell_LocaleBackend_get_implementation(
328 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
330 return cppu::acquire(new LocaleBackend());
333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */