blob: 4a6faa33223fde006d9ef6c972d4dbf9343c3eeb [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
#include "cellkeytranslator.hxx"
#include "comphelper/processfactory.hxx"
#include "i18npool/mslangid.hxx"
#include "i18npool/lang.h"
#include "rtl/ustring.hxx"
#include <com/sun/star/i18n/TransliterationModules.hpp>
using ::com::sun::star::lang::Locale;
using ::com::sun::star::uno::Sequence;
using ::std::list;
using ::std::hash_map;
using ::rtl::OUString;
using namespace ::com::sun::star;
enum LocaleMatch
{
LOCALE_MATCH_NONE = 0,
LOCALE_MATCH_LANG,
LOCALE_MATCH_LANG_COUNTRY,
LOCALE_MATCH_ALL
};
static LocaleMatch lclLocaleCompare(const Locale& rLocale1, const Locale& rLocale2)
{
LocaleMatch eMatchLevel = LOCALE_MATCH_NONE;
if ( !rLocale1.Language.compareTo(rLocale1.Language) )
eMatchLevel = LOCALE_MATCH_LANG;
else
return eMatchLevel;
if ( !rLocale1.Country.compareTo(rLocale2.Country) )
eMatchLevel = LOCALE_MATCH_LANG_COUNTRY;
else
return eMatchLevel;
if ( !rLocale1.Variant.compareTo(rLocale2.Variant) )
eMatchLevel = LOCALE_MATCH_ALL;
return eMatchLevel;
}
ScCellKeyword::ScCellKeyword(const sal_Char* pName, OpCode eOpCode, const Locale& rLocale) :
mpName(pName),
meOpCode(eOpCode),
mrLocale(rLocale)
{
}
::std::auto_ptr<ScCellKeywordTranslator> ScCellKeywordTranslator::spInstance(NULL);
static void lclMatchKeyword(String& rName, const ScCellKeywordHashMap& aMap,
OpCode eOpCode = ocNone, const Locale* pLocale = NULL)
{
ScCellKeywordHashMap::const_iterator itrEnd = aMap.end();
ScCellKeywordHashMap::const_iterator itr = aMap.find(rName);
if ( itr == itrEnd || itr->second.empty() )
// No candidate strings exist. Bail out.
return;
if ( eOpCode == ocNone && !pLocale )
{
// Since no locale nor opcode matching is needed, simply return
// the first item on the list.
rName = String::CreateFromAscii( itr->second.front().mpName );
return;
}
const sal_Char* aBestMatchName = itr->second.front().mpName;
LocaleMatch eLocaleMatchLevel = LOCALE_MATCH_NONE;
bool bOpCodeMatched = false;
list<ScCellKeyword>::const_iterator itrListEnd = itr->second.end();
list<ScCellKeyword>::const_iterator itrList = itr->second.begin();
for ( ; itrList != itrListEnd; ++itrList )
{
if ( eOpCode != ocNone && pLocale )
{
if ( itrList->meOpCode == eOpCode )
{
LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, *pLocale);
if ( eLevel == LOCALE_MATCH_ALL )
{
// Name with matching opcode and locale found.
rName = String::CreateFromAscii( itrList->mpName );
return;
}
else if ( eLevel > eLocaleMatchLevel )
{
// Name with a better matching locale.
eLocaleMatchLevel = eLevel;
aBestMatchName = itrList->mpName;
}
else if ( !bOpCodeMatched )
// At least the opcode matches.
aBestMatchName = itrList->mpName;
bOpCodeMatched = true;
}
}
else if ( eOpCode != ocNone && !pLocale )
{
if ( itrList->meOpCode == eOpCode )
{
// Name with a matching opcode preferred.
rName = String::CreateFromAscii( itrList->mpName );
return;
}
}
else if ( !eOpCode && pLocale )
{
LocaleMatch eLevel = lclLocaleCompare(itrList->mrLocale, *pLocale);
if ( eLevel == LOCALE_MATCH_ALL )
{
// Name with matching locale preferred.
rName = String::CreateFromAscii( itrList->mpName );
return;
}
else if ( eLevel > eLocaleMatchLevel )
{
// Name with a better matching locale.
eLocaleMatchLevel = eLevel;
aBestMatchName = itrList->mpName;
}
}
}
// No preferred strings found. Return the best matching name.
rName = String::CreateFromAscii(aBestMatchName);
}
void ScCellKeywordTranslator::transKeyword(String& rName, const Locale* pLocale, OpCode eOpCode)
{
if ( !spInstance.get() )
spInstance.reset( new ScCellKeywordTranslator );
LanguageType eLang = pLocale ? MsLangId::convertLocaleToLanguageWithFallback(*pLocale) : LANGUAGE_SYSTEM;
Sequence<sal_Int32> aOffsets;
rName = spInstance->maTransWrapper.transliterate(rName, eLang, 0, rName.Len(), &aOffsets);
lclMatchKeyword(rName, spInstance->maStringNameMap, eOpCode, pLocale);
}
ScCellKeywordTranslator::ScCellKeywordTranslator() :
maTransWrapper( ::comphelper::getProcessServiceFactory(),
i18n::TransliterationModules_LOWERCASE_UPPERCASE )
{
init();
}
ScCellKeywordTranslator::~ScCellKeywordTranslator()
{
}
struct TransItem
{
const sal_Unicode* from;
const sal_Char* to;
OpCode func;
};
void ScCellKeywordTranslator::init()
{
::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
// The file below has been autogenerated by sc/workben/celltrans/parse.py.
// To add new locale keywords, edit sc/workben/celltrans/keywords_utf16.txt
// and re-run the parse.py script.
//
// All keywords must be uppercase, and the mapping must be from the
// localized keyword to the English keyword.
//
// Make sure that the original keyword file (keywords_utf16.txt) is
// encoded in UCS-2/UTF-16!
#include "cellkeywords.inl"
}
void ScCellKeywordTranslator::addToMap(const String& rKey, const sal_Char* pName, const Locale& rLocale, OpCode eOpCode)
{
ScCellKeyword aKeyItem( pName, eOpCode, rLocale );
ScCellKeywordHashMap::iterator itrEnd = maStringNameMap.end();
ScCellKeywordHashMap::iterator itr = maStringNameMap.find(rKey);
if ( itr == itrEnd )
{
// New keyword.
list<ScCellKeyword> aList;
aList.push_back(aKeyItem);
maStringNameMap.insert( ScCellKeywordHashMap::value_type(rKey, aList) );
}
else
itr->second.push_back(aKeyItem);
}
void ScCellKeywordTranslator::addToMap(const TransItem* pItems, const Locale& rLocale)
{
for (sal_uInt16 i = 0; pItems[i].from != NULL; ++i)
addToMap(String(pItems[i].from), pItems[i].to, rLocale, pItems[i].func);
}