Audacity 3.2.0
numformatter.cpp
Go to the documentation of this file.
1
2//
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
97wxString NumberFormatter::PostProcessIntString(const wxString &sArg, int style)
98{
99 wxString s(sArg);
100
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
116wxString 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
123wxString 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
131wxString 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
162
163 if ( precision != -1 )
164 {
167
170
173
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
211void 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
244bool 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
253bool 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
263bool NumberFormatter::FromString(const wxString &sArg, double *val)
264{
265 wxString s(sArg);
266
268 return s.ToDouble(val);
269}
wxT("CloseDown"))
#define _(s)
Definition: Internat.h:73
static bool FromString(const wxString &s, long *val)
static wxChar GetDecimalSeparator()
static wxString PostProcessIntString(const wxString &s, int style)
static void RemoveTrailingZeroes(wxString &s, size_t retain=0)
static bool GetThousandsSeparatorIfUsed(wxChar *sep)
static void RemoveThousandsSeparators(wxString &s)
static void AddThousandsSeparators(wxString &s)
static wxString ToString(long val, int style=Style_WithThousandsSep)
constexpr size_t npos(-1)