diff options
Diffstat (limited to 'configmgr/source/xml/matchlocale.cxx')
-rw-r--r-- | configmgr/source/xml/matchlocale.cxx | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/configmgr/source/xml/matchlocale.cxx b/configmgr/source/xml/matchlocale.cxx new file mode 100644 index 000000000000..b0cf48092bb6 --- /dev/null +++ b/configmgr/source/xml/matchlocale.cxx @@ -0,0 +1,387 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: matchlocale.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_configmgr.hxx" +#include "matchlocale.hxx" + +#include <rtl/ustrbuf.hxx> + +#include <algorithm> +#include <iterator> + +namespace configmgr +{ +// ----------------------------------------------------------------------------- + namespace localehelper + { +// ----------------------------------------------------------------------------- + namespace uno = ::com::sun::star::uno; + namespace lang = ::com::sun::star::lang; + +#define ARRAYSIZE( arr ) (sizeof(arr) / sizeof 0[arr] ) +// ----------------------------------------------------------------------------- + struct StaticLocale + { + char const * aLanguage; + char const * aCountry; + }; + + char const * const c_sAnyLanguage = "*"; // exported ! + char const * const c_sDefLanguage = "x-default"; // exported ! + + char const * const c_sNoCountry = ""; + + char const * const c_sLanguageEnglish = "en"; + char const * const c_sCountryUS = "US"; + + StaticLocale const c_aFallbackLocales[] = + { + { c_sLanguageEnglish, c_sCountryUS }, // english [cannot make 'en' better than 'en-US' :-(] + { c_sAnyLanguage, c_sNoCountry } // just take the first you find + }; + std::vector< com::sun::star::lang::Locale >::size_type const c_nFallbackLocales = ARRAYSIZE(c_aFallbackLocales); + +// ----------------------------------------------------------------------------- + bool isAnyLanguage(rtl::OUString const & _sLanguage) + { + return !!_sLanguage.equalsAscii(c_sAnyLanguage); + } + +// ----------------------------------------------------------------------------- + bool isDefaultLanguage(rtl::OUString const & _sLanguage) + { + return !!_sLanguage.equalsAscii(c_sDefLanguage); + } + +// ----------------------------------------------------------------------------- + rtl::OUString getAnyLanguage() + { + return rtl::OUString::createFromAscii( c_sAnyLanguage ); + } + +// ----------------------------------------------------------------------------- + rtl::OUString getDefaultLanguage() + { + return rtl::OUString::createFromAscii( c_sDefLanguage ); + } + +// ----------------------------------------------------------------------------- + com::sun::star::lang::Locale getAnyLocale() + { + return com::sun::star::lang::Locale( getAnyLanguage(), rtl::OUString(), rtl::OUString() ); + } + +// ----------------------------------------------------------------------------- + com::sun::star::lang::Locale getDefaultLocale() + { + return com::sun::star::lang::Locale( getDefaultLanguage(), rtl::OUString(), rtl::OUString() ); + } + +// ----------------------------------------------------------------------------- + static inline sal_Int32 countrySeparatorPos(rtl::OUString const& aLocaleName_) + { + sal_Int32 pos = aLocaleName_.indexOf('-'); + if (pos == 1) // allow for x-LL or i-LL + pos = aLocaleName_.indexOf('-',pos+1); + + if (pos < 0) + pos = aLocaleName_.indexOf('_'); + + return pos; + } + // ------------------------------------------------------------------------- + static inline sal_Int32 countryLength(rtl::OUString const& aLocaleName_, sal_Int32 nCountryPos) + { + sal_Int32 pos1 = aLocaleName_.indexOf('.',nCountryPos); + sal_Int32 pos2 = aLocaleName_.indexOf('_',nCountryPos); + + if (pos1 < 0) pos1 = aLocaleName_.getLength(); + + if (pos2 < 0 || pos1 < pos2) + return pos1 - nCountryPos; + + else + return pos2 - nCountryPos; + } + // ------------------------------------------------------------------------- + static inline void splitLocaleString(rtl::OUString const& aLocaleName_, rtl::OUString& rLanguage_, rtl::OUString& rCountry_) + { + sal_Int32 nCountryPos = countrySeparatorPos(aLocaleName_); + if (nCountryPos >= 0) + { + rLanguage_ = aLocaleName_.copy(0,nCountryPos).toAsciiLowerCase(); + + ++nCountryPos; // advance past separator + sal_Int32 nCountryLength = countryLength(aLocaleName_, nCountryPos); + + rCountry_ = aLocaleName_.copy(nCountryPos,nCountryLength).toAsciiUpperCase(); + } + else + { + rLanguage_ = aLocaleName_.toAsciiLowerCase(); + rCountry_ = rtl::OUString(); + } + } +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// conversion helpers +com::sun::star::lang::Locale makeLocale(rtl::OUString const& sLocaleName_) +{ + com::sun::star::lang::Locale aResult; + splitLocaleString(sLocaleName_, aResult.Language, aResult.Country); + return aResult; +} +rtl::OUString makeIsoLocale(com::sun::star::lang::Locale const& aUnoLocale_) +{ + rtl::OUStringBuffer aResult(aUnoLocale_.Language.toAsciiLowerCase()); + if (aUnoLocale_.Country.getLength()) + { + aResult.append( sal_Unicode('-') ).append(aUnoLocale_.Country.toAsciiUpperCase()); + } + return aResult.makeStringAndClear(); +} +static +com::sun::star::lang::Locale makeLocale(StaticLocale const& aConstLocale_) +{ + com::sun::star::lang::Locale aResult; + aResult.Language = rtl::OUString::createFromAscii(aConstLocale_.aLanguage); + aResult.Country = rtl::OUString::createFromAscii(aConstLocale_.aCountry); + return aResult; +} +// ----------------------------------------------------------------------------- +template <class T> +inline +void addLocaleSeq_impl(T const* first, T const* last, std::vector< com::sun::star::lang::Locale >& rSeq) +{ + com::sun::star::lang::Locale (* const xlate)(T const&) = &makeLocale; + + std::transform(first, last, std::back_inserter(rSeq), xlate); +} +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +template <class T> +inline +std::vector< com::sun::star::lang::Locale > makeLocaleSeq_impl(uno::Sequence< T > const& aLocales_) +{ + sal_Int32 const nLocaleCount = aLocales_.getLength(); + + T const* pLocaleBegin = aLocales_.getConstArray(); + + std::vector< com::sun::star::lang::Locale > aResult; + aResult.reserve( nLocaleCount + c_nFallbackLocales ); // make room for fallback stuff as well + + addLocaleSeq_impl(pLocaleBegin, pLocaleBegin + nLocaleCount, aResult); + + return aResult; +} +// ----------------------------------------------------------------------------- + +void addFallbackLocales(std::vector< com::sun::star::lang::Locale >& aTargetList_) +{ + addLocaleSeq_impl(c_aFallbackLocales, c_aFallbackLocales + c_nFallbackLocales, aTargetList_); +} +// ----------------------------------------------------------------------------- + +std::vector< com::sun::star::lang::Locale > makeLocaleSequence(uno::Sequence<rtl::OUString> const& sLocaleNames_) +{ + return makeLocaleSeq_impl(sLocaleNames_); +} +// ----------------------------------------------------------------------------- + +uno::Sequence<rtl::OUString> makeIsoSequence(std::vector< com::sun::star::lang::Locale > const& aLocales_) +{ + std::vector< com::sun::star::lang::Locale >::size_type const nLocaleCount = aLocales_.size(); + sal_Int32 const nSeqSize = sal_Int32(nLocaleCount); + OSL_ASSERT( nSeqSize >= 0 && sal_uInt32(nSeqSize) == nLocaleCount ); + + uno::Sequence<rtl::OUString> aResult(nSeqSize); + std::transform(aLocales_.begin(), aLocales_.end(), aResult.getArray(), &makeIsoLocale); + + return aResult; +} +// ----------------------------------------------------------------------------- +bool designatesAllLocales(com::sun::star::lang::Locale const& aLocale_) +{ + return aLocale_.Language.equalsAscii(c_sAnyLanguage); +} +bool designatesAllLocales(std::vector< com::sun::star::lang::Locale > const& aLocales_) +{ + return aLocales_.size() <= 1 && + (aLocales_.size() == 0 || designatesAllLocales(aLocales_)); +} +// ----------------------------------------------------------------------------- + +MatchQuality match(com::sun::star::lang::Locale const& aLocale_, com::sun::star::lang::Locale const& aTarget_) +{ + // check language + if (!aLocale_.Language.equals(aTarget_.Language)) + { + // can we accept any language + if (aTarget_.Language.equalsAscii(c_sAnyLanguage)) + return MATCH_LANGUAGE; + + return MISMATCH; + } + + // check for exact match + else if (aLocale_.Country.equals(aTarget_.Country)) + return MATCH_LOCALE; + + // check for plain language + else if (aLocale_.Country.getLength() == 0) + return MATCH_LANGUAGE_PLAIN; + + // so we are left with the wrong country + else + return MATCH_LANGUAGE; +} + +// ----------------------------------------------------------------------------- + +/// check the given position and quality, if they are an improvement +bool MatchResult::improve(std::vector< com::sun::star::lang::Locale >::size_type nPos_, MatchQuality eQuality_) +{ + // is this a match at all ? + if (eQuality_ == MISMATCH) + return false; + + // is the position worse ? + if (nPos_ > m_nPos ) + return false; + + // is this just a non-positive quality change ? + if (nPos_ == m_nPos && eQuality_ <= m_eQuality) + return false; + + // Improvement found + m_nPos = nPos_; + m_eQuality = eQuality_; + + return true; +} + +// ----------------------------------------------------------------------------- + +bool isMatch(com::sun::star::lang::Locale const& aLocale_, std::vector< com::sun::star::lang::Locale > const& aTarget_, MatchQuality eRequiredQuality_) +{ + std::vector< com::sun::star::lang::Locale >::size_type const nEnd = aTarget_.size(); + + for (std::vector< com::sun::star::lang::Locale >::size_type nPos = 0; nPos < nEnd; ++nPos) + { + MatchQuality eQuality = match(aLocale_, aTarget_[nPos]); + if (eQuality >= eRequiredQuality_) + { + return true; + } + } + return false; +} +// ----------------------------------------------------------------------------- + +static +inline +std::vector< com::sun::star::lang::Locale >::size_type getSearchLimitPosition(MatchResult const& aPrevMatch_,std::vector< com::sun::star::lang::Locale > const& aTarget_) +{ + std::vector< com::sun::star::lang::Locale >::size_type nSize = aTarget_.size(); + + if (aPrevMatch_.isMatch()) + { + std::vector< com::sun::star::lang::Locale >::size_type nMatchPos = aPrevMatch_.position(); + + OSL_ENSURE(nMatchPos < nSize,"localehelper::getSearchLimitPosition: ERROR - previous position is out-of-bounds"); + + if (nMatchPos < nSize) + { + return nMatchPos + 1; + } + } + return nSize; +} +// ----------------------------------------------------------------------------- + +bool improveMatch(MatchResult& rMatch_, com::sun::star::lang::Locale const& aLocale_, std::vector< com::sun::star::lang::Locale > const& aTarget_) +{ + std::vector< com::sun::star::lang::Locale >::size_type const nEnd = getSearchLimitPosition(rMatch_,aTarget_); + + for (std::vector< com::sun::star::lang::Locale >::size_type nPos = 0; nPos < nEnd; ++nPos) + { + if (rMatch_.improve(nPos, match(aLocale_, aTarget_[nPos]))) + { + return true; + } + } + return false; +} +// ----------------------------------------------------------------------------- + + +// ----------------------------------------------------------------------------- +// class FindBestLocale +// ----------------------------------------------------------------------------- + +inline +void FindBestLocale::implSetTarget(std::vector< com::sun::star::lang::Locale > const& aTarget_) +{ + m_aTarget = aTarget_; + addFallbackLocales(m_aTarget); +} +// ----------------------------------------------------------------------------- + +FindBestLocale::FindBestLocale(com::sun::star::lang::Locale const& aTarget_) +{ + std::vector< com::sun::star::lang::Locale > aSeq(1,aTarget_); + implSetTarget( aSeq ); +} +// ----------------------------------------------------------------------------- + +bool FindBestLocale::accept(com::sun::star::lang::Locale const& aLocale_) +{ + return improveMatch(m_aResult, aLocale_, m_aTarget); +} +// ----------------------------------------------------------------------------- + +void FindBestLocale::reset(bool bNeedLocale_) +{ + if (bNeedLocale_) + m_aResult.reset(); + + else // mark as best match already (no improvement possible) + m_aResult = m_aResult.best(); +} +// ----------------------------------------------------------------------------- + + } // namespace locale helper +// ----------------------------------------------------------------------------- + +} // namespace + + |