diff options
16 files changed, 358 insertions, 33 deletions
diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 466b940..e2d9350 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -76,7 +76,7 @@ To see the QML elements listed by functional area, see the \o \l {FocusScope} - Element that mediate keyboard focus changes \o \l {Flickable} - Provides a surface that can be "flicked" \o \l {Flipable} - Provides a surface that produces "flipping" effects -\o \l {GestureArea} - Enables simple gesture handling +\o \l {PinchArea} - Enables simple pinch gesture handling \endlist \section1 Positioners and Repeater diff --git a/doc/src/declarative/qmlinuse.qdoc b/doc/src/declarative/qmlinuse.qdoc index 7380ef5..131be1b 100644 --- a/doc/src/declarative/qmlinuse.qdoc +++ b/doc/src/declarative/qmlinuse.qdoc @@ -207,7 +207,7 @@ <li><a href="qml-flipable.html">Flipable Element</a> - The Flipable item provides a surface that can be flipped or reflected.</li> <li><a href="qml-focuspanel.html">FocusPanel Element</a> - The FocusPanel item explicitly creates a focus panel.</li> <li><a href="qml-focusscope.html">FocusScope Element</a> - The FocusScope object explicitly creates a focus scope for focus management.</li> - <li><a href="qml-gesturearea.html">GestureArea Element</a> - The GestureArea item enables simple gesture handling.</li> + <li><a href="qml-pincharea.html">PinchArea Element</a> - The PinchArea item enables simple pinch gesture handling.</li> <li><a href="qml-keynavigation.html">KeyNavigation Element</a> - The KeyNavigation attached property supports key navigation by arrow keys.</li> <li><a href="qml-keys.html">Keys Element</a> - The Keys attached property provides key handling to Items.</li> <li><a href="qml-mousearea.html">MouseArea Element</a> - The MouseArea item enables simple mouse handling.</li> diff --git a/doc/src/development/qmake-manual.qdoc b/doc/src/development/qmake-manual.qdoc index 9a46ea8..9695d84 100644 --- a/doc/src/development/qmake-manual.qdoc +++ b/doc/src/development/qmake-manual.qdoc @@ -1650,8 +1650,7 @@ \section1 INCLUDEPATH This variable specifies the #include directories which should be - searched when compiling the project. Use ';' or a space as the - directory separator. + searched when compiling the project. For example: diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index d92eb69..44e5164 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -662,10 +662,10 @@ void Win32MakefileGenerator::writeStandardParts(QTextStream &t) if(project->isActiveConfig("shared") && !project->values("DLLDESTDIR").isEmpty()) { QStringList dlldirs = project->values("DLLDESTDIR"); for (QStringList::Iterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) { - t << "\n\t" << "-$(COPY_FILE) \"$(DESTDIR_TARGET)\" " << Option::fixPathToTargetOS(*dlldir, false); + t << "\t" << "-$(COPY_FILE) \"$(DESTDIR_TARGET)\" " << Option::fixPathToTargetOS(*dlldir, false) << endl; } } - t << endl << endl; + t << endl; writeRcFilePart(t); diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index 59921d5..c28d7f4 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -606,6 +606,22 @@ int QDeclarativeTextEdit::positionAt(int x, int y) const { Q_D(const QDeclarativeTextEdit); int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit); + QTextCursor cursor = d->control->textCursor(); + if (r > cursor.position()) { + // The cursor position includes positions within the preedit text, but only positions in the + // same text block are offset so it is possible to get a position that is either part of the + // preedit or the next text block. + QTextLayout *layout = cursor.block().layout(); + const int preeditLength = layout + ? layout->preeditAreaText().length() + : 0; + if (preeditLength > 0 + && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) { + r = r > cursor.position() + preeditLength + ? r - preeditLength + : cursor.position(); + } + } return r; } @@ -1318,7 +1334,10 @@ Handles the given input method \a event. void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event) { Q_D(QDeclarativeTextEdit); + const bool wasComposing = isInputMethodComposing(); d->control->processEvent(event, QPointF(0, -d->yoff)); + if (wasComposing != isInputMethodComposing()) + emit inputMethodComposingChanged(); } /*! @@ -1394,6 +1413,27 @@ bool QDeclarativeTextEdit::canPaste() const return d->canPaste; } +/*! + \qmlproperty bool TextEdit::isInputMethodComposing() + + \since QtQuick 1.1 + + This property holds whether the TextEdit has partial text input from an + input method. + + While it is composing an input method may rely on mouse or key events from + the TextEdit to edit or commit the partial text. This property can be used + to determine when to disable events handlers that may interfere with the + correct operation of an input method. +*/ +bool QDeclarativeTextEdit::isInputMethodComposing() const +{ + Q_D(const QDeclarativeTextEdit); + if (QTextLayout *layout = d->control->textCursor().block().layout()) + return layout->preeditAreaText().length() > 0; + return false; +} + void QDeclarativeTextEditPrivate::init() { Q_Q(QDeclarativeTextEdit); diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index 7785a7a..612f9a9 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -94,6 +94,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePa Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1) + Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1) public: QDeclarativeTextEdit(QDeclarativeItem *parent=0); @@ -215,6 +216,8 @@ public: QRectF boundingRect() const; + bool isInputMethodComposing() const; + Q_SIGNALS: void textChanged(const QString &); void paintedSizeChanged(); @@ -242,6 +245,7 @@ Q_SIGNALS: Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void linkActivated(const QString &link); Q_REVISION(1) void canPasteChanged(); + Q_REVISION(1) void inputMethodComposingChanged(); public Q_SLOTS: void selectAll(); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 65ed5c6..dc44bfe 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -482,6 +482,7 @@ QRect QDeclarativeTextInput::cursorRectangle() const Q_D(const QDeclarativeTextInput); QRect r = d->control->cursorRect(); r.setHeight(r.height()-1); // Make consistent with TextEdit (QLineControl inexplicably adds 1) + r.moveLeft(r.x() - d->hscroll); return r; } @@ -921,6 +922,8 @@ void QDeclarativeTextInput::moveCursor() QRectF QDeclarativeTextInput::positionToRectangle(int pos) const { Q_D(const QDeclarativeTextInput); + if (pos > d->control->cursorPosition()) + pos += d->control->preeditAreaText().length(); return QRectF(d->control->cursorToX(pos)-d->hscroll, 0.0, d->control->cursorWidth(), @@ -929,8 +932,7 @@ QRectF QDeclarativeTextInput::positionToRectangle(int pos) const int QDeclarativeTextInput::positionAt(int x) const { - Q_D(const QDeclarativeTextInput); - return d->control->xToPos(x + d->hscroll); + return positionAt(x, CursorBetweenCharacters); } /*! @@ -952,10 +954,18 @@ int QDeclarativeTextInput::positionAt(int x) const \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x. \endlist */ -int QDeclarativeTextInput::positionAt(int x, CursorPosition position) +int QDeclarativeTextInput::positionAt(int x, CursorPosition position) const { Q_D(const QDeclarativeTextInput); - return d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position)); + int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position)); + const int cursor = d->control->cursor(); + if (pos > cursor) { + const int preeditLength = d->control->preeditAreaText().length(); + pos = pos > cursor + preeditLength + ? pos - preeditLength + : cursor; + } + return pos; } void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus) @@ -996,18 +1006,22 @@ void QDeclarativeTextInput::inputMethodEvent(QInputMethodEvent *ev) { Q_D(QDeclarativeTextInput); ev->ignore(); + const bool wasComposing = d->control->preeditAreaText().length() > 0; inputMethodPreHandler(ev); - if (ev->isAccepted()) - return; - if (d->control->isReadOnly()) { - ev->ignore(); - } else { - d->control->processInputMethodEvent(ev); - updateSize(); - d->updateHorizontalScroll(); + if (!ev->isAccepted()) { + if (d->control->isReadOnly()) { + ev->ignore(); + } else { + d->control->processInputMethodEvent(ev); + updateSize(); + d->updateHorizontalScroll(); + } } if (!ev->isAccepted()) QDeclarativePaintedItem::inputMethodEvent(ev); + + if (wasComposing != (d->control->preeditAreaText().length() > 0)) + emit inputMethodComposingChanged(); } /*! @@ -1061,7 +1075,7 @@ void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextInput); if (d->sendMouseEventToInputContext(event, QEvent::MouseMove)) - event->setAccepted(true); + return; if (d->selectByMouse) { if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance()) setKeepMouseGrab(true); @@ -1706,6 +1720,25 @@ void QDeclarativeTextInput::focusInEvent(QFocusEvent *event) QDeclarativePaintedItem::focusInEvent(event); } +/*! + \qmlproperty bool TextInput::isInputMethodComposing() + + \since QtQuick 1.1 + + This property holds whether the TextInput has partial text input from an + input method. + + While it is composing an input method may rely on mouse or key events from + the TextInput to edit or commit the partial text. This property can be + used to determine when to disable events handlers that may interfere with + the correct operation of an input method. +*/ +bool QDeclarativeTextInput::isInputMethodComposing() const +{ + Q_D(const QDeclarativeTextInput); + return d->control->preeditAreaText().length() > 0; +} + void QDeclarativeTextInputPrivate::init() { Q_Q(QDeclarativeTextInput); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index c29be26..822d5e2 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -97,6 +97,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1) + Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1) public: QDeclarativeTextInput(QDeclarativeItem* parent=0); @@ -127,7 +128,7 @@ public: //Auxilliary functions needed to control the TextInput from QML Q_INVOKABLE int positionAt(int x) const; - Q_INVOKABLE Q_REVISION(1) int positionAt(int x, CursorPosition position); + Q_INVOKABLE Q_REVISION(1) int positionAt(int x, CursorPosition position) const; Q_INVOKABLE QRectF positionToRectangle(int pos) const; Q_INVOKABLE void moveCursorSelection(int pos); Q_INVOKABLE Q_REVISION(1) void moveCursorSelection(int pos, SelectionMode mode); @@ -210,6 +211,8 @@ public: QRectF boundingRect() const; bool canPaste() const; + bool isInputMethodComposing() const; + Q_SIGNALS: void textChanged(); void cursorPositionChanged(); @@ -237,6 +240,7 @@ Q_SIGNALS: void selectByMouseChanged(bool selectByMouse); Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void canPasteChanged(); + Q_REVISION(1) void inputMethodComposingChanged(); protected: virtual void geometryChanged(const QRectF &newGeometry, diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp index b24dd2c..31819f5 100644 --- a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp @@ -99,7 +99,6 @@ class DrawTextItemRecorder: public QPaintEngine needFreshCurrentItem = false; last.numChars += ti.num_chars; - last.numGlyphs += ti.glyphs.numGlyphs; } } @@ -111,7 +110,7 @@ class DrawTextItemRecorder: public QPaintEngine currentItem.font = ti.font(); currentItem.charOffset = charOffset; currentItem.numChars = ti.num_chars; - currentItem.numGlyphs = ti.glyphs.numGlyphs; + currentItem.numGlyphs = 0; currentItem.glyphOffset = glyphOffset; currentItem.positionOffset = positionOffset; currentItem.useBackendOptimizations = m_useBackendOptimizations; @@ -121,6 +120,8 @@ class DrawTextItemRecorder: public QPaintEngine m_inertText->items.append(currentItem); } + QStaticTextItem ¤tItem = m_inertText->items.last(); + QTransform matrix = m_untransformedCoordinates ? QTransform() : state->transform(); matrix.translate(position.x(), position.y()); @@ -129,18 +130,18 @@ class DrawTextItemRecorder: public QPaintEngine ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); int size = glyphs.size(); - Q_ASSERT(size == ti.glyphs.numGlyphs); Q_ASSERT(size == positions.size()); + currentItem.numGlyphs += size; m_inertText->glyphs.resize(m_inertText->glyphs.size() + size); m_inertText->positions.resize(m_inertText->glyphs.size()); m_inertText->chars.resize(m_inertText->chars.size() + ti.num_chars); glyph_t *glyphsDestination = m_inertText->glyphs.data() + glyphOffset; - qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * ti.glyphs.numGlyphs); + qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * size); QFixedPoint *positionsDestination = m_inertText->positions.data() + positionOffset; - qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * ti.glyphs.numGlyphs); + qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * size); QChar *charsDestination = m_inertText->chars.data() + charOffset; qMemCopy(charsDestination, ti.chars, sizeof(QChar) * ti.num_chars); diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index d108ad9..bffc2b5 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -420,7 +420,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) int c = m_cursor; // cursor position after insertion of commit string if (event->replacementStart() <= 0) - c += event->commitString().length() + qMin(-event->replacementStart(), event->replacementLength()); + c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength()); m_cursor += event->replacementStart(); diff --git a/src/imports/gestures/qdeclarativegesturearea.cpp b/src/imports/gestures/qdeclarativegesturearea.cpp index 1b6e723..c2a2e98 100644 --- a/src/imports/gestures/qdeclarativegesturearea.cpp +++ b/src/imports/gestures/qdeclarativegesturearea.cpp @@ -89,6 +89,10 @@ public: \warning Elements in the Qt.labs module are not guaranteed to remain compatible in future versions. + \warning GestureArea is an experimental element whose development has + been discontinued. PinchArea is available in QtQuick 1.1 and handles + two finger gesture input. + \note This element is only functional on devices with touch input. \qml diff --git a/tests/auto/declarative/qdeclarativetext/data/qtbug_14734.qml b/tests/auto/declarative/qdeclarativetext/data/qtbug_14734.qml new file mode 100644 index 0000000..bd07d66 --- /dev/null +++ b/tests/auto/declarative/qdeclarativetext/data/qtbug_14734.qml @@ -0,0 +1,10 @@ +import QtQuick 1.0 + +Rectangle { + width: 640 + height: 480 + + Text { + text: "Ã " + } +} diff --git a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp index 05546cb..7e0069f 100644 --- a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp +++ b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp @@ -109,6 +109,7 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); + void qtbug_14734(); private: QStringList standard; QStringList richText; @@ -1202,6 +1203,19 @@ void tst_qdeclarativetext::testQtQuick11Attributes_data() << ""; } +void tst_qdeclarativetext::qtbug_14734() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/qtbug_14734.qml"); + QVERIFY(canvas); + + canvas->show(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas)); + + delete canvas; +} + QTEST_MAIN(tst_qdeclarativetext) #include "tst_qdeclarativetext.moc" diff --git a/tests/auto/declarative/qdeclarativetextedit/data/positionAt.qml b/tests/auto/declarative/qdeclarativetextedit/data/positionAt.qml new file mode 100644 index 0000000..e010135 --- /dev/null +++ b/tests/auto/declarative/qdeclarativetextedit/data/positionAt.qml @@ -0,0 +1,9 @@ +import QtQuick 1.0 + +TextEdit { + focus: true + objectName: "myInput" + width: 50 + height: 25 + text: "This is\n a long piece of text" +} diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 2c3ec7c..dc1063f 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -121,6 +121,8 @@ private slots: void dragMouseSelection(); void inputMethodHints(); + void positionAt(); + void cursorDelegate(); void cursorVisible(); void delegateLoading_data(); @@ -140,6 +142,7 @@ private slots: void preeditMicroFocus(); void inputContextMouseHandler(); + void inputMethodComposing(); private: void simulateKey(QDeclarativeView *, int key); @@ -1250,6 +1253,56 @@ void tst_qdeclarativetextedit::inputMethodHints() delete canvas; } +void tst_qdeclarativetextedit::positionAt() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/positionAt.qml"); + QVERIFY(canvas->rootObject() != 0); + canvas->show(); + canvas->setFocus(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + + QDeclarativeTextEdit *texteditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject()); + QVERIFY(texteditObject != 0); + + QFontMetrics fm(texteditObject->font()); + const int y0 = fm.height() / 2; + const int y1 = fm.height() * 3 / 2; + + int pos = texteditObject->positionAt(texteditObject->width()/2, y0); + int diff = abs(int(fm.width(texteditObject->text().left(pos))-texteditObject->width()/2)); + + // some tollerance for different fonts. +#ifdef Q_OS_LINUX + QVERIFY(diff < 2); +#else + QVERIFY(diff < 5); +#endif + + const qreal x0 = texteditObject->positionToRectangle(pos).x(); + const qreal x1 = texteditObject->positionToRectangle(pos + 1).x(); + + QString preeditText = texteditObject->text().mid(0, pos); + texteditObject->setText(texteditObject->text().mid(pos)); + texteditObject->setCursorPosition(0); + + QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QApplication::sendEvent(canvas, &inputEvent); + + // Check all points within the preedit text return the same position. + QCOMPARE(texteditObject->positionAt(0, y0), 0); + QCOMPARE(texteditObject->positionAt(x0 / 2, y0), 0); + QCOMPARE(texteditObject->positionAt(x0, y0), 0); + + // Verify positioning returns to normal after the preedit text. + QCOMPARE(texteditObject->positionAt(x1, y0), 1); + QCOMPARE(texteditObject->positionToRectangle(1).x(), x1); + + QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0); + + delete canvas; +} + void tst_qdeclarativetextedit::cursorDelegate() { QDeclarativeView* view = createView(SRCDIR "/data/cursorTest.qml"); @@ -2079,6 +2132,43 @@ void tst_qdeclarativetextedit::inputContextMouseHandler() ic.eventType = QEvent::None; } +void tst_qdeclarativetextedit::inputMethodComposing() +{ + QString text = "supercalifragisiticexpialidocious!"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextEdit edit; + edit.setWidth(200); + edit.setText(text.mid(0, 12)); + edit.setCursorPosition(12); + edit.setPos(0, 0); + edit.setFocus(true); + scene.addItem(&edit); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QSignalSpy spy(&edit, SIGNAL(inputMethodComposingChanged())); + + QCOMPARE(edit.isInputMethodComposing(), false); + + ic.sendEvent(QInputMethodEvent(text.mid(3), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(edit.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(edit.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent()); + QCOMPARE(edit.isInputMethodComposing(), false); + QCOMPARE(spy.count(), 2); +} + QTEST_MAIN(tst_qdeclarativetextedit) #include "tst_qdeclarativetextedit.moc" diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 6cb57a2..24ce0e4 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -111,6 +111,7 @@ private slots: void passwordCharacter(); void cursorDelegate(); void cursorVisible(); + void cursorRectangle(); void navigation(); void copyAndPaste(); void readOnly(); @@ -128,6 +129,7 @@ private slots: void preeditAutoScroll(); void preeditMicroFocus(); void inputContextMouseHandler(); + void inputMethodComposing(); private: void simulateKey(QDeclarativeView *, int key); @@ -975,6 +977,25 @@ void tst_qdeclarativetextinput::positionAt() QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorBetweenCharacters), pos + 1); QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorOnCharacter), pos); + const qreal x0 = textinputObject->positionToRectangle(pos).x(); + const qreal x1 = textinputObject->positionToRectangle(pos + 1).x(); + + QString preeditText = textinputObject->text().mid(0, pos); + textinputObject->setText(textinputObject->text().mid(pos)); + textinputObject->setCursorPosition(0); + + QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QApplication::sendEvent(canvas, &inputEvent); + + // Check all points within the preedit text return the same position. + QCOMPARE(textinputObject->positionAt(0), 0); + QCOMPARE(textinputObject->positionAt(x0 / 2), 0); + QCOMPARE(textinputObject->positionAt(x0), 0); + + // Verify positioning returns to normal after the preedit text. + QCOMPARE(textinputObject->positionAt(x1), 1); + QCOMPARE(textinputObject->positionToRectangle(1).x(), x1); + delete canvas; } @@ -1153,6 +1174,24 @@ void tst_qdeclarativetextinput::inputMethods() QApplication::sendEvent(canvas, &event); QCOMPARE(input->text(), QString("My Hello world!")); + input->setCursorPosition(2); + event.setCommitString("Your", -2, 2); + QApplication::sendEvent(canvas, &event); + QCOMPARE(input->text(), QString("Your Hello world!")); + QCOMPARE(input->cursorPosition(), 4); + + input->setCursorPosition(7); + event.setCommitString("Goodbye", -2, 5); + QApplication::sendEvent(canvas, &event); + QCOMPARE(input->text(), QString("Your Goodbye world!")); + QCOMPARE(input->cursorPosition(), 12); + + input->setCursorPosition(8); + event.setCommitString("Our", -8, 4); + QApplication::sendEvent(canvas, &event); + QCOMPARE(input->text(), QString("Our Goodbye world!")); + QCOMPARE(input->cursorPosition(), 7); + delete canvas; } @@ -1394,6 +1433,41 @@ void tst_qdeclarativetextinput::cursorVisible() #endif } +void tst_qdeclarativetextinput::cursorRectangle() +{ + QString text = "Hello World!"; + + QDeclarativeTextInput input; + input.setText(text); + QFontMetricsF fm(input.font()); + input.setWidth(fm.width(text.mid(0, 5))); + + QRect r; + + for (int i = 0; i <= 5; ++i) { + input.setCursorPosition(i); + r = input.cursorRectangle(); + int textWidth = fm.width(text.mid(0, i)); + + QVERIFY(r.left() < textWidth); + QVERIFY(r.right() > textWidth); + } + + // Check the cursor rectangle remains within the input bounding rect when auto scrolling. + QVERIFY(r.left() < input.boundingRect().width()); + QVERIFY(r.right() >= input.width()); + + for (int i = 6; i < text.length(); ++i) { + input.setCursorPosition(i); + QCOMPARE(r, input.cursorRectangle()); + } + + for (int i = text.length() - 2; i >= 0; --i) { + input.setCursorPosition(i); + QVERIFY(r.right() >= 0); + } +} + void tst_qdeclarativetextinput::readOnly() { QDeclarativeView *canvas = createView(SRCDIR "/data/readOnly.qml"); @@ -1848,7 +1922,8 @@ void tst_qdeclarativetextinput::preeditAutoScroll() MyInputContext ic; view.setInputContext(&ic); QDeclarativeTextInput input; - input.setWidth(QFontMetricsF(input.font()).width(committedText)); + QFontMetricsF fm(input.font()); + input.setWidth(fm.width(committedText)); input.setText(committedText); input.setPos(0, 0); input.setFocus(true); @@ -1861,7 +1936,7 @@ void tst_qdeclarativetextinput::preeditAutoScroll() // test the text is scrolled so the preedit is visible. ic.sendPreeditText(preeditText.mid(0, 3), 1); QVERIFY(input.positionAt(0) != 0); - QCOMPARE(input.positionAt(input.width()), 8); + QVERIFY(input.cursorRectangle().left() < input.boundingRect().width()); // test the text is scrolled back when the preedit is removed. ic.sendEvent(QInputMethodEvent()); @@ -1870,26 +1945,31 @@ void tst_qdeclarativetextinput::preeditAutoScroll() // test if the preedit is larger than the text input that the // character preceding the cursor is still visible. + qreal x = input.positionToRectangle(0).x(); for (int i = 0; i < 3; ++i) { ic.sendPreeditText(preeditText, i + 1); - QCOMPARE(input.positionAt(0), 5 + i); + QVERIFY(input.cursorRectangle().right() >= fm.width(preeditText.at(i))); + QVERIFY(input.positionToRectangle(0).x() < x); + x = input.positionToRectangle(0).x(); } for (int i = 1; i >= 0; --i) { ic.sendPreeditText(preeditText, i + 1); - QCOMPARE(input.positionAt(0), 5 + i); + QVERIFY(input.cursorRectangle().right() >= fm.width(preeditText.at(i))); + QVERIFY(input.positionToRectangle(0).x() > x); + x = input.positionToRectangle(0).x(); } // Test incrementing the preedit cursor doesn't cause further // scrolling when right most text is visible. ic.sendPreeditText(preeditText, preeditText.length() - 3); - int position = input.positionAt(0); + x = input.positionToRectangle(0).x(); for (int i = 2; i >= 0; --i) { ic.sendPreeditText(preeditText, preeditText.length() - i); - QCOMPARE(input.positionAt(0), position); + QCOMPARE(input.positionToRectangle(0).x(), x); } for (int i = 1; i < 3; ++i) { ic.sendPreeditText(preeditText, preeditText.length() - i); - QCOMPARE(input.positionAt(0), position); + QCOMPARE(input.positionToRectangle(0).x(), x); } // Test disabling auto scroll. @@ -2074,6 +2154,43 @@ void tst_qdeclarativetextinput::inputContextMouseHandler() ic.eventType = QEvent::None; } +void tst_qdeclarativetextinput::inputMethodComposing() +{ + QString text = "supercalifragisiticexpialidocious!"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextInput input; + input.setWidth(200); + input.setText(text.mid(0, 12)); + input.setCursorPosition(12); + input.setPos(0, 0); + input.setFocus(true); + scene.addItem(&input); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QSignalSpy spy(&input, SIGNAL(inputMethodComposingChanged())); + + QCOMPARE(input.isInputMethodComposing(), false); + + ic.sendEvent(QInputMethodEvent(text.mid(3), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(input.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(input.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent()); + QCOMPARE(input.isInputMethodComposing(), false); + QCOMPARE(spy.count(), 2); +} + QTEST_MAIN(tst_qdeclarativetextinput) #include "tst_qdeclarativetextinput.moc" |