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 #pragma once 21 22 #include <com/sun/star/uno/Reference.hxx> 23 #include <i18nlangtag/lang.h> 24 #include <i18nutil/transliteration.hxx> 25 #include <unotools/syslocale.hxx> 26 #include <unotools/localedatawrapper.hxx> 27 #include <unotools/calendarwrapper.hxx> 28 #include <unotools/transliterationwrapper.hxx> 29 #include <unotools/nativenumberwrapper.hxx> 30 #include <unotools/charclass.hxx> 31 #include <optional> 32 33 /* 34 On demand instantiation and initialization of several i18n wrappers, 35 helping the number formatter to not perform worse than it already does. 36 */ 37 38 /** @short 39 Switch between LANGUAGE_SYSTEM and LANGUAGE_ENGLISH_US and any other 40 LocaleDataWrapper. 41 SvNumberformatter uses it upon switching locales. 42 43 @descr 44 Avoids reloading and analysing of locale data again and again. 45 46 @ATTENTION 47 If the default ctor is used the init() method MUST be called before 48 accessing any locale data. The passed parameters Locale and LanguageType 49 must match each other. 50 */ 51 52 class OnDemandLocaleDataWrapper 53 { 54 css::uno::Reference<css::uno::XComponentContext> m_xContext; 55 SvtSysLocale aSysLocale; 56 LanguageType eCurrentLanguage; 57 LanguageType eLastAnyLanguage; 58 std::optional<LocaleDataWrapper> moEnglish; 59 std::optional<LocaleDataWrapper> moAny; 60 int nCurrent; // 0 == system, 1 == english, 2 == any 61 bool bInitialized; 62 63 public: OnDemandLocaleDataWrapper()64 OnDemandLocaleDataWrapper() 65 : eLastAnyLanguage(LANGUAGE_DONTKNOW) 66 , nCurrent(0) 67 , bInitialized(false) 68 { 69 eCurrentLanguage = LANGUAGE_SYSTEM; 70 } 71 isInitialized() const72 bool isInitialized() const { return bInitialized; } 73 init(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const LanguageTag & rLanguageTag)74 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext, 75 const LanguageTag& rLanguageTag) 76 { 77 m_xContext = rxContext; 78 changeLocale(rLanguageTag); 79 bInitialized = true; 80 } 81 changeLocale(const LanguageTag & rLanguageTag)82 void changeLocale(const LanguageTag& rLanguageTag) 83 { 84 LanguageType eLang = rLanguageTag.getLanguageType(false); 85 if (eLang == LANGUAGE_SYSTEM) 86 nCurrent = 0; 87 else if (eLang == LANGUAGE_ENGLISH_US) 88 { 89 if (!moEnglish) 90 moEnglish.emplace(m_xContext, rLanguageTag); 91 nCurrent = 1; 92 } 93 else 94 { 95 if (!moAny) 96 { 97 moAny.emplace(m_xContext, rLanguageTag); 98 eLastAnyLanguage = eLang; 99 } 100 else if (eLastAnyLanguage != eLang) 101 { 102 moAny.emplace(m_xContext, rLanguageTag); 103 eLastAnyLanguage = eLang; 104 } 105 nCurrent = 2; 106 } 107 eCurrentLanguage = eLang; 108 } 109 getCurrentLanguage() const110 LanguageType getCurrentLanguage() const { return eCurrentLanguage; } 111 get() const112 const LocaleDataWrapper* get() const 113 { 114 switch (nCurrent) 115 { 116 case 0: 117 return &aSysLocale.GetLocaleData(); 118 case 1: 119 return &*moEnglish; 120 case 2: 121 return &*moAny; 122 default: 123 assert(false); 124 return nullptr; 125 } 126 } operator ->() const127 const LocaleDataWrapper* operator->() const { return get(); } operator *() const128 const LocaleDataWrapper& operator*() const { return *get(); } 129 }; 130 131 /** Load a calendar only if it's needed. Keep calendar for "en-US" locale 132 separately, as there can be alternation between locale dependent and 133 locale independent formats. 134 SvNumberformatter uses it upon switching locales. 135 136 @ATTENTION If the default ctor is used the init() method MUST be called 137 before accessing the calendar. 138 */ 139 class OnDemandCalendarWrapper 140 { 141 css::uno::Reference<css::uno::XComponentContext> m_xContext; 142 css::lang::Locale aEnglishLocale; 143 css::lang::Locale aLocale; 144 mutable css::lang::Locale aLastAnyLocale; 145 mutable std::optional<CalendarWrapper> moEnglish; 146 mutable std::optional<CalendarWrapper> moAny; 147 148 public: OnDemandCalendarWrapper()149 OnDemandCalendarWrapper() 150 { 151 LanguageTag aEnglishLanguageTag(LANGUAGE_ENGLISH_US); 152 aEnglishLocale = aEnglishLanguageTag.getLocale(); 153 aLastAnyLocale = aEnglishLocale; 154 } 155 init(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::lang::Locale & rLocale)156 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext, 157 const css::lang::Locale& rLocale) 158 { 159 m_xContext = rxContext; 160 changeLocale(rLocale); 161 moEnglish.reset(); 162 moAny.reset(); 163 } 164 changeLocale(const css::lang::Locale & rLocale)165 void changeLocale(const css::lang::Locale& rLocale) { aLocale = rLocale; } 166 get() const167 CalendarWrapper* get() const 168 { 169 CalendarWrapper* pPtr; 170 if (aLocale == aEnglishLocale) 171 { 172 if (!moEnglish) 173 { 174 moEnglish.emplace(m_xContext); 175 moEnglish->loadDefaultCalendar(aEnglishLocale); 176 } 177 pPtr = &*moEnglish; 178 } 179 else 180 { 181 if (!moAny) 182 { 183 moAny.emplace(m_xContext); 184 moAny->loadDefaultCalendar(aLocale); 185 aLastAnyLocale = aLocale; 186 } 187 else if (aLocale != aLastAnyLocale) 188 { 189 moAny->loadDefaultCalendar(aLocale); 190 aLastAnyLocale = aLocale; 191 } 192 pPtr = &*moAny; 193 } 194 return pPtr; 195 } 196 }; 197 198 /** Load a transliteration only if it's needed. 199 SvNumberformatter uses it upon switching locales. 200 @ATTENTION If the default ctor is used the init() method MUST be called 201 before accessing the transliteration. 202 */ 203 class OnDemandTransliterationWrapper 204 { 205 css::uno::Reference<css::uno::XComponentContext> m_xContext; 206 LanguageType eLanguage; 207 TransliterationFlags nType; 208 mutable std::optional<::utl::TransliterationWrapper> moTransliterate; 209 mutable bool bValid; 210 bool bInitialized; 211 212 public: OnDemandTransliterationWrapper()213 OnDemandTransliterationWrapper() 214 : eLanguage(LANGUAGE_SYSTEM) 215 , nType(TransliterationFlags::NONE) 216 , bValid(false) 217 , bInitialized(false) 218 { 219 } 220 isInitialized() const221 bool isInitialized() const { return bInitialized; } 222 init(const css::uno::Reference<css::uno::XComponentContext> & rxContext,LanguageType eLang)223 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext, LanguageType eLang) 224 { 225 m_xContext = rxContext; 226 nType = TransliterationFlags::IGNORE_CASE; 227 changeLocale(eLang); 228 moTransliterate.reset(); 229 bInitialized = true; 230 } 231 changeLocale(LanguageType eLang)232 void changeLocale(LanguageType eLang) 233 { 234 bValid = false; 235 eLanguage = eLang; 236 } 237 get() const238 const ::utl::TransliterationWrapper* get() const 239 { 240 if (!bValid) 241 { 242 if (!moTransliterate) 243 moTransliterate.emplace(m_xContext, nType); 244 moTransliterate->loadModuleIfNeeded(eLanguage); 245 bValid = true; 246 } 247 return &*moTransliterate; 248 } 249 operator ->() const250 const ::utl::TransliterationWrapper* operator->() const { return get(); } 251 }; 252 253 /** Load a native number service wrapper only if it's needed. 254 SvNumberformatter uses it. 255 */ 256 class OnDemandNativeNumberWrapper 257 { 258 css::uno::Reference<css::uno::XComponentContext> m_xContext; 259 mutable std::optional<NativeNumberWrapper> moNativeNumber; 260 261 public: OnDemandNativeNumberWrapper(const css::uno::Reference<css::uno::XComponentContext> & rContext)262 OnDemandNativeNumberWrapper(const css::uno::Reference<css::uno::XComponentContext>& rContext) 263 : m_xContext(rContext) 264 { 265 } 266 get() const267 NativeNumberWrapper& get() const 268 { 269 if (!moNativeNumber) 270 moNativeNumber.emplace(m_xContext); 271 return *moNativeNumber; 272 } 273 }; 274 275 /** @short 276 SvNumberformatter uses it upon switching locales. 277 278 @descr 279 Avoids reloading and analysing of locale data again and again. 280 281 @ATTENTION 282 If the default ctor is used the init() method MUST be called before 283 accessing any locale data. 284 */ 285 286 class OnDemandCharClass 287 { 288 std::optional<CharClass> moCharClass1; 289 std::optional<CharClass> moCharClass2; 290 int nCurrent; // -1 == uninitialised, 0 == class1, 1 == class2 291 292 public: OnDemandCharClass()293 OnDemandCharClass() 294 : nCurrent(-1) 295 { 296 } 297 changeLocale(const css::uno::Reference<css::uno::XComponentContext> & xContext,const LanguageTag & rLanguageTag)298 void changeLocale(const css::uno::Reference<css::uno::XComponentContext>& xContext, 299 const LanguageTag& rLanguageTag) 300 { 301 // check for existing match 302 if (moCharClass1 && moCharClass1->getLanguageTag() == rLanguageTag) 303 { 304 nCurrent = 0; 305 return; 306 } 307 if (moCharClass2 && moCharClass2->getLanguageTag() == rLanguageTag) 308 { 309 nCurrent = 1; 310 return; 311 } 312 // no match - update one the current entries 313 if (nCurrent == -1 || nCurrent == 1) 314 { 315 moCharClass1.emplace(xContext, rLanguageTag); 316 nCurrent = 0; 317 } 318 else 319 { 320 moCharClass2.emplace(xContext, rLanguageTag); 321 nCurrent = 1; 322 } 323 } 324 get() const325 const CharClass* get() const 326 { 327 switch (nCurrent) 328 { 329 case 0: 330 return &*moCharClass1; 331 case 1: 332 return &*moCharClass2; 333 default: 334 assert(false); 335 return nullptr; 336 } 337 } operator ->() const338 const CharClass* operator->() const { return get(); } operator *() const339 const CharClass& operator*() const { return *get(); } 340 }; 341 342 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 343
