Audacity  3.0.3
valnum.h
Go to the documentation of this file.
1 // Name: wx/valnum.h
3 // Purpose: Numeric validator classes.
4 // Author: Vadim Zeitlin based on the submission of Fulvio Senore
5 // Created: 2010-11-06
6 // Copyright: (c) 2010 wxWidgets team
7 // (c) 2011 Vadim Zeitlin <[email protected]>
8 // Licence: wxWindows licence
10 
11 #ifndef _WIDGETS_VALNUM_H_
12 #define _WIDGETS_VALNUM_H_
13 
14 #include <memory>
15 #include <wx/setup.h> // for wxUSE_* macros
16 #include <wx/defs.h>
17 
18 #if wxUSE_VALIDATORS
19 
20 #include <wx/textctrl.h> // complete type needed in template function
21 #include <wx/validate.h> // to inherit
22 
23 #include <limits>
24 
25 class TranslatableString;
26 
27 // Bit masks used for numeric validator styles.
28 enum class NumValidatorStyle : int
29 {
30  DEFAULT = 0x0,
31  THOUSANDS_SEPARATOR = 0x1,
32  ZERO_AS_BLANK = 0x2,
33  NO_TRAILING_ZEROES = 0x4,
34  ONE_TRAILING_ZERO = 0x8,
35  TWO_TRAILING_ZEROES = 0x10,
36  THREE_TRAILING_ZEROES = 0x20
37 };
38 
39 inline NumValidatorStyle operator | (NumValidatorStyle x, NumValidatorStyle y)
40 { return NumValidatorStyle( int(x) | int(y) ); }
41 
42 inline int operator & (NumValidatorStyle x, NumValidatorStyle y)
43 { return int(x) & int(y); }
44 
45 // ----------------------------------------------------------------------------
46 // Base class for all numeric validators.
47 // ----------------------------------------------------------------------------
48 
49 class AUDACITY_DLL_API NumValidatorBase /* not final */ : public wxValidator
50 {
51 public:
52  // Change the validator style. Usually it's specified during construction.
53  void SetStyle(NumValidatorStyle style) { m_style = style; }
54 
55  // Called when the value in the window must be validated.
56  // This function can pop up an error message.
57  bool Validate(wxWindow * parent) override;
58 
59 protected:
60  NumValidatorBase(NumValidatorStyle style)
61  {
62  m_style = style;
63  m_minSet = false;
64  m_maxSet = false;
65  }
66 
67  NumValidatorBase(const NumValidatorBase& other) : wxValidator()
68  {
69  m_style = other.m_style;
70  m_minSet = other.m_minSet;
71  m_maxSet = other.m_maxSet;
72  }
73 
74  bool HasFlag(NumValidatorStyle style) const
75  {
76  return (m_style & style) != 0;
77  }
78 
79  // Get the text entry of the associated control. Normally shouldn't ever
80  // return NULL (and will assert if it does return it) but the caller should
81  // still test the return value for safety.
82  wxTextEntry *GetTextEntry() const;
83 
84  // Convert NumValidatorStyle::THOUSANDS_SEPARATOR and NumValidatorStyle::NO_TRAILING_ZEROES
85  // bits of our style to the corresponding NumberFormatter::Style values.
86  int GetFormatFlags() const;
87 
88  // Return true if pressing a '-' key is acceptable for the current control
89  // contents and insertion point. This is meant to be called from the
90  // derived class IsCharOk() implementation.
91  bool IsMinusOk(const wxString& val, int pos) const;
92 
93  // Return the string which would result from inserting the given character
94  // at the specified position.
95  wxString GetValueAfterInsertingChar(const wxString &valArg, int pos, wxChar ch) const
96  {
97  wxString val(valArg);
98  val.insert(pos, ch);
99  return val;
100  }
101 
102  bool m_minSet;
103  bool m_maxSet;
104 
105 private:
106  // Check whether the specified character can be inserted in the control at
107  // the given position in the string representing the current controls
108  // contents.
109  //
110  // Notice that the base class checks for '-' itself so it's never passed to
111  // this function.
112  virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const = 0;
113 
114  // NormalizeString the contents of the string if it's a valid number, return
115  // empty string otherwise.
116  virtual wxString NormalizeString(const wxString& s) const = 0;
117 
118  // Do all checks to ensure this is a valid value.
119  // Returns 'true' if the control has valid value.
120  // Otherwise the cause is indicated in 'errMsg'.
121  virtual bool DoValidateNumber(TranslatableString * errMsg) const = 0;
122 
123  // Event handlers.
124  void OnChar(wxKeyEvent& event);
125  void OnPaste(wxClipboardTextEvent& event);
126  void OnKillFocus(wxFocusEvent& event);
127 
128 
129  // Determine the current insertion point and text in the associated control.
130  void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const;
131 
132 
133  // Combination of wxVAL_NUM_XXX values.
134  NumValidatorStyle m_style;
135 
136  DECLARE_EVENT_TABLE()
137 
138  DECLARE_NO_ASSIGN_CLASS(NumValidatorBase)
139 };
140 
141 namespace Private
142 {
143 
144 // This is a helper class used by IntegerValidator and FloatingPointValidator
145 // below that implements Transfer{To,From}Window() adapted to the type of the
146 // variable.
147 //
148 // The template argument B is the name of the base class which must derive from
149 // NumValidatorBase and define LongestValueType type and {To,As}String()
150 // methods i.e. basically be one of {Integer,Number}ValidatorBase classes.
151 //
152 // The template argument T is just the type handled by the validator that will
153 // inherit from this one.
154 template <class B, typename T>
155 class NumValidator /* final */ : public B
156 {
157 public:
158  typedef B BaseValidator;
159  typedef T ValueType;
160 
161  typedef typename BaseValidator::LongestValueType LongestValueType;
162 
163  // FIXME-VC6: This compiler fails to compile the assert below with a
164  // nonsensical error C2248: "'LongestValueType' : cannot access protected
165  // typedef declared in class 'IntegerValidatorBase'" so just disable the
166  // check for it.
167 #ifndef __VISUALC6__
168  wxCOMPILE_TIME_ASSERT
169  (
170  sizeof(ValueType) <= sizeof(LongestValueType),
171  UnsupportedType
172  );
173 #endif // __VISUALC6__
174 
175  void SetMin(ValueType min)
176  {
177  this->DoSetMin(min);
178  BaseValidator::m_minSet = (min != std::numeric_limits<T>::lowest());
179  }
180 
181  void SetMax(ValueType max)
182  {
183  this->DoSetMax(max);
184  BaseValidator::m_maxSet = (max != std::numeric_limits<T>::max());
185  }
186 
187  void SetRange(ValueType min, ValueType max)
188  {
189  SetMin(min);
190  SetMax(max);
191  }
192 
193  bool TransferToWindow() override
194  {
195  if ( m_value )
196  {
197  wxTextEntry * const control = BaseValidator::GetTextEntry();
198  if ( !control )
199  return false;
200 
201  control->ChangeValue(NormalizeValue(*m_value));
202  }
203 
204  return true;
205  }
206 
207  bool TransferFromWindow() override
208  {
209  if ( m_value )
210  {
211  wxTextEntry * const control = BaseValidator::GetTextEntry();
212  if ( !control )
213  return false;
214 
215  // If window is disabled, simply return
216  if ( !this->m_validatorWindow->IsEnabled() )
217  return true;
218 
219  const wxString s(control->GetValue());
220  LongestValueType value;
221  if ( s.empty() && BaseValidator::HasFlag(NumValidatorStyle::ZERO_AS_BLANK) )
222  value = 0;
223  else if ( !BaseValidator::FromString(s, &value) )
224  return false;
225 
226  if ( !this->IsInRange(value) )
227  return false;
228 
229  *m_value = static_cast<ValueType>(value);
230  }
231 
232  return true;
233  }
234 
235 protected:
236  NumValidator(ValueType *value, NumValidatorStyle style)
237  : BaseValidator(style),
238  m_value(value)
239  {
240  }
241 
242  // Implement NumValidatorBase virtual method which is the same for
243  // both integer and floating point numbers.
244  wxString NormalizeString(const wxString& s) const override
245  {
246  LongestValueType value;
247  return BaseValidator::FromString(s, &value) ? NormalizeValue(value)
248  : wxString();
249  }
250 
251 private:
252  // Just a helper which is a common part of TransferToWindow() and
253  // NormalizeString(): returns string representation of a number honouring
254  // NumValidatorStyle::ZERO_AS_BLANK flag.
255  wxString NormalizeValue(LongestValueType value) const
256  {
257  wxString s;
258  if ( value != 0 || !BaseValidator::HasFlag(NumValidatorStyle::ZERO_AS_BLANK) )
259  s = this->ToString(value);
260 
261  return s;
262  }
263 
264 
265  ValueType * const m_value;
266 
267  DECLARE_NO_ASSIGN_CLASS(NumValidator)
268 };
269 
270 } // namespace Private
271 
272 // ----------------------------------------------------------------------------
273 // Validators for integer numbers.
274 // ----------------------------------------------------------------------------
275 
276 // Base class for integer numbers validator. This class contains all non
277 // type-dependent code of wxIntegerValidator<> and always works with values of
278 // type LongestValueType. It is not meant to be used directly, please use
279 // IntegerValidator<> only instead.
280 class AUDACITY_DLL_API IntegerValidatorBase /* not final */
281  : public NumValidatorBase
282 {
283 protected:
284  // Define the type we use here, it should be the maximal-sized integer type
285  // we support to make it possible to base IntegerValidator<> for any type
286  // on it.
287 #ifdef wxLongLong_t
288  typedef wxLongLong_t LongestValueType;
289 #else
290  typedef long LongestValueType;
291 #endif
292 
293  IntegerValidatorBase(NumValidatorStyle style)
294  : NumValidatorBase(style)
295  {
296  wxASSERT_MSG( !(style & NumValidatorStyle::NO_TRAILING_ZEROES),
297  wxT("This style doesn't make sense for integers.") );
298  wxASSERT_MSG( !(style & NumValidatorStyle::ONE_TRAILING_ZERO),
299  wxT("This style doesn't make sense for integers.") );
300  wxASSERT_MSG( !(style & NumValidatorStyle::TWO_TRAILING_ZEROES),
301  wxT("This style doesn't make sense for integers.") );
302  wxASSERT_MSG( !(style & NumValidatorStyle::THREE_TRAILING_ZEROES),
303  wxT("This style doesn't make sense for integers.") );
304  }
305 
306  IntegerValidatorBase(const IntegerValidatorBase& other)
307  : NumValidatorBase(other)
308  {
309  m_min = other.m_min;
310  m_max = other.m_max;
311  }
312 
313  // Provide methods for NumValidator use.
314  wxString ToString(LongestValueType value) const;
315  static bool FromString(const wxString& s, LongestValueType *value);
316 
317  void DoSetMin(LongestValueType min) { m_min = min; }
318  void DoSetMax(LongestValueType max) { m_max = max; }
319 
320  bool IsInRange(LongestValueType value) const
321  {
322  return m_min <= value && value <= m_max;
323  }
324 
325  // Implement NumValidatorBase pure virtual method.
326  bool IsCharOk(const wxString& val, int pos, wxChar ch) const override;
327  bool DoValidateNumber(TranslatableString * errMsg) const override;
328 
329 private:
330  // Minimal and maximal values accepted (inclusive).
331  LongestValueType m_min, m_max;
332 
333  DECLARE_NO_ASSIGN_CLASS(IntegerValidatorBase)
334 };
335 
336 // Validator for integer numbers. It can actually work with any integer type
337 // (short, int or long and long long if supported) and their unsigned versions
338 // as well.
339 template <typename T>
340 class IntegerValidator final
341  : public Private::NumValidator<IntegerValidatorBase, T>
342 {
343 public:
344  typedef T ValueType;
345 
346  typedef
347  Private::NumValidator<IntegerValidatorBase, T> Base;
348 
349  // Ctor for an integer validator.
350  //
351  // Sets the range appropriately for the type, including setting 0 as the
352  // minimal value for the unsigned types.
353  IntegerValidator(
354  ValueType *value = NULL,
355  NumValidatorStyle style = NumValidatorStyle::DEFAULT,
357  ValueType max = std::numeric_limits<ValueType>::max())
358  : Base(value, style)
359  {
360  this->SetRange(min, max);
361  }
362 
363  // Clone is required by wxwidgets; implemented via copy constructor
364  wxObject *Clone() const override { return safenew IntegerValidator(*this); }
365 
366 private:
367  DECLARE_NO_ASSIGN_CLASS(IntegerValidator)
368 };
369 
370 // Helper function for creating integer validators which allows to avoid
371 // explicitly specifying the type as it deduces it from its parameter.
372 template <typename T>
373 inline IntegerValidator<T>
374 MakeIntegerValidator(T *value, NumValidatorStyle style = NumValidatorStyle::DEFAULT)
375 {
376  return IntegerValidator<T>(value, style);
377 }
378 
379 // ----------------------------------------------------------------------------
380 // Validators for floating point numbers.
381 // ----------------------------------------------------------------------------
382 
383 // Similar to IntegerValidatorBase, this class is not meant to be used
384 // directly, only FloatingPointValidator<> should be used in the user code.
385 class AUDACITY_DLL_API FloatingPointValidatorBase /* not final */
386  : public NumValidatorBase
387 {
388 public:
389  // Set precision i.e. the number of digits shown (and accepted on input)
390  // after the decimal point. By default this is set to the maximal precision
391  // supported by the type handled by the validator.
392  void SetPrecision(unsigned precision) { m_precision = precision; }
393 
394 protected:
395  // Notice that we can't use "long double" here because it's not supported
396  // by NumberFormatter yet, so restrict ourselves to just double (and
397  // float).
398  typedef double LongestValueType;
399 
400  FloatingPointValidatorBase(NumValidatorStyle style)
401  : NumValidatorBase(style)
402  {
403  }
404 
405  FloatingPointValidatorBase(const FloatingPointValidatorBase& other)
406  : NumValidatorBase(other)
407  {
408  m_precision = other.m_precision;
409 
410  m_min = other.m_min;
411  m_max = other.m_max;
412  }
413 
414  // Provide methods for NumValidator use.
415  wxString ToString(LongestValueType value) const;
416  static bool FromString(const wxString& s, LongestValueType *value);
417 
418  void DoSetMin(LongestValueType min) { m_min = min; }
419  void DoSetMax(LongestValueType max) { m_max = max; }
420 
421  bool IsInRange(LongestValueType value) const
422  {
423  return m_min <= value && value <= m_max;
424  }
425 
426  // Implement NumValidatorBase pure virtual method.
427  bool IsCharOk(const wxString& val, int pos, wxChar ch) const override;
428  bool DoValidateNumber(TranslatableString * errMsg) const override;
429 
430  //Checks that it doesn't have too many decimal digits.
431  bool ValidatePrecision(const wxString& s) const;
432 
433 private:
434  // Maximum number of decimals digits after the decimal separator.
435  unsigned m_precision;
436 
437  // Minimal and maximal values accepted (inclusive).
438  LongestValueType m_min, m_max;
439 
440  DECLARE_NO_ASSIGN_CLASS(FloatingPointValidatorBase)
441 };
442 
443 // Validator for floating point numbers. It can be used with float, double or
444 // long double values.
445 template <typename T>
446 class FloatingPointValidator final
447  : public Private::NumValidator<FloatingPointValidatorBase, T>
448 {
449 public:
450  typedef T ValueType;
451  typedef Private::NumValidator<FloatingPointValidatorBase, T> Base;
452 
453  // Ctor using implicit (maximal) precision for this type.
454  FloatingPointValidator(ValueType *value = NULL,
455  NumValidatorStyle style = NumValidatorStyle::DEFAULT)
456  : Base(value, style)
457  {
458  DoSetMinMax();
459 
460  this->SetPrecision(std::numeric_limits<ValueType>::digits10);
461  }
462 
463  // Ctor specifying an explicit precision.
464  FloatingPointValidator(int precision,
465  ValueType *value = NULL,
466  NumValidatorStyle style = NumValidatorStyle::DEFAULT,
467  ValueType min = std::numeric_limits<ValueType>::lowest(),
468  ValueType max = std::numeric_limits<ValueType>::max())
469  : Base(value, style)
470  {
471  this->SetRange( min, max );
472 
473  this->SetPrecision(precision);
474  }
475 
476  // Clone is required by wxwidgets; implemented via copy constructor
477  wxObject *Clone() const override
478  {
479  return safenew FloatingPointValidator(*this);
480  }
481 
482 private:
483  void DoSetMinMax()
484  {
485  // NB: Do not use min(), it's not the smallest representable value for
486  // the floating point types but rather the smallest representable
487  // positive value.
488  this->DoSetMin( std::numeric_limits<ValueType>::lowest());
489  this->DoSetMax( std::numeric_limits<ValueType>::max());
490  }
491 };
492 
493 // Helper similar to MakeIntValidator().
494 //
495 // NB: Unfortunately we can't just have a MakeNumericValidator() which would
496 // return either IntegerValidator<> or FloatingPointValidator<> so we
497 // do need two different functions.
498 template <typename T>
499 inline FloatingPointValidator<T>
500 MakeFloatingPointValidator(T *value, NumValidatorStyle style = NumValidatorStyle::DEFAULT)
501 {
502  return FloatingPointValidator<T>(value, style);
503 }
504 
505 template <typename T>
506 inline FloatingPointValidator<T>
507 MakeFloatingPointValidator(int precision, T *value, NumValidatorStyle style = NumValidatorStyle::DEFAULT)
508 {
509  return FloatingPointValidator<T>(precision, value, style);
510 }
511 
512 // Sometimes useful for specifying max and min values for validators, when they
513 // must have the same precision as the validated value
514 AUDACITY_DLL_API double RoundValue(int precision, double value);
515 
516 #endif // wxUSE_VALIDATORS
517 
518 #endif // _WIDGETS_VALNUM_H_
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
operator|
UndoPush operator|(UndoPush a, UndoPush b)
Definition: UndoManager.h:128
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
operator&
UndoPush operator&(UndoPush a, UndoPush b)
Definition: UndoManager.h:130
safenew
#define safenew
Definition: MemoryX.h:10