From 48adc38bbb8c847a0587d5e07e865fd87a63e97e Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Fri, 28 Jun 2019 21:16:58 +0200 Subject: [PATCH] Refactor code for numeric validation in numeric wxPG properties Move template function NumericValidation() to wxNumericProperty because all data necessary to validate the value are available here: acceptable value range, SpinCtrl editor value wrapping mode, etc. --- include/wx/propgrid/props.h | 7 +- interface/wx/propgrid/props.h | 3 - src/propgrid/props.cpp | 273 ++++++++++++++++------------------ 3 files changed, 134 insertions(+), 149 deletions(-) diff --git a/include/wx/propgrid/props.h b/include/wx/propgrid/props.h index d7455479c1..72d252988f 100644 --- a/include/wx/propgrid/props.h +++ b/include/wx/propgrid/props.h @@ -166,10 +166,13 @@ public: virtual wxVariant AddSpinStepValue(long stepScale) const = 0; - wxVariant GetMinVal() const { return m_minVal; } - wxVariant GetMaxVal() const { return m_maxVal; } bool UseSpinMotion() const { return m_spinMotion; } + // Common validation code - for internal use. + template + bool DoNumericValidation(T& value, wxPGValidationInfo* pValidationInfo, + int mode, T defMin, T defMax) const; + protected: wxNumericProperty(const wxString& label, const wxString& name); diff --git a/interface/wx/propgrid/props.h b/interface/wx/propgrid/props.h index f0403ceca3..0bd8dc196c 100644 --- a/interface/wx/propgrid/props.h +++ b/interface/wx/propgrid/props.h @@ -146,9 +146,6 @@ public: */ bool UseSpinMotion() const; - wxVariant GetMinVal() const; - wxVariant GetMaxVal() const; - protected: /** Constructor is protected because wxNumericProperty is only a base diff --git a/src/propgrid/props.cpp b/src/propgrid/props.cpp index 8e3785cadb..68e0755aa1 100644 --- a/src/propgrid/props.cpp +++ b/src/propgrid/props.cpp @@ -261,6 +261,123 @@ bool wxNumericProperty::DoSetAttribute(const wxString& name, wxVariant& value) } return wxPGProperty::DoSetAttribute(name, value); } +namespace { + // This function by default doesn't modify the value. + // For argument 'value' of type 'double' there is a specialized function (below). + template + T GetRoundedValue(const wxPGProperty* prop, T value) + { + wxUnusedVar(prop); + return value; + } + + // Specialized function for floating-point values + // takes into account required precision of the numbers + // to avoid rounding and conversion errors. + template<> + double GetRoundedValue(const wxPGProperty* prop, double value) + { + // Round value to the required precision. + wxVariant variant = value; + wxString strVal = prop->ValueToString(variant, wxPG_FULL_VALUE); + strVal.ToDouble(&value); + return value; + } +} // namespace + +// Common validation code to be called in ValidateValue() implementations. +// Note that 'value' is reference on purpose, so we can write +// back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE or wxPG_PROPERTY_VALIDATION_WRAP. +template +bool wxNumericProperty::DoNumericValidation(T& value, wxPGValidationInfo* pValidationInfo, + int mode, T defMin, T defMax) const +{ + T min = defMin; + T max = defMax; + wxVariant variant; + bool minOk = false; + bool maxOk = false; + + // Round current value to the required precision, if applicable + value = GetRoundedValue(this, value); + + variant = m_minVal; + if ( !variant.IsNull() ) + { + minOk = variant.Convert(&min); + } + if ( minOk ) + { + // Round minimal value to the required precision, if applicable + min = GetRoundedValue(this, min); + } + + variant = m_maxVal; + if ( !variant.IsNull() ) + { + maxOk = variant.Convert(&max); + } + if ( maxOk ) + { + // Round maximal value to the required precision, if applicable + max = GetRoundedValue(this, max); + } + + if ( minOk ) + { + if ( value < min ) + { + if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE ) + { + wxString msg; + wxVariant vmin = WXVARIANT(min); + wxString smin = ValueToString(vmin); + if ( !maxOk ) + msg = wxString::Format(_("Value must be %s or higher."), smin); + else + { + wxVariant vmax = WXVARIANT(max); + wxString smax = ValueToString(vmax); + msg = wxString::Format(_("Value must be between %s and %s."), smin, smax); + } + pValidationInfo->SetFailureMessage(msg); + } + else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE ) + value = min; + else + value = max - (min - value); + return false; + } + } + + if ( maxOk ) + { + if ( value > max ) + { + if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE ) + { + wxString msg; + wxVariant vmax = WXVARIANT(max); + wxString smax = ValueToString(vmax); + if ( !minOk ) + msg = wxString::Format(_("Value must be %s or less."), smax); + else + { + wxVariant vmin = WXVARIANT(min); + wxString smin = ValueToString(vmin); + msg = wxString::Format(_("Value must be between %s and %s."), smin, smax); + } + pValidationInfo->SetFailureMessage(msg); + } + else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE ) + value = max; + else + value = min + (value - max); + return false; + } + } + return true; +} // ----------------------------------------------------------------------- // wxIntProperty @@ -384,143 +501,13 @@ bool wxIntProperty::IntToValue( wxVariant& variant, int value, int WXUNUSED(argF return false; } -namespace { -// This function by default doesn't modify the value. -// For argument 'value' of type 'double' there is a specialized function (below). -template -T GetRoundedValue(const wxPGProperty* prop, T value) -{ - wxUnusedVar(prop); - return value; -} - -// Specialized function for floating-point values -// takes into account required precision of the numbers -// to avoid rounding and conversion errors. -template<> -double GetRoundedValue(const wxPGProperty* prop, double value) -{ - // Round value to the required precision. - wxVariant variant = value; - wxString strVal = prop->ValueToString(variant, wxPG_FULL_VALUE); - strVal.ToDouble(&value); - return value; -} - -// Common validation code to be called in ValidateValue() -// implementations. -// Note that 'value' is reference on purpose, so we can write -// back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE or wxPG_PROPERTY_VALIDATION_WRAP. -template -bool NumericValidation( const wxNumericProperty* property, - T& value, - wxPGValidationInfo* pValidationInfo, - int mode, T defMin, T defMax) -{ - T min = defMin; - T max = defMax; - wxVariant variant; - bool minOk = false; - bool maxOk = false; - - // Round current value to the required precision, if applicable - value = GetRoundedValue(property, value); - - variant = property->GetMinVal(); - if ( !variant.IsNull() ) - { - minOk = variant.Convert(&min); - } - if ( minOk ) - { - // Round minimal value to the required precision, if applicable - min = GetRoundedValue(property, min); - } - - variant = property->GetMaxVal(); - if ( !variant.IsNull() ) - { - maxOk = variant.Convert(&max); - } - if ( maxOk ) - { - // Round maximal value to the required precision, if applicable - max = GetRoundedValue(property, max); - } - - if ( minOk ) - { - if ( value < min ) - { - if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE ) - { - wxString msg; - wxVariant vmin = WXVARIANT(min); - wxString smin = property->ValueToString(vmin); - if ( !maxOk ) - msg = wxString::Format( - _("Value must be %s or higher."), - smin); - else - { - wxVariant vmax = WXVARIANT(max); - wxString smax = property->ValueToString(vmax); - msg = wxString::Format( - _("Value must be between %s and %s."), - smin, smax); - } - pValidationInfo->SetFailureMessage(msg); - } - else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE ) - value = min; - else - value = max - (min - value); - return false; - } - } - - if ( maxOk ) - { - if ( value > max ) - { - if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE ) - { - wxString msg; - wxVariant vmax = WXVARIANT(max); - wxString smax = property->ValueToString(vmax); - if ( !minOk ) - msg = wxString::Format( - _("Value must be %s or less."), - smax); - else - { - wxVariant vmin = WXVARIANT(min); - wxString smin = property->ValueToString(vmin); - msg = wxString::Format( - _("Value must be between %s and %s."), - smin, smax); - } - pValidationInfo->SetFailureMessage(msg); - } - else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE ) - value = max; - else - value = min + (value - max); - return false; - } - } - return true; -} -} // namespace - #if wxUSE_LONGLONG bool wxIntProperty::DoValidation( const wxNumericProperty* property, wxLongLong& value, wxPGValidationInfo* pValidationInfo, int mode ) { - return NumericValidation(property, - value, + return property->DoNumericValidation(value, pValidationInfo, mode, wxLongLong(LLONG_MIN), wxLongLong(LLONG_MAX)); } @@ -531,8 +518,8 @@ bool wxIntProperty::DoValidation( const wxNumericProperty* property, wxPGValidationInfo* pValidationInfo, int mode ) { - return NumericValidation(property, value, pValidationInfo, - mode, LLONG_MIN, LLONG_MAX); + return property->DoNumericValidation(value, pValidationInfo, + mode, LLONG_MIN, LLONG_MAX); } #endif // wxLongLong_t #endif // wxUSE_LONGLONG @@ -542,8 +529,8 @@ bool wxIntProperty::DoValidation(const wxNumericProperty* property, wxPGValidationInfo* pValidationInfo, int mode) { - return NumericValidation(property, value, pValidationInfo, - mode, LONG_MIN, LONG_MAX); + return property->DoNumericValidation(value, pValidationInfo, + mode, LONG_MIN, LONG_MAX); } bool wxIntProperty::ValidateValue( wxVariant& value, @@ -796,7 +783,7 @@ bool wxUIntProperty::DoValidation(const wxNumericProperty* property, wxPGValidationInfo* pValidationInfo, int mode ) { - return NumericValidation(property, value, pValidationInfo, + return property->DoNumericValidation(value, pValidationInfo, mode, wxULongLong(0), wxULongLong(ULLONG_MAX)); } @@ -806,8 +793,8 @@ bool wxUIntProperty::DoValidation(const wxNumericProperty* property, wxPGValidationInfo* pValidationInfo, int mode ) { - return NumericValidation(property, value, pValidationInfo, - mode, 0, ULLONG_MAX); + return property->DoNumericValidation(value, pValidationInfo, + mode, 0, ULLONG_MAX); } #endif // wxULongLong_t #endif // wxUSE_LONGLONG @@ -817,8 +804,8 @@ bool wxUIntProperty::DoValidation(const wxNumericProperty* property, wxPGValidationInfo* pValidationInfo, int mode) { - return NumericValidation(property, value, pValidationInfo, - mode, 0, ULONG_MAX); + return property->DoNumericValidation(value, pValidationInfo, + mode, 0, ULONG_MAX); } bool wxUIntProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const @@ -1042,10 +1029,8 @@ bool wxFloatProperty::DoValidation( const wxNumericProperty* property, wxPGValidationInfo* pValidationInfo, int mode ) { - return NumericValidation(property, - value, - pValidationInfo, - mode, DBL_MIN, DBL_MAX); + return property->DoNumericValidation(value, pValidationInfo, + mode, DBL_MIN, DBL_MAX); } bool