Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qvalidator.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <qdebug.h>
6
7#include "qvalidator.h"
8#ifndef QT_NO_VALIDATOR
9#include "private/qobject_p.h"
10#include "private/qlocale_p.h"
11#include "private/qnumeric_p.h"
12
13#include <limits.h>
14#include <cmath>
15
17
160 Q_DECLARE_PUBLIC(QValidator)
161public:
165
167};
168
169
176 : QValidator(*new QValidatorPrivate, parent)
177{
178}
179
188
196{
197 Q_D(const QValidator);
198 return d->locale;
199}
200
210{
211 Q_D(QValidator);
212 if (d->locale != locale) {
213 d->locale = locale;
214 emit changed();
215 }
216}
217
251{
252}
253
254
297 : QIntValidator(INT_MIN, INT_MAX, parent)
298{
299}
300
301
307QIntValidator::QIntValidator(int minimum, int maximum,
308 QObject * parent)
309 : QValidator(parent)
310{
311 b = minimum;
312 t = maximum;
313}
314
315
321{
322 // nothing
323}
324
325
351{
352 if (n == 0)
353 return 1;
354 return (int)std::log10(double(n)) + 1;
355}
356
357static qlonglong pow10(int exp)
358{
359 qlonglong result = 1;
360 for (int i = 0; i < exp; ++i)
361 result *= 10;
362 return result;
363}
364
365template <typename T> static inline
366std::optional<QValidator::State> initialResultCheck(T min, T max, const ParsingResult &result)
367{
368 if (result.state == ParsingResult::Invalid)
369 return QValidator::Invalid;
370
371 const CharBuff &buff = result.buff;
372 if (buff.isEmpty())
374
375 char ch = buff[0];
376 const bool signConflicts = (min >= 0 && ch == '-') || (max < 0 && ch == '+');
377 if (signConflicts)
378 return QValidator::Invalid;
379
382
383 return std::nullopt;
384}
385
387{
390 locale().numberOptions());
391
392 std::optional<State> opt = initialResultCheck(b, t, result);
393 if (opt)
394 return *opt;
395
396 const CharBuff &buff = result.buff;
398 if (!r.ok())
399 return Invalid;
400
401 qint64 entered = r.result;
402 if (entered >= b && entered <= t) {
403 bool ok = false;
404 locale().toInt(input, &ok);
405 return ok ? Acceptable : Intermediate;
406 }
407
408 if (entered >= 0) {
409 // the -entered < b condition is necessary to allow people to type
410 // the minus last (e.g. for right-to-left languages)
411 // The buffLength > tLength condition validates values consisting
412 // of a number of digits equal to or less than the max value as intermediate.
413
414 int buffLength = buff.size();
415 if (buff[0] == '+')
416 buffLength--;
417 const int tLength = t != 0 ? static_cast<int>(std::log10(qAbs(t))) + 1 : 1;
418
419 return (entered > t && -entered < b && buffLength > tLength) ? Invalid : Intermediate;
420 } else {
421 return (entered < b) ? Invalid : Intermediate;
422 }
423}
424
427{
428 auto [parseState, buff] =
430 locale().numberOptions());
431 if (parseState == ParsingResult::Invalid)
432 return;
433
435 if (r.ok())
436 input = locale().toString(r.result);
437}
438
445{
446 bool rangeChanged = false;
447 if (b != bottom) {
448 b = bottom;
449 rangeChanged = true;
451 }
452
453 if (t != top) {
454 t = top;
455 rangeChanged = true;
457 }
458
459 if (rangeChanged)
460 emit changed();
461}
462
463
474{
475 setRange(bottom, top());
476}
477
488{
489 setRange(bottom(), top);
490}
491
496 : QObject(d, parent)
497{
498}
499
504 : QObject(d, parent)
505{
506}
507
509{
510 Q_DECLARE_PUBLIC(QDoubleValidator)
511public:
514 , notation(QDoubleValidator::ScientificNotation)
515 {
516 }
517
519
522 const QLocale &locale) const;
523};
524
525
584 : QDoubleValidator(-HUGE_VAL, HUGE_VAL, -1, parent)
585{
586}
587
588
595QDoubleValidator::QDoubleValidator(double bottom, double top, int decimals,
596 QObject * parent)
597 : QValidator(*new QDoubleValidatorPrivate , parent)
598{
599 b = bottom;
600 t = top;
601 dec = decimals;
602}
603
604
612
613
636#ifndef LLONG_MAX
637# define LLONG_MAX Q_INT64_C(0x7fffffffffffffff)
638#endif
639
641{
642 Q_D(const QDoubleValidator);
643
645 switch (d->notation) {
646 case StandardNotation:
648 break;
651 break;
652 }
653
654 return d->validateWithLocale(input, numMode, locale());
655}
656
658{
659 Q_Q(const QDoubleValidator);
661 locale.d->m_data->validateChars(input, numMode, q->dec, locale.numberOptions());
662
663 std::optional<QValidator::State> opt = initialResultCheck(q->b, q->t, result);
664 if (opt)
665 return *opt;
666
667 bool ok = false;
668 double i = locale.toDouble(input, &ok); // returns 0.0 if !ok
669 Q_ASSERT(!qIsNaN(i)); // Would be caught by validateChars()
670 if (!ok)
672
673 if (i >= q->b && i <= q->t)
675
677 double max = qMax(qAbs(q->b), qAbs(q->t));
678 qlonglong v;
679 // Need a whole number to pass to convertDoubleTo() or it fails. Use
680 // floor, as max is positive so this has the same number of digits
681 // before the decimal point, where qCeil() might take us up to a power
682 // of ten, adding a digit.
683 if (convertDoubleTo(qFloor(max), &v)) {
685 // In order to get the highest possible number in the intermediate
686 // range we need to get 10 to the power of the number of digits
687 // after the decimal's and subtract that from the top number.
688 //
689 // For example, where q->dec == 2 and with a range of 0.0 - 9.0
690 // then the minimum possible number is 0.00 and the maximum
691 // possible is 9.99. Therefore 9.999 and 10.0 should be seen as
692 // invalid.
693 if (qAbs(i) > (n - std::pow(10, -q->dec)))
694 return QValidator::Invalid;
695 }
696 }
697
699}
700
732{
733 Q_D(const QDoubleValidator);
734 const auto numberMode = d->notation == StandardNotation ? QLocaleData::DoubleStandardMode
736
737 d->fixupWithLocale(input, numberMode, locale());
738}
739
741 const QLocale &locale) const
742{
743 Q_Q(const QDoubleValidator);
744 // Passing -1 as the number of decimals, because fixup() exists to improve
745 // an Intermediate value, if it can.
746 auto [parseState, buff] =
748 if (parseState == ParsingResult::Invalid)
749 return;
750
751 // buff contains data in C locale.
752 bool ok = false;
753 const double entered = QByteArrayView(buff).toDouble(&ok);
754 if (ok) {
755 // Here we need to adjust the output format accordingly
756 char mode;
757 if (numMode == QLocaleData::DoubleStandardMode) {
758 mode = 'f';
759 } else {
760 // scientific mode can be either 'e' or 'E'
761 mode = input.contains(QChar::fromLatin1('E')) ? 'E' : 'e';
762 }
763 int precision;
764 if (q->dec < 0) {
766 } else {
767 if (mode == 'f') {
768 const auto decimalPointIndex = buff.indexOf('.');
769 precision = decimalPointIndex >= 0 ? buff.size() - decimalPointIndex - 1 : 0;
770 } else {
771 auto eIndex = buff.indexOf('e');
772 // No need to check for 'E' because we can get only 'e' after a
773 // call to validateChars()
774 if (eIndex < 0)
775 eIndex = buff.size();
776 precision = eIndex - (buff.contains('.') ? 1 : 0)
777 - (buff[0] == '-' || buff[0] == '+' ? 1 : 0);
778 }
779 // Use q->dec to limit the number of decimals, because we want the
780 // fixup() result to pass validate().
781 precision = qMin(precision, q->dec);
782 }
783 input = locale.toString(entered, mode, precision);
784 }
785}
786
796void QDoubleValidator::setRange(double minimum, double maximum, int decimals)
797{
798 bool rangeChanged = false;
799 if (b != minimum) {
800 b = minimum;
801 rangeChanged = true;
803 }
804
805 if (t != maximum) {
806 t = maximum;
807 rangeChanged = true;
809 }
810
811 if (dec != decimals) {
812 dec = decimals;
813 rangeChanged = true;
815 }
816 if (rangeChanged)
817 emit changed();
818}
819
826void QDoubleValidator::setRange(double minimum, double maximum)
827{
828 setRange(minimum, maximum, decimals());
829}
830
844
845
856{
858}
859
871{
873}
874
886{
887 Q_D(QDoubleValidator);
888 if (d->notation != newNotation) {
889 d->notation = newNotation;
890 emit notationChanged(d->notation);
891 emit changed();
892 }
893}
894
896{
897 Q_D(const QDoubleValidator);
898 return d->notation;
899}
900
901#if QT_CONFIG(regularexpression)
902
935class QRegularExpressionValidatorPrivate : public QValidatorPrivate
936{
937 Q_DECLARE_PUBLIC(QRegularExpressionValidator)
938
939public:
940 QRegularExpression origRe; // the one set by the user
941 QRegularExpression usedRe; // the one actually used
942 void setRegularExpression(const QRegularExpression &re);
943};
944
950QRegularExpressionValidator::QRegularExpressionValidator(QObject *parent)
951 : QValidator(*new QRegularExpressionValidatorPrivate, parent)
952{
953 // origRe in the private will be an empty QRegularExpression,
954 // and therefore this validator will match any string.
955}
956
962QRegularExpressionValidator::QRegularExpressionValidator(const QRegularExpression &re, QObject *parent)
963 : QRegularExpressionValidator(parent)
964{
965 Q_D(QRegularExpressionValidator);
966 d->setRegularExpression(re);
967}
968
969
974QRegularExpressionValidator::~QRegularExpressionValidator()
975{
976}
977
994QValidator::State QRegularExpressionValidator::validate(QString &input, int &pos) const
995{
996 Q_D(const QRegularExpressionValidator);
997
998 // We want a validator with an empty QRegularExpression to match anything;
999 // since we're going to do an exact match (by using d->usedRe), first check if the rx is empty
1000 // (and, if so, accept the input).
1001 if (d->origRe.pattern().isEmpty())
1002 return Acceptable;
1003
1005 if (m.hasMatch()) {
1006 return Acceptable;
1007 } else if (input.isEmpty() || m.hasPartialMatch()) {
1008 return Intermediate;
1009 } else {
1010 pos = input.size();
1011 return Invalid;
1012 }
1013}
1014
1023QRegularExpression QRegularExpressionValidator::regularExpression() const
1024{
1025 Q_D(const QRegularExpressionValidator);
1026 return d->origRe;
1027}
1028
1029void QRegularExpressionValidator::setRegularExpression(const QRegularExpression &re)
1030{
1031 Q_D(QRegularExpressionValidator);
1032 d->setRegularExpression(re);
1033}
1034
1041void QRegularExpressionValidatorPrivate::setRegularExpression(const QRegularExpression &re)
1042{
1043 Q_Q(QRegularExpressionValidator);
1044
1045 if (origRe != re) {
1046 usedRe = origRe = re; // copies also the pattern options
1047 usedRe.setPattern(QRegularExpression::anchoredPattern(re.pattern()));
1048 emit q->regularExpressionChanged(re);
1049 emit q->changed();
1050 }
1051}
1052
1053#endif // QT_CONFIG(regularexpression)
1054
1056
1057#include "moc_qvalidator.cpp"
1058
1059#endif // QT_NO_VALIDATOR
double toDouble(bool *ok=nullptr) const
QValidator::State validateWithLocale(QString &input, QLocaleData::NumberMode numMode, const QLocale &locale) const
void fixupWithLocale(QString &input, QLocaleData::NumberMode numMode, const QLocale &locale) const
QDoubleValidator::Notation notation
The QDoubleValidator class provides range checking of floating-point numbers.
Definition qvalidator.h:89
void bottomChanged(double bottom)
This signal is emitted after the bottom property changed.
double bottom
the validator's minimum acceptable value
Definition qvalidator.h:91
void setBottom(double)
void decimalsChanged(int decimals)
This signal is emitted after the decimals property changed.
Notation notation
the notation of how a string can describe a number
Definition qvalidator.h:94
~QDoubleValidator()
Destroys the validator.
QDoubleValidator(QObject *parent=nullptr)
Constructs a validator object with a parent object that accepts any double.
void notationChanged(QDoubleValidator::Notation notation)
This signal is emitted after the notation property changed.
QValidator::State validate(QString &, int &) const override
Returns \l Acceptable if the string input is in the correct format and contains a double within the v...
void setRange(double bottom, double top, int decimals)
Sets the validator to accept doubles from minimum to maximum inclusive, with at most decimals digits ...
int decimals
the validator's maximum number of digits after the decimal point
Definition qvalidator.h:93
void setTop(double)
void setNotation(Notation)
void topChanged(double top)
This signal is emitted after the top property changed.
double top
the validator's maximum acceptable value
Definition qvalidator.h:92
void setDecimals(int)
void fixup(QString &input) const override
The QIntValidator class provides a validator that ensures a string contains a valid integer within a ...
Definition qvalidator.h:56
void topChanged(int top)
This signal is emitted after the top property changed.
void setRange(int bottom, int top)
Sets the range of the validator to only accept integers between bottom and top inclusive.
int bottom
the validator's lowest acceptable value
Definition qvalidator.h:58
QValidator::State validate(QString &, int &) const override
Returns \l Acceptable if the input is an integer within the valid range.
void fixup(QString &input) const override
\reimp
void setTop(int)
int top
the validator's highest acceptable value
Definition qvalidator.h:59
void setBottom(int)
QIntValidator(QObject *parent=nullptr)
Constructs a validator with a parent object that accepts all integers.
void bottomChanged(int bottom)
This signal is emitted after the bottom property changed.
~QIntValidator()
Destroys the validator.
const QLocaleData *const m_data
Definition qlocale_p.h:529
double toDouble(const QString &s, bool *ok=nullptr) const
Returns the double represented by the localized string s.
Definition qlocale.h:969
@ FloatingPointShortest
Definition qlocale.h:890
int toInt(const QString &s, bool *ok=nullptr) const
Returns the int represented by the localized string s.
Definition qlocale.h:955
QString toString(qlonglong i) const
Returns a localized string representation of i.
Definition qlocale.cpp:2052
NumberOptions numberOptions() const
Definition qlocale.cpp:1193
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore \reentrant
\inmodule QtCore \reentrant
static QString anchoredPattern(const QString &expression)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
constexpr size_type size() const noexcept
The QValidator class provides validation of input text.
Definition qvalidator.h:24
void setLocale(const QLocale &locale)
Sets the locale that will be used for the validator.
State
This enum type defines the states in which a validated string can exist.
Definition qvalidator.h:30
virtual void fixup(QString &) const
This function attempts to change input to be valid according to this validator's rules.
QValidator(QObject *parent=nullptr)
Sets up the validator.
QLocale locale() const
Returns the locale for the validator.
~QValidator()
Destroys the validator, freeing any storage and other resources used.
void changed()
This signal is emitted when any property that may affect the validity of a string has changed.
bool isEmpty() const
QStyleOptionButton opt
Combined button and popup list for selecting options.
bool qIsNaN(qfloat16 f) noexcept
Definition qfloat16.h:284
int qFloor(T v)
Definition qmath.h:42
@ Invalid
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLenum mode
const GLfloat * m
GLboolean r
[2]
GLdouble GLdouble GLdouble GLdouble top
GLint GLint bottom
GLfloat n
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLenum GLenum GLenum input
GLenum GLint GLint * precision
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
long long qint64
Definition qtypes.h:60
qint64 qlonglong
Definition qtypes.h:63
static qlonglong pow10(int exp)
static std::optional< QValidator::State > initialResultCheck(T min, T max, const ParsingResult &result)
static int numDigits(qlonglong n)
Q_CORE_EXPORT ParsingResult validateChars(QStringView str, NumberMode numMode, int decDigits=-1, QLocale::NumberOptions number_options=QLocale::DefaultNumberOptions) const
Definition qlocale.cpp:4365
@ DoubleScientificMode
Definition qlocale_p.h:273
@ DoubleStandardMode
Definition qlocale_p.h:273
static Q_CORE_EXPORT QSimpleParsedNumber< qint64 > bytearrayToLongLong(QByteArrayView num, int base)
Definition qlocale.cpp:4516