diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 6920354e73..ba7e2ddacf 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -1279,6 +1279,13 @@ void QWidgetLineControl::internalUndo(int until) return; cancelPasswordEchoTimer(); internalDeselect(); + + // Undo works only for clearing the line when in any of password the modes + if (m_echoMode != QLineEdit::Normal) { + clear(); + return; + } + while (m_undoState && m_undoState > until) { Command& cmd = m_history[--m_undoState]; switch (cmd.type) { @@ -1868,6 +1875,21 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) event->accept(); } +bool QWidgetLineControl::isUndoAvailable() const +{ + // For security reasons undo is not available in any password mode (NoEcho included) + // with the exception that the user can clear the password with undo. + return !m_readOnly && m_undoState + && (m_echoMode == QLineEdit::Normal || m_history[m_undoState - 1].type == QWidgetLineControl::Insert); +} + +bool QWidgetLineControl::isRedoAvailable() const +{ + // Same as with undo. Disabled for password modes. + return !m_readOnly + && m_echoMode == QLineEdit::Normal + && m_undoState < m_history.size(); +} QT_END_NAMESPACE diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index ba3b202bda..2dce790c1e 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -125,8 +125,8 @@ public: return (c != -1 ? c : 0); } - bool isUndoAvailable() const { return !m_readOnly && m_undoState; } - bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); } + bool isUndoAvailable() const; + bool isRedoAvailable() const; void clearUndo() { m_history.clear(); m_modifiedState = m_undoState = 0; } bool isModified() const { return m_modifiedState != m_undoState; } diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 956f970b85..ed53a133e4 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -287,6 +287,9 @@ private slots: void inputMethodQueryImHints_data(); void inputMethodQueryImHints(); + void undoRedoAndEchoModes_data(); + void undoRedoAndEchoModes(); + protected slots: void editingFinished(); @@ -3954,5 +3957,68 @@ void tst_QLineEdit::inputMethodQueryImHints() QCOMPARE(static_cast(value.toInt()), hints); } +void tst_QLineEdit::undoRedoAndEchoModes_data() +{ + QTest::addColumn("echoMode"); + QTest::addColumn("input"); + QTest::addColumn("expected"); + + QStringList input(QList() << "aaa" << "bbb" << "ccc"); + + QTest::newRow("Normal") + << (int) QLineEdit::Normal + << input + << QStringList(QList() << "aaa" << "ccc" << ""); + + QTest::newRow("NoEcho") + << (int) QLineEdit::NoEcho + << input + << QStringList(QList() << "" << "" << ""); + + QTest::newRow("Password") + << (int) QLineEdit::Password + << input + << QStringList(QList() << "" << "" << ""); + + QTest::newRow("PasswordEchoOnEdit") + << (int) QLineEdit::PasswordEchoOnEdit + << input + << QStringList(QList() << "" << "" << ""); +} + +void tst_QLineEdit::undoRedoAndEchoModes() +{ + QFETCH(int, echoMode); + QFETCH(QStringList, input); + QFETCH(QStringList, expected); + + // create some history for the QLineEdit + testWidget->clear(); + testWidget->setEchoMode(QLineEdit::EchoMode(echoMode)); + testWidget->insert(input.at(0)); + testWidget->selectAll(); + testWidget->backspace(); + testWidget->insert(input.at(1)); + + // test undo + QVERIFY(testWidget->isUndoAvailable()); + testWidget->undo(); + QCOMPARE(testWidget->text(), expected.at(0)); + testWidget->insert(input.at(2)); + testWidget->selectAll(); + testWidget->backspace(); + QCOMPARE(testWidget->isUndoAvailable(), echoMode == QLineEdit::Normal); + testWidget->undo(); + QCOMPARE(testWidget->text(), expected.at(1)); + + // test redo + QCOMPARE(testWidget->isRedoAvailable(), echoMode == QLineEdit::Normal); + testWidget->redo(); + QCOMPARE(testWidget->text(), expected.at(2)); + QVERIFY(!testWidget->isRedoAvailable()); + testWidget->redo(); + QCOMPARE(testWidget->text(), expected.at(2)); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc"