git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67215 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			464 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			464 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| // Name:        wx/valnum.h
 | |
| // Purpose:     Numeric validator classes.
 | |
| // Author:      Vadim Zeitlin based on the submission of Fulvio Senore
 | |
| // Created:     2010-11-06
 | |
| // Copyright:   (c) 2010 wxWidgets team
 | |
| //              (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
 | |
| // Licence:     wxWindows licence
 | |
| /////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #ifndef _WX_VALNUM_H_
 | |
| #define _WX_VALNUM_H_
 | |
| 
 | |
| #include "wx/defs.h"
 | |
| 
 | |
| #if wxUSE_VALIDATORS
 | |
| 
 | |
| #include "wx/validate.h"
 | |
| 
 | |
| #include <limits>
 | |
| 
 | |
| // Bit masks used for numeric validator styles.
 | |
| enum wxNumValidatorStyle
 | |
| {
 | |
|     wxNUM_VAL_DEFAULT               = 0x0,
 | |
|     wxNUM_VAL_THOUSANDS_SEPARATOR   = 0x1,
 | |
|     wxNUM_VAL_ZERO_AS_BLANK         = 0x2,
 | |
|     wxNUM_VAL_NO_TRAILING_ZEROES    = 0x4
 | |
| };
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // Base class for all numeric validators.
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| class WXDLLIMPEXP_CORE wxNumValidatorBase : public wxValidator
 | |
