summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2021-09-14 11:45:24 +0200
committerIvan Solovev <ivan.solovev@qt.io>2021-09-17 09:55:11 +0200
commitfb3549fc47b19de2956cd2dda07ef67ec529cf3e (patch)
tree02beef1e21a4436f55b23f9f388e38f8f1d373a7 /src/gui
parentd47278fd09f73ddc34011ab980dafc23aa453e71 (diff)
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>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/doc/snippets/code/src_gui_util_qvalidator.cpp19
-rw-r--r--src/gui/util/qvalidator.cpp90
-rw-r--r--src/gui/util/qvalidator.h1
3 files changed, 108 insertions, 2 deletions
diff --git a/src/gui/doc/snippets/code/src_gui_util_qvalidator.cpp b/src/gui/doc/snippets/code/src_gui_util_qvalidator.cpp
index 51fc3a6e14..7503c12afb 100644
--- a/src/gui/doc/snippets/code/src_gui_util_qvalidator.cpp
+++ b/src/gui/doc/snippets/code/src_gui_util_qvalidator.cpp
@@ -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
diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp
index 6f93738340..52dfad11a4 100644
--- a/src/gui/util/qvalidator.cpp
+++ b/src/gui/util/qvalidator.cpp
@@ -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
@@ -712,6 +713,91 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL
}
/*!
+ \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
point.
diff --git a/src/gui/util/qvalidator.h b/src/gui/util/qvalidator.h
index 7e72a60f24..be9042d653 100644
--- a/src/gui/util/qvalidator.h
+++ b/src/gui/util/qvalidator.h
@@ -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);