1 /////////////////////////////////////////////////////////////////////////////
2 // Name: numformatter.cpp
3 // Purpose: wxNumberFormatter
4 // Author: Fulvio Senore, Vadim Zeitlin
6 // Copyright: (c) 2010 wxWidgets team
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
21 #include "wx/numformatter.h"
24 // ============================================================================
25 // wxNumberFormatter implementation
26 // ============================================================================
28 // ----------------------------------------------------------------------------
29 // Locale information accessors
30 // ----------------------------------------------------------------------------
32 wxChar
wxNumberFormatter::GetDecimalSeparator()
34 // Notice that while using static variable here is not MT-safe, the worst
35 // that can happen is that we redo the initialization if we're called
36 // concurrently from more than one thread so it's not a real problem.
37 static wxChar s_decimalSeparator
= 0;
39 // Remember the locale which was current when we initialized, we must redo
40 // the initialization if the locale changed.
41 static wxLocale
*s_localeUsedForInit
= NULL
;
43 if ( !s_decimalSeparator
|| (s_localeUsedForInit
!= wxGetLocale()) )
46 s
= wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
);
49 // We really must have something for decimal separator, so fall
50 // back to the C locale default.
51 s_decimalSeparator
= '.';
55 // To the best of my knowledge there are no locales like this.
56 wxASSERT_MSG( s
.length() == 1,
57 "Multi-character decimal separator?" );
59 s_decimalSeparator
= s
[0];
62 s_localeUsedForInit
= wxGetLocale();
65 return s_decimalSeparator
;
68 bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar
*sep
)
70 static wxChar s_thousandsSeparator
= 0;
71 static bool s_initialized
= false;
72 static wxLocale
*s_localeUsedForInit
= NULL
;
74 if ( !s_initialized
|| (s_localeUsedForInit
!= wxGetLocale()) )
77 s
= wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP
, wxLOCALE_CAT_NUMBER
);
80 wxASSERT_MSG( s
.length() == 1,
81 "Multi-character thousands separator?" );
83 s_thousandsSeparator
= s
[0];
85 //else: Unlike above it's perfectly fine for the thousands separator to
86 // be empty if grouping is not used, so just leave it as 0.
89 s_localeUsedForInit
= wxGetLocale();
92 if ( !s_thousandsSeparator
)
96 *sep
= s_thousandsSeparator
;
101 // ----------------------------------------------------------------------------
102 // Conversion to string and helpers
103 // ----------------------------------------------------------------------------
105 wxString
wxNumberFormatter::PostProcessIntString(wxString s
, int style
)
107 if ( style
& Style_WithThousandsSep
)
108 AddThousandsSeparators(s
);
110 wxASSERT_MSG( !(style
& Style_NoTrailingZeroes
),
111 "Style_NoTrailingZeroes can't be used with integer values" );
116 wxString
wxNumberFormatter::ToString(long val
, int style
)
118 return PostProcessIntString(wxString::Format("%ld", val
), style
);
121 #ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
123 wxString
wxNumberFormatter::ToString(wxLongLong_t val
, int style
)
125 return PostProcessIntString(wxString::Format("%" wxLongLongFmtSpec
"d", val
),
129 #endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
131 wxString
wxNumberFormatter::ToString(double val
, int precision
, int style
)
133 const wxString fmt
= wxString::Format("%%.%df", precision
);
134 wxString s
= wxString::Format(fmt
, val
);
136 if ( style
& Style_WithThousandsSep
)
137 AddThousandsSeparators(s
);
139 if ( style
& Style_NoTrailingZeroes
)
140 RemoveTrailingZeroes(s
);
145 void wxNumberFormatter::AddThousandsSeparators(wxString
& s
)
148 if ( !GetThousandsSeparatorIfUsed(&thousandsSep
) )
151 size_t pos
= s
.find(GetDecimalSeparator());
152 if ( pos
== wxString::npos
)
154 // Start grouping at the end of an integer number.
158 // We currently group digits by 3 independently of the locale. This is not
159 // the right thing to do and we should use lconv::grouping (under POSIX)
160 // and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about
161 // the correct grouping to use. This is something that needs to be done at
162 // wxLocale level first and then used here in the future (TODO).
163 const size_t GROUP_LEN
= 3;
165 while ( pos
> GROUP_LEN
)
168 s
.insert(pos
, thousandsSep
);
172 void wxNumberFormatter::RemoveTrailingZeroes(wxString
& s
)
174 const size_t posDecSep
= s
.find(GetDecimalSeparator());
175 wxCHECK_RET( posDecSep
!= wxString::npos
,
176 wxString::Format("No decimal separator in \"%s\"", s
) );
177 wxCHECK_RET( posDecSep
, "Can't start with decimal separator" );
179 // Find the last character to keep.
180 size_t posLastNonZero
= s
.find_last_not_of("0");
182 // If it's the decimal separator itself, don't keep it neither.
183 if ( posLastNonZero
== posDecSep
)
186 s
.erase(posLastNonZero
+ 1);
189 // ----------------------------------------------------------------------------
190 // Conversion from strings
191 // ----------------------------------------------------------------------------
193 void wxNumberFormatter::RemoveThousandsSeparators(wxString
& s
)
196 if ( !GetThousandsSeparatorIfUsed(&thousandsSep
) )
199 s
.Replace(wxString(thousandsSep
), wxString());
202 bool wxNumberFormatter::FromString(wxString s
, long *val
)
204 RemoveThousandsSeparators(s
);
205 return s
.ToLong(val
);
208 #ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
210 bool wxNumberFormatter::FromString(wxString s
, wxLongLong_t
*val
)
212 RemoveThousandsSeparators(s
);
213 return s
.ToLongLong(val
);
216 #endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
218 bool wxNumberFormatter::FromString(wxString s
, double *val
)
220 RemoveThousandsSeparators(s
);
221 return s
.ToDouble(val
);