Fix unstable GridView test
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qsggridview / tst_qsggridview.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
42 #include <QtTest/QtTest>
43 #include <QtGui/qstringlistmodel.h>
44 #include <QtDeclarative/qsgview.h>
45 #include <QtDeclarative/qdeclarativeengine.h>
46 #include <QtDeclarative/qdeclarativecomponent.h>
47 #include <QtDeclarative/qdeclarativecontext.h>
48 #include <QtDeclarative/qdeclarativeexpression.h>
49 #include <QtDeclarative/private/qsgitem_p.h>
50 #include <QtDeclarative/private/qlistmodelinterface_p.h>
51 #include <QtDeclarative/private/qsggridview_p.h>
52 #include <QtDeclarative/private/qsgtext_p.h>
53 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
54 #include "../../../shared/util.h"
55 #include <QtOpenGL/QGLShaderProgram>
56
57 #ifdef Q_OS_SYMBIAN
58 // In Symbian OS test data is located in applications private dir
59 #define SRCDIR "."
60 #endif
61
62 Q_DECLARE_METATYPE(Qt::LayoutDirection)
63 Q_DECLARE_METATYPE(QSGGridView::Flow)
64
65 class tst_QSGGridView : public QObject
66 {
67     Q_OBJECT
68 public:
69     tst_QSGGridView();
70
71 private slots:
72     void initTestCase();
73     void cleanupTestCase();
74     void items();
75     void changed();
76     void inserted();
77     void removed();
78     void clear();
79     void moved();
80     void changeFlow();
81     void currentIndex();
82     void noCurrentIndex();
83     void defaultValues();
84     void properties();
85     void propertyChanges();
86     void componentChanges();
87     void modelChanges();
88     void positionViewAtIndex();
89     void positionViewAtIndex_rightToLeft();
90     void mirroring();
91     void snapping();
92     void resetModel();
93     void enforceRange();
94     void enforceRange_rightToLeft();
95     void QTBUG_8456();
96     void manualHighlight();
97     void footer();
98     void footer_data();
99     void header();
100     void header_data();
101     void indexAt();
102     void onAdd();
103     void onAdd_data();
104     void onRemove();
105     void onRemove_data();
106     void testQtQuick11Attributes();
107     void testQtQuick11Attributes_data();
108
109 private:
110     QSGView *createView();
111     template<typename T>
112     T *findItem(QSGItem *parent, const QString &id, int index=-1);
113     template<typename T>
114     QList<T*> findItems(QSGItem *parent, const QString &objectName);
115     void dumpTree(QSGItem *parent, int depth = 0);
116 };
117 void tst_QSGGridView::initTestCase()
118 {
119     QSGView canvas;
120     if (!QGLShaderProgram::hasOpenGLShaderPrograms(canvas.context()))
121         QSKIP("QSGGridView needs OpenGL 2.0", SkipAll);
122 }
123
124 void tst_QSGGridView::cleanupTestCase()
125 {
126
127 }
128 class TestModel : public QAbstractListModel
129 {
130 public:
131     enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
132
133     TestModel(QObject *parent=0) : QAbstractListModel(parent) {
134         QHash<int, QByteArray> roles;
135         roles[Name] = "name";
136         roles[Number] = "number";
137         setRoleNames(roles);
138     }
139
140     int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
141     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
142         QVariant rv;
143         if (role == Name)
144             rv = list.at(index.row()).first;
145         else if (role == Number)
146             rv = list.at(index.row()).second;
147
148         return rv;
149     }
150
151     int count() const { return rowCount(); }
152     QString name(int index) const { return list.at(index).first; }
153     QString number(int index) const { return list.at(index).second; }
154
155     void addItem(const QString &name, const QString &number) {
156         emit beginInsertRows(QModelIndex(), list.count(), list.count());
157         list.append(QPair<QString,QString>(name, number));
158         emit endInsertRows();
159     }
160
161     void addItems(const QList<QPair<QString, QString> > &items) {
162         emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
163         for (int i=0; i<items.count(); i++)
164             list.append(QPair<QString,QString>(items[i].first, items[i].second));
165         emit endInsertRows();
166     }
167
168     void insertItem(int index, const QString &name, const QString &number) {
169         emit beginInsertRows(QModelIndex(), index, index);
170         list.insert(index, QPair<QString,QString>(name, number));
171         emit endInsertRows();
172     }
173
174     void removeItem(int index) {
175         emit beginRemoveRows(QModelIndex(), index, index);
176         list.removeAt(index);
177         emit endRemoveRows();
178     }
179
180     void removeItems(int index, int count) {
181         emit beginRemoveRows(QModelIndex(), index, index+count-1);
182         while (count--)
183             list.removeAt(index);
184         emit endRemoveRows();
185     }
186
187     void moveItem(int from, int to) {
188         emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
189         list.move(from, to);
190         emit endMoveRows();
191     }
192
193     void modifyItem(int idx, const QString &name, const QString &number) {
194         list[idx] = QPair<QString,QString>(name, number);
195         emit dataChanged(index(idx,0), index(idx,0));
196     }
197
198     void clear() {
199         int count = list.count();
200         emit beginRemoveRows(QModelIndex(), 0, count-1);
201         list.clear();
202         emit endRemoveRows();
203     }
204
205
206 private:
207     QList<QPair<QString,QString> > list;
208 };
209
210 tst_QSGGridView::tst_QSGGridView()
211 {
212 }
213
214 void tst_QSGGridView::items()
215 {
216     QSGView *canvas = createView();
217
218     TestModel model;
219     model.addItem("Fred", "12345");
220     model.addItem("John", "2345");
221     model.addItem("Bob", "54321");
222     model.addItem("Billy", "22345");
223     model.addItem("Sam", "2945");
224     model.addItem("Ben", "04321");
225     model.addItem("Jim", "0780");
226
227     QDeclarativeContext *ctxt = canvas->rootContext();
228     ctxt->setContextProperty("testModel", &model);
229     ctxt->setContextProperty("testRightToLeft", QVariant(false));
230     ctxt->setContextProperty("testTopToBottom", QVariant(false));
231
232     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
233     qApp->processEvents();
234
235     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
236     QTRY_VERIFY(gridview != 0);
237
238     QSGItem *contentItem = gridview->contentItem();
239     QTRY_VERIFY(contentItem != 0);
240
241     QTRY_COMPARE(gridview->count(), model.count());
242     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
243     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
244
245     for (int i = 0; i < model.count(); ++i) {
246         QSGText *name = findItem<QSGText>(contentItem, "textName", i);
247         QTRY_VERIFY(name != 0);
248         QTRY_COMPARE(name->text(), model.name(i));
249         QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
250         QTRY_VERIFY(number != 0);
251         QTRY_COMPARE(number->text(), model.number(i));
252     }
253
254     // set an empty model and confirm that items are destroyed
255     TestModel model2;
256     ctxt->setContextProperty("testModel", &model2);
257
258     int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
259     QTRY_VERIFY(itemCount == 0);
260
261     delete canvas;
262 }
263
264 void tst_QSGGridView::changed()
265 {
266     QSGView *canvas = createView();
267
268     TestModel model;
269     model.addItem("Fred", "12345");
270     model.addItem("John", "2345");
271     model.addItem("Bob", "54321");
272     model.addItem("Billy", "22345");
273     model.addItem("Sam", "2945");
274     model.addItem("Ben", "04321");
275     model.addItem("Jim", "0780");
276
277     QDeclarativeContext *ctxt = canvas->rootContext();
278     ctxt->setContextProperty("testModel", &model);
279     ctxt->setContextProperty("testRightToLeft", QVariant(false));
280     ctxt->setContextProperty("testTopToBottom", QVariant(false));
281
282     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
283     qApp->processEvents();
284
285     QSGFlickable *gridview = findItem<QSGFlickable>(canvas->rootObject(), "grid");
286     QTRY_VERIFY(gridview != 0);
287
288     QSGItem *contentItem = gridview->contentItem();
289     QTRY_VERIFY(contentItem != 0);
290
291     model.modifyItem(1, "Will", "9876");
292     QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
293     QTRY_VERIFY(name != 0);
294     QTRY_COMPARE(name->text(), model.name(1));
295     QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
296     QTRY_VERIFY(number != 0);
297     QTRY_COMPARE(number->text(), model.number(1));
298
299     delete canvas;
300 }
301
302 void tst_QSGGridView::inserted()
303 {
304     QSGView *canvas = createView();
305     canvas->show();
306
307     TestModel model;
308     model.addItem("Fred", "12345");
309     model.addItem("John", "2345");
310     model.addItem("Bob", "54321");
311
312     QDeclarativeContext *ctxt = canvas->rootContext();
313     ctxt->setContextProperty("testModel", &model);
314     ctxt->setContextProperty("testRightToLeft", QVariant(false));
315     ctxt->setContextProperty("testTopToBottom", QVariant(false));
316
317     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
318     qApp->processEvents();
319
320     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
321     QTRY_VERIFY(gridview != 0);
322
323     QSGItem *contentItem = gridview->contentItem();
324     QTRY_VERIFY(contentItem != 0);
325
326     model.insertItem(1, "Will", "9876");
327     QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
328
329     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
330
331     QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
332     QTRY_VERIFY(name != 0);
333     QTRY_COMPARE(name->text(), model.name(1));
334     QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
335     QTRY_VERIFY(number != 0);
336     QTRY_COMPARE(number->text(), model.number(1));
337
338     // Checks that onAdd is called
339     int added = canvas->rootObject()->property("added").toInt();
340     QTRY_COMPARE(added, 1);
341
342     // Confirm items positioned correctly
343     for (int i = 0; i < model.count(); ++i) {
344         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
345         QTRY_COMPARE(item->x(), (i%3)*80.0);
346         QTRY_COMPARE(item->y(), (i/3)*60.0);
347     }
348
349     model.insertItem(0, "Foo", "1111"); // zero index, and current item
350
351     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
352
353     name = findItem<QSGText>(contentItem, "textName", 0);
354     QTRY_VERIFY(name != 0);
355     QTRY_COMPARE(name->text(), model.name(0));
356     number = findItem<QSGText>(contentItem, "textNumber", 0);
357     QTRY_VERIFY(number != 0);
358     QTRY_COMPARE(number->text(), model.number(0));
359
360     QTRY_COMPARE(gridview->currentIndex(), 1);
361
362     // Confirm items positioned correctly
363     for (int i = 0; i < model.count(); ++i) {
364         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
365         QTRY_VERIFY(item->x() == (i%3)*80);
366         QTRY_VERIFY(item->y() == (i/3)*60);
367     }
368
369     for (int i = model.count(); i < 30; ++i)
370         model.insertItem(i, "Hello", QString::number(i));
371
372     gridview->setContentY(120);
373
374     // Insert item outside visible area
375     model.insertItem(1, "Hello", "1324");
376
377     QTRY_VERIFY(gridview->contentY() == 120);
378
379     delete canvas;
380 }
381
382 void tst_QSGGridView::removed()
383 {
384     QSGView *canvas = createView();
385     canvas->show();
386
387     TestModel model;
388     for (int i = 0; i < 40; i++)
389         model.addItem("Item" + QString::number(i), "");
390
391     QDeclarativeContext *ctxt = canvas->rootContext();
392     ctxt->setContextProperty("testModel", &model);
393     ctxt->setContextProperty("testRightToLeft", QVariant(false));
394     ctxt->setContextProperty("testTopToBottom", QVariant(false));
395
396     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
397     qApp->processEvents();
398
399     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
400     QTRY_VERIFY(gridview != 0);
401
402     QSGItem *contentItem = gridview->contentItem();
403     QTRY_VERIFY(contentItem != 0);
404
405     model.removeItem(1);
406     QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
407
408     QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
409     QTRY_VERIFY(name != 0);
410     QTRY_COMPARE(name->text(), model.name(1));
411     QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
412     QTRY_VERIFY(number != 0);
413     QTRY_COMPARE(number->text(), model.number(1));
414
415     // Checks that onRemove is called
416     QString removed = canvas->rootObject()->property("removed").toString();
417     QTRY_COMPARE(removed, QString("Item1"));
418
419     // Confirm items positioned correctly
420     int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
421     for (int i = 0; i < model.count() && i < itemCount; ++i) {
422         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
423         if (!item) qWarning() << "Item" << i << "not found";
424         QTRY_VERIFY(item);
425         QTRY_VERIFY(item->x() == (i%3)*80);
426         QTRY_VERIFY(item->y() == (i/3)*60);
427     }
428
429     // Remove first item (which is the current item);
430     model.removeItem(0);
431
432     name = findItem<QSGText>(contentItem, "textName", 0);
433     QTRY_VERIFY(name != 0);
434     QTRY_COMPARE(name->text(), model.name(0));
435     number = findItem<QSGText>(contentItem, "textNumber", 0);
436     QTRY_VERIFY(number != 0);
437     QTRY_COMPARE(number->text(), model.number(0));
438
439     // Confirm items positioned correctly
440     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
441     for (int i = 0; i < model.count() && i < itemCount; ++i) {
442         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
443         if (!item) qWarning() << "Item" << i << "not found";
444         QTRY_VERIFY(item);
445         QTRY_VERIFY(item->x() == (i%3)*80);
446         QTRY_VERIFY(item->y() == (i/3)*60);
447     }
448
449     // Remove items not visible
450     model.removeItem(25);
451
452     // Confirm items positioned correctly
453     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
454     for (int i = 0; i < model.count() && i < itemCount; ++i) {
455         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
456         if (!item) qWarning() << "Item" << i << "not found";
457         QTRY_VERIFY(item);
458         QTRY_VERIFY(item->x() == (i%3)*80);
459         QTRY_VERIFY(item->y() == (i/3)*60);
460     }
461
462     // Remove items before visible
463     gridview->setContentY(120);
464     gridview->setCurrentIndex(10);
465
466     // Setting currentIndex above shouldn't cause view to scroll
467     QTRY_COMPARE(gridview->contentY(), 120.0);
468
469     model.removeItem(1);
470
471     // Confirm items positioned correctly
472     for (int i = 6; i < 18; ++i) {
473         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
474         if (!item) qWarning() << "Item" << i << "not found";
475         QTRY_VERIFY(item);
476         QTRY_VERIFY(item->x() == (i%3)*80);
477         QTRY_VERIFY(item->y() == (i/3)*60);
478     }
479
480     // Remove currentIndex
481     QSGItem *oldCurrent = gridview->currentItem();
482     model.removeItem(9);
483
484     QTRY_COMPARE(gridview->currentIndex(), 9);
485     QTRY_VERIFY(gridview->currentItem() != oldCurrent);
486
487     gridview->setContentY(0);
488     // let transitions settle.
489     QTest::qWait(100);
490
491     // Confirm items positioned correctly
492     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
493     for (int i = 0; i < model.count() && i < itemCount; ++i) {
494         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
495         if (!item) qWarning() << "Item" << i << "not found";
496         QTRY_VERIFY(item);
497         QTRY_VERIFY(item->x() == (i%3)*80);
498         QTRY_VERIFY(item->y() == (i/3)*60);
499     }
500
501     // remove item outside current view.
502     gridview->setCurrentIndex(32);
503     gridview->setContentY(240);
504
505     model.removeItem(30);
506     QTRY_VERIFY(gridview->currentIndex() == 31);
507
508     // remove current item beyond visible items.
509     gridview->setCurrentIndex(20);
510     gridview->setContentY(0);
511     model.removeItem(20);
512
513     QTRY_COMPARE(gridview->currentIndex(), 20);
514     QTRY_VERIFY(gridview->currentItem() != 0);
515
516     // remove item before current, but visible
517     gridview->setCurrentIndex(8);
518     gridview->setContentY(240);
519     oldCurrent = gridview->currentItem();
520     model.removeItem(6);
521
522     QTRY_COMPARE(gridview->currentIndex(), 7);
523     QTRY_VERIFY(gridview->currentItem() == oldCurrent);
524
525     delete canvas;
526 }
527
528 void tst_QSGGridView::clear()
529 {
530     QSGView *canvas = createView();
531
532     TestModel model;
533     for (int i = 0; i < 30; i++)
534         model.addItem("Item" + QString::number(i), "");
535
536     QDeclarativeContext *ctxt = canvas->rootContext();
537     ctxt->setContextProperty("testModel", &model);
538     ctxt->setContextProperty("testRightToLeft", QVariant(false));
539     ctxt->setContextProperty("testTopToBottom", QVariant(false));
540
541     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
542     qApp->processEvents();
543
544     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
545     QVERIFY(gridview != 0);
546
547     QSGItem *contentItem = gridview->contentItem();
548     QVERIFY(contentItem != 0);
549
550     model.clear();
551
552     QVERIFY(gridview->count() == 0);
553     QVERIFY(gridview->currentItem() == 0);
554     QVERIFY(gridview->contentY() == 0);
555     QVERIFY(gridview->currentIndex() == -1);
556
557     // confirm sanity when adding an item to cleared list
558     model.addItem("New", "1");
559     QVERIFY(gridview->count() == 1);
560     QVERIFY(gridview->currentItem() != 0);
561     QVERIFY(gridview->currentIndex() == 0);
562
563     delete canvas;
564 }
565
566 void tst_QSGGridView::moved()
567 {
568     QSGView *canvas = createView();
569
570     TestModel model;
571     for (int i = 0; i < 30; i++)
572         model.addItem("Item" + QString::number(i), "");
573
574     QDeclarativeContext *ctxt = canvas->rootContext();
575     ctxt->setContextProperty("testModel", &model);
576     ctxt->setContextProperty("testRightToLeft", QVariant(false));
577     ctxt->setContextProperty("testTopToBottom", QVariant(false));
578
579     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
580     qApp->processEvents();
581
582     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
583     QTRY_VERIFY(gridview != 0);
584
585     QSGItem *contentItem = gridview->contentItem();
586     QTRY_VERIFY(contentItem != 0);
587
588     model.moveItem(1, 8);
589
590     QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
591     QTRY_VERIFY(name != 0);
592     QTRY_COMPARE(name->text(), model.name(1));
593     QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
594     QTRY_VERIFY(number != 0);
595     QTRY_COMPARE(number->text(), model.number(1));
596
597     name = findItem<QSGText>(contentItem, "textName", 8);
598     QTRY_VERIFY(name != 0);
599     QTRY_COMPARE(name->text(), model.name(8));
600     number = findItem<QSGText>(contentItem, "textNumber", 8);
601     QTRY_VERIFY(number != 0);
602     QTRY_COMPARE(number->text(), model.number(8));
603
604     // Confirm items positioned correctly
605     int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
606     for (int i = 0; i < model.count() && i < itemCount; ++i) {
607         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
608         if (!item) qWarning() << "Item" << i << "not found";
609         QTRY_VERIFY(item);
610         QTRY_VERIFY(item->x() == (i%3)*80);
611         QTRY_VERIFY(item->y() == (i/3)*60);
612     }
613
614     gridview->setContentY(120);
615
616     // move outside visible area
617     model.moveItem(1, 25);
618
619     // Confirm items positioned correctly and indexes correct
620     itemCount = findItems<QSGItem>(contentItem, "wrapper").count()-1;
621     for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) {
622         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
623         if (!item) qWarning() << "Item" << i << "not found";
624         QTRY_VERIFY(item);
625         QTRY_COMPARE(item->x(), qreal((i%3)*80));
626         QTRY_COMPARE(item->y(), qreal((i/3)*60));
627         name = findItem<QSGText>(contentItem, "textName", i);
628         QTRY_VERIFY(name != 0);
629         QTRY_COMPARE(name->text(), model.name(i));
630         number = findItem<QSGText>(contentItem, "textNumber", i);
631         QTRY_VERIFY(number != 0);
632         QTRY_COMPARE(number->text(), model.number(i));
633     }
634
635     // move from outside visible into visible
636     model.moveItem(28, 8);
637
638     // Confirm items positioned correctly and indexes correct
639     for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) {
640         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
641         if (!item) qWarning() << "Item" << i << "not found";
642         QTRY_VERIFY(item);
643         QTRY_VERIFY(item->x() == (i%3)*80);
644         QTRY_VERIFY(item->y() == (i/3)*60);
645         name = findItem<QSGText>(contentItem, "textName", i);
646         QTRY_VERIFY(name != 0);
647         QTRY_COMPARE(name->text(), model.name(i));
648         number = findItem<QSGText>(contentItem, "textNumber", i);
649         QTRY_VERIFY(number != 0);
650         QTRY_COMPARE(number->text(), model.number(i));
651     }
652
653     // ensure content position is stable
654     gridview->setContentY(0);
655     model.moveItem(10, 0);
656     QTRY_VERIFY(gridview->contentY() == 0);
657
658     delete canvas;
659 }
660
661 void tst_QSGGridView::currentIndex()
662 {
663     TestModel model;
664     for (int i = 0; i < 60; i++)
665         model.addItem("Item" + QString::number(i), QString::number(i));
666
667     QSGView *canvas = new QSGView(0);
668     canvas->setFixedSize(240,320);
669     canvas->show();
670
671     QDeclarativeContext *ctxt = canvas->rootContext();
672     ctxt->setContextProperty("testModel", &model);
673
674     QString filename(SRCDIR "/data/gridview-initCurrent.qml");
675     canvas->setSource(QUrl::fromLocalFile(filename));
676
677     qApp->processEvents();
678
679     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
680     QVERIFY(gridview != 0);
681
682     QSGItem *contentItem = gridview->contentItem();
683     QVERIFY(contentItem != 0);
684
685     // current item should be third item
686     QCOMPARE(gridview->currentIndex(), 35);
687     QCOMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 35));
688     QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
689     QCOMPARE(gridview->contentY(), 400.0);
690
691     gridview->moveCurrentIndexRight();
692     QCOMPARE(gridview->currentIndex(), 36);
693     gridview->moveCurrentIndexDown();
694     QCOMPARE(gridview->currentIndex(), 39);
695     gridview->moveCurrentIndexUp();
696     QCOMPARE(gridview->currentIndex(), 36);
697     gridview->moveCurrentIndexLeft();
698     QCOMPARE(gridview->currentIndex(), 35);
699
700     // no wrap
701     gridview->setCurrentIndex(0);
702     QCOMPARE(gridview->currentIndex(), 0);
703     // confirm that the velocity is updated
704     QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
705
706     gridview->moveCurrentIndexUp();
707     QCOMPARE(gridview->currentIndex(), 0);
708
709     gridview->moveCurrentIndexLeft();
710     QCOMPARE(gridview->currentIndex(), 0);
711
712     gridview->setCurrentIndex(model.count()-1);
713     QCOMPARE(gridview->currentIndex(), model.count()-1);
714
715     gridview->moveCurrentIndexRight();
716     QCOMPARE(gridview->currentIndex(), model.count()-1);
717
718     gridview->moveCurrentIndexDown();
719     QCOMPARE(gridview->currentIndex(), model.count()-1);
720
721     // with wrap
722     gridview->setWrapEnabled(true);
723
724     gridview->setCurrentIndex(0);
725     QCOMPARE(gridview->currentIndex(), 0);
726
727     gridview->moveCurrentIndexLeft();
728     QCOMPARE(gridview->currentIndex(), model.count()-1);
729
730     qApp->processEvents();
731     QTRY_COMPARE(gridview->contentY(), 880.0);
732
733     gridview->moveCurrentIndexRight();
734     QCOMPARE(gridview->currentIndex(), 0);
735
736     QTRY_COMPARE(gridview->contentY(), 0.0);
737
738     // Test keys
739     qApp->setActiveWindow(canvas);
740 #ifdef Q_WS_X11
741     // to be safe and avoid failing setFocus with window managers
742     qt_x11_wait_for_window_manager(canvas);
743 #endif
744     QTRY_VERIFY(canvas->hasFocus());
745     qApp->processEvents();
746
747     QTest::keyClick(canvas, Qt::Key_Down);
748     QCOMPARE(gridview->currentIndex(), 3);
749
750     QTest::keyClick(canvas, Qt::Key_Up);
751     QCOMPARE(gridview->currentIndex(), 0);
752
753     gridview->setFlow(QSGGridView::TopToBottom);
754
755     qApp->setActiveWindow(canvas);
756 #ifdef Q_WS_X11
757     // to be safe and avoid failing setFocus with window managers
758     qt_x11_wait_for_window_manager(canvas);
759 #endif
760     QTRY_VERIFY(canvas->hasFocus());
761     qApp->processEvents();
762
763     QTest::keyClick(canvas, Qt::Key_Right);
764     QCOMPARE(gridview->currentIndex(), 5);
765
766     QTest::keyClick(canvas, Qt::Key_Left);
767     QCOMPARE(gridview->currentIndex(), 0);
768
769     QTest::keyClick(canvas, Qt::Key_Down);
770     QCOMPARE(gridview->currentIndex(), 1);
771
772     QTest::keyClick(canvas, Qt::Key_Up);
773     QCOMPARE(gridview->currentIndex(), 0);
774
775
776     // turn off auto highlight
777     gridview->setHighlightFollowsCurrentItem(false);
778     QVERIFY(gridview->highlightFollowsCurrentItem() == false);
779     QVERIFY(gridview->highlightItem());
780     qreal hlPosX = gridview->highlightItem()->x();
781     qreal hlPosY = gridview->highlightItem()->y();
782
783     gridview->setCurrentIndex(5);
784     QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
785     QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
786
787     // insert item before currentIndex
788     gridview->setCurrentIndex(28);
789     model.insertItem(0, "Foo", "1111");
790     QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
791
792     // check removing highlight by setting currentIndex to -1;
793     gridview->setCurrentIndex(-1);
794
795     QCOMPARE(gridview->currentIndex(), -1);
796     QVERIFY(!gridview->highlightItem());
797     QVERIFY(!gridview->currentItem());
798
799     gridview->setHighlightFollowsCurrentItem(true);
800
801     gridview->setFlow(QSGGridView::LeftToRight);
802     gridview->setLayoutDirection(Qt::RightToLeft);
803
804     qApp->setActiveWindow(canvas);
805 #ifdef Q_WS_X11
806     // to be safe and avoid failing setFocus with window managers
807     qt_x11_wait_for_window_manager(canvas);
808 #endif
809     QTRY_VERIFY(canvas->hasFocus());
810     qApp->processEvents();
811
812     gridview->setCurrentIndex(35);
813
814     QTest::keyClick(canvas, Qt::Key_Right);
815     QCOMPARE(gridview->currentIndex(), 34);
816
817     QTest::keyClick(canvas, Qt::Key_Down);
818     QCOMPARE(gridview->currentIndex(), 37);
819
820     QTest::keyClick(canvas, Qt::Key_Up);
821     QCOMPARE(gridview->currentIndex(), 34);
822
823     QTest::keyClick(canvas, Qt::Key_Left);
824     QCOMPARE(gridview->currentIndex(), 35);
825
826
827     // turn off auto highlight
828     gridview->setHighlightFollowsCurrentItem(false);
829     QVERIFY(gridview->highlightFollowsCurrentItem() == false);
830     QVERIFY(gridview->highlightItem());
831     hlPosX = gridview->highlightItem()->x();
832     hlPosY = gridview->highlightItem()->y();
833
834     gridview->setCurrentIndex(5);
835     QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
836     QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
837
838     // insert item before currentIndex
839     gridview->setCurrentIndex(28);
840     model.insertItem(0, "Foo", "1111");
841     QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
842
843     // check removing highlight by setting currentIndex to -1;
844     gridview->setCurrentIndex(-1);
845
846     QCOMPARE(gridview->currentIndex(), -1);
847     QVERIFY(!gridview->highlightItem());
848     QVERIFY(!gridview->currentItem());
849
850     delete canvas;
851 }
852
853 void tst_QSGGridView::noCurrentIndex()
854 {
855     TestModel model;
856     for (int i = 0; i < 60; i++)
857         model.addItem("Item" + QString::number(i), QString::number(i));
858
859     QSGView *canvas = new QSGView(0);
860     canvas->setFixedSize(240,320);
861
862     QDeclarativeContext *ctxt = canvas->rootContext();
863     ctxt->setContextProperty("testModel", &model);
864
865     QString filename(SRCDIR "/data/gridview-noCurrent.qml");
866     canvas->setSource(QUrl::fromLocalFile(filename));
867
868     qApp->processEvents();
869
870     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
871     QVERIFY(gridview != 0);
872
873     QSGItem *contentItem = gridview->contentItem();
874     QVERIFY(contentItem != 0);
875
876     // current index should be -1
877     QCOMPARE(gridview->currentIndex(), -1);
878     QVERIFY(!gridview->currentItem());
879     QVERIFY(!gridview->highlightItem());
880     QCOMPARE(gridview->contentY(), 0.0);
881
882     gridview->setCurrentIndex(5);
883     QCOMPARE(gridview->currentIndex(), 5);
884     QVERIFY(gridview->currentItem());
885     QVERIFY(gridview->highlightItem());
886
887     delete canvas;
888 }
889
890 void tst_QSGGridView::changeFlow()
891 {
892     QSGView *canvas = createView();
893
894     TestModel model;
895     for (int i = 0; i < 30; i++)
896         model.addItem("Item" + QString::number(i), QString::number(i));
897
898     QDeclarativeContext *ctxt = canvas->rootContext();
899     ctxt->setContextProperty("testModel", &model);
900     ctxt->setContextProperty("testRightToLeft", QVariant(false));
901     ctxt->setContextProperty("testTopToBottom", QVariant(false));
902
903     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
904     qApp->processEvents();
905
906     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
907     QTRY_VERIFY(gridview != 0);
908
909     QSGItem *contentItem = gridview->contentItem();
910     QTRY_VERIFY(contentItem != 0);
911
912     // Confirm items positioned correctly and indexes correct
913     int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
914     for (int i = 0; i < model.count() && i < itemCount; ++i) {
915         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
916         if (!item) qWarning() << "Item" << i << "not found";
917         QTRY_VERIFY(item);
918         QTRY_COMPARE(item->x(), qreal((i%3)*80));
919         QTRY_COMPARE(item->y(), qreal((i/3)*60));
920         QSGText *name = findItem<QSGText>(contentItem, "textName", i);
921         QTRY_VERIFY(name != 0);
922         QTRY_COMPARE(name->text(), model.name(i));
923         QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
924         QTRY_VERIFY(number != 0);
925         QTRY_COMPARE(number->text(), model.number(i));
926     }
927
928     ctxt->setContextProperty("testTopToBottom", QVariant(true));
929
930     // Confirm items positioned correctly and indexes correct
931     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
932     for (int i = 0; i < model.count() && i < itemCount; ++i) {
933         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
934         if (!item) qWarning() << "Item" << i << "not found";
935         QTRY_VERIFY(item);
936         QTRY_COMPARE(item->x(), qreal((i/5)*80));
937         QTRY_COMPARE(item->y(), qreal((i%5)*60));
938         QSGText *name = findItem<QSGText>(contentItem, "textName", i);
939         QTRY_VERIFY(name != 0);
940         QTRY_COMPARE(name->text(), model.name(i));
941         QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
942         QTRY_VERIFY(number != 0);
943         QTRY_COMPARE(number->text(), model.number(i));
944     }
945
946     ctxt->setContextProperty("testRightToLeft", QVariant(true));
947
948     // Confirm items positioned correctly and indexes correct
949     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
950     for (int i = 0; i < model.count() && i < itemCount; ++i) {
951         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
952         if (!item) qWarning() << "Item" << i << "not found";
953         QTRY_VERIFY(item);
954         QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
955         QTRY_COMPARE(item->y(), qreal((i%5)*60));
956         QSGText *name = findItem<QSGText>(contentItem, "textName", i);
957         QTRY_VERIFY(name != 0);
958         QTRY_COMPARE(name->text(), model.name(i));
959         QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
960         QTRY_VERIFY(number != 0);
961         QTRY_COMPARE(number->text(), model.number(i));
962     }
963     gridview->setContentX(100);
964     QTRY_COMPARE(gridview->contentX(), 100.);
965     ctxt->setContextProperty("testTopToBottom", QVariant(false));
966     QTRY_COMPARE(gridview->contentX(), 0.);
967
968     // Confirm items positioned correctly and indexes correct
969     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
970     for (int i = 0; i < model.count() && i < itemCount; ++i) {
971         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
972         if (!item) qWarning() << "Item" << i << "not found";
973         QTRY_VERIFY(item);
974         QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
975         QTRY_COMPARE(item->y(), qreal((i/3)*60));
976         QSGText *name = findItem<QSGText>(contentItem, "textName", i);
977         QTRY_VERIFY(name != 0);
978         QTRY_COMPARE(name->text(), model.name(i));
979         QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
980         QTRY_VERIFY(number != 0);
981         QTRY_COMPARE(number->text(), model.number(i));
982     }
983
984     delete canvas;
985 }
986
987 void tst_QSGGridView::defaultValues()
988 {
989     QDeclarativeEngine engine;
990     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview3.qml"));
991     QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
992
993     QTRY_VERIFY(obj != 0);
994     QTRY_VERIFY(obj->model() == QVariant());
995     QTRY_VERIFY(obj->delegate() == 0);
996     QTRY_COMPARE(obj->currentIndex(), -1);
997     QTRY_VERIFY(obj->currentItem() == 0);
998     QTRY_COMPARE(obj->count(), 0);
999     QTRY_VERIFY(obj->highlight() == 0);
1000     QTRY_VERIFY(obj->highlightItem() == 0);
1001     QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1002     QTRY_VERIFY(obj->flow() == 0);
1003     QTRY_COMPARE(obj->isWrapEnabled(), false);
1004     QTRY_COMPARE(obj->cacheBuffer(), 0);
1005     QTRY_COMPARE(obj->cellWidth(), 100); //### Should 100 be the default?
1006     QTRY_COMPARE(obj->cellHeight(), 100);
1007     delete obj;
1008 }
1009
1010 void tst_QSGGridView::properties()
1011 {
1012     QDeclarativeEngine engine;
1013     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview2.qml"));
1014     QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1015
1016     QTRY_VERIFY(obj != 0);
1017     QTRY_VERIFY(obj->model() != QVariant());
1018     QTRY_VERIFY(obj->delegate() != 0);
1019     QTRY_COMPARE(obj->currentIndex(), 0);
1020     QTRY_VERIFY(obj->currentItem() != 0);
1021     QTRY_COMPARE(obj->count(), 4);
1022     QTRY_VERIFY(obj->highlight() != 0);
1023     QTRY_VERIFY(obj->highlightItem() != 0);
1024     QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1025     QTRY_VERIFY(obj->flow() == 0);
1026     QTRY_COMPARE(obj->isWrapEnabled(), true);
1027     QTRY_COMPARE(obj->cacheBuffer(), 200);
1028     QTRY_COMPARE(obj->cellWidth(), 100);
1029     QTRY_COMPARE(obj->cellHeight(), 100);
1030     delete obj;
1031 }
1032
1033 void tst_QSGGridView::propertyChanges()
1034 {
1035     QSGView *canvas = createView();
1036     QTRY_VERIFY(canvas);
1037     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1038
1039     QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1040     QTRY_VERIFY(gridView);
1041
1042     QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1043     QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1044     QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1045     QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1046
1047     QTRY_COMPARE(gridView->isWrapEnabled(), true);
1048     QTRY_COMPARE(gridView->cacheBuffer(), 10);
1049     QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1050
1051     gridView->setWrapEnabled(false);
1052     gridView->setCacheBuffer(3);
1053     gridView->setFlow(QSGGridView::TopToBottom);
1054
1055     QTRY_COMPARE(gridView->isWrapEnabled(), false);
1056     QTRY_COMPARE(gridView->cacheBuffer(), 3);
1057     QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1058
1059     QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1060     QTRY_COMPARE(cacheBufferSpy.count(),1);
1061     QTRY_COMPARE(flowSpy.count(),1);
1062
1063     gridView->setWrapEnabled(false);
1064     gridView->setCacheBuffer(3);
1065     gridView->setFlow(QSGGridView::TopToBottom);
1066
1067     QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1068     QTRY_COMPARE(cacheBufferSpy.count(),1);
1069     QTRY_COMPARE(flowSpy.count(),1);
1070
1071     gridView->setFlow(QSGGridView::LeftToRight);
1072     QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1073
1074     gridView->setWrapEnabled(true);
1075     gridView->setCacheBuffer(5);
1076     gridView->setLayoutDirection(Qt::RightToLeft);
1077
1078     QTRY_COMPARE(gridView->isWrapEnabled(), true);
1079     QTRY_COMPARE(gridView->cacheBuffer(), 5);
1080     QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1081
1082     QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1083     QTRY_COMPARE(cacheBufferSpy.count(),2);
1084     QTRY_COMPARE(layoutSpy.count(),1);
1085     QTRY_COMPARE(flowSpy.count(),2);
1086
1087     gridView->setWrapEnabled(true);
1088     gridView->setCacheBuffer(5);
1089     gridView->setLayoutDirection(Qt::RightToLeft);
1090
1091     QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1092     QTRY_COMPARE(cacheBufferSpy.count(),2);
1093     QTRY_COMPARE(layoutSpy.count(),1);
1094     QTRY_COMPARE(flowSpy.count(),2);
1095
1096     gridView->setFlow(QSGGridView::TopToBottom);
1097     QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1098     QTRY_COMPARE(flowSpy.count(),3);
1099
1100     gridView->setFlow(QSGGridView::TopToBottom);
1101     QTRY_COMPARE(flowSpy.count(),3);
1102
1103     delete canvas;
1104 }
1105
1106 void tst_QSGGridView::componentChanges()
1107 {
1108     QSGView *canvas = createView();
1109     QTRY_VERIFY(canvas);
1110     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1111
1112     QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1113     QTRY_VERIFY(gridView);
1114
1115     QDeclarativeComponent component(canvas->engine());
1116     component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1117
1118     QDeclarativeComponent delegateComponent(canvas->engine());
1119     delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1120
1121     QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1122     QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1123     QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1124     QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1125
1126     gridView->setHighlight(&component);
1127     gridView->setDelegate(&delegateComponent);
1128     gridView->setHeader(&component);
1129     gridView->setFooter(&component);
1130
1131     QTRY_COMPARE(gridView->highlight(), &component);
1132     QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1133     QTRY_COMPARE(gridView->header(), &component);
1134     QTRY_COMPARE(gridView->footer(), &component);
1135
1136     QTRY_COMPARE(highlightSpy.count(),1);
1137     QTRY_COMPARE(delegateSpy.count(),1);
1138     QTRY_COMPARE(headerSpy.count(),1);
1139     QTRY_COMPARE(footerSpy.count(),1);
1140
1141     gridView->setHighlight(&component);
1142     gridView->setDelegate(&delegateComponent);
1143     gridView->setHeader(&component);
1144     gridView->setFooter(&component);
1145
1146     QTRY_COMPARE(highlightSpy.count(),1);
1147     QTRY_COMPARE(delegateSpy.count(),1);
1148     QTRY_COMPARE(headerSpy.count(),1);
1149     QTRY_COMPARE(footerSpy.count(),1);
1150
1151     delete canvas;
1152 }
1153
1154 void tst_QSGGridView::modelChanges()
1155 {
1156     QSGView *canvas = createView();
1157     QTRY_VERIFY(canvas);
1158     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1159
1160     QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1161     QTRY_VERIFY(gridView);
1162
1163     QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1164     QTRY_VERIFY(alternateModel);
1165     QVariant modelVariant = QVariant::fromValue(alternateModel);
1166     QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1167
1168     gridView->setModel(modelVariant);
1169     QTRY_COMPARE(gridView->model(), modelVariant);
1170     QTRY_COMPARE(modelSpy.count(),1);
1171
1172     gridView->setModel(modelVariant);
1173     QTRY_COMPARE(modelSpy.count(),1);
1174
1175     gridView->setModel(QVariant());
1176     QTRY_COMPARE(modelSpy.count(),2);
1177     delete canvas;
1178 }
1179
1180 void tst_QSGGridView::positionViewAtIndex()
1181 {
1182     QSGView *canvas = createView();
1183
1184     TestModel model;
1185     for (int i = 0; i < 40; i++)
1186         model.addItem("Item" + QString::number(i), "");
1187
1188     QDeclarativeContext *ctxt = canvas->rootContext();
1189     ctxt->setContextProperty("testModel", &model);
1190     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1191     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1192
1193     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1194     qApp->processEvents();
1195
1196     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1197     QTRY_VERIFY(gridview != 0);
1198
1199     QSGItem *contentItem = gridview->contentItem();
1200     QTRY_VERIFY(contentItem != 0);
1201
1202     // Confirm items positioned correctly
1203     int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1204     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1205         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1206         if (!item) qWarning() << "Item" << i << "not found";
1207         QTRY_VERIFY(item);
1208         QTRY_COMPARE(item->x(), (i%3)*80.);
1209         QTRY_COMPARE(item->y(), (i/3)*60.);
1210     }
1211
1212     // Position on a currently visible item
1213     gridview->positionViewAtIndex(4, QSGGridView::Beginning);
1214     QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1215     QTRY_COMPARE(gridview->contentY(), 60.);
1216
1217     // Confirm items positioned correctly
1218     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1219     for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1220         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1221         if (!item) qWarning() << "Item" << i << "not found";
1222         QTRY_VERIFY(item);
1223         QTRY_COMPARE(item->x(), (i%3)*80.);
1224         QTRY_COMPARE(item->y(), (i/3)*60.);
1225     }
1226
1227     // Position on an item beyond the visible items
1228     gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1229     QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1230     QTRY_COMPARE(gridview->contentY(), 420.);
1231
1232     // Confirm items positioned correctly
1233     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1234     for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1235         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1236         if (!item) qWarning() << "Item" << i << "not found";
1237         QTRY_VERIFY(item);
1238         QTRY_COMPARE(item->x(), (i%3)*80.);
1239         QTRY_COMPARE(item->y(), (i/3)*60.);
1240     }
1241
1242     // Position on an item that would leave empty space if positioned at the top
1243     gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1244     QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1245     QTRY_COMPARE(gridview->contentY(), 520.);
1246
1247     // Confirm items positioned correctly
1248     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1249     for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1250         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1251         if (!item) qWarning() << "Item" << i << "not found";
1252         QTRY_VERIFY(item);
1253         QTRY_COMPARE(item->x(), (i%3)*80.);
1254         QTRY_COMPARE(item->y(), (i/3)*60.);
1255     }
1256
1257     // Position at the beginning again
1258     gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1259     QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1260     QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1261     QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1262     QTRY_COMPARE(gridview->contentY(), 0.);
1263
1264     // Confirm items positioned correctly
1265     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1266     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1267         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1268         if (!item) qWarning() << "Item" << i << "not found";
1269         QTRY_VERIFY(item);
1270         QTRY_COMPARE(item->x(), (i%3)*80.);
1271         QTRY_COMPARE(item->y(), (i/3)*60.);
1272     }
1273
1274     // Position at End
1275     gridview->positionViewAtIndex(30, QSGGridView::End);
1276     QTRY_COMPARE(gridview->contentY(), 340.);
1277
1278     // Position in Center
1279     gridview->positionViewAtIndex(15, QSGGridView::Center);
1280     QTRY_COMPARE(gridview->contentY(), 170.);
1281
1282     // Ensure at least partially visible
1283     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1284     QTRY_COMPARE(gridview->contentY(), 170.);
1285
1286     gridview->setContentY(302);
1287     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1288     QTRY_COMPARE(gridview->contentY(), 302.);
1289
1290     gridview->setContentY(360);
1291     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1292     QTRY_COMPARE(gridview->contentY(), 300.);
1293
1294     gridview->setContentY(60);
1295     gridview->positionViewAtIndex(20, QSGGridView::Visible);
1296     QTRY_COMPARE(gridview->contentY(), 60.);
1297
1298     gridview->setContentY(20);
1299     gridview->positionViewAtIndex(20, QSGGridView::Visible);
1300     QTRY_COMPARE(gridview->contentY(), 100.);
1301
1302     // Ensure completely visible
1303     gridview->setContentY(120);
1304     gridview->positionViewAtIndex(20, QSGGridView::Contain);
1305     QTRY_COMPARE(gridview->contentY(), 120.);
1306
1307     gridview->setContentY(302);
1308     gridview->positionViewAtIndex(15, QSGGridView::Contain);
1309     QTRY_COMPARE(gridview->contentY(), 300.);
1310
1311     gridview->setContentY(60);
1312     gridview->positionViewAtIndex(20, QSGGridView::Contain);
1313     QTRY_COMPARE(gridview->contentY(), 100.);
1314
1315     // Test for Top To Bottom layout
1316     ctxt->setContextProperty("testTopToBottom", QVariant(true));
1317
1318     // Confirm items positioned correctly
1319     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1320     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1321         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1322         if (!item) qWarning() << "Item" << i << "not found";
1323         QTRY_VERIFY(item);
1324         QTRY_COMPARE(item->x(), (i/5)*80.);
1325         QTRY_COMPARE(item->y(), (i%5)*60.);
1326     }
1327
1328     // Position at End
1329     gridview->positionViewAtIndex(30, QSGGridView::End);
1330     QTRY_COMPARE(gridview->contentX(), 320.);
1331     QTRY_COMPARE(gridview->contentY(), 0.);
1332
1333     // Position in Center
1334     gridview->positionViewAtIndex(15, QSGGridView::Center);
1335     QTRY_COMPARE(gridview->contentX(), 160.);
1336
1337     // Ensure at least partially visible
1338     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1339     QTRY_COMPARE(gridview->contentX(), 160.);
1340
1341     gridview->setContentX(170);
1342     gridview->positionViewAtIndex(25, QSGGridView::Visible);
1343     QTRY_COMPARE(gridview->contentX(), 170.);
1344
1345     gridview->positionViewAtIndex(30, QSGGridView::Visible);
1346     QTRY_COMPARE(gridview->contentX(), 320.);
1347
1348     gridview->setContentX(170);
1349     gridview->positionViewAtIndex(25, QSGGridView::Contain);
1350     QTRY_COMPARE(gridview->contentX(), 240.);
1351
1352     // positionViewAtBeginning
1353     gridview->positionViewAtBeginning();
1354     QTRY_COMPARE(gridview->contentX(), 0.);
1355
1356     gridview->setContentX(80);
1357     canvas->rootObject()->setProperty("showHeader", true);
1358     gridview->positionViewAtBeginning();
1359     QTRY_COMPARE(gridview->contentX(), -30.);
1360
1361     // positionViewAtEnd
1362     gridview->positionViewAtEnd();
1363     QTRY_COMPARE(gridview->contentX(), 400.);   // 8*80 - 240   (8 columns)
1364
1365     gridview->setContentX(80);
1366     canvas->rootObject()->setProperty("showFooter", true);
1367     gridview->positionViewAtEnd();
1368     QTRY_COMPARE(gridview->contentX(), 430.);
1369
1370     // set current item to outside visible view, position at beginning
1371     // and ensure highlight moves to current item
1372     gridview->setCurrentIndex(6);
1373     gridview->positionViewAtBeginning();
1374     QTRY_COMPARE(gridview->contentX(), -30.);
1375     QVERIFY(gridview->highlightItem());
1376     QCOMPARE(gridview->highlightItem()->x(), 80.);
1377
1378     delete canvas;
1379 }
1380
1381 void tst_QSGGridView::snapping()
1382 {
1383     QSGView *canvas = createView();
1384
1385     TestModel model;
1386     for (int i = 0; i < 40; i++)
1387         model.addItem("Item" + QString::number(i), "");
1388
1389     QDeclarativeContext *ctxt = canvas->rootContext();
1390     ctxt->setContextProperty("testModel", &model);
1391     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1392     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1393
1394     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1395     qApp->processEvents();
1396
1397     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1398     QTRY_VERIFY(gridview != 0);
1399
1400     gridview->setHeight(220);
1401     QCOMPARE(gridview->height(), 220.);
1402
1403     gridview->positionViewAtIndex(12, QSGGridView::Visible);
1404     QCOMPARE(gridview->contentY(), 80.);
1405
1406     gridview->setContentY(0);
1407     QCOMPARE(gridview->contentY(), 0.);
1408
1409     gridview->setSnapMode(QSGGridView::SnapToRow);
1410     QCOMPARE(gridview->snapMode(), QSGGridView::SnapToRow);
1411
1412     gridview->positionViewAtIndex(12, QSGGridView::Visible);
1413     QCOMPARE(gridview->contentY(), 60.);
1414
1415     gridview->positionViewAtIndex(15, QSGGridView::End);
1416     QCOMPARE(gridview->contentY(), 120.);
1417
1418     delete canvas;
1419
1420 }
1421
1422 void tst_QSGGridView::mirroring()
1423 {
1424     QSGView *canvasA = createView();
1425     canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
1426     QSGGridView *gridviewA = findItem<QSGGridView>(canvasA->rootObject(), "view");
1427     QTRY_VERIFY(gridviewA != 0);
1428
1429     QSGView *canvasB = createView();
1430     canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
1431     QSGGridView *gridviewB = findItem<QSGGridView>(canvasB->rootObject(), "view");
1432     QTRY_VERIFY(gridviewA != 0);
1433     qApp->processEvents();
1434
1435     QList<QString> objectNames;
1436     objectNames << "item1" << "item2"; // << "item3"
1437
1438     gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1439     gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
1440     QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
1441
1442     // LTR != RTL
1443     foreach(const QString objectName, objectNames)
1444         QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1445
1446     gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1447     gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
1448
1449     // LTR == LTR
1450     foreach(const QString objectName, objectNames)
1451         QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1452
1453     QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
1454     QSGItemPrivate::get(gridviewB)->setLayoutMirror(true);
1455     QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
1456
1457     // LTR != LTR+mirror
1458     foreach(const QString objectName, objectNames)
1459         QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1460
1461     gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
1462
1463     // RTL == LTR+mirror
1464     foreach(const QString objectName, objectNames)
1465         QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1466
1467     gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
1468
1469     // RTL != RTL+mirror
1470     foreach(const QString objectName, objectNames)
1471         QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1472
1473     gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1474
1475     // LTR == RTL+mirror
1476     foreach(const QString objectName, objectNames)
1477         QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1478
1479     delete canvasA;
1480     delete canvasB;
1481 }
1482
1483 void tst_QSGGridView::positionViewAtIndex_rightToLeft()
1484 {
1485     QSGView *canvas = createView();
1486
1487     TestModel model;
1488     for (int i = 0; i < 40; i++)
1489         model.addItem("Item" + QString::number(i), "");
1490
1491     QDeclarativeContext *ctxt = canvas->rootContext();
1492     ctxt->setContextProperty("testModel", &model);
1493     ctxt->setContextProperty("testTopToBottom", QVariant(true));
1494     ctxt->setContextProperty("testRightToLeft", QVariant(true));
1495
1496     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1497     qApp->processEvents();
1498
1499     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1500     QTRY_VERIFY(gridview != 0);
1501
1502     QSGItem *contentItem = gridview->contentItem();
1503     QTRY_VERIFY(contentItem != 0);
1504
1505     // Confirm items positioned correctly
1506     int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1507     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1508         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1509         if (!item) qWarning() << "Item" << i << "not found";
1510         QTRY_VERIFY(item);
1511         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1512         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1513     }
1514
1515     // Position on a currently visible item
1516     gridview->positionViewAtIndex(6, QSGGridView::Beginning);
1517     QTRY_COMPARE(gridview->contentX(), -320.);
1518
1519     // Confirm items positioned correctly
1520     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1521     for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1522         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1523         if (!item) qWarning() << "Item" << i << "not found";
1524         QTRY_VERIFY(item);
1525         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1526         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1527     }
1528
1529     // Position on an item beyond the visible items
1530     gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1531     QTRY_COMPARE(gridview->contentX(), -560.);
1532
1533     // Confirm items positioned correctly
1534     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1535     for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1536         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1537         if (!item) qWarning() << "Item" << i << "not found";
1538         QTRY_VERIFY(item);
1539         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1540         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1541     }
1542
1543     // Position on an item that would leave empty space if positioned at the top
1544     gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1545     QTRY_COMPARE(gridview->contentX(), -640.);
1546
1547     // Confirm items positioned correctly
1548     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1549     for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1550         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1551         if (!item) qWarning() << "Item" << i << "not found";
1552         QTRY_VERIFY(item);
1553         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1554         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1555     }
1556
1557     // Position at the beginning again
1558     gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1559     QTRY_COMPARE(gridview->contentX(), -240.);
1560
1561     // Confirm items positioned correctly
1562     itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1563     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1564         QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1565         if (!item) qWarning() << "Item" << i << "not found";
1566         QTRY_VERIFY(item);
1567         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1568         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1569     }
1570
1571     // Position at End
1572     gridview->positionViewAtIndex(30, QSGGridView::End);
1573     QTRY_COMPARE(gridview->contentX(), -560.);
1574
1575     // Position in Center
1576     gridview->positionViewAtIndex(15, QSGGridView::Center);
1577     QTRY_COMPARE(gridview->contentX(), -400.);
1578
1579     // Ensure at least partially visible
1580     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1581     QTRY_COMPARE(gridview->contentX(), -400.);
1582
1583     gridview->setContentX(-555.);
1584     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1585     QTRY_COMPARE(gridview->contentX(), -555.);
1586
1587     gridview->setContentX(-239);
1588     gridview->positionViewAtIndex(15, QSGGridView::Visible);
1589     QTRY_COMPARE(gridview->contentX(), -320.);
1590
1591     gridview->setContentX(-239);
1592     gridview->positionViewAtIndex(20, QSGGridView::Visible);
1593     QTRY_COMPARE(gridview->contentX(), -400.);
1594
1595     gridview->setContentX(-640);
1596     gridview->positionViewAtIndex(20, QSGGridView::Visible);
1597     QTRY_COMPARE(gridview->contentX(), -560.);
1598
1599     // Ensure completely visible
1600     gridview->setContentX(-400);
1601     gridview->positionViewAtIndex(20, QSGGridView::Contain);
1602     QTRY_COMPARE(gridview->contentX(), -400.);
1603
1604     gridview->setContentX(-315);
1605     gridview->positionViewAtIndex(15, QSGGridView::Contain);
1606     QTRY_COMPARE(gridview->contentX(), -320.);
1607
1608     gridview->setContentX(-640);
1609     gridview->positionViewAtIndex(20, QSGGridView::Contain);
1610     QTRY_COMPARE(gridview->contentX(), -560.);
1611
1612     delete canvas;
1613 }
1614
1615 void tst_QSGGridView::resetModel()
1616 {
1617     QSGView *canvas = createView();
1618
1619     QStringList strings;
1620     strings << "one" << "two" << "three";
1621     QStringListModel model(strings);
1622
1623     QDeclarativeContext *ctxt = canvas->rootContext();
1624     ctxt->setContextProperty("testModel", &model);
1625
1626     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaygrid.qml"));
1627     qApp->processEvents();
1628
1629     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1630     QTRY_VERIFY(gridview != 0);
1631
1632     QSGItem *contentItem = gridview->contentItem();
1633     QTRY_VERIFY(contentItem != 0);
1634
1635     QTRY_COMPARE(gridview->count(), model.rowCount());
1636
1637     for (int i = 0; i < model.rowCount(); ++i) {
1638         QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
1639         QTRY_VERIFY(display != 0);
1640         QTRY_COMPARE(display->text(), strings.at(i));
1641     }
1642
1643     strings.clear();
1644     strings << "four" << "five" << "six" << "seven";
1645     model.setStringList(strings);
1646
1647     QTRY_COMPARE(gridview->count(), model.rowCount());
1648
1649     for (int i = 0; i < model.rowCount(); ++i) {
1650         QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
1651         QTRY_VERIFY(display != 0);
1652         QTRY_COMPARE(display->text(), strings.at(i));
1653     }
1654
1655     delete canvas;
1656 }
1657
1658 void tst_QSGGridView::enforceRange()
1659 {
1660     QSGView *canvas = createView();
1661
1662     TestModel model;
1663     for (int i = 0; i < 30; i++)
1664         model.addItem("Item" + QString::number(i), "");
1665
1666     QDeclarativeContext *ctxt = canvas->rootContext();
1667     ctxt->setContextProperty("testModel", &model);
1668     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1669     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1670
1671     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
1672     qApp->processEvents();
1673     QVERIFY(canvas->rootObject() != 0);
1674
1675     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1676     QTRY_VERIFY(gridview != 0);
1677
1678     QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
1679     QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
1680     QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
1681
1682     QSGItem *contentItem = gridview->contentItem();
1683     QTRY_VERIFY(contentItem != 0);
1684
1685     // view should be positioned at the top of the range.
1686     QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
1687     QTRY_VERIFY(item);
1688     QTRY_COMPARE(gridview->contentY(), -100.0);
1689
1690     QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
1691     QTRY_VERIFY(name != 0);
1692     QTRY_COMPARE(name->text(), model.name(0));
1693     QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
1694     QTRY_VERIFY(number != 0);
1695     QTRY_COMPARE(number->text(), model.number(0));
1696
1697     // Check currentIndex is updated when contentItem moves
1698     gridview->setContentY(0);
1699     QTRY_COMPARE(gridview->currentIndex(), 2);
1700
1701     gridview->setCurrentIndex(5);
1702     QTRY_COMPARE(gridview->contentY(), 100.);
1703
1704     TestModel model2;
1705     for (int i = 0; i < 5; i++)
1706         model2.addItem("Item" + QString::number(i), "");
1707
1708     ctxt->setContextProperty("testModel", &model2);
1709     QCOMPARE(gridview->count(), 5);
1710
1711     delete canvas;
1712 }
1713
1714 void tst_QSGGridView::enforceRange_rightToLeft()
1715 {
1716     QSGView *canvas = createView();
1717
1718     TestModel model;
1719     for (int i = 0; i < 30; i++)
1720         model.addItem("Item" + QString::number(i), "");
1721
1722     QDeclarativeContext *ctxt = canvas->rootContext();
1723     ctxt->setContextProperty("testModel", &model);
1724     ctxt->setContextProperty("testRightToLeft", QVariant(true));
1725     ctxt->setContextProperty("testTopToBottom", QVariant(true));
1726
1727     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
1728     qApp->processEvents();
1729     QVERIFY(canvas->rootObject() != 0);
1730
1731     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1732     QTRY_VERIFY(gridview != 0);
1733
1734     QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
1735     QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
1736     QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
1737
1738     QSGItem *contentItem = gridview->contentItem();
1739     QTRY_VERIFY(contentItem != 0);
1740
1741     // view should be positioned at the top of the range.
1742     QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
1743     QTRY_VERIFY(item);
1744     QTRY_COMPARE(gridview->contentX(), -100.);
1745     QTRY_COMPARE(gridview->contentY(), 0.0);
1746
1747     QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
1748     QTRY_VERIFY(name != 0);
1749     QTRY_COMPARE(name->text(), model.name(0));
1750     QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
1751     QTRY_VERIFY(number != 0);
1752     QTRY_COMPARE(number->text(), model.number(0));
1753
1754     // Check currentIndex is updated when contentItem moves
1755     gridview->setContentX(-200);
1756     QTRY_COMPARE(gridview->currentIndex(), 3);
1757
1758     gridview->setCurrentIndex(7);
1759     QTRY_COMPARE(gridview->contentX(), -300.);
1760     QTRY_COMPARE(gridview->contentY(), 0.0);
1761
1762     TestModel model2;
1763     for (int i = 0; i < 5; i++)
1764         model2.addItem("Item" + QString::number(i), "");
1765
1766     ctxt->setContextProperty("testModel", &model2);
1767     QCOMPARE(gridview->count(), 5);
1768
1769     delete canvas;
1770 }
1771
1772 void tst_QSGGridView::QTBUG_8456()
1773 {
1774     QSGView *canvas = createView();
1775
1776     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/setindex.qml"));
1777     qApp->processEvents();
1778
1779     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1780     QTRY_VERIFY(gridview != 0);
1781
1782     QTRY_COMPARE(gridview->currentIndex(), 0);
1783
1784     delete canvas;
1785 }
1786
1787 void tst_QSGGridView::manualHighlight()
1788 {
1789     QSGView *canvas = createView();
1790
1791     QString filename(SRCDIR "/data/manual-highlight.qml");
1792     canvas->setSource(QUrl::fromLocalFile(filename));
1793
1794     qApp->processEvents();
1795
1796     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1797     QTRY_VERIFY(gridview != 0);
1798
1799     QSGItem *contentItem = gridview->contentItem();
1800     QTRY_VERIFY(contentItem != 0);
1801
1802     QTRY_COMPARE(gridview->currentIndex(), 0);
1803     QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
1804     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1805     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1806
1807     gridview->setCurrentIndex(2);
1808
1809     QTRY_COMPARE(gridview->currentIndex(), 2);
1810     QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
1811     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1812     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1813
1814     gridview->positionViewAtIndex(8, QSGGridView::Contain);
1815
1816     QTRY_COMPARE(gridview->currentIndex(), 2);
1817     QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
1818     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1819     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1820
1821     gridview->setFlow(QSGGridView::TopToBottom);
1822     QTRY_COMPARE(gridview->flow(), QSGGridView::TopToBottom);
1823
1824     gridview->setCurrentIndex(0);
1825     QTRY_COMPARE(gridview->currentIndex(), 0);
1826     QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
1827     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1828     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1829
1830     delete canvas;
1831 }
1832
1833
1834 void tst_QSGGridView::footer()
1835 {
1836     QFETCH(QSGGridView::Flow, flow);
1837     QFETCH(Qt::LayoutDirection, layoutDirection);
1838     QFETCH(QPointF, initialFooterPos);
1839     QFETCH(QPointF, changedFooterPos);
1840     QFETCH(QPointF, initialContentPos);
1841     QFETCH(QPointF, changedContentPos);
1842     QFETCH(QPointF, firstDelegatePos);
1843
1844     QSGView *canvas = createView();
1845     canvas->show();
1846
1847     TestModel model;
1848     for (int i = 0; i < 7; i++)
1849         model.addItem("Item" + QString::number(i), "");
1850
1851     QDeclarativeContext *ctxt = canvas->rootContext();
1852     ctxt->setContextProperty("testModel", &model);
1853
1854     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml"));
1855     qApp->processEvents();
1856
1857     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1858     QTRY_VERIFY(gridview != 0);
1859     gridview->setFlow(flow);
1860     gridview->setLayoutDirection(layoutDirection);
1861
1862     QSGItem *contentItem = gridview->contentItem();
1863     QTRY_VERIFY(contentItem != 0);
1864
1865     QSGText *footer = findItem<QSGText>(contentItem, "footer");
1866     QVERIFY(footer);
1867
1868     QCOMPARE(footer->pos(), initialFooterPos);
1869     QCOMPARE(footer->width(), 100.);
1870     QCOMPARE(footer->height(), 30.);
1871     QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
1872
1873     QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
1874     QVERIFY(item);
1875     QCOMPARE(item->pos(), firstDelegatePos);
1876
1877     if (flow == QSGGridView::LeftToRight) {
1878         // shrink by one row
1879         model.removeItem(2);
1880         QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
1881     } else {
1882         // shrink by one column
1883         model.removeItem(2);
1884         model.removeItem(3);
1885         if (layoutDirection == Qt::LeftToRight)
1886             QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
1887         else
1888             QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
1889     }
1890
1891     // remove all items
1892     model.clear();
1893
1894     QPointF posWhenNoItems(0, 0);
1895     if (layoutDirection == Qt::RightToLeft)
1896         posWhenNoItems.setX(flow == QSGGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
1897     QTRY_COMPARE(footer->pos(), posWhenNoItems);
1898
1899     // if header is present, it's at a negative pos, so the footer should not move
1900     canvas->rootObject()->setProperty("showHeader", true);
1901     QVERIFY(findItem<QSGItem>(contentItem, "header") != 0);
1902     QTRY_COMPARE(footer->pos(), posWhenNoItems);
1903     canvas->rootObject()->setProperty("showHeader", false);
1904
1905     // add 30 items
1906     for (int i = 0; i < 30; i++)
1907         model.addItem("Item" + QString::number(i), "");
1908     QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
1909
1910     footer = findItem<QSGText>(contentItem, "footer");
1911     QVERIFY(!footer);
1912     footer = findItem<QSGText>(contentItem, "footer2");
1913     QVERIFY(footer);
1914
1915     QCOMPARE(footer->pos(), changedFooterPos);
1916     QCOMPARE(footer->width(), 50.);
1917     QCOMPARE(footer->height(), 20.);
1918     QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
1919
1920     item = findItem<QSGItem>(contentItem, "wrapper", 0);
1921     QVERIFY(item);
1922     QCOMPARE(item->pos(), firstDelegatePos);
1923
1924     delete canvas;
1925 }
1926
1927 void tst_QSGGridView::footer_data()
1928 {
1929     QTest::addColumn<QSGGridView::Flow>("flow");
1930     QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
1931     QTest::addColumn<QPointF>("initialFooterPos");
1932     QTest::addColumn<QPointF>("changedFooterPos");
1933     QTest::addColumn<QPointF>("initialContentPos");
1934     QTest::addColumn<QPointF>("changedContentPos");
1935     QTest::addColumn<QPointF>("firstDelegatePos");
1936
1937     // footer1 = 100 x 30
1938     // footer2 = 100 x 20
1939     // cells = 80 * 60
1940     // view width = 240
1941
1942     // footer below items, bottom left
1943     QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
1944         << QPointF(0, 3 * 60)  // 180 = height of 3 rows (cell height is 60)
1945         << QPointF(0, 10 * 60)  // 30 items = 10 rows
1946         << QPointF(0, 0)
1947         << QPointF(0, 0)
1948         << QPointF(0, 0);
1949
1950     // footer below items, bottom right
1951     QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
1952         << QPointF(240 - 100, 3 * 60)
1953         << QPointF((240 - 100) + 50, 10 * 60)     // 50 = width diff between old and new footers
1954         << QPointF(0, 0)
1955         << QPointF(0, 0)
1956         << QPointF(240 - 80, 0);
1957
1958     // footer to right of items
1959     QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
1960         << QPointF(2 * 80, 0)      // 2 columns, cell width 80
1961         << QPointF(6 * 80, 0)      // 30 items = 6 columns
1962         << QPointF(0, 0)
1963         << QPointF(0, 0)
1964         << QPointF(0, 0);
1965
1966     // footer to left of items
1967     QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
1968         << QPointF(-(2 * 80) - 100, 0)
1969         << QPointF(-(6 * 80) - 50, 0)     // 50 = new footer width
1970         << QPointF(-240, 0)
1971         << QPointF(-240, 0)    // unchanged, footer change doesn't change content pos
1972         << QPointF(-80, 0);
1973 }
1974
1975 void tst_QSGGridView::header()
1976 {
1977     QFETCH(QSGGridView::Flow, flow);
1978     QFETCH(Qt::LayoutDirection, layoutDirection);
1979     QFETCH(QPointF, initialHeaderPos);
1980     QFETCH(QPointF, changedHeaderPos);
1981     QFETCH(QPointF, initialContentPos);
1982     QFETCH(QPointF, changedContentPos);
1983     QFETCH(QPointF, firstDelegatePos);
1984
1985     QSGView *canvas = createView();
1986
1987     TestModel model;
1988     for (int i = 0; i < 30; i++)
1989         model.addItem("Item" + QString::number(i), "");
1990
1991     QDeclarativeContext *ctxt = canvas->rootContext();
1992     ctxt->setContextProperty("testModel", &model);
1993
1994     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
1995     qApp->processEvents();
1996
1997     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1998     QTRY_VERIFY(gridview != 0);
1999     gridview->setFlow(flow);
2000     gridview->setLayoutDirection(layoutDirection);
2001
2002     QSGItem *contentItem = gridview->contentItem();
2003     QTRY_VERIFY(contentItem != 0);
2004
2005     QSGText *header = findItem<QSGText>(contentItem, "header");
2006     QVERIFY(header);
2007
2008     QCOMPARE(header->pos(), initialHeaderPos);
2009     QCOMPARE(header->width(), 100.);
2010     QCOMPARE(header->height(), 30.);
2011     QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2012
2013     QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2014     QVERIFY(item);
2015     QCOMPARE(item->pos(), firstDelegatePos);
2016
2017     model.clear();
2018     QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
2019
2020     for (int i = 0; i < 30; i++)
2021         model.addItem("Item" + QString::number(i), "");
2022
2023     QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
2024
2025     header = findItem<QSGText>(contentItem, "header");
2026     QVERIFY(!header);
2027     header = findItem<QSGText>(contentItem, "header2");
2028     QVERIFY(header);
2029
2030     QCOMPARE(header->pos(), changedHeaderPos);
2031     QCOMPARE(header->width(), 50.);
2032     QCOMPARE(header->height(), 20.);
2033     QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2034
2035     item = findItem<QSGItem>(contentItem, "wrapper", 0);
2036     QVERIFY(item);
2037     QCOMPARE(item->pos(), firstDelegatePos);
2038
2039     delete canvas;
2040 }
2041
2042 void tst_QSGGridView::header_data()
2043 {
2044     QTest::addColumn<QSGGridView::Flow>("flow");
2045     QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2046     QTest::addColumn<QPointF>("initialHeaderPos");
2047     QTest::addColumn<QPointF>("changedHeaderPos");
2048     QTest::addColumn<QPointF>("initialContentPos");
2049     QTest::addColumn<QPointF>("changedContentPos");
2050     QTest::addColumn<QPointF>("firstDelegatePos");
2051
2052     // header1 = 100 x 30
2053     // header2 = 100 x 20
2054     // cells = 80 x 60
2055     // view width = 240
2056
2057     // header above items, top left
2058     QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2059         << QPointF(0, -30)
2060         << QPointF(0, -20)
2061         << QPointF(0, -30)
2062         << QPointF(0, -20)
2063         << QPointF(0, 0);
2064
2065     // header above items, top right
2066     QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2067         << QPointF(240 - 100, -30)
2068         << QPointF((240 - 100) + 50, -20)     // 50 = width diff between old and new headers
2069         << QPointF(0, -30)
2070         << QPointF(0, -20)
2071         << QPointF(160, 0);
2072
2073     // header to left of items
2074     QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2075         << QPointF(-100, 0)
2076         << QPointF(-50, 0)
2077         << QPointF(-100, 0)
2078         << QPointF(-50, 0)
2079         << QPointF(0, 0);
2080
2081     // header to right of items
2082     QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2083         << QPointF(0, 0)
2084         << QPointF(0, 0)
2085         << QPointF(-(240 - 100), 0)
2086         << QPointF(-(240 - 50), 0)
2087         << QPointF(-80, 0);
2088 }
2089
2090 void tst_QSGGridView::indexAt()
2091 {
2092     QSGView *canvas = createView();
2093
2094     TestModel model;
2095     model.addItem("Fred", "12345");
2096     model.addItem("John", "2345");
2097     model.addItem("Bob", "54321");
2098     model.addItem("Billy", "22345");
2099     model.addItem("Sam", "2945");
2100     model.addItem("Ben", "04321");
2101     model.addItem("Jim", "0780");
2102
2103     QDeclarativeContext *ctxt = canvas->rootContext();
2104     ctxt->setContextProperty("testModel", &model);
2105     ctxt->setContextProperty("testRightToLeft", QVariant(false));
2106     ctxt->setContextProperty("testTopToBottom", QVariant(false));
2107
2108     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
2109     qApp->processEvents();
2110
2111     QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2112     QTRY_VERIFY(gridview != 0);
2113
2114     QSGItem *contentItem = gridview->contentItem();
2115     QTRY_VERIFY(contentItem != 0);
2116
2117     QTRY_COMPARE(gridview->count(), model.count());
2118
2119     QCOMPARE(gridview->indexAt(0, 0), 0);
2120     QCOMPARE(gridview->indexAt(79, 59), 0);
2121     QCOMPARE(gridview->indexAt(80, 0), 1);
2122     QCOMPARE(gridview->indexAt(0, 60), 3);
2123     QCOMPARE(gridview->indexAt(240, 0), -1);
2124
2125     delete canvas;
2126 }
2127
2128 void tst_QSGGridView::onAdd()
2129 {
2130     QFETCH(int, initialItemCount);
2131     QFETCH(int, itemsToAdd);
2132
2133     const int delegateWidth = 50;
2134     const int delegateHeight = 100;
2135     TestModel model;
2136     QSGView *canvas = createView();
2137     canvas->setFixedSize(5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
2138
2139     // these initial items should not trigger GridView.onAdd
2140     for (int i=0; i<initialItemCount; i++)
2141         model.addItem("dummy value", "dummy value");
2142
2143     QDeclarativeContext *ctxt = canvas->rootContext();
2144     ctxt->setContextProperty("testModel", &model);
2145     ctxt->setContextProperty("delegateWidth", delegateWidth);
2146     ctxt->setContextProperty("delegateHeight", delegateHeight);
2147     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2148
2149     QObject *object = canvas->rootObject();
2150     object->setProperty("width", canvas->width());
2151     object->setProperty("height", canvas->height());
2152     qApp->processEvents();
2153
2154     QList<QPair<QString, QString> > items;
2155     for (int i=0; i<itemsToAdd; i++)
2156         items << qMakePair(QString("value %1").arg(i), QString::number(i));
2157     model.addItems(items);
2158
2159     qApp->processEvents();
2160
2161     QVariantList result = object->property("addedDelegates").toList();
2162     QCOMPARE(result.count(), items.count());
2163     for (int i=0; i<items.count(); i++)
2164         QCOMPARE(result[i].toString(), items[i].first);
2165
2166     delete canvas;
2167 }
2168
2169 void tst_QSGGridView::onAdd_data()
2170 {
2171     QTest::addColumn<int>("initialItemCount");
2172     QTest::addColumn<int>("itemsToAdd");
2173
2174     QTest::newRow("0, add 1") << 0 << 1;
2175     QTest::newRow("0, add 2") << 0 << 2;
2176     QTest::newRow("0, add 10") << 0 << 10;
2177
2178     QTest::newRow("1, add 1") << 1 << 1;
2179     QTest::newRow("1, add 2") << 1 << 2;
2180     QTest::newRow("1, add 10") << 1 << 10;
2181
2182     QTest::newRow("5, add 1") << 5 << 1;
2183     QTest::newRow("5, add 2") << 5 << 2;
2184     QTest::newRow("5, add 10") << 5 << 10;
2185 }
2186
2187 void tst_QSGGridView::onRemove()
2188 {
2189     QFETCH(int, initialItemCount);
2190     QFETCH(int, indexToRemove);
2191     QFETCH(int, removeCount);
2192
2193     const int delegateWidth = 50;
2194     const int delegateHeight = 100;
2195     TestModel model;
2196     for (int i=0; i<initialItemCount; i++)
2197         model.addItem(QString("value %1").arg(i), "dummy value");
2198
2199     QSGView *canvas = createView();
2200     QDeclarativeContext *ctxt = canvas->rootContext();
2201     ctxt->setContextProperty("testModel", &model);
2202     ctxt->setContextProperty("delegateWidth", delegateWidth);
2203     ctxt->setContextProperty("delegateHeight", delegateHeight);
2204     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2205     QObject *object = canvas->rootObject();
2206
2207     qApp->processEvents();
2208
2209     model.removeItems(indexToRemove, removeCount);
2210     qApp->processEvents();
2211     QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2212
2213     delete canvas;
2214 }
2215
2216 void tst_QSGGridView::onRemove_data()
2217 {
2218     QTest::addColumn<int>("initialItemCount");
2219     QTest::addColumn<int>("indexToRemove");
2220     QTest::addColumn<int>("removeCount");
2221
2222     QTest::newRow("remove first") << 1 << 0 << 1;
2223     QTest::newRow("two items, remove first") << 2 << 0 << 1;
2224     QTest::newRow("two items, remove last") << 2 << 1 << 1;
2225     QTest::newRow("two items, remove all") << 2 << 0 << 2;
2226
2227     QTest::newRow("four items, remove first") << 4 << 0 << 1;
2228     QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2229     QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2230     QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2231     QTest::newRow("four items, remove last") << 4 << 3 << 1;
2232     QTest::newRow("four items, remove all") << 4 << 0 << 4;
2233
2234     QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2235     QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2236     QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2237 }
2238
2239 void tst_QSGGridView::testQtQuick11Attributes()
2240 {
2241     QFETCH(QString, code);
2242     QFETCH(QString, warning);
2243     QFETCH(QString, error);
2244
2245     QDeclarativeEngine engine;
2246     QObject *obj;
2247
2248     QDeclarativeComponent valid(&engine);
2249     valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
2250     obj = valid.create();
2251     QVERIFY(obj);
2252     QVERIFY(valid.errorString().isEmpty());
2253     delete obj;
2254
2255     QDeclarativeComponent invalid(&engine);
2256     invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
2257     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2258     obj = invalid.create();
2259     QCOMPARE(invalid.errorString(), error);
2260     delete obj;
2261 }
2262
2263 void tst_QSGGridView::testQtQuick11Attributes_data()
2264 {
2265     QTest::addColumn<QString>("code");
2266     QTest::addColumn<QString>("warning");
2267     QTest::addColumn<QString>("error");
2268
2269     QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2270         << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2271         << "";
2272
2273     QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2274         << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2275         << "";
2276 }
2277
2278 QSGView *tst_QSGGridView::createView()
2279 {
2280     QSGView *canvas = new QSGView(0);
2281     canvas->setFixedSize(240,320);
2282
2283     return canvas;
2284 }
2285
2286 /*
2287    Find an item with the specified objectName.  If index is supplied then the
2288    item must also evaluate the {index} expression equal to index
2289 */
2290 template<typename T>
2291 T *tst_QSGGridView::findItem(QSGItem *parent, const QString &objectName, int index)
2292 {
2293     const QMetaObject &mo = T::staticMetaObject;
2294     //qDebug() << parent->childItems().count() << "children";
2295     for (int i = 0; i < parent->childItems().count(); ++i) {
2296         QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2297         if(!item)
2298             continue;
2299         //qDebug() << "try" << item;
2300         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2301             if (index != -1) {
2302                 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
2303                 if (context) {
2304                     if (context->contextProperty("index").toInt() == index) {
2305                         return static_cast<T*>(item);
2306                     }
2307                 }
2308             } else {
2309                 return static_cast<T*>(item);
2310             }
2311         }
2312         item = findItem<T>(item, objectName, index);
2313         if (item)
2314             return static_cast<T*>(item);
2315     }
2316
2317     return 0;
2318 }
2319
2320 template<typename T>
2321 QList<T*> tst_QSGGridView::findItems(QSGItem *parent, const QString &objectName)
2322 {
2323     QList<T*> items;
2324     const QMetaObject &mo = T::staticMetaObject;
2325     //qDebug() << parent->childItems().count() << "children";
2326     for (int i = 0; i < parent->childItems().count(); ++i) {
2327         QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2328         if(!item)
2329             continue;
2330         //qDebug() << "try" << item;
2331         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2332             items.append(static_cast<T*>(item));
2333             //qDebug() << " found:" << item;
2334         }
2335         items += findItems<T>(item, objectName);
2336     }
2337
2338     return items;
2339 }
2340
2341 void tst_QSGGridView::dumpTree(QSGItem *parent, int depth)
2342 {
2343     static QString padding("                       ");
2344     for (int i = 0; i < parent->childItems().count(); ++i) {
2345         QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2346         if(!item)
2347             continue;
2348         QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
2349         qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
2350         dumpTree(item, depth+1);
2351     }
2352 }
2353
2354
2355 QTEST_MAIN(tst_QSGGridView)
2356
2357 #include "tst_qsggridview.moc"