aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquicktextinput.cpp62
-rw-r--r--src/quick/items/qquicktextinput_p_p.h17
-rw-r--r--tests/auto/qtquick2/qquicktextinput/data/validators.qml7
-rw-r--r--tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp82
4 files changed, 144 insertions, 24 deletions
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index fb96709e8d..4ccf3a37fd 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -102,6 +102,7 @@ void QQuickTextInput::componentComplete()
QQuickImplicitSizeItem::componentComplete();
+ d->checkIsValid();
d->updateLayout();
updateCursorRectangle();
if (d->cursorComponent && d->cursorComponent->isReady())
@@ -948,20 +949,32 @@ void QQuickTextInput::setValidator(QValidator* v)
return;
d->m_validator = v;
- if (!d->hasAcceptableInput(d->m_text)) {
- if (d->m_validInput) {
- d->m_validInput = false;
- emit acceptableInputChanged();
- }
- } else if (!d->m_validInput) {
- d->m_validInput = true;
- emit acceptableInputChanged();
- }
+
+ if (isComponentComplete())
+ d->checkIsValid();
emit validatorChanged();
}
+
#endif // QT_NO_VALIDATOR
+void QQuickTextInputPrivate::checkIsValid()
+{
+ Q_Q(QQuickTextInput);
+
+ ValidatorState state = hasAcceptableInput(m_text);
+ m_validInput = state != InvalidInput;
+ if (state != AcceptableInput) {
+ if (m_acceptableInput) {
+ m_acceptableInput = false;
+ emit q->acceptableInputChanged();
+ }
+ } else if (!m_acceptableInput) {
+ m_acceptableInput = true;
+ emit q->acceptableInputChanged();
+ }
+}
+
/*!
\qmlproperty string QtQuick2::TextInput::inputMask
@@ -998,7 +1011,7 @@ void QQuickTextInput::setInputMask(const QString &im)
bool QQuickTextInput::hasAcceptableInput() const
{
Q_D(const QQuickTextInput);
- return d->hasAcceptableInput(d->m_text);
+ return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
}
/*!
@@ -3021,12 +3034,16 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
if (m_textDirty) {
// do validation
bool wasValidInput = m_validInput;
+ bool wasAcceptable = m_acceptableInput;
m_validInput = true;
+ m_acceptableInput = true;
#ifndef QT_NO_VALIDATOR
if (m_validator) {
QString textCopy = m_text;
int cursorCopy = m_cursor;
- m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
+ QValidator::State state = m_validator->validate(textCopy, cursorCopy);
+ m_validInput = state != QValidator::Invalid;
+ m_acceptableInput = state == QValidator::Acceptable;
if (m_validInput) {
if (m_text != textCopy) {
internalSetText(textCopy, cursorCopy);
@@ -3053,6 +3070,7 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
if (m_modifiedState > m_undoState)
m_modifiedState = -1;
m_validInput = true;
+ m_acceptableInput = wasAcceptable;
m_textDirty = false;
}
@@ -3065,7 +3083,7 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
updateDisplayText(alignmentChanged);
- if (m_validInput != wasValidInput)
+ if (m_acceptableInput != wasAcceptable)
emit q->acceptableInputChanged();
}
if (m_preeditDirty) {
@@ -3437,32 +3455,34 @@ bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
Otherwise returns false
*/
-bool QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
+QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
{
#ifndef QT_NO_VALIDATOR
QString textCopy = str;
int cursorCopy = m_cursor;
- if (m_validator && m_validator->validate(textCopy, cursorCopy)
- != QValidator::Acceptable)
- return false;
+ if (m_validator) {
+ QValidator::State state = m_validator->validate(textCopy, cursorCopy);
+ if (state != QValidator::Acceptable)
+ return ValidatorState(state);
+ }
#endif
if (!m_maskData)
- return true;
+ return AcceptableInput;
if (str.length() != m_maxLength)
- return false;
+ return InvalidInput;
for (int i=0; i < m_maxLength; ++i) {
if (m_maskData[i].separator) {
if (str.at(i) != m_maskData[i].maskChar)
- return false;
+ return InvalidInput;
} else {
if (!isValidInput(str.at(i), m_maskData[i].maskChar))
- return false;
+ return InvalidInput;
}
}
- return true;
+ return AcceptableInput;
}
/*!
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index 44ea7772c9..74f17f0116 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -125,6 +125,7 @@ public:
, m_preeditDirty(0)
, m_selDirty(0)
, m_validInput(1)
+ , m_acceptableInput(1)
, m_blinkStatus(0)
, m_passwordEchoEditing(false)
{
@@ -251,6 +252,7 @@ public:
uint m_preeditDirty : 1;
uint m_selDirty : 1;
uint m_validInput : 1;
+ uint m_acceptableInput : 1;
uint m_blinkStatus : 1;
uint m_passwordEchoEditing;
@@ -432,10 +434,23 @@ private:
inline void separate() { m_separator = true; }
+ enum ValidatorState {
+#ifndef QT_NO_VALIDATOR
+ InvalidInput = QValidator::Invalid,
+ IntermediateInput = QValidator::Intermediate,
+ AcceptableInput = QValidator::Acceptable
+#else
+ Invalid,
+ Intermediate,
+ Acceptable
+#endif
+ };
+
// masking
void parseInputMask(const QString &maskFields);
bool isValidInput(QChar key, QChar mask) const;
- bool hasAcceptableInput(const QString &text) const;
+ ValidatorState hasAcceptableInput(const QString &text) const;
+ void checkIsValid();
QString maskString(uint pos, const QString &str, bool clear = false) const;
QString clearString(uint pos, uint len) const;
QString stripString(const QString &str) const;
diff --git a/tests/auto/qtquick2/qquicktextinput/data/validators.qml b/tests/auto/qtquick2/qquicktextinput/data/validators.qml
index 0a074ce7dc..0ba87e0592 100644
--- a/tests/auto/qtquick2/qquicktextinput/data/validators.qml
+++ b/tests/auto/qtquick2/qquicktextinput/data/validators.qml
@@ -4,19 +4,26 @@ Item {
property variant intInput: intInput
property variant dblInput: dblInput
property variant strInput: strInput
+ property variant unvalidatedInput: unvalidatedInput
width: 800; height: 600;
Column{
TextInput { id: intInput;
+ property bool acceptable: acceptableInput
validator: IntValidator{top: 11; bottom: 2}
}
TextInput { id: dblInput;
+ property bool acceptable: acceptableInput
validator: DoubleValidator{top: 12.12; bottom: 2.93; decimals: 2; notation: DoubleValidator.StandardNotation}
}
TextInput { id: strInput;
+ property bool acceptable: acceptableInput
validator: RegExpValidator { regExp: /[a-zA-z]{2,4}/ }
}
+ TextInput { id: unvalidatedInput
+ property bool acceptable: acceptableInput
+ }
}
}
diff --git a/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
index 8cc35f3b50..4ae5b525b1 100644
--- a/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
@@ -1573,139 +1573,217 @@ void tst_qquicktextinput::validators()
QQuickTextInput *intInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("intInput")));
QVERIFY(intInput);
+ QSignalSpy intSpy(intInput, SIGNAL(acceptableInputChanged()));
intInput->setFocus(true);
QTRY_VERIFY(intInput->hasActiveFocus());
+ QCOMPARE(intInput->hasAcceptableInput(), false);
+ QCOMPARE(intInput->property("acceptable").toBool(), false);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
+ QCOMPARE(intInput->property("acceptable").toBool(), false);
+ QCOMPARE(intSpy.count(), 0);
QTest::keyPress(&canvas, Qt::Key_2);
QTest::keyRelease(&canvas, Qt::Key_2, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
+ QCOMPARE(intInput->property("acceptable").toBool(), false);
+ QCOMPARE(intSpy.count(), 0);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QCOMPARE(intInput->text(), QLatin1String("11"));
QCOMPARE(intInput->hasAcceptableInput(), true);
+ QCOMPARE(intInput->property("acceptable").toBool(), true);
+ QCOMPARE(intSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_0);
QTest::keyRelease(&canvas, Qt::Key_0, Qt::NoModifier ,10);
QTest::qWait(50);
QCOMPARE(intInput->text(), QLatin1String("11"));
QCOMPARE(intInput->hasAcceptableInput(), true);
+ QCOMPARE(intInput->property("acceptable").toBool(), true);
+ QCOMPARE(intSpy.count(), 1);
QQuickTextInput *dblInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("dblInput")));
- QTRY_VERIFY(dblInput);
+ QVERIFY(dblInput);
+ QSignalSpy dblSpy(dblInput, SIGNAL(acceptableInputChanged()));
dblInput->setFocus(true);
QVERIFY(dblInput->hasActiveFocus() == true);
+ QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 0);
QTest::keyPress(&canvas, Qt::Key_2);
QTest::keyRelease(&canvas, Qt::Key_2, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QCOMPARE(dblInput->property("acceptable").toBool(), true);
+ QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_Period);
QTest::keyRelease(&canvas, Qt::Key_Period, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QCOMPARE(dblInput->property("acceptable").toBool(), true);
+ QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QCOMPARE(dblInput->property("acceptable").toBool(), true);
+ QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QCOMPARE(dblInput->property("acceptable").toBool(), true);
+ QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QCOMPARE(dblInput->property("acceptable").toBool(), true);
+ QCOMPARE(dblSpy.count(), 1);
// Ensure the validator doesn't prevent characters being removed.
dblInput->setValidator(intInput->validator());
QCOMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&canvas, Qt::Key_Backspace);
QTest::keyRelease(&canvas, Qt::Key_Backspace, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 2);
// Once unacceptable input is in anything goes until it reaches an acceptable state again.
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&canvas, Qt::Key_Backspace);
QTest::keyRelease(&canvas, Qt::Key_Backspace, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&canvas, Qt::Key_Backspace);
QTest::keyRelease(&canvas, Qt::Key_Backspace, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&canvas, Qt::Key_Backspace);
QTest::keyRelease(&canvas, Qt::Key_Backspace, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&canvas, Qt::Key_Backspace);
QTest::keyRelease(&canvas, Qt::Key_Backspace, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
+ QCOMPARE(dblInput->property("acceptable").toBool(), false);
+ QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QCOMPARE(dblInput->text(), QLatin1String("11"));
+ QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblInput->hasAcceptableInput(), true);
+ QCOMPARE(dblSpy.count(), 3);
QQuickTextInput *strInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("strInput")));
- QTRY_VERIFY(strInput);
+ QVERIFY(strInput);
+ QSignalSpy strSpy(strInput, SIGNAL(acceptableInputChanged()));
strInput->setFocus(true);
QVERIFY(strInput->hasActiveFocus() == true);
+ QCOMPARE(strInput->hasAcceptableInput(), false);
+ QCOMPARE(strInput->property("acceptable").toBool(), false);
QTest::keyPress(&canvas, Qt::Key_1);
QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(strInput->text(), QLatin1String(""));
QCOMPARE(strInput->hasAcceptableInput(), false);
+ QCOMPARE(strInput->property("acceptable").toBool(), false);
+ QCOMPARE(strSpy.count(), 0);
QTest::keyPress(&canvas, Qt::Key_A);
QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(strInput->text(), QLatin1String("a"));
QCOMPARE(strInput->hasAcceptableInput(), false);
+ QCOMPARE(strInput->property("acceptable").toBool(), false);
+ QCOMPARE(strSpy.count(), 0);
QTest::keyPress(&canvas, Qt::Key_A);
QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(strInput->text(), QLatin1String("aa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
+ QCOMPARE(strInput->property("acceptable").toBool(), true);
+ QCOMPARE(strSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_A);
QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(strInput->text(), QLatin1String("aaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
+ QCOMPARE(strInput->property("acceptable").toBool(), true);
+ QCOMPARE(strSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_A);
QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(strInput->text(), QLatin1String("aaaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
+ QCOMPARE(strInput->property("acceptable").toBool(), true);
+ QCOMPARE(strSpy.count(), 1);
QTest::keyPress(&canvas, Qt::Key_A);
QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
QTest::qWait(50);
QTRY_COMPARE(strInput->text(), QLatin1String("aaaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
+ QCOMPARE(strInput->property("acceptable").toBool(), true);
+ QCOMPARE(strSpy.count(), 1);
+
+ QQuickTextInput *unvalidatedInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(canvas.rootObject()->property("unvalidatedInput")));
+ QVERIFY(unvalidatedInput);
+ QSignalSpy unvalidatedSpy(unvalidatedInput, SIGNAL(acceptableInputChanged()));
+ unvalidatedInput->setFocus(true);
+ QVERIFY(unvalidatedInput->hasActiveFocus() == true);
+ QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
+ QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
+ QTest::keyPress(&canvas, Qt::Key_1);
+ QTest::keyRelease(&canvas, Qt::Key_1, Qt::NoModifier ,10);
+ QTest::qWait(50);
+ QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1"));
+ QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
+ QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
+ QCOMPARE(unvalidatedSpy.count(), 0);
+ QTest::keyPress(&canvas, Qt::Key_A);
+ QTest::keyRelease(&canvas, Qt::Key_A, Qt::NoModifier ,10);
+ QTest::qWait(50);
+ QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1a"));
+ QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
+ QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
+ QCOMPARE(unvalidatedSpy.count(), 0);
}
void tst_qquicktextinput::inputMethods()