From b25035e51289d6f5f50ee967575c7c97c26a127c Mon Sep 17 00:00:00 2001
From: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
Date: Tue, 22 Jul 2014 17:39:53 +1000
Subject: [PATCH] Fix incorrect acceptableInput value on construction.

The value for acceptableInput was being calculated every time the
property value was read. This can lead to situations where the value
returned from successive property reads is different even though no
acceptableInputChanged() signal is emitted between the two calls.

This can be seen during QML component construction where emission of
the changed signal is suppressed until the component completes and the
value of acceptableInput changes as the other properties are set. If
the property is read during binding evaluation an intermediate value
can be seen and the QML engine will not re-read the property until
after the changed signal is emitted. This doesn't happen until the true
value of the acceptableInput property is toggled.

Fixed by changing the property getter to returned the precalculated
value of acceptableInput and ensuring that this value is set when
correctly.

Change-Id: Id3ba3a34988ff50f590e4f8330b873f390eaa025
Reviewed-by: Martin Jones <martin.jones@jollamobile.com>
---
 src/quick/items/qquicktextinput.cpp           | 27 ++++++++++++++++---
 .../qquicktextinput/tst_qquicktextinput.cpp   |  6 ++---
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index f3f9d0b5aa..37b103613d 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1199,7 +1199,7 @@ void QQuickTextInput::setInputMask(const QString &im)
 bool QQuickTextInput::hasAcceptableInput() const
 {
     Q_D(const QQuickTextInput);
-    return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
+    return d->m_acceptableInput;
 }
 
 /*!
@@ -2589,7 +2589,7 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
                 && !persistentSelection)
             deselect();
 
-        if (q->hasAcceptableInput() || fixup())
+        if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
             emit q->editingFinished();
 
 #ifndef QT_NO_IM
@@ -3415,6 +3415,27 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
             }
         }
 #endif
+
+        if (m_maskData) {
+            if (m_text.length() != m_maxLength) {
+                m_acceptableInput = false;
+            } else {
+                for (int i = 0; i < m_maxLength; ++i) {
+                    if (m_maskData[i].separator) {
+                        if (m_text.at(i) != m_maskData[i].maskChar) {
+                            m_acceptableInput = false;
+                            break;
+                        }
+                    } else {
+                        if (!isValidInput(m_text.at(i), m_maskData[i].maskChar)) {
+                            m_acceptableInput = false;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
             if (m_transactions.count())
                 return false;
@@ -4199,7 +4220,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
     Q_Q(QQuickTextInput);
 
     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
-        if (q->hasAcceptableInput() || fixup()) {
+        if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
             emit q->accepted();
             emit q->editingFinished();
         }
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index fc1be16bc8..e5ef83ba32 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -6272,13 +6272,11 @@ void tst_qquicktextinput::hasAcceptableInputMask()
     textInput->setText(invalid);
     QVERIFY(textInput->hasAcceptableInput());
 
-    // at the moment we don't strip the blank character if it is valid input, this makes the test between x vs X useless
-    QEXPECT_FAIL( "Any optional and required", "To eat blanks or not? Known issue. Task 43172", Abort);
-
     // test requiredMask
     textInput->setInputMask(requiredMask);
     textInput->setText(invalid);
-    QVERIFY(!textInput->hasAcceptableInput());
+    // invalid text gets the input mask applied when setting, text becomes acceptable.
+    QVERIFY(textInput->hasAcceptableInput());
 
     textInput->setText(valid);
     QVERIFY(textInput->hasAcceptableInput());
-- 
GitLab