diff options
author | Bartlomiej Moskal <bartlomiej.moskal@qt.io> | 2021-01-19 11:47:54 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-02-19 11:18:57 +0000 |
commit | f839f2f3d6bcdc1a9b87a35b8f308ec5bc6c583d (patch) | |
tree | 9562338d0fef84caaab2d30d5b3e0aaf487df701 /src | |
parent | dae0fe461b26b6db85586db1979bc1d9fb05670b (diff) |
qquicktextinput: Fix validation for IM event
If validation did not pass after text pre-editing is finished, it need
to be roll back to state before pre-editing started.
Before this change, if validation did not pass, text was always rolled
back to previous state. In pre-editing text case, it means back to the
state in which part of the text was removed (and later changed to
pre-edited text). It may cause a situation of removing part of the text
that was already validated
Fixes: QTBUG-90239
Change-Id: I3ec39e0f6b8a93d4e6fd190af30d4c80a0e495eb
Reviewed-by: Rami Potinkara <rami.potinkara@qt.io>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
(cherry picked from commit b1ae151acc80254ab0ec2937c55b99223205875c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/items/qquicktextinput.cpp | 20 | ||||
-rw-r--r-- | src/quick/items/qquicktextinput_p_p.h | 10 |
2 files changed, 28 insertions, 2 deletions
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index b1945e9eb8..419ac4a2bb 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -3471,8 +3471,12 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) } QString oldPreeditString = m_textLayout.preeditAreaText(); m_textLayout.setPreeditArea(m_cursor, event->preeditString()); - if (oldPreeditString != m_textLayout.preeditAreaText()) + if (oldPreeditString != m_textLayout.preeditAreaText()) { emit q->preeditTextChanged(); + if (!event->preeditString().isEmpty() && m_undoPreeditState == -1) + // Pre-edit text started. Remember state for undo purpose. + m_undoPreeditState = priorState; + } const int oldPreeditCursor = m_preeditCursor; m_preeditCursor = event->preeditString().length(); hasImState = !event->preeditString().isEmpty(); @@ -3515,6 +3519,11 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCurrentSelection); } + + // Empty pre-edit text handled. Clean m_undoPreeditState + if (event->preeditString().isEmpty()) + m_undoPreeditState = -1; + } #endif // im @@ -3591,6 +3600,12 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo if (m_maskData) checkIsValid(); +#if QT_CONFIG(im) + // If we were during pre-edit, validateFromState should point to the state before pre-edit + // has been started. Choose the correct oldest remembered state + if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0)) + validateFromState = m_undoPreeditState; +#endif if (validateFromState >= 0 && wasValidInput && !m_validInput) { if (m_transactions.count()) return false; @@ -3663,6 +3678,9 @@ void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool e } m_history.clear(); m_undoState = 0; +#if QT_CONFIG(im) + m_undoPreeditState = -1; +#endif m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos; m_textDirty = (oldText != m_text); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index cb965f2fed..b4561556aa 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -110,6 +110,7 @@ public: , m_cursor(0) #if QT_CONFIG(im) , m_preeditCursor(0) + , m_undoPreeditState(-1) #endif , m_blinkEnabled(false) , m_blinkTimer(0) @@ -248,6 +249,7 @@ public: int m_cursor; #if QT_CONFIG(im) int m_preeditCursor; + int m_undoPreeditState; #endif bool m_blinkEnabled; int m_blinkTimer; @@ -335,7 +337,13 @@ public: bool isUndoAvailable() const { return !m_readOnly && m_undoState; } bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); } - void clearUndo() { m_history.clear(); m_undoState = 0; } + void clearUndo() { + m_history.clear(); + m_undoState = 0; +#if QT_CONFIG(im) + m_undoPreeditState = -1; +#endif + } bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); } bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; } |