diff options
Diffstat (limited to 'include/svl/ondemand.hxx')
-rw-r--r-- | include/svl/ondemand.hxx | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/include/svl/ondemand.hxx b/include/svl/ondemand.hxx new file mode 100644 index 000000000..4a0a91b18 --- /dev/null +++ b/include/svl/ondemand.hxx @@ -0,0 +1,349 @@ +/* -*- 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 <com/sun/star/uno/Reference.hxx> +#include <i18nlangtag/lang.h> +#include <i18nutil/transliteration.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/calendarwrapper.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/nativenumberwrapper.hxx> +#include <unotools/charclass.hxx> +#include <optional> + +/* + 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<css::uno::XComponentContext> m_xContext; + SvtSysLocale aSysLocale; + LanguageType eCurrentLanguage; + LanguageType eLastAnyLanguage; + std::optional<LocaleDataWrapper> moEnglish; + std::optional<LocaleDataWrapper> 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<css::uno::XComponentContext>& 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<css::uno::XComponentContext> m_xContext; + css::lang::Locale aEnglishLocale; + css::lang::Locale aLocale; + mutable css::lang::Locale aLastAnyLocale; + mutable std::optional<CalendarWrapper> moEnglish; + mutable std::optional<CalendarWrapper> moAny; + +public: + OnDemandCalendarWrapper() + { + LanguageTag aEnglishLanguageTag(LANGUAGE_ENGLISH_US); + aEnglishLocale = aEnglishLanguageTag.getLocale(); + aLastAnyLocale = aEnglishLocale; + } + + void init(const css::uno::Reference<css::uno::XComponentContext>& 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<css::uno::XComponentContext> 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<css::uno::XComponentContext>& 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<css::uno::XComponentContext> m_xContext; + mutable std::optional<NativeNumberWrapper> moNativeNumber; + +public: + OnDemandNativeNumberWrapper() {} + + void init(const css::uno::Reference<css::uno::XComponentContext>& 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<CharClass> moCharClass1; + std::optional<CharClass> moCharClass2; + int nCurrent; // -1 == uninitialised, 0 == class1, 1 == class2 + +public: + OnDemandCharClass() + : nCurrent(-1) + { + } + + void changeLocale(const css::uno::Reference<css::uno::XComponentContext>& 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: */ |