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