diff options
Diffstat (limited to 'tests/auto/declarative')
60 files changed, 4362 insertions, 143 deletions
diff --git a/tests/auto/declarative/qdeclarativeanchors/data/fill.qml b/tests/auto/declarative/qdeclarativeanchors/data/fill.qml index 50fbbe0..ff19675 100644 --- a/tests/auto/declarative/qdeclarativeanchors/data/fill.qml +++ b/tests/auto/declarative/qdeclarativeanchors/data/fill.qml @@ -6,9 +6,9 @@ Rectangle { objectName: "filler" width: 50; height: 50; color: "blue" anchors.fill: parent; - anchors.leftMargin: 10; - anchors.rightMargin: 20; - anchors.topMargin: 30; - anchors.bottomMargin: 40; + anchors.leftMargin: 10; + anchors.rightMargin: 20; + anchors.topMargin: 30; + anchors.bottomMargin: 40; } } diff --git a/tests/auto/declarative/qdeclarativeanchors/data/margins.qml b/tests/auto/declarative/qdeclarativeanchors/data/margins.qml index dace9c0..685346a 100644 --- a/tests/auto/declarative/qdeclarativeanchors/data/margins.qml +++ b/tests/auto/declarative/qdeclarativeanchors/data/margins.qml @@ -6,8 +6,8 @@ Rectangle { objectName: "filler" width: 50; height: 50; color: "blue" anchors.fill: parent; - anchors.margins: 10 - anchors.leftMargin: 5 - anchors.topMargin: 6 + anchors.margins: 10 + anchors.leftMargin: 5 + anchors.topMargin: 6 } } diff --git a/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp b/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp index e880857..0442350 100644 --- a/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp +++ b/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp @@ -65,13 +65,10 @@ class tst_qdeclarativeanchors : public QObject public: tst_qdeclarativeanchors() {} - template<typename T> - T *findItem(QGraphicsObject *parent, const QString &id); - QGraphicsObject *findObject(QGraphicsObject *parent, const QString &objectName); - private slots: void basicAnchors(); void basicAnchorsQGraphicsWidget(); + void basicAnchorsRTL(); void loops(); void illegalSets(); void illegalSets_data(); @@ -82,16 +79,20 @@ private slots: void nullItem_data(); void crash1(); void centerIn(); + void centerInRTL(); void hvCenter(); + void hvCenterRTL(); void fill(); + void fillRTL(); void margins(); + void marginsRTL(); }; /* Find an item with the specified id. */ template<typename T> -T *tst_qdeclarativeanchors::findItem(QGraphicsObject *parent, const QString &objectName) +T *findItem(QGraphicsObject *parent, const QString &objectName) { const QMetaObject &mo = T::staticMetaObject; QList<QGraphicsItem *> children = parent->childItems(); @@ -110,7 +111,7 @@ T *tst_qdeclarativeanchors::findItem(QGraphicsObject *parent, const QString &obj return 0; } -QGraphicsObject *tst_qdeclarativeanchors::findObject(QGraphicsObject *parent, const QString &objectName) +QGraphicsObject *findObject(QGraphicsObject *parent, const QString &objectName) { QList<QGraphicsItem *> children = parent->childItems(); for (int i = 0; i < children.count(); ++i) { @@ -263,6 +264,105 @@ void tst_qdeclarativeanchors::basicAnchorsQGraphicsWidget() delete view; } +QDeclarativeItem* childItem(QDeclarativeItem *parentItem, const char * itemString) { + return findItem<QDeclarativeItem>(parentItem, QLatin1String(itemString)); +} + +qreal offsetMasterRTL(QDeclarativeItem *rootItem, const char * itemString) { + QDeclarativeItem* masterItem = findItem<QDeclarativeItem>(rootItem, QLatin1String("masterRect")); + return masterItem->width()+2*masterItem->x()-findItem<QDeclarativeItem>(rootItem, QLatin1String(itemString))->width(); +} + +qreal offsetParentRTL(QDeclarativeItem *rootItem, const char * itemString) { + return rootItem->width()+2*rootItem->x()-findItem<QDeclarativeItem>(rootItem, QLatin1String(itemString))->width(); +} + +void mirrorAnchors(QDeclarativeItem *item) { + QDeclarativeItemPrivate *itemPrivate = QDeclarativeItemPrivate::get(item); + itemPrivate->setLayoutMirror(true); +} + +void tst_qdeclarativeanchors::basicAnchorsRTL() +{ + QDeclarativeView *view = new QDeclarativeView; + view->setSource(QUrl::fromLocalFile(SRCDIR "/data/anchors.qml")); + + qApp->processEvents(); + + QDeclarativeItem* rootItem = qobject_cast<QDeclarativeItem*>(view->rootObject()); + foreach(QObject *child, rootItem->children()) { + bool mirrored = QDeclarativeItemPrivate::get(qobject_cast<QDeclarativeItem*>(child))->anchors()->property("mirrored").toBool(); + QCOMPARE(mirrored, false); + } + + foreach(QObject *child, rootItem->children()) + mirrorAnchors(qobject_cast<QDeclarativeItem*>(child)); + + foreach(QObject *child, rootItem->children()) { + bool mirrored = QDeclarativeItemPrivate::get(qobject_cast<QDeclarativeItem*>(child))->anchors()->property("mirrored").toBool(); + QCOMPARE(mirrored, true); + } + + //sibling horizontal + QCOMPARE(childItem(rootItem, "rect1")->x(), offsetMasterRTL(rootItem, "rect1")-26.0); + QCOMPARE(childItem(rootItem, "rect2")->x(), offsetMasterRTL(rootItem, "rect2")-122.0); + QCOMPARE(childItem(rootItem, "rect3")->x(), offsetMasterRTL(rootItem, "rect3")-74.0); + QCOMPARE(childItem(rootItem, "rect4")->x(), offsetMasterRTL(rootItem, "rect4")-16.0); + QCOMPARE(childItem(rootItem, "rect5")->x(), offsetMasterRTL(rootItem, "rect5")-112.0); + QCOMPARE(childItem(rootItem, "rect6")->x(), offsetMasterRTL(rootItem, "rect6")-64.0); + + //parent horizontal + QCOMPARE(childItem(rootItem, "rect7")->x(), offsetParentRTL(rootItem, "rect7")-0.0); + QCOMPARE(childItem(rootItem, "rect8")->x(), offsetParentRTL(rootItem, "rect8")-240.0); + QCOMPARE(childItem(rootItem, "rect9")->x(), offsetParentRTL(rootItem, "rect9")-120.0); + QCOMPARE(childItem(rootItem, "rect10")->x(), offsetParentRTL(rootItem, "rect10")+10.0); + QCOMPARE(childItem(rootItem, "rect11")->x(), offsetParentRTL(rootItem, "rect11")-230.0); + QCOMPARE(childItem(rootItem, "rect12")->x(), offsetParentRTL(rootItem, "rect12")-110.0); + + //vertical + QCOMPARE(childItem(rootItem, "rect13")->y(), 20.0); + QCOMPARE(childItem(rootItem, "rect14")->y(), 155.0); + + //stretch + QCOMPARE(childItem(rootItem, "rect15")->x(), offsetMasterRTL(rootItem, "rect15")-26.0); + QCOMPARE(childItem(rootItem, "rect15")->width(), 96.0); + QCOMPARE(childItem(rootItem, "rect16")->x(), offsetMasterRTL(rootItem, "rect16")-26.0); + QCOMPARE(childItem(rootItem, "rect16")->width(), 192.0); + QCOMPARE(childItem(rootItem, "rect17")->x(), offsetMasterRTL(rootItem, "rect17")+70.0); + QCOMPARE(childItem(rootItem, "rect17")->width(), 192.0); + + //vertical stretch + QCOMPARE(childItem(rootItem, "rect18")->y(), 20.0); + QCOMPARE(childItem(rootItem, "rect18")->height(), 40.0); + + //more parent horizontal + QCOMPARE(childItem(rootItem, "rect19")->x(), offsetParentRTL(rootItem, "rect19")-115.0); + QCOMPARE(childItem(rootItem, "rect20")->x(), offsetParentRTL(rootItem, "rect20")-235.0); + QCOMPARE(childItem(rootItem, "rect21")->x(), offsetParentRTL(rootItem, "rect21")+5.0); + + //centerIn + QCOMPARE(childItem(rootItem, "rect22")->x(), offsetMasterRTL(rootItem, "rect22")-69.0); + QCOMPARE(childItem(rootItem, "rect22")->y(), 5.0); + + //margins + QCOMPARE(childItem(rootItem, "rect23")->x(), offsetMasterRTL(rootItem, "rect23")-31.0); + QCOMPARE(childItem(rootItem, "rect23")->y(), 5.0); + QCOMPARE(childItem(rootItem, "rect23")->width(), 86.0); + QCOMPARE(childItem(rootItem, "rect23")->height(), 10.0); + + // offsets + QCOMPARE(childItem(rootItem, "rect24")->x(), offsetMasterRTL(rootItem, "rect24")-26.0); + QCOMPARE(childItem(rootItem, "rect25")->y(), 60.0); + QCOMPARE(childItem(rootItem, "rect26")->y(), 5.0); + + //baseline + QDeclarativeText *text1 = findItem<QDeclarativeText>(rootItem, QLatin1String("text1")); + QDeclarativeText *text2 = findItem<QDeclarativeText>(rootItem, QLatin1String("text2")); + QCOMPARE(text1->y(), text2->y()); + + delete view; +} + // mostly testing that we don't crash void tst_qdeclarativeanchors::loops() { @@ -514,6 +614,31 @@ void tst_qdeclarativeanchors::fill() delete view; } +void tst_qdeclarativeanchors::fillRTL() +{ + QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/fill.qml")); + + qApp->processEvents(); + QDeclarativeRectangle* rect = findItem<QDeclarativeRectangle>(view->rootObject(), QLatin1String("filler")); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 0.0 + 20.0); + QCOMPARE(rect->y(), 0.0 + 30.0); + QCOMPARE(rect->width(), 200.0 - 10.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 30.0 - 40.0); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setLeftMargin(20.0); + rectPrivate->anchors()->setRightMargin(0.0); + rectPrivate->anchors()->setBottomMargin(0.0); + rectPrivate->anchors()->setTopMargin(10.0); + QCOMPARE(rect->x(), 0.0 + 0.0); + QCOMPARE(rect->y(), 0.0 + 10.0); + QCOMPARE(rect->width(), 200.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 10.0); + + delete view; +} void tst_qdeclarativeanchors::centerIn() { QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/centerin.qml")); @@ -521,6 +646,7 @@ void tst_qdeclarativeanchors::centerIn() qApp->processEvents(); QDeclarativeRectangle* rect = findItem<QDeclarativeRectangle>(view->rootObject(), QLatin1String("centered")); QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QCOMPARE(rect->x(), 75.0 + 10); QCOMPARE(rect->y(), 75.0 + 30); //Alter Offsets (tests QTBUG-6631) @@ -532,6 +658,27 @@ void tst_qdeclarativeanchors::centerIn() delete view; } + +void tst_qdeclarativeanchors::centerInRTL() +{ + QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/centerin.qml")); + + qApp->processEvents(); + QDeclarativeRectangle* rect = findItem<QDeclarativeRectangle>(view->rootObject(), QLatin1String("centered")); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 75.0 - 10); + QCOMPARE(rect->y(), 75.0 + 30); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setHorizontalCenterOffset(-20.0); + rectPrivate->anchors()->setVerticalCenterOffset(-10.0); + QCOMPARE(rect->x(), 75.0 + 20.0); + QCOMPARE(rect->y(), 75.0 - 10.0); + + delete view; +} + void tst_qdeclarativeanchors::hvCenter() { QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/hvCenter.qml")); @@ -539,12 +686,39 @@ void tst_qdeclarativeanchors::hvCenter() qApp->processEvents(); QDeclarativeRectangle* rect = findItem<QDeclarativeRectangle>(view->rootObject(), QLatin1String("centered")); QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + // test QTBUG-10999 QCOMPARE(rect->x(), 10.0); QCOMPARE(rect->y(), 19.0); + + rectPrivate->anchors()->setHorizontalCenterOffset(-5.0); + rectPrivate->anchors()->setVerticalCenterOffset(5.0); + QCOMPARE(rect->x(), 10.0 - 5.0); + QCOMPARE(rect->y(), 19.0 + 5.0); + delete view; } +void tst_qdeclarativeanchors::hvCenterRTL() +{ + QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/hvCenter.qml")); + + qApp->processEvents(); + QDeclarativeRectangle* rect = findItem<QDeclarativeRectangle>(view->rootObject(), QLatin1String("centered")); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + mirrorAnchors(rect); + + // test QTBUG-10999 + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 19.0); + + rectPrivate->anchors()->setHorizontalCenterOffset(-5.0); + rectPrivate->anchors()->setVerticalCenterOffset(5.0); + QCOMPARE(rect->x(), 10.0 + 5.0); + QCOMPARE(rect->y(), 19.0 + 5.0); + + delete view; +} void tst_qdeclarativeanchors::margins() { QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/margins.qml")); @@ -568,6 +742,31 @@ void tst_qdeclarativeanchors::margins() delete view; } +void tst_qdeclarativeanchors::marginsRTL() +{ + QDeclarativeView *view = new QDeclarativeView(QUrl::fromLocalFile(SRCDIR "/data/margins.qml")); + + QDeclarativeRectangle* rect = findItem<QDeclarativeRectangle>(view->rootObject(), QLatin1String("filler")); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 6.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 10.0); + QCOMPARE(rect->height(), 200.0 - 6.0 - 10.0); + + rectPrivate->anchors()->setTopMargin(0.0); + rectPrivate->anchors()->setMargins(20.0); + + QCOMPARE(rect->x(), 20.0); + QCOMPARE(rect->y(), 20.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 20.0 - 20.0); + + delete view; +} + + QTEST_MAIN(tst_qdeclarativeanchors) #include "tst_qdeclarativeanchors.moc" diff --git a/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp b/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp index 104ee15..7d1b807 100644 --- a/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp +++ b/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp @@ -46,6 +46,7 @@ #include <private/qdeclarativeimage_p.h> #include <private/qdeclarativeanimatedimage_p.h> #include <QSignalSpy> +#include <QtDeclarative/qdeclarativecontext.h> #include "../shared/testhttpserver.h" #include "../../../shared/util.h" @@ -76,6 +77,7 @@ private slots: void sourceSizeReadOnly(); void invalidSource(); void qtbug_16520(); + void progressAndStatusChanges(); private: QPixmap grabScene(QGraphicsScene *scene, int width, int height); @@ -333,6 +335,53 @@ void tst_qdeclarativeanimatedimage::qtbug_16520() delete anim; } +void tst_qdeclarativeanimatedimage::progressAndStatusChanges() +{ + TestHTTPServer server(14449); + QVERIFY(server.isValid()); + server.serveDirectory(SRCDIR "/data"); + + QDeclarativeEngine engine; + QString componentStr = "import QtQuick 1.0\nAnimatedImage { source: srcImage }"; + QDeclarativeContext *ctxt = engine.rootContext(); + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/stickman.gif")); + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeImage *obj = qobject_cast<QDeclarativeImage*>(component.create()); + QVERIFY(obj != 0); + QVERIFY(obj->status() == QDeclarativeImage::Ready); + QTRY_VERIFY(obj->progress() == 1.0); + + QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &))); + QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal))); + QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QDeclarativeImageBase::Status))); + + // Loading local file + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.gif")); + QTRY_VERIFY(obj->status() == QDeclarativeImage::Ready); + QTRY_VERIFY(obj->progress() == 1.0); + QTRY_COMPARE(sourceSpy.count(), 1); + QTRY_COMPARE(progressSpy.count(), 0); + QTRY_COMPARE(statusSpy.count(), 0); + + // Loading remote file + ctxt->setContextProperty("srcImage", "http://127.0.0.1:14449/stickman.gif"); + QTRY_VERIFY(obj->status() == QDeclarativeImage::Loading); + QTRY_VERIFY(obj->progress() == 0.0); + QTRY_VERIFY(obj->status() == QDeclarativeImage::Ready); + QTRY_VERIFY(obj->progress() == 1.0); + QTRY_COMPARE(sourceSpy.count(), 2); + QTRY_VERIFY(progressSpy.count() > 1); + QTRY_COMPARE(statusSpy.count(), 2); + + ctxt->setContextProperty("srcImage", ""); + QTRY_VERIFY(obj->status() == QDeclarativeImage::Null); + QTRY_VERIFY(obj->progress() == 0.0); + QTRY_COMPARE(sourceSpy.count(), 3); + QTRY_VERIFY(progressSpy.count() > 2); + QTRY_COMPARE(statusSpy.count(), 3); +} + QTEST_MAIN(tst_qdeclarativeanimatedimage) #include "tst_qdeclarativeanimatedimage.moc" diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/writeAttachedProperty.qml b/tests/auto/declarative/qdeclarativeecmascript/data/writeAttachedProperty.qml new file mode 100644 index 0000000..31bf69d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/writeAttachedProperty.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +QtObject { + function writeValue2() { MyQmlObject.value2 = 9 } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 40b0e1b..48466d5 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -639,15 +639,29 @@ void tst_qdeclarativeecmascript::overrideExtensionProperties() void tst_qdeclarativeecmascript::attachedProperties() { - QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); - QCOMPARE(object->property("a").toInt(), 19); - QCOMPARE(object->property("b").toInt(), 19); - QCOMPARE(object->property("c").toInt(), 19); - QCOMPARE(object->property("d").toInt(), 19); + { + QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("a").toInt(), 19); + QCOMPARE(object->property("b").toInt(), 19); + QCOMPARE(object->property("c").toInt(), 19); + QCOMPARE(object->property("d").toInt(), 19); + } - // ### Need to test attached property assignment + { + QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QMetaObject::invokeMethod(object, "writeValue2"); + + MyQmlAttachedObject *attached = + qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object)); + QVERIFY(attached != 0); + + QCOMPARE(attached->value2(), 9); + } } void tst_qdeclarativeecmascript::enums() diff --git a/tests/auto/declarative/qdeclarativeflickable/data/disabledcontent.qml b/tests/auto/declarative/qdeclarativeflickable/data/disabledcontent.qml new file mode 100644 index 0000000..dcbb20b --- /dev/null +++ b/tests/auto/declarative/qdeclarativeflickable/data/disabledcontent.qml @@ -0,0 +1,8 @@ +import QtQuick 1.0 + +Flickable { + width: 100; height: 100 + contentWidth: 200; contentHeight: 300 + + QGraphicsWidget { width: 200; height: 300; enabled: false } +} diff --git a/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp b/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp index 736f8f4..d499edf 100644 --- a/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp +++ b/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp @@ -69,6 +69,7 @@ private slots: void maximumFlickVelocity(); void flickDeceleration(); void pressDelay(); + void disabledContent(); void nestedPressDelay(); void flickableDirection(); void qgraphicswidget(); @@ -247,6 +248,44 @@ void tst_qdeclarativeflickable::pressDelay() QCOMPARE(spy.count(),1); } +// QT-4677 +void tst_qdeclarativeflickable::disabledContent() +{ + QDeclarativeView *canvas = new QDeclarativeView; + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabledcontent.qml")); + canvas->show(); + canvas->setFocus(); + QVERIFY(canvas->rootObject() != 0); + + QDeclarativeFlickable *flickable = qobject_cast<QDeclarativeFlickable*>(canvas->rootObject()); + QVERIFY(flickable != 0); + + QVERIFY(flickable->contentX() == 0); + QVERIFY(flickable->contentY() == 0); + + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 50))); + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(70,70)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(90,90)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(100,100)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + + QVERIFY(flickable->contentX() < 0); + QVERIFY(flickable->contentY() < 0); + + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(90, 90))); + + delete canvas; +} + + // QTBUG-17361 void tst_qdeclarativeflickable::nestedPressDelay() { @@ -267,8 +306,8 @@ void tst_qdeclarativeflickable::nestedPressDelay() QVERIFY(outer->property("pressed").toBool() == false); // The outer pressDelay will prevail (50ms, vs. 10sec) - QTest::qWait(300); - QVERIFY(outer->property("pressed").toBool() == true); + // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec. + QTRY_VERIFY(outer->property("pressed").toBool() == true); QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150))); diff --git a/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp b/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp index a62ea31..ffd5d38 100644 --- a/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp +++ b/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp @@ -62,14 +62,24 @@ class tst_qdeclarativefolderlistmodel : public QObject { Q_OBJECT public: - tst_qdeclarativefolderlistmodel() {} + tst_qdeclarativefolderlistmodel() : removeStart(0), removeEnd(0) {} + +public slots: + void removed(const QModelIndex &, int start, int end) { + removeStart = start; + removeEnd = end; + } private slots: void basicProperties(); + void refresh(); private: void checkNoErrors(const QDeclarativeComponent& component); QDeclarativeEngine engine; + + int removeStart; + int removeEnd; }; void tst_qdeclarativefolderlistmodel::checkNoErrors(const QDeclarativeComponent& component) @@ -115,6 +125,28 @@ void tst_qdeclarativefolderlistmodel::basicProperties() QCOMPARE(flm->property("folder").toUrl(), QUrl::fromLocalFile("")); } +void tst_qdeclarativefolderlistmodel::refresh() +{ + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/basic.qml")); + checkNoErrors(component); + + QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create()); + QVERIFY(flm != 0); + + flm->setProperty("folder",QUrl::fromLocalFile(SRCDIR "/data")); + QTRY_COMPARE(flm->property("count").toInt(),2); // wait for refresh + + int count = flm->rowCount(); + + connect(flm, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), + this, SLOT(removed(const QModelIndex&,int,int))); + + flm->setProperty("sortReversed", true); + + QCOMPARE(removeStart, 0); + QCOMPARE(removeEnd, count-1); +} + QTEST_MAIN(tst_qdeclarativefolderlistmodel) #include "tst_qdeclarativefolderlistmodel.moc" diff --git a/tests/auto/declarative/qdeclarativegridview/data/gridview-enforcerange.qml b/tests/auto/declarative/qdeclarativegridview/data/gridview-enforcerange.qml index 5719f43..69eaa47 100644 --- a/tests/auto/declarative/qdeclarativegridview/data/gridview-enforcerange.qml +++ b/tests/auto/declarative/qdeclarativegridview/data/gridview-enforcerange.qml @@ -1,4 +1,4 @@ -import QtQuick 1.0 +import QtQuick 1.1 Rectangle { width: 240 @@ -48,6 +48,8 @@ Rectangle { model: testModel delegate: myDelegate highlight: myHighlight + flow: (testTopToBottom == true) ? GridView.TopToBottom : GridView.LeftToRight + layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight preferredHighlightBegin: 100 preferredHighlightEnd: 100 highlightRangeMode: "StrictlyEnforceRange" diff --git a/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml b/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml index e4e699c..caa28d6 100644 --- a/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml +++ b/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml @@ -1,4 +1,4 @@ -import QtQuick 1.0 +import QtQuick 1.1 Rectangle { id: root @@ -55,7 +55,8 @@ Rectangle { height: 320 cellWidth: 80 cellHeight: 60 - flow: (testTopToBottom == false) ? "LeftToRight" : "TopToBottom" + flow: (testTopToBottom == false) ? GridView.LeftToRight : GridView.TopToBottom + layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight model: testModel delegate: myDelegate header: root.showHeader ? headerFooter : null diff --git a/tests/auto/declarative/qdeclarativegridview/data/mirroring.qml b/tests/auto/declarative/qdeclarativegridview/data/mirroring.qml new file mode 100644 index 0000000..54de16b --- /dev/null +++ b/tests/auto/declarative/qdeclarativegridview/data/mirroring.qml @@ -0,0 +1,43 @@ +// This example demonstrates how item positioning +// changes in right-to-left layout direction + +import QtQuick 1.1 + +Rectangle { + color: "lightgray" + width: 340 + height: 370 + + VisualItemModel { + id: itemModel + objectName: "itemModel" + Rectangle { + objectName: "item1" + height: 110; width: 120; color: "#FFFEF0" + Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item2" + height: 130; width: 150; color: "#F0FFF7" + Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item3" + height: 170; width: 190; color: "#F4F0FF" + Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + } + + GridView { + id: view + objectName: "view" + cellWidth: 190 + cellHeight: 170 + anchors.fill: parent + anchors.bottomMargin: 30 + model: itemModel + highlightRangeMode: "StrictlyEnforceRange" + flow: GridView.TopToBottom + flickDeceleration: 2000 + } +} diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp index 79189a7..c183934 100644 --- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp +++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp @@ -46,6 +46,7 @@ #include <QtDeclarative/qdeclarativecomponent.h> #include <QtDeclarative/qdeclarativecontext.h> #include <QtDeclarative/qdeclarativeexpression.h> +#include <QtDeclarative/private/qdeclarativeitem_p.h> #include <QtDeclarative/private/qlistmodelinterface_p.h> #include <QtDeclarative/private/qdeclarativegridview_p.h> #include <QtDeclarative/private/qdeclarativetext_p.h> @@ -68,6 +69,7 @@ private slots: void changed(); void inserted(); void removed(); + void clear(); void moved(); void changeFlow(); void currentIndex(); @@ -78,9 +80,12 @@ private slots: void componentChanges(); void modelChanges(); void positionViewAtIndex(); + void positionViewAtIndex_rightToLeft(); + void mirroring(); void snapping(); void resetModel(); void enforceRange(); + void enforceRange_rightToLeft(); void QTBUG_8456(); void manualHighlight(); void footer(); @@ -203,6 +208,7 @@ void tst_QDeclarativeGridView::items() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -251,6 +257,7 @@ void tst_QDeclarativeGridView::changed() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -284,6 +291,7 @@ void tst_QDeclarativeGridView::inserted() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -360,6 +368,7 @@ void tst_QDeclarativeGridView::removed() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -493,6 +502,44 @@ void tst_QDeclarativeGridView::removed() delete canvas; } +void tst_QDeclarativeGridView::clear() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); + qApp->processEvents(); + + QDeclarativeGridView *gridview = findItem<QDeclarativeGridView>(canvas->rootObject(), "grid"); + QVERIFY(gridview != 0); + + QDeclarativeItem *contentItem = gridview->contentItem(); + QVERIFY(contentItem != 0); + + model.clear(); + + QVERIFY(gridview->count() == 0); + QVERIFY(gridview->currentItem() == 0); + QVERIFY(gridview->contentY() == 0); + QVERIFY(gridview->currentIndex() == -1); + + // confirm sanity when adding an item to cleared list + model.addItem("New", "1"); + QVERIFY(gridview->count() == 1); + QVERIFY(gridview->currentItem() != 0); + QVERIFY(gridview->currentIndex() == 0); + + delete canvas; +} + void tst_QDeclarativeGridView::moved() { QDeclarativeView *canvas = createView(); @@ -503,6 +550,7 @@ void tst_QDeclarativeGridView::moved() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -726,6 +774,58 @@ void tst_QDeclarativeGridView::currentIndex() QVERIFY(!gridview->highlightItem()); QVERIFY(!gridview->currentItem()); + gridview->setHighlightFollowsCurrentItem(true); + + gridview->setFlow(QDeclarativeGridView::LeftToRight); + gridview->setLayoutDirection(Qt::RightToLeft); + + qApp->setActiveWindow(canvas); +#ifdef Q_WS_X11 + // to be safe and avoid failing setFocus with window managers + qt_x11_wait_for_window_manager(canvas); +#endif + QTRY_VERIFY(canvas->hasFocus()); + QTRY_VERIFY(canvas->scene()->hasFocus()); + qApp->processEvents(); + + gridview->setCurrentIndex(35); + + QTest::keyClick(canvas, Qt::Key_Right); + QCOMPARE(gridview->currentIndex(), 34); + + QTest::keyClick(canvas, Qt::Key_Down); + QCOMPARE(gridview->currentIndex(), 37); + + QTest::keyClick(canvas, Qt::Key_Up); + QCOMPARE(gridview->currentIndex(), 34); + + QTest::keyClick(canvas, Qt::Key_Left); + QCOMPARE(gridview->currentIndex(), 35); + + + // turn off auto highlight + gridview->setHighlightFollowsCurrentItem(false); + QVERIFY(gridview->highlightFollowsCurrentItem() == false); + QVERIFY(gridview->highlightItem()); + hlPosX = gridview->highlightItem()->x(); + hlPosY = gridview->highlightItem()->y(); + + gridview->setCurrentIndex(5); + QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX); + QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY); + + // insert item before currentIndex + gridview->setCurrentIndex(28); + model.insertItem(0, "Foo", "1111"); + QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29); + + // check removing highlight by setting currentIndex to -1; + gridview->setCurrentIndex(-1); + + QCOMPARE(gridview->currentIndex(), -1); + QVERIFY(!gridview->highlightItem()); + QVERIFY(!gridview->currentItem()); + delete canvas; } @@ -774,6 +874,7 @@ void tst_QDeclarativeGridView::changeFlow() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -819,6 +920,44 @@ void tst_QDeclarativeGridView::changeFlow() QTRY_COMPARE(number->text(), model.number(i)); } + ctxt->setContextProperty("testRightToLeft", QVariant(true)); + + // Confirm items positioned correctly and indexes correct + itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width())); + QTRY_COMPARE(item->y(), qreal((i%5)*60)); + QDeclarativeText *name = findItem<QDeclarativeText>(contentItem, "textName", i); + QTRY_VERIFY(name != 0); + QTRY_COMPARE(name->text(), model.name(i)); + QDeclarativeText *number = findItem<QDeclarativeText>(contentItem, "textNumber", i); + QTRY_VERIFY(number != 0); + QTRY_COMPARE(number->text(), model.number(i)); + } + gridview->setContentX(100); + QTRY_COMPARE(gridview->contentX(), 100.); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + QTRY_COMPARE(gridview->contentX(), 0.); + + // Confirm items positioned correctly and indexes correct + itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80)); + QTRY_COMPARE(item->y(), qreal((i/3)*60)); + QDeclarativeText *name = findItem<QDeclarativeText>(contentItem, "textName", i); + QTRY_VERIFY(name != 0); + QTRY_COMPARE(name->text(), model.name(i)); + QDeclarativeText *number = findItem<QDeclarativeText>(contentItem, "textNumber", i); + QTRY_VERIFY(number != 0); + QTRY_COMPARE(number->text(), model.number(i)); + } + delete canvas; } @@ -879,6 +1018,7 @@ void tst_QDeclarativeGridView::propertyChanges() QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged())); QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged())); + QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged())); QSignalSpy flowSpy(gridView, SIGNAL(flowChanged())); QTRY_COMPARE(gridView->isWrapEnabled(), true); @@ -905,6 +1045,38 @@ void tst_QDeclarativeGridView::propertyChanges() QTRY_COMPARE(cacheBufferSpy.count(),1); QTRY_COMPARE(flowSpy.count(),1); + gridView->setFlow(QDeclarativeGridView::LeftToRight); + QTRY_COMPARE(gridView->flow(), QDeclarativeGridView::LeftToRight); + + gridView->setWrapEnabled(true); + gridView->setCacheBuffer(5); + gridView->setLayoutDirection(Qt::RightToLeft); + + QTRY_COMPARE(gridView->isWrapEnabled(), true); + QTRY_COMPARE(gridView->cacheBuffer(), 5); + QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft); + + QTRY_COMPARE(keyNavigationWrapsSpy.count(),2); + QTRY_COMPARE(cacheBufferSpy.count(),2); + QTRY_COMPARE(layoutSpy.count(),1); + QTRY_COMPARE(flowSpy.count(),2); + + gridView->setWrapEnabled(true); + gridView->setCacheBuffer(5); + gridView->setLayoutDirection(Qt::RightToLeft); + + QTRY_COMPARE(keyNavigationWrapsSpy.count(),2); + QTRY_COMPARE(cacheBufferSpy.count(),2); + QTRY_COMPARE(layoutSpy.count(),1); + QTRY_COMPARE(flowSpy.count(),2); + + gridView->setFlow(QDeclarativeGridView::TopToBottom); + QTRY_COMPARE(gridView->flow(), QDeclarativeGridView::TopToBottom); + QTRY_COMPARE(flowSpy.count(),3); + + gridView->setFlow(QDeclarativeGridView::TopToBottom); + QTRY_COMPARE(flowSpy.count(),3); + delete canvas; } @@ -992,6 +1164,7 @@ void tst_QDeclarativeGridView::positionViewAtIndex() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); @@ -1185,6 +1358,7 @@ void tst_QDeclarativeGridView::snapping() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); ctxt->setContextProperty("testTopToBottom", QVariant(false)); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); qApp->processEvents(); @@ -1211,6 +1385,200 @@ void tst_QDeclarativeGridView::snapping() QCOMPARE(gridview->contentY(), 120.); delete canvas; + +} + +void tst_QDeclarativeGridView::mirroring() +{ + QDeclarativeView *canvasA = createView(); + canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml")); + QDeclarativeGridView *gridviewA = findItem<QDeclarativeGridView>(canvasA->rootObject(), "view"); + QTRY_VERIFY(gridviewA != 0); + + QDeclarativeView *canvasB = createView(); + canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml")); + QDeclarativeGridView *gridviewB = findItem<QDeclarativeGridView>(canvasB->rootObject(), "view"); + QTRY_VERIFY(gridviewA != 0); + qApp->processEvents(); + + QList<QString> objectNames; + objectNames << "item1" << "item2"; // << "item3" + + gridviewA->setProperty("layoutDirection", Qt::LeftToRight); + gridviewB->setProperty("layoutDirection", Qt::RightToLeft); + QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection()); + + // LTR != RTL + foreach(const QString objectName, objectNames) + QVERIFY(findItem<QDeclarativeItem>(gridviewA, objectName)->x() != findItem<QDeclarativeItem>(gridviewB, objectName)->x()); + + gridviewA->setProperty("layoutDirection", Qt::LeftToRight); + gridviewB->setProperty("layoutDirection", Qt::LeftToRight); + + // LTR == LTR + foreach(const QString objectName, objectNames) + QCOMPARE(findItem<QDeclarativeItem>(gridviewA, objectName)->x(), findItem<QDeclarativeItem>(gridviewB, objectName)->x()); + + QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection()); + QDeclarativeItemPrivate::get(gridviewB)->setLayoutMirror(true); + QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection()); + + // LTR != LTR+mirror + foreach(const QString objectName, objectNames) + QVERIFY(findItem<QDeclarativeItem>(gridviewA, objectName)->x() != findItem<QDeclarativeItem>(gridviewB, objectName)->x()); + + gridviewA->setProperty("layoutDirection", Qt::RightToLeft); + + // RTL == LTR+mirror + foreach(const QString objectName, objectNames) + QCOMPARE(findItem<QDeclarativeItem>(gridviewA, objectName)->x(), findItem<QDeclarativeItem>(gridviewB, objectName)->x()); + + gridviewB->setProperty("layoutDirection", Qt::RightToLeft); + + // RTL != RTL+mirror + foreach(const QString objectName, objectNames) + QVERIFY(findItem<QDeclarativeItem>(gridviewA, objectName)->x() != findItem<QDeclarativeItem>(gridviewB, objectName)->x()); + + gridviewA->setProperty("layoutDirection", Qt::LeftToRight); + + // LTR == RTL+mirror + foreach(const QString objectName, objectNames) + QCOMPARE(findItem<QDeclarativeItem>(gridviewA, objectName)->x(), findItem<QDeclarativeItem>(gridviewB, objectName)->x()); + + delete canvasA; + delete canvasB; +} + +void tst_QDeclarativeGridView::positionViewAtIndex_rightToLeft() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 40; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testTopToBottom", QVariant(true)); + ctxt->setContextProperty("testRightToLeft", QVariant(true)); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); + qApp->processEvents(); + + QDeclarativeGridView *gridview = findItem<QDeclarativeGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + + QDeclarativeItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + // Confirm items positioned correctly + int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount-1; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width())); + QTRY_COMPARE(item->y(), qreal((i%5)*60)); + } + + // Position on a currently visible item + gridview->positionViewAtIndex(6, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->contentX(), -320.); + + // Confirm items positioned correctly + itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width())); + QTRY_COMPARE(item->y(), qreal((i%5)*60)); + } + + // Position on an item beyond the visible items + gridview->positionViewAtIndex(21, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->contentX(), -560.); + + // Confirm items positioned correctly + itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width())); + QTRY_COMPARE(item->y(), qreal((i%5)*60)); + } + + // Position on an item that would leave empty space if positioned at the top + gridview->positionViewAtIndex(31, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->contentX(), -639.); + + // Confirm items positioned correctly + itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width())); + QTRY_COMPARE(item->y(), qreal((i%5)*60)); + } + + // Position at the beginning again + gridview->positionViewAtIndex(0, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->contentX(), -240.); + + // Confirm items positioned correctly + itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount-1; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width())); + QTRY_COMPARE(item->y(), qreal((i%5)*60)); + } + + // Position at End + gridview->positionViewAtIndex(30, QDeclarativeGridView::End); + QTRY_COMPARE(gridview->contentX(), -560.); + + // Position in Center + gridview->positionViewAtIndex(15, QDeclarativeGridView::Center); + QTRY_COMPARE(gridview->contentX(), -400.); + + // Ensure at least partially visible + gridview->positionViewAtIndex(15, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), -400.); + + gridview->setContentX(-555.); + gridview->positionViewAtIndex(15, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), -555.); + + gridview->setContentX(-239); + gridview->positionViewAtIndex(15, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), -320.); + + gridview->setContentX(-239); + gridview->positionViewAtIndex(20, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), -400.); + + gridview->setContentX(-640); + gridview->positionViewAtIndex(20, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), -560.); + + // Ensure completely visible + gridview->setContentX(-400); + gridview->positionViewAtIndex(20, QDeclarativeGridView::Contain); + QTRY_COMPARE(gridview->contentX(), -400.); + + gridview->setContentX(-315); + gridview->positionViewAtIndex(15, QDeclarativeGridView::Contain); + QTRY_COMPARE(gridview->contentX(), -320.); + + gridview->setContentX(-640); + gridview->positionViewAtIndex(20, QDeclarativeGridView::Contain); + QTRY_COMPARE(gridview->contentX(), -560.); + + delete canvas; } void tst_QDeclarativeGridView::resetModel() @@ -1264,9 +1632,12 @@ void tst_QDeclarativeGridView::enforceRange() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml")); qApp->processEvents(); + QVERIFY(canvas->rootObject() != 0); QDeclarativeGridView *gridview = findItem<QDeclarativeGridView>(canvas->rootObject(), "grid"); QTRY_VERIFY(gridview != 0); @@ -1307,6 +1678,64 @@ void tst_QDeclarativeGridView::enforceRange() delete canvas; } +void tst_QDeclarativeGridView::enforceRange_rightToLeft() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(true)); + ctxt->setContextProperty("testTopToBottom", QVariant(true)); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml")); + qApp->processEvents(); + QVERIFY(canvas->rootObject() != 0); + + QDeclarativeGridView *gridview = findItem<QDeclarativeGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + + QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0); + QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0); + QTRY_COMPARE(gridview->highlightRangeMode(), QDeclarativeGridView::StrictlyEnforceRange); + + QDeclarativeItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + // view should be positioned at the top of the range. + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", 0); + QTRY_VERIFY(item); + QTRY_COMPARE(gridview->contentX(), -100.); + QTRY_COMPARE(gridview->contentY(), 0.0); + + QDeclarativeText *name = findItem<QDeclarativeText>(contentItem, "textName", 0); + QTRY_VERIFY(name != 0); + QTRY_COMPARE(name->text(), model.name(0)); + QDeclarativeText *number = findItem<QDeclarativeText>(contentItem, "textNumber", 0); + QTRY_VERIFY(number != 0); + QTRY_COMPARE(number->text(), model.number(0)); + + // Check currentIndex is updated when contentItem moves + gridview->setContentX(-200); + QTRY_COMPARE(gridview->currentIndex(), 3); + + gridview->setCurrentIndex(7); + QTRY_COMPARE(gridview->contentX(), -300.); + QTRY_COMPARE(gridview->contentY(), 0.0); + + TestModel model2; + for (int i = 0; i < 5; i++) + model2.addItem("Item" + QString::number(i), ""); + + ctxt->setContextProperty("testModel", &model2); + QCOMPARE(gridview->count(), 5); + + delete canvas; +} + void tst_QDeclarativeGridView::QTBUG_8456() { QDeclarativeView *canvas = createView(); @@ -1475,6 +1904,7 @@ void tst_QDeclarativeGridView::indexAt() QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); ctxt->setContextProperty("testTopToBottom", QVariant(false)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); diff --git a/tests/auto/declarative/qdeclarativeimage/data/qtbug_16389.qml b/tests/auto/declarative/qdeclarativeimage/data/qtbug_16389.qml new file mode 100644 index 0000000..29fba40 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeimage/data/qtbug_16389.qml @@ -0,0 +1,30 @@ +import QtQuick 1.0 +Rectangle { + width: 400 + height: 400 + + Item { + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: blueHandle.top + anchors.right: blueHandle.left + + Image { + id: iconImage + objectName: "iconImage" + anchors.top: parent.top + anchors.bottom: parent.bottom + source: "heart200.png" + fillMode: Image.PreserveAspectFit + smooth: true + } + } + + Rectangle { + id: blueHandle + objectName: "blueHandle" + color: "blue" + width: 25 + height: 25 + } +} diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp index f1fe2bd..9e090d2 100644 --- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp +++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp @@ -89,6 +89,7 @@ private slots: void noLoading(); void paintedWidthHeight(); void sourceSize_QTBUG_14303(); + void sourceSize_QTBUG_16389(); void nullPixmapPaint(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); @@ -640,6 +641,29 @@ void tst_qdeclarativeimage::sourceSize_QTBUG_14303() QTRY_COMPARE(sourceSizeSpy.count(), 2); } +void tst_qdeclarativeimage::sourceSize_QTBUG_16389() +{ + QDeclarativeView *canvas = new QDeclarativeView(0); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug_16389.qml")); + canvas->show(); + qApp->processEvents(); + + QDeclarativeImage *image = findItem<QDeclarativeImage>(canvas->rootObject(), "iconImage"); + QDeclarativeItem *handle = findItem<QDeclarativeItem>(canvas->rootObject(), "blueHandle"); + + QCOMPARE(image->sourceSize().width(), 200); + QCOMPARE(image->sourceSize().height(), 200); + QCOMPARE(image->paintedWidth(), 0.0); + QCOMPARE(image->paintedHeight(), 0.0); + + handle->setY(20); + + QCOMPARE(image->sourceSize().width(), 200); + QCOMPARE(image->sourceSize().height(), 200); + QCOMPARE(image->paintedWidth(), 20.0); + QCOMPARE(image->paintedHeight(), 20.0); +} + static int numberOfWarnings = 0; static void checkWarnings(QtMsgType, const char *) { diff --git a/tests/auto/declarative/qdeclarativeitem/data/layoutmirroring.qml b/tests/auto/declarative/qdeclarativeitem/data/layoutmirroring.qml new file mode 100644 index 0000000..866b615 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeitem/data/layoutmirroring.qml @@ -0,0 +1,54 @@ +import QtQuick 1.1 + +Item { + property bool childrenInherit: true + Item { + objectName: "mirrored1" + LayoutMirroring.enabled: true + LayoutMirroring.childrenInherit: parent.childrenInherit + Item { + Item { + objectName: "notMirrored1" + LayoutMirroring.enabled: false + Item { + objectName: "inheritedMirror1" + } + } + Item { + objectName: "inheritedMirror2" + } + } + } + Item { + objectName: "mirrored2" + LayoutMirroring.enabled: true + LayoutMirroring.childrenInherit: false + Item { + objectName: "notMirrored2" + } + } + Item { + LayoutMirroring.enabled: true + LayoutMirroring.childrenInherit: true + Loader { + id: loader + } + } + states: State { + name: "newContent" + PropertyChanges { + target: loader + sourceComponent: component + } + } + Component { + id: component + Item { + objectName: "notMirrored3" + LayoutMirroring.enabled: false + Item { + objectName: "inheritedMirror3" + } + } + } +} diff --git a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp index 137522d..52c9a72 100644 --- a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp +++ b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp @@ -65,7 +65,10 @@ private slots: void keys(); void keysProcessingOrder(); void keyNavigation(); + void keyNavigation_RightToLeft(); void keyNavigation_skipNotVisible(); + void layoutMirroring(); + void layoutMirroringIllegalParent(); void smooth(); void clip(); void mapCoordinates(); @@ -87,13 +90,33 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); void qtbug_16871(); - private: - template<typename T> - T *findItem(QGraphicsObject *parent, const QString &objectName); QDeclarativeEngine engine; }; +template<typename T> +T *findItem(QGraphicsObject *parent, const QString &objectName) +{ + if (!parent) + return 0; + + const QMetaObject &mo = T::staticMetaObject; + //qDebug() << parent->QGraphicsObject::children().count() << "children"; + for (int i = 0; i < parent->childItems().count(); ++i) { + QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i)); + if(!item) + continue; + //qDebug() << "try" << item; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) + return static_cast<T*>(item); + item = findItem<T>(item, objectName); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + class KeysTestObject : public QObject { Q_OBJECT @@ -380,6 +403,165 @@ void tst_QDeclarativeItem::keysProcessingOrder() delete testObject; } +QDeclarativeItemPrivate *childPrivate(QGraphicsObject *rootItem, const char * itemString) +{ + QDeclarativeItem *item = findItem<QDeclarativeItem>(rootItem, QString(QLatin1String(itemString))); + QDeclarativeItemPrivate* itemPrivate = QDeclarativeItemPrivate::get(item); + return itemPrivate; +} + +QVariant childProperty(QGraphicsObject *rootItem, const char * itemString, const char * property) +{ + QDeclarativeItem *item = findItem<QDeclarativeItem>(rootItem, QString(QLatin1String(itemString))); + return item->property(property); +} + +bool anchorsMirrored(QGraphicsObject *rootItem, const char * itemString) +{ + QDeclarativeItem *item = findItem<QDeclarativeItem>(rootItem, QString(QLatin1String(itemString))); + QDeclarativeItemPrivate* itemPrivate = QDeclarativeItemPrivate::get(item); + return itemPrivate->anchors()->mirrored(); +} + +void tst_QDeclarativeItem::layoutMirroring() +{ + QDeclarativeView *canvas = new QDeclarativeView(0); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/layoutmirroring.qml")); + canvas->show(); + + QDeclarativeItem *rootItem = qobject_cast<QDeclarativeItem*>(canvas->rootObject()); + QVERIFY(rootItem); + QDeclarativeItemPrivate *rootPrivate = QDeclarativeItemPrivate::get(rootItem); + QVERIFY(rootPrivate); + + QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true); + + QCOMPARE(anchorsMirrored(rootItem, "mirrored1"), true); + QCOMPARE(anchorsMirrored(rootItem, "mirrored2"), true); + QCOMPARE(anchorsMirrored(rootItem, "notMirrored1"), false); + QCOMPARE(anchorsMirrored(rootItem, "notMirrored2"), false); + QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror1"), true); + QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror2"), true); + + QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true); + + QCOMPARE(childPrivate(rootItem, "mirrored1")->isMirrorImplicit, false); + QCOMPARE(childPrivate(rootItem, "mirrored2")->isMirrorImplicit, false); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->isMirrorImplicit, false); + QCOMPARE(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit, true); + + QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent, true); + QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent, false); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent, true); + QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent, true); + + QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem, true); + QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem, false); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem, false); + QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem, false); + + // load dynamic content using Loader that needs to inherit mirroring + rootItem->setProperty("state", "newContent"); + QCOMPARE(childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror, true); + + QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror, true); + + QCOMPARE(childPrivate(rootItem, "notMirrored3")->isMirrorImplicit, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit, true); + + QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent, true); + + QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false); + QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false); + + // disable inheritance + rootItem->setProperty("childrenInherit", false); + + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false); + + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, false); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, false); + + // re-enable inheritance + rootItem->setProperty("childrenInherit", true); + + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false); + + QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true); + QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true); + + // + // dynamic parenting + // + QDeclarativeItem *parentItem1 = new QDeclarativeItem(); + QDeclarativeItemPrivate::get(parentItem1)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true + QDeclarativeItemPrivate::get(parentItem1)->isMirrorImplicit = false; + QDeclarativeItemPrivate::get(parentItem1)->inheritMirrorFromItem = true; // LayoutMirroring.childrenInherit: true + QDeclarativeItemPrivate::get(parentItem1)->resolveLayoutMirror(); + + // inherit in constructor + QDeclarativeItem *childItem1 = new QDeclarativeItem(parentItem1); + QCOMPARE(QDeclarativeItemPrivate::get(childItem1)->effectiveLayoutMirror, true); + QCOMPARE(QDeclarativeItemPrivate::get(childItem1)->inheritMirrorFromParent, true); + + // inherit through a parent change + QDeclarativeItem *childItem2 = new QDeclarativeItem(); + QCOMPARE(QDeclarativeItemPrivate::get(childItem2)->effectiveLayoutMirror, false); + QCOMPARE(QDeclarativeItemPrivate::get(childItem2)->inheritMirrorFromParent, false); + childItem2->setParentItem(parentItem1); + QCOMPARE(QDeclarativeItemPrivate::get(childItem2)->effectiveLayoutMirror, true); + QCOMPARE(QDeclarativeItemPrivate::get(childItem2)->inheritMirrorFromParent, true); + + // stop inherting through a parent change + QDeclarativeItem *parentItem2 = new QDeclarativeItem(); + QDeclarativeItemPrivate::get(parentItem2)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true + QDeclarativeItemPrivate::get(parentItem2)->resolveLayoutMirror(); + childItem2->setParentItem(parentItem2); + QCOMPARE(QDeclarativeItemPrivate::get(childItem2)->effectiveLayoutMirror, false); + QCOMPARE(QDeclarativeItemPrivate::get(childItem2)->inheritMirrorFromParent, false); + + delete parentItem1; + delete parentItem2; +} + +void tst_QDeclarativeItem::layoutMirroringIllegalParent() +{ + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.1; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile("")); + QTest::ignoreMessage(QtWarningMsg, "file::1:21: QML QtObject: LayoutDirection attached property only works with Items"); + QObject *object = component.create(); + QVERIFY(object != 0); +} + void tst_QDeclarativeItem::keyNavigation() { QDeclarativeView *canvas = new QDeclarativeView(0); @@ -460,6 +642,59 @@ void tst_QDeclarativeItem::keyNavigation() delete canvas; } +void tst_QDeclarativeItem::keyNavigation_RightToLeft() +{ + QDeclarativeView *canvas = new QDeclarativeView(0); + canvas->setFixedSize(240,320); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest.qml")); + canvas->show(); + qApp->processEvents(); + + QDeclarativeItem *rootItem = qobject_cast<QDeclarativeItem*>(canvas->rootObject()); + QVERIFY(rootItem); + QDeclarativeItemPrivate* rootItemPrivate = QDeclarativeItemPrivate::get(rootItem); + + rootItemPrivate->effectiveLayoutMirror = true; // LayoutMirroring.mirror: true + rootItemPrivate->isMirrorImplicit = false; + rootItemPrivate->inheritMirrorFromItem = true; // LayoutMirroring.inherit: true + rootItemPrivate->resolveLayoutMirror(); + + QEvent wa(QEvent::WindowActivate); + QApplication::sendEvent(canvas, &wa); + QFocusEvent fe(QEvent::FocusIn); + QApplication::sendEvent(canvas, &fe); + + QDeclarativeItem *item = findItem<QDeclarativeItem>(canvas->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + QVariant result; + QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "verify", + Q_RETURN_ARG(QVariant, result))); + QVERIFY(result.toBool()); + + // right + QKeyEvent key(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem<QDeclarativeItem>(canvas->rootObject(), "item2"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // left + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem<QDeclarativeItem>(canvas->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + delete canvas; +} + void tst_QDeclarativeItem::keyNavigation_skipNotVisible() { QDeclarativeView *canvas = new QDeclarativeView(0); @@ -1003,32 +1238,6 @@ void tst_QDeclarativeItem::qtbug_16871() delete o; } - -template<typename T> -T *tst_QDeclarativeItem::findItem(QGraphicsObject *parent, const QString &objectName) -{ - if (!parent) - return 0; - - const QMetaObject &mo = T::staticMetaObject; - //qDebug() << parent->QGraphicsObject::children().count() << "children"; - for (int i = 0; i < parent->childItems().count(); ++i) { - QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i)); - if(!item) - continue; - //qDebug() << "try" << item; - if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) - return static_cast<T*>(item); - item = findItem<T>(item, objectName); - if (item) - return static_cast<T*>(item); - } - - return 0; -} - - - QTEST_MAIN(tst_QDeclarativeItem) #include "tst_qdeclarativeitem.moc" diff --git a/tests/auto/declarative/qdeclarativelanguage/data/InlineAssignmentsOverrideBindingsType.qml b/tests/auto/declarative/qdeclarativelanguage/data/InlineAssignmentsOverrideBindingsType.qml new file mode 100644 index 0000000..4526cf0 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/InlineAssignmentsOverrideBindingsType.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +QtObject { + property InlineAssignmentsOverrideBindingsType2 nested: InlineAssignmentsOverrideBindingsType2 { + value: 19 * 33 + } +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/InlineAssignmentsOverrideBindingsType2.qml b/tests/auto/declarative/qdeclarativelanguage/data/InlineAssignmentsOverrideBindingsType2.qml new file mode 100644 index 0000000..4127ca4 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/InlineAssignmentsOverrideBindingsType2.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 + +QtObject { + property int value +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/inlineAssignmentsOverrideBindings.qml b/tests/auto/declarative/qdeclarativelanguage/data/inlineAssignmentsOverrideBindings.qml new file mode 100644 index 0000000..8f3c5ce --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/inlineAssignmentsOverrideBindings.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 + +InlineAssignmentsOverrideBindingsType { + property int test: nested.value + nested.value: 11 +} diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index f3f41a9..5a2591f 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -134,6 +134,7 @@ private slots: void dontDoubleCallClassBegin(); void reservedWords_data(); void reservedWords(); + void inlineAssignmentsOverrideBindings(); void basicRemote_data(); void basicRemote(); @@ -1413,9 +1414,18 @@ void tst_qdeclarativelanguage::testType(const QString& qml, const QString& type, } } +// QTBUG-17276 +void tst_qdeclarativelanguage::inlineAssignmentsOverrideBindings() +{ + QDeclarativeComponent component(&engine, TEST_FILE("inlineAssignmentsOverrideBindings.qml")); -// Import tests (QT-558) + QObject *o = component.create(); + QVERIFY(o != 0); + QCOMPARE(o->property("test").toInt(), 11); + delete o; +} +// Import tests (QT-558) void tst_qdeclarativelanguage::importsBuiltin_data() { // QT-610 diff --git a/tests/auto/declarative/qdeclarativelistview/data/headerfooter.qml b/tests/auto/declarative/qdeclarativelistview/data/headerfooter.qml new file mode 100644 index 0000000..5633831 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/data/headerfooter.qml @@ -0,0 +1,26 @@ +import QtQuick 1.1 + +ListView { + id: view + property bool horizontal: false + property bool rtl: false + width: 240 + height: 320 + + orientation: horizontal ? ListView.Horizontal : ListView.Vertical + header: Rectangle { + objectName: "header" + width: horizontal ? 20 : view.width + height: horizontal ? view.height : 20 + color: "red" + } + footer: Rectangle { + objectName: "footer" + width: horizontal ? 30 : view.width + height: horizontal ? view.height : 30 + color: "blue" + } +// model: testModel + delegate: Text { width: 30; height: 30; text: index + "(" + x + ")" } + layoutDirection: rtl ? Qt.RightToLeft : Qt.LeftToRight +} diff --git a/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml b/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml index 9d9cda8..b2d9213 100644 --- a/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml +++ b/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml @@ -1,6 +1,7 @@ import QtQuick 1.0 Rectangle { + property string sectionProperty: "number" width: 240 height: 320 color: "#ffffff" @@ -56,7 +57,7 @@ Rectangle { height: 320 model: testModel delegate: myDelegate - section.property: "number" + section.property: sectionProperty section.delegate: Rectangle { objectName: "sect_" + section color: "#99bb99" diff --git a/tests/auto/declarative/qdeclarativelistview/data/rightToLeft.qml b/tests/auto/declarative/qdeclarativelistview/data/rightToLeft.qml new file mode 100644 index 0000000..1e92bb3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/data/rightToLeft.qml @@ -0,0 +1,42 @@ +// This example demonstrates how item positioning +// changes in right-to-left layout direction + +import QtQuick 1.1 + +Rectangle { + color: "lightgray" + width: 640 + height: 320 + + VisualItemModel { + id: itemModel + objectName: "itemModel" + Rectangle { + objectName: "item1" + height: view.height; width: 100; color: "#FFFEF0" + Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item2" + height: view.height; width: 200; color: "#F0FFF7" + Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item3" + height: view.height; width: 240; color: "#F4F0FF" + Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + } + + ListView { + id: view + objectName: "view" + anchors.fill: parent + anchors.bottomMargin: 30 + model: itemModel + highlightRangeMode: "StrictlyEnforceRange" + orientation: ListView.Horizontal + flickDeceleration: 2000 + layoutDirection: Qt.RightToLeft + } +} diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index c7f90da..2267a89 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -45,6 +45,7 @@ #include <QtDeclarative/qdeclarativeengine.h> #include <QtDeclarative/qdeclarativecontext.h> #include <QtDeclarative/qdeclarativeexpression.h> +#include <QtDeclarative/private/qdeclarativeitem_p.h> #include <QtDeclarative/private/qdeclarativelistview_p.h> #include <QtDeclarative/private/qdeclarativetext_p.h> #include <QtDeclarative/private/qdeclarativevisualitemmodel_p.h> @@ -102,6 +103,7 @@ private slots: void QTBUG_11105(); void header(); void footer(); + void headerFooter(); void resizeView(); void sizeLessThan1(); void QTBUG_14821(); @@ -115,6 +117,8 @@ private slots: void onRemove_data(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); + void rightToLeft(); + void test_mirroring(); private: template <class T> void items(); @@ -737,6 +741,13 @@ void tst_QDeclarativeListView::clear() QTRY_VERIFY(listview->count() == 0); QTRY_VERIFY(listview->currentItem() == 0); QTRY_VERIFY(listview->contentY() == 0); + QVERIFY(listview->currentIndex() == -1); + + // confirm sanity when adding an item to cleared list + model.addItem("New", "1"); + QTRY_VERIFY(listview->count() == 1); + QVERIFY(listview->currentItem() != 0); + QVERIFY(listview->currentIndex() == 0); delete canvas; } @@ -1091,6 +1102,52 @@ void tst_QDeclarativeListView::sectionsDelegate() QList<QDeclarativeItem*> items = findItems<QDeclarativeItem>(contentItem, "sect_1"); QCOMPARE(items.count(), 1); + // QTBUG-17759 + model.modifyItem(0, "One", "aaa"); + model.modifyItem(1, "One", "aaa"); + model.modifyItem(2, "One", "aaa"); + model.modifyItem(3, "Four", "aaa"); + model.modifyItem(4, "Four", "aaa"); + model.modifyItem(5, "Four", "aaa"); + model.modifyItem(6, "Five", "aaa"); + model.modifyItem(7, "Five", "aaa"); + model.modifyItem(8, "Five", "aaa"); + model.modifyItem(9, "Two", "aaa"); + model.modifyItem(10, "Two", "aaa"); + model.modifyItem(11, "Two", "aaa"); + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_aaa").count(), 1); + canvas->rootObject()->setProperty("sectionProperty", "name"); + // ensure view has settled. + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_Four").count(), 1); + for (int i = 0; i < 4; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, + "sect_" + model.name(i*3)); + QVERIFY(item); + QTRY_COMPARE(item->y(), qreal(i*20*4)); + } + + // QTBUG-17769 + model.removeItems(10, 20); + // ensure view has settled. + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "wrapper").count(), 10); + // Drag view up beyond bounds + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,20))); + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,0)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-50)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-200)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,-200))); + // view should settle back at 0 + QTRY_COMPARE(listview->contentY(), 0.0); + delete canvas; } @@ -1709,8 +1766,6 @@ void tst_QDeclarativeListView::manualHighlight() QDeclarativeView *canvas = new QDeclarativeView(0); canvas->setFixedSize(240,320); - QDeclarativeContext *ctxt = canvas->rootContext(); - QString filename(SRCDIR "/data/manual-highlight.qml"); canvas->setSource(QUrl::fromLocalFile(filename)); @@ -1841,8 +1896,6 @@ void tst_QDeclarativeListView::header() TestModel model; - QDeclarativeContext *ctxt = canvas->rootContext(); - canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header1.qml")); qApp->processEvents(); @@ -1913,6 +1966,112 @@ void tst_QDeclarativeListView::footer() delete canvas; } +class LVAccessor : public QDeclarativeListView +{ +public: + qreal minY() const { return minYExtent(); } + qreal maxY() const { return maxYExtent(); } + qreal minX() const { return minXExtent(); } + qreal maxX() const { return maxXExtent(); } +}; + +void tst_QDeclarativeListView::headerFooter() +{ + { + // Vertical + QDeclarativeView *canvas = createView(); + + TestModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast<QDeclarativeListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->y(), 0.0); + + QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 20.0); + + QVERIFY(static_cast<LVAccessor*>(listview)->minY() == 0); + QVERIFY(static_cast<LVAccessor*>(listview)->maxY() == 0); + + delete canvas; + } + { + // Horizontal + QDeclarativeView *canvas = createView(); + + TestModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml")); + canvas->rootObject()->setProperty("horizontal", true); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast<QDeclarativeListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->x(), 0.0); + + QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->x(), 20.0); + + QVERIFY(static_cast<LVAccessor*>(listview)->minX() == 0); + QVERIFY(static_cast<LVAccessor*>(listview)->maxX() == 0); + + delete canvas; + } + { + // Horizontal RTL + QDeclarativeView *canvas = createView(); + + TestModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml")); + canvas->rootObject()->setProperty("horizontal", true); + canvas->rootObject()->setProperty("rtl", true); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast<QDeclarativeListView*>(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header"); + QVERIFY(header); + QCOMPARE(header->x(), -20.0); + + QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->x(), -50.0); + + QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), 240.); + QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), 240.); + + delete canvas; + } +} + void tst_QDeclarativeListView::resizeView() { QDeclarativeView *canvas = createView(); @@ -2312,6 +2471,118 @@ void tst_QDeclarativeListView::testQtQuick11Attributes_data() << ""; } +void tst_QDeclarativeListView::rightToLeft() +{ + QDeclarativeView *canvas = createView(); + canvas->setFixedSize(640,320); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml")); + qApp->processEvents(); + + QVERIFY(canvas->rootObject() != 0); + QDeclarativeListView *listview = findItem<QDeclarativeListView>(canvas->rootObject(), "view"); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeVisualItemModel *model = canvas->rootObject()->findChild<QDeclarativeVisualItemModel*>("itemModel"); + QTRY_VERIFY(model != 0); + + QTRY_VERIFY(model->count() == 3); + QTRY_COMPARE(listview->currentIndex(), 0); + + // initial position at first item, right edge aligned + QCOMPARE(listview->contentX(), -640.); + + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "item1"); + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), -100.0); + QCOMPARE(item->height(), listview->height()); + + QDeclarativeText *text = findItem<QDeclarativeText>(contentItem, "text1"); + QTRY_VERIFY(text); + QTRY_COMPARE(text->text(), QLatin1String("index: 0")); + + listview->setCurrentIndex(2); + + item = findItem<QDeclarativeItem>(contentItem, "item3"); + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), -540.0); + + text = findItem<QDeclarativeText>(contentItem, "text3"); + QTRY_VERIFY(text); + QTRY_COMPARE(text->text(), QLatin1String("index: 2")); + + QCOMPARE(listview->contentX(), -640.); + + // Ensure resizing maintains position relative to right edge + qobject_cast<QDeclarativeItem*>(canvas->rootObject())->setWidth(600); + QTRY_COMPARE(listview->contentX(), -600.); + + delete canvas; +} + +void tst_QDeclarativeListView::test_mirroring() +{ + QDeclarativeView *canvasA = createView(); + canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml")); + QDeclarativeListView *listviewA = findItem<QDeclarativeListView>(canvasA->rootObject(), "view"); + QTRY_VERIFY(listviewA != 0); + + QDeclarativeView *canvasB = createView(); + canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml")); + QDeclarativeListView *listviewB = findItem<QDeclarativeListView>(canvasB->rootObject(), "view"); + QTRY_VERIFY(listviewA != 0); + qApp->processEvents(); + + QList<QString> objectNames; + objectNames << "item1" << "item2"; // << "item3" + + listviewA->setProperty("layoutDirection", Qt::LeftToRight); + listviewB->setProperty("layoutDirection", Qt::RightToLeft); + QCOMPARE(listviewA->layoutDirection(), listviewA->effectiveLayoutDirection()); + + // LTR != RTL + foreach(const QString objectName, objectNames) + QVERIFY(findItem<QDeclarativeItem>(listviewA, objectName)->x() != findItem<QDeclarativeItem>(listviewB, objectName)->x()); + + listviewA->setProperty("layoutDirection", Qt::LeftToRight); + listviewB->setProperty("layoutDirection", Qt::LeftToRight); + + // LTR == LTR + foreach(const QString objectName, objectNames) + QCOMPARE(findItem<QDeclarativeItem>(listviewA, objectName)->x(), findItem<QDeclarativeItem>(listviewB, objectName)->x()); + + QVERIFY(listviewB->layoutDirection() == listviewB->effectiveLayoutDirection()); + QDeclarativeItemPrivate::get(listviewB)->setLayoutMirror(true); + QVERIFY(listviewB->layoutDirection() != listviewB->effectiveLayoutDirection()); + + // LTR != LTR+mirror + foreach(const QString objectName, objectNames) + QVERIFY(findItem<QDeclarativeItem>(listviewA, objectName)->x() != findItem<QDeclarativeItem>(listviewB, objectName)->x()); + + listviewA->setProperty("layoutDirection", Qt::RightToLeft); + + // RTL == LTR+mirror + foreach(const QString objectName, objectNames) + QCOMPARE(findItem<QDeclarativeItem>(listviewA, objectName)->x(), findItem<QDeclarativeItem>(listviewB, objectName)->x()); + + listviewB->setProperty("layoutDirection", Qt::RightToLeft); + + // RTL != RTL+mirror + foreach(const QString objectName, objectNames) + QVERIFY(findItem<QDeclarativeItem>(listviewA, objectName)->x() != findItem<QDeclarativeItem>(listviewB, objectName)->x()); + + listviewA->setProperty("layoutDirection", Qt::LeftToRight); + + // LTR == RTL+mirror + foreach(const QString objectName, objectNames) + QCOMPARE(findItem<QDeclarativeItem>(listviewA, objectName)->x(), findItem<QDeclarativeItem>(listviewB, objectName)->x()); + + delete canvasA; + delete canvasB; +} + void tst_QDeclarativeListView::qListModelInterface_items() { items<TestModel>(); @@ -2421,7 +2692,7 @@ QList<T*> tst_QDeclarativeListView::findItems(QGraphicsObject *parent, const QSt //qDebug() << parent->childItems().count() << "children"; for (int i = 0; i < parent->childItems().count(); ++i) { QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i)); - if(!item) + if(!item || !item->isVisible()) continue; //qDebug() << "try" << item; if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) diff --git a/tests/auto/declarative/qdeclarativepathview/data/dragpath.qml b/tests/auto/declarative/qdeclarativepathview/data/dragpath.qml index a361bdc..0f94840 100644 --- a/tests/auto/declarative/qdeclarativepathview/data/dragpath.qml +++ b/tests/auto/declarative/qdeclarativepathview/data/dragpath.qml @@ -9,7 +9,7 @@ PathView { startX: 0; startY: 100 PathLine { x: 400; y: 100 } } - delegate: Rectangle { height: 100; width: 1; color: PathView.isCurrentItem?"red" : "black" } + delegate: Rectangle { objectName: "wrapper"; height: 100; width: 2; color: PathView.isCurrentItem?"red" : "black" } dragMargin: 100 preferredHighlightBegin: 0.5 preferredHighlightEnd: 0.5 diff --git a/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp b/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp index ebb5f98..8000137 100644 --- a/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp +++ b/tests/auto/declarative/qdeclarativepathview/tst_qdeclarativepathview.cpp @@ -111,6 +111,7 @@ private slots: void undefinedPath(); void mouseDrag(); void treeModel(); + void changePreferredHighlight(); private: QDeclarativeView *createView(); @@ -948,6 +949,45 @@ void tst_QDeclarativePathView::treeModel() delete canvas; } +void tst_QDeclarativePathView::changePreferredHighlight() +{ + QDeclarativeView *canvas = createView(); + canvas->setFixedSize(400,200); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragpath.qml")); + canvas->show(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas)); + + QDeclarativePathView *pathview = qobject_cast<QDeclarativePathView*>(canvas->rootObject()); + QVERIFY(pathview != 0); + + int current = pathview->currentIndex(); + QCOMPARE(current, 0); + + QDeclarativeRectangle *firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 0); + QVERIFY(firstItem); + QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path()); + QVERIFY(path); + QPointF start = path->pointAt(0.5); + start.setX(qRound(start.x())); + start.setY(qRound(start.y())); + QPointF offset;//Center of item is at point, but pos is from corner + offset.setX(firstItem->width()/2); + offset.setY(firstItem->height()/2); + QTRY_COMPARE(firstItem->pos() + offset, start); + + pathview->setPreferredHighlightBegin(0.8); + pathview->setPreferredHighlightEnd(0.8); + start = path->pointAt(0.8); + start.setX(qRound(start.x())); + start.setY(qRound(start.y())); + QTRY_COMPARE(firstItem->pos() + offset, start); + QCOMPARE(pathview->currentIndex(), 0); + + delete canvas; +} + QDeclarativeView *tst_QDeclarativePathView::createView() { QDeclarativeView *canvas = new QDeclarativeView(0); diff --git a/tests/auto/declarative/qdeclarativepositioners/data/grid-righttoleft.qml b/tests/auto/declarative/qdeclarativepositioners/data/grid-righttoleft.qml deleted file mode 100644 index 0ec1f37..0000000 --- a/tests/auto/declarative/qdeclarativepositioners/data/grid-righttoleft.qml +++ /dev/null @@ -1,41 +0,0 @@ -import QtQuick 1.1 - -Item { - width: 640 - height: 480 - Grid { - objectName: "grid" - columns: 3 - layoutDirection: Qt.RightToLeft - Rectangle { - objectName: "one" - color: "red" - width: 50 - height: 50 - } - Rectangle { - objectName: "two" - color: "green" - width: 20 - height: 50 - } - Rectangle { - objectName: "three" - color: "blue" - width: 50 - height: 20 - } - Rectangle { - objectName: "four" - color: "cyan" - width: 50 - height: 50 - } - Rectangle { - objectName: "five" - color: "magenta" - width: 10 - height: 10 - } - } -} diff --git a/tests/auto/declarative/qdeclarativepositioners/data/gridtest.qml b/tests/auto/declarative/qdeclarativepositioners/data/gridtest.qml index f3b17dd..929b726 100644 --- a/tests/auto/declarative/qdeclarativepositioners/data/gridtest.qml +++ b/tests/auto/declarative/qdeclarativepositioners/data/gridtest.qml @@ -1,9 +1,11 @@ -import QtQuick 1.0 +import QtQuick 1.1 Item { width: 640 height: 480 + property bool testRightToLeft: false Grid { + layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight objectName: "grid" columns: 3 Rectangle { @@ -21,7 +23,7 @@ Item { Rectangle { objectName: "three" color: "blue" - width: 50 + width: 30 height: 20 } Rectangle { diff --git a/tests/auto/declarative/qdeclarativepositioners/data/horizontal.qml b/tests/auto/declarative/qdeclarativepositioners/data/horizontal.qml index e1a9652..d35c02d 100644 --- a/tests/auto/declarative/qdeclarativepositioners/data/horizontal.qml +++ b/tests/auto/declarative/qdeclarativepositioners/data/horizontal.qml @@ -4,7 +4,6 @@ Item { width: 640 height: 480 property bool testRightToLeft: false - Row { objectName: "row" layoutDirection: testRightToLeft ? Qt.RightToLeft : Qt.LeftToRight diff --git a/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp b/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp index 40e533d..92ab722 100644 --- a/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp +++ b/tests/auto/declarative/qdeclarativepositioners/tst_qdeclarativepositioners.cpp @@ -45,6 +45,7 @@ #include <private/qdeclarativerectangle_p.h> #include <private/qdeclarativepositioners_p.h> #include <private/qdeclarativetransition_p.h> +#include <private/qdeclarativeitem_p.h> #include <qdeclarativeexpression.h> #include <QtGui/qgraphicswidget.h> #include "../../../shared/util.h" @@ -87,6 +88,7 @@ private slots: void test_flow_implicit_resize(); void test_conflictinganchors(); void test_vertical_qgraphicswidget(); + void test_mirroring(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); private: @@ -452,7 +454,7 @@ void tst_QDeclarativePositioners::test_grid() QDeclarativeGrid *grid = canvas->rootObject()->findChild<QDeclarativeGrid*>("grid"); QCOMPARE(grid->flow(), QDeclarativeGrid::LeftToRight); - QCOMPARE(grid->width(), 120.0); + QCOMPARE(grid->width(), 100.0); QCOMPARE(grid->height(), 100.0); delete canvas; @@ -494,7 +496,9 @@ void tst_QDeclarativePositioners::test_grid_topToBottom() void tst_QDeclarativePositioners::test_grid_rightToLeft() { - QDeclarativeView *canvas = createView(SRCDIR "/data/grid-righttoleft.qml"); + QDeclarativeView *canvas = createView(SRCDIR "/data/gridtest.qml"); + + canvas->rootObject()->setProperty("testRightToLeft", true); QDeclarativeRectangle *one = canvas->rootObject()->findChild<QDeclarativeRectangle*>("one"); QVERIFY(one != 0); @@ -507,20 +511,20 @@ void tst_QDeclarativePositioners::test_grid_rightToLeft() QDeclarativeRectangle *five = canvas->rootObject()->findChild<QDeclarativeRectangle*>("five"); QVERIFY(five != 0); - QCOMPARE(one->x(), 70.0); + QCOMPARE(one->x(), 50.0); QCOMPARE(one->y(), 0.0); - QCOMPARE(two->x(), 50.0); + QCOMPARE(two->x(), 30.0); QCOMPARE(two->y(), 0.0); QCOMPARE(three->x(), 0.0); QCOMPARE(three->y(), 0.0); - QCOMPARE(four->x(), 70.0); + QCOMPARE(four->x(), 50.0); QCOMPARE(four->y(), 50.0); - QCOMPARE(five->x(), 60.0); + QCOMPARE(five->x(), 40.0); QCOMPARE(five->y(), 50.0); QDeclarativeGrid *grid = canvas->rootObject()->findChild<QDeclarativeGrid*>("grid"); QCOMPARE(grid->layoutDirection(), Qt::RightToLeft); - QCOMPARE(grid->width(), 120.0); + QCOMPARE(grid->width(), 100.0); QCOMPARE(grid->height(), 100.0); delete canvas; @@ -1198,6 +1202,66 @@ void tst_QDeclarativePositioners::test_vertical_qgraphicswidget() delete canvas; } +void tst_QDeclarativePositioners::test_mirroring() +{ + QList<QString> qmlFiles; + qmlFiles << "horizontal.qml" << "gridtest.qml" << "flowtest.qml"; + QList<QString> objectNames; + objectNames << "one" << "two" << "three" << "four" << "five"; + + foreach(const QString qmlFile, qmlFiles) { + QDeclarativeView *canvasA = createView(QString(SRCDIR) + "/data/" + qmlFile); + QDeclarativeItem *rootA = qobject_cast<QDeclarativeItem*>(canvasA->rootObject()); + + QDeclarativeView *canvasB = createView(QString(SRCDIR) + "/data/" + qmlFile); + QDeclarativeItem *rootB = qobject_cast<QDeclarativeItem*>(canvasB->rootObject()); + + rootA->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft + + // LTR != RTL + foreach(const QString objectName, objectNames) { + // horizontal.qml only has three items + if (qmlFile == QString("horizontal.qml") && objectName == QString("four")) + break; + QDeclarativeItem *itemA = rootA->findChild<QDeclarativeItem*>(objectName); + QDeclarativeItem *itemB = rootB->findChild<QDeclarativeItem*>(objectName); + QVERIFY(itemA->x() != itemB->x()); + } + + QDeclarativeItemPrivate* rootPrivateB = QDeclarativeItemPrivate::get(rootB); + + rootPrivateB->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true + rootPrivateB->isMirrorImplicit = false; + rootPrivateB->inheritMirrorFromItem = true; // LayoutMirroring.childrenInherit: true + rootPrivateB->resolveLayoutMirror(); + + // RTL == mirror + foreach(const QString objectName, objectNames) { + // horizontal.qml only has three items + if (qmlFile == QString("horizontal.qml") && objectName == QString("four")) + break; + QDeclarativeItem *itemA = rootA->findChild<QDeclarativeItem*>(objectName); + QDeclarativeItem *itemB = rootB->findChild<QDeclarativeItem*>(objectName); + QCOMPARE(itemA->x(), itemB->x()); + } + + rootA->setProperty("testRightToLeft", false); // layoutDirection: Qt.LeftToRight + rootB->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft + + // LTR == RTL + mirror + foreach(const QString objectName, objectNames) { + // horizontal.qml only has three items + if (qmlFile == QString("horizontal.qml") && objectName == QString("four")) + break; + QDeclarativeItem *itemA = rootA->findChild<QDeclarativeItem*>(objectName); + QDeclarativeItem *itemB = rootB->findChild<QDeclarativeItem*>(objectName); + QCOMPARE(itemA->x(), itemB->x()); + } + delete canvasA; + delete canvasB; + } +} + void tst_QDeclarativePositioners::testQtQuick11Attributes() { QFETCH(QString, code); diff --git a/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp b/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp index 7d746a7..e3a4723 100644 --- a/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp +++ b/tests/auto/declarative/qdeclarativepropertymap/tst_qdeclarativepropertymap.cpp @@ -76,6 +76,40 @@ void tst_QDeclarativePropertyMap::insert() map.insert(QLatin1String("key1"),"Hello World"); QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); + + //inserting property names same with existing method(signal, slot, method) names is not allowed + //QDeclarativePropertyMap has an invokable keys() method + QTest::ignoreMessage(QtWarningMsg, "Creating property with name \"keys\" is not permitted, conflicts with internal symbols. "); + map.insert(QLatin1String("keys"), 1); + QVERIFY(map.keys().count() == 2); + QVERIFY(!map.contains(QLatin1String("keys"))); + QVERIFY(map.value(QLatin1String("keys")).isNull()); + + //QDeclarativePropertyMap has a deleteLater() slot + QTest::ignoreMessage(QtWarningMsg, "Creating property with name \"deleteLater\" is not permitted, conflicts with internal symbols. "); + map.insert(QLatin1String("deleteLater"), 1); + QVERIFY(map.keys().count() == 2); + QVERIFY(!map.contains(QLatin1String("deleteLater"))); + QVERIFY(map.value(QLatin1String("deleteLater")).isNull()); + + //QDeclarativePropertyMap has an valueChanged() signal + QTest::ignoreMessage(QtWarningMsg, "Creating property with name \"valueChanged\" is not permitted, conflicts with internal symbols. "); + map.insert(QLatin1String("valueChanged"), 1); + QVERIFY(map.keys().count() == 2); + QVERIFY(!map.contains(QLatin1String("valueChanged"))); + QVERIFY(map.value(QLatin1String("valueChanged")).isNull()); + + //but 'valueChange' should be ok + map.insert(QLatin1String("valueChange"), 1); + QVERIFY(map.keys().count() == 3); + QVERIFY(map.contains(QLatin1String("valueChange"))); + QCOMPARE(map.value(QLatin1String("valueChange")), QVariant(1)); + + //'valueCHANGED' should be ok, too + map.insert(QLatin1String("valueCHANGED"), 1); + QVERIFY(map.keys().count() == 4); + QVERIFY(map.contains(QLatin1String("valueCHANGED"))); + QCOMPARE(map.value(QLatin1String("valueCHANGED")), QVariant(1)); } void tst_QDeclarativePropertyMap::operatorInsert() diff --git a/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp index 56bed30..20e2640 100644 --- a/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp +++ b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp @@ -120,6 +120,9 @@ private slots: void anchorChanges3(); void anchorChanges4(); void anchorChanges5(); + void anchorChangesRTL(); + void anchorChangesRTL2(); + void anchorChangesRTL3(); void anchorChangesCrash(); void anchorRewindBug(); void anchorRewindBug2(); @@ -813,6 +816,125 @@ void tst_qdeclarativestates::anchorChanges5() delete rect; } +void mirrorAnchors(QDeclarativeItem *item) { + QDeclarativeItemPrivate *itemPrivate = QDeclarativeItemPrivate::get(item); + itemPrivate->setLayoutMirror(true); +} + +qreal offsetRTL(QDeclarativeItem *anchorItem, QDeclarativeItem *item) { + return anchorItem->width()+2*anchorItem->x()-item->width(); +} + +void tst_qdeclarativestates::anchorChangesRTL() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges1.qml"); + QDeclarativeRectangle *rect = qobject_cast<QDeclarativeRectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QDeclarativeRectangle *innerRect = qobject_cast<QDeclarativeRectangle*>(rect->findChild<QDeclarativeRectangle*>("MyRect")); + QVERIFY(innerRect != 0); + mirrorAnchors(innerRect); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeAnchorChanges *aChanges = qobject_cast<QDeclarativeAnchorChanges*>(state->operationAt(0)); + QVERIFY(aChanges != 0); + + rectPrivate->setState("right"); + QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150)); + QCOMPARE(aChanges->object(), qobject_cast<QDeclarativeItem*>(innerRect)); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QDeclarativeAnchorLine::Invalid); //### was reset (how do we distinguish from not set at all) + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine); + + rectPrivate->setState(""); + QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) -qreal(5)); + + delete rect; +} + +void tst_qdeclarativestates::anchorChangesRTL2() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges2.qml"); + QDeclarativeRectangle *rect = qobject_cast<QDeclarativeRectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QDeclarativeRectangle *innerRect = qobject_cast<QDeclarativeRectangle*>(rect->findChild<QDeclarativeRectangle*>("MyRect")); + QVERIFY(innerRect != 0); + mirrorAnchors(innerRect); + + rectPrivate->setState("right"); + QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150)); + + rectPrivate->setState(""); + QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(5)); + + delete rect; +} + +void tst_qdeclarativestates::anchorChangesRTL3() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges3.qml"); + QDeclarativeRectangle *rect = qobject_cast<QDeclarativeRectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QDeclarativeRectangle *innerRect = qobject_cast<QDeclarativeRectangle*>(rect->findChild<QDeclarativeRectangle*>("MyRect")); + QVERIFY(innerRect != 0); + mirrorAnchors(innerRect); + + QDeclarativeItem *leftGuideline = qobject_cast<QDeclarativeItem*>(rect->findChild<QDeclarativeItem*>("LeftGuideline")); + QVERIFY(leftGuideline != 0); + + QDeclarativeItem *bottomGuideline = qobject_cast<QDeclarativeItem*>(rect->findChild<QDeclarativeItem*>("BottomGuideline")); + QVERIFY(bottomGuideline != 0); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeAnchorChanges *aChanges = qobject_cast<QDeclarativeAnchorChanges*>(state->operationAt(0)); + QVERIFY(aChanges != 0); + + rectPrivate->setState("reanchored"); + QCOMPARE(aChanges->object(), qobject_cast<QDeclarativeItem*>(innerRect)); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->left().item, QDeclarativeItemPrivate::get(leftGuideline)->left().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QDeclarativeItemPrivate::get(leftGuideline)->left().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->top().item, rectPrivate->top().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->top().anchorLine, rectPrivate->top().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->bottom().item, QDeclarativeItemPrivate::get(bottomGuideline)->bottom().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->bottom().anchorLine, QDeclarativeItemPrivate::get(bottomGuideline)->bottom().anchorLine); + + QCOMPARE(innerRect->x(), offsetRTL(leftGuideline, innerRect) - qreal(10)); + QCOMPARE(innerRect->y(), qreal(0)); + // between left side of parent and leftGuideline.x: 10, which has width 0 + QCOMPARE(innerRect->width(), qreal(10)); + QCOMPARE(innerRect->height(), qreal(150)); + + rectPrivate->setState(""); + QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(0)); + QCOMPARE(innerRect->y(), qreal(10)); + // between right side of parent and left side of rightGuideline.x: 150, which has width 0 + QCOMPARE(innerRect->width(), qreal(50)); + QCOMPARE(innerRect->height(), qreal(190)); + + delete rect; +} + //QTBUG-9609 void tst_qdeclarativestates::anchorChangesCrash() { 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..581b58c 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; @@ -517,20 +518,112 @@ void tst_qdeclarativetext::horizontalAlignment_RightToLeft() QDeclarativeTextPrivate *textPrivate = QDeclarativeTextPrivate::get(text); QVERIFY(textPrivate != 0); - QVERIFY(textPrivate->layout.lineAt(0).x() > canvas->width()/2); + // implicit alignment should follow the reading direction of RTL text + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2); + + // explicitly left aligned text + text->setHAlign(QDeclarativeText::AlignLeft); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignLeft); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2); + + // explicitly right aligned text + text->setHAlign(QDeclarativeText::AlignRight); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2); - // "Right" aligned + // change to rich text + QString textString = text->text(); + text->setText(QString("<i>") + textString + QString("</i>")); + text->setTextFormat(QDeclarativeText::RichText); + text->resetHAlign(); + + // implicitly aligned rich text should follow the reading direction of text + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft); + + // explicitly left aligned rich text + text->setHAlign(QDeclarativeText::AlignLeft); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignLeft); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignRight); + + // explicitly right aligned rich text text->setHAlign(QDeclarativeText::AlignRight); QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); - QVERIFY(textPrivate->layout.lineAt(0).x() < canvas->width()/2); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft); + + text->setText(textString); + text->setTextFormat(QDeclarativeText::PlainText); - // Center aligned + // explicitly center aligned text->setHAlign(QDeclarativeText::AlignHCenter); QCOMPARE(text->hAlign(), QDeclarativeText::AlignHCenter); - QVERIFY(textPrivate->layout.lineAt(0).x() < canvas->width()/2); - QVERIFY(textPrivate->layout.lineAt(0).x() + textPrivate->layout.lineAt(0).width() > canvas->width()/2); + QCOMPARE(text->effectiveHAlign(), text->hAlign()); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2); + + // reseted alignment should go back to following the text reading direction + text->resetHAlign(); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2); + + // mirror the text item + QDeclarativeItemPrivate::get(text)->setLayoutMirror(true); + + // mirrored implicit alignment should continue to follow the reading direction of the text + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); + QCOMPARE(text->effectiveHAlign(), QDeclarativeText::AlignRight); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2); + + // mirrored explicitly right aligned behaves as left aligned + text->setHAlign(QDeclarativeText::AlignRight); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); + QCOMPARE(text->effectiveHAlign(), QDeclarativeText::AlignLeft); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2); + + // mirrored explicitly left aligned behaves as right aligned + text->setHAlign(QDeclarativeText::AlignLeft); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignLeft); + QCOMPARE(text->effectiveHAlign(), QDeclarativeText::AlignRight); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2); + + // disable mirroring + QDeclarativeItemPrivate::get(text)->setLayoutMirror(false); + text->resetHAlign(); + + // English text should be implicitly left aligned + text->setText("Hello world!"); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignLeft); + QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2); + +#ifndef Q_OS_MAC // QTBUG-18040 + // empty text with implicit alignment follows the system locale-based + // keyboard input direction from QApplication::keyboardInputDirection + text->setText(""); + QCOMPARE(text->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ? + QDeclarativeText::AlignLeft : QDeclarativeText::AlignRight); + text->setHAlign(QDeclarativeText::AlignRight); + QCOMPARE(text->hAlign(), QDeclarativeText::AlignRight); +#endif delete canvas; + +#ifndef Q_OS_MAC // QTBUG-18040 + // alignment of Text with no text set to it + QString componentStr = "import QtQuick 1.0\nText {}"; + QDeclarativeComponent textComponent(&engine); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeText *textObject = qobject_cast<QDeclarativeText*>(textComponent.create()); + QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ? + QDeclarativeText::AlignLeft : QDeclarativeText::AlignRight); + delete textObject; +#endif } void tst_qdeclarativetext::verticalAlignment() @@ -1113,13 +1206,13 @@ void tst_qdeclarativetext::lineHeight() myText->setLineHeightMode(QDeclarativeText::ProportionalHeight); myText->setLineHeight(1.0); - //qreal h2 = myText->height(); + qreal h2 = myText->height(); myText->setLineHeight(2.0); - //QVERIFY(myText->height() == h2 * 2.0); + QVERIFY(myText->height() == h2 * 2.0); myText->setLineHeightMode(QDeclarativeText::FixedHeight); myText->setLineHeight(10); - //QCOMPARE(myText->height(), myText->lineCount() * 10.0); + QCOMPARE(myText->height(), myText->lineCount() * 10.0); delete canvas; } @@ -1202,6 +1295,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/mouseselection_false_words.qml b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_false_words.qml new file mode 100644 index 0000000..22a9871 --- /dev/null +++ b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_false_words.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +TextEdit { + focus: true + text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + selectByMouse: false +} diff --git a/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml new file mode 100644 index 0000000..d61da46 --- /dev/null +++ b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +TextEdit { + focus: true + text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + selectByMouse: true +} diff --git a/tests/auto/declarative/qdeclarativetextedit/data/navigation.qml b/tests/auto/declarative/qdeclarativetextedit/data/navigation.qml index 9ee8a93..0e1caf6 100644 --- a/tests/auto/declarative/qdeclarativetextedit/data/navigation.qml +++ b/tests/auto/declarative/qdeclarativetextedit/data/navigation.qml @@ -15,6 +15,7 @@ Rectangle { KeyNavigation.right: lastItem KeyNavigation.up: firstItem KeyNavigation.down: lastItem + text: "a" } Item { id: lastItem 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..f62c2c5 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -110,6 +110,9 @@ private slots: void persistentSelection(); void focusOnPress(); void selection(); + void isRightToLeft_data(); + void isRightToLeft(); + void keySelection(); void moveCursorSelection_data(); void moveCursorSelection(); void moveCursorSelectionSequence_data(); @@ -121,6 +124,8 @@ private slots: void dragMouseSelection(); void inputMethodHints(); + void positionAt(); + void cursorDelegate(); void cursorVisible(); void delegateLoading_data(); @@ -128,6 +133,8 @@ private slots: void navigation(); void readOnly(); void copyAndPaste(); + void canPaste(); + void canPasteEmpty(); void textInput(); void openInputPanelOnClick(); void openInputPanelOnFocus(); @@ -140,9 +147,10 @@ private slots: void preeditMicroFocus(); void inputContextMouseHandler(); + void inputMethodComposing(); private: - void simulateKey(QDeclarativeView *, int key); + void simulateKey(QDeclarativeView *, int key, Qt::KeyboardModifiers modifiers = 0); QDeclarativeView *createView(const QString &filename); QStringList standard; @@ -440,21 +448,109 @@ void tst_qdeclarativetextedit::hAlign_RightToLeft() QVERIFY(textEdit != 0); canvas->show(); + // implicit alignment should follow the reading direction of text + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); - // "Right" align + // explicitly left aligned + textEdit->setHAlign(QDeclarativeTextEdit::AlignLeft); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft); + QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2); + + // explicitly right aligned textEdit->setHAlign(QDeclarativeTextEdit::AlignRight); QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + + QString textString = textEdit->text(); + textEdit->setText(QString("<i>") + textString + QString("</i>")); + textEdit->resetHAlign(); + + // implicitly aligned rich text should follow the reading direction of RTL text + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign()); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + + // explicitly left aligned rich text + textEdit->setHAlign(QDeclarativeTextEdit::AlignLeft); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft); + QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign()); QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2); - // Center align - // Note that position 0 is on the right-hand side + // explicitly right aligned rich text + textEdit->setHAlign(QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->effectiveHAlign(), textEdit->hAlign()); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + + textEdit->setText(textString); + + // explicitly center aligned textEdit->setHAlign(QDeclarativeTextEdit::AlignHCenter); QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignHCenter); - QVERIFY(textEdit->positionToRectangle(0).x() - textEdit->width() < canvas->width()/2); QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + // reseted alignment should go back to following the text reading direction + textEdit->resetHAlign(); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + + // mirror the text item + QDeclarativeItemPrivate::get(textEdit)->setLayoutMirror(true); + + // mirrored implicit alignment should continue to follow the reading direction of the text + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->effectiveHAlign(), QDeclarativeTextEdit::AlignRight); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + + // mirrored explicitly right aligned behaves as left aligned + textEdit->setHAlign(QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->effectiveHAlign(), QDeclarativeTextEdit::AlignLeft); + QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2); + + // mirrored explicitly left aligned behaves as right aligned + textEdit->setHAlign(QDeclarativeTextEdit::AlignLeft); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft); + QCOMPARE(textEdit->effectiveHAlign(), QDeclarativeTextEdit::AlignRight); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + + // disable mirroring + QDeclarativeItemPrivate::get(textEdit)->setLayoutMirror(false); + textEdit->resetHAlign(); + + // English text should be implicitly left aligned + textEdit->setText("Hello world!"); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft); + QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2); + +#ifndef Q_OS_MAC // QTBUG-18040 + // empty text with implicit alignment follows the system locale-based + // keyboard input direction from QApplication::keyboardInputDirection + textEdit->setText(""); + QCOMPARE(textEdit->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ? + QDeclarativeTextEdit::AlignLeft : QDeclarativeTextEdit::AlignRight); + if (QApplication::keyboardInputDirection() == Qt::LeftToRight) + QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2); + else + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); + textEdit->setHAlign(QDeclarativeTextEdit::AlignRight); + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); +#endif + delete canvas; + +#ifndef Q_OS_MAC // QTBUG-18040 + // alignment of TextEdit with no text set to it + QString componentStr = "import QtQuick 1.0\nTextEdit {}"; + QDeclarativeComponent textComponent(&engine); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeTextEdit *textObject = qobject_cast<QDeclarativeTextEdit*>(textComponent.create()); + QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ? + QDeclarativeTextEdit::AlignLeft : QDeclarativeTextEdit::AlignRight); + delete textObject; +#endif } void tst_qdeclarativetextedit::vAlign() @@ -757,6 +853,113 @@ void tst_qdeclarativetextedit::selection() QVERIFY(textEditObject->selectedText().isNull()); } +void tst_qdeclarativetextedit::isRightToLeft_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<bool>("emptyString"); + QTest::addColumn<bool>("firstCharacter"); + QTest::addColumn<bool>("lastCharacter"); + QTest::addColumn<bool>("middleCharacter"); + QTest::addColumn<bool>("startString"); + QTest::addColumn<bool>("midString"); + QTest::addColumn<bool>("endString"); + + const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; + QTest::newRow("Empty") << "" << false << false << false << false << false << false << false; + QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false; + QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false; + QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true; + QTest::newRow("Bidi RTL + LTR + RTL") << QString::fromUtf16(arabic_str, 11) + QString("Hello world") + QString::fromUtf16(arabic_str, 11) << false << true << true << false << true << true << true; + QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false; +} + +void tst_qdeclarativetextedit::isRightToLeft() +{ + QFETCH(QString, text); + QFETCH(bool, emptyString); + QFETCH(bool, firstCharacter); + QFETCH(bool, lastCharacter); + QFETCH(bool, middleCharacter); + QFETCH(bool, startString); + QFETCH(bool, midString); + QFETCH(bool, endString); + + QDeclarativeTextEdit textEdit; + textEdit.setText(text); + + // first test that the right string is delivered to the QString::isRightToLeft() + QCOMPARE(textEdit.isRightToLeft(0,0), text.mid(0,0).isRightToLeft()); + QCOMPARE(textEdit.isRightToLeft(0,1), text.mid(0,1).isRightToLeft()); + QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft()); + QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft()); + QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft()); + QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft()); + if (text.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start."); + QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft()); + + // then test that the feature actually works + QCOMPARE(textEdit.isRightToLeft(0,0), emptyString); + QCOMPARE(textEdit.isRightToLeft(0,1), firstCharacter); + QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), lastCharacter); + QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter); + QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), startString); + QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), midString); + if (text.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start."); + QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), endString); +} + +void tst_qdeclarativetextedit::keySelection() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/navigation.qml"); + canvas->show(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas)); + canvas->setFocus(); + + QVERIFY(canvas->rootObject() != 0); + + QDeclarativeTextEdit *input = qobject_cast<QDeclarativeTextEdit *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput"))); + + QVERIFY(input != 0); + QTRY_VERIFY(input->hasActiveFocus() == true); + + QSignalSpy spy(input, SIGNAL(selectionChanged())); + + simulateKey(canvas, Qt::Key_Right, Qt::ShiftModifier); + QVERIFY(input->hasActiveFocus() == true); + QCOMPARE(input->selectedText(), QString("a")); + QCOMPARE(spy.count(), 1); + simulateKey(canvas, Qt::Key_Right); + QVERIFY(input->hasActiveFocus() == true); + QCOMPARE(input->selectedText(), QString()); + QCOMPARE(spy.count(), 2); + simulateKey(canvas, Qt::Key_Right); + QVERIFY(input->hasActiveFocus() == false); + QCOMPARE(input->selectedText(), QString()); + QCOMPARE(spy.count(), 2); + + simulateKey(canvas, Qt::Key_Left); + QVERIFY(input->hasActiveFocus() == true); + QCOMPARE(spy.count(), 2); + simulateKey(canvas, Qt::Key_Left, Qt::ShiftModifier); + QVERIFY(input->hasActiveFocus() == true); + QCOMPARE(input->selectedText(), QString("a")); + QCOMPARE(spy.count(), 3); + simulateKey(canvas, Qt::Key_Left); + QVERIFY(input->hasActiveFocus() == true); + QCOMPARE(input->selectedText(), QString()); + QCOMPARE(spy.count(), 4); + simulateKey(canvas, Qt::Key_Left); + QVERIFY(input->hasActiveFocus() == false); + QCOMPARE(input->selectedText(), QString()); + QCOMPARE(spy.count(), 4); + + delete canvas; +} + void tst_qdeclarativetextedit::moveCursorSelection_data() { QTest::addColumn<QString>("testStr"); @@ -1102,6 +1305,8 @@ void tst_qdeclarativetextedit::mouseSelection_data() QTest::newRow("on") << SRCDIR "/data/mouseselection_true.qml" << true; QTest::newRow("off") << SRCDIR "/data/mouseselection_false.qml" << false; QTest::newRow("default") << SRCDIR "/data/mouseselection_default.qml" << false; + QTest::newRow("on word selection") << SRCDIR "/data/mouseselection_true_words.qml" << true; + QTest::newRow("off word selection") << SRCDIR "/data/mouseselection_false_words.qml" << false; } void tst_qdeclarativetextedit::mouseSelection() @@ -1250,6 +1455,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"); @@ -1425,6 +1680,8 @@ void tst_qdeclarativetextedit::navigation() simulateKey(canvas, Qt::Key_Right); QVERIFY(input->hasActiveFocus() == true); simulateKey(canvas, Qt::Key_Right); + QVERIFY(input->hasActiveFocus() == true); + simulateKey(canvas, Qt::Key_Right); QVERIFY(input->hasActiveFocus() == false); simulateKey(canvas, Qt::Key_Left); QVERIFY(input->hasActiveFocus() == true); @@ -1492,6 +1749,42 @@ void tst_qdeclarativetextedit::copyAndPaste() { #endif } +void tst_qdeclarativetextedit::canPaste() { +#ifndef QT_NO_CLIPBOARD + + QApplication::clipboard()->setText("Some text"); + + QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"Hello world!\" }"; + QDeclarativeComponent textEditComponent(&engine); + textEditComponent.setData(componentStr.toLatin1(), QUrl()); + QDeclarativeTextEdit *textEdit = qobject_cast<QDeclarativeTextEdit*>(textEditComponent.create()); + QVERIFY(textEdit != 0); + + // check initial value - QTBUG-17765 + QTextControl tc; + QCOMPARE(textEdit->canPaste(), tc.canPaste()); + +#endif +} + +void tst_qdeclarativetextedit::canPasteEmpty() { +#ifndef QT_NO_CLIPBOARD + + QApplication::clipboard()->clear(); + + QString componentStr = "import QtQuick 1.0\nTextEdit { text: \"Hello world!\" }"; + QDeclarativeComponent textEditComponent(&engine); + textEditComponent.setData(componentStr.toLatin1(), QUrl()); + QDeclarativeTextEdit *textEdit = qobject_cast<QDeclarativeTextEdit*>(textEditComponent.create()); + QVERIFY(textEdit != 0); + + // check initial value - QTBUG-17765 + QTextControl tc; + QCOMPARE(textEdit->canPaste(), tc.canPaste()); + +#endif +} + void tst_qdeclarativetextedit::readOnly() { QDeclarativeView *canvas = createView(SRCDIR "/data/readOnly.qml"); @@ -1516,10 +1809,10 @@ void tst_qdeclarativetextedit::readOnly() delete canvas; } -void tst_qdeclarativetextedit::simulateKey(QDeclarativeView *view, int key) +void tst_qdeclarativetextedit::simulateKey(QDeclarativeView *view, int key, Qt::KeyboardModifiers modifiers) { - QKeyEvent press(QKeyEvent::KeyPress, key, 0); - QKeyEvent release(QKeyEvent::KeyRelease, key, 0); + QKeyEvent press(QKeyEvent::KeyPress, key, modifiers); + QKeyEvent release(QKeyEvent::KeyRelease, key, modifiers); QApplication::sendEvent(view, &press); QApplication::sendEvent(view, &release); @@ -2079,6 +2372,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 49a05a3..45f38a4 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -89,6 +89,8 @@ private slots: void font(); void color(); void selection(); + void isRightToLeft_data(); + void isRightToLeft(); void moveCursorSelection_data(); void moveCursorSelection(); void moveCursorSelectionSequence_data(); @@ -111,8 +113,12 @@ private slots: void passwordCharacter(); void cursorDelegate(); void cursorVisible(); + void cursorRectangle(); void navigation(); + void navigation_RTL(); void copyAndPaste(); + void canPasteEmpty(); + void canPaste(); void readOnly(); void openInputPanelOnClick(); @@ -128,6 +134,7 @@ private slots: void preeditAutoScroll(); void preeditMicroFocus(); void inputContextMouseHandler(); + void inputMethodComposing(); private: void simulateKey(QDeclarativeView *, int key); @@ -143,7 +150,8 @@ tst_qdeclarativetextinput::tst_qdeclarativetextinput() standard << "the quick brown fox jumped over the lazy dog" << "It's supercalifragisiticexpialidocious!" << "Hello, world!" - << "!dlrow ,olleH"; + << "!dlrow ,olleH" + << " spacey text "; colorStrings << "aliceblue" << "antiquewhite" @@ -434,6 +442,63 @@ void tst_qdeclarativetextinput::selection() delete textinputObject; } +void tst_qdeclarativetextinput::isRightToLeft_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<bool>("emptyString"); + QTest::addColumn<bool>("firstCharacter"); + QTest::addColumn<bool>("lastCharacter"); + QTest::addColumn<bool>("middleCharacter"); + QTest::addColumn<bool>("startString"); + QTest::addColumn<bool>("midString"); + QTest::addColumn<bool>("endString"); + + const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; + QTest::newRow("Empty") << "" << false << false << false << false << false << false << false; + QTest::newRow("Neutral") << "23244242" << false << false << false << false << false << false << false; + QTest::newRow("LTR") << "Hello world" << false << false << false << false << false << false << false; + QTest::newRow("RTL") << QString::fromUtf16(arabic_str, 11) << false << true << true << true << true << true << true; + QTest::newRow("Bidi RTL + LTR + RTL") << QString::fromUtf16(arabic_str, 11) + QString("Hello world") + QString::fromUtf16(arabic_str, 11) << false << true << true << false << true << true << true; + QTest::newRow("Bidi LTR + RTL + LTR") << QString("Hello world") + QString::fromUtf16(arabic_str, 11) + QString("Hello world") << false << false << false << true << false << false << false; +} + +void tst_qdeclarativetextinput::isRightToLeft() +{ + QFETCH(QString, text); + QFETCH(bool, emptyString); + QFETCH(bool, firstCharacter); + QFETCH(bool, lastCharacter); + QFETCH(bool, middleCharacter); + QFETCH(bool, startString); + QFETCH(bool, midString); + QFETCH(bool, endString); + + QDeclarativeTextInput textInput; + textInput.setText(text); + + // first test that the right string is delivered to the QString::isRightToLeft() + QCOMPARE(textInput.isRightToLeft(0,0), text.mid(0,0).isRightToLeft()); + QCOMPARE(textInput.isRightToLeft(0,1), text.mid(0,1).isRightToLeft()); + QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft()); + QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft()); + QCOMPARE(textInput.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft()); + QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft()); + if (text.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start."); + QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft()); + + // then test that the feature actually works + QCOMPARE(textInput.isRightToLeft(0,0), emptyString); + QCOMPARE(textInput.isRightToLeft(0,1), firstCharacter); + QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), lastCharacter); + QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter); + QCOMPARE(textInput.isRightToLeft(0,text.count()/4), startString); + QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), midString); + if (text.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start."); + QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), endString); +} + void tst_qdeclarativetextinput::moveCursorSelection_data() { QTest::addColumn<QString>("testStr"); @@ -444,6 +509,9 @@ void tst_qdeclarativetextinput::moveCursorSelection_data() QTest::addColumn<int>("selectionEnd"); QTest::addColumn<bool>("reversible"); + // () contains the text selected by the cursor. + // <> contains the actual selection. + QTest::newRow("(t)he|characters") << standard[0] << 0 << 1 << QDeclarativeTextInput::SelectCharacters << 0 << 1 << true; QTest::newRow("do(g)|characters") @@ -581,6 +649,24 @@ void tst_qdeclarativetextinput::moveCursorSelection_data() << standard[3] << 0 << 0 << QDeclarativeTextInput::SelectWords << 0 << 0 << true; QTest::newRow("!<()>dlrow|words") << standard[3] << 1 << 1 << QDeclarativeTextInput::SelectWords << 1 << 1 << true; + + QTest::newRow(" <s(pac)ey> text |words") + << standard[4] << 1 << 4 << QDeclarativeTextInput::SelectWords << 1 << 7 << true; + QTest::newRow(" spacey <t(ex)t> |words") + << standard[4] << 11 << 13 << QDeclarativeTextInput::SelectWords << 10 << 14 << false; // Should be reversible. QTBUG-11365 + QTest::newRow("<( )>spacey text |words|ltr") + << standard[4] << 0 << 1 << QDeclarativeTextInput::SelectWords << 0 << 1 << false; + QTest::newRow("<( )spacey> text |words|rtl") + << standard[4] << 1 << 0 << QDeclarativeTextInput::SelectWords << 0 << 7 << false; + QTest::newRow("spacey <text( )>|words|ltr") + << standard[4] << 14 << 15 << QDeclarativeTextInput::SelectWords << 10 << 15 << false; +// QTBUG-11365 +// QTest::newRow("spacey text<( )>|words|rtl") +// << standard[4] << 15 << 14 << QDeclarativeTextInput::SelectWords << 14 << 15 << false; + QTest::newRow("<()> spacey text |words") + << standard[4] << 0 << 0 << QDeclarativeTextInput::SelectWords << 0 << 0 << false; + QTest::newRow(" spacey text <()>|words") + << standard[4] << 15 << 15 << QDeclarativeTextInput::SelectWords << 15 << 15 << false; } void tst_qdeclarativetextinput::moveCursorSelection() @@ -627,6 +713,11 @@ void tst_qdeclarativetextinput::moveCursorSelectionSequence_data() QTest::addColumn<int>("selection2Start"); QTest::addColumn<int>("selection2End"); + // () contains the text selected by the cursor. + // <> contains the actual selection. + // ^ is the revised cursor position. + // {} contains the revised selection. + QTest::newRow("the {<quick( bro)wn> f^ox} jumped|ltr") << standard[0] << 9 << 13 << 17 @@ -739,6 +830,50 @@ void tst_qdeclarativetextinput::moveCursorSelectionSequence_data() << 11 << 9 << 5 << 8 << 13 << 1 << 13; + + QTest::newRow("{<(^} sp)acey> text |ltr") + << standard[4] + << 0 << 3 << 0 + << 0 << 7 + << 0 << 0; + QTest::newRow("{<( ^}sp)acey> text |ltr") + << standard[4] + << 0 << 3 << 1 + << 0 << 7 + << 0 << 1; + QTest::newRow("<( {s^p)acey>} text |rtl") + << standard[4] + << 3 << 0 << 2 + << 0 << 7 + << 1 << 7; + QTest::newRow("<( {^sp)acey>} text |rtl") + << standard[4] + << 3 << 0 << 1 + << 0 << 7 + << 1 << 7; + + QTest::newRow(" spacey <te(xt {^)>}|rtl") + << standard[4] + << 15 << 12 << 15 + << 10 << 15 + << 15 << 15; +// QTBUG-11365 +// QTest::newRow(" spacey <te(xt{^ )>}|rtl") +// << standard[4] +// << 15 << 12 << 14 +// << 10 << 15 +// << 14 << 15; + QTest::newRow(" spacey {<te(x^t} )>|ltr") + << standard[4] + << 12 << 15 << 13 + << 10 << 15 + << 10 << 14; +// QTBUG-11365 +// QTest::newRow(" spacey {<te(xt^} )>|ltr") +// << standard[4] +// << 12 << 15 << 14 +// << 10 << 15 +// << 10 << 14; } void tst_qdeclarativetextinput::moveCursorSelectionSequence() @@ -916,18 +1051,93 @@ void tst_qdeclarativetextinput::horizontalAlignment_RightToLeft() QVERIFY(textInputPrivate != 0); QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); - // "Right" Align - textInput->setHAlign(QDeclarativeTextInput::AlignRight); + // implicit alignment should follow the reading direction of RTL text QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); + + // explicitly left aligned + textInput->setHAlign(QDeclarativeTextInput::AlignLeft); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignLeft); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); QVERIFY(-textInputPrivate->hscroll < canvas->width()/2); - // Center Align + // explicitly right aligned + textInput->setHAlign(QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); + + // explicitly center aligned textInput->setHAlign(QDeclarativeTextInput::AlignHCenter); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignHCenter); QVERIFY(-textInputPrivate->hscroll < canvas->width()/2); QVERIFY(-textInputPrivate->hscroll + textInputPrivate->width() > canvas->width()/2); + // reseted alignment should go back to following the text reading direction + textInput->resetHAlign(); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); + + // mirror the text item + QDeclarativeItemPrivate::get(textInput)->setLayoutMirror(true); + + // mirrored implicit alignment should continue to follow the reading direction of the text + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); + + // explicitly right aligned behaves as left aligned + textInput->setHAlign(QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->effectiveHAlign(), QDeclarativeTextInput::AlignLeft); + QVERIFY(-textInputPrivate->hscroll < canvas->width()/2); + + // mirrored explicitly left aligned behaves as right aligned + textInput->setHAlign(QDeclarativeTextInput::AlignLeft); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignLeft); + QCOMPARE(textInput->effectiveHAlign(), QDeclarativeTextInput::AlignRight); + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); + + // disable mirroring + QDeclarativeItemPrivate::get(textInput)->setLayoutMirror(false); + QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign()); + textInput->resetHAlign(); + + // English text should be implicitly left aligned + textInput->setText("Hello world!"); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignLeft); + QVERIFY(-textInputPrivate->hscroll < canvas->width()/2); + +#ifndef Q_OS_MAC // QTBUG-18040 + // empty text with implicit alignment follows the system locale-based + // keyboard input direction from QApplication::keyboardInputDirection + textInput->setText(""); + QCOMPARE(textInput->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ? + QDeclarativeTextInput::AlignLeft : QDeclarativeTextInput::AlignRight); + if (QApplication::keyboardInputDirection() == Qt::LeftToRight) + QVERIFY(-textInputPrivate->hscroll < canvas->width()/2); + else + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); + textInput->setHAlign(QDeclarativeTextInput::AlignRight); + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); +#endif + delete canvas; + +#ifndef Q_OS_MAC // QTBUG-18040 + // alignment of TextInput with no text set to it + QString componentStr = "import QtQuick 1.0\nTextInput {}"; + QDeclarativeComponent textComponent(&engine); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeTextInput *textObject = qobject_cast<QDeclarativeTextInput*>(textComponent.create()); + QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ? + QDeclarativeTextInput::AlignLeft : QDeclarativeTextInput::AlignRight); + delete textObject; +#endif } void tst_qdeclarativetextinput::positionAt() @@ -955,6 +1165,10 @@ void tst_qdeclarativetextinput::positionAt() QVERIFY(diff < 5); #endif + int x = textinputObject->positionToRectangle(pos + 1).x() - 1; + QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorBetweenCharacters), pos + 1); + QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorOnCharacter), pos); + // Check without autoscroll... textinputObject->setAutoScroll(false); pos = textinputObject->positionAt(textinputObject->width()/2); @@ -967,6 +1181,29 @@ void tst_qdeclarativetextinput::positionAt() QVERIFY(diff < 5); #endif + x = textinputObject->positionToRectangle(pos + 1).x() - 1; + 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; } @@ -1145,6 +1382,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; } @@ -1194,6 +1449,45 @@ void tst_qdeclarativetextinput::navigation() delete canvas; } +void tst_qdeclarativetextinput::navigation_RTL() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/navigation.qml"); + canvas->show(); + canvas->setFocus(); + + QVERIFY(canvas->rootObject() != 0); + + QDeclarativeTextInput *input = qobject_cast<QDeclarativeTextInput *>(qvariant_cast<QObject *>(canvas->rootObject()->property("myInput"))); + + QVERIFY(input != 0); + const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; + input->setText(QString::fromUtf16(arabic_str, 11)); + + input->setCursorPosition(0); + QTRY_VERIFY(input->hasActiveFocus() == true); + + // move off + simulateKey(canvas, Qt::Key_Right); + QVERIFY(input->hasActiveFocus() == false); + + // move back + simulateKey(canvas, Qt::Key_Left); + QVERIFY(input->hasActiveFocus() == true); + + input->setCursorPosition(input->text().length()); + QVERIFY(input->hasActiveFocus() == true); + + // move off + simulateKey(canvas, Qt::Key_Left); + QVERIFY(input->hasActiveFocus() == false); + + // move back + simulateKey(canvas, Qt::Key_Right); + QVERIFY(input->hasActiveFocus() == true); + + delete canvas; +} + void tst_qdeclarativetextinput::copyAndPaste() { #ifndef QT_NO_CLIPBOARD @@ -1273,6 +1567,42 @@ void tst_qdeclarativetextinput::copyAndPaste() { #endif } +void tst_qdeclarativetextinput::canPasteEmpty() { +#ifndef QT_NO_CLIPBOARD + + QApplication::clipboard()->clear(); + + QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\" }"; + QDeclarativeComponent textInputComponent(&engine); + textInputComponent.setData(componentStr.toLatin1(), QUrl()); + QDeclarativeTextInput *textInput = qobject_cast<QDeclarativeTextInput*>(textInputComponent.create()); + QVERIFY(textInput != 0); + + QLineControl lc; + bool cp = !lc.isReadOnly() && QApplication::clipboard()->text().length() != 0; + QCOMPARE(textInput->canPaste(), cp); + +#endif +} + +void tst_qdeclarativetextinput::canPaste() { +#ifndef QT_NO_CLIPBOARD + + QApplication::clipboard()->setText("Some text"); + + QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\" }"; + QDeclarativeComponent textInputComponent(&engine); + textInputComponent.setData(componentStr.toLatin1(), QUrl()); + QDeclarativeTextInput *textInput = qobject_cast<QDeclarativeTextInput*>(textInputComponent.create()); + QVERIFY(textInput != 0); + + QLineControl lc; + bool cp = !lc.isReadOnly() && QApplication::clipboard()->text().length() != 0; + QCOMPARE(textInput->canPaste(), cp); + +#endif +} + void tst_qdeclarativetextinput::passwordCharacter() { QString componentStr = "import QtQuick 1.0\nTextInput { text: \"Hello world!\"; font.family: \"Helvetica\"; echoMode: TextInput.Password }"; @@ -1386,6 +1716,45 @@ 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); + QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r); + } + + // 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()); + QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r); + } + + for (int i = text.length() - 2; i >= 0; --i) { + input.setCursorPosition(i); + r = input.cursorRectangle(); + QVERIFY(r.right() >= 0); + QCOMPARE(input.inputMethodQuery(Qt::ImMicroFocus).toRect(), r); + } +} + void tst_qdeclarativetextinput::readOnly() { QDeclarativeView *canvas = createView(SRCDIR "/data/readOnly.qml"); @@ -1460,13 +1829,23 @@ void tst_qdeclarativetextinput::echoMode() QCOMPARE(input->inputMethodHints(), ref); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ")); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("QQQQQQQQ")); QTest::keyPress(canvas, Qt::Key_A);//Clearing previous entry is part of PasswordEchoOnEdit QTest::keyRelease(canvas, Qt::Key_A, Qt::NoModifier ,10); QCOMPARE(input->text(), QLatin1String("a")); QCOMPARE(input->displayText(), QLatin1String("a")); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("a")); input->setFocus(false); QVERIFY(input->hasActiveFocus() == false); QCOMPARE(input->displayText(), QLatin1String("Q")); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("Q")); + input->setFocus(true); + QInputMethodEvent inputEvent; + inputEvent.setCommitString(initial); + QApplication::sendEvent(canvas, &inputEvent); + QCOMPARE(input->text(), initial); + QCOMPARE(input->displayText(), initial); + QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial); delete canvas; } @@ -1840,7 +2219,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); @@ -1853,7 +2233,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()); @@ -1862,26 +2242,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. @@ -1903,6 +2288,7 @@ void tst_qdeclarativetextinput::preeditMicroFocus() view.setInputContext(&ic); QDeclarativeTextInput input; input.setPos(0, 0); + input.setAutoScroll(false); input.setFocus(true); scene.addItem(&input); view.show(); @@ -2066,6 +2452,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" diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/Global.js b/tests/auto/declarative/qdeclarativeworkerscript/data/Global.js new file mode 100644 index 0000000..6bdb4a5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/Global.js @@ -0,0 +1 @@ +var data = "World" diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/script_include.js b/tests/auto/declarative/qdeclarativeworkerscript/data/script_include.js new file mode 100644 index 0000000..0385d91 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/script_include.js @@ -0,0 +1,5 @@ +WorkerScript.onMessage = function(msg) { + var res = Qt.include("Global.js"); + WorkerScript.sendMessage(msg + " " + data) +} + diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/worker_include.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/worker_include.qml new file mode 100644 index 0000000..595cb2b --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/worker_include.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 + +BaseWorker { + source: "script_include.js" +} diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp index 4b922fb..b64e10c 100644 --- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp +++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp @@ -79,6 +79,7 @@ private slots: void messaging_sendQObjectList(); void messaging_sendJsObject(); void script_with_pragma(); + void script_included(); void scriptError_onLoad(); void scriptError_onCall(); @@ -226,6 +227,24 @@ void tst_QDeclarativeWorkerScript::script_with_pragma() delete worker; } +void tst_QDeclarativeWorkerScript::script_included() +{ + QDeclarativeComponent component(&m_engine, SRCDIR "/data/worker_include.qml"); + QDeclarativeWorkerScript *worker = qobject_cast<QDeclarativeWorkerScript*>(component.create()); + QVERIFY(worker != 0); + + QString value("Hello"); + + QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value))); + waitForEchoMessage(worker); + + const QMetaObject *mo = worker->metaObject(); + QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker).toString(), value + " World"); + + qApp->processEvents(); + delete worker; +} + static QString qdeclarativeworkerscript_lastWarning; static void qdeclarativeworkerscript_warningsHandler(QtMsgType type, const char *msg) { diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.0.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.0.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.0.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.1.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.1.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.1.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.10.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.10.png Binary files differnew file mode 100644 index 0000000..1ccab41 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.10.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.11.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.11.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.11.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.12.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.12.png Binary files differnew file mode 100644 index 0000000..f25bd7c --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.12.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.2.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.2.png Binary files differnew file mode 100644 index 0000000..f25bd7c --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.2.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.3.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.3.png Binary files differnew file mode 100644 index 0000000..dad1de4 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.3.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.4.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.4.png Binary files differnew file mode 100644 index 0000000..cd4f23a --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.4.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.5.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.5.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.5.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.6.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.6.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.6.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.7.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.7.png Binary files differnew file mode 100644 index 0000000..f25bd7c --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.7.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.8.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.8.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.8.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.9.png b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.9.png Binary files differnew file mode 100644 index 0000000..160155e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.9.png diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.qml b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.qml new file mode 100644 index 0000000..e858c11 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/data/reanchor.qml @@ -0,0 +1,1499 @@ +import Qt.VisualTest 4.7 + +VisualTest { + Frame { + msec: 0 + } + Frame { + msec: 16 + image: "reanchor.0.png" + } + Frame { + msec: 32 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 48 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 64 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 80 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 96 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 112 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 128 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 144 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 160 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 176 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 192 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 208 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 224 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 240 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 256 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 272 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 288 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 304 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 320 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 336 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 352 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 368 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 384 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 400 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 416 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 432 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 448 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 464 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 480 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 496 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 512 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 528 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 544 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 560 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 576 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 592 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 608 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 624 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 640 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 656 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 672 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 688 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 704 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 720 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 736 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 752 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 768 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 784 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 800 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 816 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 832 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 848 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 864 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 880 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 896 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 912 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 928 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 944 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 960 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 976 + image: "reanchor.1.png" + } + Frame { + msec: 992 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1008 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1024 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1040 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1056 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 164; y: 196 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1072 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1088 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1104 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1120 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1136 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 164; y: 196 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1152 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 1168 + hash: "f7814217626627ce70ca0e9487354ba9" + } + Frame { + msec: 1184 + hash: "7825b2b77e441ca6f46dbca80c7fe602" + } + Frame { + msec: 1200 + hash: "0ac443a9946b0bcf8db768af7d16d51e" + } + Frame { + msec: 1216 + hash: "c943d5d46f0d527690f38a9c8bd7be51" + } + Frame { + msec: 1232 + hash: "38151db0c9964d33bcb2ff155ebd468c" + } + Frame { + msec: 1248 + hash: "0fb8c53587a95a12cced6d30018edec1" + } + Frame { + msec: 1264 + hash: "2c684a649652270a638aca41a80e327c" + } + Frame { + msec: 1280 + hash: "60dd5c448ef8b97ec13ad3140a584229" + } + Frame { + msec: 1296 + hash: "d564f28f9d528daca729db6fab163b6c" + } + Frame { + msec: 1312 + hash: "4c07b33632ec4f30ee31141099c15a88" + } + Frame { + msec: 1328 + hash: "9facfd27fa16ee9d493e7fb7bcfadbf8" + } + Frame { + msec: 1344 + hash: "fc0fbb8aac8f389841e615be1e7b06de" + } + Frame { + msec: 1360 + hash: "579c18fa201b5609276c761ffd42df33" + } + Frame { + msec: 1376 + hash: "5b3630c37acfc2599a5a8b2e11aaa34c" + } + Frame { + msec: 1392 + hash: "2c1ee8aca06dccf0d39287721bf76aa7" + } + Frame { + msec: 1408 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1424 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1440 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1456 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1472 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1488 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1504 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1520 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1536 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1552 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1568 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1584 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1600 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1616 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1632 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1648 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1664 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1680 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1696 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1712 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1728 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1744 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1760 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1776 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1792 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1808 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1824 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1840 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1856 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1872 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1888 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1904 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1920 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1936 + image: "reanchor.2.png" + } + Frame { + msec: 1952 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1968 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 1984 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2000 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2016 + hash: "c03bb338fff252a100b080366ac907b5" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 170; y: 120 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2032 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2048 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2064 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2080 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2096 + hash: "c03bb338fff252a100b080366ac907b5" + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 170; y: 120 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2112 + hash: "c03bb338fff252a100b080366ac907b5" + } + Frame { + msec: 2128 + hash: "e9d7372c17ca1510eb15faff5d0794b2" + } + Frame { + msec: 2144 + hash: "60f897e2b9594c4b5c02ce2fbdf9ae3c" + } + Frame { + msec: 2160 + hash: "c35ead9a8e682e8f3c0a091d232310f7" + } + Frame { + msec: 2176 + hash: "272632b0568391022590edc09ea30e28" + } + Frame { + msec: 2192 + hash: "9d4cdb31b01e86a31627e3ff9bb64100" + } + Frame { + msec: 2208 + hash: "5ee65b0290721fe47508c6435c18554b" + } + Frame { + msec: 2224 + hash: "8dd65e1a9417318d793d2027de4fe6ae" + } + Frame { + msec: 2240 + hash: "bcce6d1fd7d2c1539ad9ac42c0552d5e" + } + Frame { + msec: 2256 + hash: "e01f5850113c178da3383406fe73d6e0" + } + Frame { + msec: 2272 + hash: "968fc6b2bf6b7d43e05254339cf6123f" + } + Frame { + msec: 2288 + hash: "30f25fdde31e13934e328fa1d2655ccb" + } + Frame { + msec: 2304 + hash: "f58a21e96037813c9dd7f933405c9b11" + } + Frame { + msec: 2320 + hash: "1fe42c887f2eaf7696fcf0b8b884d0fd" + } + Frame { + msec: 2336 + hash: "848a27b9e4f4c0bcc1a11d6dba7ce92b" + } + Frame { + msec: 2352 + hash: "ca92736257db83e39f54b04325201942" + } + Frame { + msec: 2368 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 2384 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 134; y: 106 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2400 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 2416 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 2432 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 2448 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 2464 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 134; y: 106 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2480 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 2496 + hash: "9082504eee5e0c3cbef9fd9545f09dcb" + } + Frame { + msec: 2512 + hash: "dbe5169edb4400c74841a8af64e0949f" + } + Frame { + msec: 2528 + hash: "d588405fc5e2423cdb954c5624172209" + } + Frame { + msec: 2544 + hash: "ed2b273ea36fb7d8feaca4d5dae72f81" + } + Frame { + msec: 2560 + hash: "5249e4824eb169b5ee3f7fb52fe09aa7" + } + Frame { + msec: 2576 + hash: "2838eff2a1a299c9e47cf78be99172ca" + } + Frame { + msec: 2592 + hash: "c47f6a937a4a6ef045159d7ba04de8af" + } + Frame { + msec: 2608 + hash: "fd3bc1b9ba2629bccb0fec04deffcdad" + } + Frame { + msec: 2624 + hash: "54c9b8599a32ac95aff324977b34f7e6" + } + Frame { + msec: 2640 + hash: "cc5652a05828146cdc9c9b8430f5f59c" + } + Frame { + msec: 2656 + hash: "ce5815fb51a4bd697a2fde46084e118b" + } + Frame { + msec: 2672 + hash: "01dfd2604263f1fd24382ce876af10f9" + } + Frame { + msec: 2688 + hash: "45ea282d20ee9e345eb2cac8c22c42e0" + } + Frame { + msec: 2704 + hash: "afd26ac9776e57c94e4b52ebfeb7206c" + } + Frame { + msec: 2720 + hash: "97aeed321d4d92cb1ec236d2a98fbe9b" + } + Mouse { + type: 4 + button: 1 + buttons: 1 + x: 134; y: 106 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2736 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 2752 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 2768 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 2784 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 2800 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 134; y: 106 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2816 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 2832 + hash: "81b8228c6aeefe8072b7704f11e6707e" + } + Frame { + msec: 2848 + hash: "617e416bf117a51b756c90321ebb1449" + } + Frame { + msec: 2864 + hash: "656d8d5d54c9ee137aceb519aff72cce" + } + Frame { + msec: 2880 + hash: "94ba3b6f558c010cdd32f54cce436388" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 134; y: 106 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2896 + image: "reanchor.3.png" + } + Frame { + msec: 2912 + hash: "0bc822fdd4caac17aab80e8601d3a523" + } + Frame { + msec: 2928 + hash: "886d0407ac76d7344f7a314f07b3efff" + } + Frame { + msec: 2944 + hash: "eb6c46af5037f24348edbe0dda48fb62" + } + Frame { + msec: 2960 + hash: "1c578a1eeb67c6833241bcb3214f06fb" + } + Frame { + msec: 2976 + hash: "55f1631ef567217a5945b2a23c59b549" + } + Frame { + msec: 2992 + hash: "25fdd4d54ddb035b082dc3a0d0816114" + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 134; y: 106 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3008 + hash: "25fdd4d54ddb035b082dc3a0d0816114" + } + Frame { + msec: 3024 + hash: "efd61e7c1aaffec77bd3d2de6645b2c0" + } + Frame { + msec: 3040 + hash: "02ac5ca0fa7d2ec3903fccd5dc556fa5" + } + Frame { + msec: 3056 + hash: "daf52e45b8fc68f74e424554074678cc" + } + Frame { + msec: 3072 + hash: "9e2def87e83b0c4b9f26684665aa1e51" + } + Frame { + msec: 3088 + hash: "0e72fc762cc9a061e91692376d65d292" + } + Frame { + msec: 3104 + hash: "c5ac37e4a5250b35a4976bcb31505cca" + } + Frame { + msec: 3120 + hash: "eefe6bb7963c580c68198ee6098a36f4" + } + Frame { + msec: 3136 + hash: "7b78d77ac11b72d1fb827ebb66a04c8e" + } + Frame { + msec: 3152 + hash: "ce5815fb51a4bd697a2fde46084e118b" + } + Frame { + msec: 3168 + hash: "94ba3b6f558c010cdd32f54cce436388" + } + Frame { + msec: 3184 + hash: "61a56140e5a6a2bfcee5c6322b37e130" + } + Frame { + msec: 3200 + hash: "a67b22c0a966fe3fbe869497dc00960f" + } + Frame { + msec: 3216 + hash: "4edd212676ac93ae761039e80f989349" + } + Frame { + msec: 3232 + hash: "fea5797441d65625c400238f73d94807" + } + Frame { + msec: 3248 + hash: "23e9209ff0257343016cffdf7ea6571c" + } + Frame { + msec: 3264 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3280 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3296 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3312 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3328 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3344 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3360 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3376 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3392 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3408 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3424 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3440 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3456 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3472 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3488 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3504 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3520 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3536 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3552 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3568 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3584 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3600 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3616 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3632 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3648 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3664 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3680 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3696 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3712 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3728 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3744 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3760 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3776 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3792 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3808 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3824 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3840 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3856 + image: "reanchor.4.png" + } + Frame { + msec: 3872 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3888 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3904 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3920 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3936 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3952 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3968 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 3984 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4000 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4016 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4032 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4048 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4064 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4080 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4096 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4112 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4128 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4144 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4160 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4176 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 124; y: 113 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4192 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4208 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4224 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4240 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4256 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 124; y: 113 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4272 + hash: "3a1fc9be558078e35a9828e411847c19" + } + Frame { + msec: 4288 + hash: "81b8228c6aeefe8072b7704f11e6707e" + } + Frame { + msec: 4304 + hash: "617e416bf117a51b756c90321ebb1449" + } + Frame { + msec: 4320 + hash: "656d8d5d54c9ee137aceb519aff72cce" + } + Frame { + msec: 4336 + hash: "94ba3b6f558c010cdd32f54cce436388" + } + Frame { + msec: 4352 + hash: "5b0679ff3730cba4ac026e89c7811fbe" + } + Frame { + msec: 4368 + hash: "0bc822fdd4caac17aab80e8601d3a523" + } + Frame { + msec: 4384 + hash: "886d0407ac76d7344f7a314f07b3efff" + } + Frame { + msec: 4400 + hash: "eb6c46af5037f24348edbe0dda48fb62" + } + Frame { + msec: 4416 + hash: "1c578a1eeb67c6833241bcb3214f06fb" + } + Frame { + msec: 4432 + hash: "55f1631ef567217a5945b2a23c59b549" + } + Frame { + msec: 4448 + hash: "25fdd4d54ddb035b082dc3a0d0816114" + } + Frame { + msec: 4464 + hash: "295ea6ff4d3c2c7de0cfbc29b2bd2c38" + } + Frame { + msec: 4480 + hash: "26b978ab645c04731703bcf15ac34a11" + } + Frame { + msec: 4496 + hash: "0db4c2515b89506df51732c4b9bf75dc" + } + Frame { + msec: 4512 + hash: "3cf30f3a06e325e195a4a7dec1e04c01" + } + Frame { + msec: 4528 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4544 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4560 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4576 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4592 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4608 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4624 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4640 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4656 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4672 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4688 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4704 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4720 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4736 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4752 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4768 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4784 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4800 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4816 + image: "reanchor.5.png" + } + Frame { + msec: 4832 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4848 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4864 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4880 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4896 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4912 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4928 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4944 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4960 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4976 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 4992 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5008 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5024 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5040 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5056 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5072 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5088 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5104 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5120 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5136 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5152 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5168 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5184 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5200 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5216 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5232 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5248 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5264 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5280 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5296 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5312 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5328 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5344 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5360 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5376 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5392 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5408 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5424 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5440 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5456 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5472 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5488 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5504 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5520 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5536 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5552 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5568 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } + Frame { + msec: 5584 + hash: "0009d8bfdfaed2a4f05aacb7a7992234" + } +} diff --git a/tests/auto/declarative/qmlvisual/animation/reanchorRTL/reanchor.qml b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/reanchor.qml new file mode 100644 index 0000000..ba37737 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/animation/reanchorRTL/reanchor.qml @@ -0,0 +1,69 @@ +import QtQuick 1.1 + +Rectangle { + id: container + width: 200; height: 200 + Rectangle { + id: myRect + anchors.layoutDirection: Qt.RightToLeft + objectName: "MyRect" + color: "green"; + anchors.left: parent.left + anchors.right: rightGuideline.left + anchors.top: topGuideline.top + anchors.bottom: container.bottom + } + Item { id: leftGuideline; x: 10 } + Item { id: rightGuideline; x: 150 } + Item { id: topGuideline; y: 10 } + Item { id: bottomGuideline; y: 150 } + Item { id: topGuideline2; y: 50 } + Item { id: bottomGuideline2; y: 175 } + MouseArea { + id: wholeArea + anchors.fill: parent + onClicked: { + if (container.state == "") { + container.state = "reanchored"; + } else if (container.state == "reanchored") { + container.state = "reanchored2"; + } else if (container.state == "reanchored2") + container.state = "reanchored"; + } + } + + states: [ State { + name: "reanchored" + AnchorChanges { + target: myRect; + anchors.left: leftGuideline.left + anchors.right: container.right + anchors.top: container.top + anchors.bottom: bottomGuideline.bottom + } + }, State { + name: "reanchored2" + AnchorChanges { + target: myRect; + anchors.left: undefined + anchors.right: undefined + anchors.top: topGuideline2.top + anchors.bottom: bottomGuideline2.bottom + } + }] + + transitions: Transition { + AnchorAnimation { } + } + + MouseArea { + width: 50; height: 50 + anchors.right: parent.right + anchors.bottom: parent.bottom + onClicked: { + container.state = ""; + } + } + + state: "reanchored" +} |