]> git.saurik.com Git - wxWidgets.git/blob - src/common/numformatter.cpp
Add support for long long to wxNumberFormatter.
[wxWidgets.git] / src / common / numformatter.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: numformatter.cpp
3 // Purpose: wxNumberFormatter
4 // Author: Fulvio Senore, Vadim Zeitlin
5 // Created: 2010-11-06
6 // Copyright: (c) 2010 wxWidgets team
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ----------------------------------------------------------------------------
11 // headers
12 // ----------------------------------------------------------------------------
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/numformatter.h"
22 #include "wx/intl.h"
23
24 // ============================================================================
25 // wxNumberFormatter implementation
26 // ============================================================================
27
28 // ----------------------------------------------------------------------------
29 // Locale information accessors
30 // ----------------------------------------------------------------------------
31
32 wxChar wxNumberFormatter::GetDecimalSeparator()
33 {
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;
38
39 if ( !s_decimalSeparator )
40 {
41 const wxString
42 s = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
43 if ( s.empty() )
44 {
45 // We really must have something for decimal separator, so fall
46 // back to the C locale default.
47 s_decimalSeparator = '.';
48 }
49 else
50 {
51 // To the best of my knowledge there are no locales like this.
52 wxASSERT_MSG( s.length() == 1,
53 "Multi-character decimal separator?" );
54
55 s_decimalSeparator = s[0];
56 }
57 }
58
59 return s_decimalSeparator;
60 }
61
62 bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep)
63 {
64 static wxChar s_thousandsSeparator = 0;
65 static bool s_initialized = false;
66
67 if ( !s_initialized )
68 {
69 const wxString
70 s = wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER);
71 if ( !s.empty() )
72 {
73 wxASSERT_MSG( s.length() == 1,
74 "Multi-character thousands separator?" );
75
76 s_thousandsSeparator = s[0];
77 }
78 //else: Unlike above it's perfectly fine for the thousands separator to
79 // be empty if grouping is not used, so just leave it as 0.
80
81 s_initialized = true;
82 }
83
84 if ( !s_thousandsSeparator )
85 return false;
86
87 if ( sep )
88 *sep = s_thousandsSeparator;
89
90 return true;
91 }
92
93 // ----------------------------------------------------------------------------
94 // Conversion to string and helpers
95 // ----------------------------------------------------------------------------
96
97 wxString wxNumberFormatter::PostProcessIntString(wxString s, int style)
98 {
99 if ( style & Style_WithThousandsSep )
100 AddThousandsSeparators(s);
101
102 wxASSERT_MSG( !(style & Style_NoTrailingZeroes),
103 "Style_NoTrailingZeroes can't be used with integer values" );
104
105 return s;
106 }
107
108 wxString wxNumberFormatter::ToString(long val, int style)
109 {
110 return PostProcessIntString(wxString::Format("%ld", val), style);
111 }
112
113 #ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
114
115 wxString wxNumberFormatter::ToString(wxLongLong_t val, int style)
116 {
117 return PostProcessIntString(wxString::Format("%" wxLongLongFmtSpec "d", val),
118 style);
119 }
120
121 #endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
122
123 wxString wxNumberFormatter::ToString(double val, int precision, int style)
124 {
125 const wxString fmt = wxString::Format("%%.%df", precision);
126 wxString s = wxString::Format(fmt, val);
127
128 if ( style & Style_WithThousandsSep )
129 AddThousandsSeparators(s);
130
131 if ( style & Style_NoTrailingZeroes )
132 RemoveTrailingZeroes(s);
133
134 return s;
135 }
136
137 void wxNumberFormatter::AddThousandsSeparators(wxString& s)
138 {
139 wxChar thousandsSep;
140 if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
141 return;
142
143 size_t pos = s.find(GetDecimalSeparator());
144 if ( pos == wxString::npos )
145 {
146 // Start grouping at the end of an integer number.
147 pos = s.length();
148 }
149
150 // We currently group digits by 3 independently of the locale. This is not
151 // the right thing to do and we should use lconv::grouping (under POSIX)
152 // and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about
153 // the correct grouping to use. This is something that needs to be done at
154 // wxLocale level first and then used here in the future (TODO).
155 const size_t GROUP_LEN = 3;
156
157 while ( pos > GROUP_LEN )
158 {
159 pos -= GROUP_LEN;
160 s.insert(pos, thousandsSep);
161 }
162 }
163
164 void wxNumberFormatter::RemoveTrailingZeroes(wxString& s)
165 {
166 const size_t posDecSep = s.find(GetDecimalSeparator());
167 wxCHECK_RET( posDecSep != wxString::npos, "No decimal separator" );
168 wxCHECK_RET( posDecSep, "Can't start with decimal separator" );
169
170 // Find the last character to keep.
171 size_t posLastNonZero = s.find_last_not_of("0");
172
173 // If it's the decimal separator itself, don't keep it neither.
174 if ( posLastNonZero == posDecSep )
175 posLastNonZero--;
176
177 s.erase(posLastNonZero + 1);
178 }
179
180 // ----------------------------------------------------------------------------
181 // Conversion from strings
182 // ----------------------------------------------------------------------------
183
184 void wxNumberFormatter::RemoveThousandsSeparators(wxString& s)
185 {
186 wxChar thousandsSep;
187 if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
188 return;
189
190 s.Replace(wxString(thousandsSep), wxString());
191 }
192
193 bool wxNumberFormatter::FromString(wxString s, long *val)
194 {
195 RemoveThousandsSeparators(s);
196 return s.ToLong(val);
197 }
198
199 #ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
200
201 bool wxNumberFormatter::FromString(wxString s, wxLongLong_t *val)
202 {
203 RemoveThousandsSeparators(s);
204 return s.ToLongLong(val);
205 }
206
207 #endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
208
209 bool wxNumberFormatter::FromString(wxString s, double *val)
210 {
211 RemoveThousandsSeparators(s);
212 return s.ToDouble(val);
213 }