Audacity  3.0.3
numformatter.cpp
Go to the documentation of this file.
1 //
3 // Backport from wxWidgets-3.0-rc1
4 //
6 // Name: src/common/numformatter.cpp
7 // Purpose: NumberFormatter
8 // Author: Fulvio Senore, Vadim Zeitlin
9 // Created: 2010-11-06
10 // Copyright: (c) 2010 wxWidgets team
11 // Licence: wxWindows licence
13 
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17 
18 
19 #include "numformatter.h"
20 
21 // For compilers that support precompilation, includes "wx.h".
22 #include <wx/wxprec.h>
23 
24 #include <wx/setup.h> // for wxUSE_* macros
25 
26 #ifdef __BORLANDC__
27  #pragma hdrstop
28 #endif
29 
30 #ifdef __WIN32__
31  #include <wx/msw/private.h>
32 
33 #endif
34 
35 
36 #include "Internat.h"
37 #include <wx/intl.h>
38 
39 #include <locale.h> // for setlocale and LC_ALL
40 #include <cmath>
41 #include <limits>
42 #include <wx/log.h>
43 
44 // ----------------------------------------------------------------------------
45 // local helpers
46 // ----------------------------------------------------------------------------
47 
48 // ============================================================================
49 // NumberFormatter implementation
50 // ============================================================================
51 
52 // ----------------------------------------------------------------------------
53 // Locale information accessors
54 // ----------------------------------------------------------------------------
55 
57 {
58 #if wxUSE_INTL
59  struct lconv *info = localeconv();
60  wxString s = info ? wxString::FromUTF8(info->decimal_point) : wxString(".");
61  if (s.empty())
62  {
63  // We really must have something for decimal separator, so fall
64  // back to the C locale default.
65  s = wxT(".");
66  }
67 
68  return s[0];
69 #else // !wxUSE_INTL
70  return wxT('.');
71 #endif // wxUSE_INTL/!wxUSE_INTL
72 }
73 
75 {
76 #if wxUSE_INTL
77  struct lconv *info = localeconv();
78  wxString s = info ? wxString::FromUTF8(info->thousands_sep) : wxString{};
79 
80  if (s.empty())
81  {
82  return false;
83  }
84 
85  *sep = s[0];
86  return true;
87 #else // !wxUSE_INTL
88  wxUnusedVar(sep);
89  return false;
90 #endif // wxUSE_INTL/!wxUSE_INTL
91 }
92 
93 // ----------------------------------------------------------------------------
94 // Conversion to string and helpers
95 // ----------------------------------------------------------------------------
96 
97 wxString NumberFormatter::PostProcessIntString(const wxString &sArg, int style)
98 {
99  wxString s(sArg);
100 
101  if ( style & Style_WithThousandsSep )
103 
104  wxASSERT_MSG( !(style & Style_NoTrailingZeroes),
105  wxT("Style_NoTrailingZeroes can't be used with integer values") );
106  wxASSERT_MSG( !(style & Style_OneTrailingZero),
107  wxT("Style_OneTrailingZero can't be used with integer values") );
108  wxASSERT_MSG( !(style & Style_TwoTrailingZeroes),
109  wxT("Style_TwoTrailingZeroes can't be used with integer values") );
110  wxASSERT_MSG( !(style & Style_ThreeTrailingZeroes),
111  wxT("Style_ThreeTrailingZeroes can't be used with integer values") );
112 
113  return s;
114 }
115 
116 wxString NumberFormatter::ToString(long val, int style)
117 {
118  return PostProcessIntString(wxString::Format(wxT("%ld"), val), style);
119 }
120 
121 #ifdef HAS_LONG_LONG_T_DIFFERENT_FROM_LONG
122 
123 wxString NumberFormatter::ToString(wxLongLong_t val, int style)
124 {
125  return PostProcessIntString(wxString::Format("%" wxLongLongFmtSpec "d", val),
126  style);
127 }
128 
129 #endif // HAS_LONG_LONG_T_DIFFERENT_FROM_LONG
130 
131 wxString NumberFormatter::ToString(double val, int precision, int style)
132 {
133  wxString format;
134  if ( precision == -1 )
135  {
136  format = wxT("%g");
137  }
138  else // Use fixed precision.
139  {
140  format.Printf(wxT("%%.%df"), precision);
141  }
142 
143  if (std::isnan(val))
144  {
145  return _("NaN");
146  }
147  if (std::isinf(val))
148  {
149  if (val == std::numeric_limits<double>::infinity())
150  {
151  return _("Infinity");
152  }
153  else
154  {
155  return _("-Infinity");
156  }
157  }
158  wxString s = wxString::Format(format, val);
159 
160  if ( style & Style_WithThousandsSep )
162 
163  if ( precision != -1 )
164  {
165  if ( style & Style_NoTrailingZeroes )
166  RemoveTrailingZeroes(s, 0);
167 
168  if ( style & Style_OneTrailingZero )
169  RemoveTrailingZeroes(s, 1);
170 
171  if ( style & Style_TwoTrailingZeroes )
172  RemoveTrailingZeroes(s, 2);
173 
174  if ( style & Style_ThreeTrailingZeroes )
175  RemoveTrailingZeroes(s, 3);
176  }
177  return s;
178 }
179 
181 {
182  wxChar thousandsSep;
183  if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
184  return;
185 
186  size_t pos = s.find(GetDecimalSeparator());
187  if ( pos == wxString::npos )
188  {
189  // Start grouping at the end of an integer number.
190  pos = s.length();
191  }
192 
193  // End grouping at the beginning of the digits -- there could be at a sign
194  // before their start.
195  const size_t start = s.find_first_of(wxT("0123456789"));
196 
197  // We currently group digits by 3 independently of the locale. This is not
198  // the right thing to do and we should use lconv::grouping (under POSIX)
199  // and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about
200  // the correct grouping to use. This is something that needs to be done at
201  // wxLocale level first and then used here in the future (TODO).
202  const size_t GROUP_LEN = 3;
203 
204  while ( pos > start + GROUP_LEN )
205  {
206  pos -= GROUP_LEN;
207  s.insert(pos, thousandsSep);
208  }
209 }
210 
211 void NumberFormatter::RemoveTrailingZeroes(wxString& s, size_t retain /* = 0 */)
212 {
213  const size_t posDecSep = s.find(GetDecimalSeparator());
214  wxCHECK_RET( posDecSep != wxString::npos,
215  wxString::Format(wxT("No decimal separator in \"%s\""), s) );
216  wxCHECK_RET( posDecSep, wxT("Can't start with decimal separator" ));
217 
218  // Find the last character to keep.
219  size_t posLastCharacterToKeep = s.find_last_not_of(wxT("0"));
220 
221  // If it's the decimal separator itself, remove it.
222  if ((posLastCharacterToKeep == posDecSep) && (retain == 0)) {
223  posLastCharacterToKeep--;
224  } else if ((posLastCharacterToKeep - posDecSep) < retain) {
225  posLastCharacterToKeep = retain + posDecSep;
226  }
227 
228  s.erase(posLastCharacterToKeep + 1);
229 }
230 
231 // ----------------------------------------------------------------------------
232 // Conversion from strings
233 // ----------------------------------------------------------------------------
234 
236 {
237  wxChar thousandsSep;
238  if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
239  return;
240 
241  s.Replace(wxString(thousandsSep), wxString());
242 }
243 
244 bool NumberFormatter::FromString(const wxString &sArg, long *val)
245 {
246  wxString s(sArg);
248  return s.ToLong(val);
249 }
250 
251 #ifdef HAS_LONG_LONG_T_DIFFERENT_FROM_LONG
252 
253 bool NumberFormatter::FromString(const wxString &sArg, wxLongLong_t *val)
254 {
255  wxString s(sArg);
256 
258  return s.ToLongLong(val);
259 }
260 
261 #endif // HAS_LONG_LONG_T_DIFFERENT_FROM_LONG
262 
263 bool NumberFormatter::FromString(const wxString &sArg, double *val)
264 {
265  wxString s(sArg);
266 
268  return s.ToDouble(val);
269 }
NumberFormatter::AddThousandsSeparators
static void AddThousandsSeparators(wxString &s)
Definition: numformatter.cpp:180
NumberFormatter::PostProcessIntString
static wxString PostProcessIntString(const wxString &s, int style)
Definition: numformatter.cpp:97
NumberFormatter::FromString
static bool FromString(const wxString &s, long *val)
Definition: numformatter.cpp:244
NumberFormatter::GetDecimalSeparator
static wxChar GetDecimalSeparator()
Definition: numformatter.cpp:56
NumberFormatter::Style_OneTrailingZero
@ Style_OneTrailingZero
Definition: numformatter.h:36
NumberFormatter::RemoveThousandsSeparators
static void RemoveThousandsSeparators(wxString &s)
Definition: numformatter.cpp:235
NumberFormatter::ToString
static wxString ToString(long val, int style=Style_WithThousandsSep)
Definition: numformatter.cpp:116
NumberFormatter::Style_NoTrailingZeroes
@ Style_NoTrailingZeroes
Definition: numformatter.h:35
format
int format
Definition: ExportPCM.cpp:56
NumberFormatter::RemoveTrailingZeroes
static void RemoveTrailingZeroes(wxString &s, size_t retain=0)
Definition: numformatter.cpp:211
Internat.h
NumberFormatter::Style_ThreeTrailingZeroes
@ Style_ThreeTrailingZeroes
Definition: numformatter.h:38
_
#define _(s)
Definition: Internat.h:75
NumberFormatter::Style_TwoTrailingZeroes
@ Style_TwoTrailingZeroes
Definition: numformatter.h:37
NumberFormatter::Style_WithThousandsSep
@ Style_WithThousandsSep
Definition: numformatter.h:34
NumberFormatter::GetThousandsSeparatorIfUsed
static bool GetThousandsSeparatorIfUsed(wxChar *sep)
Definition: numformatter.cpp:74
numformatter.h