diff options
author | Hannu Koivisto <hannu.koivisto@vincit.fi> | 2010-09-14 15:30:48 +0300 |
---|---|---|
committer | Pekka Vuorela <pekka.ta.vuorela@nokia.com> | 2010-09-15 15:19:20 +0300 |
commit | 813e63a214fb79f3428a562763e2bbcb9e61e8a9 (patch) | |
tree | f4b46352b84acd0e30ea2da688f6f070ec6222e6 | |
parent | 3f6c9a17d619d21bcb1245d836f6d36157a57665 (diff) |
Fixes: shift+arrow key selection with MTextEdit
RevBy: Pekka Vuorela
Details: selecting just a single character with shift+arrow key didn't work
because MInputContext::update() was called due to smartMoveCursor() ->
moveCursor() -> updateMicroFocus() and at that time edit mode wasn't yet
EditModeSelect and therefore query for selected text returned nothing.
updateMicroFocus() wasn't called again after setting the mode either and just
adding that would have resulted to unnecessary update() calls, so a mechanism
to suppress actual updateMicroFocus() calls was introduced and that was used
to ensure just one updateMicroFocus() call after moving the cursor and
setting the mode.
-rwxr-xr-x | src/corelib/widgets/mtextedit.cpp | 61 | ||||
-rwxr-xr-x | src/corelib/widgets/mtextedit_p.h | 16 | ||||
-rw-r--r-- | tests/ut_mtextedit/ut_mtextedit.cpp | 41 |
3 files changed, 104 insertions, 14 deletions
diff --git a/src/corelib/widgets/mtextedit.cpp b/src/corelib/widgets/mtextedit.cpp index 1d8e688d..6cfc24bc 100755 --- a/src/corelib/widgets/mtextedit.cpp +++ b/src/corelib/widgets/mtextedit.cpp @@ -302,7 +302,9 @@ MTextEditPrivate::MTextEditPrivate() completer(0), registeredToolbarId(-1), editActive(false), - omitInputMethodEvents(false) + omitInputMethodEvents(false), + updateMicroFocusDisabled(0), + pendingMicroFocusUpdate(false) { } @@ -374,7 +376,7 @@ bool MTextEditPrivate::moveCursor(QTextCursor::MoveOperation moveOp, result = cursor()->movePosition(moveOp, moveMode, n); if (result) { q->model()->updateCursor(); - q->updateMicroFocus(); + updateMicroFocus(); emit q->cursorPositionChanged(); } @@ -788,7 +790,7 @@ void MTextEditPrivate::commitPreedit() } setMode(MTextEditModel::EditModeBasic); - q->updateMicroFocus(); + updateMicroFocus(); if (q->hasFocus()) { // make sure the committed preedit doesn't get left on the input context @@ -1212,7 +1214,7 @@ void MTextEditPrivate::_q_confirmCompletion(const QString &completion) QObject::disconnect(q, SIGNAL(textChanged()), completer, SLOT(complete())); emit q->textChanged(); QObject::connect(q, SIGNAL(textChanged()), completer, SLOT(complete())); - q->updateMicroFocus(); + updateMicroFocus(); } bool MTextEditPrivate::copy() @@ -1240,6 +1242,34 @@ QString MTextEditPrivate::replaceLineBreaks(QString text, QChar replacement) return text; } +void MTextEditPrivate::disableUpdateMicroFocus() +{ + ++updateMicroFocusDisabled; +} + +void MTextEditPrivate::enableUpdateMicroFocus(bool flush) +{ + Q_Q(MTextEdit); + Q_ASSERT(updateMicroFocusDisabled); + if ((--updateMicroFocusDisabled == 0) && pendingMicroFocusUpdate && flush) { + q->updateMicroFocus(); + } + pendingMicroFocusUpdate = false; +} + +void MTextEditPrivate::updateMicroFocus() +{ + Q_Q(MTextEdit); + + if (updateMicroFocusDisabled <= 0) { + q->updateMicroFocus(); + pendingMicroFocusUpdate = false; + } else { + pendingMicroFocusUpdate = true; + } +} + + /////////////////////////////////////////////// // Actual class implementation @@ -1357,7 +1387,7 @@ void MTextEdit::setSelection(int start, int length, bool useBoundaries) model()->updateCursor(); - updateMicroFocus(); + d->updateMicroFocus(); emit selectionChanged(); @@ -1439,6 +1469,7 @@ void MTextEdit::keyPressEvent(QKeyEvent *event) d->smartMoveCursor(moveDirection, QTextCursor::MoveAnchor, 1); } else if (event->modifiers() == Qt::ShiftModifier && (textInteractionFlags() & Qt::TextSelectableByKeyboard)) { + d->disableUpdateMicroFocus(); const bool moved = d->smartMoveCursor(moveDirection, QTextCursor::KeepAnchor, 1); if (!wasSelecting && d->cursor()->hasSelection()) { // first character was selected d->setMode(MTextEditModel::EditModeSelect); @@ -1449,7 +1480,9 @@ void MTextEdit::keyPressEvent(QKeyEvent *event) } if (moved) { emit selectionChanged(); + d->updateMicroFocus(); } + d->enableUpdateMicroFocus(true); } event->accept(); return; @@ -1577,7 +1610,7 @@ void MTextEdit::keyPressEvent(QKeyEvent *event) } model()->updateCursor(); - updateMicroFocus(); + d->updateMicroFocus(); emit textChanged(); emit cursorPositionChanged(); @@ -1700,7 +1733,7 @@ bool MTextEdit::insert(const QString &text) // either something was inserted or something was deleted, or both if (insertionSuccess || wasSelecting) { emit textChanged(); - updateMicroFocus(); + d->updateMicroFocus(); } return insertionSuccess; @@ -1751,7 +1784,7 @@ bool MTextEdit::setText(const QString &text) // only avoid signaling if empty before and after if (!((document()->characterCount() == 0) && wasEmpty)) { - updateMicroFocus(); + d->updateMicroFocus(); emit textChanged(); } @@ -1899,7 +1932,7 @@ void MTextEdit::handleMouseRelease(int eventCursorPosition, QGraphicsSceneMouseE } if (cursorPosition() != cursorPositionBefore) { - updateMicroFocus(); + d->updateMicroFocus(); } } @@ -1988,7 +2021,7 @@ void MTextEdit::paste() if (changed) { emit textChanged(); emit cursorPositionChanged(); - updateMicroFocus(); + d->updateMicroFocus(); } else { mDebug("MTextEdit") << __PRETTY_FUNCTION__ << "paste failed"; emit pasteFailed(); @@ -2021,7 +2054,7 @@ void MTextEdit::cut() emit selectionChanged(); emit textChanged(); emit cursorPositionChanged(); - updateMicroFocus(); + d->updateMicroFocus(); } } @@ -2121,7 +2154,7 @@ void MTextEdit::inputMethodEvent(QInputMethodEvent *event) } if (changed) { - updateMicroFocus(); + d->updateMicroFocus(); emit textChanged(); emit cursorPositionChanged(); } @@ -2406,7 +2439,7 @@ void MTextEdit::deselect() d->setMode(MTextEditModel::EditModeBasic); model()->updateCursor(); d->sendCopyAvailable(false); - updateMicroFocus(); + d->updateMicroFocus(); emit selectionChanged(); } } @@ -2581,7 +2614,7 @@ void MTextEdit::setCompleter(MCompleter *completer) setInputMethodAutoCapitalizationEnabled(false); if (hasFocus()) { - updateMicroFocus(); + d->updateMicroFocus(); connect(d->completer, SIGNAL(confirmed(QString, QModelIndex)), this, SLOT(_q_confirmCompletion(QString))); } diff --git a/src/corelib/widgets/mtextedit_p.h b/src/corelib/widgets/mtextedit_p.h index 00ad99b8..9fb65f90 100755 --- a/src/corelib/widgets/mtextedit_p.h +++ b/src/corelib/widgets/mtextedit_p.h @@ -105,6 +105,19 @@ public: QString replaceLineBreaks(QString text, QChar replacement); void _q_confirmCompletion(const QString &); + //! \brief Disable MTextEdit::updateMicroFocus(). + //! + //! Can be called multiple times without calling \a enableUpdateMicroFocus in between. In such a case + //! \a enableUpdateMicroFocus must be called equally many times. + void disableUpdateMicroFocus(); + //! \param flush call updateMicroFocus() automatically if true and updateMicroFocus was called + //! while being disabled + void enableUpdateMicroFocus(bool flush = false); + //! \brief updateMicroFocus() wrapper that can be disabled + //! \sa disableUpdateMicroFocus + //! \sa enableUpdateMicroFocus + void updateMicroFocus(); + bool pendingSoftwareInputPanelRequest; private: @@ -118,6 +131,9 @@ private: // protection from input methods that send something on QInputContext::reset() bool omitInputMethodEvents; + + int updateMicroFocusDisabled; + bool pendingMicroFocusUpdate; }; #endif diff --git a/tests/ut_mtextedit/ut_mtextedit.cpp b/tests/ut_mtextedit/ut_mtextedit.cpp index 2983526b..8521500f 100644 --- a/tests/ut_mtextedit/ut_mtextedit.cpp +++ b/tests/ut_mtextedit/ut_mtextedit.cpp @@ -97,6 +97,9 @@ class SimpleInputContext: public QInputContext public: SimpleInputContext(QObject *parent = 0) : QInputContext(parent), + updateCallCount(0), + selectionAvailableAtLastUpdate(false), + edit(0), m_visible(false) {} @@ -143,6 +146,20 @@ public: return false; } + void update() + { + ++updateCallCount; + if (edit) { + selectedTextAtLastUpdate = edit->selectedText(); + } + selectionAvailableAtLastUpdate = !selectedTextAtLastUpdate.isEmpty(); + } + + int updateCallCount; + bool selectionAvailableAtLastUpdate; + QString selectedTextAtLastUpdate; + MTextEdit *edit; + private: bool m_visible; }; @@ -258,6 +275,7 @@ void Ut_MTextEdit::init() { m_subject.reset(new MTextEdit(MTextEditModel::MultiLine, "")); qApp->setInputContext(m_sic = new SimpleInputContext); + m_sic->edit = m_subject.get(); } @@ -1946,6 +1964,7 @@ void Ut_MTextEdit::testArrowKeys() void Ut_MTextEdit::testSelectByArrowKeys() { + setupSipEnv(m_subject.get()); QSignalSpy copyAvailableSpy(m_subject.get(), SIGNAL(copyAvailable(bool))); QVERIFY(copyAvailableSpy.isValid()); @@ -1982,9 +2001,12 @@ void Ut_MTextEdit::testSelectByArrowKeys() QCOMPARE(copyAvailableSpy.count(), 0); QCOMPARE(selectionChangedSpy.count(), 0); + QCOMPARE(m_sic->updateCallCount, 0); + m_subject->setText(line); m_subject->setCursorPosition(1); + m_sic->updateCallCount = 0; m_subject->keyPressEvent(&right); QCOMPARE(m_subject->cursorPosition(), 2); QCOMPARE(m_subject->selectedText(), QString("2")); @@ -1994,6 +2016,9 @@ void Ut_MTextEdit::testSelectByArrowKeys() QCOMPARE(selectionChangedSpy.count(), 1); copyAvailableSpy.clear(); selectionChangedSpy.clear(); + QCOMPARE(m_sic->updateCallCount, 1); + m_sic->updateCallCount = 0; + QVERIFY(m_sic->selectionAvailableAtLastUpdate); m_subject->keyPressEvent(&left); QCOMPARE(m_subject->cursorPosition(), 1); @@ -2004,6 +2029,9 @@ void Ut_MTextEdit::testSelectByArrowKeys() QCOMPARE(selectionChangedSpy.count(), 1); copyAvailableSpy.clear(); selectionChangedSpy.clear(); + QCOMPARE(m_sic->updateCallCount, 1); + m_sic->updateCallCount = 0; + QVERIFY(!m_sic->selectionAvailableAtLastUpdate); m_subject->keyPressEvent(&left); QCOMPARE(m_subject->cursorPosition(), 0); @@ -2014,11 +2042,14 @@ void Ut_MTextEdit::testSelectByArrowKeys() QCOMPARE(selectionChangedSpy.count(), 1); copyAvailableSpy.clear(); selectionChangedSpy.clear(); + QCOMPARE(m_sic->updateCallCount, 1); + QVERIFY(m_sic->selectionAvailableAtLastUpdate); m_subject->setCursorPosition(0); copyAvailableSpy.clear(); selectionChangedSpy.clear(); + m_sic->updateCallCount = 0; m_subject->keyPressEvent(&down); QVERIFY(m_subject->cursorPosition() > 0); QVERIFY(!m_subject->selectedText().isEmpty()); @@ -2028,6 +2059,9 @@ void Ut_MTextEdit::testSelectByArrowKeys() QCOMPARE(selectionChangedSpy.count(), 1); copyAvailableSpy.clear(); selectionChangedSpy.clear(); + QCOMPARE(m_sic->updateCallCount, 1); + m_sic->updateCallCount = 0; + QVERIFY(m_sic->selectionAvailableAtLastUpdate); m_subject->keyPressEvent(&up); QVERIFY(m_subject->cursorPosition() == 0); @@ -2038,15 +2072,21 @@ void Ut_MTextEdit::testSelectByArrowKeys() QCOMPARE(selectionChangedSpy.count(), 1); copyAvailableSpy.clear(); selectionChangedSpy.clear(); + QCOMPARE(m_sic->updateCallCount, 1); + QVERIFY(!m_sic->selectionAvailableAtLastUpdate); //disable flag Qt::TextSelectableByKeyboard m_subject->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextEditable); + m_sic->updateCallCount = 0; m_subject->keyPressEvent(&right); QCOMPARE(m_subject->cursorPosition(), 0); QVERIFY(!m_subject->hasSelectedText()); QCOMPARE(copyAvailableSpy.count(), 0); QCOMPARE(selectionChangedSpy.count(), 0); + QCOMPARE(m_sic->updateCallCount, 0); + m_sic->updateCallCount = 0; + QVERIFY(!m_sic->selectionAvailableAtLastUpdate); } void Ut_MTextEdit::testAutoSipEnabled() @@ -2419,6 +2459,7 @@ void Ut_MTextEdit::testArrowKeyNavigation() void Ut_MTextEdit::setupSipEnv(MTextEdit *edit) { edit->setFlag(QGraphicsItem::ItemAcceptsInputMethod); + m_sic->edit = edit; } void Ut_MTextEdit::requestSip(MTextEdit *edit, Qt::FocusReason fr) |