From 92cd8d99595595131f8a04d1bc81e00f24385dfb Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 8 Jan 2017 23:58:00 +0000 Subject: [PATCH] Improve frequency input validation Allow group separators as well as decimal points in MHz input fields git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7462 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- FrequencyLineEdit.cpp | 38 ++++++++++++++++++++++++++++++++++---- FrequencyList.cpp | 3 ++- Radio.cpp | 38 ++++++++++++++++++++++++++++++-------- Radio.hpp | 6 ++++-- StationList.cpp | 14 +++++++++++--- 5 files changed, 81 insertions(+), 18 deletions(-) diff --git a/FrequencyLineEdit.cpp b/FrequencyLineEdit.cpp index b51aecee9..78f8b2e1f 100644 --- a/FrequencyLineEdit.cpp +++ b/FrequencyLineEdit.cpp @@ -1,16 +1,45 @@ #include "FrequencyLineEdit.hpp" -#include -#include +#include + +#include #include #include #include "moc_FrequencyLineEdit.cpp" +namespace +{ + class MHzValidator + : public QDoubleValidator + { + public: + MHzValidator (double bottom, double top, QObject * parent = nullptr) + : QDoubleValidator {bottom, top, 6, parent} + { + } + + State validate (QString& input, int& pos) const override + { + State result = QDoubleValidator::validate (input, pos); + if (Acceptable == result) + { + bool ok; + (void)QLocale {}.toDouble (input, &ok); + if (!ok) + { + result = Intermediate; + } + } + return result; + } + }; +} + FrequencyLineEdit::FrequencyLineEdit (QWidget * parent) : QLineEdit (parent) { - setValidator (new QRegExpValidator {QRegExp {QString {R"(\d{0,6}(\)"} + QLocale {}.decimalPoint () + R"(\d{0,6})?)"}, this}); + setValidator (new MHzValidator {0., std::numeric_limits::max () / 10.e6, this}); } auto FrequencyLineEdit::frequency () const -> Frequency @@ -27,7 +56,8 @@ void FrequencyLineEdit::frequency (Frequency f) FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent) : QLineEdit (parent) { - setValidator (new QRegExpValidator {QRegExp {QString {R"(-?\d{0,6}(\)"} + QLocale {}.decimalPoint () + R"(\d{0,6})?)"}, this}); + setValidator (new MHzValidator {-std::numeric_limits::max () / 10.e6, + std::numeric_limits::max () / 10.e6, this}); } auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta diff --git a/FrequencyList.cpp b/FrequencyList.cpp index 7ab164b8e..f3750eab6 100644 --- a/FrequencyList.cpp +++ b/FrequencyList.cpp @@ -17,6 +17,7 @@ #include #include +#include "Radio.hpp" #include "Bands.hpp" #include "pimpl_impl.hpp" @@ -480,7 +481,7 @@ bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant cons case frequency_column: if (value.canConvert ()) { - auto frequency = value.value (); + Radio::Frequency frequency {qvariant_cast (value)}; if (frequency != item.frequency_) { item.frequency_ = frequency; diff --git a/Radio.cpp b/Radio.cpp index 9e211a689..4eecd931e 100644 --- a/Radio.cpp +++ b/Radio.cpp @@ -1,6 +1,7 @@ #include "Radio.hpp" #include +#include #include #include @@ -19,32 +20,53 @@ namespace Radio } - Frequency frequency (QVariant const& v, int scale, QLocale const& locale) + Frequency frequency (QVariant const& v, int scale, bool * ok, QLocale const& locale) { - double value {0}; + double value {0.}; if (QVariant::String == v.type ()) { - value = locale.toDouble (v.value ()); + value = locale.toDouble (v.value (), ok); } else { value = v.toDouble (); + if (ok) *ok = true; } - return std::llround (value * std::pow (10., scale)); + value *= std::pow (10., scale); + if (ok) + { + if (value < 0. || value > std::numeric_limits::max ()) + { + value = 0.; + *ok = false; + } + } + return std::llround (value); } - FrequencyDelta frequency_delta (QVariant const& v, int scale, QLocale const& locale) + FrequencyDelta frequency_delta (QVariant const& v, int scale, bool * ok, QLocale const& locale) { - double value {0}; + double value {0.}; if (QVariant::String == v.type ()) { - value = locale.toDouble (v.value ()); + value = locale.toDouble (v.value (), ok); } else { value = v.toDouble (); + if (ok) *ok = true; } - return std::llround (value * std::pow (10., scale)); + value *= std::pow (10., scale); + if (ok) + { + if (value < -std::numeric_limits::max () + || value > std::numeric_limits::max ()) + { + value = 0.; + *ok = false; + } + } + return std::llround (value); } diff --git a/Radio.hpp b/Radio.hpp index ca7cbf641..b8eec22a7 100644 --- a/Radio.hpp +++ b/Radio.hpp @@ -34,8 +34,10 @@ namespace Radio // QVariant argument is convertible to double and is assumed to // be scaled by (10 ** -scale). // - Frequency UDP_EXPORT frequency (QVariant const&, int scale, QLocale const& = QLocale ()); - FrequencyDelta UDP_EXPORT frequency_delta (QVariant const&, int scale, QLocale const& = QLocale ()); + Frequency UDP_EXPORT frequency (QVariant const&, int scale, + bool * ok = nullptr, QLocale const& = QLocale ()); + FrequencyDelta UDP_EXPORT frequency_delta (QVariant const&, int scale, + bool * ok = nullptr, QLocale const& = QLocale ()); // // Frequency type formatting diff --git a/StationList.cpp b/StationList.cpp index 8965525dc..d881d2315 100644 --- a/StationList.cpp +++ b/StationList.cpp @@ -18,6 +18,7 @@ #include "pimpl_impl.hpp" +#include "Radio.hpp" #include "Bands.hpp" #include "FrequencyList.hpp" @@ -403,9 +404,16 @@ bool StationList::impl::setData (QModelIndex const& model_index, QVariant const& case offset_column: { - stations_[row].offset_ = value.value (); - Q_EMIT dataChanged (model_index, model_index, roles); - changed = true; + if (value.canConvert ()) + { + FrequencyDelta offset {qvariant_cast (value)}; + if (offset != stations_[row].offset_) + { + stations_[row].offset_ = offset; + Q_EMIT dataChanged (model_index, model_index, roles); + changed = true; + } + } } break;