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 <lars.knoll@nokia.com>
This commit is contained in:
Pekka Vuorela 2011-10-04 17:44:35 +03:00 committed by Qt by Nokia
parent 10dc2171cf
commit 7851568c65
5 changed files with 83 additions and 16 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -234,6 +234,7 @@ public:
m_tentativeCommit.clear();
internalSetText(txt, -1, false);
}
void commitPreedit();
QString displayText() const { return m_textLayout.text(); }