summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/widgets/qlinecontrol.cpp54
-rw-r--r--src/gui/widgets/qlinecontrol_p.h26
-rw-r--r--tests/auto/qlineedit/tst_qlineedit.cpp51
3 files changed, 128 insertions, 3 deletions
diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp
index bf36033c08..84674a51d3 100644
--- a/src/gui/widgets/qlinecontrol.cpp
+++ b/src/gui/widgets/qlinecontrol.cpp
@@ -59,6 +59,22 @@
QT_BEGIN_NAMESPACE
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+static int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
+#endif
+
+/*!
+ \macro QT_GUI_PASSWORD_ECHO_DELAY
+
+ \internal
+
+ Defines the amount of time in milliseconds the last entered character
+ should be displayed unmasked in the Password echo mode.
+
+ If not defined in qplatformdefs.h there will be no delay in masking
+ password characters.
+*/
+
/*!
\internal
@@ -74,9 +90,25 @@ void QLineControl::updateDisplayText(bool forceUpdate)
else
str = m_text;
- if (m_echoMode == QLineEdit::Password || (m_echoMode == QLineEdit::PasswordEchoOnEdit
- && !m_passwordEchoEditing))
+ if (m_echoMode == QLineEdit::Password) {
str.fill(m_passwordCharacter);
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ if (m_passwordEchoTimer != 0 && !str.isEmpty()) {
+ int cursor = m_text.length() - 1;
+ QChar uc = m_text.at(cursor);
+ str[cursor] = uc;
+ if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
+ // second half of a surrogate, check if we have the first half as well,
+ // if yes restore both at once
+ uc = m_text.at(cursor - 1);
+ if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
+ str[cursor - 1] = uc;
+ }
+ }
+#endif
+ } else if (m_echoMode == QLineEdit::PasswordEchoOnEdit && !m_passwordEchoEditing) {
+ str.fill(m_passwordCharacter);
+ }
// replace certain non-printable characters with spaces (to avoid
// drawing boxes when using fonts that don't have glyphs for such
@@ -311,6 +343,7 @@ void QLineControl::init(const QString &txt)
*/
void QLineControl::updatePasswordEchoEditing(bool editing)
{
+ cancelPasswordEchoTimer();
m_passwordEchoEditing = editing;
updateDisplayText();
}
@@ -640,6 +673,7 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited)
*/
void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
{
+ cancelPasswordEchoTimer();
internalDeselect();
emit resetInputContext();
QString oldText = m_text;
@@ -692,6 +726,13 @@ void QLineControl::addCommand(const Command &cmd)
*/
void QLineControl::internalInsert(const QString &s)
{
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ if (m_echoMode == QLineEdit::Password) {
+ if (m_passwordEchoTimer != 0)
+ killTimer(m_passwordEchoTimer);
+ m_passwordEchoTimer = startTimer(qt_passwordEchoDelay);
+ }
+#endif
if (hasSelectedText())
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
if (m_maskData) {
@@ -729,6 +770,7 @@ void QLineControl::internalInsert(const QString &s)
void QLineControl::internalDelete(bool wasBackspace)
{
if (m_cursor < (int) m_text.length()) {
+ cancelPasswordEchoTimer();
if (hasSelectedText())
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
@@ -755,6 +797,7 @@ void QLineControl::internalDelete(bool wasBackspace)
void QLineControl::removeSelectedText()
{
if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
+ cancelPasswordEchoTimer();
separate();
int i ;
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
@@ -1153,6 +1196,7 @@ void QLineControl::internalUndo(int until)
{
if (!isUndoAvailable())
return;
+ cancelPasswordEchoTimer();
internalDeselect();
while (m_undoState && m_undoState > until) {
Command& cmd = m_history[--m_undoState];
@@ -1357,6 +1401,12 @@ void QLineControl::timerEvent(QTimerEvent *event)
} else if (event->timerId() == m_tripleClickTimer) {
killTimer(m_tripleClickTimer);
m_tripleClickTimer = 0;
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ } else if (event->timerId() == m_passwordEchoTimer) {
+ killTimer(m_passwordEchoTimer);
+ m_passwordEchoTimer = 0;
+ updateDisplayText();
+#endif
}
}
diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h
index c6105f8472..44bd7214be 100644
--- a/src/gui/widgets/qlinecontrol_p.h
+++ b/src/gui/widgets/qlinecontrol_p.h
@@ -66,6 +66,8 @@
#include "QtGui/qcompleter.h"
#include "QtGui/qaccessible.h"
+#include "qplatformdefs.h"
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -85,6 +87,9 @@ public:
m_ascent(0), m_maxLength(32767), m_lastCursorPos(-1),
m_tripleClickTimer(0), m_maskData(0), m_modifiedState(0), m_undoState(0),
m_selstart(0), m_selend(0), m_passwordEchoEditing(false)
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ , m_passwordEchoTimer(0)
+#endif
{
init(txt);
}
@@ -222,6 +227,7 @@ public:
uint echoMode() const { return m_echoMode; }
void setEchoMode(uint mode)
{
+ cancelPasswordEchoTimer();
m_echoMode = mode;
m_passwordEchoEditing = false;
updateDisplayText();
@@ -271,7 +277,13 @@ public:
QString preeditAreaText() const { return m_textLayout.preeditAreaText(); }
void updatePasswordEchoEditing(bool editing);
- bool passwordEchoEditing() const { return m_passwordEchoEditing; }
+ bool passwordEchoEditing() const {
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ if (m_passwordEchoTimer != 0)
+ return true;
+#endif
+ return m_passwordEchoEditing ;
+ }
QChar passwordCharacter() const { return m_passwordCharacter; }
void setPasswordCharacter(const QChar &character) { m_passwordCharacter = character; updateDisplayText(); }
@@ -426,6 +438,18 @@ private:
bool m_passwordEchoEditing;
QChar m_passwordCharacter;
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ int m_passwordEchoTimer;
+#endif
+ void cancelPasswordEchoTimer()
+ {
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ if (m_passwordEchoTimer != 0) {
+ killTimer(m_passwordEchoTimer);
+ m_passwordEchoTimer = 0;
+ }
+#endif
+ }
Q_SIGNALS:
void cursorPositionChanged(int, int);
diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp
index 92574ea01b..d178e26476 100644
--- a/tests/auto/qlineedit/tst_qlineedit.cpp
+++ b/tests/auto/qlineedit/tst_qlineedit.cpp
@@ -72,6 +72,8 @@
#include "qcommonstyle.h"
#include "qstyleoption.h"
+#include "qplatformdefs.h"
+
QT_BEGIN_NAMESPACE
class QPainter;
QT_END_NAMESPACE
@@ -180,6 +182,10 @@ private slots:
void echoMode();
void passwordEchoOnEdit();
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+ void passwordEchoDelay();
+#endif
+
void maxLength_mask_data();
void maxLength_mask();
@@ -1679,6 +1685,51 @@ void tst_QLineEdit::passwordEchoOnEdit()
testWidget->setEchoMode(QLineEdit::Normal);
}
+#ifdef QT_GUI_PASSWORD_ECHO_DELAY
+void tst_QLineEdit::passwordEchoDelay()
+{
+ QStyleOptionFrameV2 opt;
+ QChar fillChar = testWidget->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, testWidget);
+
+ testWidget->setEchoMode(QLineEdit::Password);
+ testWidget->setFocus();
+ testWidget->raise();
+ QTRY_VERIFY(testWidget->hasFocus());
+
+ QTest::keyPress(testWidget, '0');
+ QTest::keyPress(testWidget, '1');
+ QTest::keyPress(testWidget, '2');
+ QCOMPARE(testWidget->displayText(), QString(2, fillChar) + QLatin1Char('2'));
+ QTest::keyPress(testWidget, '3');
+ QTest::keyPress(testWidget, '4');
+ QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4'));
+ QTest::keyPress(testWidget, Qt::Key_Backspace);
+ QCOMPARE(testWidget->displayText(), QString(4, fillChar));
+ QTest::keyPress(testWidget, '4');
+ QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4'));
+ QTest::qWait(QT_GUI_PASSWORD_ECHO_DELAY);
+ QTRY_COMPARE(testWidget->displayText(), QString(5, fillChar));
+ QTest::keyPress(testWidget, '5');
+ QCOMPARE(testWidget->displayText(), QString(5, fillChar) + QLatin1Char('5'));
+ testWidget->clearFocus();
+ QVERIFY(!testWidget->hasFocus());
+ QCOMPARE(testWidget->displayText(), QString(6, fillChar));
+ testWidget->setFocus();
+ QTRY_VERIFY(testWidget->hasFocus());
+ QCOMPARE(testWidget->displayText(), QString(6, fillChar));
+ QTest::keyPress(testWidget, '6');
+ QCOMPARE(testWidget->displayText(), QString(6, fillChar) + QLatin1Char('6'));
+
+ QInputMethodEvent ev;
+ ev.setCommitString(QLatin1String("7"));
+ QApplication::sendEvent(testWidget, &ev);
+ QCOMPARE(testWidget->displayText(), QString(7, fillChar) + QLatin1Char('7'));
+
+ // restore clean state
+ testWidget->setEchoMode(QLineEdit::Normal);
+}
+#endif
+
void tst_QLineEdit::maxLength_mask_data()
{
QTest::addColumn<QString>("mask");