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 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 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 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 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 171 ScCellKeywordTranslator::ScCellKeywordTranslator() : 172 maTransWrapper( ::comphelper::getProcessServiceFactory(), 173 i18n::TransliterationModules_LOWERCASE_UPPERCASE ) 174 { 175 init(); 176 } 177 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 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 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 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