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