1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Numeric validator classes.
4 // Author: Vadim Zeitlin based on the submission of Fulvio Senore
6 // Copyright: (c) 2010 wxWidgets team
7 // (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
18 #include "wx/validate.h"
22 // Bit masks used for numeric validator styles.
23 enum wxNumValidatorStyle
25 wxNUM_VAL_DEFAULT
= 0x0,
26 wxNUM_VAL_THOUSANDS_SEPARATOR
= 0x1,
27 wxNUM_VAL_ZERO_AS_BLANK
= 0x2,
28 wxNUM_VAL_NO_TRAILING_ZEROES
= 0x4
31 // ----------------------------------------------------------------------------
32 // Base class for all numeric validators.
33 // ----------------------------------------------------------------------------
35 class WXDLLIMPEXP_CORE wxNumValidatorBase
: public wxValidator
38 // Change the validator style. Usually it's specified during construction.
39 void SetStyle(int style
) { m_style
= style
; }
42 // Override base class method to not do anything but always return success:
43 // we don't need this as we do our validation on the fly here.
44 virtual bool Validate(wxWindow
* WXUNUSED(parent
)) { return true; }
47 wxNumValidatorBase(int style
)
52 wxNumValidatorBase(const wxNumValidatorBase
& other
)
54 m_style
= other
.m_style
;
57 bool HasFlag(wxNumValidatorStyle style
) const
59 return (m_style
& style
) != 0;
62 // Get the text entry of the associated control. Normally shouldn't ever
63 // return NULL (and will assert if it does return it) but the caller should
64 // still test the return value for safety.
65 wxTextEntry
*GetTextEntry() const;
67 // Convert wxNUM_VAL_THOUSANDS_SEPARATOR and wxNUM_VAL_NO_TRAILING_ZEROES
68 // bits of our style to the corresponding wxNumberFormatter::Style values.
69 int GetFormatFlags() const;
71 // Return true if pressing a '-' key is acceptable for the current control
72 // contents and insertion point. This is meant to be called from the
73 // derived class IsCharOk() implementation.
74 bool IsMinusOk(const wxString
& val
, int pos
) const;
76 // Return the string which would result from inserting the given character
77 // at the specified position.
78 wxString
GetValueAfterInsertingChar(wxString val
, int pos
, wxChar ch
) const
85 // Check whether the specified character can be inserted in the control at
86 // the given position in the string representing the current controls
89 // Notice that the base class checks for '-' itself so it's never passed to
91 virtual bool IsCharOk(const wxString
& val
, int pos
, wxChar ch
) const = 0;
93 // NormalizeString the contents of the string if it's a valid number, return
94 // empty string otherwise.
95 virtual wxString
NormalizeString(const wxString
& s
) const = 0;
99 void OnChar(wxKeyEvent
& event
);
100 void OnKillFocus(wxFocusEvent
& event
);
103 // Determine the current insertion point and text in the associated control.
104 void GetCurrentValueAndInsertionPoint(wxString
& val
, int& pos
) const;
107 // Combination of wxVAL_NUM_XXX values.
111 wxDECLARE_EVENT_TABLE();
113 wxDECLARE_NO_ASSIGN_CLASS(wxNumValidatorBase
);
119 // This is a helper class used by wxIntegerValidator and wxFloatingPointValidator
120 // below that implements Transfer{To,From}Window() adapted to the type of the
123 // The template argument B is the name of the base class which must derive from
124 // wxNumValidatorBase and define LongestValueType type and {To,As}String()
125 // methods i.e. basically be one of wx{Integer,Number}ValidatorBase classes.
127 // The template argument T is just the type handled by the validator that will
128 // inherit from this one.
129 template <class B
, typename T
>
130 class wxNumValidator
: public B
133 typedef B BaseValidator
;
136 typedef typename
BaseValidator::LongestValueType LongestValueType
;
138 // FIXME-VC6: This compiler fails to compile the assert below with a
139 // nonsensical error C2248: "'LongestValueType' : cannot access protected
140 // typedef declared in class 'wxIntegerValidatorBase'" so just disable the
143 wxCOMPILE_TIME_ASSERT
145 sizeof(ValueType
) <= sizeof(LongestValueType
),
148 #endif // __VISUALC6__
150 void SetMin(ValueType min
)
155 void SetMax(ValueType max
)
160 void SetRange(ValueType min
, ValueType max
)
166 virtual bool TransferToWindow()
170 wxTextEntry
* const control
= BaseValidator::GetTextEntry();
174 control
->SetValue(NormalizeValue(*m_value
));
180 virtual bool TransferFromWindow()
184 wxTextEntry
* const control
= BaseValidator::GetTextEntry();
188 const wxString
s(control
->GetValue());
189 LongestValueType value
;
190 if ( s
.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK
) )
192 else if ( !BaseValidator::FromString(s
, &value
) )
195 if ( !this->IsInRange(value
) )
198 *m_value
= static_cast<ValueType
>(value
);
205 wxNumValidator(ValueType
*value
, int style
)
206 : BaseValidator(style
),
211 // Implement wxNumValidatorBase virtual method which is the same for
212 // both integer and floating point numbers.
213 virtual wxString
NormalizeString(const wxString
& s
) const
215 LongestValueType value
;
216 return BaseValidator::FromString(s
, &value
) ? NormalizeValue(value
)
221 // Just a helper which is a common part of TransferToWindow() and
222 // NormalizeString(): returns string representation of a number honouring
223 // wxNUM_VAL_ZERO_AS_BLANK flag.
224 wxString
NormalizeValue(LongestValueType value
) const
227 if ( value
!= 0 || !BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK
) )
228 s
= this->ToString(value
);
234 ValueType
* const m_value
;
236 wxDECLARE_NO_ASSIGN_CLASS(wxNumValidator
);
239 } // namespace wxPrivate
241 // ----------------------------------------------------------------------------
242 // Validators for integer numbers.
243 // ----------------------------------------------------------------------------
245 // Base class for integer numbers validator. This class contains all non
246 // type-dependent code of wxIntegerValidator<> and always works with values of
247 // type LongestValueType. It is not meant to be used directly, please use
248 // wxIntegerValidator<> only instead.
249 class WXDLLIMPEXP_CORE wxIntegerValidatorBase
: public wxNumValidatorBase
252 // Define the type we use here, it should be the maximal-sized integer type
253 // we support to make it possible to base wxIntegerValidator<> for any type
256 typedef wxLongLong_t LongestValueType
;
258 typedef long LongestValueType
;
261 wxIntegerValidatorBase(int style
)
262 : wxNumValidatorBase(style
)
264 wxASSERT_MSG( !(style
& wxNUM_VAL_NO_TRAILING_ZEROES
),
265 "This style doesn't make sense for integers." );
268 wxIntegerValidatorBase(const wxIntegerValidatorBase
& other
)
269 : wxNumValidatorBase(other
)
275 // Provide methods for wxNumValidator use.
276 wxString
ToString(LongestValueType value
) const;
277 static bool FromString(const wxString
& s
, LongestValueType
*value
);
279 void DoSetMin(LongestValueType min
) { m_min
= min
; }
280 void DoSetMax(LongestValueType max
) { m_max
= max
; }
282 bool IsInRange(LongestValueType value
) const
284 return m_min
<= value
&& value
<= m_max
;
287 // Implement wxNumValidatorBase pure virtual method.
288 virtual bool IsCharOk(const wxString
& val
, int pos
, wxChar ch
) const;
291 // Minimal and maximal values accepted (inclusive).
292 LongestValueType m_min
, m_max
;
294 wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidatorBase
);
297 // Validator for integer numbers. It can actually work with any integer type
298 // (short, int or long and long long if supported) and their unsigned versions
300 template <typename T
>
301 class wxIntegerValidator
302 : public wxPrivate::wxNumValidator
<wxIntegerValidatorBase
, T
>
308 wxPrivate::wxNumValidator
<wxIntegerValidatorBase
, T
> Base
;
310 // Ctor for an integer validator.
312 // Sets the range appropriately for the type, including setting 0 as the
313 // minimal value for the unsigned types.
314 wxIntegerValidator(ValueType
*value
= NULL
, int style
= wxNUM_VAL_DEFAULT
)
317 this->DoSetMin(std::numeric_limits
<ValueType
>::min());
318 this->DoSetMax(std::numeric_limits
<ValueType
>::max());
321 virtual wxObject
*Clone() const { return new wxIntegerValidator(*this); }
324 wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidator
);
327 // Helper function for creating integer validators which allows to avoid
328 // explicitly specifying the type as it deduces it from its parameter.
329 template <typename T
>
330 inline wxIntegerValidator
<T
>
331 wxMakeIntegerValidator(T
*value
, int style
= wxNUM_VAL_DEFAULT
)
333 return wxIntegerValidator
<T
>(value
, style
);
336 // ----------------------------------------------------------------------------
337 // Validators for floating point numbers.
338 // ----------------------------------------------------------------------------
340 // Similar to wxIntegerValidatorBase, this class is not meant to be used
341 // directly, only wxFloatingPointValidator<> should be used in the user code.
342 class WXDLLIMPEXP_CORE wxFloatingPointValidatorBase
: public wxNumValidatorBase
345 // Set precision i.e. the number of digits shown (and accepted on input)
346 // after the decimal point. By default this is set to the maximal precision
347 // supported by the type handled by the validator.
348 void SetPrecision(unsigned precision
) { m_precision
= precision
; }
351 // Notice that we can't use "long double" here because it's not supported
352 // by wxNumberFormatter yet, so restrict ourselves to just double (and
354 typedef double LongestValueType
;
356 wxFloatingPointValidatorBase(int style
)
357 : wxNumValidatorBase(style
)
361 wxFloatingPointValidatorBase(const wxFloatingPointValidatorBase
& other
)
362 : wxNumValidatorBase(other
)
364 m_precision
= other
.m_precision
;
370 // Provide methods for wxNumValidator use.
371 wxString
ToString(LongestValueType value
) const;
372 static bool FromString(const wxString
& s
, LongestValueType
*value
);
374 void DoSetMin(LongestValueType min
) { m_min
= min
; }
375 void DoSetMax(LongestValueType max
) { m_max
= max
; }
377 bool IsInRange(LongestValueType value
) const
379 return m_min
<= value
&& value
<= m_max
;
382 // Implement wxNumValidatorBase pure virtual method.
383 virtual bool IsCharOk(const wxString
& val
, int pos
, wxChar ch
) const;
386 // Maximum number of decimals digits after the decimal separator.
387 unsigned m_precision
;
389 // Minimal and maximal values accepted (inclusive).
390 LongestValueType m_min
, m_max
;
392 wxDECLARE_NO_ASSIGN_CLASS(wxFloatingPointValidatorBase
);
395 // Validator for floating point numbers. It can be used with float, double or
396 // long double values.
397 template <typename T
>
398 class wxFloatingPointValidator
399 : public wxPrivate::wxNumValidator
<wxFloatingPointValidatorBase
, T
>
403 typedef wxPrivate::wxNumValidator
<wxFloatingPointValidatorBase
, T
> Base
;
405 // Ctor using implicit (maximal) precision for this type.
406 wxFloatingPointValidator(ValueType
*value
= NULL
,
407 int style
= wxNUM_VAL_DEFAULT
)
412 this->SetPrecision(std::numeric_limits
<ValueType
>::digits10
);
415 // Ctor specifying an explicit precision.
416 wxFloatingPointValidator(int precision
,
417 ValueType
*value
= NULL
,
418 int style
= wxNUM_VAL_DEFAULT
)
423 this->SetPrecision(precision
);
426 virtual wxObject
*Clone() const
428 return new wxFloatingPointValidator(*this);
434 // NB: Do not use min(), it's not the smallest representable value for
435 // the floating point types but rather the smallest representable
437 this->DoSetMin(-std::numeric_limits
<ValueType
>::max());
438 this->DoSetMax( std::numeric_limits
<ValueType
>::max());
442 // Helper similar to wxMakeIntValidator().
444 // NB: Unfortunately we can't just have a wxMakeNumericValidator() which would
445 // return either wxIntegerValidator<> or wxFloatingPointValidator<> so we
446 // do need two different functions.
447 template <typename T
>
448 inline wxFloatingPointValidator
<T
>
449 wxMakeFloatingPointValidator(T
*value
, int style
= wxNUM_VAL_DEFAULT
)
451 return wxFloatingPointValidator
<T
>(value
, style
);
454 template <typename T
>
455 inline wxFloatingPointValidator
<T
>
456 wxMakeFloatingPointValidator(int precision
, T
*value
, int style
= wxNUM_VAL_DEFAULT
)
458 return wxFloatingPointValidator
<T
>(precision
, value
, style
);
461 #endif // wxUSE_VALIDATORS
463 #endif // _WX_VALNUM_H_