Replace workaround of resize to invalidate with an explicit SfxHint
[LibreOffice.git] / i18npool / source / ordinalsuffix / ordinalsuffix.cxx
blob482f540a1435b764520565d9c158ede86a5b3707
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <i18nlangtag/languagetag.hxx>
21 #include <i18nlangtag/languagetagicu.hxx>
22 #include <sal/log.hxx>
23 #include <comphelper/sequence.hxx>
24 #include <cppuhelper/supportsservice.hxx>
25 #include <ordinalsuffix.hxx>
27 #include <unicode/rbnf.h>
28 #include <unicode/normlzr.h>
29 #include <memory>
31 namespace com::sun::star::uno { class XComponentContext; }
33 using namespace ::com::sun::star::i18n;
34 using namespace ::com::sun::star::uno;
35 using namespace ::com::sun::star;
37 namespace i18npool {
40 OrdinalSuffixService::OrdinalSuffixService()
44 OrdinalSuffixService::~OrdinalSuffixService()
48 namespace
50 OUString mungeUnicodeStringToOUString(const icu::UnicodeString &rIn, UErrorCode &rCode)
52 // Apply NFKC normalization to get normal letters
53 icu::UnicodeString normalized;
54 icu::Normalizer::normalize(rIn, UNORM_NFKC, 0, normalized, rCode);
55 // Convert the normalized UnicodeString to OUString
56 OUString sRet = (U_SUCCESS(rCode))
57 ? OUString(reinterpret_cast<const sal_Unicode *>(normalized.getBuffer()), normalized.length())
58 : OUString();
59 // replace any minus signs with hyphen-minus so that negative numbers
60 // from the simple number formatter and heavy-duty pattern formatter
61 // agree as to their negative number sign
62 return sRet.replace(0x2212, '-');
67 * For this method to properly return the ordinal suffix for other locales
68 * than english ones, ICU 4.2+ has to be used.
70 uno::Sequence< OUString > SAL_CALL OrdinalSuffixService::getOrdinalSuffix( sal_Int32 nNumber,
71 const lang::Locale &rLocale )
73 uno::Sequence< OUString > retValue;
75 // Get the value from ICU
76 UErrorCode nCode = U_ZERO_ERROR;
77 const icu::Locale aIcuLocale( LanguageTagIcu::getIcuLocale( LanguageTag( rLocale)));
79 icu::RuleBasedNumberFormat formatter(icu::URBNF_ORDINAL, aIcuLocale, nCode);
80 if (!U_SUCCESS(nCode))
81 return retValue;
83 std::unique_ptr<icu::NumberFormat> xNumberFormat(icu::NumberFormat::createInstance(aIcuLocale, nCode));
84 if (!U_SUCCESS(nCode))
85 return retValue;
87 icu::UnicodeString sFormatWithNoOrdinal;
88 icu::Formattable ftmNumber(static_cast<int32_t>(nNumber));
89 icu::FieldPosition icuPosA;
90 xNumberFormat->format(ftmNumber, sFormatWithNoOrdinal, icuPosA, nCode);
91 if (!U_SUCCESS(nCode))
92 return retValue;
94 OUString sValueWithNoOrdinal = mungeUnicodeStringToOUString(sFormatWithNoOrdinal, nCode);
95 if (!U_SUCCESS(nCode))
96 return retValue;
98 int32_t nRuleSets = formatter.getNumberOfRuleSetNames( );
99 std::vector<OUString> retVec;
100 retVec.reserve(nRuleSets);
101 for (int32_t i = 0; i < nRuleSets; ++i)
103 icu::UnicodeString ruleSet = formatter.getRuleSetName(i);
105 // format the string
106 icu::UnicodeString sFormatWithOrdinal;
107 icu::FieldPosition icuPosB;
108 formatter.format(static_cast<int32_t>(nNumber), ruleSet, sFormatWithOrdinal, icuPosB, nCode);
110 if (!U_SUCCESS(nCode))
111 continue;
113 OUString sValueWithOrdinal = mungeUnicodeStringToOUString(sFormatWithOrdinal, nCode);
114 if (!U_SUCCESS(nCode))
115 continue;
117 // fdo#54486 let's make sure that the ordinal format and the non-ordinal
118 // format match at the start, so that the expectation can be verified
119 // that there is some trailing "ordinal suffix" which can be extracted
120 bool bSimpleOrdinalSuffix = sValueWithOrdinal.startsWith(sValueWithNoOrdinal);
122 SAL_WARN_IF(!bSimpleOrdinalSuffix, "i18npool", "ordinal " <<
123 sValueWithOrdinal << " didn't start with expected " <<
124 sValueWithNoOrdinal << " prefix");
126 if (!bSimpleOrdinalSuffix)
127 continue;
129 // Remove the number to get the prefix
130 sal_Int32 len = sValueWithNoOrdinal.getLength();
131 retVec.push_back(sValueWithOrdinal.copy(len));
134 return comphelper::containerToSequence(retVec);
137 constexpr OUString cOrdinalSuffix = u"com.sun.star.i18n.OrdinalSuffix"_ustr;
139 OUString SAL_CALL OrdinalSuffixService::getImplementationName()
141 return cOrdinalSuffix;
144 sal_Bool SAL_CALL OrdinalSuffixService::supportsService( const OUString& rServiceName)
146 return cppu::supportsService(this, rServiceName);
149 Sequence< OUString > SAL_CALL OrdinalSuffixService::getSupportedServiceNames()
151 return { cOrdinalSuffix };
156 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
157 com_sun_star_i18n_OrdinalSuffix_get_implementation(
158 css::uno::XComponentContext *,
159 css::uno::Sequence<css::uno::Any> const &)
161 return cppu::acquire(new i18npool::OrdinalSuffixService());
164 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */