1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/config.h>
21
22 #include <sal/log.hxx>
23 #include <unotools/localedatawrapper.hxx>
24 #include <unotools/charclass.hxx>
25 #include <unotools/syslocale.hxx>
26 #include <unotools/syslocaleoptions.hxx>
27 #include <comphelper/lok.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <rtl/tencinfo.h>
30 #include <rtl/locale.h>
31 #include <osl/thread.h>
32 #include <osl/nlsupport.h>
33
34 #include <vector>
35 #include <memory>
36
37 using namespace osl;
38 using namespace com::sun::star;
39
40 namespace {
41
42 std::weak_ptr<SvtSysLocale_Impl> g_pSysLocale;
43
44 }
45
46 class SvtSysLocale_Impl : public utl::ConfigurationListener
47 {
48 public:
49 SvtSysLocaleOptions aSysLocaleOptions;
50 std::unique_ptr<LocaleDataWrapper> pLocaleData;
51 std::unique_ptr<CharClass> pCharClass;
52
53 SvtSysLocale_Impl();
54 virtual ~SvtSysLocale_Impl() override;
55
56 CharClass* GetCharClass();
57 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override;
58
59 private:
60 std::vector<OUString> getDateAcceptancePatternsConfig() const;
61 };
62
SvtSysLocale_Impl()63 SvtSysLocale_Impl::SvtSysLocale_Impl()
64 {
65 pLocaleData.reset(new LocaleDataWrapper(
66 aSysLocaleOptions.GetRealLanguageTag(),
67 getDateAcceptancePatternsConfig() ));
68
69 // listen for further changes
70 aSysLocaleOptions.AddListener( this );
71 }
72
~SvtSysLocale_Impl()73 SvtSysLocale_Impl::~SvtSysLocale_Impl()
74 {
75 aSysLocaleOptions.RemoveListener( this );
76 }
77
GetCharClass()78 CharClass* SvtSysLocale_Impl::GetCharClass()
79 {
80 if ( !pCharClass )
81 pCharClass.reset(new CharClass( aSysLocaleOptions.GetRealLanguageTag() ));
82 return pCharClass.get();
83 }
84
ConfigurationChanged(utl::ConfigurationBroadcaster *,ConfigurationHints nHint)85 void SvtSysLocale_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints nHint )
86 {
87 if ( !(nHint & ConfigurationHints::Locale) &&
88 !(nHint & ConfigurationHints::DatePatterns) )
89 return;
90
91 MutexGuard aGuard( SvtSysLocale::GetMutex() );
92
93 const LanguageTag& rLanguageTag = aSysLocaleOptions.GetRealLanguageTag();
94 if ( nHint & ConfigurationHints::Locale )
95 {
96 GetCharClass()->setLanguageTag( rLanguageTag );
97 }
98 pLocaleData.reset(new LocaleDataWrapper(rLanguageTag, getDateAcceptancePatternsConfig()));
99 }
100
getDateAcceptancePatternsConfig() const101 std::vector<OUString> SvtSysLocale_Impl::getDateAcceptancePatternsConfig() const
102 {
103 OUString aStr( aSysLocaleOptions.GetDatePatternsConfigString());
104 if (aStr.isEmpty())
105 return {}; // reset
106 ::std::vector< OUString > aVec;
107 for (sal_Int32 nIndex = 0; nIndex >= 0; /*nop*/)
108 {
109 OUString aTok( aStr.getToken( 0, ';', nIndex));
110 if (!aTok.isEmpty())
111 aVec.push_back( aTok);
112 }
113 return aVec;
114 }
115
SvtSysLocale()116 SvtSysLocale::SvtSysLocale()
117 {
118 MutexGuard aGuard( GetMutex() );
119 pImpl = g_pSysLocale.lock();
120 if ( !pImpl )
121 {
122 pImpl = std::make_shared<SvtSysLocale_Impl>();
123 g_pSysLocale = pImpl;
124 }
125 }
126
~SvtSysLocale()127 SvtSysLocale::~SvtSysLocale()
128 {
129 MutexGuard aGuard( GetMutex() );
130 pImpl.reset();
131 }
132
133 // static
GetMutex()134 Mutex& SvtSysLocale::GetMutex()
135 {
136 // #i77768# Due to a static reference in the toolkit lib
137 // we need a mutex that lives longer than the svl library.
138 // Otherwise the dtor would use a destructed mutex!!
139 static Mutex* persistentMutex(new Mutex);
140
141 return *persistentMutex;
142 }
143
GetLocaleData() const144 const LocaleDataWrapper& SvtSysLocale::GetLocaleData() const
145 {
146 return *(pImpl->pLocaleData);
147 }
148
GetCharClass() const149 const CharClass& SvtSysLocale::GetCharClass() const
150 {
151 return *(pImpl->GetCharClass());
152 }
153
GetCharClassPtr() const154 const CharClass* SvtSysLocale::GetCharClassPtr() const
155 {
156 return pImpl->GetCharClass();
157 }
158
GetOptions() const159 SvtSysLocaleOptions& SvtSysLocale::GetOptions() const
160 {
161 return pImpl->aSysLocaleOptions;
162 }
163
GetLanguageTag() const164 const LanguageTag& SvtSysLocale::GetLanguageTag() const
165 {
166 if (comphelper::LibreOfficeKit::isActive())
167 return comphelper::LibreOfficeKit::getLocale();
168
169 return pImpl->aSysLocaleOptions.GetRealLanguageTag();
170 }
171
GetUILanguageTag() const172 const LanguageTag& SvtSysLocale::GetUILanguageTag() const
173 {
174 if (comphelper::LibreOfficeKit::isActive())
175 return comphelper::LibreOfficeKit::getLanguageTag();
176
177 return pImpl->aSysLocaleOptions.GetRealUILanguageTag();
178 }
179
180 // static
GetBestMimeEncoding()181 rtl_TextEncoding SvtSysLocale::GetBestMimeEncoding()
182 {
183 const char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding(
184 osl_getThreadTextEncoding() );
185 if ( !pCharSet )
186 {
187 // If the system locale is unknown to us, e.g. LC_ALL=xx, match the UI
188 // language if possible.
189 SvtSysLocale aSysLocale;
190 const LanguageTag& rLanguageTag = aSysLocale.GetUILanguageTag();
191 // Converting blindly to Locale and then to rtl_Locale may feed the
192 // 'qlt' to rtl_locale_register() and the underlying system locale
193 // stuff, which doesn't know about it nor about BCP47 in the Variant
194 // field. So use the real language and for non-pure ISO cases hope for
195 // the best... the fallback to UTF-8 should solve these cases nowadays.
196 /* FIXME-BCP47: the script needs to go in here as well, so actually
197 * we'd need some variant fiddling or glibc locale string and tweak
198 * rtl_locale_register() to know about it! But then again the Windows
199 * implementation still wouldn't know anything about it ... */
200 SAL_WARN_IF( !rLanguageTag.isIsoLocale(), "unotools.i18n",
201 "SvtSysLocale::GetBestMimeEncoding - non-ISO UI locale");
202 rtl_Locale * pLocale = rtl_locale_register( rLanguageTag.getLanguage().getStr(),
203 rLanguageTag.getCountry().getStr(), OUString().getStr() );
204 rtl_TextEncoding nEnc = osl_getTextEncodingFromLocale( pLocale );
205 pCharSet = rtl_getBestMimeCharsetFromTextEncoding( nEnc );
206 }
207 rtl_TextEncoding nRet;
208 if ( pCharSet )
209 nRet = rtl_getTextEncodingFromMimeCharset( pCharSet );
210 else
211 nRet = RTL_TEXTENCODING_UTF8;
212 return nRet;
213 }
214
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
216