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