/* -*- 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 . */ #pragma once #include #include #include #include #include #include #include #include #include #include /* On demand instantiation and initialization of several i18n wrappers, helping the number formatter to not perform worse than it already does. */ /** @short Switch between LANGUAGE_SYSTEM and LANGUAGE_ENGLISH_US and any other LocaleDataWrapper. SvNumberformatter uses it upon switching locales. @descr Avoids reloading and analysing of locale data again and again. @ATTENTION If the default ctor is used the init() method MUST be called before accessing any locale data. The passed parameters Locale and LanguageType must match each other. */ class OnDemandLocaleDataWrapper { css::uno::Reference m_xContext; SvtSysLocale aSysLocale; LanguageType eCurrentLanguage; LanguageType eLastAnyLanguage; std::optional moEnglish; std::optional moAny; int nCurrent; // 0 == system, 1 == english, 2 == any bool bInitialized; public: OnDemandLocaleDataWrapper() : eLastAnyLanguage(LANGUAGE_DONTKNOW) , nCurrent(0) , bInitialized(false) { eCurrentLanguage = LANGUAGE_SYSTEM; } bool isInitialized() const { return bInitialized; } void init(const css::uno::Reference& rxContext, const LanguageTag& rLanguageTag) { m_xContext = rxContext; changeLocale(rLanguageTag); bInitialized = true; } void changeLocale(const LanguageTag& rLanguageTag) { LanguageType eLang = rLanguageTag.getLanguageType(false); if (eLang == LANGUAGE_SYSTEM) nCurrent = 0; else if (eLang == LANGUAGE_ENGLISH_US) { if (!moEnglish) moEnglish.emplace(m_xContext, rLanguageTag); nCurrent = 1; } else { if (!moAny) { moAny.emplace(m_xContext, rLanguageTag); eLastAnyLanguage = eLang; } else if (eLastAnyLanguage != eLang) { moAny.emplace(m_xContext, rLanguageTag); eLastAnyLanguage = eLang; } nCurrent = 2; } eCurrentLanguage = eLang; } LanguageType getCurrentLanguage() const { return eCurrentLanguage; } const LocaleDataWrapper* get() const { switch (nCurrent) { case 0: return &aSysLocale.GetLocaleData(); case 1: return &*moEnglish; case 2: return &*moAny; default: assert(false); return nullptr; } } const LocaleDataWrapper* operator->() const { return get(); } const LocaleDataWrapper& operator*() const { return *get(); } }; /** Load a calendar only if it's needed. Keep calendar for "en-US" locale separately, as there can be alternation between locale dependent and locale independent formats. SvNumberformatter uses it upon switching locales. @ATTENTION If the default ctor is used the init() method MUST be called before accessing the calendar. */ class OnDemandCalendarWrapper { css::uno::Reference m_xContext; css::lang::Locale aEnglishLocale; css::lang::Locale aLocale; mutable css::lang::Locale aLastAnyLocale; mutable std::optional moEnglish; mutable std::optional moAny; public: OnDemandCalendarWrapper() { LanguageTag aEnglishLanguageTag(LANGUAGE_ENGLISH_US); aEnglishLocale = aEnglishLanguageTag.getLocale(); aLastAnyLocale = aEnglishLocale; } void init(const css::uno::Reference& rxContext, const css::lang::Locale& rLocale) { m_xContext = rxContext; changeLocale(rLocale); moEnglish.reset(); moAny.reset(); } void changeLocale(const css::lang::Locale& rLocale) { aLocale = rLocale; } CalendarWrapper* get() const { CalendarWrapper* pPtr; if (aLocale == aEnglishLocale) { if (!moEnglish) { moEnglish.emplace(m_xContext); moEnglish->loadDefaultCalendar(aEnglishLocale); } pPtr = &*moEnglish; } else { if (!moAny) { moAny.emplace(m_xContext); moAny->loadDefaultCalendar(aLocale); aLastAnyLocale = aLocale; } else if (aLocale != aLastAnyLocale) { moAny->loadDefaultCalendar(aLocale); aLastAnyLocale = aLocale; } pPtr = &*moAny; } return pPtr; } }; /** Load a transliteration only if it's needed. SvNumberformatter uses it upon switching locales. @ATTENTION If the default ctor is used the init() method MUST be called before accessing the transliteration. */ class OnDemandTransliterationWrapper { css::uno::Reference m_xContext; LanguageType eLanguage; TransliterationFlags nType; mutable std::optional<::utl::TransliterationWrapper> moTransliterate; mutable bool bValid; bool bInitialized; public: OnDemandTransliterationWrapper() : eLanguage(LANGUAGE_SYSTEM) , nType(TransliterationFlags::NONE) , bValid(false) , bInitialized(false) { } bool isInitialized() const { return bInitialized; } void init(const css::uno::Reference& rxContext, LanguageType eLang) { m_xContext = rxContext; nType = TransliterationFlags::IGNORE_CASE; changeLocale(eLang); moTransliterate.reset(); bInitialized = true; } void changeLocale(LanguageType eLang) { bValid = false; eLanguage = eLang; } const ::utl::TransliterationWrapper* get() const { if (!bValid) { if (!moTransliterate) moTransliterate.emplace(m_xContext, nType); moTransliterate->loadModuleIfNeeded(eLanguage); bValid = true; } return &*moTransliterate; } const ::utl::TransliterationWrapper* operator->() const { return get(); } }; /** Load a native number service wrapper only if it's needed. SvNumberformatter uses it. @ATTENTION If the default ctor is used the init() method MUST be called before accessing the native number supplier. */ class OnDemandNativeNumberWrapper { css::uno::Reference m_xContext; mutable std::optional moNativeNumber; public: OnDemandNativeNumberWrapper() {} void init(const css::uno::Reference& rxContext) { m_xContext = rxContext; moNativeNumber.reset(); } NativeNumberWrapper* get() const { if (!moNativeNumber) moNativeNumber.emplace(m_xContext); return &*moNativeNumber; } }; /** @short SvNumberformatter uses it upon switching locales. @descr Avoids reloading and analysing of locale data again and again. @ATTENTION If the default ctor is used the init() method MUST be called before accessing any locale data. */ class OnDemandCharClass { std::optional moCharClass1; std::optional moCharClass2; int nCurrent; // -1 == uninitialised, 0 == class1, 1 == class2 public: OnDemandCharClass() : nCurrent(-1) { } void changeLocale(const css::uno::Reference& xContext, const LanguageTag& rLanguageTag) { // check for existing match if (moCharClass1 && moCharClass1->getLanguageTag() == rLanguageTag) { nCurrent = 0; return; } if (moCharClass2 && moCharClass2->getLanguageTag() == rLanguageTag) { nCurrent = 1; return; } // no match - update one the current entries if (nCurrent == -1 || nCurrent == 1) { moCharClass1.emplace(xContext, rLanguageTag); nCurrent = 0; } else { moCharClass2.emplace(xContext, rLanguageTag); nCurrent = 1; } } const CharClass* get() const { switch (nCurrent) { case 0: return &*moCharClass1; case 1: return &*moCharClass2; default: assert(false); return nullptr; } } const CharClass* operator->() const { return get(); } const CharClass& operator*() const { return *get(); } }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */