Introduce QDoubleValidator::fixup()
The provided implementation tries to fix positions for the group separator. In case of scientific notation it can also converts the value to normalized form. It uses QLocale::FloatingPointShortest internally to convert the double value back to string, so the number of decimals may change after calling this method. Change-Id: I963bc5f97b653e2bb912f4b95b09a4d1ee201e7f Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>bb10
parent
d47278fd09
commit
fb3549fc47
|
|
@ -57,6 +57,7 @@ struct Wrapper : public QWidget {
|
|||
void wrapper0();
|
||||
void wrapper1();
|
||||
void wrapper2();
|
||||
void wrapper3();
|
||||
};
|
||||
|
||||
void Wrapper::wrapper0() {
|
||||
|
|
@ -164,4 +165,22 @@ s = "readm"; v.validate(s, pos); // Returns Intermediate
|
|||
|
||||
} // Wrapper::wrapper2
|
||||
|
||||
void Wrapper::wrapper3()
|
||||
{
|
||||
//! [7]
|
||||
QString input = "0.98765e2";
|
||||
QDoubleValidator val;
|
||||
val.setLocale(QLocale::C);
|
||||
val.setNotation(QDoubleValidator::ScientificNotation);
|
||||
val.fixup(input); // input == "9.8765e+01"
|
||||
//! [7]
|
||||
//! [8]
|
||||
input = "-1234.6789";
|
||||
val.setDecimals(2);
|
||||
val.setLocale(QLocale::C);
|
||||
val.setNotation(QDoubleValidator::StandardNotation);
|
||||
val.fixup(input); // input == "-1234.68"
|
||||
//! [8]
|
||||
} // Wrapper::wrapper3
|
||||
|
||||
} // src_gui_util_qvalidator
|
||||
|
|
|
|||
|
|
@ -543,6 +543,8 @@ public:
|
|||
QDoubleValidator::Notation notation;
|
||||
|
||||
QValidator::State validateWithLocale(QString & input, QLocaleData::NumberMode numMode, const QLocale &locale) const;
|
||||
void fixupWithLocale(QString &input, QLocaleData::NumberMode numMode,
|
||||
const QLocale &locale) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -554,8 +556,7 @@ public:
|
|||
\inmodule QtGui
|
||||
|
||||
QDoubleValidator provides an upper bound, a lower bound, and a
|
||||
limit on the number of digits after the decimal point. It does not
|
||||
provide a fixup() function.
|
||||
limit on the number of digits after the decimal point.
|
||||
|
||||
You can set the acceptable range in one call with setRange(), or
|
||||
with setBottom() and setTop(). Set the number of decimal places
|
||||
|
|
@ -711,6 +712,91 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL
|
|||
return QValidator::Intermediate;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.3
|
||||
\overload
|
||||
|
||||
Attempts to fix the \a input string to an \l Acceptable representation of a
|
||||
double.
|
||||
|
||||
The format of the number is determined by \l notation(), \l decimals(),
|
||||
\l locale() and the latter's \l {QLocale::}{numberOptions()}.
|
||||
|
||||
To comply with \l notation(), when \l ScientificNotation is used, the fixed
|
||||
value will be represented in its normalized form, which means that any
|
||||
non-zero value will have one non-zero digit before the decimal point.
|
||||
|
||||
\snippet code/src_gui_util_qvalidator.cpp 7
|
||||
|
||||
To comply with \l decimals(), when it is \c {-1} the number of digits used
|
||||
will be determined by \l QLocale::FloatingPointShortest. Otherwise, the
|
||||
fractional part of the number is truncated (with rounding, as appropriate)
|
||||
if its length exceeds \l decimals(). When \l notation() is
|
||||
\l ScientificNotation this is done after the number has been put into its
|
||||
normalized form.
|
||||
|
||||
\snippet code/src_gui_util_qvalidator.cpp 8
|
||||
|
||||
\note If \l decimals() is set to, and the string provides, more than
|
||||
\c {std::numeric_limits<double>::digits10}, digits beyond that many in the
|
||||
fractional part may be changed. The resulting string shall encode the same
|
||||
floating-point number, when parsed to a \c double.
|
||||
*/
|
||||
void QDoubleValidator::fixup(QString &input) const
|
||||
{
|
||||
Q_D(const QDoubleValidator);
|
||||
const auto numberMode = d->notation == StandardNotation ? QLocaleData::DoubleStandardMode
|
||||
: QLocaleData::DoubleScientificMode;
|
||||
|
||||
d->fixupWithLocale(input, numberMode, locale());
|
||||
}
|
||||
|
||||
void QDoubleValidatorPrivate::fixupWithLocale(QString &input, QLocaleData::NumberMode numMode,
|
||||
const QLocale &locale) const
|
||||
{
|
||||
Q_Q(const QDoubleValidator);
|
||||
QByteArray buff;
|
||||
// Passing -1 as the number of decimals, because fixup() exists to improve
|
||||
// an Intermediate value, if it can.
|
||||
if (!locale.d->m_data->validateChars(input, numMode, &buff, -1, locale.numberOptions()))
|
||||
return;
|
||||
|
||||
// buff now contains data in C locale.
|
||||
bool ok = false;
|
||||
const double entered = buff.toDouble(&ok);
|
||||
if (ok) {
|
||||
// Here we need to adjust the output format accordingly
|
||||
char mode;
|
||||
if (numMode == QLocaleData::DoubleStandardMode) {
|
||||
mode = 'f';
|
||||
} else {
|
||||
// scientific mode can be either 'e' or 'E'
|
||||
mode = input.contains(QChar::fromLatin1('E')) ? 'E' : 'e';
|
||||
}
|
||||
int precision;
|
||||
if (q->dec < 0) {
|
||||
precision = QLocale::FloatingPointShortest;
|
||||
} else {
|
||||
if (mode == 'f') {
|
||||
const auto decimalPointIndex = buff.indexOf('.');
|
||||
precision = decimalPointIndex >= 0 ? buff.size() - decimalPointIndex - 1 : 0;
|
||||
} else {
|
||||
auto eIndex = buff.indexOf('e');
|
||||
// No need to check for 'E' because we can get only 'e' after a
|
||||
// call to validateChars()
|
||||
if (eIndex < 0)
|
||||
eIndex = buff.size();
|
||||
precision = eIndex - (buff.contains('.') ? 1 : 0)
|
||||
- (buff.startsWith('-') || buff.startsWith('+') ? 1 : 0);
|
||||
}
|
||||
// Use q->dec to limit the number of decimals, because we want the
|
||||
// fixup() result to pass validate().
|
||||
precision = qMin(precision, q->dec);
|
||||
}
|
||||
input = locale.toString(entered, mode, precision);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the validator to accept doubles from \a minimum to \a maximum
|
||||
inclusive, with at most \a decimals digits after the decimal
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ public:
|
|||
};
|
||||
Q_ENUM(Notation)
|
||||
QValidator::State validate(QString &, int &) const override;
|
||||
void fixup(QString &input) const override;
|
||||
|
||||
void setRange(double bottom, double top, int decimals = 0);
|
||||
void setBottom(double);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ private slots:
|
|||
void validateIntEquiv_data();
|
||||
void validateIntEquiv();
|
||||
void notifySignals();
|
||||
void fixup();
|
||||
void fixup_data();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QValidator::State);
|
||||
|
|
@ -393,6 +395,224 @@ void tst_QDoubleValidator::notifySignals()
|
|||
QCOMPARE(changedSpy.count(), 9);
|
||||
}
|
||||
|
||||
void tst_QDoubleValidator::fixup()
|
||||
{
|
||||
QFETCH(QString, localeName);
|
||||
QFETCH(QDoubleValidator::Notation, notation);
|
||||
QFETCH(int, decimals);
|
||||
QFETCH(QString, input);
|
||||
QFETCH(QString, output);
|
||||
|
||||
QDoubleValidator val;
|
||||
val.setLocale(QLocale(localeName));
|
||||
val.setNotation(notation);
|
||||
val.setDecimals(decimals);
|
||||
|
||||
val.fixup(input);
|
||||
QCOMPARE(input, output);
|
||||
}
|
||||
|
||||
void tst_QDoubleValidator::fixup_data()
|
||||
{
|
||||
QTest::addColumn<QString>("localeName");
|
||||
QTest::addColumn<QDoubleValidator::Notation>("notation");
|
||||
QTest::addColumn<int>("decimals");
|
||||
QTest::addColumn<QString>("input");
|
||||
QTest::addColumn<QString>("output");
|
||||
|
||||
// C locale uses '.' as decimal point and ',' as grouping separator.
|
||||
// C locale does not group digits by default.
|
||||
QTest::newRow("C standard no digit grouping")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "12.345"
|
||||
<< "12.345";
|
||||
QTest::newRow("C standard with digit grouping")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "-12,345.678"
|
||||
<< "-12345.678";
|
||||
QTest::newRow("C standard with invalid digit grouping")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "1,234,5.678"
|
||||
<< "12345.678";
|
||||
QTest::newRow("C standard with invalid number of decimals")
|
||||
<< "C" << QDoubleValidator::StandardNotation << 2 << "-12,34.678"
|
||||
<< "-1234.68";
|
||||
QTest::newRow("C standard truncate decimals")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1
|
||||
<< "1.23456789012345678901234567890"
|
||||
<< "1.2345678901234567";
|
||||
QTest::newRow("C standard skip trailing zeroes")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "1,234.5670000"
|
||||
<< "1234.567";
|
||||
QTest::newRow("C standard zero value")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "0.0"
|
||||
<< "0";
|
||||
QTest::newRow("C standard scientific value")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "1.23e-2"
|
||||
<< "1.23e-2";
|
||||
QTest::newRow("C standard no fractional part")
|
||||
<< "C" << QDoubleValidator::StandardNotation << -1 << "-1,234"
|
||||
<< "-1234";
|
||||
|
||||
QTest::newRow("C scientific no digit grouping")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "0.98765e2"
|
||||
<< "9.8765e+01";
|
||||
QTest::newRow("C scientific with digit grouping")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "-1,234.98765E-4"
|
||||
<< "-1.23498765E-01";
|
||||
QTest::newRow("C scientific with invalid digit grouping")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "12,34.98765e2"
|
||||
<< "1.23498765e+05";
|
||||
QTest::newRow("C scientific with invalid number of decimals")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << 2 << "-12,34.98765e2"
|
||||
<< "-1.23e+05";
|
||||
QTest::newRow("C scientific truncate decimals")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1
|
||||
<< "1.23456789012345678901234567890E5"
|
||||
<< "1.2345678901234567E+05";
|
||||
QTest::newRow("C scientific skip trailing zeroes")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "1,234.5670000e3"
|
||||
<< "1.234567e+06";
|
||||
QTest::newRow("C scientific zero value")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "0.0"
|
||||
<< "0e+00";
|
||||
QTest::newRow("C scientific standard value")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "12.345"
|
||||
<< "1.2345e+01";
|
||||
QTest::newRow("C scientific no fractional part")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "1,234e2"
|
||||
<< "1.234e+05";
|
||||
QTest::newRow("C scientific negative no fractional part")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "-1,234e2"
|
||||
<< "-1.234e+05";
|
||||
QTest::newRow("C scientific no fractional and exponent")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "1,234"
|
||||
<< "1.234e+03";
|
||||
QTest::newRow("C scientific negative no fractional and exponent")
|
||||
<< "C" << QDoubleValidator::ScientificNotation << -1 << "-1,234"
|
||||
<< "-1.234e+03";
|
||||
|
||||
// en locale uses '.' as decimal point and ',' as grouping separator.
|
||||
// en locale groups digits by default. 'E' is used in scientific notation.
|
||||
QTest::newRow("en standard no digit grouping")
|
||||
<< "en" << QDoubleValidator::StandardNotation << -1 << "-12.345"
|
||||
<< "-12.345";
|
||||
QTest::newRow("en standard with digit grouping")
|
||||
<< "en" << QDoubleValidator::StandardNotation << -1 << "12,345.678"
|
||||
<< "12,345.678";
|
||||
QTest::newRow("en standard with invalid digit grouping")
|
||||
<< "en" << QDoubleValidator::StandardNotation << -1 << "-1,234,5.678"
|
||||
<< "-12,345.678";
|
||||
QTest::newRow("en standard with invalid number of decimals")
|
||||
<< "en" << QDoubleValidator::StandardNotation << 2 << "12,34.678"
|
||||
<< "1,234.68";
|
||||
QTest::newRow("en standard no fractional part")
|
||||
<< "en" << QDoubleValidator::StandardNotation << -1 << "-12,34"
|
||||
<< "-1,234";
|
||||
|
||||
QTest::newRow("en scientific no digit grouping")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "-0.98765e2"
|
||||
<< "-9.8765E+01";
|
||||
QTest::newRow("en scientific with digit grouping")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "1,234.98765E-4"
|
||||
<< "1.23498765E-01";
|
||||
QTest::newRow("en scientific with invalid digit grouping")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "-12,34.98765e2"
|
||||
<< "-1.23498765E+05";
|
||||
QTest::newRow("en scientific with invalid number of decimals")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << 2 << "12,34.98765e2"
|
||||
<< "1.23E+05";
|
||||
QTest::newRow("en scientific no fractional part")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "12,34e2"
|
||||
<< "1.234E+05";
|
||||
QTest::newRow("en scientific negative no fractional part")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "-12,34e2"
|
||||
<< "-1.234E+05";
|
||||
QTest::newRow("en scientific no fractional and exponent")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "1,234"
|
||||
<< "1.234E+03";
|
||||
QTest::newRow("en scientific negative no fractional and exponent")
|
||||
<< "en" << QDoubleValidator::ScientificNotation << -1 << "-1,234"
|
||||
<< "-1.234E+03";
|
||||
|
||||
// de locale uses ',' as decimal point and '.' as grouping separator.
|
||||
// de locale groups digits by default. 'E' is used in scientific notation.
|
||||
QTest::newRow("de standard no digit grouping")
|
||||
<< "de" << QDoubleValidator::StandardNotation << -1 << "12,345"
|
||||
<< "12,345";
|
||||
QTest::newRow("de standard with digit grouping")
|
||||
<< "de" << QDoubleValidator::StandardNotation << -1 << "-12.345,678"
|
||||
<< "-12.345,678";
|
||||
QTest::newRow("de standard with invalid digit grouping")
|
||||
<< "de" << QDoubleValidator::StandardNotation << -1 << "1.234.5,678"
|
||||
<< "12.345,678";
|
||||
QTest::newRow("de standard with invalid number of decimals")
|
||||
<< "de" << QDoubleValidator::StandardNotation << 2 << "-12.34,678"
|
||||
<< "-1.234,68";
|
||||
QTest::newRow("de standard no fractional part")
|
||||
<< "de" << QDoubleValidator::StandardNotation << -1 << "12.34" << "1.234";
|
||||
|
||||
QTest::newRow("de scientific no digit grouping")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "0,98765e2"
|
||||
<< "9,8765E+01";
|
||||
QTest::newRow("de scientific with digit grouping")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "-1.234,98765E-4"
|
||||
<< "-1,23498765E-01";
|
||||
QTest::newRow("de scientific with invalid digit grouping")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "12.34,98765e2"
|
||||
<< "1,23498765E+05";
|
||||
QTest::newRow("de scientific with invalid number of decimals")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << 2 << "-12.34,98765e2"
|
||||
<< "-1,23E+05";
|
||||
QTest::newRow("de scientific no fractional part")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "1.234e2"
|
||||
<< "1,234E+05";
|
||||
QTest::newRow("de scientific negative no fractional part")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "-1.234e2"
|
||||
<< "-1,234E+05";
|
||||
QTest::newRow("de scientific no fractional and exponent")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "12.34"
|
||||
<< "1,234E+03";
|
||||
QTest::newRow("de scientific negative no fractional and exponent")
|
||||
<< "de" << QDoubleValidator::ScientificNotation << -1 << "-12.34"
|
||||
<< "-1,234E+03";
|
||||
|
||||
// hi locale uses '.' as decimal point and ',' as grouping separator.
|
||||
// The rightmost group is of three digits, all the others contain two
|
||||
// digits.
|
||||
QTest::newRow("hi standard no digit grouping")
|
||||
<< "hi" << QDoubleValidator::StandardNotation << -1 << "123456.78"
|
||||
<< "1,23,456.78";
|
||||
QTest::newRow("hi standard with digit grouping")
|
||||
<< "hi" << QDoubleValidator::StandardNotation << -1 << "-12,345.678"
|
||||
<< "-12,345.678";
|
||||
QTest::newRow("hi standard with invalid digit grouping")
|
||||
<< "hi" << QDoubleValidator::StandardNotation << -1 << "12,34,56.78"
|
||||
<< "1,23,456.78";
|
||||
QTest::newRow("hi standard no fractional part")
|
||||
<< "hi" << QDoubleValidator::StandardNotation << -1 << "-12,345,6"
|
||||
<< "-1,23,456";
|
||||
|
||||
QTest::newRow("hi scientific no digit grouping")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "-0.123e-2"
|
||||
<< "-1.23E-03";
|
||||
QTest::newRow("hi scientific with digit grouping")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "12,345.678e-2"
|
||||
<< "1.2345678E+02";
|
||||
QTest::newRow("hi scientific with invalid digit grouping")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "-1,23,45.678e-2"
|
||||
<< "-1.2345678E+02";
|
||||
QTest::newRow("hi scientific no fractional part")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "1,23,456e2"
|
||||
<< "1.23456E+07";
|
||||
QTest::newRow("hi scientific negative no fractional part")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "-1,23,456e2"
|
||||
<< "-1.23456E+07";
|
||||
QTest::newRow("hi scientific no fractional and exponent")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "1,234,56"
|
||||
<< "1.23456E+05";
|
||||
QTest::newRow("hi scientific negative no fractional and exponent")
|
||||
<< "hi" << QDoubleValidator::ScientificNotation << -1 << "-1,234,56"
|
||||
<< "-1.23456E+05";
|
||||
}
|
||||
|
||||
void tst_QDoubleValidator::validateIntEquiv_data()
|
||||
{
|
||||
QTest::addColumn<double>("minimum");
|
||||
|
|
|
|||
Loading…
Reference in New Issue