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