section.property cannot deal with nested properties
[profile/ivi/qtdeclarative.git] / tests / auto / quick / qquickvisualdatamodel / tst_qquickvisualdatamodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include "../../shared/util.h"
42 #include "../shared/visualtestutil.h"
43 #include "../shared/viewtestutil.h"
44
45 #include <qtest.h>
46 #include <QtTest/QSignalSpy>
47 #include <QtQml/qqmlengine.h>
48 #include <QtQml/qqmlcomponent.h>
49 #include <QtQml/qqmlcontext.h>
50 #include <QtQml/qqmlexpression.h>
51 #include <QtQml/qqmlincubator.h>
52 #include <QtQuick/qquickview.h>
53 #include <private/qquicklistview_p.h>
54 #include <QtQuick/private/qquicktext_p.h>
55 #include <QtQuick/private/qquickvisualdatamodel_p.h>
56 #include <private/qqmlvaluetype_p.h>
57 #include <private/qquickchangeset_p.h>
58 #include <private/qqmlengine_p.h>
59 #include <math.h>
60
61 using namespace QQuickVisualTestUtil;
62 using namespace QQuickViewTestUtil;
63
64 template <typename T, int N> int lengthOf(const T (&)[N]) { return N; }
65
66 #ifndef QT_NO_WIDGETS
67 #include <QStandardItemModel>
68 static void initStandardTreeModel(QStandardItemModel *model)
69 {
70     QStandardItem *item;
71     item = new QStandardItem(QLatin1String("Row 1 Item"));
72     model->insertRow(0, item);
73
74     item = new QStandardItem(QLatin1String("Row 2 Item"));
75     item->setCheckable(true);
76     model->insertRow(1, item);
77
78     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
79     item->setChild(0, childItem);
80
81     item = new QStandardItem(QLatin1String("Row 3 Item"));
82     item->setIcon(QIcon());
83     model->insertRow(2, item);
84 }
85 #endif
86
87 class SingleRoleModel : public QAbstractListModel
88 {
89     Q_OBJECT
90     Q_PROPERTY(QStringList values READ getList WRITE setList)
91 public:
92     SingleRoleModel(const QByteArray &role = "name", QObject *parent = 0)
93         : QAbstractListModel(parent)
94     {
95         QHash<int, QByteArray> roles;
96         roles.insert(Qt::DisplayRole , role);
97         setRoleNames(roles);
98         list << "one" << "two" << "three" << "four";
99     }
100
101     void emitMove(int sourceFirst, int sourceLast, int destinationChild) {
102         emit beginMoveRows(QModelIndex(), sourceFirst, sourceLast, QModelIndex(), destinationChild);
103         emit endMoveRows();
104     }
105
106     QStringList list;
107
108     QStringList getList() const { return list; }
109     void setList(const QStringList &l) { list = l; }
110
111 public slots:
112     void set(int idx, QString string) {
113         list[idx] = string;
114         emit dataChanged(index(idx,0), index(idx,0));
115     }
116
117 protected:
118     int rowCount(const QModelIndex & /* parent */ = QModelIndex()) const {
119         return list.count();
120     }
121     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
122         if (role == Qt::DisplayRole)
123             return list.at(index.row());
124         return QVariant();
125     }
126 };
127
128 #ifndef QT_NO_WIDGETS
129 class StandardItem : public QObject, public QStandardItem
130 {
131     Q_OBJECT
132     Q_PROPERTY(QString text READ readText WRITE setText)
133
134 public:
135     QString readText() const { return text(); }
136     void writeText(const QString &text) { setText(text); }
137 };
138
139 class StandardItemModel : public QStandardItemModel
140 {
141     Q_OBJECT
142     Q_PROPERTY(QQmlListProperty<StandardItem> items READ items CONSTANT)
143     Q_CLASSINFO("DefaultProperty", "items")
144 public:
145     QQmlListProperty<StandardItem> items() { return QQmlListProperty<StandardItem>(this, 0, append); }
146
147     static void append(QQmlListProperty<StandardItem> *property, StandardItem *item)
148     {
149         static_cast<QStandardItemModel *>(property->object)->appendRow(item);
150     }
151 };
152 #endif
153
154 class DataSubObject : public QObject
155 {
156     Q_OBJECT
157
158     Q_PROPERTY(QString subName READ subName WRITE setSubName NOTIFY subNameChanged)
159
160 public:
161     DataSubObject(QObject *parent=0) : QObject(parent) {}
162
163     QString subName() const { return m_subName; }
164     void setSubName(const QString &name) {
165         if (name != m_subName) {
166             m_subName = name;
167             emit subNameChanged();
168         }
169     }
170
171 signals:
172     void subNameChanged();
173
174 private:
175     QString m_subName;
176 };
177
178 class DataObject : public QObject
179 {
180     Q_OBJECT
181
182     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
183     Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
184     Q_PROPERTY(QObject *object READ object)
185
186 public:
187     DataObject(QObject *parent=0) : QObject(parent) {}
188     DataObject(const QString &name, const QString &color, QObject *parent=0)
189         : QObject(parent), m_name(name), m_color(color), m_object(new DataSubObject(this)) { }
190
191
192     QString name() const { return m_name; }
193     void setName(const QString &name) {
194         if (name != m_name) {
195             m_name = name;
196             emit nameChanged();
197         }
198     }
199
200     QString color() const { return m_color; }
201     void setColor(const QString &color) {
202         if (color != m_color) {
203             m_color = color;
204             emit colorChanged();
205         }
206     }
207
208     QObject *object() const { return m_object; }
209     void setSubName(const QString &sn) {
210         m_object->setSubName(sn);
211     }
212
213 signals:
214     void nameChanged();
215     void colorChanged();
216
217 private:
218     QString m_name;
219     QString m_color;
220     DataSubObject *m_object;
221 };
222
223 class ItemRequester : public QObject
224 {
225     Q_OBJECT
226 public:
227     ItemRequester(QObject *parent = 0)
228         : QObject(parent)
229         , itemInitialized(0)
230         , itemCreated(0)
231         , itemDestroyed(0)
232         , indexInitialized(-1)
233         , indexCreated(-1)
234     {
235     }
236
237     QQuickItem *itemInitialized;
238     QQuickItem *itemCreated;
239     QQuickItem *itemDestroyed;
240     int indexInitialized;
241     int indexCreated;
242
243 public Q_SLOTS:
244     void initItem(int index, QQuickItem *item)
245     {
246         itemInitialized = item;
247         indexInitialized = index;
248     }
249
250     void createdItem(int index, QQuickItem *item)
251     {
252         itemCreated = item;
253         indexCreated = index;
254     }
255
256     void destroyingItem(QQuickItem *item)
257     {
258         itemDestroyed = item;
259     }
260 };
261
262 QML_DECLARE_TYPE(SingleRoleModel)
263 QML_DECLARE_TYPE(DataObject)
264 #ifndef QT_NO_WIDGETS
265 QML_DECLARE_TYPE(StandardItem)
266 QML_DECLARE_TYPE(StandardItemModel)
267 #endif
268
269 class tst_qquickvisualdatamodel : public QQmlDataTest
270 {
271     Q_OBJECT
272 public:
273     tst_qquickvisualdatamodel();
274
275 private slots:
276     void initTestCase();
277     void cleanupTestCase();
278 #ifndef QT_NO_WIDGETS
279     void rootIndex();
280     void updateLayout_data();
281     void updateLayout();
282     void childChanged_data();
283     void childChanged();
284     void noDelegate_data();
285     void noDelegate();
286     void itemsDestroyed_data();
287     void itemsDestroyed();
288 #endif
289     void objectListModel();
290     void singleRole();
291     void modelProperties();
292     void packagesDestroyed();
293     void qaimRowsMoved();
294     void qaimRowsMoved_data();
295     void remove_data();
296     void remove();
297     void move_data();
298     void move();
299     void groups_data();
300     void groups();
301     void invalidGroups();
302     void get();
303     void onChanged_data();
304     void onChanged();
305     void create();
306     void incompleteModel();
307     void insert_data();
308     void insert();
309     void resolve_data();
310     void resolve();
311     void warnings_data();
312     void warnings();
313     void invalidAttachment();
314     void asynchronousInsert_data();
315     void asynchronousInsert();
316     void asynchronousRemove_data();
317     void asynchronousRemove();
318     void asynchronousMove();
319     void asynchronousMove_data();
320     void asynchronousCancel();
321
322 private:
323     template <int N> void groups_verify(
324             const SingleRoleModel &model,
325             QQuickItem *contentItem,
326             const int (&mIndex)[N],
327             const int (&iIndex)[N],
328             const int (&vIndex)[N],
329             const int (&sIndex)[N],
330             const bool (&vMember)[N],
331             const bool (&sMember)[N]);
332
333     template <int N> void get_verify(
334             const SingleRoleModel &model,
335             QQuickVisualDataModel *visualModel,
336             QQuickVisualDataGroup *visibleItems,
337             QQuickVisualDataGroup *selectedItems,
338             const int (&mIndex)[N],
339             const int (&iIndex)[N],
340             const int (&vIndex)[N],
341             const int (&sIndex)[N],
342             const bool (&vMember)[N],
343             const bool (&sMember)[N]);
344
345     bool failed;
346     QQmlIncubationController controller;
347     QQmlEngine engine;
348 };
349
350 Q_DECLARE_METATYPE(QQuickChangeSet)
351
352 template <typename T> static T evaluate(QObject *scope, const QString &expression)
353 {
354     QQmlExpression expr(qmlContext(scope), scope, expression);
355     T result = expr.evaluate().value<T>();
356     if (expr.hasError())
357         qWarning() << expr.error().toString();
358     return result;
359 }
360
361 template <> void evaluate<void>(QObject *scope, const QString &expression)
362 {
363     QQmlExpression expr(qmlContext(scope), scope, expression);
364     expr.evaluate();
365     if (expr.hasError())
366         qWarning() << expr.error().toString();
367 }
368
369 void tst_qquickvisualdatamodel::initTestCase()
370 {
371     QQmlDataTest::initTestCase();
372     qRegisterMetaType<QQuickChangeSet>();
373
374     qmlRegisterType<SingleRoleModel>("tst_qquickvisualdatamodel", 1, 0, "SingleRoleModel");
375     qmlRegisterType<DataObject>("tst_qquickvisualdatamodel", 1, 0, "DataObject");
376 #ifndef QT_NO_WIDGETS
377     qmlRegisterType<StandardItem>("tst_qquickvisualdatamodel", 1, 0, "StandardItem");
378     qmlRegisterType<StandardItemModel>("tst_qquickvisualdatamodel", 1, 0, "StandardItemModel");
379 #endif
380
381     engine.setIncubationController(&controller);
382 }
383
384 void tst_qquickvisualdatamodel::cleanupTestCase()
385 {
386 }
387
388 tst_qquickvisualdatamodel::tst_qquickvisualdatamodel()
389 {
390 }
391
392 #ifndef QT_NO_WIDGETS
393 void tst_qquickvisualdatamodel::rootIndex()
394 {
395     QQmlEngine engine;
396     QQmlComponent c(&engine, testFileUrl("visualdatamodel.qml"));
397
398     QStandardItemModel model;
399     initStandardTreeModel(&model);
400
401     engine.rootContext()->setContextProperty("myModel", &model);
402
403     QQuickVisualDataModel *obj = qobject_cast<QQuickVisualDataModel*>(c.create());
404     QVERIFY(obj != 0);
405
406     QMetaObject::invokeMethod(obj, "setRoot");
407     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == model.index(0,0));
408
409     QMetaObject::invokeMethod(obj, "setRootToParent");
410     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == QModelIndex());
411
412     QMetaObject::invokeMethod(obj, "setRoot");
413     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == model.index(0,0));
414     model.clear(); // will emit modelReset()
415     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == QModelIndex());
416
417     delete obj;
418 }
419
420 void tst_qquickvisualdatamodel::updateLayout_data()
421 {
422     QTest::addColumn<QUrl>("source");
423
424     QTest::newRow("item delegate") << testFileUrl("datalist.qml");
425     QTest::newRow("package delegate") << testFileUrl("datalist-package.qml");
426 }
427
428 void tst_qquickvisualdatamodel::updateLayout()
429 {
430     QFETCH(QUrl, source);
431
432     QQuickView view;
433
434     QStandardItemModel model;
435     initStandardTreeModel(&model);
436
437     view.rootContext()->setContextProperty("myModel", &model);
438
439     view.setSource(source);
440
441     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
442     QVERIFY(listview != 0);
443
444     QQuickItem *contentItem = listview->contentItem();
445     QVERIFY(contentItem != 0);
446
447     QQuickText *name = findItem<QQuickText>(contentItem, "display", 0);
448     QVERIFY(name);
449     QCOMPARE(name->text(), QString("Row 1 Item"));
450     name = findItem<QQuickText>(contentItem, "display", 1);
451     QVERIFY(name);
452     QCOMPARE(name->text(), QString("Row 2 Item"));
453     name = findItem<QQuickText>(contentItem, "display", 2);
454     QVERIFY(name);
455     QCOMPARE(name->text(), QString("Row 3 Item"));
456
457     model.invisibleRootItem()->sortChildren(0, Qt::DescendingOrder);
458
459     name = findItem<QQuickText>(contentItem, "display", 0);
460     QVERIFY(name);
461     QCOMPARE(name->text(), QString("Row 3 Item"));
462     name = findItem<QQuickText>(contentItem, "display", 1);
463     QVERIFY(name);
464     QCOMPARE(name->text(), QString("Row 2 Item"));
465     name = findItem<QQuickText>(contentItem, "display", 2);
466     QVERIFY(name);
467     QCOMPARE(name->text(), QString("Row 1 Item"));
468 }
469
470 void tst_qquickvisualdatamodel::childChanged_data()
471 {
472     QTest::addColumn<QUrl>("source");
473
474     QTest::newRow("item delegate") << testFileUrl("datalist.qml");
475     QTest::newRow("package delegate") << testFileUrl("datalist-package.qml");
476 }
477
478 void tst_qquickvisualdatamodel::childChanged()
479 {
480     QFETCH(QUrl, source);
481
482     QQuickView view;
483
484     QStandardItemModel model;
485     initStandardTreeModel(&model);
486
487     view.rootContext()->setContextProperty("myModel", &model);
488
489     view.setSource(source);
490
491     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
492     QVERIFY(listview != 0);
493
494     QQuickItem *contentItem = listview->contentItem();
495     QVERIFY(contentItem != 0);
496
497     QQuickVisualDataModel *vdm = listview->findChild<QQuickVisualDataModel*>("visualModel");
498     vdm->setRootIndex(QVariant::fromValue(model.indexFromItem(model.item(1,0))));
499     QCOMPARE(listview->count(), 1);
500
501     QQuickText *name = findItem<QQuickText>(contentItem, "display", 0);
502     QVERIFY(name);
503     QCOMPARE(name->text(), QString("Row 2 Child Item"));
504
505     model.item(1,0)->child(0,0)->setText("Row 2 updated child");
506
507     name = findItem<QQuickText>(contentItem, "display", 0);
508     QVERIFY(name);
509     QCOMPARE(name->text(), QString("Row 2 updated child"));
510
511     model.item(1,0)->appendRow(new QStandardItem(QLatin1String("Row 2 Child Item 2")));
512     QCOMPARE(listview->count(), 2);
513
514     name = findItem<QQuickText>(contentItem, "display", 1);
515     QVERIFY(name != 0);
516     QCOMPARE(name->text(), QString("Row 2 Child Item 2"));
517
518     model.item(1,0)->takeRow(1);
519     name = findItem<QQuickText>(contentItem, "display", 1);
520     QVERIFY(name == 0);
521
522     vdm->setRootIndex(QVariant::fromValue(QModelIndex()));
523     QCOMPARE(listview->count(), 3);
524     name = findItem<QQuickText>(contentItem, "display", 0);
525     QVERIFY(name);
526     QCOMPARE(name->text(), QString("Row 1 Item"));
527     name = findItem<QQuickText>(contentItem, "display", 1);
528     QVERIFY(name);
529     QCOMPARE(name->text(), QString("Row 2 Item"));
530     name = findItem<QQuickText>(contentItem, "display", 2);
531     QVERIFY(name);
532     QCOMPARE(name->text(), QString("Row 3 Item"));
533 }
534 #endif
535
536 void tst_qquickvisualdatamodel::objectListModel()
537 {
538     QQuickView view;
539
540     QList<QObject*> dataList;
541     dataList.append(new DataObject("Item 1", "red"));
542     dataList.append(new DataObject("Item 2", "green"));
543     dataList.append(new DataObject("Item 3", "blue"));
544     dataList.append(new DataObject("Item 4", "yellow"));
545
546     QQmlContext *ctxt = view.rootContext();
547     ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
548
549     view.setSource(testFileUrl("objectlist.qml"));
550
551     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
552     QVERIFY(listview != 0);
553
554     QQuickItem *contentItem = listview->contentItem();
555     QVERIFY(contentItem != 0);
556
557     QQuickText *name = findItem<QQuickText>(contentItem, "name", 0);
558     QCOMPARE(name->text(), QString("Item 1"));
559     QCOMPARE(name->property("modelName").toString(), QString("Item 1"));
560
561     QQuickText *section = findItem<QQuickText>(contentItem, "section", 0);
562     QCOMPARE(section->text(), QString("Item 1"));
563
564     dataList[0]->setProperty("name", QLatin1String("Changed"));
565     QCOMPARE(name->text(), QString("Changed"));
566     QCOMPARE(name->property("modelName").toString(), QString("Changed"));
567
568     // Test resolving nested section property
569     DataObject *obj = static_cast<DataObject*>(dataList[0]);
570     obj->setSubName("SubItem 1");
571
572     QMetaObject::invokeMethod(listview, "changeSectionProperty");
573     section = findItem<QQuickText>(contentItem, "section", 0);
574     QCOMPARE(section->text(), QString("SubItem 1"));
575 }
576
577 void tst_qquickvisualdatamodel::singleRole()
578 {
579     {
580         QQuickView view;
581
582         SingleRoleModel model;
583
584         QQmlContext *ctxt = view.rootContext();
585         ctxt->setContextProperty("myModel", &model);
586
587         view.setSource(testFileUrl("singlerole1.qml"));
588
589         QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
590         QVERIFY(listview != 0);
591
592         QQuickItem *contentItem = listview->contentItem();
593         QVERIFY(contentItem != 0);
594
595         QQuickText *name = findItem<QQuickText>(contentItem, "name", 1);
596         QCOMPARE(name->text(), QString("two"));
597
598         model.set(1, "Changed");
599         QCOMPARE(name->text(), QString("Changed"));
600     }
601     {
602         QQuickView view;
603
604         SingleRoleModel model;
605
606         QQmlContext *ctxt = view.rootContext();
607         ctxt->setContextProperty("myModel", &model);
608
609         view.setSource(testFileUrl("singlerole2.qml"));
610
611         QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
612         QVERIFY(listview != 0);
613
614         QQuickItem *contentItem = listview->contentItem();
615         QVERIFY(contentItem != 0);
616
617         QQuickText *name = findItem<QQuickText>(contentItem, "name", 1);
618         QCOMPARE(name->text(), QString("two"));
619
620         model.set(1, "Changed");
621         QCOMPARE(name->text(), QString("Changed"));
622     }
623     {
624         QQuickView view;
625
626         SingleRoleModel model("modelData");
627
628         QQmlContext *ctxt = view.rootContext();
629         ctxt->setContextProperty("myModel", &model);
630
631         view.setSource(testFileUrl("singlerole2.qml"));
632
633         QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
634         QVERIFY(listview != 0);
635
636         QQuickItem *contentItem = listview->contentItem();
637         QVERIFY(contentItem != 0);
638
639         QQuickText *name = findItem<QQuickText>(contentItem, "name", 1);
640         QCOMPARE(name->text(), QString("two"));
641
642         model.set(1, "Changed");
643         QCOMPARE(name->text(), QString("Changed"));
644     }
645 }
646
647 void tst_qquickvisualdatamodel::modelProperties()
648 {
649     {
650         QQuickView view;
651
652         SingleRoleModel model;
653
654         QQmlContext *ctxt = view.rootContext();
655         ctxt->setContextProperty("myModel", &model);
656
657         view.setSource(testFileUrl("modelproperties.qml"));
658
659         QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
660         QVERIFY(listview != 0);
661
662         QQuickItem *contentItem = listview->contentItem();
663         QVERIFY(contentItem != 0);
664
665         QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 1);
666         QVERIFY(delegate);
667         QCOMPARE(delegate->property("test1").toString(),QString("two"));
668         QCOMPARE(delegate->property("test2").toString(),QString("two"));
669         QCOMPARE(delegate->property("test3").toString(),QString("two"));
670         QCOMPARE(delegate->property("test4").toString(),QString("two"));
671         QVERIFY(!delegate->property("test9").isValid());
672         QCOMPARE(delegate->property("test5").toString(),QString(""));
673         QVERIFY(delegate->property("test6").value<QObject*>() != 0);
674         QCOMPARE(delegate->property("test7").toInt(),1);
675         QCOMPARE(delegate->property("test8").toInt(),1);
676     }
677
678     {
679         QQuickView view;
680
681         QList<QObject*> dataList;
682         dataList.append(new DataObject("Item 1", "red"));
683         dataList.append(new DataObject("Item 2", "green"));
684         dataList.append(new DataObject("Item 3", "blue"));
685         dataList.append(new DataObject("Item 4", "yellow"));
686
687         QQmlContext *ctxt = view.rootContext();
688         ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
689
690         view.setSource(testFileUrl("modelproperties.qml"));
691
692         QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
693         QVERIFY(listview != 0);
694
695         QQuickItem *contentItem = listview->contentItem();
696         QVERIFY(contentItem != 0);
697
698         QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 1);
699         QVERIFY(delegate);
700         QCOMPARE(delegate->property("test1").toString(),QString("Item 2"));
701         QCOMPARE(delegate->property("test2").toString(),QString("Item 2"));
702         QVERIFY(qobject_cast<DataObject*>(delegate->property("test3").value<QObject*>()) != 0);
703         QVERIFY(qobject_cast<DataObject*>(delegate->property("test4").value<QObject*>()) != 0);
704         QCOMPARE(delegate->property("test5").toString(),QString("Item 2"));
705         QCOMPARE(delegate->property("test9").toString(),QString("Item 2"));
706         QVERIFY(delegate->property("test6").value<QObject*>() != 0);
707         QCOMPARE(delegate->property("test7").toInt(),1);
708         QCOMPARE(delegate->property("test8").toInt(),1);
709     }
710
711 #ifndef QT_NO_WIDGETS
712     {
713         QQuickView view;
714
715         QStandardItemModel model;
716         initStandardTreeModel(&model);
717
718         view.rootContext()->setContextProperty("myModel", &model);
719
720         QUrl source(testFileUrl("modelproperties2.qml"));
721
722         //3 items, 3 i each
723         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
724         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
725         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
726         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
727         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
728         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
729         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
730         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
731         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
732
733         view.setSource(source);
734
735         QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
736         QVERIFY(listview != 0);
737
738         QQuickItem *contentItem = listview->contentItem();
739         QVERIFY(contentItem != 0);
740
741         QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 1);
742         QVERIFY(delegate);
743         QCOMPARE(delegate->property("test1").toString(),QString("Row 2 Item"));
744         QCOMPARE(delegate->property("test2").toString(),QString("Row 2 Item"));
745         QVERIFY(!delegate->property("test3").isValid());
746         QVERIFY(!delegate->property("test4").isValid());
747         QVERIFY(!delegate->property("test5").isValid());
748         QVERIFY(!delegate->property("test9").isValid());
749         QVERIFY(delegate->property("test6").value<QObject*>() != 0);
750         QCOMPARE(delegate->property("test7").toInt(),1);
751         QCOMPARE(delegate->property("test8").toInt(),1);
752     }
753 #endif
754     //### should also test QStringList and QVariantList
755 }
756
757 #ifndef QT_NO_WIDGETS
758 void tst_qquickvisualdatamodel::noDelegate_data()
759 {
760     QTest::addColumn<QUrl>("source");
761
762     QTest::newRow("item delegate") << testFileUrl("datalist.qml");
763     QTest::newRow("package delegate") << testFileUrl("datalist-package.qml");
764 }
765
766 void tst_qquickvisualdatamodel::noDelegate()
767 {
768     QFETCH(QUrl, source);
769
770     QQuickView view;
771
772     QStandardItemModel model;
773     initStandardTreeModel(&model);
774
775     view.rootContext()->setContextProperty("myModel", &model);
776
777     view.setSource(source);
778
779     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
780     QVERIFY(listview != 0);
781
782     QQuickVisualDataModel *vdm = listview->findChild<QQuickVisualDataModel*>("visualModel");
783     QVERIFY(vdm != 0);
784     QCOMPARE(vdm->count(), 3);
785
786     vdm->setDelegate(0);
787     QCOMPARE(vdm->count(), 0);
788 }
789
790 void tst_qquickvisualdatamodel::itemsDestroyed_data()
791 {
792     QTest::addColumn<QUrl>("source");
793
794     QTest::newRow("listView") << testFileUrl("itemsDestroyed_listView.qml");
795     QTest::newRow("package") << testFileUrl("itemsDestroyed_package.qml");
796     QTest::newRow("pathView") << testFileUrl("itemsDestroyed_pathView.qml");
797     QTest::newRow("repeater") << testFileUrl("itemsDestroyed_repeater.qml");
798 }
799
800 void tst_qquickvisualdatamodel::itemsDestroyed()
801 {
802     QFETCH(QUrl, source);
803
804     QQmlGuard<QQuickItem> delegate;
805
806     {
807         QQuickView view;
808         QStandardItemModel model;
809         initStandardTreeModel(&model);
810         view.rootContext()->setContextProperty("myModel", &model);
811         view.setSource(source);
812
813         view.show();
814         QTest::qWaitForWindowShown(&view);
815
816         QVERIFY(delegate = findItem<QQuickItem>(view.rootItem(), "delegate", 1));
817     }
818     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
819     QVERIFY(!delegate);
820 }
821 #endif
822
823 void tst_qquickvisualdatamodel::packagesDestroyed()
824 {
825     SingleRoleModel model;
826     model.list.clear();
827     for (int i=0; i<30; i++)
828         model.list << (QLatin1String("item ") + i);
829
830     QQuickView view;
831     view.rootContext()->setContextProperty("testModel", &model);
832
833     QString filename(testFile("packageView.qml"));
834     view.setSource(QUrl::fromLocalFile(filename));
835
836     qApp->processEvents();
837
838     QQuickListView *leftview = findItem<QQuickListView>(view.rootObject(), "leftList");
839     QTRY_VERIFY(leftview != 0);
840
841     QQuickListView *rightview = findItem<QQuickListView>(view.rootObject(), "rightList");
842     QTRY_VERIFY(rightview != 0);
843
844     QQuickItem *leftContent = leftview->contentItem();
845     QTRY_VERIFY(leftContent != 0);
846
847     QQuickItem *rightContent = rightview->contentItem();
848     QTRY_VERIFY(rightContent != 0);
849
850     QCOMPARE(leftview->currentIndex(), 0);
851     QCOMPARE(rightview->currentIndex(), 0);
852
853     rightview->setCurrentIndex(20);
854     QTRY_COMPARE(rightview->contentY(), 100.0);
855
856     QQmlGuard<QQuickItem> left;
857     QQmlGuard<QQuickItem> right;
858
859     QVERIFY(findItem<QQuickItem>(leftContent, "wrapper", 1));
860     QVERIFY(findItem<QQuickItem>(rightContent, "wrapper", 1));
861
862     QVERIFY(left = findItem<QQuickItem>(leftContent, "wrapper", 19));
863     QVERIFY(right = findItem<QQuickItem>(rightContent, "wrapper", 19));
864
865     rightview->setCurrentIndex(0);
866     QCOMPARE(rightview->currentIndex(), 0);
867
868     QTRY_COMPARE(rightview->contentY(), 0.0);
869     QCoreApplication::sendPostedEvents();
870
871     QVERIFY(!left);
872     QVERIFY(!right);
873
874     QVERIFY(left = findItem<QQuickItem>(leftContent, "wrapper", 1));
875     QVERIFY(right = findItem<QQuickItem>(rightContent, "wrapper", 1));
876
877     rightview->setCurrentIndex(20);
878     QTRY_COMPARE(rightview->contentY(), 100.0);
879
880     QVERIFY(left);
881     QVERIFY(right);
882
883     QVERIFY(findItem<QQuickItem>(leftContent, "wrapper", 19));
884     QVERIFY(findItem<QQuickItem>(rightContent, "wrapper", 19));
885
886     leftview->setCurrentIndex(20);
887     QTRY_COMPARE(leftview->contentY(), 100.0);
888
889     QVERIFY(!left);
890     QVERIFY(!right);
891 }
892
893 void tst_qquickvisualdatamodel::qaimRowsMoved()
894 {
895     // Test parameters passed in QAIM::rowsMoved() signal are converted correctly
896     // when translated and emitted as the QListModelInterface::itemsMoved() signal
897     QFETCH(int, sourceFirst);
898     QFETCH(int, sourceLast);
899     QFETCH(int, destinationChild);
900     QFETCH(int, expectFrom);
901     QFETCH(int, expectTo);
902     QFETCH(int, expectCount);
903
904     QQmlEngine engine;
905     QQmlComponent c(&engine, testFileUrl("visualdatamodel.qml"));
906
907     SingleRoleModel model;
908     model.list.clear();
909     for (int i=0; i<30; i++)
910         model.list << (QLatin1String("item ") + i);
911     engine.rootContext()->setContextProperty("myModel", &model);
912
913     QQuickVisualDataModel *obj = qobject_cast<QQuickVisualDataModel*>(c.create());
914     QVERIFY(obj != 0);
915
916     QSignalSpy spy(obj, SIGNAL(modelUpdated(QQuickChangeSet,bool)));
917     model.emitMove(sourceFirst, sourceLast, destinationChild);
918     QCOMPARE(spy.count(), 1);
919
920     QCOMPARE(spy[0].count(), 2);
921     QQuickChangeSet changeSet = spy[0][0].value<QQuickChangeSet>();
922     QCOMPARE(changeSet.removes().count(), 1);
923     QCOMPARE(changeSet.removes().at(0).index, expectFrom);
924     QCOMPARE(changeSet.removes().at(0).count, expectCount);
925     QCOMPARE(changeSet.inserts().count(), 1);
926     QCOMPARE(changeSet.inserts().at(0).index, expectTo);
927     QCOMPARE(changeSet.inserts().at(0).count, expectCount);
928     QCOMPARE(changeSet.removes().at(0).moveId, changeSet.inserts().at(0).moveId);
929     QCOMPARE(spy[0][1].toBool(), false);
930
931     delete obj;
932 }
933
934 void tst_qquickvisualdatamodel::qaimRowsMoved_data()
935 {
936     QTest::addColumn<int>("sourceFirst");
937     QTest::addColumn<int>("sourceLast");
938     QTest::addColumn<int>("destinationChild");
939     QTest::addColumn<int>("expectFrom");
940     QTest::addColumn<int>("expectTo");
941     QTest::addColumn<int>("expectCount");
942
943     QTest::newRow("move 1 forward")
944         << 1 << 1 << 6
945         << 1 << 5 << 1;
946
947     QTest::newRow("move 1 backwards")
948         << 4 << 4 << 1
949         << 4 << 1 << 1;
950
951     QTest::newRow("move multiple forwards")
952         << 0 << 2 << 13
953         << 0 << 10 << 3;
954
955     QTest::newRow("move multiple forwards, with same to")
956         << 0 << 1 << 3
957         << 0 << 1 << 2;
958
959     QTest::newRow("move multiple backwards")
960         << 10 << 14 << 1
961         << 10 << 1 << 5;
962 }
963
964 void tst_qquickvisualdatamodel::remove_data()
965 {
966     QTest::addColumn<QUrl>("source");
967     QTest::addColumn<QString>("package delegate");
968
969     QTest::newRow("item delegate")
970             << testFileUrl("groups.qml")
971             << QString();
972     QTest::newRow("package")
973             << testFileUrl("groups-package.qml")
974             << QString("package.");
975 }
976
977 void tst_qquickvisualdatamodel::remove()
978 {
979     QQuickView view;
980
981     SingleRoleModel model;
982     model.list = QStringList()
983             << "one"
984             << "two"
985             << "three"
986             << "four"
987             << "five"
988             << "six"
989             << "seven"
990             << "eight"
991             << "nine"
992             << "ten"
993             << "eleven"
994             << "twelve";
995
996     QQmlContext *ctxt = view.rootContext();
997     ctxt->setContextProperty("myModel", &model);
998
999     view.setSource(testFileUrl("groups.qml"));
1000
1001     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
1002     QVERIFY(listview != 0);
1003
1004     QQuickItem *contentItem = listview->contentItem();
1005     QVERIFY(contentItem != 0);
1006
1007     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
1008     QVERIFY(visualModel);
1009
1010     {
1011         QCOMPARE(listview->count(), 12);
1012         QCOMPARE(visualModel->items()->count(), 12);
1013         static const int mIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1014         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1015
1016         for (int i = 0; i < lengthOf(mIndex); ++i) {
1017             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1018             QVERIFY(delegate);
1019             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1020             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1021             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1022         }
1023     } {
1024         evaluate<void>(visualModel, "items.remove(2)");
1025         QCOMPARE(listview->count(), 11);
1026         QCOMPARE(visualModel->items()->count(), 11);
1027         static const int mIndex[] = { 0, 1, 3, 4, 5, 6, 7, 8, 9,10,11 };
1028         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10 };
1029
1030         for (int i = 0; i < lengthOf(mIndex); ++i) {
1031             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1032             QVERIFY(delegate);
1033             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1034             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1035             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1036         }
1037     } {
1038         evaluate<void>(visualModel, "items.remove(1, 4)");
1039         QCOMPARE(listview->count(), 7);
1040         QCOMPARE(visualModel->items()->count(), 7);
1041         static const int mIndex[] = { 0, 6, 7, 8, 9,10,11 };
1042         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6 };
1043
1044         for (int i = 0; i < lengthOf(mIndex); ++i) {
1045             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1046             QVERIFY(delegate);
1047             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1048             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1049             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1050         }
1051     } {
1052         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range");
1053         evaluate<void>(visualModel, "items.remove(-8, 4)");
1054         QCOMPARE(listview->count(), 7);
1055         QCOMPARE(visualModel->items()->count(), 7);
1056     } {
1057         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range");
1058         evaluate<void>(visualModel, "items.remove(12, 2)");
1059         QCOMPARE(listview->count(), 7);
1060         QCOMPARE(visualModel->items()->count(), 7);
1061     } {
1062         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: invalid count");
1063         evaluate<void>(visualModel, "items.remove(5, 3)");
1064         QCOMPARE(listview->count(), 7);
1065         QCOMPARE(visualModel->items()->count(), 7);
1066     } {
1067         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: invalid count");
1068         evaluate<void>(visualModel, "items.remove(5, -2)");
1069         QCOMPARE(listview->count(), 7);
1070         QCOMPARE(visualModel->items()->count(), 7);
1071     }
1072 }
1073
1074 void tst_qquickvisualdatamodel::move_data()
1075 {
1076     QTest::addColumn<QUrl>("source");
1077     QTest::addColumn<QString>("package delegate");
1078
1079     QTest::newRow("item delegate")
1080             << testFileUrl("groups.qml")
1081             << QString();
1082     QTest::newRow("package")
1083             << testFileUrl("groups-package.qml")
1084             << QString("package.");
1085 }
1086
1087 void tst_qquickvisualdatamodel::move()
1088 {
1089     QQuickView view;
1090
1091     SingleRoleModel model;
1092     model.list = QStringList()
1093             << "one"
1094             << "two"
1095             << "three"
1096             << "four"
1097             << "five"
1098             << "six"
1099             << "seven"
1100             << "eight"
1101             << "nine"
1102             << "ten"
1103             << "eleven"
1104             << "twelve";
1105
1106     QQmlContext *ctxt = view.rootContext();
1107     ctxt->setContextProperty("myModel", &model);
1108
1109     view.setSource(testFileUrl("groups.qml"));
1110
1111     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
1112     QVERIFY(listview != 0);
1113
1114     QQuickItem *contentItem = listview->contentItem();
1115     QVERIFY(contentItem != 0);
1116
1117     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
1118     QVERIFY(visualModel);
1119
1120     {
1121         QCOMPARE(listview->count(), 12);
1122         QCOMPARE(visualModel->items()->count(), 12);
1123         static const int mIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1124         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1125
1126         for (int i = 0; i < lengthOf(mIndex); ++i) {
1127             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1128             QVERIFY(delegate);
1129             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1130             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1131             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1132         }
1133     } {
1134         evaluate<void>(visualModel, "items.move(2, 4)");
1135         QCOMPARE(listview->count(), 12);
1136         QCOMPARE(visualModel->items()->count(), 12);
1137         static const int mIndex[] = { 0, 1, 3, 4, 2, 5, 6, 7, 8, 9,10,11 };
1138         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1139
1140         for (int i = 0; i < lengthOf(mIndex); ++i) {
1141             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1142             QVERIFY(delegate);
1143             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1144             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1145             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1146         }
1147     } {
1148         evaluate<void>(visualModel, "items.move(4, 2)");
1149         QCOMPARE(listview->count(), 12);
1150         QCOMPARE(visualModel->items()->count(), 12);
1151         static const int mIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1152         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1153
1154         for (int i = 0; i < lengthOf(mIndex); ++i) {
1155             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1156             QVERIFY(delegate);
1157             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1158             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1159             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1160         }
1161     } {
1162         evaluate<void>(visualModel, "items.move(8, 0, 4)");
1163         QCOMPARE(listview->count(), 12);
1164         QCOMPARE(visualModel->items()->count(), 12);
1165         static const int mIndex[] = { 8, 9,10,11, 0, 1, 2, 3, 4, 5, 6, 7 };
1166         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1167
1168         for (int i = 0; i < lengthOf(mIndex); ++i) {
1169             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1170             QVERIFY(delegate);
1171             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1172             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1173             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1174         }
1175     } {
1176         evaluate<void>(visualModel, "items.move(3, 4, 5)");
1177         QCOMPARE(listview->count(), 12);
1178         QCOMPARE(visualModel->items()->count(), 12);
1179         static const int mIndex[] = { 8, 9,10,4, 11, 0, 1, 2, 3, 5, 6, 7 };
1180         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1181
1182         for (int i = 0; i < lengthOf(mIndex); ++i) {
1183             QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1184             QVERIFY(delegate);
1185             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
1186             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
1187             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
1188         }
1189     } {
1190         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: invalid count");
1191         evaluate<void>(visualModel, "items.move(5, 2, -2)");
1192         QCOMPARE(listview->count(), 12);
1193         QCOMPARE(visualModel->items()->count(), 12);
1194     } {
1195         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range");
1196         evaluate<void>(visualModel, "items.move(-6, 2, 1)");
1197         QCOMPARE(listview->count(), 12);
1198         QCOMPARE(visualModel->items()->count(), 12);
1199     } {
1200         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range");
1201         evaluate<void>(visualModel, "items.move(15, 2, 1)");
1202         QCOMPARE(listview->count(), 12);
1203         QCOMPARE(visualModel->items()->count(), 12);
1204     } {
1205         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range");
1206         evaluate<void>(visualModel, "items.move(11, 1, 3)");
1207         QCOMPARE(listview->count(), 12);
1208         QCOMPARE(visualModel->items()->count(), 12);
1209     } {
1210         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range");
1211         evaluate<void>(visualModel, "items.move(2, -5, 1)");
1212         QCOMPARE(listview->count(), 12);
1213         QCOMPARE(visualModel->items()->count(), 12);
1214     } {
1215         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range");
1216         evaluate<void>(visualModel, "items.move(2, 14, 1)");
1217         QCOMPARE(listview->count(), 12);
1218         QCOMPARE(visualModel->items()->count(), 12);
1219     } {
1220         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range");
1221         evaluate<void>(visualModel, "items.move(2, 11, 4)");
1222         QCOMPARE(listview->count(), 12);
1223         QCOMPARE(visualModel->items()->count(), 12);
1224     }
1225 }
1226
1227 void tst_qquickvisualdatamodel::groups_data()
1228 {
1229     QTest::addColumn<QUrl>("source");
1230     QTest::addColumn<QString>("part");
1231
1232     QTest::newRow("item delegate")
1233             << testFileUrl("groups.qml")
1234             << QString();
1235     QTest::newRow("package")
1236             << testFileUrl("groups-package.qml")
1237             << QString("visualModel.parts.package.");
1238 }
1239
1240 template <int N> void tst_qquickvisualdatamodel::groups_verify(
1241         const SingleRoleModel &model,
1242         QQuickItem *contentItem,
1243         const int (&mIndex)[N],
1244         const int (&iIndex)[N],
1245         const int (&vIndex)[N],
1246         const int (&sIndex)[N],
1247         const bool (&vMember)[N],
1248         const bool (&sMember)[N])
1249 {
1250     failed = true;
1251     for (int i = 0; i < N; ++i) {
1252         QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]);
1253         QVERIFY(delegate);
1254         QCOMPARE(evaluate<QString>(delegate, "test1"), model.list.at(mIndex[i]));
1255         QCOMPARE(evaluate<int>(delegate, "test2") , mIndex[i]);
1256         QCOMPARE(evaluate<int>(delegate, "test3") , iIndex[i]);
1257         QCOMPARE(evaluate<bool>(delegate, "test4"), true);
1258         QCOMPARE(evaluate<int>(delegate, "test5") , vIndex[i]);
1259         QCOMPARE(evaluate<bool>(delegate, "test6"), vMember[i]);
1260         QCOMPARE(evaluate<int>(delegate, "test7") , sIndex[i]);
1261         QCOMPARE(evaluate<bool>(delegate, "test8"), sMember[i]);
1262         QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("items")   , bool(true));
1263         QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("visible") , bool(vMember[i]));
1264         QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("selected"), bool(sMember[i]));
1265     }
1266     failed = false;
1267 }
1268
1269 #define VERIFY_GROUPS \
1270     groups_verify(model, contentItem, mIndex, iIndex, vIndex, sIndex, vMember, sMember); \
1271     QVERIFY(!failed)
1272
1273
1274 void tst_qquickvisualdatamodel::groups()
1275 {
1276     QFETCH(QUrl, source);
1277     QFETCH(QString, part);
1278
1279     QQuickView view;
1280
1281     SingleRoleModel model;
1282     model.list = QStringList()
1283             << "one"
1284             << "two"
1285             << "three"
1286             << "four"
1287             << "five"
1288             << "six"
1289             << "seven"
1290             << "eight"
1291             << "nine"
1292             << "ten"
1293             << "eleven"
1294             << "twelve";
1295
1296     QQmlContext *ctxt = view.rootContext();
1297     ctxt->setContextProperty("myModel", &model);
1298
1299     view.setSource(source);
1300
1301     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
1302     QVERIFY(listview != 0);
1303
1304     QQuickItem *contentItem = listview->contentItem();
1305     QVERIFY(contentItem != 0);
1306
1307     QQuickVisualDataModel *visualModel = listview->findChild<QQuickVisualDataModel *>("visualModel");
1308     QVERIFY(visualModel);
1309
1310     QQuickVisualDataGroup *visibleItems = listview->findChild<QQuickVisualDataGroup *>("visibleItems");
1311     QVERIFY(visibleItems);
1312
1313     QQuickVisualDataGroup *selectedItems = listview->findChild<QQuickVisualDataGroup *>("selectedItems");
1314     QVERIFY(selectedItems);
1315
1316     const bool f = false;
1317     const bool t = true;
1318
1319     {
1320         QCOMPARE(listview->count(), 12);
1321         QCOMPARE(visualModel->items()->count(), 12);
1322         QCOMPARE(visibleItems->count(), 12);
1323         QCOMPARE(selectedItems->count(), 0);
1324         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1325         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1326         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1327         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1328         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1329         static const bool sMember[] = { f, f, f, f, f, f, f, f, f, f, f, f };
1330         VERIFY_GROUPS;
1331     } {
1332         evaluate<void>(visualModel, "items.addGroups(8, \"selected\")");
1333         QCOMPARE(listview->count(), 12);
1334         QCOMPARE(visualModel->items()->count(), 12);
1335         QCOMPARE(visibleItems->count(), 12);
1336         QCOMPARE(selectedItems->count(), 1);
1337         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1338         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1339         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1340         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1341         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 };
1342         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, f, f, f };
1343         VERIFY_GROUPS;
1344     } {
1345         evaluate<void>(visualModel, "items.addGroups(6, 4, [\"visible\", \"selected\"])");
1346         QCOMPARE(listview->count(), 12);
1347         QCOMPARE(visualModel->items()->count(), 12);
1348         QCOMPARE(visibleItems->count(), 12);
1349         QCOMPARE(selectedItems->count(), 4);
1350         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1351         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1352         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1353         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1354         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4 };
1355         static const bool sMember[] = { f, f, f, f, f, f, t, t, t, t, f, f };
1356         VERIFY_GROUPS;
1357     } {
1358         evaluate<void>(visualModel, "items.setGroups(2, [\"items\", \"selected\"])");
1359         QCOMPARE(listview->count(), 12);
1360         QCOMPARE(visualModel->items()->count(), 12);
1361         QCOMPARE(visibleItems->count(), 11);
1362         QCOMPARE(selectedItems->count(), 5);
1363         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1364         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1365         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9,10 };
1366         static const bool vMember[] = { t, t, f, t, t, t, t, t, t, t, t, t };
1367         static const int  sIndex [] = { 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 5, 5 };
1368         static const bool sMember[] = { f, f, t, f, f, f, t, t, t, t, f, f };
1369         VERIFY_GROUPS;
1370     } {
1371         evaluate<void>(selectedItems, "setGroups(0, 3, \"items\")");
1372         QCOMPARE(listview->count(), 12);
1373         QCOMPARE(visualModel->items()->count(), 12);
1374         QCOMPARE(visibleItems->count(), 9);
1375         QCOMPARE(selectedItems->count(), 2);
1376         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1377         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1378         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
1379         static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
1380         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1381         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1382         VERIFY_GROUPS;
1383     } {
1384         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: invalid count");
1385         evaluate<void>(visualModel, "items.addGroups(11, -4, \"items\")");
1386         QCOMPARE(listview->count(), 12);
1387         QCOMPARE(visualModel->items()->count(), 12);
1388         QCOMPARE(visibleItems->count(), 9);
1389         QCOMPARE(selectedItems->count(), 2);
1390     } {
1391         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range");
1392         evaluate<void>(visualModel, "items.addGroups(-1, 3, \"items\")");
1393         QCOMPARE(listview->count(), 12);
1394         QCOMPARE(visualModel->items()->count(), 12);
1395         QCOMPARE(visibleItems->count(), 9);
1396         QCOMPARE(selectedItems->count(), 2);
1397     } {
1398         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range");
1399         evaluate<void>(visualModel, "items.addGroups(14, 3, \"items\")");
1400         QCOMPARE(listview->count(), 12);
1401         QCOMPARE(visualModel->items()->count(), 12);
1402         QCOMPARE(visibleItems->count(), 9);
1403         QCOMPARE(selectedItems->count(), 2);
1404     } {
1405         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: invalid count");
1406         evaluate<void>(visualModel, "items.addGroups(11, 5, \"items\")");
1407         QCOMPARE(listview->count(), 12);
1408         QCOMPARE(visualModel->items()->count(), 12);
1409         QCOMPARE(visibleItems->count(), 9);
1410         QCOMPARE(selectedItems->count(), 2);
1411     } {
1412         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: invalid count");
1413         evaluate<void>(visualModel, "items.setGroups(11, -4, \"items\")");
1414         QCOMPARE(listview->count(), 12);
1415         QCOMPARE(visualModel->items()->count(), 12);
1416         QCOMPARE(visibleItems->count(), 9);
1417         QCOMPARE(selectedItems->count(), 2);
1418     } {
1419         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range");
1420         evaluate<void>(visualModel, "items.setGroups(-1, 3, \"items\")");
1421         QCOMPARE(listview->count(), 12);
1422         QCOMPARE(visualModel->items()->count(), 12);
1423         QCOMPARE(visibleItems->count(), 9);
1424         QCOMPARE(selectedItems->count(), 2);
1425     } {
1426         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range");
1427         evaluate<void>(visualModel, "items.setGroups(14, 3, \"items\")");
1428         QCOMPARE(listview->count(), 12);
1429         QCOMPARE(visualModel->items()->count(), 12);
1430         QCOMPARE(visibleItems->count(), 9);
1431         QCOMPARE(selectedItems->count(), 2);
1432     } {
1433         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: invalid count");
1434         evaluate<void>(visualModel, "items.setGroups(11, 5, \"items\")");
1435         QCOMPARE(listview->count(), 12);
1436         QCOMPARE(visualModel->items()->count(), 12);
1437         QCOMPARE(visibleItems->count(), 9);
1438         QCOMPARE(selectedItems->count(), 2);
1439     } {
1440         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: invalid count");
1441         evaluate<void>(visualModel, "items.removeGroups(11, -4, \"items\")");
1442         QCOMPARE(listview->count(), 12);
1443         QCOMPARE(visualModel->items()->count(), 12);
1444     } {
1445         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range");
1446         evaluate<void>(visualModel, "items.removeGroups(-1, 3, \"items\")");
1447         QCOMPARE(listview->count(), 12);
1448         QCOMPARE(visualModel->items()->count(), 12);
1449         QCOMPARE(visibleItems->count(), 9);
1450         QCOMPARE(selectedItems->count(), 2);
1451     } {
1452         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range");
1453         evaluate<void>(visualModel, "items.removeGroups(14, 3, \"items\")");
1454         QCOMPARE(listview->count(), 12);
1455         QCOMPARE(visualModel->items()->count(), 12);
1456         QCOMPARE(visibleItems->count(), 9);
1457         QCOMPARE(selectedItems->count(), 2);
1458     } {
1459         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: invalid count");
1460         evaluate<void>(visualModel, "items.removeGroups(11, 5, \"items\")");
1461         QCOMPARE(listview->count(), 12);
1462         QCOMPARE(visualModel->items()->count(), 12);
1463         QCOMPARE(visibleItems->count(), 9);
1464         QCOMPARE(selectedItems->count(), 2);
1465     } {
1466         evaluate<void>(visualModel, part + "filterOnGroup = \"visible\"");
1467         QCOMPARE(listview->count(), 9);
1468         QCOMPARE(visualModel->items()->count(), 12);
1469         QCOMPARE(visibleItems->count(), 9);
1470         QCOMPARE(selectedItems->count(), 2);
1471         QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("visible"));
1472     } {
1473         evaluate<void>(visualModel, part + "filterOnGroup = \"selected\"");
1474         QCOMPARE(listview->count(), 2);
1475         QCOMPARE(visualModel->items()->count(), 12);
1476         QCOMPARE(visibleItems->count(), 9);
1477         QCOMPARE(selectedItems->count(), 2);
1478         QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("selected"));
1479     } {
1480         evaluate<void>(visualModel, part + "filterOnGroup = undefined");
1481         QCOMPARE(listview->count(), 12);
1482         QCOMPARE(visualModel->items()->count(), 12);
1483         QCOMPARE(visibleItems->count(), 9);
1484         QCOMPARE(selectedItems->count(), 2);
1485         QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("items"));
1486     } {
1487         QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 5);
1488         QVERIFY(delegate);
1489
1490         evaluate<void>(delegate, "hide()");
1491         QCOMPARE(listview->count(), 12);
1492         QCOMPARE(visualModel->items()->count(), 12);
1493         QCOMPARE(visibleItems->count(), 8);
1494         QCOMPARE(selectedItems->count(), 2);
1495         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1496         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1497         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1498         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1499         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1500         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1501         VERIFY_GROUPS;
1502     } {
1503         QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 5);
1504         QVERIFY(delegate);
1505
1506         evaluate<void>(delegate, "select()");
1507         QCOMPARE(listview->count(), 12);
1508         QCOMPARE(visualModel->items()->count(), 12);
1509         QCOMPARE(visibleItems->count(), 8);
1510         QCOMPARE(selectedItems->count(), 3);
1511         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1512         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1513         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1514         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1515         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3 };
1516         static const bool sMember[] = { f, f, f, f, f, t, f, f, t, t, f, f };
1517         VERIFY_GROUPS;
1518     } {
1519         evaluate<void>(visualModel, "items.move(2, 6, 3)");
1520         QCOMPARE(listview->count(), 12);
1521         QCOMPARE(visualModel->items()->count(), 12);
1522         QCOMPARE(visibleItems->count(), 8);
1523         QCOMPARE(selectedItems->count(), 3);
1524         static const int  mIndex [] = { 0, 1, 5, 6, 7, 8, 2, 3, 4, 9,10,11 };
1525         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1526         static const int  vIndex [] = { 0, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 7 };
1527         static const bool vMember[] = { t, t, f, f, f, t, f, t, t, t, t, t };
1528         static const int  sIndex [] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3 };
1529         static const bool sMember[] = { f, f, t, f, f, t, f, f, f, t, f, f };
1530         VERIFY_GROUPS;
1531     }
1532 }
1533
1534 template <int N> void tst_qquickvisualdatamodel::get_verify(
1535         const SingleRoleModel &model,
1536         QQuickVisualDataModel *visualModel,
1537         QQuickVisualDataGroup *visibleItems,
1538         QQuickVisualDataGroup *selectedItems,
1539         const int (&mIndex)[N],
1540         const int (&iIndex)[N],
1541         const int (&vIndex)[N],
1542         const int (&sIndex)[N],
1543         const bool (&vMember)[N],
1544         const bool (&sMember)[N])
1545 {
1546     failed = true;
1547     for (int i = 0; i < N; ++i) {
1548         QCOMPARE(evaluate<QString>(visualModel, QString("items.get(%1).model.name").arg(i)), model.list.at(mIndex[i]));
1549         QCOMPARE(evaluate<QString>(visualModel, QString("items.get(%1).model.modelData").arg(i)), model.list.at(mIndex[i]));
1550         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).model.index").arg(i)), mIndex[i]);
1551         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).itemsIndex").arg(i)), iIndex[i]);
1552         QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inItems").arg(i)), true);
1553         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).visibleIndex").arg(i)), vIndex[i]);
1554         QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inVisible").arg(i)), vMember[i]);
1555         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).selectedIndex").arg(i)), sIndex[i]);
1556         QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inSelected").arg(i)), sMember[i]);
1557         QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"items\")").arg(i)), true);
1558         QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"visible\")").arg(i)), vMember[i]);
1559         QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"selected\")").arg(i)), sMember[i]);
1560
1561         if (vMember[i]) {
1562             QCOMPARE(evaluate<QString>(visibleItems, QString("get(%1).model.name").arg(vIndex[i])), model.list.at(mIndex[i]));
1563             QCOMPARE(evaluate<QString>(visibleItems, QString("get(%1).model.modelData").arg(vIndex[i])), model.list.at(mIndex[i]));
1564             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).model.index").arg(vIndex[i])), mIndex[i]);
1565             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).itemsIndex").arg(vIndex[i])), iIndex[i]);
1566             QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inItems").arg(vIndex[i])), true);
1567             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).visibleIndex").arg(vIndex[i])), vIndex[i]);
1568             QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inVisible").arg(vIndex[i])), vMember[i]);
1569             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).selectedIndex").arg(vIndex[i])), sIndex[i]);
1570             QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inSelected").arg(vIndex[i])), sMember[i]);
1571
1572             QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"items\")").arg(vIndex[i])), true);
1573             QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"visible\")").arg(vIndex[i])), vMember[i]);
1574             QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"selected\")").arg(vIndex[i])), sMember[i]);
1575         }
1576         if (sMember[i]) {
1577             QCOMPARE(evaluate<QString>(selectedItems, QString("get(%1).model.name").arg(sIndex[i])), model.list.at(mIndex[i]));
1578             QCOMPARE(evaluate<QString>(selectedItems, QString("get(%1).model.modelData").arg(sIndex[i])), model.list.at(mIndex[i]));
1579             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).model.index").arg(sIndex[i])), mIndex[i]);
1580             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).itemsIndex").arg(sIndex[i])), iIndex[i]);
1581             QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inItems").arg(sIndex[i])), true);
1582             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).visibleIndex").arg(sIndex[i])), vIndex[i]);
1583             QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inVisible").arg(sIndex[i])), vMember[i]);
1584             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).selectedIndex").arg(sIndex[i])), sIndex[i]);
1585             QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inSelected").arg(sIndex[i])), sMember[i]);
1586             QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"items\")").arg(sIndex[i])), true);
1587             QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"visible\")").arg(sIndex[i])), vMember[i]);
1588             QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"selected\")").arg(sIndex[i])), sMember[i]);
1589         }
1590     }
1591     failed = false;
1592 }
1593
1594 #define VERIFY_GET \
1595     get_verify(model, visualModel, visibleItems, selectedItems, mIndex, iIndex, vIndex, sIndex, vMember, sMember); \
1596     QVERIFY(!failed)
1597
1598 void tst_qquickvisualdatamodel::get()
1599 {
1600     QQuickView view;
1601
1602     SingleRoleModel model;
1603     model.list = QStringList()
1604             << "one"
1605             << "two"
1606             << "three"
1607             << "four"
1608             << "five"
1609             << "six"
1610             << "seven"
1611             << "eight"
1612             << "nine"
1613             << "ten"
1614             << "eleven"
1615             << "twelve";
1616
1617     QQmlContext *ctxt = view.rootContext();
1618     ctxt->setContextProperty("myModel", &model);
1619
1620     view.setSource(testFileUrl("groups.qml"));
1621
1622     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
1623     QVERIFY(listview != 0);
1624
1625     QQuickItem *contentItem = listview->contentItem();
1626     QVERIFY(contentItem != 0);
1627
1628     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
1629     QVERIFY(visualModel);
1630
1631     QQuickVisualDataGroup *visibleItems = visualModel->findChild<QQuickVisualDataGroup *>("visibleItems");
1632     QVERIFY(visibleItems);
1633
1634     QQuickVisualDataGroup *selectedItems = visualModel->findChild<QQuickVisualDataGroup *>("selectedItems");
1635     QVERIFY(selectedItems);
1636
1637     QV8Engine *v8Engine = QQmlEnginePrivate::getV8Engine(ctxt->engine());
1638     QVERIFY(v8Engine);
1639
1640     const bool f = false;
1641     const bool t = true;
1642
1643     {
1644         QCOMPARE(listview->count(), 12);
1645         QCOMPARE(visualModel->items()->count(), 12);
1646         QCOMPARE(visibleItems->count(), 12);
1647         QCOMPARE(selectedItems->count(), 0);
1648         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1649         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1650         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1651         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1652         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1653         static const bool sMember[] = { f, f, f, f, f, f, f, f, f, f, f, f };
1654         VERIFY_GET;
1655     } {
1656         evaluate<void>(visualModel, "items.addGroups(8, \"selected\")");
1657         QCOMPARE(listview->count(), 12);
1658         QCOMPARE(visualModel->items()->count(), 12);
1659         QCOMPARE(visibleItems->count(), 12);
1660         QCOMPARE(selectedItems->count(), 1);
1661         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1662         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1663         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1664         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1665         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 };
1666         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, f, f, f };
1667         VERIFY_GET;
1668     } {
1669         evaluate<void>(visualModel, "items.addGroups(6, 4, [\"visible\", \"selected\"])");
1670         QCOMPARE(listview->count(), 12);
1671         QCOMPARE(visualModel->items()->count(), 12);
1672         QCOMPARE(visibleItems->count(), 12);
1673         QCOMPARE(selectedItems->count(), 4);
1674         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1675         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1676         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1677         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1678         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4 };
1679         static const bool sMember[] = { f, f, f, f, f, f, t, t, t, t, f, f };
1680         VERIFY_GET;
1681     } {
1682         evaluate<void>(visualModel, "items.setGroups(2, [\"items\", \"selected\"])");
1683         QCOMPARE(listview->count(), 12);
1684         QCOMPARE(visualModel->items()->count(), 12);
1685         QCOMPARE(visibleItems->count(), 11);
1686         QCOMPARE(selectedItems->count(), 5);
1687         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1688         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1689         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9,10 };
1690         static const bool vMember[] = { t, t, f, t, t, t, t, t, t, t, t, t };
1691         static const int  sIndex [] = { 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 5, 5 };
1692         static const bool sMember[] = { f, f, t, f, f, f, t, t, t, t, f, f };
1693         VERIFY_GET;
1694     } {
1695         evaluate<void>(selectedItems, "setGroups(0, 3, \"items\")");
1696         QCOMPARE(listview->count(), 12);
1697         QCOMPARE(visualModel->items()->count(), 12);
1698         QCOMPARE(visibleItems->count(), 9);
1699         QCOMPARE(selectedItems->count(), 2);
1700         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1701         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1702         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
1703         static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
1704         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1705         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1706         VERIFY_GET;
1707     } {
1708         evaluate<void>(visualModel, "items.get(5).inVisible = false");
1709         QCOMPARE(listview->count(), 12);
1710         QCOMPARE(visualModel->items()->count(), 12);
1711         QCOMPARE(visibleItems->count(), 8);
1712         QCOMPARE(selectedItems->count(), 2);
1713         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1714         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1715         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1716         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1717         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1718         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1719         VERIFY_GET;
1720     } {
1721         evaluate<void>(visualModel, "items.get(5).inSelected = true");
1722         QCOMPARE(listview->count(), 12);
1723         QCOMPARE(visualModel->items()->count(), 12);
1724         QCOMPARE(visibleItems->count(), 8);
1725         QCOMPARE(selectedItems->count(), 3);
1726         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1727         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1728         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1729         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1730         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3 };
1731         static const bool sMember[] = { f, f, f, f, f, t, f, f, t, t, f, f };
1732         VERIFY_GET;
1733     } {
1734         evaluate<void>(visualModel, "items.get(5).groups = [\"visible\", \"items\"]");
1735         QCOMPARE(listview->count(), 12);
1736         QCOMPARE(visualModel->items()->count(), 12);
1737         QCOMPARE(visibleItems->count(), 9);
1738         QCOMPARE(selectedItems->count(), 2);
1739         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1740         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1741         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
1742         static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
1743         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1744         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1745         VERIFY_GET;
1746     }
1747 }
1748
1749 void tst_qquickvisualdatamodel::invalidGroups()
1750 {
1751     QUrl source = testFileUrl("groups-invalid.qml");
1752     QTest::ignoreMessage(QtWarningMsg, (source.toString() + ":12:9: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("Group names must start with a lower case letter")).toUtf8());
1753
1754     QQmlComponent component(&engine, source);
1755     QScopedPointer<QObject> object(component.create());
1756     QVERIFY(object);
1757
1758     QCOMPARE(evaluate<int>(object.data(), "groups.length"), 4);
1759     QCOMPARE(evaluate<QString>(object.data(), "groups[0].name"), QString("items"));
1760     QCOMPARE(evaluate<QString>(object.data(), "groups[1].name"), QString("persistedItems"));
1761     QCOMPARE(evaluate<QString>(object.data(), "groups[2].name"), QString("visible"));
1762     QCOMPARE(evaluate<QString>(object.data(), "groups[3].name"), QString("selected"));
1763 }
1764
1765 void tst_qquickvisualdatamodel::onChanged_data()
1766 {
1767     QTest::addColumn<QString>("expression");
1768     QTest::addColumn<QStringList>("tests");
1769
1770     QTest::newRow("item appended")
1771             << QString("listModel.append({\"number\": \"five\"})")
1772             << (QStringList()
1773                 << "verify(vm.removed, [], [], [])"
1774                 << "verify(vm.inserted, [4], [1], [undefined])"
1775                 << "verify(vi.removed, [], [], [])"
1776                 << "verify(vi.inserted, [4], [1], [undefined])"
1777                 << "verify(si.removed, [], [], [])"
1778                 << "verify(si.inserted, [], [], [])");
1779     QTest::newRow("item prepended")
1780             << QString("listModel.insert(0, {\"number\": \"five\"})")
1781             << (QStringList()
1782                 << "verify(vm.removed, [], [], [])"
1783                 << "verify(vm.inserted, [0], [1], [undefined])"
1784                 << "verify(vi.removed, [], [], [])"
1785                 << "verify(vi.inserted, [0], [1], [undefined])"
1786                 << "verify(si.removed, [], [], [])"
1787                 << "verify(si.inserted, [], [], [])");
1788     QTest::newRow("item inserted")
1789             << QString("listModel.insert(2, {\"number\": \"five\"})")
1790             << (QStringList()
1791                 << "verify(vm.removed, [], [], [])"
1792                 << "verify(vm.inserted, [2], [1], [undefined])"
1793                 << "verify(vi.removed, [], [], [])"
1794                 << "verify(vi.inserted, [2], [1], [undefined])"
1795                 << "verify(si.removed, [], [], [])"
1796                 << "verify(si.inserted, [], [], [])");
1797
1798     QTest::newRow("item removed tail")
1799             << QString("listModel.remove(3)")
1800             << (QStringList()
1801                 << "verify(vm.removed, [3], [1], [undefined])"
1802                 << "verify(vm.inserted, [], [], [])"
1803                 << "verify(vi.removed, [3], [1], [undefined])"
1804                 << "verify(vi.inserted, [], [], [])"
1805                 << "verify(si.removed, [], [], [])"
1806                 << "verify(si.inserted, [], [], [])");
1807     QTest::newRow("item removed head")
1808             << QString("listModel.remove(0)")
1809             << (QStringList()
1810                 << "verify(vm.removed, [0], [1], [undefined])"
1811                 << "verify(vm.inserted, [], [], [])"
1812                 << "verify(vi.removed, [0], [1], [undefined])"
1813                 << "verify(vi.inserted, [], [], [])"
1814                 << "verify(si.removed, [], [], [])"
1815                 << "verify(si.inserted, [], [], [])");
1816     QTest::newRow("item removed middle")
1817             << QString("listModel.remove(1)")
1818             << (QStringList()
1819                 << "verify(vm.removed, [1], [1], [undefined])"
1820                 << "verify(vm.inserted, [], [], [])"
1821                 << "verify(vi.removed, [1], [1], [undefined])"
1822                 << "verify(vi.inserted, [], [], [])"
1823                 << "verify(si.removed, [], [], [])"
1824                 << "verify(si.inserted, [], [], [])");
1825
1826
1827     QTest::newRow("item moved from tail")
1828             << QString("listModel.move(3, 0, 1)")
1829             << (QStringList()
1830                 << "verify(vm.removed, [3], [1], [vm.inserted[0].moveId])"
1831                 << "verify(vm.inserted, [0], [1], [vm.removed[0].moveId])"
1832                 << "verify(vi.removed, [3], [1], [vi.inserted[0].moveId])"
1833                 << "verify(vi.inserted, [0], [1], [vi.removed[0].moveId])"
1834                 << "verify(si.removed, [], [], [])"
1835                 << "verify(si.inserted, [], [], [])");
1836     QTest::newRow("item moved from head")
1837             << QString("listModel.move(0, 2, 2)")
1838             << (QStringList()
1839                 << "verify(vm.removed, [0], [2], [vm.inserted[0].moveId])"
1840                 << "verify(vm.inserted, [2], [2], [vm.removed[0].moveId])"
1841                 << "verify(vi.removed, [0], [2], [vi.inserted[0].moveId])"
1842                 << "verify(vi.inserted, [2], [2], [vi.removed[0].moveId])"
1843                 << "verify(si.removed, [], [], [])"
1844                 << "verify(si.inserted, [], [], [])");
1845
1846     QTest::newRow("groups changed")
1847             << QString("items.setGroups(1, 2, [\"items\", \"selected\"])")
1848             << (QStringList()
1849                 << "verify(vm.inserted, [], [], [])"
1850                 << "verify(vm.removed, [], [], [])"
1851                 << "verify(vi.removed, [1], [2], [undefined])"
1852                 << "verify(vi.inserted, [], [], [])"
1853                 << "verify(si.removed, [], [], [])"
1854                 << "verify(si.inserted, [0], [2], [undefined])");
1855
1856     QTest::newRow("multiple removes")
1857             << QString("{ vi.remove(1, 1); "
1858                        "vi.removeGroups(0, 2, \"items\") }")
1859             << (QStringList()
1860                 << "verify(vm.removed, [0, 1], [1, 1], [undefined, undefined])"
1861                 << "verify(vm.inserted, [], [], [])"
1862                 << "verify(vi.removed, [1], [1], [undefined])"
1863                 << "verify(vi.inserted, [], [], [])"
1864                 << "verify(si.removed, [], [], [])"
1865                 << "verify(si.inserted, [], [], [])");
1866 }
1867
1868 void tst_qquickvisualdatamodel::onChanged()
1869 {
1870     QFETCH(QString, expression);
1871     QFETCH(QStringList, tests);
1872
1873     QQmlComponent component(&engine, testFileUrl("onChanged.qml"));
1874     QScopedPointer<QObject> object(component.create());
1875     QVERIFY(object);
1876
1877     evaluate<void>(object.data(), expression);
1878
1879     foreach (const QString &test, tests) {
1880         bool passed = evaluate<bool>(object.data(), test);
1881         if (!passed)
1882             qWarning() << test;
1883         QVERIFY(passed);
1884     }
1885 }
1886
1887 void tst_qquickvisualdatamodel::create()
1888 {
1889     QQuickView view;
1890
1891     SingleRoleModel model;
1892     model.list = QStringList()
1893             << "one"
1894             << "two"
1895             << "three"
1896             << "four"
1897             << "five"
1898             << "six"
1899             << "seven"
1900             << "eight"
1901             << "nine"
1902             << "ten"
1903             << "eleven"
1904             << "twelve"
1905             << "thirteen"
1906             << "fourteen"
1907             << "fifteen"
1908             << "sixteen"
1909             << "seventeen"
1910             << "eighteen"
1911             << "nineteen"
1912             << "twenty";
1913
1914     QQmlContext *ctxt = view.rootContext();
1915     ctxt->setContextProperty("myModel", &model);
1916
1917     view.setSource(testFileUrl("create.qml"));
1918
1919     QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject());
1920     QVERIFY(listview != 0);
1921
1922     QQuickItem *contentItem = listview->contentItem();
1923     QVERIFY(contentItem != 0);
1924
1925     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
1926     QVERIFY(visualModel);
1927
1928     QCOMPARE(listview->count(), 20);
1929
1930     QQmlGuard<QQuickItem> delegate;
1931
1932     // persistedItems.includeByDefault is true, so all items belong to persistedItems initially.
1933     QVERIFY(delegate = findItem<QQuickItem>(contentItem, "delegate", 1));
1934     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1935
1936     // changing include by default doesn't remove persistance.
1937     evaluate<void>(visualModel, "persistedItems.includeByDefault = false");
1938     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1939
1940     // removing from persistedItems does.
1941     evaluate<void>(visualModel, "persistedItems.remove(0, 20)");
1942     QCOMPARE(listview->count(), 20);
1943     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1944
1945     // Request an item instantiated by the view.
1946     QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(1)")));
1947     QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 1));
1948     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1949     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1950
1951     evaluate<void>(delegate, "VisualDataModel.inPersistedItems = false");
1952     QCOMPARE(listview->count(), 20);
1953     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
1954     QVERIFY(delegate);
1955     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1956     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1957
1958     // Request an item not instantiated by the view.
1959     QVERIFY(!findItem<QQuickItem>(contentItem, "delegate", 15));
1960     QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(15)")));
1961     QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 15));
1962     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1963     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1964
1965     evaluate<void>(visualModel, "persistedItems.remove(0)");
1966     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
1967     QVERIFY(!delegate);
1968     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1969
1970     // Request an item not instantiated by the view, then scroll the view so it will request it.
1971     QVERIFY(!findItem<QQuickItem>(contentItem, "delegate", 16));
1972     QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(16)")));
1973     QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 16));
1974     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1975     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1976
1977     evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)");
1978     QCOMPARE(listview->count(), 20);
1979     evaluate<void>(delegate, "VisualDataModel.groups = [\"items\"]");
1980     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
1981     QVERIFY(delegate);
1982     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1983     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1984
1985     // Request and release an item instantiated by the view, then scroll the view so it releases it.
1986     QVERIFY(findItem<QQuickItem>(contentItem, "delegate", 17));
1987     QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(17)")));
1988     QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 17));
1989     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1990     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1991
1992     evaluate<void>(visualModel, "items.removeGroups(17, \"persistedItems\")");
1993     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
1994     QVERIFY(delegate);
1995     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1996     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1997     evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)");
1998     QCOMPARE(listview->count(), 20);
1999     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
2000     QVERIFY(!delegate);
2001
2002     // Adding an item to the persistedItems group won't instantiate it, but if later requested by
2003     // the view it will be persisted.
2004     evaluate<void>(visualModel, "items.addGroups(18, \"persistedItems\")");
2005     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
2006     QVERIFY(!findItem<QQuickItem>(contentItem, "delegate", 18));
2007     evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)");
2008     QCOMPARE(listview->count(), 20);
2009     QVERIFY(delegate = findItem<QQuickItem>(contentItem, "delegate", 18));
2010     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
2011     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
2012     QVERIFY(delegate);
2013     evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)");
2014     QCOMPARE(listview->count(), 20);
2015     QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete);
2016     QVERIFY(delegate);
2017
2018     // Remove an uninstantiated but cached item from the persistedItems group.
2019     evaluate<void>(visualModel, "items.addGroups(19, \"persistedItems\")");
2020     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 2);
2021     QVERIFY(!findItem<QQuickItem>(contentItem, "delegate", 19));
2022      // Store a reference to the item so it is retained in the cache.
2023     evaluate<void>(visualModel, "persistentHandle = items.get(19)");
2024     QCOMPARE(evaluate<bool>(visualModel, "persistentHandle.inPersistedItems"), true);
2025     evaluate<void>(visualModel, "items.removeGroups(19, \"persistedItems\")");
2026     QCOMPARE(evaluate<bool>(visualModel, "persistentHandle.inPersistedItems"), false);
2027 }
2028
2029 void tst_qquickvisualdatamodel::incompleteModel()
2030 {
2031     // VisualDataModel is first populated in componentComplete.  Verify various functions are
2032     // harmlessly ignored until then.
2033
2034     QQmlComponent component(&engine);
2035     component.setData("import QtQuick 2.0\n VisualDataModel {}", testFileUrl(""));
2036
2037     QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
2038
2039     QQuickVisualDataModel *model = qobject_cast<QQuickVisualDataModel *>(object.data());
2040     QVERIFY(model);
2041
2042     QSignalSpy itemsSpy(model->items(), SIGNAL(countChanged()));
2043     QSignalSpy persistedItemsSpy(model->items(), SIGNAL(countChanged()));
2044
2045     evaluate<void>(model, "items.removeGroups(0, items.count, \"items\")");
2046     QCOMPARE(itemsSpy.count(), 0);
2047     QCOMPARE(persistedItemsSpy.count(), 0);
2048
2049     evaluate<void>(model, "items.setGroups(0, items.count, \"persistedItems\")");
2050     QCOMPARE(itemsSpy.count(), 0);
2051     QCOMPARE(persistedItemsSpy.count(), 0);
2052
2053     evaluate<void>(model, "items.addGroups(0, items.count, \"persistedItems\")");
2054     QCOMPARE(itemsSpy.count(), 0);
2055     QCOMPARE(persistedItemsSpy.count(), 0);
2056
2057     evaluate<void>(model, "items.remove(0, items.count)");
2058     QCOMPARE(itemsSpy.count(), 0);
2059     QCOMPARE(persistedItemsSpy.count(), 0);
2060
2061     evaluate<void>(model, "items.insert([ \"color\": \"blue\" ])");
2062     QCOMPARE(itemsSpy.count(), 0);
2063     QCOMPARE(persistedItemsSpy.count(), 0);
2064
2065     QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: get: index out of range");
2066     QVERIFY(evaluate<bool>(model, "items.get(0) === undefined"));
2067
2068     component.completeCreate();
2069 }
2070
2071 void tst_qquickvisualdatamodel::insert_data()
2072 {
2073     QTest::addColumn<QUrl>("source");
2074     QTest::addColumn<QString>("expression");
2075     QTest::addColumn<int>("modelCount");
2076     QTest::addColumn<int>("visualCount");
2077     QTest::addColumn<int>("index");
2078     QTest::addColumn<bool>("inItems");
2079     QTest::addColumn<bool>("persisted");
2080     QTest::addColumn<bool>("visible");
2081     QTest::addColumn<bool>("selected");
2082     QTest::addColumn<bool>("modelData");
2083     QTest::addColumn<QString>("property");
2084     QTest::addColumn<QStringList>("propertyData");
2085
2086     const QUrl listModelSource[] = {
2087         testFileUrl("listmodelproperties.qml"),
2088         testFileUrl("listmodelproperties-package.qml") };
2089     const QUrl singleRoleSource[] = {
2090         testFileUrl("singleroleproperties.qml"),
2091         testFileUrl("singleroleproperties-package.qml") };
2092     const QUrl multipleRoleSource[] = {
2093         testFileUrl("multipleroleproperties.qml"),
2094         testFileUrl("multipleroleproperties-package.qml") };
2095     const QUrl stringListSource[] = {
2096         testFileUrl("stringlistproperties.qml"),
2097         testFileUrl("stringlistproperties-package.qml") };
2098     const QUrl objectListSource[] = {
2099         testFileUrl("objectlistproperties.qml"),
2100         testFileUrl("objectlistproperties-package.qml") };
2101
2102     for (int i = 0; i < 2; ++i) {
2103         // List Model.
2104         QTest::newRow("ListModel.items prepend")
2105                 << listModelSource[i]
2106                 << QString("items.insert(0, {\"number\": \"eight\"})")
2107                 << 4 << 5 << 0 << true << false << false << false << true
2108                 << QString("number")
2109                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2110
2111         QTest::newRow("ListModel.items append")
2112                 << listModelSource[i]
2113                 << QString("items.insert({\"number\": \"eight\"})")
2114                 << 4 << 5 << 4 << true << false << false << false << true
2115                 << QString("number")
2116                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2117
2118         QTest::newRow("ListModel.items insert at 2")
2119                 << listModelSource[i]
2120                 << QString("items.insert(2, {\"number\": \"eight\"})")
2121                 << 4 << 5 << 2 << true << false << false << false << true
2122                 << QString("number")
2123                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2124
2125         QTest::newRow("ListModel.items insert at items.get(2)")
2126                 << listModelSource[i]
2127                 << QString("items.insert(items.get(2), {\"number\": \"eight\"})")
2128                 << 4 << 5 << 2 << true << false << false << false << true
2129                 << QString("number")
2130                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2131
2132         QTest::newRow("ListModel.items insert at visibleItems.get(2)")
2133                 << listModelSource[i]
2134                 << QString("items.insert(visibleItems.get(2), {\"number\": \"eight\"})")
2135                 << 4 << 5 << 2 << true << false << false << false << true
2136                 << QString("number")
2137                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2138
2139         QTest::newRow("ListModel.selectedItems insert at items.get(2)")
2140                 << listModelSource[i]
2141                 << QString("selectedItems.insert(items.get(2), {\"number\": \"eight\"})")
2142                 << 4 << 5 << 2 << false << false << false << true << true
2143                 << QString("number")
2144                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2145
2146         QTest::newRow("ListModel.selectedItems insert at visibleItems.get(2)")
2147                 << listModelSource[i]
2148                 << QString("selectedItems.insert(visibleItems.get(2), {\"number\": \"eight\"})")
2149                 << 4 << 5 << 2 << false << false << false << true << true
2150                 << QString("number")
2151                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2152
2153         QTest::newRow("ListModel.items prepend modelData")
2154                 << listModelSource[i]
2155                 << QString("items.insert(0, {\"modelData\": \"eight\"})")
2156                 << 4 << 5 << 0 << true << false << false << false << true
2157                 << QString("number")
2158                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2159
2160         QTest::newRow("ListModel.items prepend, edit number")
2161                 << listModelSource[i]
2162                 << QString("{ "
2163                        "items.insert(0, {\"number\": \"eight\"}); "
2164                        "items.get(0).model.number = \"seven\"; }")
2165                 << 4 << 5 << 0 << true << false << false << false << true
2166                 << QString("number")
2167                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2168
2169         QTest::newRow("ListModel.items prepend, edit modelData")
2170                 << listModelSource[i]
2171                 << QString("{ "
2172                        "items.insert(0, {\"number\": \"eight\"}); "
2173                        "items.get(0).model.modelData = \"seven\"; }")
2174                 << 4 << 5 << 0 << true << false << false << false << true
2175                 << QString("number")
2176                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2177
2178         QTest::newRow("ListModel.items prepend, edit resolved")
2179                 << listModelSource[i]
2180                 << QString("{ "
2181                        "items.insert(0, {\"number\": \"eight\"}); "
2182                        "items.get(2).model.number = \"seven\"; }")
2183                 << 4 << 5 << 0 << true << false << false << false << true
2184                 << QString("number")
2185                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2186
2187         QTest::newRow("ListModel.items prepend with groups")
2188                 << listModelSource[i]
2189                 << QString("items.insert(0, {\"number\": \"eight\"}, [\"visible\", \"truncheon\"])")
2190                 << 4 << 5 << 0 << true << false << true << false << true
2191                 << QString("number")
2192                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2193
2194         QTest::newRow("ListModel.items append with groups")
2195                 << listModelSource[i]
2196                 << QString("items.insert({\"number\": \"eight\"}, [\"visible\", \"selected\"])")
2197                 << 4 << 5 << 4 << true << false << true << true << true
2198                 << QString("number")
2199                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2200
2201         QTest::newRow("ListModel.items insert at 2 with groups")
2202                 << listModelSource[i]
2203                 << QString("items.insert(2, {\"number\": \"eight\"}, \"visible\")")
2204                 << 4 << 5 << 2 << true << false << true << false << true
2205                 << QString("number")
2206                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2207
2208         // create ListModel
2209         QTest::newRow("ListModel.items prepend")
2210                 << listModelSource[i]
2211                 << QString("items.create(0, {\"number\": \"eight\"})")
2212                 << 4 << 5 << 0 << true << true << false << false << true
2213                 << QString("number")
2214                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2215
2216         QTest::newRow("ListModel.items append")
2217                 << listModelSource[i]
2218                 << QString("items.create({\"number\": \"eight\"})")
2219                 << 4 << 5 << 4 << true << true << false << false << true
2220                 << QString("number")
2221                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2222
2223         QTest::newRow("ListModel.items create at 2")
2224                 << listModelSource[i]
2225                 << QString("items.create(2, {\"number\": \"eight\"})")
2226                 << 4 << 5 << 2 << true << true << false << false << true
2227                 << QString("number")
2228                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2229
2230         QTest::newRow("ListModel.items create at items.get(2)")
2231                 << listModelSource[i]
2232                 << QString("items.create(items.get(2), {\"number\": \"eight\"})")
2233                 << 4 << 5 << 2 << true << true << false << false << true
2234                 << QString("number")
2235                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2236
2237         QTest::newRow("ListModel.items create at visibleItems.get(2)")
2238                 << listModelSource[i]
2239                 << QString("items.create(visibleItems.get(2), {\"number\": \"eight\"})")
2240                 << 4 << 5 << 2 << true << true << false << false << true
2241                 << QString("number")
2242                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2243
2244         QTest::newRow("ListModel.selectedItems create at items.get(2)")
2245                 << listModelSource[i]
2246                 << QString("selectedItems.create(items.get(2), {\"number\": \"eight\"})")
2247                 << 4 << 5 << 2 << false << true << false << true << true
2248                 << QString("number")
2249                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2250
2251         QTest::newRow("ListModel.selectedItems create at visibleItems.get(2)")
2252                 << listModelSource[i]
2253                 << QString("selectedItems.create(visibleItems.get(2), {\"number\": \"eight\"})")
2254                 << 4 << 5 << 2 << false << true << false << true << true
2255                 << QString("number")
2256                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2257
2258         QTest::newRow("ListModel.items create prepended")
2259                 << listModelSource[i]
2260                 << QString("items.create(0, {\"number\": \"eight\"})")
2261                 << 4 << 5 << 0 << true << true << false << false << true
2262                 << QString("number")
2263                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2264
2265         QTest::newRow("ListModel.items create appended")
2266                 << listModelSource[i]
2267                 << QString("items.create({\"number\": \"eight\"})")
2268                 << 4 << 5 << 4 << true << true << false << false << true
2269                 << QString("number")
2270                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2271
2272         QTest::newRow("ListModel.items create at 2")
2273                 << listModelSource[i]
2274                 << QString("items.create(2, {\"number\": \"eight\"})")
2275                 << 4 << 5 << 2 << true << true << false << false << true
2276                 << QString("number")
2277                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2278
2279         QTest::newRow("ListModel.items create at items.get(2)")
2280                 << listModelSource[i]
2281                 << QString("items.create(items.get(2), {\"number\": \"eight\"})")
2282                 << 4 << 5 << 2 << true << true << false << false << true
2283                 << QString("number")
2284                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2285
2286         QTest::newRow("ListModel.items create at visibleItems.get(2)")
2287                 << listModelSource[i]
2288                 << QString("items.create(visibleItems.get(2), {\"number\": \"eight\"})")
2289                 << 4 << 5 << 2 << true << true << false << false << true
2290                 << QString("number")
2291                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2292
2293         QTest::newRow("ListModel.create prepend modelData")
2294                 << listModelSource[i]
2295                 << QString("items.create(0, {\"modelData\": \"eight\"})")
2296                 << 4 << 5 << 0 << true << true << false << false << true
2297                 << QString("number")
2298                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2299
2300         QTest::newRow("ListModel.items create prepended, edit number")
2301                 << listModelSource[i]
2302                 << QString("{ "
2303                        "var item = items.create(0, {\"number\": \"eight\"}); "
2304                        "item.setTest3(\"seven\"); }")
2305                 << 4 << 5 << 0 << true << true << false << false << true
2306                 << QString("number")
2307                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2308
2309         QTest::newRow("ListModel.items create prepended, edit model.number")
2310                 << listModelSource[i]
2311                 << QString("{ "
2312                        "var item = items.create(0, {\"number\": \"eight\"}); "
2313                        "item.setTest4(\"seven\"); }")
2314                 << 4 << 5 << 0 << true << true << false << false << true
2315                 << QString("number")
2316                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2317
2318         QTest::newRow("ListModel.items create prepended, edit modelData")
2319                 << listModelSource[i]
2320                 << QString("{ "
2321                        "var item = items.create(0, {\"number\": \"eight\"}); "
2322                        "item.setTest5(\"seven\"); }")
2323                 << 4 << 5 << 0 << true << true << false << false << true
2324                 << QString("number")
2325                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2326
2327         QTest::newRow("ListModel.items create prepended, edit model.modelData")
2328                 << listModelSource[i]
2329                 << QString("{ "
2330                        "var item = items.create(0, {\"number\": \"eight\"}); "
2331                        "item.setTest6(\"seven\"); }")
2332                 << 4 << 5 << 0 << true << true << false << false << true
2333                 << QString("number")
2334                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2335
2336         QTest::newRow("ListModel.items create prepended with groups")
2337                 << listModelSource[i]
2338                 << QString("items.create(0, {\"number\": \"eight\"}, [\"visible\", \"truncheon\"])")
2339                 << 4 << 5 << 0 << true << true << true << false << true
2340                 << QString("number")
2341                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2342
2343         QTest::newRow("ListModel.items create appended with groups")
2344                 << listModelSource[i]
2345                 << QString("items.create({\"number\": \"eight\"}, [\"visible\", \"selected\"])")
2346                 << 4 << 5 << 4 << true << true << true << true << true
2347                 << QString("number")
2348                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2349
2350         QTest::newRow("ListModel.items create inserted  with groups")
2351                 << listModelSource[i]
2352                 << QString("items.create(2, {\"number\": \"eight\"}, \"visible\")")
2353                 << 4 << 5 << 2 << true << true << true << false << true
2354                 << QString("number")
2355                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2356
2357         QTest::newRow("ListModel.items create prepended clear persistence")
2358                 << listModelSource[i]
2359                 << QString("{ items.create(0, {\"number\": \"eight\"}); "
2360                            "items.get(0).inPersistedItems = false }")
2361                 << 4 << 5 << 0 << true << false << false << false << true
2362                 << QString("number")
2363                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2364
2365         QTest::newRow("ListModel.items create appended clear persistence")
2366                 << listModelSource[i]
2367                 << QString("{ items.create({\"number\": \"eight\"}); "
2368                            "items.get(4).inPersistedItems = false }")
2369                 << 4 << 5 << 4 << true << false << false << false << true
2370                 << QString("number")
2371                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2372
2373         QTest::newRow("ListModel.items create inserted clear persistence")
2374                 << listModelSource[i]
2375                 << QString("{ items.create(2, {\"number\": \"eight\"}); "
2376                            "items.get(2).inPersistedItems = false }")
2377                 << 4 << 5 << 2 << true << false << false << false << true
2378                 << QString("number")
2379                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2380
2381         // AbstractItemModel (Single Role).
2382         QTest::newRow("AbstractItemModel.items prepend")
2383                 << singleRoleSource[i]
2384                 << QString("items.insert(0, {\"name\": \"eight\"})")
2385                 << 4 << 5 << 0 << true << false << false << false << true
2386                 << QString("name")
2387                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2388
2389         QTest::newRow("AbstractItemModel.items append")
2390                 << singleRoleSource[i]
2391                 << QString("items.insert({\"name\": \"eight\"})")
2392                 << 4 << 5 << 4 << true << false << false << false << true
2393                 << QString("name")
2394                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2395
2396         QTest::newRow("AbstractItemModel.items insert at 2")
2397                 << singleRoleSource[i]
2398                 << QString("items.insert(2, {\"name\": \"eight\"})")
2399                 << 4 << 5 << 2 << true << false << false << false << true
2400                 << QString("name")
2401                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2402
2403         QTest::newRow("AbstractItemModel.items prepend modelData")
2404                 << singleRoleSource[i]
2405                 << QString("items.insert(0, {\"modelData\": \"eight\"})")
2406                 << 4 << 5 << 0 << true << false << false << false << true
2407                 << QString("name")
2408                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2409
2410         QTest::newRow("AbstractItemModel.items prepend, edit name")
2411                 << singleRoleSource[i]
2412                 << QString("{ "
2413                        "items.insert(0, {\"name\": \"eight\"}); "
2414                        "items.get(0).model.name = \"seven\"; }")
2415                 << 4 << 5 << 0 << true << false << false << false << true
2416                 << QString("name")
2417                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2418
2419         QTest::newRow("AbstractItemModel.items prepend, edit modelData")
2420                 << singleRoleSource[i]
2421                 << QString("{ "
2422                        "items.insert(0, {\"name\": \"eight\"}); "
2423                        "items.get(0).model.modelData = \"seven\"; }")
2424                 << 4 << 5 << 0 << true << false << false << false << true
2425                 << QString("name")
2426                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2427
2428         QTest::newRow("AbstractItemModel.items prepend, edit resolved")
2429                 << singleRoleSource[i]
2430                 << QString("{ "
2431                        "items.insert(0, {\"name\": \"eight\"}); "
2432                        "items.get(2).model.name = \"seven\"; }")
2433                 << 4 << 5 << 0 << true << false << false << false << true
2434                 << QString("name")
2435                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2436
2437         QTest::newRow("AbstractItemModel.create prepend modelData")
2438                 << singleRoleSource[i]
2439                 << QString("items.create(0, {\"modelData\": \"eight\"})")
2440                 << 4 << 5 << 0 << true << true << false << false << true
2441                 << QString("name")
2442                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2443
2444         QTest::newRow("AbstractItemModel.items create prepended, edit name")
2445                 << singleRoleSource[i]
2446                 << QString("{ "
2447                        "var item = items.create(0, {\"name\": \"eight\"}); "
2448                        "item.setTest3(\"seven\"); }")
2449                 << 4 << 5 << 0 << true << true << false << false << true
2450                 << QString("name")
2451                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2452
2453         QTest::newRow("AbstractItemModel.items create prepended, edit model.name")
2454                 << singleRoleSource[i]
2455                 << QString("{ "
2456                        "var item = items.create(0, {\"name\": \"eight\"}); "
2457                        "item.setTest4(\"seven\"); }")
2458                 << 4 << 5 << 0 << true << true << false << false << true
2459                 << QString("name")
2460                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2461
2462         QTest::newRow("AbstractItemModel.items create prepended, edit modelData")
2463                 << singleRoleSource[i]
2464                 << QString("{ "
2465                        "var item = items.create(0, {\"name\": \"eight\"}); "
2466                        "item.setTest5(\"seven\"); }")
2467                 << 4 << 5 << 0 << true << true << false << false << true
2468                 << QString("name")
2469                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2470
2471         QTest::newRow("AbstractItemModel.items create prepended, edit model.modelData")
2472                 << singleRoleSource[i]
2473                 << QString("{ "
2474                        "var item = items.create(0, {\"name\": \"eight\"}); "
2475                        "item.setTest6(\"seven\"); }")
2476                 << 4 << 5 << 0 << true << true << false << false << true
2477                 << QString("name")
2478                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2479 #ifndef QT_NO_WIDGETS
2480         // AbstractItemModel (Multiple Roles).
2481         QTest::newRow("StandardItemModel.items prepend")
2482                 << multipleRoleSource[i]
2483                 << QString("items.insert(0, {\"display\": \"Row 8 Item\"})")
2484                 << 4 << 5 << 0 << true << false << false << false << false
2485                 << QString("display")
2486                 << (QStringList() << "Row 8 Item" << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2487
2488         QTest::newRow("StandardItemModel.items append")
2489                 << multipleRoleSource[i]
2490                 << QString("items.insert({\"display\": \"Row 8 Item\"})")
2491                 << 4 << 5 << 4 << true << false << false << false << false
2492                 << QString("display")
2493                 << (QStringList() << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item" << "Row 8 Item");
2494
2495         QTest::newRow("StandardItemModel.items insert at 2")
2496                 << multipleRoleSource[i]
2497                 << QString("items.insert(2, {\"display\": \"Row 8 Item\"})")
2498                 << 4 << 5 << 2 << true << false << false << false << false
2499                 << QString("display")
2500                 << (QStringList() << "Row 1 Item" << "Row 2 Item" << "Row 8 Item" << "Row 3 Item" << "Row 4 Item");
2501
2502         QTest::newRow("StandardItemModel.items prepend modelData")
2503                 << multipleRoleSource[i]
2504                 << QString("items.insert(0, {\"modelData\": \"Row 8 Item\"})")
2505                 << 4 << 5 << 0 << true << false << false << false << false
2506                 << QString("display")
2507                 << (QStringList() << QString() << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2508
2509         QTest::newRow("StandardItemModel.items prepend, edit display")
2510                 << multipleRoleSource[i]
2511                 << QString("{ "
2512                        "items.insert(0, {\"display\": \"Row 8 Item\"}); "
2513                        "items.get(0).model.display = \"Row 7 Item\"; }")
2514                 << 4 << 5 << 0 << true << false << false << false << false
2515                 << QString("display")
2516                 << (QStringList() << "Row 7 Item" << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2517
2518         QTest::newRow("StandardItemModel.items prepend, edit modelData")
2519                 << multipleRoleSource[i]
2520                 << QString("{ "
2521                        "items.insert(0, {\"display\": \"Row 8 Item\"}); "
2522                        "items.get(0).model.modelData = \"Row 7 Item\"; }")
2523                 << 4 << 5 << 0 << true << false << false << false << false
2524                 << QString("display")
2525                 << (QStringList() << "Row 8 Item" << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2526
2527         QTest::newRow("StandardItemModel.items prepend, edit resolved")
2528                 << multipleRoleSource[i]
2529                 << QString("{ "
2530                        "items.insert(0, {\"display\": \"Row 8 Item\"}); "
2531                        "items.get(2).model.display = \"Row 7 Item\"; }")
2532                 << 4 << 5 << 0 << true << false << false << false << false
2533                 << QString("display")
2534                 << (QStringList() << "Row 8 Item" << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2535
2536         QTest::newRow("StandardItemModel.create prepend modelData")
2537                 << multipleRoleSource[i]
2538                 << QString("items.create(0, {\"modelData\": \"Row 8 Item\"})")
2539                 << 4 << 5 << 0 << true << true << false << false << false
2540                 << QString("display")
2541                 << (QStringList() << QString() << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2542
2543         QTest::newRow("StandardItemModel.items create prepended, edit display")
2544                 << multipleRoleSource[i]
2545                 << QString("{ "
2546                        "var item = items.create(0, {\"display\": \"Row 8 Item\"}); "
2547                        "item.setTest3(\"Row 7 Item\"); }")
2548                 << 4 << 5 << 0 << true << true << false << false << false
2549                 << QString("display")
2550                 << (QStringList() << "Row 7 Item" << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2551
2552         QTest::newRow("StandardItemModel.items create prepended, edit model.display")
2553                 << multipleRoleSource[i]
2554                 << QString("{ "
2555                        "var item = items.create(0, {\"display\": \"Row 8 Item\"}); "
2556                        "item.setTest4(\"Row 7 Item\"); }")
2557                 << 4 << 5 << 0 << true << true << false << false << false
2558                 << QString("display")
2559                 << (QStringList() << "Row 7 Item" << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
2560 #endif
2561         // StringList.
2562         QTest::newRow("StringList.items prepend")
2563                 << stringListSource[i]
2564                 << QString("items.insert(0, {\"modelData\": \"eight\"})")
2565                 << 4 << 5 << 0 << true << false << false << false << false
2566                 << QString("modelData")
2567                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2568
2569         QTest::newRow("StringList.items append")
2570                 << stringListSource[i]
2571                 << QString("items.insert({\"modelData\": \"eight\"})")
2572                 << 4 << 5 << 4 << true << false << false << false << false
2573                 << QString("modelData")
2574                 << (QStringList() << "one" << "two" << "three" << "four" << "eight");
2575
2576         QTest::newRow("StringList.items insert at 2")
2577                 << stringListSource[i]
2578                 << QString("items.insert(2, {\"modelData\": \"eight\"})")
2579                 << 4 << 5 << 2 << true << false << false << false << false
2580                 << QString("modelData")
2581                 << (QStringList() << "one" << "two" << "eight" << "three" << "four");
2582
2583         QTest::newRow("StringList.items prepend, edit modelData")
2584                 << stringListSource[i]
2585                 << QString("{ "
2586                        "items.insert(0, {\"modelData\": \"eight\"}); "
2587                        "items.get(0).model.modelData = \"seven\"; }")
2588                 << 4 << 5 << 0 << true << false << false << false << false
2589                 << QString("modelData")
2590                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2591
2592         QTest::newRow("StringList.items prepend, edit resolved")
2593                 << stringListSource[i]
2594                 << QString("{ "
2595                        "items.insert(0, {\"modelData\": \"eight\"}); "
2596                        "items.get(2).model.modelData = \"seven\"; }")
2597                 << 4 << 5 << 0 << true << false << false << false << false
2598                 << QString("modelData")
2599                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2600
2601         QTest::newRow("StringList.create prepend modelData")
2602                 << stringListSource[i]
2603                 << QString("items.create(0, {\"modelData\": \"eight\"})")
2604                 << 4 << 5 << 0 << true << true << false << false << false
2605                 << QString("modelData")
2606                 << (QStringList() << "eight" << "one" << "two" << "three" << "four");
2607
2608         QTest::newRow("StringList.items create prepended, edit modelData")
2609                 << stringListSource[i]
2610                 << QString("{ "
2611                        "var item = items.create(0, {\"modelData\": \"eight\"}); "
2612                        "item.setTest3(\"seven\"); }")
2613                 << 4 << 5 << 0 << true << true << false << false << false
2614                 << QString("modelData")
2615                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2616
2617         QTest::newRow("StringList.items create prepended, edit model.modelData")
2618                 << stringListSource[i]
2619                 << QString("{ "
2620                        "var item = items.create(0, {\"modelData\": \"eight\"}); "
2621                        "item.setTest4(\"seven\"); }")
2622                 << 4 << 5 << 0 << true << true << false << false << false
2623                 << QString("modelData")
2624                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2625
2626         // ObjectList
2627         QTest::newRow("ObjectList.items prepend")
2628                 << objectListSource[i]
2629                 << QString("items.insert(0, {\"name\": \"Item 8\"})")
2630                 << 4 << 4 << 4 << false << false << false << false << false
2631                 << QString("name")
2632                 << (QStringList() << "Item 1" << "Item 2" << "Item 3" << "Item 4");
2633
2634         QTest::newRow("ObjectList.items append")
2635                 << objectListSource[i]
2636                 << QString("items.insert({\"name\": \"Item 8\"})")
2637                 << 4 << 4 << 4 << false << false << false << false << false
2638                 << QString("name")
2639                 << (QStringList() << "Item 1" << "Item 2" << "Item 3" << "Item 4");
2640
2641         QTest::newRow("ObjectList.items insert at 2")
2642                 << objectListSource[i]
2643                 << QString("items.insert(2, {\"name\": \"Item 8\"})")
2644                 << 4 << 4 << 4 << false << false << false << false << false
2645                 << QString("name")
2646                 << (QStringList() << "Item 1" << "Item 2" << "Item 3" << "Item 4");
2647     }
2648 }
2649
2650 void tst_qquickvisualdatamodel::insert()
2651 {
2652     QFETCH(QUrl, source);
2653     QFETCH(QString, expression);
2654     QFETCH(int, modelCount);
2655     QFETCH(int, visualCount);
2656     QFETCH(int, index);
2657     QFETCH(bool, inItems);
2658     QFETCH(bool, persisted);
2659     QFETCH(bool, visible);
2660     QFETCH(bool, selected);
2661     QFETCH(bool, modelData);
2662     QFETCH(QString, property);
2663     QFETCH(QStringList, propertyData);
2664
2665     QQuickCanvas canvas;
2666
2667     QQmlComponent component(&engine);
2668     component.loadUrl(source);
2669     QScopedPointer<QObject> object(component.create());
2670     QQuickListView *listView = qobject_cast<QQuickListView *>(object.data());
2671     QVERIFY(listView);
2672     listView->setParentItem(canvas.rootItem());
2673
2674     QQuickItem *contentItem = listView->contentItem();
2675     QVERIFY(contentItem);
2676
2677     QObject *visualModel = listView->findChild<QObject *>("visualModel");
2678     QVERIFY(visualModel);
2679
2680     evaluate<void>(visualModel, expression);
2681
2682     QCOMPARE(evaluate<int>(listView, "count"), inItems ? visualCount : modelCount);
2683     QCOMPARE(evaluate<int>(visualModel, "count"), inItems ? visualCount : modelCount);
2684     QCOMPARE(evaluate<int>(visualModel, "items.count"), inItems ? visualCount : modelCount);
2685     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), persisted ? 1 : 0);
2686     QCOMPARE(evaluate<int>(visualModel, "visibleItems.count"), visible ? visualCount : modelCount);
2687     QCOMPARE(evaluate<int>(visualModel, "selectedItems.count"), selected ? 1 : 0);
2688
2689     QCOMPARE(propertyData.count(), visualCount);
2690     for (int i = 0; i < visualCount; ++i) {
2691         int modelIndex = i;
2692         if (modelIndex > index)
2693             modelIndex -= 1;
2694         else if (modelIndex == index)
2695             modelIndex = -1;
2696
2697         const int itemsIndex = inItems || i <= index ? i : i - 1;
2698         QString get;
2699
2700         if (i != index) {
2701             get = QString("items.get(%1)").arg(itemsIndex);
2702
2703             QQuickItem *item = findItem<QQuickItem>(contentItem, "delegate", modelIndex);
2704             QVERIFY(item);
2705
2706             QCOMPARE(evaluate<int>(item, "test1"), modelIndex);
2707             QCOMPARE(evaluate<int>(item, "test2"), modelIndex);
2708             QCOMPARE(evaluate<QString>(item, "test3"), propertyData.at(i));
2709             QCOMPARE(evaluate<QString>(item, "test4"), propertyData.at(i));
2710
2711             if (modelData) {
2712                 QCOMPARE(evaluate<QString>(item, "test5"), propertyData.at(i));
2713                 QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(i));
2714             }
2715
2716             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), true);
2717             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), false);
2718             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), true);
2719             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), false);
2720             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), false);
2721
2722             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), itemsIndex);
2723             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), persisted && i > index ? 1 : 0);
2724             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), visible || i <= index ? i : i - 1);
2725             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), selected && i > index ? 1 : 0);
2726         } else if (inItems) {
2727             get = QString("items.get(%1)").arg(index);
2728         } else if (persisted) {
2729             get = "persistedItems.get(0)";
2730         } else if (visible) {
2731             get = QString("visibleItems.get(%1)").arg(index);
2732         } else if (selected) {
2733             get = "selectedItems.get(0)";
2734         } else {
2735             continue;
2736         }
2737
2738         QCOMPARE(evaluate<int>(visualModel, get + ".model.index"), modelIndex);
2739
2740         QCOMPARE(evaluate<QString>(visualModel, get + ".model." + property), propertyData.at(i));
2741
2742         QCOMPARE(evaluate<bool>(visualModel, get + ".inItems"), inItems || i != index);
2743         QCOMPARE(evaluate<bool>(visualModel, get + ".inPersistedItems"), persisted && i == index);
2744         QCOMPARE(evaluate<bool>(visualModel, get + ".inVisible"), visible || i != index);
2745         QCOMPARE(evaluate<bool>(visualModel, get + ".inSelected"), selected && i == index);
2746         QCOMPARE(evaluate<bool>(visualModel, get + ".isUnresolved"), i == index);
2747
2748         QCOMPARE(evaluate<int>(visualModel, get + ".itemsIndex"), inItems || i <= index ? i : i - 1);
2749         QCOMPARE(evaluate<int>(visualModel, get + ".persistedItemsIndex"), persisted && i > index ? 1 : 0);
2750         QCOMPARE(evaluate<int>(visualModel, get + ".visibleIndex"), visible || i <= index ? i : i - 1);
2751         QCOMPARE(evaluate<int>(visualModel, get + ".selectedIndex"), selected && i > index ? 1 : 0);
2752     }
2753
2754     QObject *item = 0;
2755
2756     if (inItems)
2757         item = evaluate<QObject *>(visualModel, QString("items.create(%1)").arg(index));
2758     else if (persisted)
2759         item = evaluate<QObject *>(visualModel, QString("persistedItems.create(%1)").arg(0));
2760     else if (visible)
2761         item = evaluate<QObject *>(visualModel, QString("visibleItems.create(%1)").arg(index));
2762     else if (selected)
2763         item = evaluate<QObject *>(visualModel, QString("selectedItems.create(%1)").arg(0));
2764     else
2765         return;
2766
2767     QVERIFY(item);
2768
2769     QCOMPARE(evaluate<int>(item, "test1"), -1);
2770     QCOMPARE(evaluate<int>(item, "test2"), -1);
2771     QCOMPARE(evaluate<QString>(item, "test3"), propertyData.at(index));
2772     QCOMPARE(evaluate<QString>(item, "test4"), propertyData.at(index));
2773
2774     if (modelData) {
2775         QCOMPARE(evaluate<QString>(item, "test5"), propertyData.at(index));
2776         QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(index));
2777     }
2778
2779     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), inItems);
2780     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), true);
2781     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), visible);
2782     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), selected);
2783     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), true);
2784
2785     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), index);
2786     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), 0);
2787     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), index);
2788     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), 0);
2789 }
2790
2791 void tst_qquickvisualdatamodel::resolve_data()
2792 {
2793     QTest::addColumn<QUrl>("source");
2794     QTest::addColumn<QString>("setupExpression");
2795     QTest::addColumn<QString>("resolveExpression");
2796     QTest::addColumn<int>("unresolvedCount");
2797     QTest::addColumn<int>("modelCount");
2798     QTest::addColumn<int>("visualCount");
2799     QTest::addColumn<int>("index");
2800     QTest::addColumn<bool>("inItems");
2801     QTest::addColumn<bool>("persisted");
2802     QTest::addColumn<bool>("visible");
2803     QTest::addColumn<bool>("selected");
2804     QTest::addColumn<bool>("modelData");
2805     QTest::addColumn<QString>("property");
2806     QTest::addColumn<QStringList>("propertyData");
2807
2808     const QUrl listModelSource[] = {
2809         testFileUrl("listmodelproperties.qml"),
2810         testFileUrl("listmodelproperties-package.qml") };
2811     const QUrl singleRoleSource[] = {
2812         testFileUrl("singleroleproperties.qml"),
2813         testFileUrl("singleroleproperties-package.qml") };
2814     const QUrl multipleRoleSource[] = {
2815         testFileUrl("multipleroleproperties.qml"),
2816         testFileUrl("multipleroleproperties-package.qml") };
2817     const QUrl stringListSource[] = {
2818         testFileUrl("stringlistproperties.qml"),
2819         testFileUrl("stringlistproperties-package.qml") };
2820
2821     for (int i = 0; i < 2; ++i) {
2822         // List Model.
2823         QTest::newRow("ListModel.items prepend, resolve prepended")
2824                 << listModelSource[i]
2825                 << QString("items.insert(0, {\"number\": \"eight\"})")
2826                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); items.resolve(0, 1) }")
2827                 << 5 << 5 << 5 << 0 << true << false << true << false << true
2828                 << QString("number")
2829                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2830
2831         QTest::newRow("ListModel.items prepend, resolve appended")
2832                 << listModelSource[i]
2833                 << QString("items.insert(0, {\"number\": \"eight\"})")
2834                 << QString("{ listModel.append({\"number\": \"seven\"}); items.resolve(0, 5) }")
2835                 << 5 << 5 << 5 << 4 << true << false << true << false << true
2836                 << QString("number")
2837                 << (QStringList() << "one" << "two" << "three" << "four" << "seven");
2838
2839         QTest::newRow("ListModel.items prepend, resolve inserted")
2840                 << listModelSource[i]
2841                 << QString("items.insert(0, {\"number\": \"eight\"})")
2842                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); items.resolve(0, 3) }")
2843                 << 5 << 5 << 5 << 2 << true << false << true << false << true
2844                 << QString("number")
2845                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
2846
2847         QTest::newRow("ListModel.items append, resolve prepended")
2848                 << listModelSource[i]
2849                 << QString("items.insert({\"number\": \"eight\"})")
2850                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); items.resolve(5, 0) }")
2851                 << 5 << 5 << 5 << 0 << true << false << true << false << true
2852                 << QString("number")
2853                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2854
2855         QTest::newRow("ListModel.items append, resolve appended")
2856                 << listModelSource[i]
2857                 << QString("items.insert({\"number\": \"eight\"})")
2858                 << QString("{ listModel.append({\"number\": \"seven\"}); items.resolve(5, 4) }")
2859                 << 5 << 5 << 5 << 4 << true << false << true << false << true
2860                 << QString("number")
2861                 << (QStringList() << "one" << "two" << "three" << "four" << "seven");
2862
2863         QTest::newRow("ListModel.items append, resolve inserted")
2864                 << listModelSource[i]
2865                 << QString("items.insert({\"number\": \"eight\"})")
2866                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); items.resolve(5, 2) }")
2867                 << 5 << 5 << 5 << 2 << true << false << true << false << true
2868                 << QString("number")
2869                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
2870
2871         QTest::newRow("ListModel.items insert, resolve prepended")
2872                 << listModelSource[i]
2873                 << QString("items.insert(2, {\"number\": \"eight\"})")
2874                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); items.resolve(3, 0) }")
2875                 << 5 << 5 << 5 << 0 << true << false << true << false << true
2876                 << QString("number")
2877                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2878
2879         QTest::newRow("ListModel.items insert, resolve appended")
2880                 << listModelSource[i]
2881                 << QString("items.insert(2, {\"number\": \"eight\"})")
2882                 << QString("{ listModel.append({\"number\": \"seven\"}); items.resolve(2, 5) }")
2883                 << 5 << 5 << 5 << 4 << true << false << true << false << true
2884                 << QString("number")
2885                 << (QStringList() << "one" << "two" << "three" << "four" << "seven");
2886
2887         QTest::newRow("ListModel.items insert, resolve inserted")
2888                 << listModelSource[i]
2889                 << QString("items.insert(2, {\"number\": \"eight\"})")
2890                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); items.resolve(2, 3) }")
2891                 << 5 << 5 << 5 << 2 << true << false << true << false << true
2892                 << QString("number")
2893                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
2894
2895         QTest::newRow("ListModel.items prepend, move resolved")
2896                 << listModelSource[i]
2897                 << QString("items.insert(0, {\"number\": \"eight\"})")
2898                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); "
2899                            "items.resolve(0, 1); "
2900                            "listModel.move(0, 2, 1) }")
2901                 << 5 << 5 << 5 << 2 << true << false << true << false << true
2902                 << QString("number")
2903                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
2904
2905         QTest::newRow("ListModel.items append, move resolved")
2906                 << listModelSource[i]
2907                 << QString("items.insert({\"number\": \"eight\"})")
2908                 << QString("{ listModel.append({\"number\": \"seven\"}); "
2909                            "items.resolve(5, 4); "
2910                            "listModel.move(4, 2, 1) }")
2911                 << 5 << 5 << 5 << 2 << true << false << true << false << true
2912                 << QString("number")
2913                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
2914
2915         QTest::newRow("ListModel.items insert, move resolved")
2916                 << listModelSource[i]
2917                 << QString("items.insert(2, {\"number\": \"eight\"})")
2918                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); "
2919                            "items.resolve(2, 3);"
2920                            "listModel.move(2, 0, 1) }")
2921                 << 5 << 5 << 5 << 0 << true << false << true << false << true
2922                 << QString("number")
2923                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2924
2925         QTest::newRow("ListModel.items prepend, remove resolved")
2926                 << listModelSource[i]
2927                 << QString("items.insert(0, {\"number\": \"eight\"})")
2928                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); "
2929                            "items.resolve(0, 1); "
2930                            "listModel.remove(0, 1) }")
2931                 << 5 << 4 << 4 << 4 << false << false << false << false << true
2932                 << QString("number")
2933                 << (QStringList() << "one" << "two" << "three" << "four");
2934
2935         QTest::newRow("ListModel.items append, remove resolved")
2936                 << listModelSource[i]
2937                 << QString("items.insert({\"number\": \"eight\"})")
2938                 << QString("{ listModel.append({\"number\": \"seven\"}); "
2939                            "items.resolve(5, 4); "
2940                            "listModel.remove(4, 1) }")
2941                 << 5 << 4 << 4 << 4 << false << false << false << false << true
2942                 << QString("number")
2943                 << (QStringList() << "one" << "two" << "three" << "four");
2944
2945         QTest::newRow("ListModel.items insert, remove resolved")
2946                 << listModelSource[i]
2947                 << QString("items.insert(2, {\"number\": \"eight\"})")
2948                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); "
2949                            "items.resolve(2, 3);"
2950                            "listModel.remove(2, 1) }")
2951                 << 5 << 4 << 4 << 4 << false << false << false << false << true
2952                 << QString("number")
2953                 << (QStringList() << "one" << "two" << "three" << "four");
2954
2955         QTest::newRow("ListModel.selectedItems prepend, resolve prepended")
2956                 << listModelSource[i]
2957                 << QString("selectedItems.insert(0, {\"number\": \"eight\"})")
2958                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); "
2959                            "selectedItems.resolve(selectedItems.get(0), items.get(0)) }")
2960                 << 4 << 5 << 5 << 0 << true << false << true << true << true
2961                 << QString("number")
2962                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2963
2964         QTest::newRow("ListModel.selectedItems prepend, resolve appended")
2965                 << listModelSource[i]
2966                 << QString("selectedItems.insert(0, {\"number\": \"eight\"})")
2967                 << QString("{ listModel.append({\"number\": \"seven\"}); "
2968                            "selectedItems.resolve(selectedItems.get(0), items.get(4)) }")
2969                 << 4 << 5 << 5 << 4 << true << false << true << true << true
2970                 << QString("number")
2971                 << (QStringList() << "one" << "two" << "three" << "four" << "seven");
2972
2973         QTest::newRow("ListModel.selectedItems prepend, resolve inserted")
2974                 << listModelSource[i]
2975                 << QString("selectedItems.insert(0, {\"number\": \"eight\"})")
2976                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); "
2977                            "selectedItems.resolve(selectedItems.get(0), items.get(2)) }")
2978                 << 4 << 5 << 5 << 2 << true << false << true << true << true
2979                 << QString("number")
2980                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
2981
2982         QTest::newRow("ListModel.selectedItems append, resolve prepended")
2983                 << listModelSource[i]
2984                 << QString("selectedItems.insert({\"number\": \"eight\"})")
2985                 << QString("{ listModel.insert(0, {\"number\": \"seven\"}); "
2986                            "selectedItems.resolve(selectedItems.get(0), items.get(0)) }")
2987                 << 4 << 5 << 5 << 0 << true << false << true << true << true
2988                 << QString("number")
2989                 << (QStringList() << "seven" << "one" << "two" << "three" << "four");
2990
2991         QTest::newRow("ListModel.selectedItems append, resolve appended")
2992                 << listModelSource[i]
2993                 << QString("selectedItems.insert({\"number\": \"eight\"})")
2994                 << QString("{ listModel.append({\"number\": \"seven\"}); "
2995                            "selectedItems.resolve(selectedItems.get(0), items.get(4)) }")
2996                 << 4 << 5 << 5 << 4 << true << false << true << true << true
2997                 << QString("number")
2998                 << (QStringList() << "one" << "two" << "three" << "four" << "seven");
2999
3000         QTest::newRow("ListModel.selectedItems append, resolve inserted")
3001                 << listModelSource[i]
3002                 << QString("selectedItems.insert({\"number\": \"eight\"})")
3003                 << QString("{ listModel.insert(2, {\"number\": \"seven\"}); "
3004                            "selectedItems.resolve(selectedItems.get(0), items.get(2)) }")
3005                 << 4 << 5 << 5 << 2 << true << false << true << true << true
3006                 << QString("number")
3007                 << (QStringList() << "one" << "two" << "seven" << "three" << "four");
3008
3009         // AbstractItemModel (Single Role)
3010         QTest::newRow("ListModel.items prepend, resolve prepended")
3011                 << singleRoleSource[i]
3012                 << QString("items.insert(0, {\"name\": \"eight\"})")
3013                 << QString("{ items.resolve(0, 1) }")
3014                 << 5 << 4 << 4 << 0 << true << false << true << false << true
3015                 << QString("name")
3016                 << (QStringList() << "one" << "two" << "three" << "four");
3017
3018
3019         QTest::newRow("ListModel.items append, resolve appended")
3020                 << singleRoleSource[i]
3021                 << QString("items.insert({\"name\": \"eight\"})")
3022                 << QString("{ items.resolve(4, 3) }")
3023                 << 5 << 4 << 4 << 3 << true << false << true << false << true
3024                 << QString("name")
3025                 << (QStringList() << "one" << "two" << "three" << "four");
3026
3027         QTest::newRow("ListModel.items insert, resolve inserted")
3028                 << singleRoleSource[i]
3029                 << QString("items.insert(2, {\"name\": \"eight\"})")
3030                 << QString("{ items.resolve(2, 3) }")
3031                 << 5 << 4 << 4 << 2 << true << false << true << false << true
3032                 << QString("name")
3033                 << (QStringList() << "one" << "two" << "three" << "four");
3034
3035         // AbstractItemModel (Single Role)
3036         QTest::newRow("AbstractItemModel.items prepend, resolve prepended")
3037                 << singleRoleSource[i]
3038                 << QString("items.insert(0, {\"name\": \"eight\"})")
3039                 << QString("{ items.resolve(0, 1) }")
3040                 << 5 << 4 << 4 << 0 << true << false << true << false << true
3041                 << QString("name")
3042                 << (QStringList() << "one" << "two" << "three" << "four");
3043
3044         QTest::newRow("AbstractItemModel.items append, resolve appended")
3045                 << singleRoleSource[i]
3046                 << QString("items.insert({\"name\": \"eight\"})")
3047                 << QString("{ items.resolve(4, 3) }")
3048                 << 5 << 4 << 4 << 3 << true << false << true << false << true
3049                 << QString("name")
3050                 << (QStringList() << "one" << "two" << "three" << "four");
3051
3052         QTest::newRow("AbstractItemModel.items insert, resolve inserted")
3053                 << singleRoleSource[i]
3054                 << QString("items.insert(2, {\"name\": \"eight\"})")
3055                 << QString("{ items.resolve(2, 3) }")
3056                 << 5 << 4 << 4 << 2 << true << false << true << false << true
3057                 << QString("name")
3058                 << (QStringList() << "one" << "two" << "three" << "four");
3059
3060 #ifndef QT_NO_WIDGETS
3061         // AbstractItemModel (Multiple Roles)
3062         QTest::newRow("StandardItemModel.items prepend, resolve prepended")
3063                 << multipleRoleSource[i]
3064                 << QString("items.insert(0, {\"display\": \"Row 8 Item\"})")
3065                 << QString("{ items.resolve(0, 1) }")
3066                 << 5 << 4 << 4 << 0 << true << false << true << false << false
3067                 << QString("display")
3068                 << (QStringList() << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
3069
3070         QTest::newRow("StandardItemModel.items append, resolve appended")
3071                 << multipleRoleSource[i]
3072                 << QString("items.insert({\"display\": \"Row 8 Item\"})")
3073                 << QString("{ items.resolve(4, 3) }")
3074                 << 5 << 4 << 4 << 3 << true << false << true << false << false
3075                 << QString("display")
3076                 << (QStringList() << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
3077
3078         QTest::newRow("StandardItemModel.items insert, resolve inserted")
3079                 << multipleRoleSource[i]
3080                 << QString("items.insert(2, {\"display\": \"Row 8 Item\"})")
3081                 << QString("{ items.resolve(2, 3) }")
3082                 << 5 << 4 << 4 << 2 << true << false << true << false << false
3083                 << QString("display")
3084                 << (QStringList() << "Row 1 Item" << "Row 2 Item" << "Row 3 Item" << "Row 4 Item");
3085 #endif
3086         // StringList
3087         QTest::newRow("StringList.items prepend, resolve prepended")
3088                 << stringListSource[i]
3089                 << QString("items.insert(0, {\"modelData\": \"eight\"})")
3090                 << QString("{ items.resolve(0, 1) }")
3091                 << 5 << 4 << 4 << 0 << true << false << true << false << false
3092                 << QString("modelData")
3093                 << (QStringList() << "one" << "two" << "three" << "four");
3094
3095         QTest::newRow("StringList.items append, resolve appended")
3096                 << stringListSource[i]
3097                 << QString("items.insert({\"modelData\": \"eight\"})")
3098                 << QString("{ items.resolve(4, 3) }")
3099                 << 5 << 4 << 4 << 3 << true << false << true << false << false
3100                 << QString("modelData")
3101                 << (QStringList() << "one" << "two" << "three" << "four");
3102
3103         QTest::newRow("StringList.items insert, resolve inserted")
3104                 << stringListSource[i]
3105                 << QString("items.insert(2, {\"modelData\": \"eight\"})")
3106                 << QString("{ items.resolve(2, 3) }")
3107                 << 5 << 4 << 4 << 2 << true << false << true << false << false
3108                 << QString("modelData")
3109                 << (QStringList() << "one" << "two" << "three" << "four");
3110     }
3111 }
3112
3113 void tst_qquickvisualdatamodel::resolve()
3114 {
3115     QFETCH(QUrl, source);
3116     QFETCH(QString, setupExpression);
3117     QFETCH(QString, resolveExpression);
3118     QFETCH(int, unresolvedCount);
3119     QFETCH(int, modelCount);
3120     QFETCH(int, visualCount);
3121     QFETCH(int, index);
3122     QFETCH(bool, inItems);
3123     QFETCH(bool, persisted);
3124     QFETCH(bool, visible);
3125     QFETCH(bool, selected);
3126     QFETCH(bool, modelData);
3127     QFETCH(QString, property);
3128     QFETCH(QStringList, propertyData);
3129
3130     QQuickCanvas canvas;
3131
3132     QQmlComponent component(&engine);
3133     component.loadUrl(source);
3134     QScopedPointer<QObject> object(component.create());
3135     QQuickListView *listView = qobject_cast<QQuickListView *>(object.data());
3136     QVERIFY(listView);
3137     listView->setParentItem(canvas.rootItem());
3138
3139     QQuickItem *contentItem = listView->contentItem();
3140     QVERIFY(contentItem);
3141
3142     QObject *visualModel = listView->findChild<QObject *>("visualModel");
3143     QVERIFY(visualModel);
3144
3145     evaluate<void>(visualModel, setupExpression);
3146     QCOMPARE(evaluate<int>(listView, "count"), unresolvedCount);
3147
3148     evaluate<void>(visualModel, resolveExpression);
3149
3150     QCOMPARE(evaluate<int>(listView, "count"), inItems ? visualCount : modelCount);
3151     QCOMPARE(evaluate<int>(visualModel, "count"), inItems ? visualCount : modelCount);
3152     QCOMPARE(evaluate<int>(visualModel, "items.count"), inItems ? visualCount : modelCount);
3153     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), persisted ? 1 : 0);
3154     QCOMPARE(evaluate<int>(visualModel, "visibleItems.count"), visible ? visualCount : modelCount);
3155     QCOMPARE(evaluate<int>(visualModel, "selectedItems.count"), selected ? 1 : 0);
3156
3157     QCOMPARE(propertyData.count(), visualCount);
3158     for (int i = 0; i < visualCount; ++i) {
3159         int modelIndex = i;
3160
3161         const int itemsIndex = inItems || i <= index ? i : i - 1;
3162         QString get;
3163
3164         if (i != index) {
3165             get = QString("items.get(%1)").arg(itemsIndex);
3166
3167             QQuickItem *item = findItem<QQuickItem>(contentItem, "delegate", modelIndex);
3168             QVERIFY(item);
3169
3170             QCOMPARE(evaluate<int>(item, "test1"), modelIndex);
3171             QCOMPARE(evaluate<int>(item, "test2"), modelIndex);
3172             QCOMPARE(evaluate<QString>(item, "test3"), propertyData.at(i));
3173             QCOMPARE(evaluate<QString>(item, "test4"), propertyData.at(i));
3174
3175             if (modelData) {
3176                 QCOMPARE(evaluate<QString>(item, "test5"), propertyData.at(i));
3177                 QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(i));
3178             }
3179
3180             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), true);
3181             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), false);
3182             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), true);
3183             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), false);
3184             QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), false);
3185
3186             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), itemsIndex);
3187             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), persisted && i > index ? 1 : 0);
3188             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), visible || i <= index ? i : i - 1);
3189             QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), selected && i > index ? 1 : 0);
3190         } else if (inItems) {
3191             get = QString("items.get(%1)").arg(index);
3192         } else if (persisted) {
3193             get = "persistedItems.get(0)";
3194         } else if (visible) {
3195             get = QString("visibleItems.get(%1)").arg(index);
3196         } else if (selected) {
3197             get = "selectedItems.get(0)";
3198         } else {
3199             continue;
3200         }
3201
3202         QCOMPARE(evaluate<int>(visualModel, get + ".model.index"), modelIndex);
3203
3204         QCOMPARE(evaluate<QString>(visualModel, get + ".model." + property), propertyData.at(i));
3205
3206         QCOMPARE(evaluate<bool>(visualModel, get + ".inItems"), inItems || i != index);
3207         QCOMPARE(evaluate<bool>(visualModel, get + ".inPersistedItems"), persisted && i == index);
3208         QCOMPARE(evaluate<bool>(visualModel, get + ".inVisible"), visible || i != index);
3209         QCOMPARE(evaluate<bool>(visualModel, get + ".inSelected"), selected && i == index);
3210         QCOMPARE(evaluate<bool>(visualModel, get + ".isUnresolved"), false);
3211
3212         QCOMPARE(evaluate<int>(visualModel, get + ".itemsIndex"), inItems || i <= index ? i : i - 1);
3213         QCOMPARE(evaluate<int>(visualModel, get + ".persistedItemsIndex"), persisted && i > index ? 1 : 0);
3214         QCOMPARE(evaluate<int>(visualModel, get + ".visibleIndex"), visible || i <= index ? i : i - 1);
3215         QCOMPARE(evaluate<int>(visualModel, get + ".selectedIndex"), selected && i > index ? 1 : 0);
3216     }
3217
3218     QObject *item = 0;
3219
3220     if (inItems)
3221         item = evaluate<QObject *>(visualModel, QString("items.create(%1)").arg(index));
3222     else if (persisted)
3223         item = evaluate<QObject *>(visualModel, QString("persistedItems.create(%1)").arg(0));
3224     else if (visible)
3225         item = evaluate<QObject *>(visualModel, QString("visibleItems.create(%1)").arg(index));
3226     else if (selected)
3227         item = evaluate<QObject *>(visualModel, QString("selectedItems.create(%1)").arg(0));
3228     else
3229         return;
3230
3231     QVERIFY(item);
3232
3233     QCOMPARE(evaluate<int>(item, "test1"), index);
3234     QCOMPARE(evaluate<int>(item, "test2"), index);
3235     QCOMPARE(evaluate<QString>(item, "test3"), propertyData.at(index));
3236     QCOMPARE(evaluate<QString>(item, "test4"), propertyData.at(index));
3237
3238     if (modelData) {
3239         QCOMPARE(evaluate<QString>(item, "test5"), propertyData.at(index));
3240         QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(index));
3241     }
3242
3243     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), inItems);
3244     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), true);
3245     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), visible);
3246     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), selected);
3247     QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), false);
3248
3249     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), index);
3250     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), 0);
3251     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), index);
3252     QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), 0);
3253 }
3254
3255 void tst_qquickvisualdatamodel::warnings_data()
3256 {
3257     QTest::addColumn<QUrl>("source");
3258     QTest::addColumn<QString>("expression");
3259     QTest::addColumn<QString>("warning");
3260     QTest::addColumn<int>("count");
3261
3262     QTest::newRow("insert < 0")
3263             << testFileUrl("listmodelproperties.qml")
3264             << QString("items.insert(-2, {\"number\": \"eight\"})")
3265             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("insert: index out of range"))
3266             << 4;
3267
3268     QTest::newRow("insert > length")
3269             << testFileUrl("listmodelproperties.qml")
3270             << QString("items.insert(8, {\"number\": \"eight\"})")
3271             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("insert: index out of range"))
3272             << 4;
3273
3274     QTest::newRow("create < 0")
3275             << testFileUrl("listmodelproperties.qml")
3276             << QString("items.create(-2, {\"number\": \"eight\"})")
3277             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("create: index out of range"))
3278             << 4;
3279
3280     QTest::newRow("create > length")
3281             << testFileUrl("listmodelproperties.qml")
3282             << QString("items.create(8, {\"number\": \"eight\"})")
3283             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("create: index out of range"))
3284             << 4;
3285
3286     QTest::newRow("resolve from < 0")
3287             << testFileUrl("listmodelproperties.qml")
3288             << QString("items.resolve(-2, 3)")
3289             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: from index out of range"))
3290             << 4;
3291
3292     QTest::newRow("resolve from > length")
3293             << testFileUrl("listmodelproperties.qml")
3294             << QString("items.resolve(8, 3)")
3295             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: from index out of range"))
3296             << 4;
3297
3298     QTest::newRow("resolve to < 0")
3299             << testFileUrl("listmodelproperties.qml")
3300             << QString("items.resolve(3, -2)")
3301             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: to index out of range"))
3302             << 4;
3303
3304     QTest::newRow("resolve to > length")
3305             << testFileUrl("listmodelproperties.qml")
3306             << QString("items.resolve(3, 8)")
3307             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: to index out of range"))
3308             << 4;
3309
3310     QTest::newRow("resolve from invalid index")
3311             << testFileUrl("listmodelproperties.qml")
3312             << QString("items.resolve(\"two\", 3)")
3313             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: from index invalid"))
3314             << 4;
3315
3316     QTest::newRow("resolve to invalid index")
3317             << testFileUrl("listmodelproperties.qml")
3318             << QString("items.resolve(3, \"two\")")
3319             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: to index invalid"))
3320             << 4;
3321
3322     QTest::newRow("resolve already resolved item")
3323             << testFileUrl("listmodelproperties.qml")
3324             << QString("items.resolve(3, 2)")
3325             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: from is not an unresolved item"))
3326             << 4;
3327
3328     QTest::newRow("resolve already resolved item")
3329             << testFileUrl("listmodelproperties.qml")
3330             << QString("{ items.insert(0, {\"number\": \"eight\"});"
3331                        "items.insert(1, {\"number\": \"seven\"});"
3332                        "items.resolve(0, 1)}")
3333             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("resolve: to is not a model item"))
3334             << 6;
3335
3336     QTest::newRow("remove index < 0")
3337             << testFileUrl("listmodelproperties.qml")
3338             << QString("items.remove(-2, 1)")
3339             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("remove: index out of range"))
3340             << 4;
3341
3342     QTest::newRow("remove index == length")
3343             << testFileUrl("listmodelproperties.qml")
3344             << QString("items.remove(4, 1)")
3345             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("remove: index out of range"))
3346             << 4;
3347
3348     QTest::newRow("remove index > length")
3349             << testFileUrl("listmodelproperties.qml")
3350             << QString("items.remove(9, 1)")
3351             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("remove: index out of range"))
3352             << 4;
3353
3354     QTest::newRow("remove invalid index")
3355             << testFileUrl("listmodelproperties.qml")
3356             << QString("items.remove(\"nine\", 1)")
3357             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("remove: invalid index"))
3358             << 4;
3359
3360     QTest::newRow("remove count < 0")
3361             << testFileUrl("listmodelproperties.qml")
3362             << QString("items.remove(1, -2)")
3363             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("remove: invalid count"))
3364             << 4;
3365
3366     QTest::newRow("remove index + count > length")
3367             << testFileUrl("listmodelproperties.qml")
3368             << QString("items.remove(2, 4, \"selected\")")
3369             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("remove: invalid count"))
3370             << 4;
3371
3372     QTest::newRow("addGroups index < 0")
3373             << testFileUrl("listmodelproperties.qml")
3374             << QString("items.addGroups(-2, 1, \"selected\")")
3375             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("addGroups: index out of range"))
3376             << 4;
3377
3378     QTest::newRow("addGroups index == length")
3379             << testFileUrl("listmodelproperties.qml")
3380             << QString("items.addGroups(4, 1, \"selected\")")
3381             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("addGroups: index out of range"))
3382             << 4;
3383
3384     QTest::newRow("addGroups index > length")
3385             << testFileUrl("listmodelproperties.qml")
3386             << QString("items.addGroups(9, 1, \"selected\")")
3387             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("addGroups: index out of range"))
3388             << 4;
3389
3390     QTest::newRow("addGroups count < 0")
3391             << testFileUrl("listmodelproperties.qml")
3392             << QString("items.addGroups(1, -2, \"selected\")")
3393             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("addGroups: invalid count"))
3394             << 4;
3395
3396     QTest::newRow("addGroups index + count > length")
3397             << testFileUrl("listmodelproperties.qml")
3398             << QString("items.addGroups(2, 4, \"selected\")")
3399             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("addGroups: invalid count"))
3400             << 4;
3401
3402     QTest::newRow("removeGroups index < 0")
3403             << testFileUrl("listmodelproperties.qml")
3404             << QString("items.removeGroups(-2, 1, \"selected\")")
3405             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("removeGroups: index out of range"))
3406             << 4;
3407
3408     QTest::newRow("removeGroups index == length")
3409             << testFileUrl("listmodelproperties.qml")
3410             << QString("items.removeGroups(4, 1, \"selected\")")
3411             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("removeGroups: index out of range"))
3412             << 4;
3413
3414     QTest::newRow("removeGroups index > length")
3415             << testFileUrl("listmodelproperties.qml")
3416             << QString("items.removeGroups(9, 1, \"selected\")")
3417             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("removeGroups: index out of range"))
3418             << 4;
3419
3420     QTest::newRow("removeGroups count < 0")
3421             << testFileUrl("listmodelproperties.qml")
3422             << QString("items.removeGroups(1, -2, \"selected\")")
3423             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("removeGroups: invalid count"))
3424             << 4;
3425
3426     QTest::newRow("removeGroups index + count > length")
3427             << testFileUrl("listmodelproperties.qml")
3428             << QString("items.removeGroups(2, 4, \"selected\")")
3429             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("removeGroups: invalid count"))
3430             << 4;
3431
3432     QTest::newRow("setGroups index < 0")
3433             << testFileUrl("listmodelproperties.qml")
3434             << QString("items.setGroups(-2, 1, \"selected\")")
3435             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("setGroups: index out of range"))
3436             << 4;
3437
3438     QTest::newRow("setGroups index == length")
3439             << testFileUrl("listmodelproperties.qml")
3440             << QString("items.setGroups(4, 1, \"selected\")")
3441             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("setGroups: index out of range"))
3442             << 4;
3443
3444     QTest::newRow("setGroups index > length")
3445             << testFileUrl("listmodelproperties.qml")
3446             << QString("items.setGroups(9, 1, \"selected\")")
3447             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("setGroups: index out of range"))
3448             << 4;
3449
3450     QTest::newRow("setGroups count < 0")
3451             << testFileUrl("listmodelproperties.qml")
3452             << QString("items.setGroups(1, -2, \"selected\")")
3453             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("setGroups: invalid count"))
3454             << 4;
3455
3456     QTest::newRow("setGroups index + count > length")
3457             << testFileUrl("listmodelproperties.qml")
3458             << QString("items.setGroups(2, 4, \"selected\")")
3459             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("setGroups: invalid count"))
3460             << 4;
3461
3462     QTest::newRow("move from < 0")
3463             << testFileUrl("listmodelproperties.qml")
3464             << QString("items.move(-2, 1, 1)")
3465             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: from index out of range"))
3466             << 4;
3467
3468     QTest::newRow("move from == length")
3469             << testFileUrl("listmodelproperties.qml")
3470             << QString("items.move(4, 1, 1)")
3471             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: from index out of range"))
3472             << 4;
3473
3474     QTest::newRow("move from > length")
3475             << testFileUrl("listmodelproperties.qml")
3476             << QString("items.move(9, 1, 1)")
3477             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: from index out of range"))
3478             << 4;
3479
3480     QTest::newRow("move invalid from")
3481             << testFileUrl("listmodelproperties.qml")
3482             << QString("items.move(\"nine\", 1, 1)")
3483             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: invalid from index"))
3484             << 4;
3485
3486     QTest::newRow("move to < 0")
3487             << testFileUrl("listmodelproperties.qml")
3488             << QString("items.move(1, -2, 1)")
3489             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: to index out of range"))
3490             << 4;
3491
3492     QTest::newRow("move to == length")
3493             << testFileUrl("listmodelproperties.qml")
3494             << QString("items.move(1, 4, 1)")
3495             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: to index out of range"))
3496             << 4;
3497
3498     QTest::newRow("move to > length")
3499             << testFileUrl("listmodelproperties.qml")
3500             << QString("items.move(1, 9, 1)")
3501             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: to index out of range"))
3502             << 4;
3503
3504     QTest::newRow("move invalid to")
3505             << testFileUrl("listmodelproperties.qml")
3506             << QString("items.move(1, \"nine\", 1)")
3507             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: invalid to index"))
3508             << 4;
3509
3510     QTest::newRow("move count < 0")
3511             << testFileUrl("listmodelproperties.qml")
3512             << QString("items.move(1, 1, -2)")
3513             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: invalid count"))
3514             << 4;
3515
3516     QTest::newRow("move from + count > length")
3517             << testFileUrl("listmodelproperties.qml")
3518             << QString("items.move(2, 1, 4)")
3519             << ("<Unknown File>: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("move: from index out of range"))
3520             << 4;
3521 }
3522
3523 void tst_qquickvisualdatamodel::warnings()
3524 {
3525     QFETCH(QUrl, source);
3526     QFETCH(QString, expression);
3527     QFETCH(QString, warning);
3528     QFETCH(int, count);
3529
3530     QQuickCanvas canvas;
3531
3532     QQmlComponent component(&engine);
3533     component.loadUrl(source);
3534     QScopedPointer<QObject> object(component.create());
3535     QQuickListView *listView = qobject_cast<QQuickListView *>(object.data());
3536     QVERIFY(listView);
3537     listView->setParentItem(canvas.rootItem());
3538
3539     QQuickItem *contentItem = listView->contentItem();
3540     QVERIFY(contentItem);
3541
3542     QObject *visualModel = evaluate<QObject *>(listView, "model");
3543     QVERIFY(visualModel);
3544
3545     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
3546
3547     evaluate<void>(visualModel, expression);
3548     QCOMPARE(evaluate<int>(listView, "count"), count);
3549 }
3550
3551 void tst_qquickvisualdatamodel::invalidAttachment()
3552 {
3553     QQmlComponent component(&engine);
3554     component.loadUrl(testFileUrl("invalidAttachment.qml"));
3555
3556     QScopedPointer<QObject> object(component.create());
3557     QVERIFY(object);
3558     QCOMPARE(component.errors().count(), 0);
3559
3560     QVariant property = object->property("invalidVdm");
3561     QCOMPARE(property.userType(), qMetaTypeId<QQuickVisualDataModel *>());
3562     QVERIFY(!property.value<QQuickVisualDataModel *>());
3563
3564     QQuickItem *item = findItem<QQuickItem>(static_cast<QQuickItem *>(object.data()), "delegate");
3565     QVERIFY(item);
3566
3567     property = item->property("validVdm");
3568     QCOMPARE(property.userType(), qMetaTypeId<QQuickVisualDataModel *>());
3569     QVERIFY(property.value<QQuickVisualDataModel *>());
3570
3571     property = item->property("invalidVdm");
3572     QCOMPARE(property.userType(), qMetaTypeId<QQuickVisualDataModel *>());
3573     QVERIFY(!property.value<QQuickVisualDataModel *>());
3574 }
3575
3576 void tst_qquickvisualdatamodel::asynchronousInsert_data()
3577 {
3578     QTest::addColumn<int>("requestIndex");
3579     QTest::addColumn<int>("insertIndex");
3580     QTest::addColumn<int>("insertCount");
3581     QTest::addColumn<int>("completeIndex");
3582
3583     QTest::newRow("insert before") << 4 << 1 << 3 << 7;
3584     QTest::newRow("insert after")  << 4 << 6 << 3 << 4;
3585     QTest::newRow("insert at")     << 4 << 4 << 3 << 7;
3586 }
3587
3588 void tst_qquickvisualdatamodel::asynchronousInsert()
3589 {
3590     QFETCH(int, requestIndex);
3591     QFETCH(int, insertIndex);
3592     QFETCH(int, insertCount);
3593     QFETCH(int, completeIndex);
3594
3595     QCOMPARE(controller.incubatingObjectCount(), 0);
3596
3597     QQmlComponent c(&engine, testFileUrl("visualdatamodel.qml"));
3598
3599     QmlListModel model;
3600     for (int i = 0; i < 8; i++)
3601         model.addItem("Original item" + QString::number(i), "");
3602
3603     engine.rootContext()->setContextProperty("myModel", &model);
3604
3605     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel*>(c.create());
3606     QVERIFY(visualModel);
3607
3608     ItemRequester requester;
3609     connect(visualModel, SIGNAL(initItem(int,QQuickItem*)), &requester, SLOT(initItem(int,QQuickItem*)));
3610     connect(visualModel, SIGNAL(createdItem(int,QQuickItem*)), &requester, SLOT(createdItem(int,QQuickItem*)));
3611     connect(visualModel, SIGNAL(destroyingItem(QQuickItem*)), &requester, SLOT(destroyingItem(QQuickItem*)));
3612
3613     QQuickItem *item = visualModel->item(requestIndex, true);
3614     QVERIFY(!item);
3615
3616     QVERIFY(!requester.itemInitialized);
3617     QVERIFY(!requester.itemCreated);
3618     QVERIFY(!requester.itemDestroyed);
3619
3620     QList<QPair<QString, QString> > newItems;
3621     for (int i = 0; i < insertCount; i++)
3622         newItems.append(qMakePair(QLatin1String("New item") + QString::number(i), QString(QLatin1String(""))));
3623     model.insertItems(insertIndex, newItems);
3624
3625     item = visualModel->item(completeIndex, false);
3626     QVERIFY(item);
3627
3628     QCOMPARE(requester.itemInitialized, item);
3629     QCOMPARE(requester.indexInitialized, completeIndex);
3630     QCOMPARE(requester.itemCreated, item);
3631     QCOMPARE(requester.indexCreated, completeIndex);
3632     QVERIFY(!requester.itemDestroyed);
3633
3634     QCOMPARE(controller.incubatingObjectCount(), 0);
3635
3636     visualModel->release(item);
3637
3638     QCOMPARE(requester.itemDestroyed, item);
3639 }
3640
3641 void tst_qquickvisualdatamodel::asynchronousRemove_data()
3642 {
3643     QTest::addColumn<int>("requestIndex");
3644     QTest::addColumn<int>("removeIndex");
3645     QTest::addColumn<int>("removeCount");
3646     QTest::addColumn<int>("completeIndex");
3647
3648     QTest::newRow("remove before")    << 4 << 1 << 3 << 1;
3649     QTest::newRow("remove after")     << 4 << 6 << 2 << 4;
3650     QTest::newRow("remove requested") << 4 << 4 << 3 << -1;
3651 }
3652
3653 void tst_qquickvisualdatamodel::asynchronousRemove()
3654 {
3655     QFETCH(int, requestIndex);
3656     QFETCH(int, removeIndex);
3657     QFETCH(int, removeCount);
3658     QFETCH(int, completeIndex);
3659
3660     QCOMPARE(controller.incubatingObjectCount(), 0);
3661
3662     QQmlComponent c(&engine, testFileUrl("visualdatamodel.qml"));
3663
3664     QmlListModel model;
3665     for (int i = 0; i < 8; i++)
3666         model.addItem("Original item" + QString::number(i), "");
3667
3668     engine.rootContext()->setContextProperty("myModel", &model);
3669
3670     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel*>(c.create());
3671     QVERIFY(visualModel);
3672
3673     ItemRequester requester;
3674     connect(visualModel, SIGNAL(initItem(int,QQuickItem*)), &requester, SLOT(initItem(int,QQuickItem*)));
3675     connect(visualModel, SIGNAL(createdItem(int,QQuickItem*)), &requester, SLOT(createdItem(int,QQuickItem*)));
3676     connect(visualModel, SIGNAL(destroyingItem(QQuickItem*)), &requester, SLOT(destroyingItem(QQuickItem*)));
3677
3678     QQuickItem *item = visualModel->item(requestIndex, true);
3679     QVERIFY(!item);
3680
3681     QVERIFY(!requester.itemInitialized);
3682     QVERIFY(!requester.itemCreated);
3683     QVERIFY(!requester.itemDestroyed);
3684
3685     model.removeItems(removeIndex, removeCount);
3686
3687     if (completeIndex == -1) {
3688         QElapsedTimer timer;
3689         timer.start();
3690         do {
3691             controller.incubateFor(50);
3692         } while (timer.elapsed() < 1000 && controller.incubatingObjectCount() > 0);
3693
3694         QVERIFY(requester.itemInitialized);
3695         QCOMPARE(requester.itemCreated, requester.itemInitialized);
3696         QCOMPARE(requester.itemDestroyed, requester.itemInitialized);
3697     } else {
3698         item = visualModel->item(completeIndex, false);
3699         QVERIFY(item);
3700
3701         QCOMPARE(requester.itemInitialized, item);
3702         QCOMPARE(requester.indexInitialized, completeIndex);
3703         QCOMPARE(requester.itemCreated, item);
3704         QCOMPARE(requester.indexCreated, completeIndex);
3705         QVERIFY(!requester.itemDestroyed);
3706
3707         QCOMPARE(controller.incubatingObjectCount(), 0);
3708
3709         visualModel->release(item);
3710
3711         QCOMPARE(requester.itemDestroyed, item);
3712     }
3713 }
3714
3715 void tst_qquickvisualdatamodel::asynchronousMove_data()
3716 {
3717     QTest::addColumn<int>("requestIndex");
3718     QTest::addColumn<int>("from");
3719     QTest::addColumn<int>("to");
3720     QTest::addColumn<int>("count");
3721     QTest::addColumn<int>("completeIndex");
3722
3723     QTest::newRow("move before")          << 4 << 1 << 0 << 3 << 4;
3724     QTest::newRow("move after")           << 4 << 6 << 5 << 2 << 4;
3725     QTest::newRow("move requested")       << 4 << 4 << 3 << 2 << 3;
3726     QTest::newRow("move before to after") << 4 << 1 << 4 << 3 << 1;
3727     QTest::newRow("move after to before") << 4 << 6 << 2 << 2 << 6;
3728 }
3729
3730 void tst_qquickvisualdatamodel::asynchronousMove()
3731 {
3732     QFETCH(int, requestIndex);
3733     QFETCH(int, from);
3734     QFETCH(int, to);
3735     QFETCH(int, count);
3736     QFETCH(int, completeIndex);
3737
3738     QCOMPARE(controller.incubatingObjectCount(), 0);
3739
3740     QQmlComponent c(&engine, testFileUrl("visualdatamodel.qml"));
3741
3742     QmlListModel model;
3743     for (int i = 0; i < 8; i++)
3744         model.addItem("Original item" + QString::number(i), "");
3745
3746     engine.rootContext()->setContextProperty("myModel", &model);
3747
3748     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel*>(c.create());
3749     QVERIFY(visualModel);
3750
3751     ItemRequester requester;
3752     connect(visualModel, SIGNAL(initItem(int,QQuickItem*)), &requester, SLOT(initItem(int,QQuickItem*)));
3753     connect(visualModel, SIGNAL(createdItem(int,QQuickItem*)), &requester, SLOT(createdItem(int,QQuickItem*)));
3754     connect(visualModel, SIGNAL(destroyingItem(QQuickItem*)), &requester, SLOT(destroyingItem(QQuickItem*)));
3755
3756     QQuickItem *item = visualModel->item(requestIndex, true);
3757     QVERIFY(!item);
3758
3759     QVERIFY(!requester.itemInitialized);
3760     QVERIFY(!requester.itemCreated);
3761     QVERIFY(!requester.itemDestroyed);
3762
3763     model.moveItems(from, to, count);
3764
3765     item = visualModel->item(completeIndex, false);
3766     QVERIFY(item);
3767
3768
3769     QCOMPARE(requester.itemInitialized, item);
3770     QCOMPARE(requester.indexInitialized, completeIndex);
3771     QCOMPARE(requester.itemCreated, item);
3772     QCOMPARE(requester.indexCreated, completeIndex);
3773     QVERIFY(!requester.itemDestroyed);
3774
3775     QCOMPARE(controller.incubatingObjectCount(), 0);
3776
3777     visualModel->release(item);
3778
3779     QCOMPARE(requester.itemDestroyed, item);
3780 }
3781
3782 void tst_qquickvisualdatamodel::asynchronousCancel()
3783 {
3784     const int requestIndex = 4;
3785
3786     QCOMPARE(controller.incubatingObjectCount(), 0);
3787
3788     QQmlComponent c(&engine, testFileUrl("visualdatamodel.qml"));
3789
3790     QmlListModel model;
3791     for (int i = 0; i < 8; i++)
3792         model.addItem("Original item" + QString::number(i), "");
3793
3794     engine.rootContext()->setContextProperty("myModel", &model);
3795
3796     QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel*>(c.create());
3797     QVERIFY(visualModel);
3798
3799     QQuickItem *item = visualModel->item(requestIndex, true);
3800     QVERIFY(!item);
3801     QCOMPARE(controller.incubatingObjectCount(), 1);
3802
3803     visualModel->cancel(requestIndex);
3804     QCOMPARE(controller.incubatingObjectCount(), 0);
3805 }
3806
3807 QTEST_MAIN(tst_qquickvisualdatamodel)
3808
3809 #include "tst_qquickvisualdatamodel.moc"