From b5f206ecd51c64d9167e019c734b8a54d3ee8c93 Mon Sep 17 00:00:00 2001 From: Pekka Vuorela Date: Wed, 16 Nov 2011 13:43:05 +0200 Subject: [PATCH] Made TextInput mouse events commit preedit Similar to what was earlier done on QWidgets editors. Additionally updated tests to check QInputPanel::invokeAction instead of the obsolete QInputContext mouse handler. Change-Id: Ia2bd22eebdeed79cff7a4925129b28dd1500b1ad Reviewed-by: Joona Petrell --- src/declarative/items/qquicktextinput.cpp | 42 ++++-- .../graphicsitems/qdeclarativetextinput.cpp | 55 +++---- .../qquicktextinput/tst_qquicktextinput.cpp | 64 ++++++++- .../tst_qdeclarativetextinput.cpp | 154 ++++++++------------ 4 files changed, 174 insertions(+), 141 deletions(-) diff --git a/src/declarative/items/qquicktextinput.cpp b/src/declarative/items/qquicktextinput.cpp index c46eba1..f3cdc88 100644 --- a/src/declarative/items/qquicktextinput.cpp +++ b/src/declarative/items/qquicktextinput.cpp @@ -1084,9 +1084,9 @@ void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev) void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event) { Q_D(QQuickTextInput); - if (d->sendMouseEventToInputContext(event)) - return; - if (d->selectByMouse) { + + if (d->selectByMouse && event->button() == Qt::LeftButton) { + d->control->commitPreedit(); int cursor = d->xToPos(event->localPos().x()); d->control->selectWordAtPos(cursor); event->setAccepted(true); @@ -1095,6 +1095,8 @@ void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event) d->tripleClickTimer.start(); } } else { + if (d->sendMouseEventToInputContext(event)) + return; QQuickImplicitSizeItem::mouseDoubleClickEvent(event); } } @@ -1102,8 +1104,9 @@ void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event) void QQuickTextInput::mousePressEvent(QMouseEvent *event) { Q_D(QQuickTextInput); - if (d->sendMouseEventToInputContext(event)) - return; + + d->pressPos = event->localPos(); + if (d->focusOnPress) { bool hadActiveFocus = hasActiveFocus(); forceActiveFocus(); @@ -1114,7 +1117,6 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event) if (d->selectByMouse) { setKeepMouseGrab(false); d->selectPressed = true; - d->pressPos = event->localPos(); QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint; if (d->hasPendingTripleClick() && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) { @@ -1123,6 +1125,10 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event) return; } } + + if (d->sendMouseEventToInputContext(event)) + return; + bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse; int cursor = d->xToPos(event->localPos().x()); d->control->moveCursor(cursor, mark); @@ -1132,12 +1138,20 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event) void QQuickTextInput::mouseMoveEvent(QMouseEvent *event) { Q_D(QQuickTextInput); - if (d->sendMouseEventToInputContext(event)) - return; + if (d->selectPressed) { if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance()) setKeepMouseGrab(true); - moveCursorSelection(d->xToPos(event->localPos().x()), d->mouseSelectionMode); + + if (d->control->composeMode()) { + // start selection + int startPos = d->xToPos(d->pressPos.x()); + int currentPos = d->xToPos(event->localPos().x()); + if (startPos != currentPos) + d->control->setSelection(startPos, currentPos - startPos); + } else { + moveCursorSelection(d->xToPos(event->localPos().x()), d->mouseSelectionMode); + } event->setAccepted(true); } else { QQuickImplicitSizeItem::mouseMoveEvent(event); @@ -1161,13 +1175,15 @@ void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event) bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event) { #if !defined QT_NO_IM - if (control->composeMode() && event->type() == QEvent::MouseButtonRelease) { + if (control->composeMode()) { int tmp_cursor = xToPos(event->localPos().x()); int mousePos = tmp_cursor - control->cursor(); - // may be causing reset() in some input methods - qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos); - if (!control->preeditAreaText().isEmpty()) + if (mousePos >= 0 && mousePos <= control->preeditAreaText().length()) { + if (event->type() == QEvent::MouseButtonRelease) { + qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos); + } return true; + } } #else Q_UNUSED(event); diff --git a/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp b/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp index 04aa06d..d2760d1 100644 --- a/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativetextinput.cpp @@ -1124,13 +1124,13 @@ Handles the given mouse \a event. void QDeclarative1TextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarative1TextInput); - if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick)) - return; - if (d->selectByMouse) { + if (d->selectByMouse && event->button() == Qt::LeftButton) { int cursor = d->xToPos(event->pos().x()); d->control->selectWordAtPos(cursor); event->setAccepted(true); } else { + if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick)) + return; QDeclarative1PaintedItem::mouseDoubleClickEvent(event); } } @@ -1138,8 +1138,9 @@ void QDeclarative1TextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *eve void QDeclarative1TextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarative1TextInput); - if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress)) - return; + + d->pressPos = event->pos(); + if(d->focusOnPress){ bool hadActiveFocus = hasActiveFocus(); forceActiveFocus(); @@ -1157,8 +1158,10 @@ void QDeclarative1TextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) if (d->selectByMouse) { setKeepMouseGrab(false); d->selectPressed = true; - d->pressPos = event->pos(); } + if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress)) + return; + bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse; int cursor = d->xToPos(event->pos().x()); d->control->moveCursor(cursor, mark); @@ -1168,12 +1171,20 @@ void QDeclarative1TextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) void QDeclarative1TextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarative1TextInput); - if (d->sendMouseEventToInputContext(event, QEvent::MouseMove)) - return; + if (d->selectPressed) { if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance()) setKeepMouseGrab(true); - moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode); + + if (d->control->composeMode()) { + // start selection + int startPos = d->xToPos(d->pressPos.x()); + int currentPos = d->xToPos(event->pos().x()); + if (startPos != currentPos) + d->control->setSelection(startPos, currentPos - startPos); + } else { + moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode); + } event->setAccepted(true); } else { QDeclarative1PaintedItem::mouseMoveEvent(event); @@ -1215,28 +1226,12 @@ bool QDeclarative1TextInputPrivate::sendMouseEventToInputContext( if (event->widget() && control->composeMode()) { int tmp_cursor = xToPos(event->pos().x()); int mousePos = tmp_cursor - control->cursor(); - if (mousePos < 0 || mousePos > control->preeditAreaText().length()) { - mousePos = -1; - // don't send move events outside the preedit area - if (eventType == QEvent::MouseMove) - return true; - } - - QInputContext *qic = event->widget()->inputContext(); - if (qic) { - QMouseEvent mouseEvent( - eventType, - event->widget()->mapFromGlobal(event->screenPos()), - event->screenPos(), - event->button(), - event->buttons(), - event->modifiers()); - // may be causing reset() in some input methods - qic->mouseHandler(mousePos, &mouseEvent); - event->setAccepted(mouseEvent.isAccepted()); - } - if (!control->preeditAreaText().isEmpty()) + if (mousePos >= 0 && mousePos <= control->preeditAreaText().length()) { + if (eventType == QEvent::MouseButtonRelease) { + qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos); + } return true; + } } #else Q_UNUSED(event); diff --git a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp index ca978c3..b217f90 100644 --- a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp @@ -41,6 +41,7 @@ #include #include #include "../shared/util.h" +#include #include #include #include @@ -94,6 +95,7 @@ public: private slots: void initTestCase(); void cleanupTestCase(); + void cleanup(); void text(); void width(); void font(); @@ -147,6 +149,7 @@ private slots: void preeditAutoScroll(); void preeditCursorRectangle(); + void inputContextMouseHandler(); void inputMethodComposing(); void cursorRectangleSize(); @@ -208,7 +211,7 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequ QList &operator <<(QList &keys, const QKeySequence &sequence) { - for (int i = 0; i < sequence.count(); ++i) + for (uint i = 0; i < sequence.count(); ++i) keys << Key(sequence[i], QChar()); return keys; } @@ -235,8 +238,15 @@ void tst_qquicktextinput::initTestCase() void tst_qquicktextinput::cleanupTestCase() { +} +void tst_qquicktextinput::cleanup() +{ + // ensure not even skipped tests with custom input context leave it dangling + QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel()); + inputPanelPrivate->testContext = 0; } + tst_qquicktextinput::tst_qquicktextinput() { standard << "the quick brown fox jumped over the lazy dog" @@ -2185,7 +2195,11 @@ void tst_qquicktextinput::simulateKey(QQuickView *view, int key) class PlatformInputContext : public QPlatformInputContext { public: - PlatformInputContext() : m_visible(false) {} + PlatformInputContext() + : m_visible(false), m_action(QInputPanel::Click), m_cursorPosition(0), + m_invokeActionCallCount(0) + { + } virtual void showInputPanel() { @@ -2199,8 +2213,17 @@ public: { return m_visible; } + virtual void invokeAction(QInputPanel::Action action, int cursorPosition) + { + m_invokeActionCallCount++; + m_action = action; + m_cursorPosition = cursorPosition; + } bool m_visible; + QInputPanel::Action m_action; + int m_cursorPosition; + int m_invokeActionCallCount; }; void tst_qquicktextinput::openInputPanel() @@ -2292,8 +2315,6 @@ void tst_qquicktextinput::openInputPanel() // input panel should close when closeSoftwareInputPanel is called input->closeSoftwareInputPanel(); QCOMPARE(qApp->inputPanel()->visible(), false); - - inputPanelPrivate->testContext = 0; } class MyTextInput : public QQuickTextInput @@ -2545,6 +2566,41 @@ void tst_qquicktextinput::preeditCursorRectangle() QVERIFY(panelSpy.count() > 0); } +void tst_qquicktextinput::inputContextMouseHandler() +{ + PlatformInputContext platformInputContext; + QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel()); + inputPanelPrivate->testContext = &platformInputContext; + + QString text = "supercalifragisiticexpialidocious!"; + QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml"))); + QQuickTextInput *input = qobject_cast(view.rootObject()); + QVERIFY(input); + + input->setFocus(true); + input->setText(""); + + view.show(); + view.requestActivateWindow(); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(&view, qGuiApp->focusWindow()); + + QFontMetricsF fm(input->font()); + const qreal y = fm.height() / 2; + QPoint position = QPointF(fm.width(text.mid(0, 2)), y).toPoint(); + + QInputMethodEvent inputEvent(text.mid(0, 5), QList()); + QApplication::sendEvent(input, &inputEvent); + + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); + QGuiApplication::processEvents(); + + QCOMPARE(platformInputContext.m_action, QInputPanel::Click); + QCOMPARE(platformInputContext.m_invokeActionCallCount, 1); + QCOMPARE(platformInputContext.m_cursorPosition, 2); +} + void tst_qquicktextinput::inputMethodComposing() { QString text = "supercalifragisiticexpialidocious!"; diff --git a/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index c84de12..ec6b3dd 100644 --- a/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/qtquick1/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -49,7 +49,8 @@ #include #include #include -#include +#include +#include #include "qplatformdefs.h" @@ -71,6 +72,41 @@ QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& return expectfile; } +class PlatformInputContext : public QPlatformInputContext +{ +public: + PlatformInputContext() + : m_visible(false), m_action(QInputPanel::Click), m_cursorPosition(0), + m_invokeActionCallCount(0) + { + } + + virtual void showInputPanel() + { + m_visible = true; + } + virtual void hideInputPanel() + { + m_visible = false; + } + virtual bool isInputPanelVisible() const + { + return m_visible; + } + virtual void invokeAction(QInputPanel::Action action, int cursorPosition) + { + m_invokeActionCallCount++; + m_action = action; + m_cursorPosition = cursorPosition; + } + + bool m_visible; + QInputPanel::Action m_action; + int m_cursorPosition; + int m_invokeActionCallCount; +}; + + class tst_qdeclarativetextinput : public QObject { @@ -79,6 +115,7 @@ public: tst_qdeclarativetextinput(); private slots: + void cleanup(); void text(); void width(); @@ -151,6 +188,7 @@ private: QStringList colorStrings; }; + tst_qdeclarativetextinput::tst_qdeclarativetextinput() { standard << "the quick brown fox jumped over the lazy dog" @@ -173,6 +211,13 @@ tst_qdeclarativetextinput::tst_qdeclarativetextinput() << "#2AC05F"; } +void tst_qdeclarativetextinput::cleanup() +{ + // ensure not even skipped tests with custom input context leave it dangling + QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel()); + inputPanelPrivate->testContext = 0; +} + void tst_qdeclarativetextinput::text() { { @@ -2669,15 +2714,17 @@ void tst_qdeclarativetextinput::preeditMicroFocus() void tst_qdeclarativetextinput::inputContextMouseHandler() { + PlatformInputContext platformInputContext; + QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel()); + inputPanelPrivate->testContext = &platformInputContext; + QString text = "supercalifragisiticexpialidocious!"; QGraphicsScene scene; QGraphicsView view(&scene); - MyInputContext *ic = new MyInputContext; - qApp->setInputContext(ic); + QDeclarative1TextInput input; input.setWidth(200); - input.setText(text.mid(0, 12)); input.setCursorPosition(12); input.setPos(0, 0); input.setFocus(true); @@ -2691,98 +2738,17 @@ void tst_qdeclarativetextinput::inputContextMouseHandler() const qreal y = fm.height() / 2; QPoint position2 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 2)), y))); - QPoint position8 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 8)), y))); - QPoint position20 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 20)), y))); - QPoint position27 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 27)), y))); - QPoint globalPosition2 = view.viewport()->mapToGlobal(position2); - QPoint globalposition8 = view.viewport()->mapToGlobal(position8); - QPoint globalposition20 = view.viewport()->mapToGlobal(position20); - QPoint globalposition27 = view.viewport()->mapToGlobal(position27); - ic->sendEvent(QInputMethodEvent(text.mid(12), QList())); - - QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic->eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic->eventPosition, position2); - QCOMPARE(ic->eventGlobalPosition, globalPosition2); - QCOMPARE(ic->eventButton, Qt::LeftButton); - QCOMPARE(ic->eventModifiers, Qt::NoModifier); - QVERIFY(ic->cursor < 0); - ic->eventType = QEvent::None; + QInputMethodEvent inputEvent(text.mid(0, 5), QList()); + QApplication::sendEvent(&view, &inputEvent); QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic->eventType, QEvent::MouseButtonPress); - QCOMPARE(ic->eventPosition, position2); - QCOMPARE(ic->eventGlobalPosition, globalPosition2); - QCOMPARE(ic->eventButton, Qt::LeftButton); - QCOMPARE(ic->eventModifiers, Qt::NoModifier); - QVERIFY(ic->cursor < 0); - ic->eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QApplication::sendEvent(view.viewport(), &mv); } - QCOMPARE(ic->eventType, QEvent::None); - - { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QApplication::sendEvent(view.viewport(), &mv); } - QCOMPARE(ic->eventType, QEvent::MouseMove); - QCOMPARE(ic->eventPosition, position27); - QCOMPARE(ic->eventGlobalPosition, globalposition27); - QCOMPARE(ic->eventButton, Qt::LeftButton); - QCOMPARE(ic->eventModifiers, Qt::NoModifier); - QVERIFY(ic->cursor >= 14 && ic->cursor <= 16); // 15 is expected but some platforms may be off by one. - ic->eventType = QEvent::None; - - QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, position27); - QCOMPARE(ic->eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic->eventPosition, position27); - QCOMPARE(ic->eventGlobalPosition, globalposition27); - QCOMPARE(ic->eventButton, Qt::LeftButton); - QCOMPARE(ic->eventModifiers, Qt::NoModifier); - QVERIFY(ic->cursor >= 14 && ic->cursor <= 16); - ic->eventType = QEvent::None; - - // And in the other direction. - QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, position27); - QCOMPARE(ic->eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic->eventPosition, position27); - QCOMPARE(ic->eventGlobalPosition, globalposition27); - QCOMPARE(ic->eventButton, Qt::LeftButton); - QCOMPARE(ic->eventModifiers, Qt::ControlModifier); - QVERIFY(ic->cursor >= 14 && ic->cursor <= 16); - ic->eventType = QEvent::None; - - QTest::mousePress(view.viewport(), Qt::RightButton, Qt::ControlModifier, position27); - QCOMPARE(ic->eventType, QEvent::MouseButtonPress); - QCOMPARE(ic->eventPosition, position27); - QCOMPARE(ic->eventGlobalPosition, globalposition27); - QCOMPARE(ic->eventButton, Qt::RightButton); - QCOMPARE(ic->eventModifiers, Qt::ControlModifier); - QVERIFY(ic->cursor >= 14 && ic->cursor <= 16); - ic->eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QApplication::sendEvent(view.viewport(), &mv); } - QCOMPARE(ic->eventType, QEvent::MouseMove); - QCOMPARE(ic->eventPosition, position20); - QCOMPARE(ic->eventGlobalPosition, globalposition20); - QCOMPARE(ic->eventButton, Qt::RightButton); - QCOMPARE(ic->eventModifiers, Qt::ControlModifier); - QVERIFY(ic->cursor >= 7 && ic->cursor <= 9); - ic->eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QApplication::sendEvent(view.viewport(), &mv); } - QCOMPARE(ic->eventType, QEvent::None); - - QTest::mouseRelease(view.viewport(), Qt::RightButton, Qt::ControlModifier, position2); - QCOMPARE(ic->eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic->eventPosition, position2); - QCOMPARE(ic->eventGlobalPosition, globalPosition2); - QCOMPARE(ic->eventButton, Qt::RightButton); - QCOMPARE(ic->eventModifiers, Qt::ControlModifier); - QVERIFY(ic->cursor < 0); - ic->eventType = QEvent::None; + QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); + QApplication::processEvents(); + + QCOMPARE(platformInputContext.m_action, QInputPanel::Click); + QCOMPARE(platformInputContext.m_invokeActionCallCount, 1); + QCOMPARE(platformInputContext.m_cursorPosition, 2); } void tst_qdeclarativetextinput::inputMethodComposing() -- 1.7.2.5