Audacity  2.2.2
Internat.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Internat.cpp
6 
7  Markus Meyer
8  Dominic Mazzoni (Mac OS X code)
9 
10 *******************************************************************//*******************************************************************/
22 
23 #include <wx/log.h>
24 #include <wx/intl.h>
25 #include <wx/filename.h>
26 
27 #include <locale.h>
28 #include <math.h> // for pow()
29 
30 #include "Experimental.h"
31 #include "FileNames.h"
32 #include "widgets/ErrorDialog.h"
33 #include "Internat.h"
34 
35 // in order for the static member variables to exist, they must appear here
36 // (_outside_) the class definition, in order to be allocated some storage.
37 // Otherwise, you get link errors.
38 
39 wxChar Internat::mDecimalSeparator = wxT('.'); // default
40 wxArrayString Internat::exclude;
41 wxCharBuffer Internat::mFilename;
42 
43 // DA: Use tweaked translation mechanism to replace 'Audacity' by 'DarkAudacity'.
44 #ifdef EXPERIMENTAL_DA
45 // This function allows us to replace Audacity by DarkAudacity without peppering
46 // the source code with changes. We split out this step, the customisation, as
47 // it is used on its own (without translation) in the wxTS macro.
48 const wxString& GetCustomSubstitution(const wxString& str2)
49 {
50  // If contains 'DarkAudacity, already converted.
51  if( str2.Contains( "DarkAudacity" ))
52  return str2;
53  // If does not contain 'Audacity', nothing to do.
54  if( !str2.Contains( "Audacity" ))
55  return str2;
56  wxString str3 = str2;
57  str3.Replace( "Audacity", "DarkAudacity" );
58  str3.Replace( " an DarkAudacity", " a DarkAudacity" );
59  // DA also renames sync-lock(ed) as time-lock(ed).
60  str3.Replace( "Sync-Lock", "Time-Lock" );
61  str3.Replace( "Sync-&Lock", "Time-&Lock" );
62  str3.Replace( "Sync Lock", "Time Lock" );
63  return wxTranslations::GetUntranslatedString(str3);
64 }
65 #else
66 const wxString& GetCustomSubstitution(const wxString& str1)
67 {
68  return str1 ;
69 }
70 #endif
71 
72 // In any translated string, we can replace the name 'Audacity' by 'DarkAudacity'
73 // without requiring translators to see extra strings for the two versions.
74 const wxString& GetCustomTranslation(const wxString& str1)
75 {
76  const wxString& str2 = wxGetTranslation( str1 );
77  return GetCustomSubstitution( str2 );
78 }
79 
80 
82 {
83  // Save decimal point character
84  struct lconv * localeInfo = localeconv();
85  if (localeInfo)
86  mDecimalSeparator = wxString(wxSafeConvertMB2WX(localeInfo->decimal_point)).GetChar(0);
87 
88 // wxLogDebug(wxT("Decimal separator set to '%c'"), mDecimalSeparator);
89 
90  // Setup list of characters that aren't allowed in file names
91  // Hey! The default wxPATH_NATIVE does not do as it should.
92 #if defined(__WXMAC__)
93  wxPathFormat format = wxPATH_MAC;
94 #elif defined(__WXGTK__)
95  wxPathFormat format = wxPATH_UNIX;
96 #elif defined(__WXMSW__)
97  wxPathFormat format = wxPATH_WIN;
98 #endif
99 
100  // This is supposed to return characters not permitted in paths to files
101  // or to directories
102  auto forbid = wxFileName::GetForbiddenChars(format);
103 
104  for(auto cc: forbid)
105  exclude.Add(wxString{ cc });
106 
107  // The path separators may not be forbidden, so add them
108  auto separators = wxFileName::GetPathSeparators(format);
109 
110  for(auto cc: separators) {
111  if (forbid.Find(cc) == wxNOT_FOUND)
112  exclude.Add(wxString{ cc });
113  }
114 }
115 
117 {
118  return mDecimalSeparator;
119 }
120 
121 bool Internat::CompatibleToDouble(const wxString& stringToConvert, double* result)
122 {
123  // Regardless of the locale, always respect comma _and_ point
124  wxString s = stringToConvert;
125  s.Replace(wxT(","), wxString(GetDecimalSeparator()));
126  s.Replace(wxT("."), wxString(GetDecimalSeparator()));
127  return s.ToDouble(result);
128 }
129 
130 double Internat::CompatibleToDouble(const wxString& stringToConvert)
131 {
132  double result = 0;
133  Internat::CompatibleToDouble(stringToConvert, &result);
134  return result;
135 }
136 
137 wxString Internat::ToString(double numberToConvert,
138  int digitsAfterDecimalPoint /* = -1 */)
139 {
140  wxString result = ToDisplayString(
141  numberToConvert, digitsAfterDecimalPoint);
142 
143  result.Replace(wxString(GetDecimalSeparator()), wxT("."));
144 
145  return result;
146 }
147 
148 wxString Internat::ToDisplayString(double numberToConvert,
149  int digitsAfterDecimalPoint /* = -1 */)
150 {
151  wxString decSep = wxString(GetDecimalSeparator());
152  wxString result;
153 
154  if (digitsAfterDecimalPoint == -1)
155  {
156  result.Printf(wxT("%f"), numberToConvert);
157 
158  // Not all libcs respect the decimal separator, so always convert
159  // any dots found to the decimal separator.
160  result.Replace(wxT("."), decSep);
161 
162  if (result.Find(decSep) != -1)
163  {
164  // Strip trailing zeros, but leave one, and decimal separator.
165  int pos = result.Length() - 1;
166  while ((pos > 1) &&
167  (result.GetChar(pos) == wxT('0')) &&
168  (result.GetChar(pos - 1) != decSep))
169  pos--;
170  // (Previous code removed all of them and decimal separator.)
171  // if (result.GetChar(pos) == decSep)
172  // pos--; // strip point before empty fractional part
173  result = result.Left(pos+1);
174  }
175  }
176  else
177  {
178  wxString format;
179  format.Printf(wxT("%%.%if"), digitsAfterDecimalPoint);
180  result.Printf(format, numberToConvert);
181 
182  // Not all libcs respect the decimal separator, so always convert
183  // any dots found to the decimal separator
184  result.Replace(wxT("."), decSep);
185  }
186 
187  return result;
188 }
189 
190 wxString Internat::FormatSize(wxLongLong size)
191 {
192  /* wxLongLong contains no built-in conversion to double */
193  double dSize = size.GetHi() * pow(2.0, 32); // 2 ^ 32
194  dSize += size.GetLo();
195 
196  return FormatSize(dSize);
197 }
198 
199 wxString Internat::FormatSize(double size)
200 {
201  wxString sizeStr;
202 
203  if (size == -1)
204  sizeStr = _("Unable to determine");
205  else {
206  /* make it look nice, by formatting into k, MB, etc */
207  if (size < 1024.0)
208  sizeStr = ToDisplayString(size) + wxT(" ") + _("bytes");
209  else if (size < 1024.0 * 1024.0) {
210  /* i18n-hint: Abbreviation for Kilo bytes */
211  sizeStr = ToDisplayString(size / 1024.0, 1) + wxT(" ") + _("KB");
212  }
213  else if (size < 1024.0 * 1024.0 * 1024.0) {
214  /* i18n-hint: Abbreviation for Mega bytes */
215  sizeStr = ToDisplayString(size / (1024.0 * 1024.0), 1) + wxT(" ") + _("MB");
216  }
217  else {
218  /* i18n-hint: Abbreviation for Giga bytes */
219  sizeStr = ToDisplayString(size / (1024.0 * 1024.0 * 1024.0), 1) + wxT(" ") + _("GB");
220  }
221  }
222 
223  return sizeStr;
224 }
225 
226 #if defined(__WXMSW__)
227 //
228 // On Windows, wxString::mb_str() can return a NULL pointer if the
229 // conversion to multi-byte fails. So, based on direction intent,
230 // returns a pointer to an empty string or prompts for a NEW name.
231 //
232 char *Internat::VerifyFilename(const wxString &s, bool input)
233 {
234  static wxCharBuffer buf;
235  wxString name = s;
236 
237  if (input) {
238  if ((char *) (const char *)name.mb_str() == NULL) {
239  name = wxEmptyString;
240  }
241  }
242  else {
243  wxFileName ff(name);
244  wxString ext;
245  while ((char *) (const char *)name.mb_str() == NULL) {
246  AudacityMessageBox(_("The specified filename could not be converted due to Unicode character use."));
247 
248  ext = ff.GetExt();
250  _("Specify New Filename:"),
251  wxEmptyString,
252  name,
253  ext,
254  wxT("*.") + ext,
255  wxFD_SAVE | wxRESIZE_BORDER,
256  wxGetTopLevelParent(NULL));
257  }
258  }
259 
260  mFilename = name.mb_str();
261 
262  return (char *) (const char *) mFilename;
263 }
264 #endif
265 
266 bool Internat::SanitiseFilename(wxString &name, const wxString &sub)
267 {
268  bool result = false;
269  for(const auto &item : exclude)
270  {
271  if(name.Contains(item))
272  {
273  name.Replace(item, sub);
274  result = true;
275  }
276  }
277 
278 #ifdef __WXMAC__
279  // Special Mac stuff
280  // '/' is permitted in file names as seen in dialogs, even though it is
281  // the path separator. The "real" filename as seen in the terminal has ':'.
282  // Do NOT return true if this is the only subsitution.
283  name.Replace(wxT("/"), wxT(":"));
284 #endif
285 
286  return result;
287 }
288 
289 wxString Internat::StripAccelerators(const wxString &s)
290 {
291  wxString result;
292  result.Alloc(s.Length());
293  for(size_t i = 0; i < s.Length(); i++) {
294  if (s[i] == '\t')
295  break;
296  if (s[i] != '&' && s[i] != '.')
297  result += s[i];
298  }
299  return result;
300 }
static wxString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:190
static wxString StripAccelerators(const wxString &str)
Remove accelerator charactors from strings.
Definition: Internat.cpp:289
static void Init()
Initialize internationalisation support. Call this once at program start.
Definition: Internat.cpp:81
static bool SanitiseFilename(wxString &name, const wxString &sub)
Protect against Unicode to multi-byte conversion failures on Windows.
Definition: Internat.cpp:266
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
Definition: Internat.cpp:137
int format
Definition: ExportPCM.cpp:56
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:121
static wxArrayString exclude
Definition: Internat.h:141
static wxChar mDecimalSeparator
Definition: Internat.h:138
const wxString & GetCustomTranslation(const wxString &str1)
Definition: Internat.cpp:74
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:405
const wxString & GetCustomSubstitution(const wxString &str1)
Definition: Internat.cpp:66
const wxChar * name
Definition: Distortion.cpp:94
static wxString ToDisplayString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, uses the user's locale's decimal separator.
Definition: Internat.cpp:148
static wxCharBuffer mFilename
Definition: Internat.h:143
static wxChar GetDecimalSeparator()
Get the decimal separator for the current locale.
Definition: Internat.cpp:116