From 249754bf7fe4a195c723eea73f2dd55a2bd905cb Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 19 Jul 2011 15:15:58 +1000 Subject: [PATCH] Delay masking the last character in Password echo mode. If QT_GUI_PASSWORD_ECHO_DELAY is defined in qplatformdefs.h with an integer value in milliseconds, QLineEdit and TextInput will display the last character entered unmasked for that delay period and then mask the character as normal. If QT_GUI_PASSWORD_ECHO_DELAY is not defined then the behaviour is unchanged. Task-number: QTBUG-17003 Reviewed-by: Martin Jones (cherry picked from commit f9e7aee2019d321edd655bfde7de43f20a106971) Change-Id: Iddfa0daa1b39f0589cab27e5003fdd86ad81ff89 Reviewed-on: http://codereview.qt.nokia.com/4170 Reviewed-by: Andrew den Exter --- src/declarative/items/qsgtextinput.cpp | 2 +- .../graphicsitems/qdeclarativetextinput.cpp | 2 +- .../declarative/qsgtextinput/tst_qsgtextinput.cpp | 58 +++++++++++++++++++ .../tst_qdeclarativetextinput.cpp | 61 ++++++++++++++++++++ 4 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/declarative/items/qsgtextinput.cpp b/src/declarative/items/qsgtextinput.cpp index 222a900..01e5173 100644 --- a/src/declarative/items/qsgtextinput.cpp +++ b/src/declarative/items/qsgtextinput.cpp @@ -1817,7 +1817,7 @@ void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value) bool hasFocus = value.boolValue; d->focused = hasFocus; setCursorVisible(hasFocus && d->canvas && d->canvas->hasFocus()); - if(echoMode() == QSGTextInput::PasswordEchoOnEdit && !hasFocus) + if(!hasFocus && d->control->passwordEchoEditing()) d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events if (!hasFocus) d->control->deselect(); diff --git a/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp b/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp index a14d837..c61a3ff 100644 --- a/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp @@ -1058,7 +1058,7 @@ void QDeclarative1TextInputPrivate::focusChanged(bool hasFocus) Q_Q(QDeclarative1TextInput); focused = hasFocus; q->setCursorVisible(hasFocus && scene && scene->hasFocus()); - if(q->echoMode() == QDeclarative1TextInput::PasswordEchoOnEdit && !hasFocus) + if(!hasFocus && control->passwordEchoEditing()) control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events if (!hasFocus) control->deselect(); diff --git a/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp b/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp index 32e59c2..1ada689 100644 --- a/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp +++ b/tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp @@ -55,6 +55,8 @@ #include #include +#include "qplatformdefs.h" + #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir #define SRCDIR "." @@ -132,6 +134,9 @@ private slots: void focusOutClearSelection(); void echoMode(); +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + void passwordEchoDelay(); +#endif void geometrySignals(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); @@ -1944,6 +1949,59 @@ void tst_qsgtextinput::echoMode() QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial); } +#ifdef QT_GUI_PASSWORD_ECHO_DELAY +void tst_qdeclarativetextinput::passwordEchoDelay() +{ + QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/echoMode.qml")); + canvas.show(); + canvas.setFocus(); + QApplication::setActiveWindow(&canvas); + QTest::qWaitForWindowShown(&canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&canvas)); + + QVERIFY(canvas.rootObject() != 0); + + QSGTextInput *input = qobject_cast(qvariant_cast(canvas.rootObject()->property("myInput"))); + + QChar fillChar = QLatin1Char('*'); + + input->setEchoMode(QDeclarativeTextInput::Password); + QCOMPARE(input->displayText(), QString(8, fillChar)); + input->setText(QString()); + QCOMPARE(input->displayText(), QString()); + + QTest::keyPress(&canvas, '0'); + QTest::keyPress(&canvas, '1'); + QTest::keyPress(&canvas, '2'); + QCOMPARE(input->displayText(), QString(2, fillChar) + QLatin1Char('2')); + QTest::keyPress(&canvas, '3'); + QTest::keyPress(&canvas, '4'); + QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::keyPress(&canvas, Qt::Key_Backspace); + QCOMPARE(input->displayText(), QString(4, fillChar)); + QTest::keyPress(&canvas, '4'); + QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::qWait(QT_GUI_PASSWORD_ECHO_DELAY); + QTRY_COMPARE(input->displayText(), QString(5, fillChar)); + QTest::keyPress(&canvas, '5'); + QCOMPARE(input->displayText(), QString(5, fillChar) + QLatin1Char('5')); + input->setFocus(false); + QVERIFY(!input->hasFocus()); + QCOMPARE(input->displayText(), QString(6, fillChar)); + input->setFocus(true); + QTRY_VERIFY(input->hasFocus()); + QCOMPARE(input->displayText(), QString(6, fillChar)); + QTest::keyPress(&canvas, '6'); + QCOMPARE(input->displayText(), QString(6, fillChar) + QLatin1Char('6')); + + QInputMethodEvent ev; + ev.setCommitString(QLatin1String("7")); + QApplication::sendEvent(&canvas, &ev); + QCOMPARE(input->displayText(), QString(7, fillChar) + QLatin1Char('7')); +} +#endif + + void tst_qsgtextinput::simulateKey(QSGView *view, int key) { QKeyEvent press(QKeyEvent::KeyPress, key, 0); diff --git a/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 2d86a4b..fe77312 100644 --- a/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -52,6 +52,8 @@ #include #include +#include "qplatformdefs.h" + #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir #define SRCDIR "." @@ -133,6 +135,9 @@ private slots: void focusOutClearSelection(); void echoMode(); +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + void passwordEchoDelay(); +#endif void geometrySignals(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); @@ -2062,6 +2067,62 @@ void tst_qdeclarativetextinput::echoMode() delete canvas; } + +#ifdef QT_GUI_PASSWORD_ECHO_DELAY +void tst_qdeclarativetextinput::passwordEchoDelay() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/echoMode.qml"); + canvas->show(); + canvas->setFocus(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(canvas)); + + QVERIFY(canvas->rootObject() != 0); + + QDeclarative1TextInput *input = qobject_cast(qvariant_cast(canvas->rootObject()->property("myInput"))); + + QChar fillChar = QLatin1Char('*'); + + input->setEchoMode(QDeclarativeTextInput::Password); + QCOMPARE(input->displayText(), QString(8, fillChar)); + input->setText(QString()); + QCOMPARE(input->displayText(), QString()); + + QTest::keyPress(canvas, '0'); + QTest::keyPress(canvas, '1'); + QTest::keyPress(canvas, '2'); + QCOMPARE(input->displayText(), QString(2, fillChar) + QLatin1Char('2')); + QTest::keyPress(canvas, '3'); + QTest::keyPress(canvas, '4'); + QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::keyPress(canvas, Qt::Key_Backspace); + QCOMPARE(input->displayText(), QString(4, fillChar)); + QTest::keyPress(canvas, '4'); + QCOMPARE(input->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::qWait(QT_GUI_PASSWORD_ECHO_DELAY); + QTRY_COMPARE(input->displayText(), QString(5, fillChar)); + QTest::keyPress(canvas, '5'); + QCOMPARE(input->displayText(), QString(5, fillChar) + QLatin1Char('5')); + input->setFocus(false); + QVERIFY(!input->hasFocus()); + QCOMPARE(input->displayText(), QString(6, fillChar)); + input->setFocus(true); + QTRY_VERIFY(input->hasFocus()); + QCOMPARE(input->displayText(), QString(6, fillChar)); + QTest::keyPress(canvas, '6'); + QCOMPARE(input->displayText(), QString(6, fillChar) + QLatin1Char('6')); + + QInputMethodEvent ev; + ev.setCommitString(QLatin1String("7")); + QApplication::sendEvent(canvas, &ev); + QCOMPARE(input->displayText(), QString(7, fillChar) + QLatin1Char('7')); + + delete canvas; +} +#endif + + void tst_qdeclarativetextinput::simulateKey(QDeclarativeView *view, int key) { QKeyEvent press(QKeyEvent::KeyPress, key, 0); -- 1.7.2.5