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