From 37e36eca17563b2580abf97f4f46a470387e5b70 Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Mon, 26 Aug 2013 15:35:25 +0200 Subject: Related fdo#68240: Rework langselect to provide better error messages ...and in general removed lots of cruft from that code. Change-Id: Ie673413d8abf5a8ec78c02f4abee2647bdf10a04 --- desktop/source/app/app.cxx | 34 ++- desktop/source/app/langselect.cxx | 525 +++++++++++--------------------------- desktop/source/app/langselect.hxx | 48 +--- 3 files changed, 179 insertions(+), 428 deletions(-) (limited to 'desktop') diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx index a3dd1165904e..28651f9a4a59 100644 --- a/desktop/source/app/app.cxx +++ b/desktop/source/app/app.cxx @@ -36,7 +36,9 @@ #include "exithelper.h" #include "migration.hxx" +#include #include +#include #include #include #include @@ -334,7 +336,7 @@ ResMgr* Desktop::GetDesktopResManager() // Use VCL to get the correct language specific message as we // are in the bootstrap process and not able to get the installed // language!! - OUString aUILocaleString = LanguageSelection::getLanguageString(); + OUString aUILocaleString = langselect::getEmergencyLocale(); LanguageTag aLanguageTag( aUILocaleString); //! ResMgr may modify the Locale for fallback! Desktop::pResMgr = ResMgr::SearchCreateResMgr( "dkt", aLanguageTag); @@ -580,13 +582,16 @@ void Desktop::Init() if ( m_aBootstrapError == BE_OK ) { - // prepare language - if ( !LanguageSelection::prepareLanguage() ) + try { - if ( LanguageSelection::getStatus() == LanguageSelection::LS_STATUS_CANNOT_DETERMINE_LANGUAGE ) + if (!langselect::prepareLocale()) + { SetBootstrapError( BE_LANGUAGE_MISSING, OUString() ); - else - SetBootstrapError( BE_OFFICECONFIG_BROKEN, OUString() ); + } + } + catch (css::uno::Exception & e) + { + SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message ); } } @@ -979,14 +984,15 @@ void Desktop::HandleBootstrapErrors( } else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN ) { - OUString aMessage; - OUStringBuffer aDiagnosticMessage( 100 ); - OUString aErrorMsg; - aErrorMsg = GetMsgString( STR_CONFIG_ERR_ACCESS_GENERAL, - OUString( "A general error occurred while accessing your central configuration." ) ); - aDiagnosticMessage.append( aErrorMsg ); - aMessage = MakeStartupErrorMessage( aDiagnosticMessage.makeStringAndClear() ); - FatalError(aMessage); + OUString msg( + GetMsgString( + STR_CONFIG_ERR_ACCESS_GENERAL, + ("A general error occurred while accessing your central" + " configuration."))); + if (!aErrorMessage.isEmpty()) { + msg += "\n(\"" + aErrorMessage + "\")"; + } + FatalError(MakeStartupErrorMessage(msg)); } else if ( aBootstrapError == BE_USERINSTALL_FAILED ) { diff --git a/desktop/source/app/langselect.cxx b/desktop/source/app/langselect.cxx index 5fc4bc21f30e..19c5edc930ce 100644 --- a/desktop/source/app/langselect.cxx +++ b/desktop/source/app/langselect.cxx @@ -17,424 +17,197 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include "sal/config.h" + +#include "boost/shared_ptr.hpp" +#include "com/sun/star/configuration/theDefaultProvider.hpp" +#include "com/sun/star/container/XNameAccess.hpp" +#include "com/sun/star/lang/XLocalizable.hpp" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/Sequence.hxx" +#include "comphelper/configuration.hxx" +#include "comphelper/processfactory.hxx" +#include "i18nlangtag/lang.h" +#include "i18nlangtag/languagetag.hxx" +#include "i18nlangtag/mslangid.hxx" +#include "officecfg/Office/Linguistic.hxx" +#include "officecfg/Setup.hxx" +#include "officecfg/System.hxx" +#include "rtl/ustring.hxx" +#include "sal/log.hxx" +#include "sal/types.h" +#include "svl/languageoptions.hxx" #include "app.hxx" -#include "langselect.hxx" -#include "cmdlineargs.hxx" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "com/sun/star/util/XFlushable.hpp" -#include -using namespace com::sun::star::uno; -using namespace com::sun::star::lang; -using namespace com::sun::star::container; -using namespace com::sun::star::beans; -using namespace com::sun::star::util; +#include "cmdlineargs.hxx" +#include "langselect.hxx" +namespace desktop { namespace langselect { -namespace desktop { +namespace { -sal_Bool LanguageSelection::bFoundLanguage = sal_False; -OUString LanguageSelection::aFoundLanguage; -LanguageSelection::LanguageSelectionStatus LanguageSelection::m_eStatus = LS_STATUS_OK; +OUString foundLocale; -bool LanguageSelection::prepareLanguage() +OUString getInstalledLocale( + css::uno::Sequence const & installed, OUString const & locale) { - m_eStatus = LS_STATUS_OK; - Reference< XLocalizable > theConfigProvider( - com::sun::star::configuration::theDefaultProvider::get( - comphelper::getProcessComponentContext() ), - UNO_QUERY_THROW ); - - sal_Bool bSuccess = sal_False; - - // #i42730#get the windows 16Bit locale - it should be preferred over the UI language - try - { - Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.System/L10N/", sal_False), UNO_QUERY_THROW); - Any aWin16SysLocale = xProp->getPropertyValue("SystemLocale"); - OUString sWin16SysLocale; - aWin16SysLocale >>= sWin16SysLocale; - if( !sWin16SysLocale.isEmpty()) - setDefaultLanguage(sWin16SysLocale); - } - catch(const Exception&) - { - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; - } - - // #i32939# use system locale to set document default locale - try - { - OUString usLocale; - Reference< XPropertySet > xLocaleProp(getConfigAccess( - "org.openoffice.System/L10N", sal_True), UNO_QUERY_THROW); - xLocaleProp->getPropertyValue("Locale") >>= usLocale; - setDefaultLanguage(usLocale); - } - catch (const Exception&) - { - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; - } - - // get the selected UI language as string - bool bCmdLanguage( false ); - OUString aLocaleString = getUserUILanguage(); - - if ( aLocaleString.isEmpty() ) - { - OUString aEmpty; - - const CommandLineArgs& rCmdLineArgs = Desktop::GetCommandLineArgs(); - aLocaleString = rCmdLineArgs.GetLanguage(); - if (isInstalledLanguage(aLocaleString, sal_False)) - { - bCmdLanguage = true; - bFoundLanguage = true; - aFoundLanguage = aLocaleString; + for (sal_Int32 i = 0; i != installed.getLength(); ++i) { + if (installed[i] == locale) { + return installed[i]; } - else - aLocaleString = aEmpty; } - - // user further fallbacks for the UI language - if ( aLocaleString.isEmpty() ) - aLocaleString = getLanguageString(); - - if ( !aLocaleString.isEmpty() ) - { - try - { - // prepare default config provider by localizing it to the selected - // locale this will ensure localized configuration settings to be - // selected according to the UI language. - LanguageTag aUILanguageTag(aLocaleString); - theConfigProvider->setLocale(aUILanguageTag.getLocale( false)); - - Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.Setup/L10N/", sal_True), UNO_QUERY_THROW); - if ( !bCmdLanguage ) - { - // Store language only - xProp->setPropertyValue("ooLocale", makeAny(aLocaleString)); - Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges(); + // FIXME: It is not very clever to handle the zh-HK -> zh-TW fallback here, + // but right now, there is no place that handles those fallbacks globally: + if (locale == "zh-HK") { + for (sal_Int32 i = 0; i != installed.getLength(); ++i) { + if (installed[i] == "zh-TW") { + return installed[i]; } - - MsLangId::setConfiguredSystemUILanguage( aUILanguageTag.getLanguageType( false) ); - - OUString sLocale; - xProp->getPropertyValue("ooSetupSystemLocale") >>= sLocale; - if ( !sLocale.isEmpty() ) - { - LanguageTag aLocaleLanguageTag(sLocale); - MsLangId::setConfiguredSystemLanguage( aLocaleLanguageTag.getLanguageType( false) ); - } - else - MsLangId::setConfiguredSystemLanguage( MsLangId::getSystemLanguage() ); - - bSuccess = sal_True; } - catch ( const PropertyVetoException& ) - { - // we are not allowed to change this - } - catch (const Exception& e) - { - OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US); - OSL_FAIL(aMsg.getStr()); - + } + for (sal_Int32 i = 0; i != installed.getLength(); ++i) { + if (locale.startsWith(installed[i])) { + return installed[i]; } } - - // #i32939# setting of default document locale - // #i32939# this should not be based on the UI language - setDefaultLanguage(aLocaleString); - - return bSuccess; + return OUString(); } -void LanguageSelection::setDefaultLanguage(const OUString& sLocale) -{ +void setMsLangIdFallback(OUString const & locale) { // #i32939# setting of default document language // See #i42730# for rules for determining source of settings - - // determine script type of locale - LanguageType nLang = LanguageTag::convertToLanguageType(sLocale); - sal_uInt16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage(nLang); - - switch (nScriptType) - { + if (!locale.isEmpty()) { + LanguageType type = LanguageTag::convertToLanguageType(locale); + switch (SvtLanguageOptions::GetScriptTypeOfLanguage(type)) { case SCRIPTTYPE_ASIAN: - MsLangId::setConfiguredAsianFallback( nLang ); + MsLangId::setConfiguredAsianFallback(type); break; case SCRIPTTYPE_COMPLEX: - MsLangId::setConfiguredComplexFallback( nLang ); + MsLangId::setConfiguredComplexFallback(type); break; default: - MsLangId::setConfiguredWesternFallback( nLang ); + MsLangId::setConfiguredWesternFallback(type); break; - } -} - -OUString LanguageSelection::getUserUILanguage() -{ - // check whether the user has selected a specific language - OUString aUserLanguage = getUserLanguage(); - if (!aUserLanguage.isEmpty() ) - { - if (isInstalledLanguage(aUserLanguage)) - { - // all is well - bFoundLanguage = sal_True; - aFoundLanguage = aUserLanguage; - return aFoundLanguage; - } - else - { - // selected language is not/no longer installed - resetUserLanguage(); - } - } - - return aUserLanguage; -} - -OUString LanguageSelection::getLanguageString() -{ - // did we already find a language? - if (bFoundLanguage) - return aFoundLanguage; - - // check whether the user has selected a specific language - OUString aUserLanguage = getUserUILanguage(); - if (!aUserLanguage.isEmpty() ) - return aUserLanguage ; - - // try to use system default - aUserLanguage = getSystemLanguage(); - if (!aUserLanguage.isEmpty() ) - { - if (isInstalledLanguage(aUserLanguage, sal_False)) - { - // great, system default language is available - bFoundLanguage = sal_True; - aFoundLanguage = aUserLanguage; - return aFoundLanguage; } } - // fallback 1: en-US - OUString usFB("en-US"); - if (isInstalledLanguage(usFB)) - { - bFoundLanguage = sal_True; - aFoundLanguage = "en-US"; - return aFoundLanguage; - } - - // fallback didn't work use first installed language - aUserLanguage = getFirstInstalledLanguage(); - - bFoundLanguage = sal_True; - aFoundLanguage = aUserLanguage; - return aFoundLanguage; } -Reference< XNameAccess > LanguageSelection::getConfigAccess(const sal_Char* pPath, sal_Bool bUpdate) -{ - Reference< XNameAccess > xNameAccess; - try{ - OUString sAccessSrvc; - if (bUpdate) - sAccessSrvc = "com.sun.star.configuration.ConfigurationUpdateAccess"; - else - sAccessSrvc = "com.sun.star.configuration.ConfigurationAccess"; - - OUString sConfigURL = OUString::createFromAscii(pPath); - - Reference< XMultiServiceFactory > theConfigProvider( - com::sun::star::configuration::theDefaultProvider::get( - comphelper::getProcessComponentContext() ) ); - - // access the provider - Sequence< Any > theArgs(1); - theArgs[ 0 ] <<= sConfigURL; - xNameAccess = Reference< XNameAccess > ( - theConfigProvider->createInstanceWithArguments( - sAccessSrvc, theArgs ), UNO_QUERY_THROW ); - } catch (const com::sun::star::uno::Exception& e) - { - OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US); - OSL_FAIL(aMsg.getStr()); - } - return xNameAccess; } -Sequence< OUString > LanguageSelection::getInstalledLanguages() -{ - Sequence< OUString > seqLanguages; - Reference< XNameAccess > xAccess = getConfigAccess("org.openoffice.Setup/Office/InstalledLocales", sal_False); - if (!xAccess.is()) return seqLanguages; - seqLanguages = xAccess->getElementNames(); - return seqLanguages; +OUString getEmergencyLocale() { + if (!foundLocale.isEmpty()) { + return foundLocale; + } + try { + css::uno::Sequence inst( + officecfg::Setup::Office::InstalledLocales::get()-> + getElementNames()); + OUString locale( + getInstalledLocale( + inst, + officecfg::Office::Linguistic::General::UILocale::get())); + if (!locale.isEmpty()) { + return locale; + } + locale = getInstalledLocale( + inst, officecfg::System::L10N::UILocale::UILocale::get()); + if (!locale.isEmpty()) { + return locale; + } + locale = getInstalledLocale(inst, "en-US"); + if (!locale.isEmpty()) { + return locale; + } + if (inst.hasElements()) { + return inst[0]; + } + } catch (css::uno::Exception & e) { + SAL_WARN("desktop.app", "ignoring Exception \"" << e.Message << "\""); + } + return OUString(); } -// FIXME -// it's not very clever to handle language fallbacks here, but -// right now, there is no place that handles those fallbacks globally -static Sequence< OUString > _getFallbackLocales(const OUString& aIsoLang) -{ - Sequence< OUString > seqFallbacks; - if ( aIsoLang == "zh-HK" ) { - seqFallbacks = Sequence< OUString >(1); - seqFallbacks[0] = "zh-TW"; - } - return seqFallbacks; -} - -sal_Bool LanguageSelection::isInstalledLanguage(OUString& usLocale, sal_Bool bExact) -{ - sal_Bool bInstalled = sal_False; - Sequence< OUString > seqLanguages = getInstalledLanguages(); - for (sal_Int32 i=0; i seqFallbacks = _getFallbackLocales(usLocale); - for (sal_Int32 j=0; j inst( + officecfg::Setup::Office::InstalledLocales::get()->getElementNames()); + OUString locale(officecfg::Office::Linguistic::General::UILocale::get()); + if (!locale.isEmpty()) { + locale = getInstalledLocale(inst, locale); + if (locale.isEmpty()) { + // Selected language is not/no longer installed: + try { + boost::shared_ptr batch( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Linguistic::General::UILocale::set( + "", batch); + batch->commit(); + } catch (css::uno::Exception & e) { + SAL_WARN( + "desktop.app", + "ignoring Exception \"" << e.Message << "\""); } } } - - if (!bInstalled && !bExact) - { - // no exact match was found, well try to find a substitute - for (sal_Int32 i=0; i seqLanguages = getInstalledLanguages(); - if (seqLanguages.getLength() > 0) - aLanguage = seqLanguages[0]; - return aLanguage; -} - -OUString LanguageSelection::getUserLanguage() -{ - OUString aUserLanguage; - Reference< XNameAccess > xAccess(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_False)); - if (xAccess.is()) - { - try - { - xAccess->getByName("UILocale") >>= aUserLanguage; - } - catch ( NoSuchElementException const & ) - { - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; - return OUString(); - } - catch ( WrappedTargetException const & ) - { - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; - return OUString(); + bool cmdLanguage = false; + if (locale.isEmpty()) { + locale = getInstalledLocale( + inst, Desktop::GetCommandLineArgs().GetLanguage()); + if (!locale.isEmpty()) { + cmdLanguage = true; } } - return aUserLanguage; -} - -OUString LanguageSelection::getSystemLanguage() -{ - OUString aUserLanguage; - Reference< XNameAccess > xAccess(getConfigAccess("org.openoffice.System/L10N", sal_False)); - if (xAccess.is()) - { - try - { - xAccess->getByName("UILocale") >>= aUserLanguage; - } - catch ( NoSuchElementException const & ) - { - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; - return OUString(); - } - catch ( WrappedTargetException const & ) - { - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; - return OUString(); - } + if (locale.isEmpty()) { + locale = getInstalledLocale( + inst, officecfg::System::L10N::UILocale::UILocale::get()); } - return aUserLanguage; -} - - -void LanguageSelection::resetUserLanguage() -{ - try - { - Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_True), UNO_QUERY_THROW); - xProp->setPropertyValue("UILocale", makeAny(OUString())); - Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges(); + if (locale.isEmpty()) { + locale = getInstalledLocale(inst, "en-US"); } - catch ( const PropertyVetoException& ) - { - // we are not allowed to change this + if (locale.isEmpty() && inst.hasElements()) { + locale = inst[0]; } - catch (const Exception& e) - { - OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US); - OSL_FAIL(aMsg.getStr()); - m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN; + if (locale.isEmpty()) { + return false; } + LanguageTag tag(locale); + // Prepare default config provider by localizing it to the selected + // locale this will ensure localized configuration settings to be + // selected according to the UI language: + css::uno::Reference( + com::sun::star::configuration::theDefaultProvider::get( + comphelper::getProcessComponentContext()), + css::uno::UNO_QUERY_THROW)->setLocale(tag.getLocale(false)); + if (!cmdLanguage) { + try { + boost::shared_ptr batch( + comphelper::ConfigurationChanges::create()); + officecfg::Setup::L10N::ooLocale::set(locale, batch); + batch->commit(); + } catch (css::uno::Exception & e) { + SAL_WARN( + "desktop.app", "ignoring Exception \"" << e.Message << "\""); + } + } + MsLangId::setConfiguredSystemUILanguage(tag.getLanguageType(false)); + OUString setupSysLoc(officecfg::Setup::L10N::ooSetupSystemLocale::get()); + MsLangId::setConfiguredSystemLanguage( + setupSysLoc.isEmpty() + ? MsLangId::getSystemLanguage() + : LanguageTag(setupSysLoc).getLanguageType(false)); + // #i32939# setting of default document locale + // #i32939# this should not be based on the UI language + setMsLangIdFallback(locale); + foundLocale = locale; + return true; } -LanguageSelection::LanguageSelectionStatus LanguageSelection::getStatus() -{ - return m_eStatus; -} - -} // namespace desktop +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/app/langselect.hxx b/desktop/source/app/langselect.hxx index f84566c6c96b..517e49f50b72 100644 --- a/desktop/source/app/langselect.hxx +++ b/desktop/source/app/langselect.hxx @@ -17,49 +17,21 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include -#include -#include -#include -#include -#include -#include -#include +#ifndef INCLUDED_DESKTOP_SOURCE_APP_LANGSELECT_HXX +#define INCLUDED_DESKTOP_SOURCE_APP_LANGSELECT_HXX -namespace desktop -{ +#include "sal/config.h" -class LanguageSelection -{ -public: - enum LanguageSelectionStatus - { - LS_STATUS_OK, - LS_STATUS_CANNOT_DETERMINE_LANGUAGE, - LS_STATUS_CONFIGURATIONACCESS_BROKEN - }; +#include "rtl/ustring.hxx" - static OUString getLanguageString(); - static bool prepareLanguage(); - static LanguageSelectionStatus getStatus(); +namespace desktop { namespace langselect { -private: - static OUString aFoundLanguage; - static sal_Bool bFoundLanguage; - static LanguageSelectionStatus m_eStatus; +OUString getEmergencyLocale(); - static com::sun::star::uno::Reference< com::sun::star::container::XNameAccess > - getConfigAccess(const sal_Char* pPath, sal_Bool bUpdate=sal_False); - static com::sun::star::uno::Sequence< OUString > getInstalledLanguages(); - static sal_Bool isInstalledLanguage(OUString& usLocale, sal_Bool bExact=sal_False); - static OUString getFirstInstalledLanguage(); - static OUString getUserUILanguage(); - static OUString getUserLanguage(); - static OUString getSystemLanguage(); - static void resetUserLanguage(); - static void setDefaultLanguage(const OUString&); -}; +bool prepareLocale(); -} //namespace desktop +} } + +#endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit