Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Enhance editors notifying input panel for input method changes
Introduced protected QQuickItem::updateInputMethod() and removed
similar, but badly named updateMicroFocus(). Added some missing
notifications from the editors and avoided unnecessary updates when not
having focus.

Change-Id: Id5c00e87dc26fd35c3f919006817511d4ed6418d
Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
Reviewed-by: Joona Petrell <joona.t.petrell@nokia.com>
  • Loading branch information
Pekka Vuorela authored and Qt by Nokia committed Jan 27, 2012
1 parent 8aa187f commit ed576da
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 24 deletions.
16 changes: 9 additions & 7 deletions src/quick/items/qquickitem.cpp
Expand Up @@ -3081,13 +3081,6 @@ void QQuickItem::setInputMethodHints(Qt::InputMethodHints hints)
qApp->inputPanel()->update(Qt::ImHints);
}

void QQuickItem::updateMicroFocus()
{
QInputPanel *p = qApp->inputPanel();
if (p->inputItem() == this)
qApp->inputPanel()->update(Qt::ImQueryInput);
}

QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const
{
Q_D(const QQuickItem);
Expand Down Expand Up @@ -3608,6 +3601,15 @@ void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value)
Q_UNUSED(value);
}

/*!
Notify input method on updated query values if needed. \a indicates changed attributes.
*/
void QQuickItem::updateInputMethod(Qt::InputMethodQueries queries)
{
if (hasActiveFocus())
qApp->inputPanel()->update(queries);
}

/*! \internal */
// XXX todo - do we want/need this anymore?
// Note that it's now used for varying clip rect
Expand Down
3 changes: 2 additions & 1 deletion src/quick/items/qquickitem.h
Expand Up @@ -324,7 +324,6 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QDeclarativeParserStatu

public Q_SLOTS:
void update();
void updateMicroFocus();

Q_SIGNALS:
void childrenRectChanged(const QRectF &);
Expand Down Expand Up @@ -359,6 +358,8 @@ public Q_SLOTS:
bool isComponentComplete() const;
virtual void itemChange(ItemChange, const ItemChangeData &);

void updateInputMethod(Qt::InputMethodQueries queries = Qt::ImQueryInput);

void setImplicitWidth(qreal);
bool widthValid() const; // ### better name?
void setImplicitHeight(qreal);
Expand Down
4 changes: 3 additions & 1 deletion src/quick/items/qquicktextedit.cpp
Expand Up @@ -373,6 +373,7 @@ void QQuickTextEdit::setFont(const QFont &font)
}
updateSize();
updateDocument();
updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
}
emit fontChanged(d->sourceFont);
}
Expand Down Expand Up @@ -1248,6 +1249,7 @@ void QQuickTextEdit::setReadOnly(bool r)
if (!r)
d->control->moveCursor(QTextCursor::End);

updateInputMethod(Qt::ImEnabled);
q_canPasteChanged();
emit readOnlyChanged(r);
}
Expand Down Expand Up @@ -1853,7 +1855,7 @@ void QQuickTextEdit::moveCursorDelegate()
{
Q_D(QQuickTextEdit);
d->determineHorizontalAlignment();
updateMicroFocus();
updateInputMethod();
emit cursorRectangleChanged();
if (!d->cursor)
return;
Expand Down
23 changes: 12 additions & 11 deletions src/quick/items/qquicktextinput.cpp
Expand Up @@ -306,7 +306,7 @@ void QQuickTextInput::setFont(const QFont &font)
if (oldFont != d->font) {
d->updateLayout();
updateCursorRectangle();
qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImFont);
updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
}
emit fontChanged(d->sourceFont);
}
Expand Down Expand Up @@ -575,6 +575,7 @@ void QQuickTextInput::setReadOnly(bool ro)
d->m_readOnly = ro;
if (!ro)
d->setCursorPosition(d->end());
updateInputMethod(Qt::ImEnabled);
q_canPasteChanged();
d->emitUndoRedoChanged();
emit readOnlyChanged(ro);
Expand Down Expand Up @@ -2508,6 +2509,7 @@ void QQuickTextInput::updateCursorRectangle()
d->cursorItem->setPos(r.topLeft());
d->cursorItem->setHeight(r.height());
}
updateInputMethod(Qt::ImCursorRectangle);
}

void QQuickTextInput::selectionChanged()
Expand Down Expand Up @@ -2873,8 +2875,8 @@ void QQuickTextInputPrivate::setSelection(int start, int length)
}
emit q->selectionChanged();
emitCursorPositionChanged();
qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
| Qt::ImCursorPosition | Qt::ImCurrentSelection);
q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
| Qt::ImCursorPosition | Qt::ImCurrentSelection);
}

/*!
Expand Down Expand Up @@ -2964,7 +2966,7 @@ void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
emit q->selectionChanged();
}
emitCursorPositionChanged();
q->updateMicroFocus();
q->updateInputMethod();
}

/*!
Expand Down Expand Up @@ -3065,7 +3067,6 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
emitCursorPositionChanged();
} else if (m_preeditCursor != oldPreeditCursor) {
q->updateCursorRectangle();
qApp->inputPanel()->update(Qt::ImCursorRectangle);
}

bool tentativeCommitChanged = m_tentativeCommit != event->tentativeCommitString();
Expand All @@ -3080,8 +3081,8 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)

if (selectionChange) {
emit q->selectionChanged();
qApp->inputPanel()->update(Qt::ImCursorRectangle | Qt::ImAnchorPosition
| Qt::ImCursorPosition | Qt::ImCurrentSelection);
q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
| Qt::ImCursorPosition | Qt::ImCurrentSelection);
}
}

Expand Down Expand Up @@ -3123,7 +3124,7 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
Q_Q(QQuickTextInput);

Q_UNUSED(update)
bool notifyInputPanel = m_textDirty || m_selDirty;
bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
bool alignmentChanged = false;

if (m_textDirty) {
Expand Down Expand Up @@ -3194,9 +3195,9 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
emit q->selectionChanged();
}

notifyInputPanel |= (m_cursor == m_lastCursorPos);
if (notifyInputPanel)
q->updateMicroFocus();
inputMethodAttributesChanged |= (m_cursor == m_lastCursorPos);
if (inputMethodAttributesChanged)
q->updateInputMethod();
emitUndoRedoChanged();

if (!emitCursorPositionChanged() && alignmentChanged)
Expand Down
99 changes: 97 additions & 2 deletions tests/auto/qtquick2/qquicktextedit/tst_qquicktextedit.cpp
Expand Up @@ -144,6 +144,7 @@ private slots:
void canPaste();
void canPasteEmpty();
void textInput();
void inputPanelUpdate();
void openInputPanel();
void geometrySignals();
void pastingRichText_QTBUG_14003();
Expand Down Expand Up @@ -226,7 +227,7 @@ void tst_qquicktextedit::simulateKeys(QWindow *window, const QList<Key> &keys)

void tst_qquicktextedit::simulateKeys(QWindow *window, const QKeySequence &sequence)
{
for (uint i = 0; i < sequence.count(); ++i) {
for (int i = 0; i < sequence.count(); ++i) {
const int key = sequence[i];
const int modifiers = key & Qt::KeyboardModifierMask;

Expand All @@ -236,7 +237,7 @@ void tst_qquicktextedit::simulateKeys(QWindow *window, const QKeySequence &seque

QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence)
{
for (uint i = 0; i < sequence.count(); ++i)
for (int i = 0; i < sequence.count(); ++i)
keys << Key(sequence[i], QChar());
return keys;
}
Expand Down Expand Up @@ -2131,6 +2132,100 @@ void tst_qquicktextedit::textInput()
QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event2);
QCOMPARE(spy.count(), 1);
QCOMPARE(edit->text(), QString("string"));

QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &queryEvent);
QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), true);

edit->setReadOnly(true);
QGuiApplication::sendEvent(edit, &queryEvent);
QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), false);
}

void tst_qquicktextedit::inputPanelUpdate()
{
PlatformInputContext platformInputContext;
QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel());
inputPanelPrivate->testContext = &platformInputContext;

QQuickView view(testFileUrl("inputMethodEvent.qml"));
view.show();
view.requestActivateWindow();
QTest::qWaitForWindowShown(&view);
QTRY_COMPARE(&view, qGuiApp->focusWindow());
QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
QVERIFY(edit);
QVERIFY(edit->hasActiveFocus() == true);

// text change even without cursor position change needs to trigger update
edit->setText("test");
platformInputContext.clear();
edit->setText("xxxx");
QVERIFY(platformInputContext.m_updateCallCount > 0);

// input method event replacing text
platformInputContext.clear();
{
QInputMethodEvent inputMethodEvent;
inputMethodEvent.setCommitString("y", -1, 1);
QGuiApplication::sendEvent(edit, &inputMethodEvent);
}
QVERIFY(platformInputContext.m_updateCallCount > 0);

// input method changing selection
platformInputContext.clear();
{
QList<QInputMethodEvent::Attribute> attributes;
attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 2, QVariant());
QInputMethodEvent inputMethodEvent("", attributes);
QGuiApplication::sendEvent(edit, &inputMethodEvent);
}
QVERIFY(edit->selectionStart() != edit->selectionEnd());
QVERIFY(platformInputContext.m_updateCallCount > 0);

// font changes
platformInputContext.clear();
QFont font = edit->font();
font.setBold(!font.bold());
edit->setFont(font);
QVERIFY(platformInputContext.m_updateCallCount > 0);

// normal input
platformInputContext.clear();
{
QInputMethodEvent inputMethodEvent;
inputMethodEvent.setCommitString("y");
QGuiApplication::sendEvent(edit, &inputMethodEvent);
}
QVERIFY(platformInputContext.m_updateCallCount > 0);

// changing cursor position
platformInputContext.clear();
edit->setCursorPosition(0);
QVERIFY(platformInputContext.m_updateCallCount > 0);

// continuing with selection
platformInputContext.clear();
edit->moveCursorSelection(1);
QVERIFY(platformInputContext.m_updateCallCount > 0);

// read only disabled input method
platformInputContext.clear();
edit->setReadOnly(true);
QVERIFY(platformInputContext.m_updateCallCount > 0);
edit->setReadOnly(false);

// no updates while no focus
edit->setFocus(false);
platformInputContext.clear();
edit->setText("Foo");
QCOMPARE(platformInputContext.m_updateCallCount, 0);
edit->setCursorPosition(1);
QCOMPARE(platformInputContext.m_updateCallCount, 0);
edit->selectAll();
QCOMPARE(platformInputContext.m_updateCallCount, 0);
edit->setReadOnly(true);
QCOMPARE(platformInputContext.m_updateCallCount, 0);
}

void tst_qquicktextedit::openInputPanel()
Expand Down
30 changes: 28 additions & 2 deletions tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
Expand Up @@ -222,7 +222,7 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)

void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
{
for (uint i = 0; i < sequence.count(); ++i) {
for (int i = 0; i < sequence.count(); ++i) {
const int key = sequence[i];
const int modifiers = key & Qt::KeyboardModifierMask;

Expand All @@ -232,7 +232,7 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequ

QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence)
{
for (uint i = 0; i < sequence.count(); ++i)
for (int i = 0; i < sequence.count(); ++i)
keys << Key(sequence[i], QChar());
return keys;
}
Expand Down Expand Up @@ -1951,6 +1951,14 @@ void tst_qquicktextinput::inputMethods()
event.setCommitString("replacement", -input->text().length(), input->text().length());
QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event);
QCOMPARE(input->selectionStart(), input->selectionEnd());

QInputMethodQueryEvent enabledQueryEvent(Qt::ImEnabled);
QGuiApplication::sendEvent(input, &enabledQueryEvent);
QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), true);

input->setReadOnly(true);
QGuiApplication::sendEvent(input, &enabledQueryEvent);
QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false);
}

/*
Expand Down Expand Up @@ -3081,6 +3089,24 @@ void tst_qquicktextinput::inputPanelUpdate()
platformInputContext.clear();
input->setCursorPosition(0);
QVERIFY(platformInputContext.m_updateCallCount > 0);

// read only disabled input method
platformInputContext.clear();
input->setReadOnly(true);
QVERIFY(platformInputContext.m_updateCallCount > 0);
input->setReadOnly(false);

// no updates while no focus
input->setFocus(false);
platformInputContext.clear();
input->setText("Foo");
QCOMPARE(platformInputContext.m_updateCallCount, 0);
input->setCursorPosition(1);
QCOMPARE(platformInputContext.m_updateCallCount, 0);
input->selectAll();
QCOMPARE(platformInputContext.m_updateCallCount, 0);
input->setReadOnly(true);
QCOMPARE(platformInputContext.m_updateCallCount, 0);
}

void tst_qquicktextinput::cursorRectangleSize()
Expand Down

0 comments on commit ed576da

Please sign in to comment.