| {
 | |
| public:
 | |
|     // Change the validator style. Usually it's specified during construction.
 | |
|     void SetStyle(int style) { m_style = style; }
 | |
| 
 | |
| 
 | |
|     // Override base class method to not do anything but always return success:
 | |
|     // we don't need this as we do our validation on the fly here.
 | |
|     virtual bool Validate(wxWindow * WXUNUSED(parent)) { return true; }
 | |
| 
 | |
| protected:
 | |
|     wxNumValidatorBase(int style)
 | |
|     {
 | |
|         m_style = style;
 | |
|     }
 | |
| 
 | |
|     wxNumValidatorBase(const wxNumValidatorBase& other) : wxValidator()
 | |
|     {
 | |
|         m_style = other.m_style;
 | |
|     }
 | |
| 
 | |
|     bool HasFlag(wxNumValidatorStyle style) const
 | |
|     {
 | |
|         return (m_style & style) != 0;
 | |
|     }
 | |
| 
 | |
|     // Get the text entry of the associated control. Normally shouldn't ever
 | |
|     // return NULL (and will assert if it does return it) but the caller should
 | |
|     // still test the return value for safety.
 | |
|     wxTextEntry *GetTextEntry() const;
 | |
| 
 | |
|     // Convert wxNUM_VAL_THOUSANDS_SEPARATOR and wxNUM_VAL_NO_TRAILING_ZEROES
 | |
|     // bits of our style to the corresponding wxNumberFormatter::Style values.
 | |
|     int GetFormatFlags() const;
 | |
| 
 | |
|     // Return true if pressing a '-' key is acceptable for the current control
 | |
|     // contents and insertion point. This is meant to be called from the
 | |
|     // derived class IsCharOk() implementation.
 | |
|     bool IsMinusOk(const wxString& val, int pos) const;
 | |
| 
 | |
|     // Return the string which would result from inserting the given character
 | |
|     // at the specified position.
 | |
|     wxString GetValueAfterInsertingChar(wxString val, int pos, wxChar ch) const
 | |
|     {
 | |
|         val.insert(pos, ch);
 | |
|         return val;
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     // Check whether the specified character can be inserted in the control at
 | |
|     // the given position in the string representing the current controls
 | |
|     // contents.
 | |
|     //
 | |
|     // Notice that the base class checks for '-' itself so it's never passed to
 | |
|     // this function.
 | |
|     virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const = 0;
 | |
| 
 | |
|     // NormalizeString the contents of the string if it's a valid number, return
 | |
|     // empty string otherwise.
 | |
|     virtual wxString NormalizeString(const wxString& s) const = 0;
 | |
| 
 | |
| 
 | |
|     // Event handlers.
 | |
|     void OnChar(wxKeyEvent& event);
 | |
|     void OnKillFocus(wxFocusEvent& event);
 | |
| 
 | |
| 
 | |
|     // Determine the current insertion point and text in the associated control.
 | |
|     void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const;
 | |
| 
 | |
| 
 | |
|     // Combination of wxVAL_NUM_XXX values.
 | |
|     int m_style;
 | |
| 
 | |
| 
 | |
|     wxDECLARE_EVENT_TABLE();
 | |
| 
 | |
|     wxDECLARE_NO_ASSIGN_CLASS(wxNumValidatorBase);
 | |
| };
 | |
| 
 | |
| namespace wxPrivate
 | |
| {
 | |
| 
 | |
| // This is a helper class used by wxIntegerValidator and wxFloatingPointValidator
 | |
| // below that implements Transfer{To,From}Window() adapted to the type of the
 | |
| // variable.
 | |
| //
 | |
| // The template argument B is the name of the base class which must derive from
 | |
| // wxNumValidatorBase and define LongestValueType type and {To,As}String()
 | |
| // methods i.e. basically be one of wx{Integer,Number}ValidatorBase classes.
 | |
| //
 | |
| // The template argument T is just the type handled by the validator that will
 | |
| // inherit from this one.
 | |
| template <class B, typename T>
 | |
| class wxNumValidator : public B
 | |
| {
 | |
| public:
 | |
|     typedef B BaseValidator;
 | |
|     typedef T ValueType;
 | |
| 
 | |
|     typedef typename BaseValidator::LongestValueType LongestValueType;
 | |
| 
 | |
|     // FIXME-VC6: This compiler fails to compile the assert below with a
 | |
|     // nonsensical error C2248: "'LongestValueType' : cannot access protected
 | |
|     // typedef declared in class 'wxIntegerValidatorBase'" so just disable the
 | |
|     // check for it.
 | |
| #ifndef __VISUALC6__
 | |
|     wxCOMPILE_TIME_ASSERT
 | |
|     (
 | |
|         sizeof(ValueType) <= sizeof(LongestValueType),
 | |
|         UnsupportedType
 | |
|     );
 | |
| #endif // __VISUALC6__
 | |
| 
 | |
|     void SetMin(ValueType min)
 | |
|     {
 | |
|         this->DoSetMin(min);
 | |
|     }
 | |
| 
 | |
|     void SetMax(ValueType max)
 | |
|     {
 | |
|         this->DoSetMax(max);
 | |
|     }
 | |
| 
 | |
|     void SetRange(ValueType min, ValueType max)
 | |
|     {
 | |
|         SetMin(min);
 | |
|         SetMax(max);
 | |
|     }
 | |
| 
 | |
|     virtual bool TransferToWindow()
 | |
|     {
 | |
|         if ( m_value )
 | |
|         {
 | |
|             wxTextEntry * const control = BaseValidator::GetTextEntry();
 | |
|             if ( !control )
 | |
|                 return false;
 | |
| 
 | |
|             control->SetValue(NormalizeValue(*m_value));
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     virtual bool TransferFromWindow()
 | |
|     {
 | |
|         if ( m_value )
 | |
|         {
 | |
|             wxTextEntry * const control = BaseValidator::GetTextEntry();
 | |
|             if ( !control )
 | |
|                 return false;
 | |
| 
 | |
|             const wxString s(control->GetValue());
 | |
|             LongestValueType value;
 | |
|             if ( s.empty() && BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
 | |
|                 value = 0;
 | |
|             else if ( !BaseValidator::FromString(s, &value) )
 | |
|                 return false;
 | |
| 
 | |
|             if ( !this->IsInRange(value) )
 | |
|                 return false;
 | |
| 
 | |
|             *m_value = static_cast<ValueType>(value);
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
| protected:
 | |
|     wxNumValidator(ValueType *value, int style)
 | |
|         : BaseValidator(style),
 | |
|           m_value(value)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     // Implement wxNumValidatorBase virtual method which is the same for
 | |
|     // both integer and floating point numbers.
 | |
|     virtual wxString NormalizeString(const wxString& s) const
 | |
|     {
 | |
|         LongestValueType value;
 | |
|         return BaseValidator::FromString(s, &value) ? NormalizeValue(value)
 | |
|                                                     : wxString();
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     // Just a helper which is a common part of TransferToWindow() and
 | |
|     // NormalizeString(): returns string representation of a number honouring
 | |
|     // wxNUM_VAL_ZERO_AS_BLANK flag.
 | |
|     wxString NormalizeValue(LongestValueType value) const
 | |
|     {
 | |
|         wxString s;
 | |
|         if ( value != 0 || !BaseValidator::HasFlag(wxNUM_VAL_ZERO_AS_BLANK) )
 | |
|             s = this->ToString(value);
 | |
| 
 | |
|         return s;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     ValueType * const m_value;
 | |
| 
 | |
|     wxDECLARE_NO_ASSIGN_CLASS(wxNumValidator);
 | |
| };
 | |
| 
 | |
| } // namespace wxPrivate
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // Validators for integer numbers.
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| // Base class for integer numbers validator. This class contains all non
 | |
| // type-dependent code of wxIntegerValidator<> and always works with values of
 | |
| // type LongestValueType. It is not meant to be used directly, please use
 | |
| // wxIntegerValidator<> only instead.
 | |
| class WXDLLIMPEXP_CORE wxIntegerValidatorBase : public wxNumValidatorBase
 | |
| {
 | |
| protected:
 | |
|     // Define the type we use here, it should be the maximal-sized integer type
 | |
|     // we support to make it possible to base wxIntegerValidator<> for any type
 | |
|     // on it.
 | |
| #ifdef wxLongLong_t
 | |
|     typedef wxLongLong_t LongestValueType;
 | |
| #else
 | |
|     typedef long LongestValueType;
 | |
| #endif
 | |
| 
 | |
|     wxIntegerValidatorBase(int style)
 | |
|         : wxNumValidatorBase(style)
 | |
|     {
 | |
|         wxASSERT_MSG( !(style & wxNUM_VAL_NO_TRAILING_ZEROES),
 | |
|                       "This style doesn't make sense for integers." );
 | |
|     }
 | |
| 
 | |
|     wxIntegerValidatorBase(const wxIntegerValidatorBase& other)
 | |
|         : wxNumValidatorBase(other)
 | |
|     {
 | |
|         m_min = other.m_min;
 | |
|         m_max = other.m_max;
 | |
|     }
 | |
| 
 | |
|     // Provide methods for wxNumValidator use.
 | |
|     wxString ToString(LongestValueType value) const;
 | |
|     static bool FromString(const wxString& s, LongestValueType *value);
 | |
| 
 | |
|     void DoSetMin(LongestValueType min) { m_min = min; }
 | |
|     void DoSetMax(LongestValueType max) { m_max = max; }
 | |
| 
 | |
|     bool IsInRange(LongestValueType value) const
 | |
|     {
 | |
|         return m_min <= value && value <= m_max;
 | |
|     }
 | |
| 
 | |
|     // Implement wxNumValidatorBase pure virtual method.
 | |
|     virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const;
 | |
| 
 | |
| private:
 | |
|     // Minimal and maximal values accepted (inclusive).
 | |
|     LongestValueType m_min, m_max;
 | |
| 
 | |
|     wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidatorBase);
 | |
| };
 | |
| 
 | |
| // Validator for integer numbers. It can actually work with any integer type
 | |
| // (short, int or long and long long if supported) and their unsigned versions
 | |
| // as well.
 | |
| template <typename T>
 | |
| class wxIntegerValidator
 | |
|     : public wxPrivate::wxNumValidator<wxIntegerValidatorBase, T>
 | |
| {
 | |
| public:
 | |
|     typedef T ValueType;
 | |
| 
 | |
|     typedef
 | |
|         wxPrivate::wxNumValidator<wxIntegerValidatorBase, T> Base;
 | |
| 
 | |
|     // Ctor for an integer validator.
 | |
|     //
 | |
|     // Sets the range appropriately for the type, including setting 0 as the
 | |
|     // minimal value for the unsigned types.
 | |
|     wxIntegerValidator(ValueType *value = NULL, int style = wxNUM_VAL_DEFAULT)
 | |
|         : Base(value, style)
 | |
|     {
 | |
|         this->DoSetMin(std::numeric_limits<ValueType>::min());
 | |
|         this->DoSetMax(std::numeric_limits<ValueType>::max());
 | |
|     }
 | |
| 
 | |
|     virtual wxObject *Clone() const { return new wxIntegerValidator(*this); }
 | |
| 
 | |
| private:
 | |
|     wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidator);
 | |
| };
 | |
| 
 | |
| // Helper function for creating integer validators which allows to avoid
 | |
| // explicitly specifying the type as it deduces it from its parameter.
 | |
| template <typename T>
 | |
| inline wxIntegerValidator<T>
 | |
| wxMakeIntegerValidator(T *value, int style = wxNUM_VAL_DEFAULT)
 | |
| {
 | |
|     return wxIntegerValidator<T>(value, style);
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // Validators for floating point numbers.
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| // Similar to wxIntegerValidatorBase, this class is not meant to be used
 | |
| // directly, only wxFloatingPointValidator<> should be used in the user code.
 | |
| class WXDLLIMPEXP_CORE wxFloatingPointValidatorBase : public wxNumValidatorBase
 | |
| {
 | |
| public:
 | |
|     // Set precision i.e. the number of digits shown (and accepted on input)
 | |
|     // after the decimal point. By default this is set to the maximal precision
 | |
|     // supported by the type handled by the validator.
 | |
|     void SetPrecision(unsigned precision) { m_precision = precision; }
 | |
| 
 | |
| protected:
 | |
|     // Notice that we can't use "long double" here because it's not supported
 | |
|     // by wxNumberFormatter yet, so restrict ourselves to just double (and
 | |
|     // float).
 | |
|     typedef double LongestValueType;
 | |
| 
 | |
|     wxFloatingPointValidatorBase(int style)
 | |
|         : wxNumValidatorBase(style)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     wxFloatingPointValidatorBase(const wxFloatingPointValidatorBase& other)
 | |
|         : wxNumValidatorBase(other)
 | |
|     {
 | |
|         m_precision = other.m_precision;
 | |
| 
 | |
|         m_min = other.m_min;
 | |
|         m_max = other.m_max;
 | |
|     }
 | |
| 
 | |
|     // Provide methods for wxNumValidator use.
 | |
|     wxString ToString(LongestValueType value) const;
 | |
|     static bool FromString(const wxString& s, LongestValueType *value);
 | |
| 
 | |
|     void DoSetMin(LongestValueType min) { m_min = min; }
 | |
|     void DoSetMax(LongestValueType max) { m_max = max; }
 | |
| 
 | |
|     bool IsInRange(LongestValueType value) const
 | |
|     {
 | |
|         return m_min <= value && value <= m_max;
 | |
|     }
 | |
| 
 | |
|     // Implement wxNumValidatorBase pure virtual method.
 | |
|     virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const;
 | |
| 
 | |
| private:
 | |
|     // Maximum number of decimals digits after the decimal separator.
 | |
|     unsigned m_precision;
 | |
| 
 | |
|     // Minimal and maximal values accepted (inclusive).
 | |
|     LongestValueType m_min, m_max;
 | |
| 
 | |
|     wxDECLARE_NO_ASSIGN_CLASS(wxFloatingPointValidatorBase);
 | |
| };
 | |
| 
 | |
| // Validator for floating point numbers. It can be used with float, double or
 | |
| // long double values.
 | |
| template <typename T>
 | |
| class wxFloatingPointValidator
 | |
|     : public wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T>
 | |
| {
 | |
| public:
 | |
|     typedef T ValueType;
 | |
|     typedef wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T> Base;
 | |
| 
 | |
|     // Ctor using implicit (maximal) precision for this type.
 | |
|     wxFloatingPointValidator(ValueType *value = NULL,
 | |
|                              int style = wxNUM_VAL_DEFAULT)
 | |
|         : Base(value, style)
 | |
|     {
 | |
|         DoSetMinMax();
 | |
| 
 | |
|         this->SetPrecision(std::numeric_limits<ValueType>::digits10);
 | |
|     }
 | |
| 
 | |
|     // Ctor specifying an explicit precision.
 | |
|     wxFloatingPointValidator(int precision,
 | |
|                       ValueType *value = NULL,
 | |
|                       int style = wxNUM_VAL_DEFAULT)
 | |
|         : Base(value, style)
 | |
|     {
 | |
|         DoSetMinMax();
 | |
| 
 | |
|         this->SetPrecision(precision);
 | |
|     }
 | |
| 
 | |
|     virtual wxObject *Clone() const
 | |
|     {
 | |
|         return new wxFloatingPointValidator(*this);
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     void DoSetMinMax()
 | |
|     {
 | |
|         // NB: Do not use min(), it's not the smallest representable value for
 | |
|         //     the floating point types but rather the smallest representable
 | |
|         //     positive value.
 | |
|         this->DoSetMin(-std::numeric_limits<ValueType>::max());
 | |
|         this->DoSetMax( std::numeric_limits<ValueType>::max());
 | |
|     }
 | |
| };
 | |
| 
 | |
| // Helper similar to wxMakeIntValidator().
 | |
| //
 | |
| // NB: Unfortunately we can't just have a wxMakeNumericValidator() which would
 | |
| //     return either wxIntegerValidator<> or wxFloatingPointValidator<> so we
 | |
| //     do need two different functions.
 | |
| template <typename T>
 | |
| inline wxFloatingPointValidator<T>
 | |
| wxMakeFloatingPointValidator(T *value, int style = wxNUM_VAL_DEFAULT)
 | |
| {
 | |
|     return wxFloatingPointValidator<T>(value, style);
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| inline wxFloatingPointValidator<T>
 | |
| wxMakeFloatingPointValidator(int precision, T *value, int style = wxNUM_VAL_DEFAULT)
 | |
| {
 | |
|     return wxFloatingPointValidator<T>(precision, value, style);
 | |
| }
 | |
| 
 | |
| #endif // wxUSE_VALIDATORS
 | |
| 
 | |
| #endif // _WX_VALNUM_H_
 |