From 7851568c65e0560056c6fa541039543d43a63e20 Mon Sep 17 00:00:00 2001 From: Pekka Vuorela Date: Tue, 4 Oct 2011 17:44:35 +0300 Subject: QLineEdit - made mouse interactions commit preedit Simplifying input context mouse handling rules by making the editor in charge when text gets committed and selected. This includes: - Allowing selection to start on top of preedit. Commits once a single character gets selected - Double click to commit preedit before selecting a word. - Only sending events to input context that happen on top of preedit. - Committing preedit when a mouse press happens outside of it, allowing to move cursor to click position. Change-Id: I9dab00ea3445055ffd0d7cae540a1197c5748509 Reviewed-by: Lars Knoll --- src/widgets/widgets/qlineedit.cpp | 57 +++++++++++++++++++++++++----- src/widgets/widgets/qlineedit_p.cpp | 10 ++---- src/widgets/widgets/qlineedit_p.h | 2 +- src/widgets/widgets/qwidgetlinecontrol.cpp | 29 +++++++++++++++ src/widgets/widgets/qwidgetlinecontrol_p.h | 1 + 5 files changed, 83 insertions(+), 16 deletions(-) (limited to 'src/widgets') diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index a4a54caa53..43030289ff 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1388,6 +1388,9 @@ bool QLineEdit::event(QEvent * e) void QLineEdit::mousePressEvent(QMouseEvent* e) { Q_D(QLineEdit); + + d->mousePressPos = e->pos(); + if (d->sendMouseEventToInputContext(e)) return; if (e->button() == Qt::RightButton) @@ -1410,7 +1413,6 @@ void QLineEdit::mousePressEvent(QMouseEvent* e) #ifndef QT_NO_DRAGANDDROP if (!mark && d->dragEnabled && d->control->echoMode() == Normal && e->button() == Qt::LeftButton && d->control->inSelection(e->pos().x())) { - d->dndPos = e->pos(); if (!d->dndTimer.isActive()) d->dndTimer.start(QApplication::startDragTime(), this); } else @@ -1425,20 +1427,28 @@ void QLineEdit::mousePressEvent(QMouseEvent* e) void QLineEdit::mouseMoveEvent(QMouseEvent * e) { Q_D(QLineEdit); - if (d->sendMouseEventToInputContext(e)) - return; if (e->buttons() & Qt::LeftButton) { #ifndef QT_NO_DRAGANDDROP if (d->dndTimer.isActive()) { - if ((d->dndPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) + if ((d->mousePressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) d->drag(); } else #endif { - d->control->moveCursor(d->xToPos(e->pos().x()), true); + if (d->control->composeMode()) { + int startPos = d->xToPos(d->mousePressPos.x()); + int currentPos = d->xToPos(e->pos().x()); + if (startPos != currentPos) + d->control->setSelection(startPos, currentPos - startPos); + + } else { + d->control->moveCursor(d->xToPos(e->pos().x()), true); + } } } + + d->sendMouseEventToInputContext(e); } /*! \reimp @@ -1478,12 +1488,43 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) { Q_D(QLineEdit); - if (d->sendMouseEventToInputContext(e)) - return; + if (e->button() == Qt::LeftButton) { - d->control->selectWordAtPos(d->xToPos(e->pos().x())); + int position = d->xToPos(e->pos().x()); + + // exit composition mode + if (d->control->composeMode()) { + int preeditPos = d->control->cursor(); + int posInPreedit = position - d->control->cursor(); + int preeditLength = d->control->preeditAreaText().length(); + bool positionOnPreedit = false; + + if (posInPreedit >= 0 && posInPreedit <= preeditLength) + positionOnPreedit = true; + + int textLength = d->control->end(); + d->control->commitPreedit(); + int sizeChange = d->control->end() - textLength; + + if (positionOnPreedit) { + if (sizeChange == 0) + position = -1; // cancel selection, word disappeared + else + // ensure not selecting after preedit if event happened there + position = qBound(preeditPos, position, preeditPos + sizeChange); + } else if (position > preeditPos) { + // adjust positions after former preedit by how much text changed + position += (sizeChange - preeditLength); + } + } + + if (position >= 0) + d->control->selectWordAtPos(position); + d->tripleClickTimer.start(QApplication::doubleClickInterval(), this); d->tripleClick = e->pos(); + } else { + d->sendMouseEventToInputContext(e); } } diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index 247d0afb0b..b17651e1d3 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -259,19 +259,15 @@ bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e ) if ( control->composeMode() ) { int tmp_cursor = xToPos(e->pos().x()); int mousePos = tmp_cursor - control->cursor(); - if ( mousePos < 0 || mousePos > control->preeditAreaText().length() ) { + if ( mousePos < 0 || mousePos > control->preeditAreaText().length() ) mousePos = -1; - // don't send move events outside the preedit area - if ( e->type() == QEvent::MouseMove ) - return true; - } QInputContext *qic = q->inputContext(); - if ( qic ) + if (qic && mousePos >= 0) { // may be causing reset() in some input methods qic->mouseHandler(mousePos, e); - if (!control->preeditAreaText().isEmpty()) return true; + } } #else Q_UNUSED(e); diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h index d916ae3185..076f2fcf11 100644 --- a/src/widgets/widgets/qlineedit_p.h +++ b/src/widgets/widgets/qlineedit_p.h @@ -137,8 +137,8 @@ public: #ifndef QT_NO_COMPLETER void _q_completionHighlighted(QString); #endif + QPoint mousePressPos; #ifndef QT_NO_DRAGANDDROP - QPoint dndPos; QBasicTimer dndTimer; void drag(); #endif diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 498b972045..027512b6ae 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -164,6 +164,31 @@ void QWidgetLineControl::paste(QClipboard::Mode clipboardMode) #endif // !QT_NO_CLIPBOARD +/*! + \internal + + Exits preedit mode and commits parts marked as tentative commit +*/ +void QWidgetLineControl::commitPreedit() +{ + if (!composeMode()) + return; + + qApp->inputPanel()->reset(); + + if (!m_tentativeCommit.isEmpty()) { + internalInsert(m_tentativeCommit); + m_tentativeCommit.clear(); + finishChange(-1, true/*not used, not documented*/, false); + } + + m_preeditCursor = 0; + setPreeditArea(-1, QString()); + m_textLayout.clearAdditionalFormats(); + updateDisplayText(/*force*/ true); +} + + /*! \internal @@ -259,6 +284,8 @@ void QWidgetLineControl::clear() */ void QWidgetLineControl::setSelection(int start, int length) { + commitPreedit(); + if(start < 0 || start > (int)m_text.length()){ qWarning("QWidgetLineControl::setSelection: Invalid start position"); return; @@ -394,6 +421,8 @@ bool QWidgetLineControl::fixup() // this function assumes that validate currentl */ void QWidgetLineControl::moveCursor(int pos, bool mark) { + commitPreedit(); + if (pos != m_cursor) { separate(); if (m_maskData) diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index 3bcdffbf08..e0c304279e 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -234,6 +234,7 @@ public: m_tentativeCommit.clear(); internalSetText(txt, -1, false); } + void commitPreedit(); QString displayText() const { return m_textLayout.text(); } -- cgit v1.2.3