diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 49084639d5..844d1ede6b 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3081,13 +3081,6 @@ void QQuickItem::setInputMethodHints(Qt::InputMethodHints hints) qApp->inputPanel()->update(Qt::ImHints); } -void QQuickItem::updateMicroFocus() -{ - QInputPanel *p = qApp->inputPanel(); - if (p->inputItem() == this) - qApp->inputPanel()->update(Qt::ImQueryInput); -} - QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const { Q_D(const QQuickItem); @@ -3608,6 +3601,15 @@ void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value) Q_UNUSED(value); } +/*! + Notify input method on updated query values if needed. \a indicates changed attributes. +*/ +void QQuickItem::updateInputMethod(Qt::InputMethodQueries queries) +{ + if (hasActiveFocus()) + qApp->inputPanel()->update(queries); +} + /*! \internal */ // XXX todo - do we want/need this anymore? // Note that it's now used for varying clip rect diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 0dd896af3d..684910a112 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -324,7 +324,6 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QDeclarativeParserStatu public Q_SLOTS: void update(); - void updateMicroFocus(); Q_SIGNALS: void childrenRectChanged(const QRectF &); @@ -359,6 +358,8 @@ public Q_SLOTS: bool isComponentComplete() const; virtual void itemChange(ItemChange, const ItemChangeData &); + void updateInputMethod(Qt::InputMethodQueries queries = Qt::ImQueryInput); + void setImplicitWidth(qreal); bool widthValid() const; // ### better name? void setImplicitHeight(qreal); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 37c76c09a3..126003906e 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -373,6 +373,7 @@ void QQuickTextEdit::setFont(const QFont &font) } updateSize(); updateDocument(); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont); } emit fontChanged(d->sourceFont); } @@ -1248,6 +1249,7 @@ void QQuickTextEdit::setReadOnly(bool r) if (!r) d->control->moveCursor(QTextCursor::End); + updateInputMethod(Qt::ImEnabled); q_canPasteChanged(); emit readOnlyChanged(r); } @@ -1853,7 +1855,7 @@ void QQuickTextEdit::moveCursorDelegate() { Q_D(QQuickTextEdit); d->determineHorizontalAlignment(); - updateMicroFocus(); + updateInputMethod(); emit cursorRectangleChanged(); if (!d->cursor) return; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 08892e1922..9d36ded9cc 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -306,7 +306,7 @@ void QQuickTextInput::setFont(const QFont &font) if (oldFont != d->font) { d->updateLayout(); updateCursorRectangle(); - qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont); } emit fontChanged(d->sourceFont); } @@ -575,6 +575,7 @@ void QQuickTextInput::setReadOnly(bool ro) d->m_readOnly = ro; if (!ro) d->setCursorPosition(d->end()); + updateInputMethod(Qt::ImEnabled); q_canPasteChanged(); d->emitUndoRedoChanged(); emit readOnlyChanged(ro); @@ -2508,6 +2509,7 @@ void QQuickTextInput::updateCursorRectangle() d->cursorItem->setPos(r.topLeft()); d->cursorItem->setHeight(r.height()); } + updateInputMethod(Qt::ImCursorRectangle); } void QQuickTextInput::selectionChanged() @@ -2873,8 +2875,8 @@ void QQuickTextInputPrivate::setSelection(int start, int length) } emit q->selectionChanged(); emitCursorPositionChanged(); - qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition - | Qt::ImCursorPosition | Qt::ImCurrentSelection); + q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition + | Qt::ImCursorPosition | Qt::ImCurrentSelection); } /*! @@ -2964,7 +2966,7 @@ void QQuickTextInputPrivate::moveCursor(int pos, bool mark) emit q->selectionChanged(); } emitCursorPositionChanged(); - q->updateMicroFocus(); + q->updateInputMethod(); } /*! @@ -3065,7 +3067,6 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) emitCursorPositionChanged(); } else if (m_preeditCursor != oldPreeditCursor) { q->updateCursorRectangle(); - qApp->inputPanel()->update(Qt::ImCursorRectangle); } bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString(); @@ -3080,8 +3081,8 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) if (selectionChange) { emit q->selectionChanged(); - qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition - | Qt::ImCursorPosition | Qt::ImCurrentSelection); + q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition + | Qt::ImCursorPosition | Qt::ImCurrentSelection); } } @@ -3123,7 +3124,7 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo Q_Q(QQuickTextInput); Q_UNUSED(update) - bool notifyInputPanel = m_textDirty || m_selDirty; + bool inputMethodAttributesChanged = m_textDirty || m_selDirty; bool alignmentChanged = false; if (m_textDirty) { @@ -3194,9 +3195,9 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo emit q->selectionChanged(); } - notifyInputPanel |= (m_cursor == m_lastCursorPos); - if (notifyInputPanel) - q->updateMicroFocus(); + inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos); + if (inputMethodAttributesChanged) + q->updateInputMethod(); emitUndoRedoChanged(); if (!emitCursorPositionChanged() && alignmentChanged) diff --git a/tests/auto/qtquick2/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/qtquick2/qquicktextedit/tst_qquicktextedit.cpp index 1d63145b2f..861f7a9efc 100644 --- a/tests/auto/qtquick2/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/qtquick2/qquicktextedit/tst_qquicktextedit.cpp @@ -144,6 +144,7 @@ private slots: void canPaste(); void canPasteEmpty(); void textInput(); + void inputPanelUpdate(); void openInputPanel(); void geometrySignals(); void pastingRichText_QTBUG_14003(); @@ -226,7 +227,7 @@ void tst_qquicktextedit::simulateKeys(QWindow *window, const QList &keys) void tst_qquicktextedit::simulateKeys(QWindow *window, const QKeySequence &sequence) { - for (uint i = 0; i < sequence.count(); ++i) { + for (int i = 0; i < sequence.count(); ++i) { const int key = sequence[i]; const int modifiers = key & Qt::KeyboardModifierMask; @@ -236,7 +237,7 @@ void tst_qquicktextedit::simulateKeys(QWindow *window, const QKeySequence &seque QList &operator <<(QList &keys, const QKeySequence &sequence) { - for (uint i = 0; i < sequence.count(); ++i) + for (int i = 0; i < sequence.count(); ++i) keys << Key(sequence[i], QChar()); return keys; } @@ -2131,6 +2132,100 @@ void tst_qquicktextedit::textInput() QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event2); QCOMPARE(spy.count(), 1); QCOMPARE(edit->text(), QString("string")); + + QInputMethodQueryEvent queryEvent(Qt::ImEnabled); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &queryEvent); + QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), true); + + edit->setReadOnly(true); + QGuiApplication::sendEvent(edit, &queryEvent); + QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), false); +} + +void tst_qquicktextedit::inputPanelUpdate() +{ + PlatformInputContext platformInputContext; + QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel()); + inputPanelPrivate->testContext = &platformInputContext; + + QQuickView view(testFileUrl("inputMethodEvent.qml")); + view.show(); + view.requestActivateWindow(); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(&view, qGuiApp->focusWindow()); + QQuickTextEdit *edit = qobject_cast(view.rootObject()); + QVERIFY(edit); + QVERIFY(edit->hasActiveFocus() == true); + + // text change even without cursor position change needs to trigger update + edit->setText("test"); + platformInputContext.clear(); + edit->setText("xxxx"); + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // input method event replacing text + platformInputContext.clear(); + { + QInputMethodEvent inputMethodEvent; + inputMethodEvent.setCommitString("y", -1, 1); + QGuiApplication::sendEvent(edit, &inputMethodEvent); + } + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // input method changing selection + platformInputContext.clear(); + { + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 2, QVariant()); + QInputMethodEvent inputMethodEvent("", attributes); + QGuiApplication::sendEvent(edit, &inputMethodEvent); + } + QVERIFY(edit->selectionStart() != edit->selectionEnd()); + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // font changes + platformInputContext.clear(); + QFont font = edit->font(); + font.setBold(!font.bold()); + edit->setFont(font); + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // normal input + platformInputContext.clear(); + { + QInputMethodEvent inputMethodEvent; + inputMethodEvent.setCommitString("y"); + QGuiApplication::sendEvent(edit, &inputMethodEvent); + } + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // changing cursor position + platformInputContext.clear(); + edit->setCursorPosition(0); + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // continuing with selection + platformInputContext.clear(); + edit->moveCursorSelection(1); + QVERIFY(platformInputContext.m_updateCallCount > 0); + + // read only disabled input method + platformInputContext.clear(); + edit->setReadOnly(true); + QVERIFY(platformInputContext.m_updateCallCount > 0); + edit->setReadOnly(false); + + // no updates while no focus + edit->setFocus(false); + platformInputContext.clear(); + edit->setText("Foo"); + QCOMPARE(platformInputContext.m_updateCallCount, 0); + edit->setCursorPosition(1); + QCOMPARE(platformInputContext.m_updateCallCount, 0); + edit->selectAll(); + QCOMPARE(platformInputContext.m_updateCallCount, 0); + edit->setReadOnly(true); + QCOMPARE(platformInputContext.m_updateCallCount, 0); } void tst_qquicktextedit::openInputPanel() diff --git a/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp index cae38bcd73..8fc768f2ab 100644 --- a/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp @@ -222,7 +222,7 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList &keys) void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence) { - for (uint i = 0; i < sequence.count(); ++i) { + for (int i = 0; i < sequence.count(); ++i) { const int key = sequence[i]; const int modifiers = key & Qt::KeyboardModifierMask; @@ -232,7 +232,7 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequ QList &operator <<(QList &keys, const QKeySequence &sequence) { - for (uint i = 0; i < sequence.count(); ++i) + for (int i = 0; i < sequence.count(); ++i) keys << Key(sequence[i], QChar()); return keys; } @@ -1951,6 +1951,14 @@ void tst_qquicktextinput::inputMethods() event.setCommitString("replacement", -input->text().length(), input->text().length()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->selectionStart(), input->selectionEnd()); + + QInputMethodQueryEvent enabledQueryEvent(Qt::ImEnabled); + QGuiApplication::sendEvent(input, &enabledQueryEvent); + QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), true); + + input->setReadOnly(true); + QGuiApplication::sendEvent(input, &enabledQueryEvent); + QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false); } /* @@ -3081,6 +3089,24 @@ void tst_qquicktextinput::inputPanelUpdate() platformInputContext.clear(); input->setCursorPosition(0); QVERIFY(platformInputContext.m_updateCallCount > 0); + + // read only disabled input method + platformInputContext.clear(); + input->setReadOnly(true); + QVERIFY(platformInputContext.m_updateCallCount > 0); + input->setReadOnly(false); + + // no updates while no focus + input->setFocus(false); + platformInputContext.clear(); + input->setText("Foo"); + QCOMPARE(platformInputContext.m_updateCallCount, 0); + input->setCursorPosition(1); + QCOMPARE(platformInputContext.m_updateCallCount, 0); + input->selectAll(); + QCOMPARE(platformInputContext.m_updateCallCount, 0); + input->setReadOnly(true); + QCOMPARE(platformInputContext.m_updateCallCount, 0); } void tst_qquicktextinput::cursorRectangleSize()