Merge branch 'valnum-unsigned'

Fix handling of unsigned types in numeric validators: don't accept
negative numbers as unsigned, allow using the full 64-bit range.

See https://github.com/wxWidgets/wxWidgets/pull/2244

Closes #12967.
This commit is contained in:
Vadim Zeitlin
2021-02-23 21:50:23 +01:00
7 changed files with 481 additions and 388 deletions

View File

@@ -34,6 +34,8 @@ public:
static wxString ToString(wxLongLong_t val,
int style = Style_WithThousandsSep);
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
static wxString ToString(wxULongLong_t val,
int style = Style_WithThousandsSep);
static wxString ToString(double val,
int precision,
int style = Style_WithThousandsSep);
@@ -46,6 +48,7 @@ public:
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
static bool FromString(wxString s, wxLongLong_t *val);
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
static bool FromString(wxString s, wxULongLong_t *val);
static bool FromString(wxString s, double *val);

View File

@@ -79,11 +79,6 @@ protected:
// 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
@@ -92,6 +87,11 @@ protected:
return val;
}
// Return true if this control allows negative numbers in it.
//
// If it doesn't, we don't allow entering "-" at all.
virtual bool CanBeNegative() const = 0;
private:
// Check whether the specified character can be inserted in the control at
// the given position in the string representing the current controls
@@ -114,6 +114,11 @@ private:
// Determine the current insertion point and text in the associated control.
void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const;
// Return true if pressing a '-' key is acceptable for the current control
// contents and insertion point. This is used by OnChar() to handle '-' and
// relies on CanBeNegative() implementation in the derived class.
bool IsMinusOk(const wxString& val, int pos) const;
// Combination of wxVAL_NUM_XXX values.
int m_style;
@@ -154,22 +159,22 @@ public:
void SetMin(ValueType min)
{
this->DoSetMin(static_cast<LongestValueType>(min));
m_min = min;
}
ValueType GetMin() const
{
return static_cast<ValueType>(this->DoGetMin());
return m_min;
}
void SetMax(ValueType max)
{
this->DoSetMax(static_cast<LongestValueType>(max));
m_max = max;
}
ValueType GetMax() const
{
return static_cast<ValueType>(this->DoGetMax());
return m_max;
}
void SetRange(ValueType min, ValueType max)
@@ -238,6 +243,9 @@ protected:
: wxString();
}
virtual bool CanBeNegative() const wxOVERRIDE { return m_min < 0; }
// This member is protected because it can be useful to the derived classes
// in their Transfer{From,To}Window() implementations.
ValueType * const m_value;
@@ -261,6 +269,8 @@ private:
return s;
}
// Minimal and maximal values accepted (inclusive).
ValueType m_min, m_max;
wxDECLARE_NO_ASSIGN_CLASS(wxNumValidator);
};
@@ -283,8 +293,10 @@ protected:
// on it.
#ifdef wxLongLong_t
typedef wxLongLong_t LongestValueType;
typedef wxULongLong_t ULongestValueType;
#else
typedef long LongestValueType;
typedef unsigned long ULongestValueType;
#endif
wxIntegerValidatorBase(int style)
@@ -294,34 +306,18 @@ protected:
"This style doesn't make sense for integers." );
}
wxIntegerValidatorBase(const wxIntegerValidatorBase& other)
: wxNumValidatorBase(other)
{
m_min = other.m_min;
m_max = other.m_max;
}
// Default copy ctor is ok.
// Provide methods for wxNumValidator use.
wxString ToString(LongestValueType value) const;
static bool FromString(const wxString& s, LongestValueType *value);
bool FromString(const wxString& s, LongestValueType *value) const;
void DoSetMin(LongestValueType min) { m_min = min; }
LongestValueType DoGetMin() const { return m_min; }
void DoSetMax(LongestValueType max) { m_max = max; }
LongestValueType DoGetMax() const { return m_max; }
bool IsInRange(LongestValueType value) const
{
return m_min <= value && value <= m_max;
}
virtual bool IsInRange(LongestValueType value) const = 0;
// Implement wxNumValidatorBase pure virtual method.
virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const wxOVERRIDE;
private:
// Minimal and maximal values accepted (inclusive).
LongestValueType m_min, m_max;
wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidatorBase);
};
@@ -337,6 +333,8 @@ public:
typedef
wxPrivate::wxNumValidator<wxIntegerValidatorBase, T> Base;
typedef
wxIntegerValidatorBase::LongestValueType LongestValueType;
// Ctor for an integer validator.
//
@@ -345,12 +343,30 @@ public:
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());
this->SetMin(std::numeric_limits<ValueType>::min());
this->SetMax(std::numeric_limits<ValueType>::max());
}
virtual wxObject *Clone() const wxOVERRIDE { return new wxIntegerValidator(*this); }
virtual bool IsInRange(LongestValueType value) const wxOVERRIDE
{
// LongestValueType is used as a container for the values of any type
// which can be used in type-independent wxIntegerValidatorBase code,
// but we need to use the correct type for comparisons, notably for
// comparing unsigned values correctly, so cast to this type and check
// that we don't lose precision while doing it.
const ValueType valueT = static_cast<ValueType>(value);
if ( static_cast<LongestValueType>(valueT) != value )
{
// The conversion wasn't lossless, so the value must not be exactly
// representable in this type and so is definitely not in range.
return false;
}
return this->GetMin() <= valueT && valueT <= this->GetMax();
}
private:
wxDECLARE_NO_ASSIGN_CLASS(wxIntegerValidator);
};
@@ -395,29 +411,13 @@ protected:
m_factor = 1.0;
}
wxFloatingPointValidatorBase(const wxFloatingPointValidatorBase& other)
: wxNumValidatorBase(other)
{
m_precision = other.m_precision;
m_factor = other.m_factor;
m_min = other.m_min;
m_max = other.m_max;
}
// Default copy ctor is ok.
// Provide methods for wxNumValidator use.
wxString ToString(LongestValueType value) const;
bool FromString(const wxString& s, LongestValueType *value) const;
void DoSetMin(LongestValueType min) { m_min = min; }
LongestValueType DoGetMin() const { return m_min; }
void DoSetMax(LongestValueType max) { m_max = max; }
LongestValueType DoGetMax() const { return m_max; }
bool IsInRange(LongestValueType value) const
{
return m_min <= value && value <= m_max;
}
virtual bool IsInRange(LongestValueType value) const = 0;
// Implement wxNumValidatorBase pure virtual method.
virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const wxOVERRIDE;
@@ -429,9 +429,6 @@ private:
// Factor applied for the displayed the value.
double m_factor;
// Minimal and maximal values accepted (inclusive).
LongestValueType m_min, m_max;
wxDECLARE_NO_ASSIGN_CLASS(wxFloatingPointValidatorBase);
};
@@ -444,6 +441,8 @@ class wxFloatingPointValidator
public:
typedef T ValueType;
typedef wxPrivate::wxNumValidator<wxFloatingPointValidatorBase, T> Base;
typedef wxFloatingPointValidatorBase::LongestValueType LongestValueType;
// Ctor using implicit (maximal) precision for this type.
wxFloatingPointValidator(ValueType *value = NULL,
@@ -471,16 +470,21 @@ public:
return new wxFloatingPointValidator(*this);
}
private:
typedef typename Base::LongestValueType LongestValueType;
virtual bool IsInRange(LongestValueType value) const wxOVERRIDE
{
const ValueType valueT = static_cast<ValueType>(value);
return this->GetMin() <= valueT && valueT <= this->GetMax();
}
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(static_cast<LongestValueType>(-std::numeric_limits<ValueType>::max()));
this->DoSetMax(static_cast<LongestValueType>( std::numeric_limits<ValueType>::max()));
this->SetMin(-std::numeric_limits<ValueType>::max());
this->SetMax( std::numeric_limits<ValueType>::max());
}
};