aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBartlomiej Moskal <bartlomiej.moskal@qt.io>2021-01-19 11:47:54 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-02-19 11:18:57 +0000
commit39a214773d554a1a03b49a7ab08b0a60a59c8279 (patch)
tree6979da87162fd92c433c72cb247a39056be6a86b /src
parent85e622f8637c93c7fa54efc905e13534af507e59 (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.cpp20
-rw-r--r--src/quick/items/qquicktextinput_p_p.h10
2 files changed, 28 insertions, 2 deletions
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index d423e6b656..faa1d5fb43 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; }