diff --git a/src/framework/uicomponents/qml/Muse/UiComponents/tests/doubleinputvalidator_tests.cpp b/src/framework/uicomponents/qml/Muse/UiComponents/tests/doubleinputvalidator_tests.cpp
index d48405bbb76ac..1cd9b2bcfa20c 100644
--- a/src/framework/uicomponents/qml/Muse/UiComponents/tests/doubleinputvalidator_tests.cpp
+++ b/src/framework/uicomponents/qml/Muse/UiComponents/tests/doubleinputvalidator_tests.cpp
@@ -23,6 +23,13 @@
#include "../validators/doubleinputvalidator.h"
+// Teach GoogleTest how to print QString so failure diffs are readable
+// instead of a UTF-16 byte dump.
+inline void PrintTo(const QString& s, std::ostream* os)
+{
+ *os << '"' << s.toStdString() << '"';
+}
+
using namespace muse;
using namespace muse::uicomponents;
@@ -56,8 +63,8 @@ TEST_F(DoubleInputValidatorTests, ValidateDotLocale) {
QLocale prev = QLocale();
QLocale::setDefault(QLocale("en_US"));
- m_validator->setTop(100.0);
- m_validator->setBottom(-100.0);
+ m_validator->setTop(1000.0);
+ m_validator->setBottom(-1000.0);
m_validator->setDecimal(2);
std::vector inputs = {
@@ -71,9 +78,11 @@ TEST_F(DoubleInputValidatorTests, ValidateDotLocale) {
{ "00.", QValidator::Intermediate, "0" },
{ "2.00", QValidator::Intermediate, "2" },
{ "2.", QValidator::Intermediate, "2" },
- { "-100.1", QValidator::Intermediate, "-100" },
- { "100.1", QValidator::Intermediate, "100" },
+ { "-1000.1", QValidator::Intermediate, "-1,000" },
+ { "1000.1", QValidator::Intermediate, "1,000" },
{ "1.123", QValidator::Invalid }, // more than 2 decimal places
+ { "1000", QValidator::Acceptable, "1,000" },
+ { "10000", QValidator::Invalid }, // more than top
{ "abc", QValidator::Invalid },
{ "", QValidator::Intermediate, "0" }
};
@@ -109,8 +118,8 @@ TEST_F(DoubleInputValidatorTests, ValidateCommaLocale) {
QLocale prev = QLocale();
QLocale::setDefault(QLocale("ro_RO"));
- m_validator->setTop(100.0);
- m_validator->setBottom(-100.0);
+ m_validator->setTop(1000.0);
+ m_validator->setBottom(-1000.0);
m_validator->setDecimal(2);
std::vector inputs = {
@@ -124,8 +133,8 @@ TEST_F(DoubleInputValidatorTests, ValidateCommaLocale) {
{ "00,", QValidator::Intermediate, "0" },
{ "2,00", QValidator::Intermediate, "2" },
{ "2,", QValidator::Intermediate, "2" },
- { "-100,1", QValidator::Intermediate, "-100" },
- { "100,1", QValidator::Intermediate, "100" },
+ { "-1000,1", QValidator::Intermediate, "-1.000" },
+ { "1000,1", QValidator::Intermediate, "1.000" },
{ "1,123", QValidator::Invalid }, // more than 2 decimal places
{ "abc", QValidator::Invalid },
{ "", QValidator::Intermediate, "0" }
@@ -149,4 +158,52 @@ TEST_F(DoubleInputValidatorTests, ValidateCommaLocale) {
// Restore previous locale
QLocale::setDefault(prev);
}
+
+TEST_F(DoubleInputValidatorTests, ValidateSmallRange) {
+ struct Input
+ {
+ QString str;
+ QValidator::State expectedState;
+ QString fixedStr = {};
+ };
+
+ QLocale prev = QLocale();
+ QLocale::setDefault(QLocale("en_US"));
+
+ m_validator->setTop(1.0);
+ m_validator->setBottom(0.0);
+ m_validator->setDecimal(2);
+
+ std::vector inputs = {
+ { "0", QValidator::Acceptable },
+ { "1", QValidator::Acceptable },
+ { "0.5", QValidator::Acceptable },
+ { "0.99", QValidator::Acceptable },
+ { "-0.1", QValidator::Intermediate, "0" }, // below bottom, clamp to 0
+ { "2", QValidator::Intermediate, "1" }, // above top, clamp to 1
+ { "1.", QValidator::Intermediate, "1" },
+ { "0.0", QValidator::Intermediate, "0" },
+ { "10", QValidator::Invalid }, // too many integer digits
+ { "1.123", QValidator::Invalid }, // more than 2 decimal places
+ { "abc", QValidator::Invalid },
+ { "", QValidator::Intermediate, "0" }
+ };
+
+ int pos = 0;
+ for (Input& input : inputs) {
+ EXPECT_EQ(m_validator->validate(input.str, pos), input.expectedState);
+
+ if (QValidator::Invalid == input.expectedState) {
+ continue;
+ }
+
+ QString fixInput = input.str;
+ m_validator->fixup(fixInput);
+
+ QString expectedStr = QValidator::Acceptable == input.expectedState ? input.str : input.fixedStr;
+ EXPECT_EQ(expectedStr, fixInput);
+ }
+
+ QLocale::setDefault(prev);
+}
}
diff --git a/src/framework/uicomponents/qml/Muse/UiComponents/validators/doubleinputvalidator.cpp b/src/framework/uicomponents/qml/Muse/UiComponents/validators/doubleinputvalidator.cpp
index 799877f538c23..5eecee0605058 100644
--- a/src/framework/uicomponents/qml/Muse/UiComponents/validators/doubleinputvalidator.cpp
+++ b/src/framework/uicomponents/qml/Muse/UiComponents/validators/doubleinputvalidator.cpp
@@ -22,8 +22,27 @@
#include "doubleinputvalidator.h"
#include "global/realfn.h"
+#include
+
using namespace muse::uicomponents;
+namespace {
+int maxIntegerDigits(qreal top, qreal bottom)
+{
+ const qreal maxAbs = std::max(std::abs(top), std::abs(bottom));
+ if (maxAbs < 1.0) {
+ return 1;
+ }
+ int digits = 1;
+ qreal v = std::floor(maxAbs);
+ while (v >= 10.0) {
+ v /= 10.0;
+ ++digits;
+ }
+ return digits;
+}
+}
+
DoubleInputValidator::DoubleInputValidator(QObject* parent)
: QValidator(parent)
{
@@ -72,9 +91,10 @@ void DoubleInputValidator::fixup(QString& string) const
QString intPart = strList.at(0);
QString floatPart = strList.size() > 1 ? strList.at(1) : 0;
- if (intPart.contains(QRegularExpression("^0{1,3}$"))) {
+ const int maxIntDigits = maxIntegerDigits(m_top, m_bottom);
+ if (intPart.contains(QRegularExpression(QString("^0{1,%1}$").arg(maxIntDigits)))) {
intPart = QString("0");
- } else if (intPart.contains(QRegularExpression("^\\-0{0,3}$"))) {
+ } else if (intPart.contains(QRegularExpression(QString("^\\-0{0,%1}$").arg(maxIntDigits)))) {
intPart = QString("-0");
}
@@ -111,10 +131,12 @@ QValidator::State DoubleInputValidator::validate(QString& inputStr, int& cursorP
QValidator::State state = Invalid;
QString decimalSep = QRegularExpression::escape(locale.decimalPoint());
- QRegularExpression validRegex(QString("^\\-?\\d{1,3}(" + decimalSep + "\\d{1,%1})?$").arg(m_decimal));
+ const int maxIntDigits = maxIntegerDigits(m_top, m_bottom);
+ QRegularExpression validRegex(QString("^\\-?\\d{1,%1}(" + decimalSep + "\\d{1,%2})?$")
+ .arg(maxIntDigits).arg(m_decimal));
if (inputStr.contains(validRegex)) {
- QRegularExpression invalidZeroRegex("^\\-?0{2,3}" + decimalSep); // for '-000,' or '-000.'
+ QRegularExpression invalidZeroRegex(QString("^\\-?0{2,%1}").arg(std::max(maxIntDigits, 2)) + decimalSep); // e.g. '-000,' or '-000.'
QRegularExpression invalidTrailingZeroRegex("^\\-?\\d+" + decimalSep + "0{1,}$"); // for '1,00' or '1.00'
QRegularExpression invalidTrailingDotRegex("^\\-?\\d+" + decimalSep + "$"); // for '1,' or '1.'
@@ -128,8 +150,9 @@ QValidator::State DoubleInputValidator::validate(QString& inputStr, int& cursorP
} else {
state = Acceptable;
}
- } else if (inputStr.contains(QRegularExpression("^\\-?\\d{0,3}" + decimalSep + "?$"))
- || inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,3}" + decimalSep + "\\d{0,%1}$").arg(m_decimal)))) {
+ } else if (inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,%1}" + decimalSep + "?$").arg(maxIntDigits)))
+ || inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,%1}" + decimalSep
+ + "\\d{0,%2}$").arg(maxIntDigits).arg(m_decimal)))) {
state = Intermediate;
} else {
cursorPos = 0;