diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index 8d1795c3c2..583e6da90a 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -815,20 +815,19 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, lastFocusItem = focusItem; #ifndef QT_NO_IM - if (lastFocusItem - && (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) { + if (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod) { // Close any external input method panel. This happens // automatically by removing WA_InputMethodEnabled on // the views, but if we are changing focus, we have to // do it ourselves. if (qApp) - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); } +#endif //QT_NO_IM focusItem = 0; QFocusEvent event(QEvent::FocusOut, focusReason); sendEvent(lastFocusItem, &event); -#endif //QT_NO_IM } // This handles the case that the item has been removed from the diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 2615ac891d..a099faae3f 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -2042,7 +2042,7 @@ void QApplication::setActiveWindow(QWidget* act) if (QApplicationPrivate::focus_widget) { if (QApplicationPrivate::focus_widget->testAttribute(Qt::WA_InputMethodEnabled)) - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange, Qt::ActiveWindowFocusReason); QApplication::sendEvent(QApplicationPrivate::focus_widget, &focusAboutToChange); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 9a32d952f9..cccde764ad 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -3090,7 +3090,7 @@ void QWidgetPrivate::setEnabled_helper(bool enable) if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) qApp->inputMethod()->update(Qt::ImEnabled); } else { - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); qApp->inputMethod()->update(Qt::ImEnabled); } } @@ -5948,7 +5948,7 @@ void QWidget::setFocus(Qt::FocusReason reason) if (prev) { if (reason != Qt::PopupFocusReason && reason != Qt::MenuBarFocusReason && prev->testAttribute(Qt::WA_InputMethodEnabled)) { - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); } if (reason != Qt::NoFocusReason) { @@ -6057,7 +6057,7 @@ void QWidget::clearFocus() { if (hasFocus()) { if (testAttribute(Qt::WA_InputMethodEnabled)) - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange); QApplication::sendEvent(this, &focusAboutToChange); @@ -10087,7 +10087,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) QWidget *focusWidget = d->effectiveFocusWidget(); if (on && !internalWinId() && hasFocus() && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) { - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); qApp->inputMethod()->update(Qt::ImEnabled); } if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget() @@ -10137,7 +10137,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) #ifndef QT_NO_IM if (qApp->focusObject() == this) { if (!on) - qApp->inputMethod()->reset(); + qApp->inputMethod()->commit(); qApp->inputMethod()->update(Qt::ImEnabled); } #endif //QT_NO_IM diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 07843136ff..1ea636ffb2 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1669,7 +1669,7 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImCursorPosition: return QVariant(d->control->cursor()); case Qt::ImSurroundingText: - return QVariant(d->control->realText()); + return QVariant(d->control->text()); case Qt::ImCurrentSelection: return QVariant(selectedText()); case Qt::ImMaximumTextLength: @@ -1748,7 +1748,6 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) reason != Qt::PopupFocusReason) deselect(); - d->control->commitPreedit(); d->setCursorVisible(false); d->control->setCursorBlinkPeriod(0); #ifdef QT_KEYPAD_NAVIGATION diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index b4a7007190..20af574049 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -184,21 +184,15 @@ void QWidgetLineControl::paste(QClipboard::Mode clipboardMode) /*! \internal - - Exits preedit mode and commits parts marked as tentative commit */ void QWidgetLineControl::commitPreedit() { if (!composeMode()) return; - qApp->inputMethod()->reset(); - - if (!m_tentativeCommit.isEmpty()) { - internalInsert(m_tentativeCommit); - m_tentativeCommit.clear(); - finishChange(-1, true/*not used, not documented*/, false); - } + qApp->inputMethod()->commit(); + if (!composeMode()) + return; m_preeditCursor = 0; setPreeditArea(-1, QString()); @@ -573,13 +567,7 @@ void QWidgetLineControl::processInputMethodEvent(QInputMethodEvent *event) else if (m_preeditCursor != oldPreeditCursor) emit updateMicroFocus(); - bool tentativeCommitChanged = (m_tentativeCommit != event->tentativeCommitString()); - if (tentativeCommitChanged) { - m_textDirty = true; - m_tentativeCommit = event->tentativeCommitString(); - } - - if (isGettingInput || tentativeCommitChanged) + if (isGettingInput) finishChange(priorState); if (selectionChange) @@ -687,15 +675,6 @@ bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool e return true; } m_cursor = cursorCopy; - - if (!m_tentativeCommit.isEmpty()) { - textCopy.insert(m_cursor, m_tentativeCommit); - bool validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); - if (!validInput) - m_tentativeCommit.clear(); - } - } else { - m_tentativeCommit.clear(); } } #endif diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index 62184a27bb..ebc5758d4f 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -217,22 +217,13 @@ public: QString text() const { QString content = m_text; - if (!m_tentativeCommit.isEmpty()) - content.insert(m_cursor, m_tentativeCommit); QString res = m_maskData ? stripString(content) : content; return (res.isNull() ? QString::fromLatin1("") : res); } - // like text() but doesn't include preedit - QString realText() const - { - QString res = m_maskData ? stripString(m_text) : m_text; - return (res.isNull() ? QString::fromLatin1("") : res); - } void setText(const QString &txt) { if (composeMode()) qApp->inputMethod()->reset(); - m_tentativeCommit.clear(); internalSetText(txt, -1, false); } void commitPreedit(); @@ -402,7 +393,6 @@ private: int m_cursor; int m_preeditCursor; int m_cursorWidth; - QString m_tentativeCommit; Qt::LayoutDirection m_layoutDirection; uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas uint m_separator : 1; diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index 86dfb30389..d602d6daa5 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -2000,7 +2000,6 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } } layout->setAdditionalFormats(overrides); - tentativeCommit = e->tentativeCommitString(); cursor.endEditBlock(); @@ -2057,7 +2056,6 @@ void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e) } #endif } else { - commitPreedit(); setBlinkingCursorEnabled(false); if (cursorIsFocusIndicator @@ -2755,17 +2753,15 @@ bool QWidgetTextControlPrivate::isPreediting() const void QWidgetTextControlPrivate::commitPreedit() { + if (!isPreediting()) + return; + + qApp->inputMethod()->commit(); + if (!isPreediting()) return; cursor.beginEditBlock(); - qApp->inputMethod()->reset(); - - if (!tentativeCommit.isEmpty()) { - cursor.insertText(tentativeCommit); - tentativeCommit.clear(); - } - preeditCursor = 0; QTextBlock block = cursor.block(); QTextLayout *layout = block.layout(); @@ -2936,17 +2932,12 @@ bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags optio QString QWidgetTextControl::toPlainText() const { - Q_D(const QWidgetTextControl); - QString plainText = document()->toPlainText(); - if (!d->tentativeCommit.isEmpty()) - plainText.insert(textCursor().position(), d->tentativeCommit); - return plainText; + return document()->toPlainText(); } #ifndef QT_NO_TEXTHTMLPARSER QString QWidgetTextControl::toHtml() const { - // note: currently not including tentative commit return document()->toHtml(); } #endif diff --git a/src/widgets/widgets/qwidgettextcontrol_p_p.h b/src/widgets/widgets/qwidgettextcontrol_p_p.h index d0d940e521..4efb59152a 100644 --- a/src/widgets/widgets/qwidgettextcontrol_p_p.h +++ b/src/widgets/widgets/qwidgettextcontrol_p_p.h @@ -209,7 +209,6 @@ public: int preeditCursor; bool hideCursor; // used to hide the cursor in the preedit area - QString tentativeCommit; QVector extraSelections; diff --git a/tests/auto/shared/platforminputcontext.h b/tests/auto/shared/platforminputcontext.h index cddeca3945..2c1a3bcb25 100644 --- a/tests/auto/shared/platforminputcontext.h +++ b/tests/auto/shared/platforminputcontext.h @@ -61,7 +61,19 @@ public: virtual QRectF keyboardRect() const { return m_keyboardRect; } virtual bool isAnimating() const { return m_animating; } virtual void reset() { m_resetCallCount++; } - virtual void commit() { m_commitCallCount++; } + virtual void commit() { + m_commitCallCount++; + QInputMethodEvent commitEvent; + commitEvent.setCommitString(m_commitString); + if (qGuiApp->focusObject()) + qGuiApp->sendEvent(qGuiApp->focusObject(), &commitEvent); + else + qWarning("Test input context to commit without focused object"); + } + void setCommitString(const QString &commitString) + { + m_commitString = commitString; + } virtual void update(Qt::InputMethodQueries queries) { @@ -105,6 +117,7 @@ public: int m_updateCallCount; int m_resetCallCount; int m_commitCallCount; + QString m_commitString; mutable int m_localeCallCount; mutable int m_inputDirectionCallCount; Qt::InputMethodQueries m_lastQueries; diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index daa06d0762..8772fb1e7e 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -3784,6 +3784,7 @@ void tst_QGraphicsScene::inputMethod() QTRY_COMPARE(QApplication::activeWindow(), static_cast(&view)); inputContext.m_resetCallCount = 0; + inputContext.m_commitCallCount = 0; scene.addItem(item); QInputMethodEvent event; @@ -3802,7 +3803,7 @@ void tst_QGraphicsScene::inputMethod() scene.setFocusItem(0); // the input context is reset twice, once because an item has lost focus and again because // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus. - QCOMPARE(inputContext.m_resetCallCount, callFocusItem ? 2 : 0); + QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, callFocusItem ? 2 : 0); QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); // verify that value is unaffected item->eventCalls = 0; diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index ee7ec7ba57..19532a0e37 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -4187,21 +4187,22 @@ void tst_QGraphicsView::inputContextReset() item1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod); inputContext.m_resetCallCount = 0; + inputContext.m_commitCallCount = 0; scene.addItem(item1); QCOMPARE(inputContext.m_resetCallCount, 0); + QCOMPARE(inputContext.m_commitCallCount, 0); - inputContext.m_resetCallCount = 0; scene.setFocusItem(item1); QCOMPARE(scene.focusItem(), (QGraphicsItem *)item1); QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled)); QCOMPARE(inputContext.m_resetCallCount, 0); + QCOMPARE(inputContext.m_commitCallCount, 0); - inputContext.m_resetCallCount = 0; scene.setFocusItem(0); // the input context is reset twice, once because an item has lost focus and again because // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus. // QEXPECT_FAIL("", "QTBUG-22454", Abort); - QCOMPARE(inputContext.m_resetCallCount, 2); + QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 2); // introduce another item that is focusable but does not accept input methods QGraphicsItem *item2 = new QGraphicsRectItem; @@ -4209,17 +4210,19 @@ void tst_QGraphicsView::inputContextReset() scene.addItem(item2); inputContext.m_resetCallCount = 0; + inputContext.m_commitCallCount = 0; scene.setFocusItem(item2); QCOMPARE(inputContext.m_resetCallCount, 0); + QCOMPARE(inputContext.m_commitCallCount, 0); - inputContext.m_resetCallCount = 0; scene.setFocusItem(item1); QCOMPARE(inputContext.m_resetCallCount, 0); + QCOMPARE(inputContext.m_commitCallCount, 0); // test changing between between items that accept input methods. item2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod); scene.setFocusItem(item2); - QCOMPARE(inputContext.m_resetCallCount, 1); + QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 1); } void tst_QGraphicsView::indirectPainting() diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index a6860006c2..384c5c2861 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -72,6 +72,10 @@ #include "qplatformdefs.h" +#include "../../../shared/platforminputcontext.h" +#include + + QT_BEGIN_NAMESPACE class QPainter; QT_END_NAMESPACE @@ -275,7 +279,6 @@ private slots: void selectAndCursorPosition(); void inputMethod(); void inputMethodSelection(); - void inputMethodTentativeCommit(); protected slots: void editingFinished(); @@ -301,6 +304,7 @@ private: int newCursorPos; QLineEdit *testWidget; int m_keyboardScheme; + PlatformInputContext m_platformInputContext; }; typedef QList IntList; @@ -357,21 +361,23 @@ void tst_QLineEdit::initTestCase() testWidget->resize(200,50); testWidget->show(); + QTest::qWaitForWindowShown(testWidget); QApplication::setActiveWindow(testWidget); -#ifdef Q_WS_X11 - // to be safe and avoid failing setFocus with window managers - qt_x11_wait_for_window_manager(testWidget); -#endif QTRY_VERIFY(testWidget->hasFocus()); changed_count = 0; edited_count = 0; selection_count = 0; + + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = &m_platformInputContext; } void tst_QLineEdit::cleanupTestCase() { delete testWidget; + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; } void tst_QLineEdit::init() @@ -3828,6 +3834,23 @@ void tst_QLineEdit::inputMethod() testWidget->setEnabled(false); QApplication::sendEvent(testWidget, &queryEvent); QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), false); + testWidget->setEnabled(true); + + // removing focus allows input method to commit preedit + testWidget->setText(""); + testWidget->activateWindow(); + QTRY_VERIFY(testWidget->hasFocus()); + QTRY_COMPARE(qApp->focusObject(), testWidget); + + m_platformInputContext.setCommitString("text"); + m_platformInputContext.m_commitCallCount = 0; + QList attributes; + QInputMethodEvent preeditEvent("preedit text", attributes); + QApplication::sendEvent(testWidget, &preeditEvent); + + testWidget->clearFocus(); + QCOMPARE(m_platformInputContext.m_commitCallCount, 1); + QCOMPARE(testWidget->text(), QString("text")); } void tst_QLineEdit::inputMethodSelection() @@ -3866,37 +3889,6 @@ void tst_QLineEdit::inputMethodSelection() QCOMPARE(selectionSpy.count(), 3); } -void tst_QLineEdit::inputMethodTentativeCommit() -{ - // test that basic tentative commit gets to text property on preedit state - QList attributes; - QInputMethodEvent event("test", attributes); - event.setTentativeCommitString("test"); - QApplication::sendEvent(testWidget, &event); - QCOMPARE(testWidget->text(), QString("test")); - - // tentative commit not allowed present in surrounding text - QInputMethodQueryEvent queryEvent(Qt::ImSurroundingText); - QApplication::sendEvent(testWidget, &queryEvent); - QCOMPARE(queryEvent.value(Qt::ImSurroundingText).toString(), QString("")); - - // if text with tentative commit does not validate, not allowed to be part of text property - testWidget->setText(""); // ensure input state is reset - QValidator *validator = new QIntValidator(0, 100); - testWidget->setValidator(validator); - QApplication::sendEvent(testWidget, &event); - QCOMPARE(testWidget->text(), QString("")); - testWidget->setValidator(0); - delete validator; - - // text remains when focus is removed - testWidget->setText(""); // ensure input state is reset - QApplication::sendEvent(testWidget, &event); - QFocusEvent lostFocus(QEvent::FocusOut); - QApplication::sendEvent(testWidget, &lostFocus); - QCOMPARE(testWidget->text(), QString("test")); -} - QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" diff --git a/tests/auto/widgets/widgets/qtextedit/qtextedit.pro b/tests/auto/widgets/widgets/qtextedit/qtextedit.pro index 85658c222e..1c2821b289 100644 --- a/tests/auto/widgets/widgets/qtextedit/qtextedit.pro +++ b/tests/auto/widgets/widgets/qtextedit/qtextedit.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_qtextedit -QT += widgets widgets-private gui-private testlib +QT += widgets widgets-private gui-private core-private testlib INCLUDEPATH += ../ HEADERS += diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp index 249e9d7fbe..9c5a3dbed7 100644 --- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp @@ -62,6 +62,10 @@ #include #include +#include "../../../shared/platforminputcontext.h" +#include + + //Used in copyAvailable typedef QPair keyPairType; typedef QList pairListType; @@ -96,6 +100,8 @@ public: tst_QTextEdit(); public slots: + void initTestCase(); + void cleanupTestCase(); void init(); void cleanup(); private slots: @@ -211,6 +217,7 @@ private: QTextEdit *ed; qreal rootFrameMargin; + PlatformInputContext m_platformInputContext; }; bool tst_QTextEdit::nativeClipboardWorking() @@ -372,6 +379,18 @@ public: tst_QTextEdit::tst_QTextEdit() {} +void tst_QTextEdit::initTestCase() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = &m_platformInputContext; +} + +void tst_QTextEdit::cleanupTestCase() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; +} + void tst_QTextEdit::init() { #ifdef Q_OS_WINCE //disable magic for WindowsCE @@ -2360,6 +2379,8 @@ void tst_QTextEdit::bidiLogicalMovement() void tst_QTextEdit::inputMethodEvent() { + ed->show(); + // test that text change with an input method event triggers change signal QSignalSpy spy(ed, SIGNAL(textChanged())); @@ -2367,14 +2388,23 @@ void tst_QTextEdit::inputMethodEvent() event.setCommitString("text"); QApplication::sendEvent(ed, &event); QCOMPARE(spy.count(), 1); - spy.clear(); + QCOMPARE(ed->toPlainText(), QString("text")); + // test that input method gets chance to commit preedit when removing focus + ed->setText(""); + QApplication::setActiveWindow(ed); + QTRY_VERIFY(QApplication::focusWindow()); + QCOMPARE(qApp->focusObject(), ed); + + m_platformInputContext.setCommitString("text"); + m_platformInputContext.m_commitCallCount = 0; QList attributes; - QInputMethodEvent event2("preedit", attributes); - event2.setTentativeCommitString("string"); - QApplication::sendEvent(ed, &event2); - QCOMPARE(spy.count(), 1); - QCOMPARE(ed->toPlainText(), QString("textstring")); + QInputMethodEvent preeditEvent("preedit text", attributes); + QApplication::sendEvent(ed, &preeditEvent); + + ed->clearFocus(); + QCOMPARE(m_platformInputContext.m_commitCallCount, 1); + QCOMPARE(ed->toPlainText(), QString("text")); } void tst_QTextEdit::inputMethodSelection()