Use wxUILocale in wxNumberFormatter
Always use the UI locale conventions for floating point numbers in wxNumberFormatter, making it different from wxString::{To,From}Double() functions that use C locale, which may, or not, correspond to the UI locale.
This commit is contained in:
@@ -8,11 +8,15 @@
|
|||||||
/**
|
/**
|
||||||
@class wxNumberFormatter
|
@class wxNumberFormatter
|
||||||
|
|
||||||
Helper class for formatting and parsing numbers with thousands separators.
|
Formatting and parsing numbers using the current UI locale conventions,
|
||||||
|
including support for using the correct decimal point character and
|
||||||
|
thousands separators.
|
||||||
|
|
||||||
This class contains only static functions, so users must not create instances
|
This class contains only static functions, so users must not create instances
|
||||||
but directly call the member functions.
|
but directly call the member functions.
|
||||||
|
|
||||||
|
@see wxUILocale
|
||||||
|
|
||||||
@since 2.9.2
|
@since 2.9.2
|
||||||
|
|
||||||
@library{wxbase}
|
@library{wxbase}
|
||||||
@@ -32,7 +36,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
If this flag is given, thousands separators will be inserted in the
|
If this flag is given, thousands separators will be inserted in the
|
||||||
number string representation as defined by the current locale.
|
number string representation as defined by the current UI locale.
|
||||||
*/
|
*/
|
||||||
Style_WithThousandsSep = 0x01,
|
Style_WithThousandsSep = 0x01,
|
||||||
|
|
||||||
@@ -56,7 +60,7 @@ public:
|
|||||||
Returns string representation of an integer number.
|
Returns string representation of an integer number.
|
||||||
|
|
||||||
By default, the string will use thousands separators if appropriate for
|
By default, the string will use thousands separators if appropriate for
|
||||||
the current locale. This can be avoided by passing Style_None as @a
|
the current UI locale. This can be avoided by passing Style_None as @a
|
||||||
flags in which case the call to the function has exactly the same
|
flags in which case the call to the function has exactly the same
|
||||||
effect as <code>wxString::Format("%ld", val)</code>.
|
effect as <code>wxString::Format("%ld", val)</code>.
|
||||||
|
|
||||||
@@ -94,7 +98,7 @@ public:
|
|||||||
Parse a string representation of a number possibly including thousands
|
Parse a string representation of a number possibly including thousands
|
||||||
separators.
|
separators.
|
||||||
|
|
||||||
These functions parse number representation in the current locale. On
|
These functions parse number representation in the current UI locale. On
|
||||||
success they return @true and store the result at the location pointed
|
success they return @true and store the result at the location pointed
|
||||||
to by @a val (which can't be @NULL), otherwise @false is returned.
|
to by @a val (which can't be @NULL), otherwise @false is returned.
|
||||||
|
|
||||||
@@ -114,7 +118,7 @@ public:
|
|||||||
//@}
|
//@}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the decimal separator for the current locale.
|
Get the decimal separator for the current UI locale.
|
||||||
|
|
||||||
Decimal separators is always defined and we fall back to returning '.'
|
Decimal separators is always defined and we fall back to returning '.'
|
||||||
in case of an error.
|
in case of an error.
|
||||||
@@ -123,14 +127,14 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Get the thousands separator if grouping of the digits is used by the
|
Get the thousands separator if grouping of the digits is used by the
|
||||||
current locale.
|
current UI locale.
|
||||||
|
|
||||||
The value returned in @a sep should be only used if the function
|
The value returned in @a sep should be only used if the function
|
||||||
returns @true, otherwise no thousands separator should be used at all.
|
returns @true, otherwise no thousands separator should be used at all.
|
||||||
|
|
||||||
@param sep
|
@param sep
|
||||||
Points to the variable receiving the thousands separator character
|
Points to the variable receiving the thousands separator character
|
||||||
if it is used by the current locale. May be @NULL if only the
|
if it is used by the current UI locale. May be @NULL if only the
|
||||||
function return value is needed.
|
function return value is needed.
|
||||||
*/
|
*/
|
||||||
static bool GetThousandsSeparatorIfUsed(wxChar *sep);
|
static bool GetThousandsSeparatorIfUsed(wxChar *sep);
|
||||||
|
@@ -16,84 +16,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "wx/numformatter.h"
|
#include "wx/numformatter.h"
|
||||||
#include "wx/intl.h"
|
#include "wx/uilocale.h"
|
||||||
|
|
||||||
#include <locale.h> // for setlocale and LC_ALL
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// local helpers
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
// Contains information about the locale which was used to initialize our
|
|
||||||
// cached values of the decimal and thousands separators. Notice that it isn't
|
|
||||||
// enough to store just wxLocale because the user code may call setlocale()
|
|
||||||
// directly and storing just C locale string is not enough because we can use
|
|
||||||
// the OS API directly instead of the CRT ones on some platforms. So just store
|
|
||||||
// both.
|
|
||||||
class LocaleId
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LocaleId()
|
|
||||||
{
|
|
||||||
#if wxUSE_INTL
|
|
||||||
m_wxloc = NULL;
|
|
||||||
#endif // wxUSE_INTL
|
|
||||||
m_cloc = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
~LocaleId()
|
|
||||||
{
|
|
||||||
Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if wxUSE_INTL
|
|
||||||
// Return true if this is the first time this function is called for this
|
|
||||||
// object or if the program locale has changed since the last time it was
|
|
||||||
// called. Otherwise just return false indicating that updating locale-
|
|
||||||
// dependent information is not necessary.
|
|
||||||
bool NotInitializedOrHasChanged()
|
|
||||||
{
|
|
||||||
wxLocale * const wxloc = wxGetLocale();
|
|
||||||
const char * const cloc = setlocale(LC_ALL, NULL);
|
|
||||||
if ( m_wxloc || m_cloc )
|
|
||||||
{
|
|
||||||
if ( m_wxloc == wxloc && strcmp(m_cloc, cloc) == 0 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Free();
|
|
||||||
}
|
|
||||||
//else: Not initialized yet.
|
|
||||||
|
|
||||||
m_wxloc = wxloc;
|
|
||||||
m_cloc = wxCRT_StrdupA(cloc);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif // wxUSE_INTL
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Free()
|
|
||||||
{
|
|
||||||
#if wxUSE_INTL
|
|
||||||
free(m_cloc);
|
|
||||||
#endif // wxUSE_INTL
|
|
||||||
}
|
|
||||||
|
|
||||||
#if wxUSE_INTL
|
|
||||||
// Non-owned pointer to wxLocale which was used.
|
|
||||||
wxLocale *m_wxloc;
|
|
||||||
#endif // wxUSE_INTL
|
|
||||||
|
|
||||||
// Owned pointer to the C locale string.
|
|
||||||
char *m_cloc;
|
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(LocaleId);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// wxNumberFormatter implementation
|
// wxNumberFormatter implementation
|
||||||
@@ -111,14 +34,10 @@ wxChar wxNumberFormatter::GetDecimalSeparator()
|
|||||||
// concurrently from more than one thread so it's not a real problem.
|
// concurrently from more than one thread so it's not a real problem.
|
||||||
static wxChar s_decimalSeparator = 0;
|
static wxChar s_decimalSeparator = 0;
|
||||||
|
|
||||||
// Remember the locale which was current when we initialized, we must redo
|
if ( !s_decimalSeparator )
|
||||||
// the initialization if the locale changed.
|
|
||||||
static LocaleId s_localeUsedForInit;
|
|
||||||
|
|
||||||
if ( s_localeUsedForInit.NotInitializedOrHasChanged() )
|
|
||||||
{
|
{
|
||||||
const wxString
|
const wxString
|
||||||
s = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
|
s = wxUILocale::GetCurrent().GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
|
||||||
if ( s.length() == 1 )
|
if ( s.length() == 1 )
|
||||||
{
|
{
|
||||||
s_decimalSeparator = s[0];
|
s_decimalSeparator = s[0];
|
||||||
@@ -141,12 +60,14 @@ bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep)
|
|||||||
{
|
{
|
||||||
#if wxUSE_INTL
|
#if wxUSE_INTL
|
||||||
static wxChar s_thousandsSeparator = 0;
|
static wxChar s_thousandsSeparator = 0;
|
||||||
static LocaleId s_localeUsedForInit;
|
static bool s_thousandsSeparatorInitialized = false;
|
||||||
|
|
||||||
if ( s_localeUsedForInit.NotInitializedOrHasChanged() )
|
if ( !s_thousandsSeparatorInitialized )
|
||||||
{
|
{
|
||||||
|
s_thousandsSeparatorInitialized = true;
|
||||||
|
|
||||||
const wxString
|
const wxString
|
||||||
s = wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER);
|
s = wxUILocale::GetCurrent().GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER);
|
||||||
if ( s.length() == 1 )
|
if ( s.length() == 1 )
|
||||||
{
|
{
|
||||||
s_thousandsSeparator = s[0];
|
s_thousandsSeparator = s[0];
|
||||||
@@ -172,6 +93,21 @@ bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep)
|
|||||||
// Conversion to string and helpers
|
// Conversion to string and helpers
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void ReplaceSeparatorIfNecessary(wxString& s, wxChar sepOld, wxChar sepNew)
|
||||||
|
{
|
||||||
|
if ( sepNew != sepOld )
|
||||||
|
{
|
||||||
|
const size_t posSep = s.find(sepOld);
|
||||||
|
if ( posSep != wxString::npos )
|
||||||
|
s[posSep] = sepNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
wxString wxNumberFormatter::PostProcessIntString(wxString s, int style)
|
wxString wxNumberFormatter::PostProcessIntString(wxString s, int style)
|
||||||
{
|
{
|
||||||
if ( style & Style_WithThousandsSep )
|
if ( style & Style_WithThousandsSep )
|
||||||
@@ -206,7 +142,9 @@ wxString wxNumberFormatter::ToString(wxULongLong_t val, int style)
|
|||||||
|
|
||||||
wxString wxNumberFormatter::ToString(double val, int precision, int style)
|
wxString wxNumberFormatter::ToString(double val, int precision, int style)
|
||||||
{
|
{
|
||||||
wxString s = wxString::FromDouble(val,precision);
|
wxString s = wxString::FromCDouble(val,precision);
|
||||||
|
|
||||||
|
ReplaceSeparatorIfNecessary(s, '.', GetDecimalSeparator());
|
||||||
|
|
||||||
if ( style & Style_WithThousandsSep )
|
if ( style & Style_WithThousandsSep )
|
||||||
AddThousandsSeparators(s);
|
AddThousandsSeparators(s);
|
||||||
@@ -330,5 +268,6 @@ bool wxNumberFormatter::FromString(wxString s, wxULongLong_t *val)
|
|||||||
bool wxNumberFormatter::FromString(wxString s, double *val)
|
bool wxNumberFormatter::FromString(wxString s, double *val)
|
||||||
{
|
{
|
||||||
RemoveThousandsSeparators(s);
|
RemoveThousandsSeparators(s);
|
||||||
return s.ToDouble(val);
|
ReplaceSeparatorIfNecessary(s, GetDecimalSeparator(), '.');
|
||||||
|
return s.ToCDouble(val);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user