1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 #include "cellkeytranslator.hxx"
28 #include "comphelper/processfactory.hxx"
29 #include "i18npool/mslangid.hxx"
30 #include "i18npool/lang.h"
31 #include "rtl/ustring.hxx"
32
33 #include <com/sun/star/i18n/TransliterationModules.hpp>
34
35 using ::com::sun::star::lang::Locale;
36 using ::com::sun::star::uno::Sequence;
37 using ::std::list;
38 using ::std::hash_map;
39 using ::rtl::OUString;
40
41 using namespace ::com::sun::star;
42
43 enum LocaleMatch
44 {
45 LOCALE_MATCH_NONE = 0,
46 LOCALE_MATCH_LANG,
47 LOCALE_MATCH_LANG_COUNTRY,
48 LOCALE_MATCH_ALL
49 };
50
lclLocaleCompare(const Locale & rLocale1,const Locale & rLocale2)51 static LocaleMatch lclLocaleCompare(const Locale& rLocale1, const Locale& rLocale2)
52 {
53 LocaleMatch eMatchLevel = LOCALE_MATCH_NONE;
54 if ( !rLocale1.Language.compareTo(rLocale1.Language) )
55 eMatchLevel = LOCALE_MATCH_LANG;
56 else
57 return eMatchLevel;
58
59 if ( !rLocale1.Country.compareTo(rLocale2.Country) )
60 eMatchLevel = LOCALE_MATCH_LANG_COUNTRY;
61 else
62 return eMatchLevel;
63
64 if ( !rLocale1.Variant.compareTo(rLocale2.Variant) )
65 eMatchLevel = LOCALE_MATCH_ALL;
66
67 return eMatchLevel;
68 }
69
ScCellKeyword(const sal_Char * pName,OpCode eOpCode,const Locale & rLocale)70 ScCellKeyword::ScCellKeyword(const sal_Char* pName, OpCode eOpCode, const Locale& rLocale) :
71 mpName(pName),
72 meOpCode(eOpCode),
73 mrLocale(rLocale)
74 {
75 }
76
77 ::std::auto_ptr<ScCellKeywordTranslator> ScCellKeywordTranslator::spInstance(NULL);
78
lclMatchKeyword(String & rName,const ScCellKeywordHashMap & aMap,OpCode eOpCode=ocNone,const Locale * pLocale=NULL)79 static void lclMatchKeyword(String& rName, const ScCellKeywordHashMap& aMap,
80 OpCode eOpCode = ocNone, const Locale* pLocale = NULL)
81 {
82 ScCellKeywordHashMap::const_iterator itrEnd = aMap.end();
83 ScCellKeywordHashMap::const_iterator itr = aMap.find(rName);
84
85 if ( itr == itrEnd || itr->second.empty() )
86 // No candidate strings exist. Bail out.
87 return;
88
89 if ( eOpCode == ocNone && !pLocale )
90 {
91 // Since no locale nor opcode matching is needed, simply return
92 // the first item on the list.
93 rName = String::CreateFromAscii( itr->second.front().mpName );
94 return;
95 }
96
97 const sal_Char* aBestMatchName = itr->second.front().mpName;
98 LocaleMatch eLocaleMatchLevel = LOCALE_MATCH_NONE;
99 bool bOpCodeMatched = false;
100
101 list<ScCellKeyword>::const_iterator itrListEnd = itr->second.end();
102 list<ScCellKeyword>::const_iterator itrList = itr->second.begin();
103 for ( ; itrList != itrListEnd; ++itrList )
104 {
105 if ( eOpCode != ocNone && pLocale )
106 {
107 if ( itrList->meOpCode == eOpCode )
108 {
109 LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, *pLocale);
110 if ( eLevel == LOCALE_MATCH_ALL )
111 {
112 // Name with matching opcode and locale found.
113 rName = String::CreateFromAscii( itrList->mpName );
114 return;
115 }
116 else if ( eLevel > eLocaleMatchLevel )
117 {
118 // Name with a better matching locale.
119 eLocaleMatchLevel = eLevel;
120 aBestMatchName = itrList->mpName;
121 }
122 else if ( !bOpCodeMatched )
123 // At least the opcode matches.
124 aBestMatchName = itrList->mpName;
125
126 bOpCodeMatched = true;
127 }
128 }
129 else if ( eOpCode != ocNone && !pLocale )
130 {
131 if ( itrList->meOpCode == eOpCode )
132 {
133 // Name with a matching opcode preferred.
134 rName = String::CreateFromAscii( itrList->mpName );
135 return;
136 }
137 }
138 else if ( !eOpCode && pLocale )
139 {
140 LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, *pLocale);
141 if ( eLevel == LOCALE_MATCH_ALL )
142 {
143 // Name with matching locale preferred.
144 rName = String::CreateFromAscii( itrList->mpName );
145 return;
146 }
147 else if ( eLevel > eLocaleMatchLevel )
148 {
149 // Name with a better matching locale.
150 eLocaleMatchLevel = eLevel;
151 aBestMatchName = itrList->mpName;
152 }
153 }
154 }
155
156 // No preferred strings found. Return the best matching name.
157 rName = String::CreateFromAscii(aBestMatchName);
158 }
159
transKeyword(String & rName,const Locale * pLocale,OpCode eOpCode)160 void ScCellKeywordTranslator::transKeyword(String& rName, const Locale* pLocale, OpCode eOpCode)
161 {
162 if ( !spInstance.get() )
163 spInstance.reset( new ScCellKeywordTranslator );
164
165 LanguageType eLang = pLocale ? MsLangId::convertLocaleToLanguageWithFallback(*pLocale) : LANGUAGE_SYSTEM;
166 Sequence<sal_Int32> aOffsets;
167 rName = spInstance->maTransWrapper.transliterate(rName, eLang, 0, rName.Len(), &aOffsets);
168 lclMatchKeyword(rName, spInstance->maStringNameMap, eOpCode, pLocale);
169 }
170
ScCellKeywordTranslator()171 ScCellKeywordTranslator::ScCellKeywordTranslator() :
172 maTransWrapper( ::comphelper::getProcessServiceFactory(),
173 i18n::TransliterationModules_LOWERCASE_UPPERCASE )
174 {
175 init();
176 }
177
~ScCellKeywordTranslator()178 ScCellKeywordTranslator::~ScCellKeywordTranslator()
179 {
180 }
181
182 struct TransItem
183 {
184 const sal_Unicode* from;
185 const sal_Char* to;
186 OpCode func;
187 };
188
init()189 void ScCellKeywordTranslator::init()
190 {
191 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
192
193 // The file below has been autogenerated by sc/workben/celltrans/parse.py.
194 // To add new locale keywords, edit sc/workben/celltrans/keywords_utf16.txt
195 // and re-run the parse.py script.
196 //
197 // All keywords must be uppercase, and the mapping must be from the
198 // localized keyword to the English keyword.
199 //
200 // Make sure that the original keyword file (keywords_utf16.txt) is
201 // encoded in UCS-2/UTF-16!
202
203 #include "cellkeywords.inl"
204 }
205
addToMap(const String & rKey,const sal_Char * pName,const Locale & rLocale,OpCode eOpCode)206 void ScCellKeywordTranslator::addToMap(const String& rKey, const sal_Char* pName, const Locale& rLocale, OpCode eOpCode)
207 {
208 ScCellKeyword aKeyItem( pName, eOpCode, rLocale );
209
210 ScCellKeywordHashMap::iterator itrEnd = maStringNameMap.end();
211 ScCellKeywordHashMap::iterator itr = maStringNameMap.find(rKey);
212
213 if ( itr == itrEnd )
214 {
215 // New keyword.
216 list<ScCellKeyword> aList;
217 aList.push_back(aKeyItem);
218 maStringNameMap.insert( ScCellKeywordHashMap::value_type(rKey, aList) );
219 }
220 else
221 itr->second.push_back(aKeyItem);
222 }
223
addToMap(const TransItem * pItems,const Locale & rLocale)224 void ScCellKeywordTranslator::addToMap(const TransItem* pItems, const Locale& rLocale)
225 {
226 for (sal_uInt16 i = 0; pItems[i].from != NULL; ++i)
227 addToMap(String(pItems[i].from), pItems[i].to, rLocale, pItems[i].func);
228 }
229