d9fec3f8b3e1217ec6f2cf5d4b386e8f2459bad4
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qsgvisualdatamodel / tst_qsgvisualdatamodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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 "../../../shared/util.h"
43 #include <qtest.h>
44 #include <QtTest/QSignalSpy>
45 #include <QStandardItemModel>
46 #include <QtDeclarative/qdeclarativeengine.h>
47 #include <QtDeclarative/qdeclarativecomponent.h>
48 #include <QtDeclarative/qdeclarativecontext.h>
49 #include <QtDeclarative/qdeclarativeexpression.h>
50 #include <QtDeclarative/qsgview.h>
51 #include <private/qsglistview_p.h>
52 #include <private/qsgtext_p.h>
53 #include <private/qsgvisualdatamodel_p.h>
54 #include <private/qdeclarativevaluetype_p.h>
55 #include <private/qdeclarativechangeset_p.h>
56 #include <private/qdeclarativeengine_p.h>
57 #include <math.h>
58
59 template <typename T, int N> int lengthOf(const T (&)[N]) { return N; }
60
61 static void initStandardTreeModel(QStandardItemModel *model)
62 {
63     QStandardItem *item;
64     item = new QStandardItem(QLatin1String("Row 1 Item"));
65     model->insertRow(0, item);
66
67     item = new QStandardItem(QLatin1String("Row 2 Item"));
68     item->setCheckable(true);
69     model->insertRow(1, item);
70
71     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
72     item->setChild(0, childItem);
73
74     item = new QStandardItem(QLatin1String("Row 3 Item"));
75     item->setIcon(QIcon());
76     model->insertRow(2, item);
77 }
78
79 class SingleRoleModel : public QAbstractListModel
80 {
81     Q_OBJECT
82
83 public:
84     SingleRoleModel(const QByteArray &role = "name", QObject *parent = 0) {
85         QHash<int, QByteArray> roles;
86         roles.insert(Qt::DisplayRole , role);
87         setRoleNames(roles);
88         list << "one" << "two" << "three" << "four";
89     }
90
91     void emitMove(int sourceFirst, int sourceLast, int destinationChild) {
92         emit beginMoveRows(QModelIndex(), sourceFirst, sourceLast, QModelIndex(), destinationChild);
93         emit endMoveRows();
94     }
95
96     QStringList list;
97
98 public slots:
99     void set(int idx, QString string) {
100         list[idx] = string;
101         emit dataChanged(index(idx,0), index(idx,0));
102     }
103
104 protected:
105     int rowCount(const QModelIndex &parent = QModelIndex()) const {
106         return list.count();
107     }
108     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
109         if (role == Qt::DisplayRole)
110             return list.at(index.row());
111         return QVariant();
112     }
113 };
114
115
116 class tst_qsgvisualdatamodel : public QObject
117 {
118     Q_OBJECT
119 public:
120     tst_qsgvisualdatamodel();
121
122 private slots:
123     void initTestCase();
124     void cleanupTestCase();
125     void rootIndex();
126     void updateLayout();
127     void childChanged();
128     void objectListModel();
129     void singleRole();
130     void modelProperties();
131     void noDelegate();
132     void qaimRowsMoved();
133     void qaimRowsMoved_data();
134     void remove();
135     void move();
136     void groups();
137     void get();
138     void create();
139
140 private:
141     template <int N> void groups_verify(
142             const SingleRoleModel &model,
143             QSGItem *contentItem,
144             const int (&mIndex)[N],
145             const int (&iIndex)[N],
146             const int (&vIndex)[N],
147             const int (&sIndex)[N],
148             const bool (&vMember)[N],
149             const bool (&sMember)[N]);
150
151     template <int N> void get_verify(
152             const SingleRoleModel &model,
153             QSGVisualDataModel *visualModel,
154             QSGVisualDataGroup *visibleItems,
155             QSGVisualDataGroup *selectedItems,
156             const int (&mIndex)[N],
157             const int (&iIndex)[N],
158             const int (&vIndex)[N],
159             const int (&sIndex)[N],
160             const bool (&vMember)[N],
161             const bool (&sMember)[N]);
162
163     bool failed;
164     QDeclarativeEngine engine;
165     template<typename T>
166     T *findItem(QSGItem *parent, const QString &objectName, int index);
167 };
168
169 Q_DECLARE_METATYPE(QDeclarativeChangeSet)
170
171 void tst_qsgvisualdatamodel::initTestCase()
172 {
173     qRegisterMetaType<QDeclarativeChangeSet>();
174 }
175
176 void tst_qsgvisualdatamodel::cleanupTestCase()
177 {
178
179 }
180 class DataObject : public QObject
181 {
182     Q_OBJECT
183
184     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
185     Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
186
187 public:
188     DataObject(QObject *parent=0) : QObject(parent) {}
189     DataObject(const QString &name, const QString &color, QObject *parent=0)
190         : QObject(parent), m_name(name), m_color(color) { }
191
192
193     QString name() const { return m_name; }
194     void setName(const QString &name) {
195         if (name != m_name) {
196             m_name = name;
197             emit nameChanged();
198         }
199     }
200
201     QString color() const { return m_color; }
202     void setColor(const QString &color) {
203         if (color != m_color) {
204             m_color = color;
205             emit colorChanged();
206         }
207     }
208
209 signals:
210     void nameChanged();
211     void colorChanged();
212
213 private:
214     QString m_name;
215     QString m_color;
216 };
217
218 template <typename T> static T evaluate(QObject *scope, const QString &expression)
219 {
220     QDeclarativeExpression expr(qmlContext(scope), scope, expression);
221     T result = expr.evaluate().value<T>();
222     if (expr.hasError())
223         qWarning() << expr.error().toString();
224     return result;
225 }
226
227 template <> void evaluate<void>(QObject *scope, const QString &expression)
228 {
229     QDeclarativeExpression expr(qmlContext(scope), scope, expression);
230     expr.evaluate();
231     if (expr.hasError())
232         qWarning() << expr.error().toString();
233 }
234
235 tst_qsgvisualdatamodel::tst_qsgvisualdatamodel()
236 {
237 }
238
239 void tst_qsgvisualdatamodel::rootIndex()
240 {
241     QDeclarativeEngine engine;
242     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("visualdatamodel.qml")));
243
244     QStandardItemModel model;
245     initStandardTreeModel(&model);
246
247     engine.rootContext()->setContextProperty("myModel", &model);
248
249     QSGVisualDataModel *obj = qobject_cast<QSGVisualDataModel*>(c.create());
250     QVERIFY(obj != 0);
251
252     QMetaObject::invokeMethod(obj, "setRoot");
253     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == model.index(0,0));
254
255     QMetaObject::invokeMethod(obj, "setRootToParent");
256     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == QModelIndex());
257
258     QMetaObject::invokeMethod(obj, "setRoot");
259     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == model.index(0,0));
260     model.clear(); // will emit modelReset()
261     QVERIFY(qvariant_cast<QModelIndex>(obj->rootIndex()) == QModelIndex());
262
263     delete obj;
264 }
265
266 void tst_qsgvisualdatamodel::updateLayout()
267 {
268     QSGView view;
269
270     QStandardItemModel model;
271     initStandardTreeModel(&model);
272
273     view.rootContext()->setContextProperty("myModel", &model);
274
275     view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml")));
276
277     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
278     QVERIFY(listview != 0);
279
280     QSGItem *contentItem = listview->contentItem();
281     QVERIFY(contentItem != 0);
282
283     QSGText *name = findItem<QSGText>(contentItem, "display", 0);
284     QVERIFY(name);
285     QCOMPARE(name->text(), QString("Row 1 Item"));
286     name = findItem<QSGText>(contentItem, "display", 1);
287     QVERIFY(name);
288     QCOMPARE(name->text(), QString("Row 2 Item"));
289     name = findItem<QSGText>(contentItem, "display", 2);
290     QVERIFY(name);
291     QCOMPARE(name->text(), QString("Row 3 Item"));
292
293     model.invisibleRootItem()->sortChildren(0, Qt::DescendingOrder);
294
295     name = findItem<QSGText>(contentItem, "display", 0);
296     QVERIFY(name);
297     QCOMPARE(name->text(), QString("Row 3 Item"));
298     name = findItem<QSGText>(contentItem, "display", 1);
299     QVERIFY(name);
300     QCOMPARE(name->text(), QString("Row 2 Item"));
301     name = findItem<QSGText>(contentItem, "display", 2);
302     QVERIFY(name);
303     QCOMPARE(name->text(), QString("Row 1 Item"));
304 }
305
306 void tst_qsgvisualdatamodel::childChanged()
307 {
308     QSGView view;
309
310     QStandardItemModel model;
311     initStandardTreeModel(&model);
312
313     view.rootContext()->setContextProperty("myModel", &model);
314
315     view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml")));
316
317     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
318     QVERIFY(listview != 0);
319
320     QSGItem *contentItem = listview->contentItem();
321     QVERIFY(contentItem != 0);
322
323     QSGVisualDataModel *vdm = listview->findChild<QSGVisualDataModel*>("visualModel");
324     vdm->setRootIndex(QVariant::fromValue(model.indexFromItem(model.item(1,0))));
325     QCOMPARE(listview->count(), 1);
326
327     QSGText *name = findItem<QSGText>(contentItem, "display", 0);
328     QVERIFY(name);
329     QCOMPARE(name->text(), QString("Row 2 Child Item"));
330
331     model.item(1,0)->child(0,0)->setText("Row 2 updated child");
332
333     name = findItem<QSGText>(contentItem, "display", 0);
334     QVERIFY(name);
335     QCOMPARE(name->text(), QString("Row 2 updated child"));
336
337     model.item(1,0)->appendRow(new QStandardItem(QLatin1String("Row 2 Child Item 2")));
338     QCOMPARE(listview->count(), 2);
339
340     name = findItem<QSGText>(contentItem, "display", 1);
341     QVERIFY(name != 0);
342     QCOMPARE(name->text(), QString("Row 2 Child Item 2"));
343
344     model.item(1,0)->takeRow(1);
345     name = findItem<QSGText>(contentItem, "display", 1);
346     QVERIFY(name == 0);
347
348     vdm->setRootIndex(QVariant::fromValue(QModelIndex()));
349     QCOMPARE(listview->count(), 3);
350     name = findItem<QSGText>(contentItem, "display", 0);
351     QVERIFY(name);
352     QCOMPARE(name->text(), QString("Row 1 Item"));
353     name = findItem<QSGText>(contentItem, "display", 1);
354     QVERIFY(name);
355     QCOMPARE(name->text(), QString("Row 2 Item"));
356     name = findItem<QSGText>(contentItem, "display", 2);
357     QVERIFY(name);
358     QCOMPARE(name->text(), QString("Row 3 Item"));
359 }
360
361 void tst_qsgvisualdatamodel::objectListModel()
362 {
363     QSGView view;
364
365     QList<QObject*> dataList;
366     dataList.append(new DataObject("Item 1", "red"));
367     dataList.append(new DataObject("Item 2", "green"));
368     dataList.append(new DataObject("Item 3", "blue"));
369     dataList.append(new DataObject("Item 4", "yellow"));
370
371     QDeclarativeContext *ctxt = view.rootContext();
372     ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
373
374     view.setSource(QUrl::fromLocalFile(TESTDATA("objectlist.qml")));
375
376     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
377     QVERIFY(listview != 0);
378
379     QSGItem *contentItem = listview->contentItem();
380     QVERIFY(contentItem != 0);
381
382     QSGText *name = findItem<QSGText>(contentItem, "name", 0);
383     QCOMPARE(name->text(), QString("Item 1"));
384
385     QSGText *section = findItem<QSGText>(contentItem, "section", 0);
386     QCOMPARE(section->text(), QString("Item 1"));
387
388     dataList[0]->setProperty("name", QLatin1String("Changed"));
389     QCOMPARE(name->text(), QString("Changed"));
390 }
391
392 void tst_qsgvisualdatamodel::singleRole()
393 {
394     {
395         QSGView view;
396
397         SingleRoleModel model;
398
399         QDeclarativeContext *ctxt = view.rootContext();
400         ctxt->setContextProperty("myModel", &model);
401
402         view.setSource(QUrl::fromLocalFile(TESTDATA("singlerole1.qml")));
403
404         QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
405         QVERIFY(listview != 0);
406
407         QSGItem *contentItem = listview->contentItem();
408         QVERIFY(contentItem != 0);
409
410         QSGText *name = findItem<QSGText>(contentItem, "name", 1);
411         QCOMPARE(name->text(), QString("two"));
412
413         model.set(1, "Changed");
414         QCOMPARE(name->text(), QString("Changed"));
415     }
416     {
417         QSGView view;
418
419         SingleRoleModel model;
420
421         QDeclarativeContext *ctxt = view.rootContext();
422         ctxt->setContextProperty("myModel", &model);
423
424         view.setSource(QUrl::fromLocalFile(TESTDATA("singlerole2.qml")));
425
426         QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
427         QVERIFY(listview != 0);
428
429         QSGItem *contentItem = listview->contentItem();
430         QVERIFY(contentItem != 0);
431
432         QSGText *name = findItem<QSGText>(contentItem, "name", 1);
433         QCOMPARE(name->text(), QString("two"));
434
435         model.set(1, "Changed");
436         QCOMPARE(name->text(), QString("Changed"));
437     }
438     {
439         QSGView view;
440
441         SingleRoleModel model("modelData");
442
443         QDeclarativeContext *ctxt = view.rootContext();
444         ctxt->setContextProperty("myModel", &model);
445
446         view.setSource(QUrl::fromLocalFile(TESTDATA("singlerole2.qml")));
447
448         QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
449         QVERIFY(listview != 0);
450
451         QSGItem *contentItem = listview->contentItem();
452         QVERIFY(contentItem != 0);
453
454         QSGText *name = findItem<QSGText>(contentItem, "name", 1);
455         QCOMPARE(name->text(), QString("two"));
456
457         model.set(1, "Changed");
458         QCOMPARE(name->text(), QString("Changed"));
459     }
460 }
461
462 void tst_qsgvisualdatamodel::modelProperties()
463 {
464     {
465         QSGView view;
466
467         SingleRoleModel model;
468
469         QDeclarativeContext *ctxt = view.rootContext();
470         ctxt->setContextProperty("myModel", &model);
471
472         view.setSource(QUrl::fromLocalFile(TESTDATA("modelproperties.qml")));
473
474         QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
475         QVERIFY(listview != 0);
476
477         QSGItem *contentItem = listview->contentItem();
478         QVERIFY(contentItem != 0);
479
480         QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 1);
481         QVERIFY(delegate);
482         QCOMPARE(delegate->property("test1").toString(),QString("two"));
483         QCOMPARE(delegate->property("test2").toString(),QString("two"));
484         QCOMPARE(delegate->property("test3").toString(),QString("two"));
485         QCOMPARE(delegate->property("test4").toString(),QString("two"));
486         QVERIFY(!delegate->property("test9").isValid());
487         QCOMPARE(delegate->property("test5").toString(),QString(""));
488         QVERIFY(delegate->property("test6").value<QObject*>() != 0);
489         QCOMPARE(delegate->property("test7").toInt(),1);
490         QCOMPARE(delegate->property("test8").toInt(),1);
491     }
492
493     {
494         QSGView view;
495
496         QList<QObject*> dataList;
497         dataList.append(new DataObject("Item 1", "red"));
498         dataList.append(new DataObject("Item 2", "green"));
499         dataList.append(new DataObject("Item 3", "blue"));
500         dataList.append(new DataObject("Item 4", "yellow"));
501
502         QDeclarativeContext *ctxt = view.rootContext();
503         ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
504
505         view.setSource(QUrl::fromLocalFile(TESTDATA("modelproperties.qml")));
506
507         QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
508         QVERIFY(listview != 0);
509
510         QSGItem *contentItem = listview->contentItem();
511         QVERIFY(contentItem != 0);
512
513         QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 1);
514         QVERIFY(delegate);
515         QCOMPARE(delegate->property("test1").toString(),QString("Item 2"));
516         QCOMPARE(delegate->property("test2").toString(),QString("Item 2"));
517         QVERIFY(qobject_cast<DataObject*>(delegate->property("test3").value<QObject*>()) != 0);
518         QVERIFY(qobject_cast<DataObject*>(delegate->property("test4").value<QObject*>()) != 0);
519         QCOMPARE(delegate->property("test5").toString(),QString("Item 2"));
520         QCOMPARE(delegate->property("test9").toString(),QString("Item 2"));
521         QVERIFY(delegate->property("test6").value<QObject*>() != 0);
522         QCOMPARE(delegate->property("test7").toInt(),1);
523         QCOMPARE(delegate->property("test8").toInt(),1);
524     }
525
526     {
527         QSGView view;
528
529         QStandardItemModel model;
530         initStandardTreeModel(&model);
531
532         view.rootContext()->setContextProperty("myModel", &model);
533
534         QUrl source(QUrl::fromLocalFile(TESTDATA("modelproperties2.qml")));
535
536         //3 items, 3 warnings each
537         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: Can't find variable: modelData");
538         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: Can't find variable: modelData");
539         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: Can't find variable: modelData");
540         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: Can't find variable: modelData");
541         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: Can't find variable: modelData");
542         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: Can't find variable: modelData");
543         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
544         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
545         QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
546
547         view.setSource(source);
548
549         QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
550         QVERIFY(listview != 0);
551
552         QSGItem *contentItem = listview->contentItem();
553         QVERIFY(contentItem != 0);
554
555         QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 1);
556         QVERIFY(delegate);
557         QCOMPARE(delegate->property("test1").toString(),QString("Row 2 Item"));
558         QCOMPARE(delegate->property("test2").toString(),QString("Row 2 Item"));
559         QVERIFY(!delegate->property("test3").isValid());
560         QVERIFY(!delegate->property("test4").isValid());
561         QVERIFY(!delegate->property("test5").isValid());
562         QVERIFY(!delegate->property("test9").isValid());
563         QVERIFY(delegate->property("test6").value<QObject*>() != 0);
564         QCOMPARE(delegate->property("test7").toInt(),1);
565         QCOMPARE(delegate->property("test8").toInt(),1);
566     }
567
568     //### should also test QStringList and QVariantList
569 }
570
571 void tst_qsgvisualdatamodel::noDelegate()
572 {
573     QSGView view;
574
575     QStandardItemModel model;
576     initStandardTreeModel(&model);
577
578     view.rootContext()->setContextProperty("myModel", &model);
579
580     view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml")));
581
582     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
583     QVERIFY(listview != 0);
584
585     QSGVisualDataModel *vdm = listview->findChild<QSGVisualDataModel*>("visualModel");
586     QVERIFY(vdm != 0);
587     QCOMPARE(vdm->count(), 3);
588
589     vdm->setDelegate(0);
590     QCOMPARE(vdm->count(), 0);
591 }
592
593
594 void tst_qsgvisualdatamodel::qaimRowsMoved()
595 {
596     // Test parameters passed in QAIM::rowsMoved() signal are converted correctly
597     // when translated and emitted as the QListModelInterface::itemsMoved() signal
598     QFETCH(int, sourceFirst);
599     QFETCH(int, sourceLast);
600     QFETCH(int, destinationChild);
601     QFETCH(int, expectFrom);
602     QFETCH(int, expectTo);
603     QFETCH(int, expectCount);
604
605     QDeclarativeEngine engine;
606     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("visualdatamodel.qml")));
607
608     SingleRoleModel model;
609     model.list.clear();
610     for (int i=0; i<30; i++)
611         model.list << ("item " + i);
612     engine.rootContext()->setContextProperty("myModel", &model);
613
614     QSGVisualDataModel *obj = qobject_cast<QSGVisualDataModel*>(c.create());
615     QVERIFY(obj != 0);
616
617     QSignalSpy spy(obj, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)));
618     model.emitMove(sourceFirst, sourceLast, destinationChild);
619     // QAbstractItemModel also emits the changed signal when items are moved.
620     QCOMPARE(spy.count(), 2);
621
622     bool move = false;
623     for (int i = 0; i < 2; ++i) {
624         QCOMPARE(spy[1].count(), 2);
625         QDeclarativeChangeSet changeSet = spy[i][0].value<QDeclarativeChangeSet>();
626         if (!changeSet.changes().isEmpty())
627             continue;
628         move = true;
629         QCOMPARE(changeSet.removes().count(), 1);
630         QCOMPARE(changeSet.removes().at(0).index, expectFrom);
631         QCOMPARE(changeSet.removes().at(0).count, expectCount);
632         QCOMPARE(changeSet.inserts().count(), 1);
633         QCOMPARE(changeSet.inserts().at(0).index, expectTo);
634         QCOMPARE(changeSet.inserts().at(0).count, expectCount);
635         QCOMPARE(changeSet.removes().at(0).moveId, changeSet.inserts().at(0).moveId);
636         QCOMPARE(spy[i][1].toBool(), false);
637     }
638     QVERIFY(move);
639
640     delete obj;
641 }
642
643 void tst_qsgvisualdatamodel::qaimRowsMoved_data()
644 {
645     QTest::addColumn<int>("sourceFirst");
646     QTest::addColumn<int>("sourceLast");
647     QTest::addColumn<int>("destinationChild");
648     QTest::addColumn<int>("expectFrom");
649     QTest::addColumn<int>("expectTo");
650     QTest::addColumn<int>("expectCount");
651
652     QTest::newRow("move 1 forward")
653         << 1 << 1 << 6
654         << 1 << 5 << 1;
655
656     QTest::newRow("move 1 backwards")
657         << 4 << 4 << 1
658         << 4 << 1 << 1;
659
660     QTest::newRow("move multiple forwards")
661         << 0 << 2 << 13
662         << 0 << 10 << 3;
663
664     QTest::newRow("move multiple forwards, with same to")
665         << 0 << 1 << 3
666         << 0 << 1 << 2;
667
668     QTest::newRow("move multiple backwards")
669         << 10 << 14 << 1
670         << 10 << 1 << 5;
671 }
672
673 void tst_qsgvisualdatamodel::remove()
674 {
675     QSGView view;
676
677     SingleRoleModel model;
678     model.list = QStringList()
679             << "one"
680             << "two"
681             << "three"
682             << "four"
683             << "five"
684             << "six"
685             << "seven"
686             << "eight"
687             << "nine"
688             << "ten"
689             << "eleven"
690             << "twelve";
691
692     QDeclarativeContext *ctxt = view.rootContext();
693     ctxt->setContextProperty("myModel", &model);
694
695     view.setSource(QUrl::fromLocalFile(TESTDATA("groups.qml")));
696
697     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
698     QVERIFY(listview != 0);
699
700     QSGItem *contentItem = listview->contentItem();
701     QVERIFY(contentItem != 0);
702
703     QSGVisualDataModel *visualModel = qobject_cast<QSGVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
704     QVERIFY(visualModel);
705
706     {
707         QCOMPARE(listview->count(), 12);
708         QCOMPARE(visualModel->items()->count(), 12);
709         static const int mIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
710         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
711
712         for (int i = 0; i < lengthOf(mIndex); ++i) {
713             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
714             QVERIFY(delegate);
715             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
716             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
717             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
718         }
719     } {
720         evaluate<void>(visualModel, "items.remove(2)");
721         QCOMPARE(listview->count(), 11);
722         QCOMPARE(visualModel->items()->count(), 11);
723         static const int mIndex[] = { 0, 1, 3, 4, 5, 6, 7, 8, 9,10,11 };
724         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10 };
725
726         for (int i = 0; i < lengthOf(mIndex); ++i) {
727             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
728             QVERIFY(delegate);
729             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
730             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
731             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
732         }
733     } {
734         evaluate<void>(visualModel, "items.remove(1, 4)");
735         QCOMPARE(listview->count(), 7);
736         QCOMPARE(visualModel->items()->count(), 7);
737         static const int mIndex[] = { 0, 6, 7, 8, 9,10,11 };
738         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6 };
739
740         for (int i = 0; i < lengthOf(mIndex); ++i) {
741             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
742             QVERIFY(delegate);
743             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
744             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
745             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
746         }
747     } {
748         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range");
749         evaluate<void>(visualModel, "items.remove(-8, 4)");
750         QCOMPARE(listview->count(), 7);
751         QCOMPARE(visualModel->items()->count(), 7);
752     } {
753         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range");
754         evaluate<void>(visualModel, "items.remove(12, 2)");
755         QCOMPARE(listview->count(), 7);
756         QCOMPARE(visualModel->items()->count(), 7);
757     } {
758         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range");
759         evaluate<void>(visualModel, "items.remove(5, 3)");
760         QCOMPARE(listview->count(), 7);
761         QCOMPARE(visualModel->items()->count(), 7);
762     } {
763         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: invalid count");
764         evaluate<void>(visualModel, "items.remove(5, -2)");
765         QCOMPARE(listview->count(), 7);
766         QCOMPARE(visualModel->items()->count(), 7);
767     }
768 }
769
770 void tst_qsgvisualdatamodel::move()
771 {
772     QSGView view;
773
774     SingleRoleModel model;
775     model.list = QStringList()
776             << "one"
777             << "two"
778             << "three"
779             << "four"
780             << "five"
781             << "six"
782             << "seven"
783             << "eight"
784             << "nine"
785             << "ten"
786             << "eleven"
787             << "twelve";
788
789     QDeclarativeContext *ctxt = view.rootContext();
790     ctxt->setContextProperty("myModel", &model);
791
792     view.setSource(QUrl::fromLocalFile(TESTDATA("groups.qml")));
793
794     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
795     QVERIFY(listview != 0);
796
797     QSGItem *contentItem = listview->contentItem();
798     QVERIFY(contentItem != 0);
799
800     QSGVisualDataModel *visualModel = qobject_cast<QSGVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
801     QVERIFY(visualModel);
802
803     {
804         QCOMPARE(listview->count(), 12);
805         QCOMPARE(visualModel->items()->count(), 12);
806         static const int mIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
807         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
808
809         for (int i = 0; i < lengthOf(mIndex); ++i) {
810             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
811             QVERIFY(delegate);
812             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
813             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
814             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
815         }
816     } {
817         evaluate<void>(visualModel, "items.move(2, 4)");
818         QCOMPARE(listview->count(), 12);
819         QCOMPARE(visualModel->items()->count(), 12);
820         static const int mIndex[] = { 0, 1, 3, 4, 2, 5, 6, 7, 8, 9,10,11 };
821         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
822
823         for (int i = 0; i < lengthOf(mIndex); ++i) {
824             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
825             QVERIFY(delegate);
826             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
827             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
828             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
829         }
830     } {
831         evaluate<void>(visualModel, "items.move(4, 2)");
832         QCOMPARE(listview->count(), 12);
833         QCOMPARE(visualModel->items()->count(), 12);
834         static const int mIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
835         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
836
837         for (int i = 0; i < lengthOf(mIndex); ++i) {
838             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
839             QVERIFY(delegate);
840             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
841             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
842             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
843         }
844     } {
845         evaluate<void>(visualModel, "items.move(8, 0, 4)");
846         QCOMPARE(listview->count(), 12);
847         QCOMPARE(visualModel->items()->count(), 12);
848         static const int mIndex[] = { 8, 9,10,11, 0, 1, 2, 3, 4, 5, 6, 7 };
849         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
850
851         for (int i = 0; i < lengthOf(mIndex); ++i) {
852             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
853             QVERIFY(delegate);
854             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
855             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
856             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
857         }
858     } {
859         evaluate<void>(visualModel, "items.move(3, 4, 5)");
860         QCOMPARE(listview->count(), 12);
861         QCOMPARE(visualModel->items()->count(), 12);
862         static const int mIndex[] = { 8, 9,10,4, 11, 0, 1, 2, 3, 5, 6, 7 };
863         static const int iIndex[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
864
865         for (int i = 0; i < lengthOf(mIndex); ++i) {
866             QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
867             QVERIFY(delegate);
868             QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
869             QCOMPARE(delegate->property("test2").toInt(), mIndex[i]);
870             QCOMPARE(delegate->property("test3").toInt(), iIndex[i]);
871         }
872     } {
873         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: invalid count");
874         evaluate<void>(visualModel, "items.move(5, 2, -2)");
875         QCOMPARE(listview->count(), 12);
876         QCOMPARE(visualModel->items()->count(), 12);
877     } {
878         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range");
879         evaluate<void>(visualModel, "items.move(-6, 2, 1)");
880         QCOMPARE(listview->count(), 12);
881         QCOMPARE(visualModel->items()->count(), 12);
882     } {
883         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range");
884         evaluate<void>(visualModel, "items.move(15, 2, 1)");
885         QCOMPARE(listview->count(), 12);
886         QCOMPARE(visualModel->items()->count(), 12);
887     } {
888         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range");
889         evaluate<void>(visualModel, "items.move(11, 1, 3)");
890         QCOMPARE(listview->count(), 12);
891         QCOMPARE(visualModel->items()->count(), 12);
892     } {
893         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range");
894         evaluate<void>(visualModel, "items.move(2, -5, 1)");
895         QCOMPARE(listview->count(), 12);
896         QCOMPARE(visualModel->items()->count(), 12);
897     } {
898         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range");
899         evaluate<void>(visualModel, "items.move(2, 14, 1)");
900         QCOMPARE(listview->count(), 12);
901         QCOMPARE(visualModel->items()->count(), 12);
902     } {
903         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range");
904         evaluate<void>(visualModel, "items.move(2, 11, 4)");
905         QCOMPARE(listview->count(), 12);
906         QCOMPARE(visualModel->items()->count(), 12);
907     }
908 }
909
910
911 template <int N> void tst_qsgvisualdatamodel::groups_verify(
912         const SingleRoleModel &model,
913         QSGItem *contentItem,
914         const int (&mIndex)[N],
915         const int (&iIndex)[N],
916         const int (&vIndex)[N],
917         const int (&sIndex)[N],
918         const bool (&vMember)[N],
919         const bool (&sMember)[N])
920 {
921     failed = true;
922     for (int i = 0; i < N; ++i) {
923         QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", mIndex[i]);
924         QVERIFY(delegate);
925         QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i]));
926         QCOMPARE(delegate->property("test2").toInt() , mIndex[i]);
927         QCOMPARE(delegate->property("test3").toInt() , iIndex[i]);
928         QCOMPARE(delegate->property("test4").toBool(), true);
929         QCOMPARE(delegate->property("test5").toInt() , vIndex[i]);
930         QCOMPARE(delegate->property("test6").toBool(), vMember[i]);
931         QCOMPARE(delegate->property("test7").toInt() , sIndex[i]);
932         QCOMPARE(delegate->property("test8").toBool(), sMember[i]);
933         QCOMPARE(delegate->property("test9").toStringList().contains("items")   , QBool(true));
934         QCOMPARE(delegate->property("test9").toStringList().contains("visible") , QBool(vMember[i]));
935         QCOMPARE(delegate->property("test9").toStringList().contains("selected"), QBool(sMember[i]));
936     }
937     failed = false;
938 }
939
940 #define VERIFY_GROUPS \
941     groups_verify(model, contentItem, mIndex, iIndex, vIndex, sIndex, vMember, sMember); \
942     QVERIFY(!failed)
943
944
945 void tst_qsgvisualdatamodel::groups()
946 {
947     QSGView view;
948
949     SingleRoleModel model;
950     model.list = QStringList()
951             << "one"
952             << "two"
953             << "three"
954             << "four"
955             << "five"
956             << "six"
957             << "seven"
958             << "eight"
959             << "nine"
960             << "ten"
961             << "eleven"
962             << "twelve";
963
964     QDeclarativeContext *ctxt = view.rootContext();
965     ctxt->setContextProperty("myModel", &model);
966
967     view.setSource(QUrl::fromLocalFile(TESTDATA("groups.qml")));
968
969     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
970     QVERIFY(listview != 0);
971
972     QSGItem *contentItem = listview->contentItem();
973     QVERIFY(contentItem != 0);
974
975     QSGVisualDataModel *visualModel = qobject_cast<QSGVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
976     QVERIFY(visualModel);
977
978     QSGVisualDataGroup *visibleItems = visualModel->findChild<QSGVisualDataGroup *>("visibleItems");
979     QVERIFY(visibleItems);
980
981     QSGVisualDataGroup *selectedItems = visualModel->findChild<QSGVisualDataGroup *>("selectedItems");
982     QVERIFY(selectedItems);
983
984     const bool f = false;
985     const bool t = true;
986
987     {
988         QCOMPARE(listview->count(), 12);
989         QCOMPARE(visualModel->items()->count(), 12);
990         QCOMPARE(visibleItems->count(), 12);
991         QCOMPARE(selectedItems->count(), 0);
992         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
993         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
994         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
995         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
996         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
997         static const bool sMember[] = { f, f, f, f, f, f, f, f, f, f, f, f };
998         VERIFY_GROUPS;
999     } {
1000         evaluate<void>(visualModel, "items.addGroups(8, \"selected\")");
1001         QCOMPARE(listview->count(), 12);
1002         QCOMPARE(visualModel->items()->count(), 12);
1003         QCOMPARE(visibleItems->count(), 12);
1004         QCOMPARE(selectedItems->count(), 1);
1005         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1006         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1007         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1008         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1009         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 };
1010         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, f, f, f };
1011         VERIFY_GROUPS;
1012     } {
1013         evaluate<void>(visualModel, "items.addGroups(6, 4, [\"visible\", \"selected\"])");
1014         QCOMPARE(listview->count(), 12);
1015         QCOMPARE(visualModel->items()->count(), 12);
1016         QCOMPARE(visibleItems->count(), 12);
1017         QCOMPARE(selectedItems->count(), 4);
1018         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1019         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1020         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1021         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1022         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4 };
1023         static const bool sMember[] = { f, f, f, f, f, f, t, t, t, t, f, f };
1024         VERIFY_GROUPS;
1025     } {
1026         evaluate<void>(visualModel, "items.setGroups(2, [\"items\", \"selected\"])");
1027         QCOMPARE(listview->count(), 12);
1028         QCOMPARE(visualModel->items()->count(), 12);
1029         QCOMPARE(visibleItems->count(), 11);
1030         QCOMPARE(selectedItems->count(), 5);
1031         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1032         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1033         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9,10 };
1034         static const bool vMember[] = { t, t, f, t, t, t, t, t, t, t, t, t };
1035         static const int  sIndex [] = { 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 5, 5 };
1036         static const bool sMember[] = { f, f, t, f, f, f, t, t, t, t, f, f };
1037         VERIFY_GROUPS;
1038     } {
1039         evaluate<void>(selectedItems, "setGroups(0, 3, \"items\")");
1040         QCOMPARE(listview->count(), 12);
1041         QCOMPARE(visualModel->items()->count(), 12);
1042         QCOMPARE(visibleItems->count(), 9);
1043         QCOMPARE(selectedItems->count(), 2);
1044         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1045         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1046         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
1047         static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
1048         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1049         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1050         VERIFY_GROUPS;
1051     } {
1052         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: invalid count");
1053         evaluate<void>(visualModel, "items.addGroups(11, -4, \"items\")");
1054         QCOMPARE(listview->count(), 12);
1055         QCOMPARE(visualModel->items()->count(), 12);
1056         QCOMPARE(visibleItems->count(), 9);
1057         QCOMPARE(selectedItems->count(), 2);
1058     } {
1059         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range");
1060         evaluate<void>(visualModel, "items.addGroups(-1, 3, \"items\")");
1061         QCOMPARE(listview->count(), 12);
1062         QCOMPARE(visualModel->items()->count(), 12);
1063         QCOMPARE(visibleItems->count(), 9);
1064         QCOMPARE(selectedItems->count(), 2);
1065     } {
1066         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range");
1067         evaluate<void>(visualModel, "items.addGroups(14, 3, \"items\")");
1068         QCOMPARE(listview->count(), 12);
1069         QCOMPARE(visualModel->items()->count(), 12);
1070         QCOMPARE(visibleItems->count(), 9);
1071         QCOMPARE(selectedItems->count(), 2);
1072     } {
1073         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range");
1074         evaluate<void>(visualModel, "items.addGroups(11, 5, \"items\")");
1075         QCOMPARE(listview->count(), 12);
1076         QCOMPARE(visualModel->items()->count(), 12);
1077         QCOMPARE(visibleItems->count(), 9);
1078         QCOMPARE(selectedItems->count(), 2);
1079     } {
1080         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: invalid count");
1081         evaluate<void>(visualModel, "items.setGroups(11, -4, \"items\")");
1082         QCOMPARE(listview->count(), 12);
1083         QCOMPARE(visualModel->items()->count(), 12);
1084         QCOMPARE(visibleItems->count(), 9);
1085         QCOMPARE(selectedItems->count(), 2);
1086     } {
1087         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range");
1088         evaluate<void>(visualModel, "items.setGroups(-1, 3, \"items\")");
1089         QCOMPARE(listview->count(), 12);
1090         QCOMPARE(visualModel->items()->count(), 12);
1091         QCOMPARE(visibleItems->count(), 9);
1092         QCOMPARE(selectedItems->count(), 2);
1093     } {
1094         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range");
1095         evaluate<void>(visualModel, "items.setGroups(14, 3, \"items\")");
1096         QCOMPARE(listview->count(), 12);
1097         QCOMPARE(visualModel->items()->count(), 12);
1098         QCOMPARE(visibleItems->count(), 9);
1099         QCOMPARE(selectedItems->count(), 2);
1100     } {
1101         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range");
1102         evaluate<void>(visualModel, "items.setGroups(11, 5, \"items\")");
1103         QCOMPARE(listview->count(), 12);
1104         QCOMPARE(visualModel->items()->count(), 12);
1105         QCOMPARE(visibleItems->count(), 9);
1106         QCOMPARE(selectedItems->count(), 2);
1107     } {
1108         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: invalid count");
1109         evaluate<void>(visualModel, "items.removeGroups(11, -4, \"items\")");
1110         QCOMPARE(listview->count(), 12);
1111         QCOMPARE(visualModel->items()->count(), 12);
1112     } {
1113         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range");
1114         evaluate<void>(visualModel, "items.removeGroups(-1, 3, \"items\")");
1115         QCOMPARE(listview->count(), 12);
1116         QCOMPARE(visualModel->items()->count(), 12);
1117         QCOMPARE(visibleItems->count(), 9);
1118         QCOMPARE(selectedItems->count(), 2);
1119     } {
1120         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range");
1121         evaluate<void>(visualModel, "items.removeGroups(14, 3, \"items\")");
1122         QCOMPARE(listview->count(), 12);
1123         QCOMPARE(visualModel->items()->count(), 12);
1124         QCOMPARE(visibleItems->count(), 9);
1125         QCOMPARE(selectedItems->count(), 2);
1126     } {
1127         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range");
1128         evaluate<void>(visualModel, "items.removeGroups(11, 5, \"items\")");
1129         QCOMPARE(listview->count(), 12);
1130         QCOMPARE(visualModel->items()->count(), 12);
1131         QCOMPARE(visibleItems->count(), 9);
1132         QCOMPARE(selectedItems->count(), 2);
1133     } {
1134         evaluate<void>(visualModel, "filterOnGroup = \"visible\"");
1135         QCOMPARE(listview->count(), 9);
1136         QCOMPARE(visualModel->items()->count(), 12);
1137         QCOMPARE(visibleItems->count(), 9);
1138         QCOMPARE(selectedItems->count(), 2);
1139     } {
1140         evaluate<void>(visualModel, "filterOnGroup = \"selected\"");
1141         QCOMPARE(listview->count(), 2);
1142         QCOMPARE(visualModel->items()->count(), 12);
1143         QCOMPARE(visibleItems->count(), 9);
1144         QCOMPARE(selectedItems->count(), 2);
1145     } {
1146         evaluate<void>(visualModel, "filterOnGroup = \"items\"");
1147         QCOMPARE(listview->count(), 12);
1148         QCOMPARE(visualModel->items()->count(), 12);
1149         QCOMPARE(visibleItems->count(), 9);
1150         QCOMPARE(selectedItems->count(), 2);
1151     } {
1152         QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 5);
1153         QVERIFY(delegate);
1154
1155         evaluate<void>(delegate, "hide()");
1156         QCOMPARE(listview->count(), 12);
1157         QCOMPARE(visualModel->items()->count(), 12);
1158         QCOMPARE(visibleItems->count(), 8);
1159         QCOMPARE(selectedItems->count(), 2);
1160         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1161         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1162         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1163         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1164         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1165         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1166         VERIFY_GROUPS;
1167     } {
1168         QSGItem *delegate = findItem<QSGItem>(contentItem, "delegate", 5);
1169         QVERIFY(delegate);
1170
1171         evaluate<void>(delegate, "select()");
1172         QCOMPARE(listview->count(), 12);
1173         QCOMPARE(visualModel->items()->count(), 12);
1174         QCOMPARE(visibleItems->count(), 8);
1175         QCOMPARE(selectedItems->count(), 3);
1176         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1177         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1178         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1179         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1180         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3 };
1181         static const bool sMember[] = { f, f, f, f, f, t, f, f, t, t, f, f };
1182         VERIFY_GROUPS;
1183     } {
1184         evaluate<void>(visualModel, "items.move(2, 6, 3)");
1185         QCOMPARE(listview->count(), 12);
1186         QCOMPARE(visualModel->items()->count(), 12);
1187         QCOMPARE(visibleItems->count(), 8);
1188         QCOMPARE(selectedItems->count(), 3);
1189         static const int  mIndex [] = { 0, 1, 5, 6, 7, 8, 2, 3, 4, 9,10,11 };
1190         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1191         static const int  vIndex [] = { 0, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 7 };
1192         static const bool vMember[] = { t, t, f, f, f, t, f, t, t, t, t, t };
1193         static const int  sIndex [] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3 };
1194         static const bool sMember[] = { f, f, t, f, f, t, f, f, f, t, f, f };
1195         VERIFY_GROUPS;
1196     }
1197 }
1198
1199 template <int N> void tst_qsgvisualdatamodel::get_verify(
1200         const SingleRoleModel &model,
1201         QSGVisualDataModel *visualModel,
1202         QSGVisualDataGroup *visibleItems,
1203         QSGVisualDataGroup *selectedItems,
1204         const int (&mIndex)[N],
1205         const int (&iIndex)[N],
1206         const int (&vIndex)[N],
1207         const int (&sIndex)[N],
1208         const bool (&vMember)[N],
1209         const bool (&sMember)[N])
1210 {
1211     failed = true;
1212     for (int i = 0; i < N; ++i) {
1213         QCOMPARE(evaluate<QString>(visualModel, QString("items.get(%1).model.name").arg(i)), model.list.at(mIndex[i]));
1214         QCOMPARE(evaluate<QString>(visualModel, QString("items.get(%1).model.modelData").arg(i)), model.list.at(mIndex[i]));
1215         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).model.index").arg(i)), mIndex[i]);
1216         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).itemsIndex").arg(i)), iIndex[i]);
1217         QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inItems").arg(i)), true);
1218         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).visibleIndex").arg(i)), vIndex[i]);
1219         QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inVisible").arg(i)), vMember[i]);
1220         QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).selectedIndex").arg(i)), sIndex[i]);
1221         QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inSelected").arg(i)), sMember[i]);
1222         QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"items\")").arg(i)), true);
1223         QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"visible\")").arg(i)), vMember[i]);
1224         QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"selected\")").arg(i)), sMember[i]);
1225
1226         if (vMember[i]) {
1227             QCOMPARE(evaluate<QString>(visibleItems, QString("get(%1).model.name").arg(vIndex[i])), model.list.at(mIndex[i]));
1228             QCOMPARE(evaluate<QString>(visibleItems, QString("get(%1).model.modelData").arg(vIndex[i])), model.list.at(mIndex[i]));
1229             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).model.index").arg(vIndex[i])), mIndex[i]);
1230             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).itemsIndex").arg(vIndex[i])), iIndex[i]);
1231             QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inItems").arg(vIndex[i])), true);
1232             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).visibleIndex").arg(vIndex[i])), vIndex[i]);
1233             QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inVisible").arg(vIndex[i])), vMember[i]);
1234             QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).selectedIndex").arg(vIndex[i])), sIndex[i]);
1235             QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inSelected").arg(vIndex[i])), sMember[i]);
1236
1237             QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"items\")").arg(vIndex[i])), true);
1238             QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"visible\")").arg(vIndex[i])), vMember[i]);
1239             QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"selected\")").arg(vIndex[i])), sMember[i]);
1240         }
1241         if (sMember[i]) {
1242             QCOMPARE(evaluate<QString>(selectedItems, QString("get(%1).model.name").arg(sIndex[i])), model.list.at(mIndex[i]));
1243             QCOMPARE(evaluate<QString>(selectedItems, QString("get(%1).model.modelData").arg(sIndex[i])), model.list.at(mIndex[i]));
1244             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).model.index").arg(sIndex[i])), mIndex[i]);
1245             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).itemsIndex").arg(sIndex[i])), iIndex[i]);
1246             QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inItems").arg(sIndex[i])), true);
1247             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).visibleIndex").arg(sIndex[i])), vIndex[i]);
1248             QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inVisible").arg(sIndex[i])), vMember[i]);
1249             QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).selectedIndex").arg(sIndex[i])), sIndex[i]);
1250             QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inSelected").arg(sIndex[i])), sMember[i]);
1251             QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"items\")").arg(sIndex[i])), true);
1252             QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"visible\")").arg(sIndex[i])), vMember[i]);
1253             QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"selected\")").arg(sIndex[i])), sMember[i]);
1254         }
1255     }
1256     failed = false;
1257 }
1258
1259 #define VERIFY_GET \
1260     get_verify(model, visualModel, visibleItems, selectedItems, mIndex, iIndex, vIndex, sIndex, vMember, sMember); \
1261     QVERIFY(!failed)
1262
1263 void tst_qsgvisualdatamodel::get()
1264 {
1265     QSGView view;
1266
1267     SingleRoleModel model;
1268     model.list = QStringList()
1269             << "one"
1270             << "two"
1271             << "three"
1272             << "four"
1273             << "five"
1274             << "six"
1275             << "seven"
1276             << "eight"
1277             << "nine"
1278             << "ten"
1279             << "eleven"
1280             << "twelve";
1281
1282     QDeclarativeContext *ctxt = view.rootContext();
1283     ctxt->setContextProperty("myModel", &model);
1284
1285     view.setSource(QUrl::fromLocalFile(TESTDATA("groups.qml")));
1286
1287     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
1288     QVERIFY(listview != 0);
1289
1290     QSGItem *contentItem = listview->contentItem();
1291     QVERIFY(contentItem != 0);
1292
1293     QSGVisualDataModel *visualModel = qobject_cast<QSGVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
1294     QVERIFY(visualModel);
1295
1296     QSGVisualDataGroup *visibleItems = visualModel->findChild<QSGVisualDataGroup *>("visibleItems");
1297     QVERIFY(visibleItems);
1298
1299     QSGVisualDataGroup *selectedItems = visualModel->findChild<QSGVisualDataGroup *>("selectedItems");
1300     QVERIFY(selectedItems);
1301
1302     QV8Engine *v8Engine = QDeclarativeEnginePrivate::getV8Engine(ctxt->engine());
1303     QVERIFY(v8Engine);
1304
1305     const bool f = false;
1306     const bool t = true;
1307
1308     {
1309         QCOMPARE(listview->count(), 12);
1310         QCOMPARE(visualModel->items()->count(), 12);
1311         QCOMPARE(visibleItems->count(), 12);
1312         QCOMPARE(selectedItems->count(), 0);
1313         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1314         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1315         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1316         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1317         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1318         static const bool sMember[] = { f, f, f, f, f, f, f, f, f, f, f, f };
1319         VERIFY_GET;
1320     } {
1321         evaluate<void>(visualModel, "items.addGroups(8, \"selected\")");
1322         QCOMPARE(listview->count(), 12);
1323         QCOMPARE(visualModel->items()->count(), 12);
1324         QCOMPARE(visibleItems->count(), 12);
1325         QCOMPARE(selectedItems->count(), 1);
1326         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1327         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1328         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1329         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1330         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 };
1331         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, f, f, f };
1332         VERIFY_GET;
1333     } {
1334         evaluate<void>(visualModel, "items.addGroups(6, 4, [\"visible\", \"selected\"])");
1335         QCOMPARE(listview->count(), 12);
1336         QCOMPARE(visualModel->items()->count(), 12);
1337         QCOMPARE(visibleItems->count(), 12);
1338         QCOMPARE(selectedItems->count(), 4);
1339         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1340         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1341         static const int  vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1342         static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
1343         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4 };
1344         static const bool sMember[] = { f, f, f, f, f, f, t, t, t, t, f, f };
1345         VERIFY_GET;
1346     } {
1347         evaluate<void>(visualModel, "items.setGroups(2, [\"items\", \"selected\"])");
1348         QCOMPARE(listview->count(), 12);
1349         QCOMPARE(visualModel->items()->count(), 12);
1350         QCOMPARE(visibleItems->count(), 11);
1351         QCOMPARE(selectedItems->count(), 5);
1352         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1353         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1354         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9,10 };
1355         static const bool vMember[] = { t, t, f, t, t, t, t, t, t, t, t, t };
1356         static const int  sIndex [] = { 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 5, 5 };
1357         static const bool sMember[] = { f, f, t, f, f, f, t, t, t, t, f, f };
1358         VERIFY_GET;
1359     } {
1360         evaluate<void>(selectedItems, "setGroups(0, 3, \"items\")");
1361         QCOMPARE(listview->count(), 12);
1362         QCOMPARE(visualModel->items()->count(), 12);
1363         QCOMPARE(visibleItems->count(), 9);
1364         QCOMPARE(selectedItems->count(), 2);
1365         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1366         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1367         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
1368         static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
1369         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1370         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1371         VERIFY_GET;
1372     } {
1373         evaluate<void>(visualModel, "items.get(5).inVisible = false");
1374         QCOMPARE(listview->count(), 12);
1375         QCOMPARE(visualModel->items()->count(), 12);
1376         QCOMPARE(visibleItems->count(), 8);
1377         QCOMPARE(selectedItems->count(), 2);
1378         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1379         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1380         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1381         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1382         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1383         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1384         VERIFY_GET;
1385     } {
1386         evaluate<void>(visualModel, "items.get(5).inSelected = true");
1387         QCOMPARE(listview->count(), 12);
1388         QCOMPARE(visualModel->items()->count(), 12);
1389         QCOMPARE(visibleItems->count(), 8);
1390         QCOMPARE(selectedItems->count(), 3);
1391         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1392         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1393         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
1394         static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
1395         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3 };
1396         static const bool sMember[] = { f, f, f, f, f, t, f, f, t, t, f, f };
1397         VERIFY_GET;
1398     } {
1399         evaluate<void>(visualModel, "items.get(5).groups = [\"visible\", \"items\"]");
1400         QCOMPARE(listview->count(), 12);
1401         QCOMPARE(visualModel->items()->count(), 12);
1402         QCOMPARE(visibleItems->count(), 9);
1403         QCOMPARE(selectedItems->count(), 2);
1404         static const int  mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1405         static const int  iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
1406         static const int  vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
1407         static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
1408         static const int  sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
1409         static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
1410         VERIFY_GET;
1411     }
1412 }
1413
1414 void tst_qsgvisualdatamodel::create()
1415 {
1416     QSGView view;
1417
1418     SingleRoleModel model;
1419     model.list = QStringList()
1420             << "one"
1421             << "two"
1422             << "three"
1423             << "four"
1424             << "five"
1425             << "six"
1426             << "seven"
1427             << "eight"
1428             << "nine"
1429             << "ten"
1430             << "eleven"
1431             << "twelve"
1432             << "thirteen"
1433             << "fourteen"
1434             << "fifteen"
1435             << "sixteen"
1436             << "seventeen"
1437             << "eighteen"
1438             << "nineteen"
1439             << "twenty";
1440
1441     QDeclarativeContext *ctxt = view.rootContext();
1442     ctxt->setContextProperty("myModel", &model);
1443
1444     view.setSource(QUrl::fromLocalFile(TESTDATA("create.qml")));
1445
1446     QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
1447     QVERIFY(listview != 0);
1448
1449     QSGItem *contentItem = listview->contentItem();
1450     QVERIFY(contentItem != 0);
1451
1452     QSGVisualDataModel *visualModel = qobject_cast<QSGVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
1453     QVERIFY(visualModel);
1454
1455     QCOMPARE(listview->count(), 20);
1456
1457     QSGItem *delegate;
1458
1459     // Request an item instantiated by the view.
1460     QVERIFY(findItem<QSGItem>(contentItem, "delegate", 1));
1461     QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(1)")));
1462     QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 1));
1463     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1464     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1465
1466     evaluate<void>(delegate, "VisualDataModel.inPersistedItems = false");
1467     QCOMPARE(listview->count(), 20);
1468     QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
1469     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1470     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1471
1472     // Request an item not instantiated by the view.
1473     QVERIFY(!findItem<QSGItem>(contentItem, "delegate", 15));
1474     QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(15)")));
1475     QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 15));
1476     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1477     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1478
1479     evaluate<void>(visualModel, "persistedItems.remove(0)");
1480     QCOMPARE(evaluate<bool>(delegate, "destroyed"), true);
1481     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1482
1483     // Request an item not instantiated by the view, then scroll the view so it will request it.
1484     QVERIFY(!findItem<QSGItem>(contentItem, "delegate", 16));
1485     QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(16)")));
1486     QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 16));
1487     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1488     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1489
1490     evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)");
1491     QCOMPARE(listview->count(), 20);
1492     evaluate<void>(delegate, "VisualDataModel.groups = [\"items\"]");
1493     QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
1494     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1495     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1496
1497     // Request and release an item instantiated by the view, then scroll the view so it releases it.
1498     QVERIFY(findItem<QSGItem>(contentItem, "delegate", 17));
1499     QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(17)")));
1500     QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 17));
1501     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1502     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1503
1504     evaluate<void>(visualModel, "items.removeGroups(17, \"persistedItems\")");
1505     QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
1506     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
1507     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
1508     evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)");
1509     QCOMPARE(listview->count(), 20);
1510     QCOMPARE(evaluate<bool>(delegate, "destroyed"), true);
1511
1512     // Adding an item to the persistedItems group won't instantiate it, but if later requested by
1513     // the view it will be persisted.
1514     evaluate<void>(visualModel, "items.addGroups(18, \"persistedItems\")");
1515     QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
1516     QVERIFY(!findItem<QSGItem>(contentItem, "delegate", 18));
1517     evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)");
1518     QCOMPARE(listview->count(), 20);
1519     QVERIFY(delegate = findItem<QSGItem>(contentItem, "delegate", 18));
1520     QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
1521     QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
1522     evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)");
1523     QCOMPARE(listview->count(), 20);
1524     QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
1525 }
1526
1527 template<typename T>
1528 T *tst_qsgvisualdatamodel::findItem(QSGItem *parent, const QString &objectName, int index)
1529 {
1530     const QMetaObject &mo = T::staticMetaObject;
1531     //qDebug() << parent->childItems().count() << "children";
1532     for (int i = 0; i < parent->childItems().count(); ++i) {
1533         QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
1534         if (!item)
1535             continue;
1536         //qDebug() << "try" << item;
1537         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
1538             if (index != -1) {
1539                 QDeclarativeExpression e(qmlContext(item), item, "index");
1540                 if (e.evaluate().toInt() == index)
1541                     return static_cast<T*>(item);
1542             } else {
1543                 return static_cast<T*>(item);
1544             }
1545         }
1546         item = findItem<T>(item, objectName, index);
1547         if (item)
1548         return static_cast<T*>(item);
1549     }
1550
1551     return 0;
1552 }
1553
1554 QTEST_MAIN(tst_qsgvisualdatamodel)
1555
1556 #include "tst_qsgvisualdatamodel.moc"