diff options
Diffstat (limited to 'shell/source/backends/localebe')
-rw-r--r-- | shell/source/backends/localebe/localebackend.cxx | 343 | ||||
-rw-r--r-- | shell/source/backends/localebe/localebackend.hxx | 122 | ||||
-rw-r--r-- | shell/source/backends/localebe/localebe1.component | 25 | ||||
-rw-r--r-- | shell/source/backends/localebe/localebecdef.cxx | 63 |
4 files changed, 553 insertions, 0 deletions
diff --git a/shell/source/backends/localebe/localebackend.cxx b/shell/source/backends/localebe/localebackend.cxx new file mode 100644 index 000000000..263b039e9 --- /dev/null +++ b/shell/source/backends/localebe/localebackend.cxx @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <cassert> +#include <limits> + +#include "localebackend.hxx" +#include <com/sun/star/beans/Optional.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <osl/time.h> +#include <rtl/character.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <i18nlangtag/mslangid.hxx> + +#include <stdio.h> + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +static css::beans::Optional<css::uno::Any> ImplGetLocale(LCID lcid) +{ + WCHAR buffer[8]; + PWSTR cp = buffer; + + cp += GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME, buffer, 4 ); + if( cp > buffer ) + { + if( 0 < GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME, cp, buffer + 8 - cp) ) + // #i50822# minus character must be written before cp + *(cp - 1) = '-'; + + return {true, css::uno::Any(OUString(o3tl::toU(buffer)))}; + } + + return {false, {}}; +} + +#elif defined(MACOSX) + +#include <rtl/ustrbuf.hxx> +#include <locale.h> +#include <string.h> + +#include <premac.h> +#include <CoreServices/CoreServices.h> +#include <CoreFoundation/CoreFoundation.h> +#include <postmac.h> + +namespace /* private */ +{ + + void OUStringBufferAppendCFString(OUStringBuffer& buffer, const CFStringRef s) + { + CFIndex lstr = CFStringGetLength(s); + for (CFIndex i = 0; i < lstr; i++) + buffer.append(sal_Unicode(CFStringGetCharacterAtIndex(s, i))); + } + + template <typename T> + class CFGuard + { + public: + explicit CFGuard(T& rT) : rT_(rT) {} + ~CFGuard() { if (rT_) CFRelease(rT_); } + private: + T& rT_; + }; + + typedef CFGuard<CFArrayRef> CFArrayGuard; + typedef CFGuard<CFStringRef> CFStringGuard; + typedef CFGuard<CFTypeRef> CFTypeRefGuard; + + /* For more information on the Apple locale concept please refer to + http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFLocales/Articles/CFLocaleConcepts.html + According to this documentation a locale identifier has the format: language[_country][_variant]* + e.g. es_ES_PREEURO -> spain prior Euro support + Note: The calling code should be able to handle locales with only language information e.g. 'en' for certain + UI languages just the language code will be returned. + */ + + CFStringRef ImplGetAppPreference(const char* pref) + { + CFStringRef csPref = CFStringCreateWithCString(nullptr, pref, kCFStringEncodingASCII); + CFStringGuard csRefGuard(csPref); + + CFTypeRef ref = CFPreferencesCopyAppValue(csPref, kCFPreferencesCurrentApplication); + CFTypeRefGuard refGuard(ref); + + if (ref == nullptr) + return nullptr; + + CFStringRef sref = (CFGetTypeID(ref) == CFArrayGetTypeID()) ? static_cast<CFStringRef>(CFArrayGetValueAtIndex(static_cast<CFArrayRef>(ref), 0)) : static_cast<CFStringRef>(ref); + + // NOTE: this API is only available with macOS >=10.3. We need to use it because + // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't + // upgrade those values during upgrade to newer macOS versions. See also #i54337# + return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref); + } + + css::beans::Optional<css::uno::Any> ImplGetLocale(const char* pref) + { + CFStringRef sref = ImplGetAppPreference(pref); + CFStringGuard srefGuard(sref); + + OUStringBuffer aLocaleBuffer; + aLocaleBuffer.append("en-US"); // initialize with fallback value + + if (sref != nullptr) + { + // split the string into substrings; the first two (if there are two) substrings + // are language and country + CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(nullptr, sref, CFSTR("_")); + CFArrayGuard subsGuard(subs); + + if (subs != nullptr) + { + aLocaleBuffer.setLength(0); // clear buffer which still contains fallback value + + CFStringRef lang = static_cast<CFStringRef>(CFArrayGetValueAtIndex(subs, 0)); + OUStringBufferAppendCFString(aLocaleBuffer, lang); + + // country also available? Assumption: if the array contains more than one + // value the second value is always the country! + if (CFArrayGetCount(subs) > 1) + { + aLocaleBuffer.append("-"); + CFStringRef country = static_cast<CFStringRef>(CFArrayGetValueAtIndex(subs, 1)); + OUStringBufferAppendCFString(aLocaleBuffer, country); + } + } + } + return {true, css::uno::Any(aLocaleBuffer.makeStringAndClear())}; + } + +} // namespace /* private */ + +#else + +#include <rtl/ustrbuf.hxx> +#include <cstdlib> +#include <cstring> + +static css::beans::Optional<css::uno::Any> ImplGetLocale(char const * category) +{ + const char *locale = std::getenv("LC_ALL"); + if (locale == nullptr || *locale == '\0') { + locale = std::getenv(category); + if (locale == nullptr || *locale == '\0') { + locale = std::getenv("LANG"); + } + } + + // Return "en-US" for C locales + if( (locale == nullptr) || *locale == '\0' || std::strcmp(locale, "C") == 0 + || std::strcmp(locale, "POSIX") == 0 ) + return {true, css::uno::Any(OUString("en-US"))}; + + + const char *cp; + const char *uscore = nullptr; + const char *end = nullptr; + + // locale string have the format lang[_ctry][.encoding][@modifier] + // Let LanguageTag handle all conversion, but do a sanity and length check + // first. + // For the fallback we are only interested in the first two items, so we + // handle '.' and '@' as string end for that. + for (cp = locale; *cp; cp++) + { + if (*cp == '_' && !uscore) + uscore = cp; + if ((*cp == '.' || *cp == '@') && !end) + end = cp; + if (!rtl::isAscii(static_cast<unsigned char>(*cp))) { + SAL_INFO("shell", "locale env var with non-ASCII content"); + return {false, {}}; + } + } + assert(cp >= locale); + if (cp - locale > std::numeric_limits<sal_Int32>::max()) { + SAL_INFO("shell", "locale env var content too long"); + return {false, {}}; + } + + // This is a tad awkward... but the easiest way to obtain what we're + // actually interested in. For example this also converts + // "ca_ES.UTF-8@valencia" to "ca-ES-valencia". + const OString aLocaleStr(locale); + const LanguageType nLang = MsLangId::convertUnxByteStringToLanguage( aLocaleStr); + if (nLang != LANGUAGE_DONTKNOW) + { + const OUString aLangTagStr( LanguageTag::convertToBcp47( nLang)); + return {true, css::uno::Any(aLangTagStr)}; + } + + // As a fallback, strip encoding and modifier and return just a + // language-country combination and let the caller handle unknowns. + OUStringBuffer aLocaleBuffer; + if (!end) + end = cp; + if( uscore != nullptr ) + { + aLocaleBuffer.appendAscii(locale, uscore++ - locale); + aLocaleBuffer.append("-"); + aLocaleBuffer.appendAscii(uscore, end - uscore); + } + else + { + aLocaleBuffer.appendAscii(locale, end - locale); + } + + return {true, css::uno::Any(aLocaleBuffer.makeStringAndClear())}; +} + +#endif + + +LocaleBackend::LocaleBackend() +{ +} + + +LocaleBackend::~LocaleBackend() +{ +} + + +LocaleBackend* LocaleBackend::createInstance() +{ + return new LocaleBackend; +} + + +css::beans::Optional<css::uno::Any> LocaleBackend::getLocale() +{ +#if defined(_WIN32) + return ImplGetLocale( GetUserDefaultLCID() ); +#elif defined (MACOSX) + return ImplGetLocale("AppleLocale"); +#else + return ImplGetLocale("LC_CTYPE"); +#endif +} + + +css::beans::Optional<css::uno::Any> LocaleBackend::getUILocale() +{ +#if defined(_WIN32) + return ImplGetLocale( MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT) ); +#elif defined(MACOSX) + return ImplGetLocale("AppleLanguages"); +#else + return ImplGetLocale("LC_MESSAGES"); +#endif +} + + +css::beans::Optional<css::uno::Any> LocaleBackend::getSystemLocale() +{ +// note: the implementation differs from getLocale() only on Windows +#if defined(_WIN32) + return ImplGetLocale( GetSystemDefaultLCID() ); +#else + return getLocale(); +#endif +} + + +void LocaleBackend::setPropertyValue( + OUString const &, css::uno::Any const &) +{ + throw css::lang::IllegalArgumentException( + "setPropertyValue not supported", + static_cast< cppu::OWeakObject * >(this), -1); +} + +css::uno::Any LocaleBackend::getPropertyValue( + OUString const & PropertyName) +{ + if ( PropertyName == "Locale" ) { + return css::uno::Any(getLocale()); + } else if (PropertyName == "SystemLocale") + { + return css::uno::Any(getSystemLocale()); + } else if (PropertyName == "UILocale") + { + return css::uno::Any(getUILocale()); + } else { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } +} + + +OUString LocaleBackend::getBackendName() { + return "com.sun.star.comp.configuration.backend.LocaleBackend" ; +} + +OUString SAL_CALL LocaleBackend::getImplementationName() +{ + return getBackendName() ; +} + +uno::Sequence<OUString> LocaleBackend::getBackendServiceNames() +{ + uno::Sequence<OUString> aServiceNameList { "com.sun.star.configuration.backend.LocaleBackend" }; + return aServiceNameList ; +} + +sal_Bool SAL_CALL LocaleBackend::supportsService(const OUString& aServiceName) +{ + return cppu::supportsService(this, aServiceName); +} + +uno::Sequence<OUString> SAL_CALL LocaleBackend::getSupportedServiceNames() +{ + return getBackendServiceNames() ; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/backends/localebe/localebackend.hxx b/shell/source/backends/localebe/localebackend.hxx new file mode 100644 index 000000000..006d669db --- /dev/null +++ b/shell/source/backends/localebe/localebackend.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SHELL_SOURCE_BACKENDS_LOCALEBE_LOCALEBACKEND_HXX +#define INCLUDED_SHELL_SOURCE_BACKENDS_LOCALEBE_LOCALEBACKEND_HXX + +#include <sal/config.h> + +#include <com/sun/star/beans/Optional.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/string.hxx> + + +namespace uno = css::uno ; +namespace lang = css::lang ; + +class LocaleBackend final : public ::cppu::WeakImplHelper < + css::beans::XPropertySet, + lang::XServiceInfo > +{ + + public: + + static LocaleBackend* createInstance(); + + // XServiceInfo + virtual OUString SAL_CALL + getImplementationName( ) override ; + + virtual sal_Bool SAL_CALL + supportsService( const OUString& aServiceName ) override ; + + virtual uno::Sequence<OUString> SAL_CALL + getSupportedServiceNames( ) override ; + + /** + Provides the implementation name. + + @return implementation name + */ + static OUString getBackendName() ; + /** + Provides the supported services names + + @return service names + */ + static uno::Sequence<OUString> getBackendServiceNames() ; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override + { return css::uno::Reference< css::beans::XPropertySetInfo >(); } + + virtual void SAL_CALL setPropertyValue( + OUString const &, css::uno::Any const &) override; + + virtual css::uno::Any SAL_CALL getPropertyValue( + OUString const & PropertyName) override; + + virtual void SAL_CALL addPropertyChangeListener( + OUString const &, + css::uno::Reference< css::beans::XPropertyChangeListener > const &) override + {} + + virtual void SAL_CALL removePropertyChangeListener( + OUString const &, + css::uno::Reference< css::beans::XPropertyChangeListener > const &) override + {} + + virtual void SAL_CALL addVetoableChangeListener( + OUString const &, + css::uno::Reference< css::beans::XVetoableChangeListener > const &) override + {} + + virtual void SAL_CALL removeVetoableChangeListener( + OUString const &, + css::uno::Reference< css::beans::XVetoableChangeListener > const &) override + {} + + private: + /** + Service constructor from a service factory. + + @param xContext component context + */ + LocaleBackend(); + + /** Destructor */ + virtual ~LocaleBackend() override ; + + // Returns the user locale + static css::beans::Optional<css::uno::Any> getLocale(); + + // Returns the user UI locale + static css::beans::Optional<css::uno::Any> getUILocale(); + + // Returns the system default locale + static css::beans::Optional<css::uno::Any> getSystemLocale(); +} ; + + +#endif // INCLUDED_SHELL_SOURCE_BACKENDS_LOCALEBE_LOCALEBACKEND_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/backends/localebe/localebe1.component b/shell/source/backends/localebe/localebe1.component new file mode 100644 index 000000000..b874527b9 --- /dev/null +++ b/shell/source/backends/localebe/localebe1.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="localebe1" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.configuration.backend.LocaleBackend"> + <service name="com.sun.star.configuration.backend.LocaleBackend"/> + </implementation> +</component> diff --git a/shell/source/backends/localebe/localebecdef.cxx b/shell/source/backends/localebe/localebecdef.cxx new file mode 100644 index 000000000..fbbd63690 --- /dev/null +++ b/shell/source/backends/localebe/localebecdef.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "localebackend.hxx" + +#include <cppuhelper/implementationentry.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace uno = com::sun::star::uno ; + + +static uno::Reference<uno::XInterface> createLocaleBackend( + SAL_UNUSED_PARAMETER const uno::Reference<uno::XComponentContext>&){ + + return * LocaleBackend::createInstance(); +} + + +static const cppu::ImplementationEntry kImplementations_entries[] = +{ + { + createLocaleBackend, + LocaleBackend::getBackendName, + LocaleBackend::getBackendServiceNames, + cppu::createSingleComponentFactory, + nullptr, + 0 + }, + { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } +} ; + + +extern "C" SAL_DLLPUBLIC_EXPORT void * localebe1_component_getFactory( + const char *aImplementationName, + void *aServiceManager, + void *aRegistryKey) { + + return cppu::component_getFactoryHelper( + aImplementationName, + aServiceManager, + aRegistryKey, + kImplementations_entries) ; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |