Line data Source code
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 "cellkeytranslator.hxx"
21 : #include <comphelper/processfactory.hxx>
22 : #include <i18nlangtag/mslangid.hxx>
23 : #include <i18nlangtag/lang.h>
24 : #include <rtl/ustring.hxx>
25 :
26 : #include <com/sun/star/i18n/TransliterationModules.hpp>
27 :
28 : using ::com::sun::star::uno::Sequence;
29 : using ::std::list;
30 :
31 : using namespace ::com::sun::star;
32 :
33 : enum LocaleMatch
34 : {
35 : LOCALE_MATCH_NONE = 0,
36 : LOCALE_MATCH_LANG,
37 : LOCALE_MATCH_LANG_SCRIPT,
38 : LOCALE_MATCH_LANG_SCRIPT_COUNTRY,
39 : LOCALE_MATCH_ALL
40 : };
41 :
42 16 : static LocaleMatch lclLocaleCompare(const lang::Locale& rLocale1, const LanguageTag& rLanguageTag2)
43 : {
44 16 : LocaleMatch eMatchLevel = LOCALE_MATCH_NONE;
45 16 : LanguageTag aLanguageTag1( rLocale1);
46 :
47 16 : if ( aLanguageTag1.getLanguage() == rLanguageTag2.getLanguage() )
48 0 : eMatchLevel = LOCALE_MATCH_LANG;
49 : else
50 16 : return eMatchLevel;
51 :
52 0 : if ( aLanguageTag1.getScript() == rLanguageTag2.getScript() )
53 0 : eMatchLevel = LOCALE_MATCH_LANG_SCRIPT;
54 : else
55 0 : return eMatchLevel;
56 :
57 0 : if ( aLanguageTag1.getCountry() == rLanguageTag2.getCountry() )
58 0 : eMatchLevel = LOCALE_MATCH_LANG_SCRIPT_COUNTRY;
59 : else
60 0 : return eMatchLevel;
61 :
62 0 : if (aLanguageTag1 == rLanguageTag2)
63 0 : return LOCALE_MATCH_ALL;
64 :
65 0 : return eMatchLevel;
66 : }
67 :
68 141 : ScCellKeyword::ScCellKeyword(const sal_Char* pName, OpCode eOpCode, const lang::Locale& rLocale) :
69 : mpName(pName),
70 : meOpCode(eOpCode),
71 141 : mrLocale(rLocale)
72 : {
73 141 : }
74 :
75 52 : ::std::unique_ptr<ScCellKeywordTranslator> ScCellKeywordTranslator::spInstance;
76 :
77 81 : static void lclMatchKeyword(OUString& rName, const ScCellKeywordHashMap& aMap,
78 : OpCode eOpCode = ocNone, const lang::Locale* pLocale = NULL)
79 : {
80 81 : ScCellKeywordHashMap::const_iterator itrEnd = aMap.end();
81 81 : ScCellKeywordHashMap::const_iterator itr = aMap.find(rName);
82 :
83 81 : if ( itr == itrEnd || itr->second.empty() )
84 : // No candidate strings exist. Bail out.
85 130 : return;
86 :
87 16 : if ( eOpCode == ocNone && !pLocale )
88 : {
89 : // Since no locale nor opcode matching is needed, simply return
90 : // the first item on the list.
91 0 : rName = OUString::createFromAscii( itr->second.front().mpName );
92 0 : return;
93 : }
94 :
95 16 : LanguageTag aLanguageTag( pLocale ? *pLocale : lang::Locale("","",""));
96 16 : const sal_Char* aBestMatchName = itr->second.front().mpName;
97 16 : LocaleMatch eLocaleMatchLevel = LOCALE_MATCH_NONE;
98 16 : bool bOpCodeMatched = false;
99 :
100 16 : list<ScCellKeyword>::const_iterator itrListEnd = itr->second.end();
101 16 : list<ScCellKeyword>::const_iterator itrList = itr->second.begin();
102 32 : for ( ; itrList != itrListEnd; ++itrList )
103 : {
104 16 : if ( eOpCode != ocNone && pLocale )
105 : {
106 16 : if ( itrList->meOpCode == eOpCode )
107 : {
108 16 : LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, aLanguageTag);
109 16 : if ( eLevel == LOCALE_MATCH_ALL )
110 : {
111 : // Name with matching opcode and locale found.
112 0 : rName = OUString::createFromAscii( itrList->mpName );
113 0 : return;
114 : }
115 16 : else if ( eLevel > eLocaleMatchLevel )
116 : {
117 : // Name with a better matching locale.
118 0 : eLocaleMatchLevel = eLevel;
119 0 : aBestMatchName = itrList->mpName;
120 : }
121 16 : else if ( !bOpCodeMatched )
122 : // At least the opcode matches.
123 16 : aBestMatchName = itrList->mpName;
124 :
125 16 : bOpCodeMatched = true;
126 16 : }
127 : }
128 0 : else if ( eOpCode != ocNone && !pLocale )
129 : {
130 0 : if ( itrList->meOpCode == eOpCode )
131 : {
132 : // Name with a matching opcode preferred.
133 0 : rName = OUString::createFromAscii( itrList->mpName );
134 0 : return;
135 : }
136 : }
137 0 : else if ( pLocale )
138 : {
139 0 : LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, aLanguageTag);
140 0 : if ( eLevel == LOCALE_MATCH_ALL )
141 : {
142 : // Name with matching locale preferred.
143 0 : rName = OUString::createFromAscii( itrList->mpName );
144 0 : return;
145 : }
146 0 : else if ( eLevel > eLocaleMatchLevel )
147 : {
148 : // Name with a better matching locale.
149 0 : eLocaleMatchLevel = eLevel;
150 0 : aBestMatchName = itrList->mpName;
151 : }
152 : }
153 : }
154 :
155 : // No preferred strings found. Return the best matching name.
156 16 : rName = OUString::createFromAscii(aBestMatchName);
157 : }
158 :
159 81 : void ScCellKeywordTranslator::transKeyword(OUString& rName, const lang::Locale* pLocale, OpCode eOpCode)
160 : {
161 81 : if ( !spInstance.get() )
162 3 : spInstance.reset( new ScCellKeywordTranslator );
163 :
164 81 : LanguageType eLang = pLocale ? LanguageTag(*pLocale).makeFallback().getLanguageType() : LANGUAGE_SYSTEM;
165 81 : Sequence<sal_Int32> aOffsets;
166 81 : rName = spInstance->maTransWrapper.transliterate(rName, eLang, 0, rName.getLength(), &aOffsets);
167 81 : lclMatchKeyword(rName, spInstance->maStringNameMap, eOpCode, pLocale);
168 81 : }
169 :
170 3 : ScCellKeywordTranslator::ScCellKeywordTranslator() :
171 : maTransWrapper( ::comphelper::getProcessComponentContext(),
172 3 : i18n::TransliterationModules_LOWERCASE_UPPERCASE )
173 : {
174 3 : init();
175 3 : }
176 :
177 3 : ScCellKeywordTranslator::~ScCellKeywordTranslator()
178 : {
179 3 : }
180 :
181 : struct TransItem
182 : {
183 : const sal_Unicode* from;
184 : const sal_Char* to;
185 : OpCode func;
186 : };
187 :
188 3 : void ScCellKeywordTranslator::init()
189 : {
190 3 : ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
191 :
192 : // The file below has been autogenerated by sc/workben/celltrans/parse.py.
193 : // To add new locale keywords, edit sc/workben/celltrans/keywords_utf16.txt
194 : // and re-run the parse.py script.
195 : //
196 : // All keywords must be uppercase, and the mapping must be from the
197 : // localized keyword to the English keyword.
198 : //
199 : // Make sure that the original keyword file (keywords_utf16.txt) is
200 : // encoded in UCS-2/UTF-16!
201 :
202 : #include "cellkeywords.inl"
203 3 : }
204 :
205 141 : void ScCellKeywordTranslator::addToMap(const OUString& rKey, const sal_Char* pName, const lang::Locale& rLocale, OpCode eOpCode)
206 : {
207 141 : ScCellKeyword aKeyItem( pName, eOpCode, rLocale );
208 :
209 141 : ScCellKeywordHashMap::iterator itrEnd = maStringNameMap.end();
210 141 : ScCellKeywordHashMap::iterator itr = maStringNameMap.find(rKey);
211 :
212 141 : if ( itr == itrEnd )
213 : {
214 : // New keyword.
215 135 : list<ScCellKeyword> aList;
216 135 : aList.push_back(aKeyItem);
217 135 : maStringNameMap.insert( ScCellKeywordHashMap::value_type(rKey, aList) );
218 : }
219 : else
220 6 : itr->second.push_back(aKeyItem);
221 141 : }
222 :
223 9 : void ScCellKeywordTranslator::addToMap(const TransItem* pItems, const lang::Locale& rLocale)
224 : {
225 150 : for (sal_uInt16 i = 0; pItems[i].from != NULL; ++i)
226 141 : addToMap(OUString(pItems[i].from), pItems[i].to, rLocale, pItems[i].func);
227 165 : }
228 :
229 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|