diff options
-rw-r--r-- | src/quick/items/qquicktextinput.cpp | 62 | ||||
-rw-r--r-- | src/quick/items/qquicktextinput_p_p.h | 17 | ||||
-rw-r--r-- | tests/auto/qtquick2/qquicktextinput/data/validators.qml | 7 | ||||
-rw-r--r-- | tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp | 82 |
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() |