diff --git a/include/wx/private/uilocale.h b/include/wx/private/uilocale.h index c5443e6b4b..9df8bb6d42 100644 --- a/include/wx/private/uilocale.h +++ b/include/wx/private/uilocale.h @@ -13,6 +13,9 @@ #include "wx/localedefs.h" #include "wx/string.h" +// Function returning hard-coded values for the "C" locale. +wxString wxGetStdCLocaleInfo(wxLocaleInfo index, wxLocaleCategory cat); + // ---------------------------------------------------------------------------- // wxUILocaleImpl provides the implementation of public wxUILocale functions // ---------------------------------------------------------------------------- @@ -53,9 +56,9 @@ public: // Use this locale in the UI. // // This is not implemented for all platforms, notably not for Mac where the - // UI locale is determined at application startup, and so this function - // always returns false there. - virtual bool Use() = 0; + // UI locale is determined at application startup, but we can't do anything + // about it anyhow, so we don't even bother returning an error code from it. + virtual void Use() = 0; // Functions corresponding to wxUILocale ones. virtual wxString GetName() const = 0; diff --git a/include/wx/uilocale.h b/include/wx/uilocale.h index 238075805c..216619068b 100644 --- a/include/wx/uilocale.h +++ b/include/wx/uilocale.h @@ -65,7 +65,7 @@ public: private: // Default ctor is private and exists only for implementation reasons, - // wxUILocale objects can't be invalid. + // creating invalid wxUILocale objects doesn't make much sense. wxUILocale() : m_impl(NULL) { } // Used by UseDefault(). diff --git a/src/common/uilocale.cpp b/src/common/uilocale.cpp index 0084d7058b..ef360fb42e 100644 --- a/src/common/uilocale.cpp +++ b/src/common/uilocale.cpp @@ -86,12 +86,7 @@ bool wxUILocale::UseLanguage(const wxLanguageInfo& info) if ( !impl ) return false; - if ( !impl->Use() ) - { - delete impl; - return false; - } - + impl->Use(); ms_current.SetImpl(impl); return true; @@ -112,8 +107,6 @@ const wxUILocale& wxUILocale::GetCurrent() wxUILocale::wxUILocale(const wxLocaleIdent& localeId) { m_impl = wxUILocaleImpl::CreateForLocale(localeId); - if ( !m_impl ) - m_impl = wxUILocaleImpl::CreateStdC(); } void wxUILocale::SetImpl(wxUILocaleImpl* impl) @@ -125,11 +118,17 @@ void wxUILocale::SetImpl(wxUILocaleImpl* impl) wxString wxUILocale::GetName() const { + if ( !m_impl ) + return wxString(); + return m_impl->GetName(); } wxString wxUILocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const { + if ( !m_impl ) + return wxGetStdCLocaleInfo(index, cat); + return m_impl->GetInfo(index, cat); } @@ -138,6 +137,17 @@ wxUILocale::CompareStrings(const wxString& lhs, const wxString& rhs, int flags) const { + if ( !m_impl ) + { + const int rc = flags & wxCompare_CaseInsensitive ? lhs.CmpNoCase(rhs) + : lhs.Cmp(rhs); + if ( rc < 0 ) + return -1; + if ( rc > 0 ) + return 1; + return 0; + } + return m_impl->CompareStrings(lhs, rhs, flags); } diff --git a/src/msw/uilocale.cpp b/src/msw/uilocale.cpp index a023c01bab..409850566f 100644 --- a/src/msw/uilocale.cpp +++ b/src/msw/uilocale.cpp @@ -114,12 +114,9 @@ public: { } - bool Use() wxOVERRIDE + void Use() wxOVERRIDE { wxUseLCID(m_lcid); - - // As long as we use a valid LCID (and we always do), it shouldn't fail. - return true; } wxString GetName() const wxOVERRIDE @@ -200,18 +197,31 @@ public: return s_canUse == 1; } - // Note that "name" can be NULL here (LOCALE_NAME_USER_DEFAULT). - explicit wxUILocaleImplName(const wchar_t* name) - : m_name(name ? wxStrdup(name) : NULL) + // Create object corresponding to the default user locale. + static wxUILocaleImplName* CreateDefault() { + return new wxUILocaleImplName(LOCALE_NAME_USER_DEFAULT); } + // Create object corresponding to the given locale, return NULL if not + // supported. + static wxUILocaleImplName* Create(const wchar_t* name) + { + // Getting the locale name seems to be the simplest way to see if it's + // really supported: unknown locale result in an error here. + if ( !ms_GetLocaleInfoEx(name, LOCALE_SNAME, NULL, 0) ) + return NULL; + + return new wxUILocaleImplName(name); + } + + ~wxUILocaleImplName() wxOVERRIDE { free(const_cast(m_name)); } - bool Use() wxOVERRIDE + void Use() wxOVERRIDE { // Construct a double NUL-terminated buffer. wchar_t buf[256]; @@ -224,9 +234,7 @@ public: ULONG num = 1; if ( !ms_SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, buf, &num) ) - return false; - - return true; + wxLogLastError(wxT("SetThreadPreferredUILanguages")); } wxString GetName() const wxOVERRIDE @@ -331,6 +339,15 @@ private: LPARAM); static CompareStringEx_t ms_CompareStringEx; + + // Ctor is private, use CreateDefault() or Create() instead. + // + // Note that "name" can be NULL here (LOCALE_NAME_USER_DEFAULT). + explicit wxUILocaleImplName(const wchar_t* name) + : m_name(name ? wxStrdup(name) : NULL) + { + } + wxString DoGetInfo(LCTYPE lctype) const { wchar_t buf[256]; @@ -366,7 +383,7 @@ wxUILocaleImpl* wxUILocaleImpl::CreateStdC() return new wxUILocaleImplLCID(lcid); } - return new wxUILocaleImplName(L"en-US"); + return wxUILocaleImplName::Create(L"en-US"); } /* static */ @@ -375,7 +392,7 @@ wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() if ( !wxUILocaleImplName::CanUse() ) return new wxUILocaleImplLCID(LOCALE_USER_DEFAULT); - return new wxUILocaleImplName(LOCALE_NAME_USER_DEFAULT); + return wxUILocaleImplName::CreateDefault(); } /* static */ @@ -403,7 +420,7 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLocale(const wxLocaleIdent& locId) return NULL; } - return new wxUILocaleImplName(locId.GetName()); + return wxUILocaleImplName::Create(locId.GetName().wc_str()); } #endif // wxUSE_INTL diff --git a/src/osx/core/uilocale.mm b/src/osx/core/uilocale.mm index 71dfab41af..501ffa0b6e 100644 --- a/src/osx/core/uilocale.mm +++ b/src/osx/core/uilocale.mm @@ -88,7 +88,7 @@ public: return new wxUILocaleImplCF(cfloc); } - bool Use() wxOVERRIDE; + void Use() wxOVERRIDE; wxString GetName() const wxOVERRIDE; wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const wxOVERRIDE; int CompareStrings(const wxString& lhs, const wxString& rhs, @@ -106,11 +106,11 @@ private: // implementation // ============================================================================ -bool +void wxUILocaleImplCF::Use() { - // There is no way to start using a locale other than default. - return false; + // There is no way to start using a locale other than default, so there is + // nothing to do here. } wxString diff --git a/src/unix/uilocale.cpp b/src/unix/uilocale.cpp index e7403d6173..a470f2a3c6 100644 --- a/src/unix/uilocale.cpp +++ b/src/unix/uilocale.cpp @@ -41,10 +41,16 @@ namespace class wxUILocaleImplUnix : public wxUILocaleImpl { public: - explicit wxUILocaleImplUnix(wxLocaleIdent locId); + // If "loc" is non-NULL, this object takes ownership of it and will free it. + explicit wxUILocaleImplUnix(wxLocaleIdent locId +#ifdef HAVE_LOCALE_T + , locale_t loc = NULL +#endif // HAVE_LOCALE_T + ); ~wxUILocaleImplUnix() wxOVERRIDE; - bool Use() wxOVERRIDE; + void Use() wxOVERRIDE; + wxString GetName() const wxOVERRIDE; wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const wxOVERRIDE; int CompareStrings(const wxString& lhs, const wxString& rhs, @@ -56,12 +62,6 @@ private: const char* GetLangInfo(nl_item item) const; #endif // HAVE_LANGINFO_H -#ifdef HAVE_LOCALE_T - // On success, set m_locale and change m_locId to the given one. - // Otherwise just return false. - bool TryCreateLocale(const wxLocaleIdent& locId); -#endif // HAVE_LOCALE_T - wxLocaleIdent m_locId; #ifdef HAVE_LOCALE_T @@ -72,6 +72,16 @@ private: wxDECLARE_NO_COPY_CLASS(wxUILocaleImplUnix); }; +#ifdef HAVE_LOCALE_T + +// Simple wrapper around newlocale(). +inline locale_t TryCreateLocale(const wxLocaleIdent& locId) +{ + return newlocale(LC_ALL_MASK, locId.GetName().mb_str(), NULL); +} + +#endif // HAVE_LOCALE_T + } // anonymous namespace // ============================================================================ @@ -162,56 +172,16 @@ const char *wxSetlocaleTryAll(int c, const wxString& lc) // wxUILocale implementation for Unix // ---------------------------------------------------------------------------- +wxUILocaleImplUnix::wxUILocaleImplUnix(wxLocaleIdent locId #ifdef HAVE_LOCALE_T - -bool -wxUILocaleImplUnix::TryCreateLocale(const wxLocaleIdent& locId) -{ - m_locale = newlocale(LC_ALL_MASK, locId.GetName(), NULL); - if ( !m_locale ) - return false; - - m_locId = locId; - return true; -} - + , locale_t loc #endif // HAVE_LOCALE_T - -wxUILocaleImplUnix::wxUILocaleImplUnix(wxLocaleIdent locId) + ) : m_locId(locId) -{ #ifdef HAVE_LOCALE_T - if ( !TryCreateLocale(locId) ) - { - // Try to find a variant of this locale available on this system: first - // of all, using just the language, without the territory, typically - // does _not_ work under Linux, so try adding one if we don't have it. - if ( locId.GetRegion().empty() ) - { - const wxLanguageInfo* const info = - wxLocale::FindLanguageInfo(locId.GetLanguage()); - if ( info ) - { - wxString region = info->CanonicalName.AfterFirst('_'); - if ( !region.empty() ) - { - // We never have encoding in our canonical names, but we - // can have modifiers, so get rid of them if necessary. - region = region.BeforeFirst('@'); - - TryCreateLocale(locId.Region(region)); - } - } - } - - // And sometimes the locale without encoding is not available, but one - // with UTF-8 encoding is, so try this too. - if ( !m_locale && locId.GetCharset().empty() ) - { - TryCreateLocale(locId.Charset("UTF-8")); - } - } + , m_locale(loc) #endif // HAVE_LOCALE_T +{ } wxUILocaleImplUnix::~wxUILocaleImplUnix() @@ -222,13 +192,13 @@ wxUILocaleImplUnix::~wxUILocaleImplUnix() #endif // HAVE_LOCALE_T } -bool +void wxUILocaleImplUnix::Use() { if ( m_locId.IsDefault() ) { // This is the default locale, it is already in use. - return true; + return; } const wxString& shortName = m_locId.GetName(); @@ -250,11 +220,9 @@ wxUILocaleImplUnix::Use() else if ( langOnly == wxS("nn") ) localeAlt = wxS("no_NY"); - if ( localeAlt.empty() || !wxSetlocaleTryAll(LC_ALL, localeAlt) ) - return false; + if ( !localeAlt.empty() ) + wxSetlocaleTryAll(LC_ALL, localeAlt); } - - return true; } wxString @@ -363,9 +331,53 @@ wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() } /* static */ -wxUILocaleImpl* wxUILocaleImpl::CreateForLocale(const wxLocaleIdent& locId) +wxUILocaleImpl* wxUILocaleImpl::CreateForLocale(const wxLocaleIdent& locIdOrig) { - return new wxUILocaleImplUnix(locId); +#ifdef HAVE_LOCALE_T + // Make a copy of it because it can be modified below. + wxLocaleIdent locId = locIdOrig; + + locale_t loc = TryCreateLocale(locId); + if ( !loc ) + { + // Try to find a variant of this locale available on this system: first + // of all, using just the language, without the territory, typically + // does _not_ work under Linux, so try adding one if we don't have it. + if ( locId.GetRegion().empty() ) + { + const wxLanguageInfo* const info = + wxLocale::FindLanguageInfo(locId.GetLanguage()); + if ( info ) + { + wxString region = info->CanonicalName.AfterFirst('_'); + if ( !region.empty() ) + { + // We never have encoding in our canonical names, but we + // can have modifiers, so get rid of them if necessary. + region = region.BeforeFirst('@'); + + loc = TryCreateLocale(locId.Region(region)); + } + } + } + + // And sometimes the locale without encoding is not available, but one + // with UTF-8 encoding is, so try this too. + if ( !loc && locId.GetCharset().empty() ) + { + loc = TryCreateLocale(locId.Charset("UTF-8")); + } + } + + if ( !loc ) + return NULL; + + return new wxUILocaleImplUnix(locId, loc); +#else // !HAVE_LOCALE_T + // We can't check locale availability without changing it in this case, so + // just assume it's valid. + return new wxUILocaleImplUnix(locIdOrig); +#endif // HAVE_LOCALE_T/!HAVE_LOCALE_T } #endif // wxUSE_INTL