diff options
Diffstat (limited to 'tests/auto/quick/qquickrepeater')
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/asyncloader.qml | 32 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/initparent.qml | 12 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/intmodel.qml | 29 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/itemlist.qml | 68 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/modelChanged.qml | 26 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/objlist.qml | 21 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/properties.qml | 11 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/repeater1.qml | 30 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/data/repeater2.qml | 36 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/qquickrepeater.pro | 15 | ||||
-rw-r--r-- | tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp | 644 |
11 files changed, 924 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickrepeater/data/asyncloader.qml b/tests/auto/quick/qquickrepeater/data/asyncloader.qml new file mode 100644 index 0000000000..82094e2666 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/asyncloader.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Item { + width: 360 + height: 480 + + Loader { + asynchronous: true + sourceComponent: viewComponent + } + + Component { + id: viewComponent + Column { + objectName: "container" + Repeater { + id: repeater + objectName: "repeater" + + model: 10 + + delegate: Rectangle { + objectName: "delegate" + index + color: "red" + width: 360 + height: 50 + Text { text: index } + } + } + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/initparent.qml b/tests/auto/quick/qquickrepeater/data/initparent.qml new file mode 100644 index 0000000000..e6571f09d3 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/initparent.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Item { + id: root + property Item parentItem: null + Repeater { + model: 1 + Item { + Component.onCompleted: root.parentItem = parent + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/intmodel.qml b/tests/auto/quick/qquickrepeater/data/intmodel.qml new file mode 100644 index 0000000000..30a650dd52 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/intmodel.qml @@ -0,0 +1,29 @@ +import QtQuick 2.0 + +Rectangle { + id: container + objectName: "container" + width: 240 + height: 320 + color: "white" + + function checkProperties() { + testObject.error = false; + if (repeater.delegate != comp) { + console.log("delegate property incorrect"); + testObject.error = true; + } + } + + Component { + id: comp + Item{} + } + + Repeater { + id: repeater + objectName: "repeater" + model: testData + delegate: comp + } +} diff --git a/tests/auto/quick/qquickrepeater/data/itemlist.qml b/tests/auto/quick/qquickrepeater/data/itemlist.qml new file mode 100644 index 0000000000..174bfd4d18 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/itemlist.qml @@ -0,0 +1,68 @@ +// This example demonstrates placing items in a view using +// a VisualItemModel + +import QtQuick 2.0 + +Rectangle { + id: root + color: "lightgray" + width: 240 + height: 320 + property variant itemModel: itemModel1 + + function checkProperties() { + testObject.error = false; + if (testObject.useModel && view.model != root.itemModel) { + console.log("model property incorrect"); + testObject.error = true; + } + } + + function switchModel() { + root.itemModel = itemModel2 + } + + VisualItemModel { + id: itemModel1 + objectName: "itemModel1" + Rectangle { + objectName: "item1" + height: 50; width: 100; color: "#FFFEF0" + Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item2" + height: 50; width: 100; color: "#F0FFF7" + Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item3" + height: 50; width: 100; color: "#F4F0FF" + Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + } + + VisualItemModel { + id: itemModel2 + objectName: "itemModel2" + Rectangle { + objectName: "item4" + height: 50; width: 100; color: "#FFFEF0" + Text { objectName: "text4"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + Rectangle { + objectName: "item5" + height: 50; width: 100; color: "#F0FFF7" + Text { objectName: "text5"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + } + } + + Column { + objectName: "container" + Repeater { + id: view + objectName: "repeater" + model: testObject.useModel ? root.itemModel : 0 + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/modelChanged.qml b/tests/auto/quick/qquickrepeater/data/modelChanged.qml new file mode 100644 index 0000000000..23af127e79 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/modelChanged.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 + +Column { + Repeater { + id: repeater + objectName: "repeater" + + property int itemsCount + property variant itemsFound: [] + + delegate: Rectangle { + color: "red" + width: (index+1)*50 + height: 50 + } + + onModelChanged: { + repeater.itemsCount = repeater.count + var items = [] + for (var i=0; i<repeater.count; i++) + items.push(repeater.itemAt(i)) + repeater.itemsFound = items + } + } +} + diff --git a/tests/auto/quick/qquickrepeater/data/objlist.qml b/tests/auto/quick/qquickrepeater/data/objlist.qml new file mode 100644 index 0000000000..c49d5926e5 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/objlist.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 + +Rectangle { + id: container + objectName: "container" + width: 240 + height: 320 + color: "white" + Repeater { + id: repeater + objectName: "repeater" + model: testData + property int errors: 0 + property int instantiated: 0 + Component { + Item{ + Component.onCompleted: {if(index!=modelData.idx) repeater.errors += 1; repeater.instantiated++} + } + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/properties.qml b/tests/auto/quick/qquickrepeater/data/properties.qml new file mode 100644 index 0000000000..035431c784 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/properties.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Row { + Repeater { + objectName: "repeater" + model: 5 + Text { + text: "I'm item " + index + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/repeater1.qml b/tests/auto/quick/qquickrepeater/data/repeater1.qml new file mode 100644 index 0000000000..3e6f4071ff --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/repeater1.qml @@ -0,0 +1,30 @@ +import QtQuick 2.0 + +Item { + Rectangle { + id: container + objectName: "container" + width: 240 + height: 320 + color: "white" + Text { + text: "Zero" + } + Repeater { + id: repeater + objectName: "repeater" + width: 240 + height: 320 + model: testData + Component { + Text { + y: index*20 + text: modelData + } + } + } + Text { + text: "Last" + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/repeater2.qml b/tests/auto/quick/qquickrepeater/data/repeater2.qml new file mode 100644 index 0000000000..691fbda1e5 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/repeater2.qml @@ -0,0 +1,36 @@ +import QtQuick 2.0 + +Rectangle { + width: 240 + height: 320 + color: "white" + Component { + id: myDelegate + Item { + objectName: "myDelegate" + height: 20 + width: 240 + Text { + objectName: "myName" + text: name + } + Text { + objectName: "myNumber" + x: 100 + text: number + } + } + } + Column { + id: container + objectName: "container" + Repeater { + id: repeater + objectName: "repeater" + width: 240 + height: 320 + delegate: myDelegate + model: testData + } + } +} diff --git a/tests/auto/quick/qquickrepeater/qquickrepeater.pro b/tests/auto/quick/qquickrepeater/qquickrepeater.pro new file mode 100644 index 0000000000..c3d96ee6d5 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/qquickrepeater.pro @@ -0,0 +1,15 @@ +CONFIG += testcase +TARGET = tst_qquickrepeater +macx:CONFIG -= app_bundle + +SOURCES += tst_qquickrepeater.cpp + +include (../../shared/util.pri) +include (../shared/util.pri) + +testFiles.files = data +testFiles.path = . +DEPLOYMENT += testFiles + +CONFIG += parallel_test +QT += core-private gui-private qml-private quick-private testlib diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp new file mode 100644 index 0000000000..1b07a6e9f8 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp @@ -0,0 +1,644 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtTest/QSignalSpy> +#include <private/qlistmodelinterface_p.h> +#include <QtQml/qqmlengine.h> +#include <QtQuick/qquickview.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlexpression.h> +#include <QtQml/qqmlincubator.h> +#include <private/qquickrepeater_p.h> +#include <QtQuick/private/qquicktext_p.h> + +#include "../../shared/util.h" +#include "../shared/viewtestutil.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickViewTestUtil; +using namespace QQuickVisualTestUtil; + + +class tst_QQuickRepeater : public QQmlDataTest +{ + Q_OBJECT +public: + tst_QQuickRepeater(); + +private slots: + void numberModel(); + void objectList(); + void stringList(); + void dataModel_adding(); + void dataModel_removing(); + void dataModel_changes(); + void itemModel(); + void resetModel(); + void modelChanged(); + void properties(); + void asynchronous(); + void initParent(); +}; + +class TestObject : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool error READ error WRITE setError) + Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged) + +public: + TestObject() : QObject(), mError(true), mUseModel(false) {} + + bool error() const { return mError; } + void setError(bool err) { mError = err; } + + bool useModel() const { return mUseModel; } + void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); } + +signals: + void useModelChanged(); + +private: + bool mError; + bool mUseModel; +}; + +tst_QQuickRepeater::tst_QQuickRepeater() +{ +} + +void tst_QQuickRepeater::numberModel() +{ + QQuickView *canvas = createView(); + + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testData", 5); + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + canvas->setSource(testFileUrl("intmodel.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + QCOMPARE(repeater->parentItem()->childItems().count(), 5+1); + + QVERIFY(!repeater->itemAt(-1)); + for (int i=0; i<repeater->count(); i++) + QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i)); + QVERIFY(!repeater->itemAt(repeater->count())); + + QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties"); + QVERIFY(testObject->error() == false); + + delete testObject; + delete canvas; +} + +class MyObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int idx READ idx CONSTANT) +public: + MyObject(int i) : QObject(), m_idx(i) {} + + int idx() const { return m_idx; } + + int m_idx; +}; + +void tst_QQuickRepeater::objectList() +{ + QQuickView *canvas = createView(); + QObjectList data; + for (int i=0; i<100; i++) + data << new MyObject(i); + + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testData", QVariant::fromValue(data)); + + canvas->setSource(testFileUrl("objlist.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + QCOMPARE(repeater->property("errors").toInt(), 0);//If this fails either they are out of order or can't find the object's data + QCOMPARE(repeater->property("instantiated").toInt(), 100); + + QVERIFY(!repeater->itemAt(-1)); + for (int i=0; i<data.count(); i++) + QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i)); + QVERIFY(!repeater->itemAt(data.count())); + + QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QQuickItem*))); + QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QQuickItem*))); + ctxt->setContextProperty("testData", QVariant::fromValue(data)); + QCOMPARE(addedSpy.count(), data.count()); + QCOMPARE(removedSpy.count(), data.count()); + + qDeleteAll(data); + delete canvas; +} + +/* +The Repeater element creates children at its own position in its parent's +stacking order. In this test we insert a repeater between two other Text +elements to test this. +*/ +void tst_QQuickRepeater::stringList() +{ + QQuickView *canvas = createView(); + + QStringList data; + data << "One"; + data << "Two"; + data << "Three"; + data << "Four"; + + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testData", data); + + canvas->setSource(testFileUrl("repeater1.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + + QQuickItem *container = findItem<QQuickItem>(canvas->rootObject(), "container"); + QVERIFY(container != 0); + + QCOMPARE(container->childItems().count(), data.count() + 3); + + bool saw_repeater = false; + for (int i = 0; i < container->childItems().count(); ++i) { + + if (i == 0) { + QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i)); + QVERIFY(name != 0); + QCOMPARE(name->text(), QLatin1String("Zero")); + } else if (i == container->childItems().count() - 2) { + // The repeater itself + QQuickRepeater *rep = qobject_cast<QQuickRepeater*>(container->childItems().at(i)); + QCOMPARE(rep, repeater); + saw_repeater = true; + continue; + } else if (i == container->childItems().count() - 1) { + QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i)); + QVERIFY(name != 0); + QCOMPARE(name->text(), QLatin1String("Last")); + } else { + QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i)); + QVERIFY(name != 0); + QCOMPARE(name->text(), data.at(i-1)); + } + } + QVERIFY(saw_repeater); + + delete canvas; +} + +void tst_QQuickRepeater::dataModel_adding() +{ + QQuickView *canvas = createView(); + QQmlContext *ctxt = canvas->rootContext(); + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + QaimModel testModel; + ctxt->setContextProperty("testData", &testModel); + canvas->setSource(testFileUrl("repeater2.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + QQuickItem *container = findItem<QQuickItem>(canvas->rootObject(), "container"); + QVERIFY(container != 0); + + QVERIFY(!repeater->itemAt(0)); + + QSignalSpy countSpy(repeater, SIGNAL(countChanged())); + QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QQuickItem*))); + + // add to empty model + testModel.addItem("two", "2"); + QCOMPARE(repeater->itemAt(0), container->childItems().at(0)); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(addedSpy.count(), 1); + QCOMPARE(addedSpy.at(0).at(0).toInt(), 0); + QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(0)); + addedSpy.clear(); + + // insert at start + testModel.insertItem(0, "one", "1"); + QCOMPARE(repeater->itemAt(0), container->childItems().at(0)); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(addedSpy.count(), 1); + QCOMPARE(addedSpy.at(0).at(0).toInt(), 0); + QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(0)); + addedSpy.clear(); + + // insert at end + testModel.insertItem(2, "four", "4"); + QCOMPARE(repeater->itemAt(2), container->childItems().at(2)); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(addedSpy.count(), 1); + QCOMPARE(addedSpy.at(0).at(0).toInt(), 2); + QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(2)); + addedSpy.clear(); + + // insert in middle + testModel.insertItem(2, "three", "3"); + QCOMPARE(repeater->itemAt(2), container->childItems().at(2)); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(addedSpy.count(), 1); + QCOMPARE(addedSpy.at(0).at(0).toInt(), 2); + QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(2)); + addedSpy.clear(); + + delete testObject; + addedSpy.clear(); + countSpy.clear(); + delete canvas; +} + +void tst_QQuickRepeater::dataModel_removing() +{ + QQuickView *canvas = createView(); + QQmlContext *ctxt = canvas->rootContext(); + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + QaimModel testModel; + testModel.addItem("one", "1"); + testModel.addItem("two", "2"); + testModel.addItem("three", "3"); + testModel.addItem("four", "4"); + testModel.addItem("five", "5"); + + ctxt->setContextProperty("testData", &testModel); + canvas->setSource(testFileUrl("repeater2.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + QQuickItem *container = findItem<QQuickItem>(canvas->rootObject(), "container"); + QVERIFY(container != 0); + QCOMPARE(container->childItems().count(), repeater->count()+1); + + QSignalSpy countSpy(repeater, SIGNAL(countChanged())); + QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QQuickItem*))); + + // remove at start + QQuickItem *item = repeater->itemAt(0); + QCOMPARE(item, container->childItems().at(0)); + + testModel.removeItem(0); + QVERIFY(repeater->itemAt(0) != item); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(removedSpy.count(), 1); + QCOMPARE(removedSpy.at(0).at(0).toInt(), 0); + QCOMPARE(removedSpy.at(0).at(1).value<QQuickItem*>(), item); + removedSpy.clear(); + + // remove at end + int lastIndex = testModel.count()-1; + item = repeater->itemAt(lastIndex); + QCOMPARE(item, container->childItems().at(lastIndex)); + + testModel.removeItem(lastIndex); + QVERIFY(repeater->itemAt(lastIndex) != item); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(removedSpy.count(), 1); + QCOMPARE(removedSpy.at(0).at(0).toInt(), lastIndex); + QCOMPARE(removedSpy.at(0).at(1).value<QQuickItem*>(), item); + removedSpy.clear(); + + // remove from middle + item = repeater->itemAt(1); + QCOMPARE(item, container->childItems().at(1)); + + testModel.removeItem(1); + QVERIFY(repeater->itemAt(lastIndex) != item); + QCOMPARE(countSpy.count(), 1); countSpy.clear(); + QCOMPARE(removedSpy.count(), 1); + QCOMPARE(removedSpy.at(0).at(0).toInt(), 1); + QCOMPARE(removedSpy.at(0).at(1).value<QQuickItem*>(), item); + removedSpy.clear(); + + delete testObject; + delete canvas; +} + +void tst_QQuickRepeater::dataModel_changes() +{ + QQuickView *canvas = createView(); + QQmlContext *ctxt = canvas->rootContext(); + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + QaimModel testModel; + testModel.addItem("one", "1"); + testModel.addItem("two", "2"); + testModel.addItem("three", "3"); + + ctxt->setContextProperty("testData", &testModel); + canvas->setSource(testFileUrl("repeater2.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + QQuickItem *container = findItem<QQuickItem>(canvas->rootObject(), "container"); + QVERIFY(container != 0); + QCOMPARE(container->childItems().count(), repeater->count()+1); + + // Check that model changes are propagated + QQuickText *text = findItem<QQuickText>(canvas->rootObject(), "myName", 1); + QVERIFY(text); + QCOMPARE(text->text(), QString("two")); + + testModel.modifyItem(1, "Item two", "_2"); + text = findItem<QQuickText>(canvas->rootObject(), "myName", 1); + QVERIFY(text); + QCOMPARE(text->text(), QString("Item two")); + + text = findItem<QQuickText>(canvas->rootObject(), "myNumber", 1); + QVERIFY(text); + QCOMPARE(text->text(), QString("_2")); + + delete testObject; + delete canvas; +} + +void tst_QQuickRepeater::itemModel() +{ + QQuickView *canvas = createView(); + QQmlContext *ctxt = canvas->rootContext(); + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + canvas->setSource(testFileUrl("itemlist.qml")); + qApp->processEvents(); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + + QQuickItem *container = findItem<QQuickItem>(canvas->rootObject(), "container"); + QVERIFY(container != 0); + + QCOMPARE(container->childItems().count(), 1); + + testObject->setUseModel(true); + QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties"); + QVERIFY(testObject->error() == false); + + QCOMPARE(container->childItems().count(), 4); + QVERIFY(qobject_cast<QObject*>(container->childItems().at(0))->objectName() == "item1"); + QVERIFY(qobject_cast<QObject*>(container->childItems().at(1))->objectName() == "item2"); + QVERIFY(qobject_cast<QObject*>(container->childItems().at(2))->objectName() == "item3"); + QVERIFY(container->childItems().at(3) == repeater); + + QMetaObject::invokeMethod(canvas->rootObject(), "switchModel"); + QCOMPARE(container->childItems().count(), 3); + QVERIFY(qobject_cast<QObject*>(container->childItems().at(0))->objectName() == "item4"); + QVERIFY(qobject_cast<QObject*>(container->childItems().at(1))->objectName() == "item5"); + QVERIFY(container->childItems().at(2) == repeater); + + testObject->setUseModel(false); + QCOMPARE(container->childItems().count(), 1); + + delete testObject; + delete canvas; +} + +void tst_QQuickRepeater::resetModel() +{ + QQuickView *canvas = createView(); + + QStringList dataA; + for (int i=0; i<10; i++) + dataA << QString::number(i); + + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testData", dataA); + canvas->setSource(testFileUrl("repeater1.qml")); + qApp->processEvents(); + QQuickRepeater *repeater = findItem<QQuickRepeater>(canvas->rootObject(), "repeater"); + QVERIFY(repeater != 0); + QQuickItem *container = findItem<QQuickItem>(canvas->rootObject(), "container"); + QVERIFY(container != 0); + + QCOMPARE(repeater->count(), dataA.count()); + for (int i=0; i<repeater->count(); i++) + QCOMPARE(repeater->itemAt(i), container->childItems().at(i+1)); // +1 to skip first Text object + + QSignalSpy modelChangedSpy(repeater, SIGNAL(modelChanged())); + QSignalSpy countSpy(repeater, SIGNAL(countChanged())); + QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QQuickItem*))); + QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QQuickItem*))); + + QStringList dataB; + for (int i=0; i<20; i++) + dataB << QString::number(i); + + // reset context property + ctxt->setContextProperty("testData", dataB); + QCOMPARE(repeater->count(), dataB.count()); + + QCOMPARE(modelChangedSpy.count(), 1); + QCOMPARE(countSpy.count(), 1); + QCOMPARE(removedSpy.count(), dataA.count()); + QCOMPARE(addedSpy.count(), dataB.count()); + for (int i=0; i<dataB.count(); i++) { + QCOMPARE(addedSpy.at(i).at(0).toInt(), i); + QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i)); + } + modelChangedSpy.clear(); + countSpy.clear(); + removedSpy.clear(); + addedSpy.clear(); + + // reset via setModel() + repeater->setModel(dataA); + QCOMPARE(repeater->count(), dataA.count()); + + QCOMPARE(modelChangedSpy.count(), 1); + QCOMPARE(countSpy.count(), 1); + QCOMPARE(removedSpy.count(), dataB.count()); + QCOMPARE(addedSpy.count(), dataA.count()); + for (int i=0; i<dataA.count(); i++) { + QCOMPARE(addedSpy.at(i).at(0).toInt(), i); + QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i)); + } + + modelChangedSpy.clear(); + countSpy.clear(); + removedSpy.clear(); + addedSpy.clear(); + + delete canvas; +} + +// QTBUG-17156 +void tst_QQuickRepeater::modelChanged() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("modelChanged.qml")); + + QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create()); + QVERIFY(rootObject); + QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater"); + QVERIFY(repeater); + + repeater->setModel(4); + QCOMPARE(repeater->count(), 4); + QCOMPARE(repeater->property("itemsCount").toInt(), 4); + QCOMPARE(repeater->property("itemsFound").toList().count(), 4); + + repeater->setModel(10); + QCOMPARE(repeater->count(), 10); + QCOMPARE(repeater->property("itemsCount").toInt(), 10); + QCOMPARE(repeater->property("itemsFound").toList().count(), 10); + + delete rootObject; +} + +void tst_QQuickRepeater::properties() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("properties.qml")); + + QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create()); + QVERIFY(rootObject); + + QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater"); + QVERIFY(repeater); + + QSignalSpy modelSpy(repeater, SIGNAL(modelChanged())); + repeater->setModel(3); + QCOMPARE(modelSpy.count(),1); + repeater->setModel(3); + QCOMPARE(modelSpy.count(),1); + + QSignalSpy delegateSpy(repeater, SIGNAL(delegateChanged())); + + QQmlComponent rectComponent(&engine); + rectComponent.setData("import QtQuick 2.0; Rectangle {}", QUrl::fromLocalFile("")); + + repeater->setDelegate(&rectComponent); + QCOMPARE(delegateSpy.count(),1); + repeater->setDelegate(&rectComponent); + QCOMPARE(delegateSpy.count(),1); + + delete rootObject; +} + +void tst_QQuickRepeater::asynchronous() +{ + QQuickView *canvas = createView(); + canvas->show(); + QQmlIncubationController controller; + canvas->engine()->setIncubationController(&controller); + + canvas->setSource(testFileUrl("asyncloader.qml")); + + QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject()); + QVERIFY(rootObject); + + QQuickItem *container = findItem<QQuickItem>(rootObject, "container"); + QVERIFY(!container); + while (!container) { + bool b = false; + controller.incubateWhile(&b); + container = findItem<QQuickItem>(rootObject, "container"); + } + + QQuickRepeater *repeater = 0; + while (!repeater) { + bool b = false; + controller.incubateWhile(&b); + repeater = findItem<QQuickRepeater>(rootObject, "repeater"); + } + + // items will be created one at a time + for (int i = 0; i < 10; ++i) { + QString name("delegate"); + name += QString::number(i); + QVERIFY(findItem<QQuickItem>(container, name) == 0); + QQuickItem *item = 0; + while (!item) { + bool b = false; + controller.incubateWhile(&b); + item = findItem<QQuickItem>(container, name); + } + } + + { + bool b = true; + controller.incubateWhile(&b); + } + + // verify positioning + for (int i = 0; i < 10; ++i) { + QString name("delegate"); + name += QString::number(i); + QQuickItem *item = findItem<QQuickItem>(container, name); + QTRY_COMPARE(item->y(), i * 50.0); + } + + delete canvas; +} + +void tst_QQuickRepeater::initParent() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("initparent.qml")); + + QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create()); + QVERIFY(rootObject); + + QCOMPARE(qvariant_cast<QQuickItem*>(rootObject->property("parentItem")), rootObject); +} + +QTEST_MAIN(tst_QQuickRepeater) + +#include "tst_qquickrepeater.moc" |