333398a50e71ea72bbe2c96bb082149e214d1336
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qquickgridview / tst_qquickgridview.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 <QtWidgets/qstringlistmodel.h>
44 #include <QtDeclarative/qquickview.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/qquickitem_p.h>
50 #include <QtDeclarative/private/qlistmodelinterface_p.h>
51 #include <QtDeclarative/private/qquickgridview_p.h>
52 #include <QtDeclarative/private/qquicktext_p.h>
53 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
54 #include "../shared/util.h"
55 #include <QtGui/qguiapplication.h>
56
57 Q_DECLARE_METATYPE(Qt::LayoutDirection)
58 Q_DECLARE_METATYPE(QQuickGridView::Flow)
59
60 class tst_QQuickGridView : public QObject
61 {
62     Q_OBJECT
63 public:
64     tst_QQuickGridView();
65
66 private slots:
67     void initTestCase();
68     void cleanupTestCase();
69     void items();
70     void changed();
71     void inserted();
72     void inserted_more();
73     void inserted_more_data();
74     void removed();
75     void clear();
76     void moved();
77     void moved_data();
78     void multipleChanges();
79     void multipleChanges_data();
80     void swapWithFirstItem();
81     void changeFlow();
82     void currentIndex();
83     void noCurrentIndex();
84     void defaultValues();
85     void properties();
86     void propertyChanges();
87     void componentChanges();
88     void modelChanges();
89     void positionViewAtIndex();
90     void positionViewAtIndex_rightToLeft();
91     void mirroring();
92     void snapping();
93     void resetModel();
94     void enforceRange();
95     void enforceRange_rightToLeft();
96     void QTBUG_8456();
97     void manualHighlight();
98     void footer();
99     void footer_data();
100     void header();
101     void header_data();
102     void resizeViewAndRepaint();
103     void indexAt();
104     void onAdd();
105     void onAdd_data();
106     void onRemove();
107     void onRemove_data();
108     void testQtQuick11Attributes();
109     void testQtQuick11Attributes_data();
110     void columnCount();
111     void margins();
112     void creationContext();
113     void snapToRow_data();
114     void snapToRow();
115
116 private:
117     QQuickView *createView();
118     void flick(QQuickView *canvas, const QPoint &from, const QPoint &to, int duration);
119     template<typename T>
120     T *findItem(QQuickItem *parent, const QString &id, int index=-1);
121     template<typename T>
122     QList<T*> findItems(QQuickItem *parent, const QString &objectName);
123     void dumpTree(QQuickItem *parent, int depth = 0);
124 };
125
126 template<typename T>
127 void tst_qquickgridview_move(int from, int to, int n, T *items)
128 {
129     if (n == 1) {
130         items->move(from, to);
131     } else {
132         T replaced;
133         int i=0;
134         typename T::ConstIterator it=items->begin(); it += from+n;
135         for (; i<to-from; ++i,++it)
136             replaced.append(*it);
137         i=0;
138         it=items->begin(); it += from;
139         for (; i<n; ++i,++it)
140             replaced.append(*it);
141         typename T::ConstIterator f=replaced.begin();
142         typename T::Iterator t=items->begin(); t += from;
143         for (; f != replaced.end(); ++f, ++t)
144             *t = *f;
145     }
146 }
147
148 void tst_QQuickGridView::initTestCase()
149 {
150 }
151
152 void tst_QQuickGridView::cleanupTestCase()
153 {
154
155 }
156
157
158 class TestModel : public QAbstractListModel
159 {
160 public:
161     enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
162
163     TestModel(QObject *parent=0) : QAbstractListModel(parent) {
164         QHash<int, QByteArray> roles;
165         roles[Name] = "name";
166         roles[Number] = "number";
167         setRoleNames(roles);
168     }
169
170     int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
171     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
172         QVariant rv;
173         if (role == Name)
174             rv = list.at(index.row()).first;
175         else if (role == Number)
176             rv = list.at(index.row()).second;
177
178         return rv;
179     }
180
181     int count() const { return rowCount(); }
182     QString name(int index) const { return list.at(index).first; }
183     QString number(int index) const { return list.at(index).second; }
184
185     void addItem(const QString &name, const QString &number) {
186         emit beginInsertRows(QModelIndex(), list.count(), list.count());
187         list.append(QPair<QString,QString>(name, number));
188         emit endInsertRows();
189     }
190
191     void addItems(const QList<QPair<QString, QString> > &items) {
192         emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
193         for (int i=0; i<items.count(); i++)
194             list.append(QPair<QString,QString>(items[i].first, items[i].second));
195         emit endInsertRows();
196     }
197
198     void insertItem(int index, const QString &name, const QString &number) {
199         emit beginInsertRows(QModelIndex(), index, index);
200         list.insert(index, QPair<QString,QString>(name, number));
201         emit endInsertRows();
202     }
203
204     void insertItems(int index, const QList<QPair<QString, QString> > &items) {
205         emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
206         for (int i=0; i<items.count(); i++)
207             list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
208         emit endInsertRows();
209     }
210
211     void removeItem(int index) {
212         emit beginRemoveRows(QModelIndex(), index, index);
213         list.removeAt(index);
214         emit endRemoveRows();
215     }
216
217     void removeItems(int index, int count) {
218         emit beginRemoveRows(QModelIndex(), index, index+count-1);
219         while (count--)
220             list.removeAt(index);
221         emit endRemoveRows();
222     }
223
224     void moveItem(int from, int to) {
225         emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
226         list.move(from, to);
227         emit endMoveRows();
228     }
229
230     void moveItems(int from, int to, int count) {
231         emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
232         tst_qquickgridview_move(from, to, count, &list);
233         emit endMoveRows();
234     }
235
236     void modifyItem(int idx, const QString &name, const QString &number) {
237         list[idx] = QPair<QString,QString>(name, number);
238         emit dataChanged(index(idx,0), index(idx,0));
239     }
240
241     void clear() {
242         int count = list.count();
243         emit beginRemoveRows(QModelIndex(), 0, count-1);
244         list.clear();
245         emit endRemoveRows();
246     }
247
248
249 private:
250     QList<QPair<QString,QString> > list;
251 };
252
253 tst_QQuickGridView::tst_QQuickGridView()
254 {
255 }
256
257 void tst_QQuickGridView::items()
258 {
259     QQuickView *canvas = createView();
260
261     TestModel model;
262     model.addItem("Fred", "12345");
263     model.addItem("John", "2345");
264     model.addItem("Bob", "54321");
265     model.addItem("Billy", "22345");
266     model.addItem("Sam", "2945");
267     model.addItem("Ben", "04321");
268     model.addItem("Jim", "0780");
269
270     QDeclarativeContext *ctxt = canvas->rootContext();
271     ctxt->setContextProperty("testModel", &model);
272     ctxt->setContextProperty("testRightToLeft", QVariant(false));
273     ctxt->setContextProperty("testTopToBottom", QVariant(false));
274
275     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
276     qApp->processEvents();
277
278     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
279     QTRY_VERIFY(gridview != 0);
280
281     QQuickItem *contentItem = gridview->contentItem();
282     QTRY_VERIFY(contentItem != 0);
283
284     QTRY_COMPARE(gridview->count(), model.count());
285     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
286     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
287
288     for (int i = 0; i < model.count(); ++i) {
289         QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
290         QTRY_VERIFY(name != 0);
291         QTRY_COMPARE(name->text(), model.name(i));
292         QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
293         QTRY_VERIFY(number != 0);
294         QTRY_COMPARE(number->text(), model.number(i));
295     }
296
297     // set an empty model and confirm that items are destroyed
298     TestModel model2;
299     ctxt->setContextProperty("testModel", &model2);
300
301     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
302     QTRY_VERIFY(itemCount == 0);
303
304     delete canvas;
305 }
306
307 void tst_QQuickGridView::changed()
308 {
309     QQuickView *canvas = createView();
310
311     TestModel model;
312     model.addItem("Fred", "12345");
313     model.addItem("John", "2345");
314     model.addItem("Bob", "54321");
315     model.addItem("Billy", "22345");
316     model.addItem("Sam", "2945");
317     model.addItem("Ben", "04321");
318     model.addItem("Jim", "0780");
319
320     QDeclarativeContext *ctxt = canvas->rootContext();
321     ctxt->setContextProperty("testModel", &model);
322     ctxt->setContextProperty("testRightToLeft", QVariant(false));
323     ctxt->setContextProperty("testTopToBottom", QVariant(false));
324
325     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
326     qApp->processEvents();
327
328     QQuickFlickable *gridview = findItem<QQuickFlickable>(canvas->rootObject(), "grid");
329     QTRY_VERIFY(gridview != 0);
330
331     QQuickItem *contentItem = gridview->contentItem();
332     QTRY_VERIFY(contentItem != 0);
333
334     model.modifyItem(1, "Will", "9876");
335     QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
336     QTRY_VERIFY(name != 0);
337     QTRY_COMPARE(name->text(), model.name(1));
338     QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
339     QTRY_VERIFY(number != 0);
340     QTRY_COMPARE(number->text(), model.number(1));
341
342     delete canvas;
343 }
344
345 void tst_QQuickGridView::inserted()
346 {
347     QQuickView *canvas = createView();
348     canvas->show();
349
350     TestModel model;
351     model.addItem("Fred", "12345");
352     model.addItem("John", "2345");
353     model.addItem("Bob", "54321");
354
355     QDeclarativeContext *ctxt = canvas->rootContext();
356     ctxt->setContextProperty("testModel", &model);
357     ctxt->setContextProperty("testRightToLeft", QVariant(false));
358     ctxt->setContextProperty("testTopToBottom", QVariant(false));
359
360     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
361     qApp->processEvents();
362
363     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
364     QTRY_VERIFY(gridview != 0);
365
366     QQuickItem *contentItem = gridview->contentItem();
367     QTRY_VERIFY(contentItem != 0);
368
369     model.insertItem(1, "Will", "9876");
370
371     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
372     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
373
374     QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
375     QTRY_VERIFY(name != 0);
376     QTRY_COMPARE(name->text(), model.name(1));
377     QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
378     QTRY_VERIFY(number != 0);
379     QTRY_COMPARE(number->text(), model.number(1));
380
381     // Checks that onAdd is called
382     int added = canvas->rootObject()->property("added").toInt();
383     QTRY_COMPARE(added, 1);
384
385     // Confirm items positioned correctly
386     for (int i = 0; i < model.count(); ++i) {
387         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
388         QTRY_COMPARE(item->x(), (i%3)*80.0);
389         QTRY_COMPARE(item->y(), (i/3)*60.0);
390     }
391
392     model.insertItem(0, "Foo", "1111"); // zero index, and current item
393
394     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
395
396     name = findItem<QQuickText>(contentItem, "textName", 0);
397     QTRY_VERIFY(name != 0);
398     QTRY_COMPARE(name->text(), model.name(0));
399     number = findItem<QQuickText>(contentItem, "textNumber", 0);
400     QTRY_VERIFY(number != 0);
401     QTRY_COMPARE(number->text(), model.number(0));
402
403     QTRY_COMPARE(gridview->currentIndex(), 1);
404
405     // Confirm items positioned correctly
406     for (int i = 0; i < model.count(); ++i) {
407         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
408         QTRY_VERIFY(item->x() == (i%3)*80);
409         QTRY_VERIFY(item->y() == (i/3)*60);
410     }
411
412     for (int i = model.count(); i < 30; ++i)
413         model.insertItem(i, "Hello", QString::number(i));
414
415     gridview->setContentY(120);
416
417     // Insert item outside visible area
418     model.insertItem(1, "Hello", "1324");
419
420     QTRY_VERIFY(gridview->contentY() == 120);
421
422     delete canvas;
423 }
424
425 void tst_QQuickGridView::inserted_more()
426 {
427     QFETCH(qreal, contentY);
428     QFETCH(int, insertIndex);
429     QFETCH(int, insertCount);
430     QFETCH(qreal, itemsOffsetAfterMove);
431
432     QQuickText *name;
433     QQuickText *number;
434     QQuickView *canvas = createView();
435     canvas->show();
436
437     TestModel model;
438     for (int i = 0; i < 30; i++)
439         model.addItem("Item" + QString::number(i), "");
440
441     QDeclarativeContext *ctxt = canvas->rootContext();
442     ctxt->setContextProperty("testModel", &model);
443     ctxt->setContextProperty("testRightToLeft", QVariant(false));
444     ctxt->setContextProperty("testTopToBottom", QVariant(false));
445
446     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
447     qApp->processEvents();
448
449     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
450     QTRY_VERIFY(gridview != 0);
451     QQuickItem *contentItem = gridview->contentItem();
452     QTRY_VERIFY(contentItem != 0);
453
454     gridview->setContentY(contentY);
455
456     QList<QPair<QString, QString> > newData;
457     for (int i=0; i<insertCount; i++)
458         newData << qMakePair(QString("value %1").arg(i), QString::number(i));
459     model.insertItems(insertIndex, newData);
460     QTRY_COMPARE(gridview->property("count").toInt(), model.count());
461
462     // check visibleItems.first() is in correct position
463     QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
464     QVERIFY(item0);
465     QCOMPARE(item0->y(), itemsOffsetAfterMove);
466
467     QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
468     int firstVisibleIndex = -1;
469     for (int i=0; i<items.count(); i++) {
470         if (items[i]->y() >= contentY) {
471             QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
472             firstVisibleIndex = e.evaluate().toInt();
473             break;
474         }
475     }
476     QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
477
478     // Confirm items positioned correctly and indexes correct
479     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
480     for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
481         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
482         QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
483
484         QCOMPARE(item->x(), (i%3)*80.0);
485         QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
486
487         name = findItem<QQuickText>(contentItem, "textName", i);
488         QVERIFY(name != 0);
489         QCOMPARE(name->text(), model.name(i));
490         number = findItem<QQuickText>(contentItem, "textNumber", i);
491         QVERIFY(number != 0);
492         QCOMPARE(number->text(), model.number(i));
493     }
494
495     delete canvas;
496 }
497
498 void tst_QQuickGridView::inserted_more_data()
499 {
500     QTest::addColumn<qreal>("contentY");
501     QTest::addColumn<int>("insertIndex");
502     QTest::addColumn<int>("insertCount");
503     QTest::addColumn<qreal>("itemsOffsetAfterMove");
504
505     QTest::newRow("add 1, before visible items")
506             << 120.0     // show 6-23
507             << 5 << 1
508             << 0.0;   // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
509                       // new 1st visible item is at 0
510
511     QTest::newRow("add 2, before visible items")
512             << 120.0     // show 6-23
513             << 5 << 2
514             << 0.0;   // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
515
516     QTest::newRow("add 3, before visible items")
517             << 120.0     // show 6-23
518             << 5 << 3
519             << -60.0;   // insert 3 (1 row) above first visible in negative pos, first visible does not move
520
521     QTest::newRow("add 5, before visible items")
522             << 120.0     // show 6-23
523             << 5 << 5
524             << -60.0;   // insert 1 row + 2 items above first visible, 1 row added at negative pos,
525                         // grid is rearranged and first visible moves forward within its row
526
527     QTest::newRow("add 6, before visible items")
528             << 120.0     // show 6-23
529             << 5 << 6
530             << -60.0 * 2;   // insert 2 rows above first visible in negative pos, first visible does not move
531
532
533
534    QTest::newRow("add 1, at start of visible, content at start")
535             << 0.0
536             << 0 << 1
537             << 0.0;
538
539     QTest::newRow("add multiple, at start of visible, content at start")
540             << 0.0
541             << 0 << 3
542             << 0.0;
543
544     QTest::newRow("add 1, at start of visible, content not at start")
545             << 120.0     // show 6-23
546             << 6 << 1
547             << 0.0;
548
549     QTest::newRow("add multiple, at start of visible, content not at start")
550             << 120.0     // show 6-23
551             << 6 << 3
552             << 0.0;
553
554
555     QTest::newRow("add 1, at end of visible, content at start")
556             << 0.0
557             << 17 << 1
558             << 0.0;
559
560     QTest::newRow("add 1, at end of visible, content at start")
561             << 0.0
562             << 17 << 3
563             << 0.0;
564
565     QTest::newRow("add 1, at end of visible, content not at start")
566             << 120.0     // show 6-23
567             << 23 << 1
568             << 0.0;
569
570     QTest::newRow("add multiple, at end of visible, content not at start")
571             << 120.0     // show 6-23
572             << 23 << 3
573             << 0.0;
574
575
576     QTest::newRow("add 1, after visible, content at start")
577             << 0.0
578             << 20 << 1
579             << 0.0;
580
581     QTest::newRow("add 1, after visible, content at start")
582             << 0.0
583             << 20 << 3
584             << 0.0;
585
586     QTest::newRow("add 1, after visible, content not at start")
587             << 120.0     // show 6-23
588             << 24 << 1
589             << 0.0;
590
591     QTest::newRow("add multiple, after visible, content not at start")
592             << 120.0     // show 6-23
593             << 24 << 3
594             << 0.0;
595 }
596
597 void tst_QQuickGridView::removed()
598 {
599     QQuickView *canvas = createView();
600     canvas->show();
601
602     TestModel model;
603     for (int i = 0; i < 40; i++)
604         model.addItem("Item" + QString::number(i), "");
605
606     QDeclarativeContext *ctxt = canvas->rootContext();
607     ctxt->setContextProperty("testModel", &model);
608     ctxt->setContextProperty("testRightToLeft", QVariant(false));
609     ctxt->setContextProperty("testTopToBottom", QVariant(false));
610
611     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
612     qApp->processEvents();
613
614     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
615     QTRY_VERIFY(gridview != 0);
616
617     QQuickItem *contentItem = gridview->contentItem();
618     QTRY_VERIFY(contentItem != 0);
619
620     model.removeItem(1);
621     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
622
623     QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
624     QTRY_VERIFY(name != 0);
625     QTRY_COMPARE(name->text(), model.name(1));
626     QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
627     QTRY_VERIFY(number != 0);
628     QTRY_COMPARE(number->text(), model.number(1));
629
630
631     // Checks that onRemove is called
632     QString removed = canvas->rootObject()->property("removed").toString();
633     QTRY_COMPARE(removed, QString("Item1"));
634
635     // Confirm items positioned correctly
636     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
637     for (int i = 0; i < model.count() && i < itemCount; ++i) {
638         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
639         if (!item) qWarning() << "Item" << i << "not found";
640         QTRY_VERIFY(item->x() == (i%3)*80);
641         QTRY_VERIFY(item->y() == (i/3)*60);
642     }
643
644     // Remove first item (which is the current item);
645     model.removeItem(0);
646     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
647
648     name = findItem<QQuickText>(contentItem, "textName", 0);
649     QTRY_VERIFY(name != 0);
650     QTRY_COMPARE(name->text(), model.name(0));
651     number = findItem<QQuickText>(contentItem, "textNumber", 0);
652     QTRY_VERIFY(number != 0);
653     QTRY_COMPARE(number->text(), model.number(0));
654
655
656     // Confirm items positioned correctly
657     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
658     for (int i = 0; i < model.count() && i < itemCount; ++i) {
659         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
660         if (!item) qWarning() << "Item" << i << "not found";
661         QTRY_VERIFY(item->x() == (i%3)*80);
662         QTRY_VERIFY(item->y() == (i/3)*60);
663     }
664
665     // Remove items not visible
666     model.removeItem(25);
667     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
668
669     // Confirm items positioned correctly
670     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
671     for (int i = 0; i < model.count() && i < itemCount; ++i) {
672         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
673         if (!item) qWarning() << "Item" << i << "not found";
674         QTRY_VERIFY(item->x() == (i%3)*80);
675         QTRY_VERIFY(item->y() == (i/3)*60);
676     }
677
678     // Remove items before visible
679     gridview->setContentY(120);
680     gridview->setCurrentIndex(10);
681
682     // Setting currentIndex above shouldn't cause view to scroll
683     QTRY_COMPARE(gridview->contentY(), 120.0);
684
685     model.removeItem(1);
686     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
687
688     // Confirm items positioned correctly
689     for (int i = 6; i < 18; ++i) {
690         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
691         if (!item) qWarning() << "Item" << i << "not found";
692         QTRY_VERIFY(item->x() == (i%3)*80);
693         QTRY_VERIFY(item->y() == (i/3)*60);
694     }
695
696     // Remove currentIndex
697     QQuickItem *oldCurrent = gridview->currentItem();
698     model.removeItem(9);
699     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
700
701     QTRY_COMPARE(gridview->currentIndex(), 9);
702     QTRY_VERIFY(gridview->currentItem() != oldCurrent);
703
704     gridview->setContentY(0);
705     // let transitions settle.
706     QTest::qWait(300);
707
708     // Confirm items positioned correctly
709     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
710     for (int i = 0; i < model.count() && i < itemCount; ++i) {
711         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
712         QTRY_VERIFY(item->x() == (i%3)*80);
713         QTRY_VERIFY(item->y() == (i/3)*60);
714     }
715
716     // remove item outside current view.
717     gridview->setCurrentIndex(32);
718     gridview->setContentY(240);
719
720     model.removeItem(30);
721     QTRY_VERIFY(gridview->currentIndex() == 31);
722
723     // remove current item beyond visible items.
724     gridview->setCurrentIndex(20);
725     gridview->setContentY(0);
726     model.removeItem(20);
727
728     QTRY_COMPARE(gridview->currentIndex(), 20);
729     QTRY_VERIFY(gridview->currentItem() != 0);
730
731     // remove item before current, but visible
732     gridview->setCurrentIndex(8);
733     gridview->setContentY(240);
734     oldCurrent = gridview->currentItem();
735     model.removeItem(6);
736
737     QTRY_COMPARE(gridview->currentIndex(), 7);
738     QTRY_VERIFY(gridview->currentItem() == oldCurrent);
739
740     delete canvas;
741 }
742
743 void tst_QQuickGridView::clear()
744 {
745     QQuickView *canvas = createView();
746
747     TestModel model;
748     for (int i = 0; i < 30; i++)
749         model.addItem("Item" + QString::number(i), "");
750
751     QDeclarativeContext *ctxt = canvas->rootContext();
752     ctxt->setContextProperty("testModel", &model);
753     ctxt->setContextProperty("testRightToLeft", QVariant(false));
754     ctxt->setContextProperty("testTopToBottom", QVariant(false));
755
756     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
757     qApp->processEvents();
758
759     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
760     QVERIFY(gridview != 0);
761
762     QQuickItem *contentItem = gridview->contentItem();
763     QVERIFY(contentItem != 0);
764
765     model.clear();
766
767     QVERIFY(gridview->count() == 0);
768     QVERIFY(gridview->currentItem() == 0);
769     QVERIFY(gridview->contentY() == 0);
770     QVERIFY(gridview->currentIndex() == -1);
771
772     // confirm sanity when adding an item to cleared list
773     model.addItem("New", "1");
774     QTRY_COMPARE(gridview->count(), 1);
775     QVERIFY(gridview->currentItem() != 0);
776     QVERIFY(gridview->currentIndex() == 0);
777
778     delete canvas;
779 }
780
781 void tst_QQuickGridView::moved()
782 {
783     QFETCH(qreal, contentY);
784     QFETCH(int, from);
785     QFETCH(int, to);
786     QFETCH(int, count);
787     QFETCH(qreal, itemsOffsetAfterMove);
788
789     QQuickText *name;
790     QQuickText *number;
791     QQuickView *canvas = createView();
792     canvas->show();
793
794     TestModel model;
795     for (int i = 0; i < 30; i++)
796         model.addItem("Item" + QString::number(i), "");
797
798     QDeclarativeContext *ctxt = canvas->rootContext();
799     ctxt->setContextProperty("testModel", &model);
800     ctxt->setContextProperty("testRightToLeft", QVariant(false));
801     ctxt->setContextProperty("testTopToBottom", QVariant(false));
802
803     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
804     qApp->processEvents();
805
806     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
807     QTRY_VERIFY(gridview != 0);
808
809     QQuickItem *contentItem = gridview->contentItem();
810     QTRY_VERIFY(contentItem != 0);
811
812     QQuickItem *currentItem = gridview->currentItem();
813     QTRY_VERIFY(currentItem != 0);
814
815     gridview->setContentY(contentY);
816     model.moveItems(from, to, count);
817
818     // wait for items to move
819     QTest::qWait(300);
820
821     // Confirm items positioned correctly and indexes correct
822     int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
823     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
824     for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
825         if (i >= firstVisibleIndex + 18)    // index has moved out of view
826             continue;
827         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
828         QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
829
830         QTRY_COMPARE(item->x(), (i%3)*80.0);
831         QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
832
833         name = findItem<QQuickText>(contentItem, "textName", i);
834         QVERIFY(name != 0);
835         QTRY_COMPARE(name->text(), model.name(i));
836         number = findItem<QQuickText>(contentItem, "textNumber", i);
837         QVERIFY(number != 0);
838         QTRY_COMPARE(number->text(), model.number(i));
839
840         // current index should have been updated
841         if (item == currentItem)
842             QTRY_COMPARE(gridview->currentIndex(), i);
843     }
844
845     delete canvas;
846 }
847
848 void tst_QQuickGridView::moved_data()
849 {
850     QTest::addColumn<qreal>("contentY");
851     QTest::addColumn<int>("from");
852     QTest::addColumn<int>("to");
853     QTest::addColumn<int>("count");
854     QTest::addColumn<qreal>("itemsOffsetAfterMove");
855
856     // model starts with 30 items, each 80x60, in area 240x320
857     // 18 items should be visible at a time
858
859     QTest::newRow("move 1 forwards, within visible items")
860             << 0.0
861             << 1 << 8 << 1
862             << 0.0;
863
864     QTest::newRow("move 1 forwards, from non-visible -> visible")
865             << 120.0     // show 6-23
866             << 1 << 23 << 1
867             << 0.0;     // only 1 item was removed from the 1st row, so it doesn't move down
868
869     QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
870             << 120.0     // // show 6-23
871             << 0 << 6 << 1
872             << 0.0;     // only 1 item was removed from the 1st row, so it doesn't move down
873
874     QTest::newRow("move 1 forwards, from visible -> non-visible")
875             << 0.0
876             << 1 << 20 << 1
877             << 0.0;
878
879     QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
880             << 0.0
881             << 0 << 20 << 1
882             << 0.0;
883
884
885     QTest::newRow("move 1 backwards, within visible items")
886             << 0.0
887             << 10 << 5 << 1
888             << 0.0;
889
890     QTest::newRow("move 1 backwards, within visible items (to first index)")
891             << 0.0
892             << 10 << 0 << 1
893             << 0.0;
894
895     QTest::newRow("move 1 backwards, from non-visible -> visible")
896             << 0.0
897             << 28 << 8 << 1
898             << 0.0;
899
900     QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
901             << 0.0
902             << 29 << 14 << 1
903             << 0.0;
904
905     QTest::newRow("move 1 backwards, from visible -> non-visible")
906             << 120.0     // show 6-23
907             << 7 << 1 << 1
908             << 0.0;     // only 1 item moved back, so items shift accordingly and first row doesn't move
909
910     QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
911             << 120.0     // show 6-23
912             << 7 << 0 << 1
913             << 0.0;     // only 1 item moved back, so items shift accordingly and first row doesn't move
914
915
916     QTest::newRow("move multiple forwards, within visible items")
917             << 0.0
918             << 0 << 5 << 3
919             << 0.0;
920
921     QTest::newRow("move multiple forwards, before visible items")
922             << 120.0     // show 6-23
923             << 3 << 4 << 3      // 3, 4, 5 move to after 6
924             << 60.0;      // row of 3,4,5 has moved down
925
926     QTest::newRow("move multiple forwards, from non-visible -> visible")
927             << 120.0     // show 6-23
928             << 1 << 6 << 3
929             << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
930
931     QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
932             << 120.0     // show 6-23
933             << 0 << 6 << 3
934             << 60.0;    // top row moved and shifted to below 3rd row, all items should shift down by 1 row
935
936     QTest::newRow("move multiple forwards, from visible -> non-visible")
937             << 0.0
938             << 1 << 16 << 3
939             << 0.0;
940
941     QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
942             << 0.0
943             << 0 << 16 << 3
944             << 0.0;
945
946
947     QTest::newRow("move multiple backwards, within visible items")
948             << 0.0
949             << 4 << 1 << 3
950             << 0.0;
951
952     QTest::newRow("move multiple backwards, from non-visible -> visible")
953             << 0.0
954             << 20 << 4 << 3
955             << 0.0;
956
957     QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
958             << 0.0
959             << 27 << 10 << 3
960             << 0.0;
961
962     QTest::newRow("move multiple backwards, from visible -> non-visible")
963             << 120.0     // show 6-23
964             << 16 << 1 << 3
965             << -60.0;   // to minimize movement, items are added above visible area, all items move up by 1 row
966
967     QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
968             << 120.0     // show 6-23
969             << 16 << 0 << 3
970             << -60.0;   // 16,17,18 move to above item 0, all items move up by 1 row
971 }
972
973 struct ListChange {
974     enum { Inserted, Removed, Moved, SetCurrent } type;
975     int index;
976     int count;
977     int to;     // Move
978
979     static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
980     static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
981     static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
982     static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
983 };
984 Q_DECLARE_METATYPE(QList<ListChange>)
985
986 void tst_QQuickGridView::multipleChanges()
987 {
988     QFETCH(int, startCount);
989     QFETCH(QList<ListChange>, changes);
990     QFETCH(int, newCount);
991     QFETCH(int, newCurrentIndex);
992
993     QQuickView *canvas = createView();
994     canvas->show();
995
996     TestModel model;
997     for (int i = 0; i < startCount; i++)
998         model.addItem("Item" + QString::number(i), "");
999
1000     QDeclarativeContext *ctxt = canvas->rootContext();
1001     ctxt->setContextProperty("testModel", &model);
1002     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1003     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1004
1005     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1006     qApp->processEvents();
1007
1008     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1009     QTRY_VERIFY(gridview != 0);
1010
1011     for (int i=0; i<changes.count(); i++) {
1012         switch (changes[i].type) {
1013             case ListChange::Inserted:
1014             {
1015                 QList<QPair<QString, QString> > items;
1016                 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1017                     items << qMakePair(QString("new item " + j), QString::number(j));
1018                 model.insertItems(changes[i].index, items);
1019                 break;
1020             }
1021             case ListChange::Removed:
1022                 model.removeItems(changes[i].index, changes[i].count);
1023                 break;
1024             case ListChange::Moved:
1025                 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1026                 break;
1027             case ListChange::SetCurrent:
1028                 gridview->setCurrentIndex(changes[i].index);
1029                 break;
1030         }
1031     }
1032
1033     QTRY_COMPARE(gridview->count(), newCount);
1034     QCOMPARE(gridview->count(), model.count());
1035     QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
1036
1037     QQuickText *name;
1038     QQuickText *number;
1039     QQuickItem *contentItem = gridview->contentItem();
1040     QTRY_VERIFY(contentItem != 0);
1041     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1042     for (int i=0; i < model.count() && i < itemCount; ++i) {
1043         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1044         QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1045         name = findItem<QQuickText>(contentItem, "textName", i);
1046         QVERIFY(name != 0);
1047         QTRY_COMPARE(name->text(), model.name(i));
1048         number = findItem<QQuickText>(contentItem, "textNumber", i);
1049         QVERIFY(number != 0);
1050         QTRY_COMPARE(number->text(), model.number(i));
1051     }
1052
1053     delete canvas;
1054 }
1055
1056 void tst_QQuickGridView::multipleChanges_data()
1057 {
1058     QTest::addColumn<int>("startCount");
1059     QTest::addColumn<QList<ListChange> >("changes");
1060     QTest::addColumn<int>("newCount");
1061     QTest::addColumn<int>("newCurrentIndex");
1062
1063     QList<ListChange> changes;
1064
1065     for (int i=1; i<30; i++)
1066         changes << ListChange::remove(0);
1067     QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1068
1069     changes << ListChange::remove(0);
1070     QTest::newRow("remove all") << 30 << changes << 0 << -1;
1071
1072     changes.clear();
1073     changes << ListChange::setCurrent(29);
1074     for (int i=29; i>0; i--)
1075         changes << ListChange::remove(i);
1076     QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1077
1078     QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1079             << ListChange::remove(0, 1)
1080             << ListChange::insert(0, 1)
1081             ) << 10 << 1;
1082
1083     QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1084             << ListChange::setCurrent(2)
1085             << ListChange::remove(2, 1)
1086             << ListChange::insert(2, 1)
1087             ) << 10 << 3;
1088
1089     QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1090             << ListChange::setCurrent(1)
1091             << ListChange::remove(1, 3)
1092             << ListChange::insert(2, 2)
1093             ) << 9 << 1;
1094
1095     QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1096             << ListChange::setCurrent(2)
1097             << ListChange::remove(1, 3)
1098             << ListChange::move(1, 5, 1)
1099             ) << 7 << 5;
1100
1101     QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1102             << ListChange::setCurrent(5)
1103             << ListChange::remove(4, 3)
1104             << ListChange::move(4, 1, 1)
1105             ) << 7 << 1;
1106
1107
1108     QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1109             << ListChange::insert(0, 2)
1110             << ListChange::insert(0, 4)
1111             << ListChange::insert(0, 6)
1112             ) << 12 << 10;
1113
1114     QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1115             << ListChange::insert(0, 2)
1116             << ListChange::insert(0, 4)
1117             << ListChange::insert(0, 6)
1118             << ListChange::setCurrent(3)
1119             << ListChange::insert(3, 2)
1120             ) << 14 << 5;
1121
1122     QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1123             << ListChange::insert(0, 30)
1124             << ListChange::remove(0, 30)
1125             ) << 0 << -1;
1126
1127     QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1128             << ListChange::insert(1)
1129             << ListChange::setCurrent(1)
1130             << ListChange::remove(1)
1131             ) << 30 << 1;
1132
1133     QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1134             << ListChange::insert(0, 10)
1135             << ListChange::remove(5, 10)
1136             ) << 10 << 5;
1137
1138     QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1139             << ListChange::insert(0, 3)
1140             << ListChange::move(0, 10, 3)
1141             ) << 13 << 0;
1142
1143     QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1144             << ListChange::insert(0, 3)
1145             << ListChange::move(0, 8, 5)
1146             ) << 13 << 11;
1147
1148     QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1149             << ListChange::setCurrent(9)
1150             << ListChange::insert(10, 3)
1151             << ListChange::move(8, 0, 5)
1152             ) << 13 << 1;
1153
1154
1155     QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1156             << ListChange::setCurrent(1)
1157             << ListChange::move(1, 2, 2)
1158             << ListChange::move(2, 1, 2)
1159             ) << 10 << 1;
1160
1161     QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1162             << ListChange::setCurrent(2)
1163             << ListChange::move(1, 2, 3)
1164             << ListChange::move(3, 0, 5)
1165             ) << 10 << 0;
1166
1167     QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1168             << ListChange::setCurrent(5)
1169             << ListChange::move(5, 0, 1)
1170             << ListChange::remove(0)
1171             ) << 9 << 0;
1172
1173     QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1174             << ListChange::setCurrent(5)
1175             << ListChange::move(5, 0, 1)
1176             << ListChange::insert(0)
1177             ) << 11 << 1;
1178
1179     QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1180             << ListChange::setCurrent(1)
1181             << ListChange::move(5, 1, 3)
1182             << ListChange::remove(1, 3)
1183             ) << 7 << 1;
1184
1185     QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1186             << ListChange::setCurrent(5)
1187             << ListChange::move(5, 1, 3)
1188             << ListChange::insert(1, 5)
1189             ) << 15 << 6;
1190
1191     QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1192             << ListChange::setCurrent(3)
1193             << ListChange::move(0, 1, 2)
1194             << ListChange::insert(3, 5)
1195             ) << 15 << 8;
1196
1197
1198     QTest::newRow("clear current") << 0 << (QList<ListChange>()
1199             << ListChange::insert(0, 5)
1200             << ListChange::setCurrent(-1)
1201             << ListChange::remove(0, 5)
1202             << ListChange::insert(0, 5)
1203             ) << 5 << -1;
1204 }
1205
1206
1207 void tst_QQuickGridView::swapWithFirstItem()
1208 {
1209     // QTBUG_9697
1210     QQuickView *canvas = createView();
1211     canvas->show();
1212
1213     TestModel model;
1214     for (int i = 0; i < 30; i++)
1215         model.addItem("Item" + QString::number(i), "");
1216
1217     QDeclarativeContext *ctxt = canvas->rootContext();
1218     ctxt->setContextProperty("testModel", &model);
1219     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1220     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1221
1222     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1223     qApp->processEvents();
1224
1225     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1226     QTRY_VERIFY(gridview != 0);
1227
1228     // ensure content position is stable
1229     gridview->setContentY(0);
1230     model.moveItem(10, 0);
1231     QTRY_VERIFY(gridview->contentY() == 0);
1232
1233     delete canvas;
1234 }
1235
1236 void tst_QQuickGridView::currentIndex()
1237 {
1238     TestModel model;
1239     for (int i = 0; i < 60; i++)
1240         model.addItem("Item" + QString::number(i), QString::number(i));
1241
1242     QQuickView *canvas = new QQuickView(0);
1243     canvas->setGeometry(0,0,240,320);
1244     canvas->show();
1245
1246     QDeclarativeContext *ctxt = canvas->rootContext();
1247     ctxt->setContextProperty("testModel", &model);
1248
1249     QString filename(TESTDATA("gridview-initCurrent.qml"));
1250     canvas->setSource(QUrl::fromLocalFile(filename));
1251
1252     qApp->processEvents();
1253
1254     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1255     QVERIFY(gridview != 0);
1256
1257     QQuickItem *contentItem = gridview->contentItem();
1258     QVERIFY(contentItem != 0);
1259
1260     // current item should be third item
1261     QCOMPARE(gridview->currentIndex(), 35);
1262     QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35));
1263     QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1264     QCOMPARE(gridview->contentY(), 400.0);
1265
1266     gridview->moveCurrentIndexRight();
1267     QCOMPARE(gridview->currentIndex(), 36);
1268     gridview->moveCurrentIndexDown();
1269     QCOMPARE(gridview->currentIndex(), 39);
1270     gridview->moveCurrentIndexUp();
1271     QCOMPARE(gridview->currentIndex(), 36);
1272     gridview->moveCurrentIndexLeft();
1273     QCOMPARE(gridview->currentIndex(), 35);
1274
1275     // no wrap
1276     gridview->setCurrentIndex(0);
1277     QCOMPARE(gridview->currentIndex(), 0);
1278     // confirm that the velocity is updated
1279     QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1280
1281     gridview->moveCurrentIndexUp();
1282     QCOMPARE(gridview->currentIndex(), 0);
1283
1284     gridview->moveCurrentIndexLeft();
1285     QCOMPARE(gridview->currentIndex(), 0);
1286
1287     gridview->setCurrentIndex(model.count()-1);
1288     QCOMPARE(gridview->currentIndex(), model.count()-1);
1289
1290     gridview->moveCurrentIndexRight();
1291     QCOMPARE(gridview->currentIndex(), model.count()-1);
1292
1293     gridview->moveCurrentIndexDown();
1294     QCOMPARE(gridview->currentIndex(), model.count()-1);
1295
1296     // with wrap
1297     gridview->setWrapEnabled(true);
1298
1299     gridview->setCurrentIndex(0);
1300     QCOMPARE(gridview->currentIndex(), 0);
1301
1302     gridview->moveCurrentIndexLeft();
1303     QCOMPARE(gridview->currentIndex(), model.count()-1);
1304
1305     qApp->processEvents();
1306     QTRY_COMPARE(gridview->contentY(), 880.0);
1307
1308     gridview->moveCurrentIndexRight();
1309     QCOMPARE(gridview->currentIndex(), 0);
1310
1311     QTRY_COMPARE(gridview->contentY(), 0.0);
1312
1313
1314     // footer should become visible if it is out of view, and then current index moves to the first row
1315     canvas->rootObject()->setProperty("showFooter", true);
1316     QTRY_VERIFY(gridview->footerItem());
1317     gridview->setCurrentIndex(model.count()-3);
1318     QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1319     gridview->setCurrentIndex(model.count()-2);
1320     QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1321     canvas->rootObject()->setProperty("showFooter", false);
1322
1323     // header should become visible if it is out of view, and then current index moves to the last row
1324     canvas->rootObject()->setProperty("showHeader", true);
1325     QTRY_VERIFY(gridview->headerItem());
1326     gridview->setCurrentIndex(3);
1327     QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1328     gridview->setCurrentIndex(1);
1329     QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1330     canvas->rootObject()->setProperty("showHeader", false);
1331
1332
1333     // Test keys
1334     canvas->requestActivateWindow();
1335     QTest::qWaitForWindowShown(canvas);
1336     QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1337
1338     gridview->setCurrentIndex(0);
1339
1340     QTest::keyClick(canvas, Qt::Key_Down);
1341     QCOMPARE(gridview->currentIndex(), 3);
1342
1343     QTest::keyClick(canvas, Qt::Key_Up);
1344     QCOMPARE(gridview->currentIndex(), 0);
1345
1346     // hold down Key_Down
1347     for (int i=0; i<(model.count() / 3) - 1; i++) {
1348         QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1349         QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1350     }
1351     QTest::keyRelease(canvas, Qt::Key_Down);
1352     QTRY_COMPARE(gridview->currentIndex(), 57);
1353     QTRY_COMPARE(gridview->contentY(), 880.0);
1354
1355     // hold down Key_Up
1356     for (int i=(model.count() / 3) - 1; i > 0; i--) {
1357         QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1358         QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1359     }
1360     QTest::keyRelease(canvas, Qt::Key_Up);
1361     QTRY_COMPARE(gridview->currentIndex(), 0);
1362     QTRY_COMPARE(gridview->contentY(), 0.0);
1363
1364
1365     gridview->setFlow(QQuickGridView::TopToBottom);
1366
1367     canvas->requestActivateWindow();
1368     QTest::qWaitForWindowShown(canvas);
1369     QVERIFY(qGuiApp->focusWindow() == canvas);
1370     qApp->processEvents();
1371
1372     QTest::keyClick(canvas, Qt::Key_Right);
1373     QCOMPARE(gridview->currentIndex(), 5);
1374
1375     QTest::keyClick(canvas, Qt::Key_Left);
1376     QCOMPARE(gridview->currentIndex(), 0);
1377
1378     QTest::keyClick(canvas, Qt::Key_Down);
1379     QCOMPARE(gridview->currentIndex(), 1);
1380
1381     QTest::keyClick(canvas, Qt::Key_Up);
1382     QCOMPARE(gridview->currentIndex(), 0);
1383
1384     // hold down Key_Right
1385     for (int i=0; i<(model.count() / 5) - 1; i++) {
1386         QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1387         QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1388     }
1389
1390     QTest::keyRelease(canvas, Qt::Key_Right);
1391     QTRY_COMPARE(gridview->currentIndex(), 55);
1392     QTRY_COMPARE(gridview->contentX(), 720.0);
1393
1394     // hold down Key_Left
1395     for (int i=(model.count() / 5) - 1; i > 0; i--) {
1396         QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1397         QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1398     }
1399     QTest::keyRelease(canvas, Qt::Key_Left);
1400     QTRY_COMPARE(gridview->currentIndex(), 0);
1401     QTRY_COMPARE(gridview->contentX(), 0.0);
1402
1403
1404     // turn off auto highlight
1405     gridview->setHighlightFollowsCurrentItem(false);
1406     QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1407     QVERIFY(gridview->highlightItem());
1408     qreal hlPosX = gridview->highlightItem()->x();
1409     qreal hlPosY = gridview->highlightItem()->y();
1410
1411     gridview->setCurrentIndex(5);
1412     QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1413     QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1414
1415     // insert item before currentIndex
1416     gridview->setCurrentIndex(28);
1417     model.insertItem(0, "Foo", "1111");
1418     QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1419
1420     // check removing highlight by setting currentIndex to -1;
1421     gridview->setCurrentIndex(-1);
1422
1423     QCOMPARE(gridview->currentIndex(), -1);
1424     QVERIFY(!gridview->highlightItem());
1425     QVERIFY(!gridview->currentItem());
1426
1427     gridview->setHighlightFollowsCurrentItem(true);
1428
1429     gridview->setFlow(QQuickGridView::LeftToRight);
1430     gridview->setLayoutDirection(Qt::RightToLeft);
1431
1432     canvas->requestActivateWindow();
1433     QTest::qWaitForWindowShown(canvas);
1434     QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1435     qApp->processEvents();
1436
1437     gridview->setCurrentIndex(35);
1438
1439     QTest::keyClick(canvas, Qt::Key_Right);
1440     QCOMPARE(gridview->currentIndex(), 34);
1441
1442     QTest::keyClick(canvas, Qt::Key_Down);
1443     QCOMPARE(gridview->currentIndex(), 37);
1444
1445     QTest::keyClick(canvas, Qt::Key_Up);
1446     QCOMPARE(gridview->currentIndex(), 34);
1447
1448     QTest::keyClick(canvas, Qt::Key_Left);
1449     QCOMPARE(gridview->currentIndex(), 35);
1450
1451
1452     // turn off auto highlight
1453     gridview->setHighlightFollowsCurrentItem(false);
1454     QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1455     QVERIFY(gridview->highlightItem());
1456     hlPosX = gridview->highlightItem()->x();
1457     hlPosY = gridview->highlightItem()->y();
1458
1459     gridview->setCurrentIndex(5);
1460     QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1461     QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1462
1463     // insert item before currentIndex
1464     gridview->setCurrentIndex(28);
1465     model.insertItem(0, "Foo", "1111");
1466     QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1467
1468     // check removing highlight by setting currentIndex to -1;
1469     gridview->setCurrentIndex(-1);
1470
1471     QCOMPARE(gridview->currentIndex(), -1);
1472     QVERIFY(!gridview->highlightItem());
1473     QVERIFY(!gridview->currentItem());
1474
1475     delete canvas;
1476 }
1477
1478 void tst_QQuickGridView::noCurrentIndex()
1479 {
1480     TestModel model;
1481     for (int i = 0; i < 60; i++)
1482         model.addItem("Item" + QString::number(i), QString::number(i));
1483
1484     QQuickView *canvas = new QQuickView(0);
1485     canvas->setGeometry(0,0,240,320);
1486
1487     QDeclarativeContext *ctxt = canvas->rootContext();
1488     ctxt->setContextProperty("testModel", &model);
1489
1490     QString filename(TESTDATA("gridview-noCurrent.qml"));
1491     canvas->setSource(QUrl::fromLocalFile(filename));
1492
1493     qApp->processEvents();
1494
1495     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1496     QVERIFY(gridview != 0);
1497
1498     QQuickItem *contentItem = gridview->contentItem();
1499     QVERIFY(contentItem != 0);
1500
1501     // current index should be -1
1502     QCOMPARE(gridview->currentIndex(), -1);
1503     QVERIFY(!gridview->currentItem());
1504     QVERIFY(!gridview->highlightItem());
1505     QCOMPARE(gridview->contentY(), 0.0);
1506
1507     gridview->setCurrentIndex(5);
1508     QCOMPARE(gridview->currentIndex(), 5);
1509     QVERIFY(gridview->currentItem());
1510     QVERIFY(gridview->highlightItem());
1511
1512     delete canvas;
1513 }
1514
1515 void tst_QQuickGridView::changeFlow()
1516 {
1517     QQuickView *canvas = createView();
1518
1519     TestModel model;
1520     for (int i = 0; i < 30; i++)
1521         model.addItem("Item" + QString::number(i), QString::number(i));
1522
1523     QDeclarativeContext *ctxt = canvas->rootContext();
1524     ctxt->setContextProperty("testModel", &model);
1525     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1526     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1527
1528     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1529     qApp->processEvents();
1530
1531     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1532     QTRY_VERIFY(gridview != 0);
1533
1534     QQuickItem *contentItem = gridview->contentItem();
1535     QTRY_VERIFY(contentItem != 0);
1536
1537     // Confirm items positioned correctly and indexes correct
1538     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1539     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1540         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1541         if (!item) qWarning() << "Item" << i << "not found";
1542         QTRY_VERIFY(item);
1543         QTRY_COMPARE(item->x(), qreal((i%3)*80));
1544         QTRY_COMPARE(item->y(), qreal((i/3)*60));
1545         QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1546         QTRY_VERIFY(name != 0);
1547         QTRY_COMPARE(name->text(), model.name(i));
1548         QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1549         QTRY_VERIFY(number != 0);
1550         QTRY_COMPARE(number->text(), model.number(i));
1551     }
1552
1553     ctxt->setContextProperty("testTopToBottom", QVariant(true));
1554
1555     // Confirm items positioned correctly and indexes correct
1556     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1557     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1558         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1559         if (!item) qWarning() << "Item" << i << "not found";
1560         QTRY_VERIFY(item);
1561         QTRY_COMPARE(item->x(), qreal((i/5)*80));
1562         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1563         QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1564         QTRY_VERIFY(name != 0);
1565         QTRY_COMPARE(name->text(), model.name(i));
1566         QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1567         QTRY_VERIFY(number != 0);
1568         QTRY_COMPARE(number->text(), model.number(i));
1569     }
1570
1571     ctxt->setContextProperty("testRightToLeft", QVariant(true));
1572
1573     // Confirm items positioned correctly and indexes correct
1574     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1575     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1576         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1577         if (!item) qWarning() << "Item" << i << "not found";
1578         QTRY_VERIFY(item);
1579         QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1580         QTRY_COMPARE(item->y(), qreal((i%5)*60));
1581         QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1582         QTRY_VERIFY(name != 0);
1583         QTRY_COMPARE(name->text(), model.name(i));
1584         QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1585         QTRY_VERIFY(number != 0);
1586         QTRY_COMPARE(number->text(), model.number(i));
1587     }
1588     gridview->setContentX(100);
1589     QTRY_COMPARE(gridview->contentX(), 100.);
1590     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1591     QTRY_COMPARE(gridview->contentX(), 0.);
1592
1593     // Confirm items positioned correctly and indexes correct
1594     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1595     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1596         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1597         if (!item) qWarning() << "Item" << i << "not found";
1598         QTRY_VERIFY(item);
1599         QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1600         QTRY_COMPARE(item->y(), qreal((i/3)*60));
1601         QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1602         QTRY_VERIFY(name != 0);
1603         QTRY_COMPARE(name->text(), model.name(i));
1604         QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1605         QTRY_VERIFY(number != 0);
1606         QTRY_COMPARE(number->text(), model.number(i));
1607     }
1608
1609     delete canvas;
1610 }
1611
1612 void tst_QQuickGridView::defaultValues()
1613 {
1614     QDeclarativeEngine engine;
1615     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview3.qml")));
1616     QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
1617
1618     QTRY_VERIFY(obj != 0);
1619     QTRY_VERIFY(obj->model() == QVariant());
1620     QTRY_VERIFY(obj->delegate() == 0);
1621     QTRY_COMPARE(obj->currentIndex(), -1);
1622     QTRY_VERIFY(obj->currentItem() == 0);
1623     QTRY_COMPARE(obj->count(), 0);
1624     QTRY_VERIFY(obj->highlight() == 0);
1625     QTRY_VERIFY(obj->highlightItem() == 0);
1626     QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1627     QTRY_VERIFY(obj->flow() == 0);
1628     QTRY_COMPARE(obj->isWrapEnabled(), false);
1629     QTRY_COMPARE(obj->cacheBuffer(), 0);
1630     QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
1631     QTRY_COMPARE(obj->cellHeight(), qreal(100));
1632     delete obj;
1633 }
1634
1635 void tst_QQuickGridView::properties()
1636 {
1637     QDeclarativeEngine engine;
1638     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview2.qml")));
1639     QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
1640
1641     QTRY_VERIFY(obj != 0);
1642     QTRY_VERIFY(obj->model() != QVariant());
1643     QTRY_VERIFY(obj->delegate() != 0);
1644     QTRY_COMPARE(obj->currentIndex(), 0);
1645     QTRY_VERIFY(obj->currentItem() != 0);
1646     QTRY_COMPARE(obj->count(), 4);
1647     QTRY_VERIFY(obj->highlight() != 0);
1648     QTRY_VERIFY(obj->highlightItem() != 0);
1649     QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1650     QTRY_VERIFY(obj->flow() == 0);
1651     QTRY_COMPARE(obj->isWrapEnabled(), true);
1652     QTRY_COMPARE(obj->cacheBuffer(), 200);
1653     QTRY_COMPARE(obj->cellWidth(), qreal(100));
1654     QTRY_COMPARE(obj->cellHeight(), qreal(100));
1655     delete obj;
1656 }
1657
1658 void tst_QQuickGridView::propertyChanges()
1659 {
1660     QQuickView *canvas = createView();
1661     QTRY_VERIFY(canvas);
1662     canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1663
1664     QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
1665     QTRY_VERIFY(gridView);
1666
1667     QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1668     QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1669     QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1670     QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1671
1672     QTRY_COMPARE(gridView->isWrapEnabled(), true);
1673     QTRY_COMPARE(gridView->cacheBuffer(), 10);
1674     QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
1675
1676     gridView->setWrapEnabled(false);
1677     gridView->setCacheBuffer(3);
1678     gridView->setFlow(QQuickGridView::TopToBottom);
1679
1680     QTRY_COMPARE(gridView->isWrapEnabled(), false);
1681     QTRY_COMPARE(gridView->cacheBuffer(), 3);
1682     QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
1683
1684     QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1685     QTRY_COMPARE(cacheBufferSpy.count(),1);
1686     QTRY_COMPARE(flowSpy.count(),1);
1687
1688     gridView->setWrapEnabled(false);
1689     gridView->setCacheBuffer(3);
1690     gridView->setFlow(QQuickGridView::TopToBottom);
1691
1692     QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1693     QTRY_COMPARE(cacheBufferSpy.count(),1);
1694     QTRY_COMPARE(flowSpy.count(),1);
1695
1696     gridView->setFlow(QQuickGridView::LeftToRight);
1697     QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
1698
1699     gridView->setWrapEnabled(true);
1700     gridView->setCacheBuffer(5);
1701     gridView->setLayoutDirection(Qt::RightToLeft);
1702
1703     QTRY_COMPARE(gridView->isWrapEnabled(), true);
1704     QTRY_COMPARE(gridView->cacheBuffer(), 5);
1705     QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1706
1707     QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1708     QTRY_COMPARE(cacheBufferSpy.count(),2);
1709     QTRY_COMPARE(layoutSpy.count(),1);
1710     QTRY_COMPARE(flowSpy.count(),2);
1711
1712     gridView->setWrapEnabled(true);
1713     gridView->setCacheBuffer(5);
1714     gridView->setLayoutDirection(Qt::RightToLeft);
1715
1716     QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1717     QTRY_COMPARE(cacheBufferSpy.count(),2);
1718     QTRY_COMPARE(layoutSpy.count(),1);
1719     QTRY_COMPARE(flowSpy.count(),2);
1720
1721     gridView->setFlow(QQuickGridView::TopToBottom);
1722     QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
1723     QTRY_COMPARE(flowSpy.count(),3);
1724
1725     gridView->setFlow(QQuickGridView::TopToBottom);
1726     QTRY_COMPARE(flowSpy.count(),3);
1727
1728     delete canvas;
1729 }
1730
1731 void tst_QQuickGridView::componentChanges()
1732 {
1733     QQuickView *canvas = createView();
1734     QTRY_VERIFY(canvas);
1735     canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1736
1737     QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
1738     QTRY_VERIFY(gridView);
1739
1740     QDeclarativeComponent component(canvas->engine());
1741     component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1742
1743     QDeclarativeComponent delegateComponent(canvas->engine());
1744     delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1745
1746     QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1747     QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1748     QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1749     QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1750
1751     gridView->setHighlight(&component);
1752     gridView->setDelegate(&delegateComponent);
1753     gridView->setHeader(&component);
1754     gridView->setFooter(&component);
1755
1756     QTRY_COMPARE(gridView->highlight(), &component);
1757     QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1758     QTRY_COMPARE(gridView->header(), &component);
1759     QTRY_COMPARE(gridView->footer(), &component);
1760
1761     QTRY_COMPARE(highlightSpy.count(),1);
1762     QTRY_COMPARE(delegateSpy.count(),1);
1763     QTRY_COMPARE(headerSpy.count(),1);
1764     QTRY_COMPARE(footerSpy.count(),1);
1765
1766     gridView->setHighlight(&component);
1767     gridView->setDelegate(&delegateComponent);
1768     gridView->setHeader(&component);
1769     gridView->setFooter(&component);
1770
1771     QTRY_COMPARE(highlightSpy.count(),1);
1772     QTRY_COMPARE(delegateSpy.count(),1);
1773     QTRY_COMPARE(headerSpy.count(),1);
1774     QTRY_COMPARE(footerSpy.count(),1);
1775
1776     delete canvas;
1777 }
1778
1779 void tst_QQuickGridView::modelChanges()
1780 {
1781     QQuickView *canvas = createView();
1782     QTRY_VERIFY(canvas);
1783     canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1784
1785     QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
1786     QTRY_VERIFY(gridView);
1787
1788     QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1789     QTRY_VERIFY(alternateModel);
1790     QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1791     QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1792
1793     gridView->setModel(modelVariant);
1794     QTRY_COMPARE(gridView->model(), modelVariant);
1795     QTRY_COMPARE(modelSpy.count(),1);
1796
1797     gridView->setModel(modelVariant);
1798     QTRY_COMPARE(modelSpy.count(),1);
1799
1800     gridView->setModel(QVariant());
1801     QTRY_COMPARE(modelSpy.count(),2);
1802     delete canvas;
1803 }
1804
1805 void tst_QQuickGridView::positionViewAtIndex()
1806 {
1807     QQuickView *canvas = createView();
1808
1809     TestModel model;
1810     for (int i = 0; i < 40; i++)
1811         model.addItem("Item" + QString::number(i), "");
1812
1813     QDeclarativeContext *ctxt = canvas->rootContext();
1814     ctxt->setContextProperty("testModel", &model);
1815     ctxt->setContextProperty("testRightToLeft", QVariant(false));
1816     ctxt->setContextProperty("testTopToBottom", QVariant(false));
1817
1818     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1819     qApp->processEvents();
1820
1821     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1822     QTRY_VERIFY(gridview != 0);
1823
1824     QQuickItem *contentItem = gridview->contentItem();
1825     QTRY_VERIFY(contentItem != 0);
1826
1827     // Confirm items positioned correctly
1828     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1829     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1830         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1831         if (!item) qWarning() << "Item" << i << "not found";
1832         QTRY_VERIFY(item);
1833         QTRY_COMPARE(item->x(), (i%3)*80.);
1834         QTRY_COMPARE(item->y(), (i/3)*60.);
1835     }
1836
1837     // Position on a currently visible item
1838     gridview->positionViewAtIndex(4, QQuickGridView::Beginning);
1839     QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1840     QTRY_COMPARE(gridview->contentY(), 60.);
1841
1842     // Confirm items positioned correctly
1843     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1844     for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1845         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1846         if (!item) qWarning() << "Item" << i << "not found";
1847         QTRY_VERIFY(item);
1848         QTRY_COMPARE(item->x(), (i%3)*80.);
1849         QTRY_COMPARE(item->y(), (i/3)*60.);
1850     }
1851
1852     // Position on an item beyond the visible items
1853     gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
1854     QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1855     QTRY_COMPARE(gridview->contentY(), 420.);
1856
1857     // Confirm items positioned correctly
1858     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1859     for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1860         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1861         if (!item) qWarning() << "Item" << i << "not found";
1862         QTRY_VERIFY(item);
1863         QTRY_COMPARE(item->x(), (i%3)*80.);
1864         QTRY_COMPARE(item->y(), (i/3)*60.);
1865     }
1866
1867     // Position on an item that would leave empty space if positioned at the top
1868     gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
1869     QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1870     QTRY_COMPARE(gridview->contentY(), 520.);
1871
1872     // Confirm items positioned correctly
1873     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1874     for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1875         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1876         if (!item) qWarning() << "Item" << i << "not found";
1877         QTRY_VERIFY(item);
1878         QTRY_COMPARE(item->x(), (i%3)*80.);
1879         QTRY_COMPARE(item->y(), (i/3)*60.);
1880     }
1881
1882     // Position at the beginning again
1883     gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
1884     QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1885     QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1886     QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1887     QTRY_COMPARE(gridview->contentY(), 0.);
1888
1889     // Confirm items positioned correctly
1890     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1891     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1892         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1893         if (!item) qWarning() << "Item" << i << "not found";
1894         QTRY_VERIFY(item);
1895         QTRY_COMPARE(item->x(), (i%3)*80.);
1896         QTRY_COMPARE(item->y(), (i/3)*60.);
1897     }
1898
1899     // Position at End
1900     gridview->positionViewAtIndex(30, QQuickGridView::End);
1901     QTRY_COMPARE(gridview->contentY(), 340.);
1902
1903     // Position in Center
1904     gridview->positionViewAtIndex(15, QQuickGridView::Center);
1905     QTRY_COMPARE(gridview->contentY(), 170.);
1906
1907     // Ensure at least partially visible
1908     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1909     QTRY_COMPARE(gridview->contentY(), 170.);
1910
1911     gridview->setContentY(302);
1912     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1913     QTRY_COMPARE(gridview->contentY(), 302.);
1914
1915     gridview->setContentY(360);
1916     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1917     QTRY_COMPARE(gridview->contentY(), 300.);
1918
1919     gridview->setContentY(60);
1920     gridview->positionViewAtIndex(20, QQuickGridView::Visible);
1921     QTRY_COMPARE(gridview->contentY(), 60.);
1922
1923     gridview->setContentY(20);
1924     gridview->positionViewAtIndex(20, QQuickGridView::Visible);
1925     QTRY_COMPARE(gridview->contentY(), 100.);
1926
1927     // Ensure completely visible
1928     gridview->setContentY(120);
1929     gridview->positionViewAtIndex(20, QQuickGridView::Contain);
1930     QTRY_COMPARE(gridview->contentY(), 120.);
1931
1932     gridview->setContentY(302);
1933     gridview->positionViewAtIndex(15, QQuickGridView::Contain);
1934     QTRY_COMPARE(gridview->contentY(), 300.);
1935
1936     gridview->setContentY(60);
1937     gridview->positionViewAtIndex(20, QQuickGridView::Contain);
1938     QTRY_COMPARE(gridview->contentY(), 100.);
1939
1940     // Test for Top To Bottom layout
1941     ctxt->setContextProperty("testTopToBottom", QVariant(true));
1942
1943     // Confirm items positioned correctly
1944     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1945     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1946         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1947         if (!item) qWarning() << "Item" << i << "not found";
1948         QTRY_VERIFY(item);
1949         QTRY_COMPARE(item->x(), (i/5)*80.);
1950         QTRY_COMPARE(item->y(), (i%5)*60.);
1951     }
1952
1953     // Position at End
1954     gridview->positionViewAtIndex(30, QQuickGridView::End);
1955     QTRY_COMPARE(gridview->contentX(), 320.);
1956     QTRY_COMPARE(gridview->contentY(), 0.);
1957
1958     // Position in Center
1959     gridview->positionViewAtIndex(15, QQuickGridView::Center);
1960     QTRY_COMPARE(gridview->contentX(), 160.);
1961
1962     // Ensure at least partially visible
1963     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1964     QTRY_COMPARE(gridview->contentX(), 160.);
1965
1966     gridview->setContentX(170);
1967     gridview->positionViewAtIndex(25, QQuickGridView::Visible);
1968     QTRY_COMPARE(gridview->contentX(), 170.);
1969
1970     gridview->positionViewAtIndex(30, QQuickGridView::Visible);
1971     QTRY_COMPARE(gridview->contentX(), 320.);
1972
1973     gridview->setContentX(170);
1974     gridview->positionViewAtIndex(25, QQuickGridView::Contain);
1975     QTRY_COMPARE(gridview->contentX(), 240.);
1976
1977     // positionViewAtBeginning
1978     gridview->positionViewAtBeginning();
1979     QTRY_COMPARE(gridview->contentX(), 0.);
1980
1981     gridview->setContentX(80);
1982     canvas->rootObject()->setProperty("showHeader", true);
1983     gridview->positionViewAtBeginning();
1984     QTRY_COMPARE(gridview->contentX(), -30.);
1985
1986     // positionViewAtEnd
1987     gridview->positionViewAtEnd();
1988     QTRY_COMPARE(gridview->contentX(), 400.);   // 8*80 - 240   (8 columns)
1989
1990     gridview->setContentX(80);
1991     canvas->rootObject()->setProperty("showFooter", true);
1992     gridview->positionViewAtEnd();
1993     QTRY_COMPARE(gridview->contentX(), 430.);
1994
1995     // set current item to outside visible view, position at beginning
1996     // and ensure highlight moves to current item
1997     gridview->setCurrentIndex(6);
1998     gridview->positionViewAtBeginning();
1999     QTRY_COMPARE(gridview->contentX(), -30.);
2000     QVERIFY(gridview->highlightItem());
2001     QCOMPARE(gridview->highlightItem()->x(), 80.);
2002
2003     delete canvas;
2004 }
2005
2006 void tst_QQuickGridView::snapping()
2007 {
2008     QQuickView *canvas = createView();
2009
2010     TestModel model;
2011     for (int i = 0; i < 40; i++)
2012         model.addItem("Item" + QString::number(i), "");
2013
2014     QDeclarativeContext *ctxt = canvas->rootContext();
2015     ctxt->setContextProperty("testModel", &model);
2016     ctxt->setContextProperty("testTopToBottom", QVariant(false));
2017     ctxt->setContextProperty("testRightToLeft", QVariant(false));
2018
2019     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2020     qApp->processEvents();
2021
2022     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2023     QTRY_VERIFY(gridview != 0);
2024
2025     gridview->setHeight(220);
2026     QCOMPARE(gridview->height(), 220.);
2027
2028     gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2029     QCOMPARE(gridview->contentY(), 80.);
2030
2031     gridview->setContentY(0);
2032     QCOMPARE(gridview->contentY(), 0.);
2033
2034     gridview->setSnapMode(QQuickGridView::SnapToRow);
2035     QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow);
2036
2037     gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2038     QCOMPARE(gridview->contentY(), 60.);
2039
2040     gridview->positionViewAtIndex(15, QQuickGridView::End);
2041     QCOMPARE(gridview->contentY(), 120.);
2042
2043     delete canvas;
2044
2045 }
2046
2047 void tst_QQuickGridView::mirroring()
2048 {
2049     QQuickView *canvasA = createView();
2050     canvasA->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2051     QQuickGridView *gridviewA = findItem<QQuickGridView>(canvasA->rootObject(), "view");
2052     QTRY_VERIFY(gridviewA != 0);
2053
2054     QQuickView *canvasB = createView();
2055     canvasB->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2056     QQuickGridView *gridviewB = findItem<QQuickGridView>(canvasB->rootObject(), "view");
2057     QTRY_VERIFY(gridviewA != 0);
2058     qApp->processEvents();
2059
2060     QList<QString> objectNames;
2061     objectNames << "item1" << "item2"; // << "item3"
2062
2063     gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2064     gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2065     QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2066
2067     // LTR != RTL
2068     foreach (const QString objectName, objectNames)
2069         QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2070
2071     gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2072     gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2073
2074     // LTR == LTR
2075     foreach (const QString objectName, objectNames)
2076         QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2077
2078     QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2079     QQuickItemPrivate::get(gridviewB)->setLayoutMirror(true);
2080     QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2081
2082     // LTR != LTR+mirror
2083     foreach (const QString objectName, objectNames)
2084         QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2085
2086     gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2087
2088     // RTL == LTR+mirror
2089     foreach (const QString objectName, objectNames)
2090         QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2091
2092     gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2093
2094     // RTL != RTL+mirror
2095     foreach (const QString objectName, objectNames)
2096         QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2097
2098     gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2099
2100     // LTR == RTL+mirror
2101     foreach (const QString objectName, objectNames)
2102         QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2103
2104     delete canvasA;
2105     delete canvasB;
2106 }
2107
2108 void tst_QQuickGridView::positionViewAtIndex_rightToLeft()
2109 {
2110     QQuickView *canvas = createView();
2111
2112     TestModel model;
2113     for (int i = 0; i < 40; i++)
2114         model.addItem("Item" + QString::number(i), "");
2115
2116     QDeclarativeContext *ctxt = canvas->rootContext();
2117     ctxt->setContextProperty("testModel", &model);
2118     ctxt->setContextProperty("testTopToBottom", QVariant(true));
2119     ctxt->setContextProperty("testRightToLeft", QVariant(true));
2120
2121     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2122     qApp->processEvents();
2123
2124     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2125     QTRY_VERIFY(gridview != 0);
2126
2127     QQuickItem *contentItem = gridview->contentItem();
2128     QTRY_VERIFY(contentItem != 0);
2129
2130     // Confirm items positioned correctly
2131     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2132     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2133         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2134         if (!item) qWarning() << "Item" << i << "not found";
2135         QTRY_VERIFY(item);
2136         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2137         QTRY_COMPARE(item->y(), qreal((i%5)*60));
2138     }
2139
2140     // Position on a currently visible item
2141     gridview->positionViewAtIndex(6, QQuickGridView::Beginning);
2142     QTRY_COMPARE(gridview->contentX(), -320.);
2143
2144     // Confirm items positioned correctly
2145     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2146     for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2147         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2148         if (!item) qWarning() << "Item" << i << "not found";
2149         QTRY_VERIFY(item);
2150         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2151         QTRY_COMPARE(item->y(), qreal((i%5)*60));
2152     }
2153
2154     // Position on an item beyond the visible items
2155     gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2156     QTRY_COMPARE(gridview->contentX(), -560.);
2157
2158     // Confirm items positioned correctly
2159     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2160     for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2161         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2162         if (!item) qWarning() << "Item" << i << "not found";
2163         QTRY_VERIFY(item);
2164         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2165         QTRY_COMPARE(item->y(), qreal((i%5)*60));
2166     }
2167
2168     // Position on an item that would leave empty space if positioned at the top
2169     gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2170     QTRY_COMPARE(gridview->contentX(), -640.);
2171
2172     // Confirm items positioned correctly
2173     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2174     for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2175         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2176         if (!item) qWarning() << "Item" << i << "not found";
2177         QTRY_VERIFY(item);
2178         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2179         QTRY_COMPARE(item->y(), qreal((i%5)*60));
2180     }
2181
2182     // Position at the beginning again
2183     gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2184     QTRY_COMPARE(gridview->contentX(), -240.);
2185
2186     // Confirm items positioned correctly
2187     itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2188     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2189         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2190         if (!item) qWarning() << "Item" << i << "not found";
2191         QTRY_VERIFY(item);
2192         QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2193         QTRY_COMPARE(item->y(), qreal((i%5)*60));
2194     }
2195
2196     // Position at End
2197     gridview->positionViewAtIndex(30, QQuickGridView::End);
2198     QTRY_COMPARE(gridview->contentX(), -560.);
2199
2200     // Position in Center
2201     gridview->positionViewAtIndex(15, QQuickGridView::Center);
2202     QTRY_COMPARE(gridview->contentX(), -400.);
2203
2204     // Ensure at least partially visible
2205     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2206     QTRY_COMPARE(gridview->contentX(), -400.);
2207
2208     gridview->setContentX(-555.);
2209     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2210     QTRY_COMPARE(gridview->contentX(), -555.);
2211
2212     gridview->setContentX(-239);
2213     gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2214     QTRY_COMPARE(gridview->contentX(), -320.);
2215
2216     gridview->setContentX(-239);
2217     gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2218     QTRY_COMPARE(gridview->contentX(), -400.);
2219
2220     gridview->setContentX(-640);
2221     gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2222     QTRY_COMPARE(gridview->contentX(), -560.);
2223
2224     // Ensure completely visible
2225     gridview->setContentX(-400);
2226     gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2227     QTRY_COMPARE(gridview->contentX(), -400.);
2228
2229     gridview->setContentX(-315);
2230     gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2231     QTRY_COMPARE(gridview->contentX(), -320.);
2232
2233     gridview->setContentX(-640);
2234     gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2235     QTRY_COMPARE(gridview->contentX(), -560.);
2236
2237     delete canvas;
2238 }
2239
2240 void tst_QQuickGridView::resetModel()
2241 {
2242     QQuickView *canvas = createView();
2243
2244     QStringList strings;
2245     strings << "one" << "two" << "three";
2246     QStringListModel model(strings);
2247
2248     QDeclarativeContext *ctxt = canvas->rootContext();
2249     ctxt->setContextProperty("testModel", &model);
2250
2251     canvas->setSource(QUrl::fromLocalFile(TESTDATA("displaygrid.qml")));
2252     qApp->processEvents();
2253
2254     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2255     QTRY_VERIFY(gridview != 0);
2256
2257     QQuickItem *contentItem = gridview->contentItem();
2258     QTRY_VERIFY(contentItem != 0);
2259
2260     QTRY_COMPARE(gridview->count(), model.rowCount());
2261
2262     for (int i = 0; i < model.rowCount(); ++i) {
2263         QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2264         QTRY_VERIFY(display != 0);
2265         QTRY_COMPARE(display->text(), strings.at(i));
2266     }
2267
2268     strings.clear();
2269     strings << "four" << "five" << "six" << "seven";
2270     model.setStringList(strings);
2271
2272     QTRY_COMPARE(gridview->count(), model.rowCount());
2273
2274     for (int i = 0; i < model.rowCount(); ++i) {
2275         QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2276         QTRY_VERIFY(display != 0);
2277         QTRY_COMPARE(display->text(), strings.at(i));
2278     }
2279
2280     delete canvas;
2281 }
2282
2283 void tst_QQuickGridView::enforceRange()
2284 {
2285     QQuickView *canvas = createView();
2286
2287     TestModel model;
2288     for (int i = 0; i < 30; i++)
2289         model.addItem("Item" + QString::number(i), "");
2290
2291     QDeclarativeContext *ctxt = canvas->rootContext();
2292     ctxt->setContextProperty("testModel", &model);
2293     ctxt->setContextProperty("testRightToLeft", QVariant(false));
2294     ctxt->setContextProperty("testTopToBottom", QVariant(false));
2295
2296     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2297     qApp->processEvents();
2298     QVERIFY(canvas->rootObject() != 0);
2299
2300     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2301     QTRY_VERIFY(gridview != 0);
2302
2303     QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2304     QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2305     QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2306
2307     QQuickItem *contentItem = gridview->contentItem();
2308     QTRY_VERIFY(contentItem != 0);
2309
2310     // view should be positioned at the top of the range.
2311     QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2312     QTRY_VERIFY(item);
2313     QTRY_COMPARE(gridview->contentY(), -100.0);
2314
2315     QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2316     QTRY_VERIFY(name != 0);
2317     QTRY_COMPARE(name->text(), model.name(0));
2318     QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2319     QTRY_VERIFY(number != 0);
2320     QTRY_COMPARE(number->text(), model.number(0));
2321
2322     // Check currentIndex is updated when contentItem moves
2323     gridview->setContentY(0);
2324     QTRY_COMPARE(gridview->currentIndex(), 2);
2325
2326     gridview->setCurrentIndex(5);
2327     QTRY_COMPARE(gridview->contentY(), 100.);
2328
2329     TestModel model2;
2330     for (int i = 0; i < 5; i++)
2331         model2.addItem("Item" + QString::number(i), "");
2332
2333     ctxt->setContextProperty("testModel", &model2);
2334     QCOMPARE(gridview->count(), 5);
2335
2336     delete canvas;
2337 }
2338
2339 void tst_QQuickGridView::enforceRange_rightToLeft()
2340 {
2341     QQuickView *canvas = createView();
2342
2343     TestModel model;
2344     for (int i = 0; i < 30; i++)
2345         model.addItem("Item" + QString::number(i), "");
2346
2347     QDeclarativeContext *ctxt = canvas->rootContext();
2348     ctxt->setContextProperty("testModel", &model);
2349     ctxt->setContextProperty("testRightToLeft", QVariant(true));
2350     ctxt->setContextProperty("testTopToBottom", QVariant(true));
2351
2352     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2353     qApp->processEvents();
2354     QVERIFY(canvas->rootObject() != 0);
2355
2356     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2357     QTRY_VERIFY(gridview != 0);
2358
2359     QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2360     QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2361     QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2362
2363     QQuickItem *contentItem = gridview->contentItem();
2364     QTRY_VERIFY(contentItem != 0);
2365
2366     // view should be positioned at the top of the range.
2367     QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2368     QTRY_VERIFY(item);
2369     QTRY_COMPARE(gridview->contentX(), -100.);
2370     QTRY_COMPARE(gridview->contentY(), 0.0);
2371
2372     QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2373     QTRY_VERIFY(name != 0);
2374     QTRY_COMPARE(name->text(), model.name(0));
2375     QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2376     QTRY_VERIFY(number != 0);
2377     QTRY_COMPARE(number->text(), model.number(0));
2378
2379     // Check currentIndex is updated when contentItem moves
2380     gridview->setContentX(-200);
2381     QTRY_COMPARE(gridview->currentIndex(), 3);
2382
2383     gridview->setCurrentIndex(7);
2384     QTRY_COMPARE(gridview->contentX(), -300.);
2385     QTRY_COMPARE(gridview->contentY(), 0.0);
2386
2387     TestModel model2;
2388     for (int i = 0; i < 5; i++)
2389         model2.addItem("Item" + QString::number(i), "");
2390
2391     ctxt->setContextProperty("testModel", &model2);
2392     QCOMPARE(gridview->count(), 5);
2393
2394     delete canvas;
2395 }
2396
2397 void tst_QQuickGridView::QTBUG_8456()
2398 {
2399     QQuickView *canvas = createView();
2400
2401     canvas->setSource(QUrl::fromLocalFile(TESTDATA("setindex.qml")));
2402     qApp->processEvents();
2403
2404     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2405     QTRY_VERIFY(gridview != 0);
2406
2407     QTRY_COMPARE(gridview->currentIndex(), 0);
2408
2409     delete canvas;
2410 }
2411
2412 void tst_QQuickGridView::manualHighlight()
2413 {
2414     QQuickView *canvas = createView();
2415
2416     QString filename(TESTDATA("manual-highlight.qml"));
2417     canvas->setSource(QUrl::fromLocalFile(filename));
2418
2419     qApp->processEvents();
2420
2421     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2422     QTRY_VERIFY(gridview != 0);
2423
2424     QQuickItem *contentItem = gridview->contentItem();
2425     QTRY_VERIFY(contentItem != 0);
2426
2427     QTRY_COMPARE(gridview->currentIndex(), 0);
2428     QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2429     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2430     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2431
2432     gridview->setCurrentIndex(2);
2433
2434     QTRY_COMPARE(gridview->currentIndex(), 2);
2435     QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2436     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2437     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2438
2439     gridview->positionViewAtIndex(8, QQuickGridView::Contain);
2440
2441     QTRY_COMPARE(gridview->currentIndex(), 2);
2442     QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2443     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2444     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2445
2446     gridview->setFlow(QQuickGridView::TopToBottom);
2447     QTRY_COMPARE(gridview->flow(), QQuickGridView::TopToBottom);
2448
2449     gridview->setCurrentIndex(0);
2450     QTRY_COMPARE(gridview->currentIndex(), 0);
2451     QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2452     QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2453     QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2454
2455     delete canvas;
2456 }
2457
2458
2459 void tst_QQuickGridView::footer()
2460 {
2461     QFETCH(QQuickGridView::Flow, flow);
2462     QFETCH(Qt::LayoutDirection, layoutDirection);
2463     QFETCH(QPointF, initialFooterPos);
2464     QFETCH(QPointF, changedFooterPos);
2465     QFETCH(QPointF, initialContentPos);
2466     QFETCH(QPointF, changedContentPos);
2467     QFETCH(QPointF, firstDelegatePos);
2468     QFETCH(QPointF, resizeContentPos);
2469
2470     QQuickView *canvas = createView();
2471     canvas->show();
2472
2473     TestModel model;
2474     for (int i = 0; i < 7; i++)
2475         model.addItem("Item" + QString::number(i), "");
2476
2477     QDeclarativeContext *ctxt = canvas->rootContext();
2478     ctxt->setContextProperty("testModel", &model);
2479
2480     canvas->setSource(QUrl::fromLocalFile(TESTDATA("footer.qml")));
2481     qApp->processEvents();
2482
2483     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2484     QTRY_VERIFY(gridview != 0);
2485     gridview->setFlow(flow);
2486     gridview->setLayoutDirection(layoutDirection);
2487
2488     QQuickItem *contentItem = gridview->contentItem();
2489     QTRY_VERIFY(contentItem != 0);
2490
2491     QQuickText *footer = findItem<QQuickText>(contentItem, "footer");
2492     QVERIFY(footer);
2493
2494     QVERIFY(footer == gridview->footerItem());
2495
2496     QCOMPARE(footer->pos(), initialFooterPos);
2497     QCOMPARE(footer->width(), 100.);
2498     QCOMPARE(footer->height(), 30.);
2499     QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2500
2501     QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2502     QVERIFY(item);
2503     QCOMPARE(item->pos(), firstDelegatePos);
2504
2505     if (flow == QQuickGridView::LeftToRight) {
2506         // shrink by one row
2507         model.removeItem(2);
2508         QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2509     } else {
2510         // shrink by one column
2511         model.removeItem(2);
2512         model.removeItem(3);
2513         if (layoutDirection == Qt::LeftToRight)
2514             QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2515         else
2516             QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2517     }
2518
2519     // remove all items
2520     model.clear();
2521
2522     QPointF posWhenNoItems(0, 0);
2523     if (layoutDirection == Qt::RightToLeft)
2524         posWhenNoItems.setX(flow == QQuickGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2525     QTRY_COMPARE(footer->pos(), posWhenNoItems);
2526
2527     // if header is present, it's at a negative pos, so the footer should not move
2528     canvas->rootObject()->setProperty("showHeader", true);
2529     QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0);
2530     QTRY_COMPARE(footer->pos(), posWhenNoItems);
2531     canvas->rootObject()->setProperty("showHeader", false);
2532
2533     // add 30 items
2534     for (int i = 0; i < 30; i++)
2535         model.addItem("Item" + QString::number(i), "");
2536
2537     QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2538     QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2539
2540     QCOMPARE(footerItemSpy.count(), 1);
2541
2542     footer = findItem<QQuickText>(contentItem, "footer");
2543     QVERIFY(!footer);
2544     footer = findItem<QQuickText>(contentItem, "footer2");
2545     QVERIFY(footer);
2546
2547     QVERIFY(footer == gridview->footerItem());
2548
2549     QCOMPARE(footer->pos(), changedFooterPos);
2550     QCOMPARE(footer->width(), 50.);
2551     QCOMPARE(footer->height(), 20.);
2552     QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2553
2554     item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2555     QVERIFY(item);
2556     QCOMPARE(item->pos(), firstDelegatePos);
2557
2558     gridview->positionViewAtEnd();
2559     footer->setHeight(10);
2560     footer->setWidth(40);
2561     QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2562
2563     delete canvas;
2564 }
2565
2566 void tst_QQuickGridView::footer_data()
2567 {
2568     QTest::addColumn<QQuickGridView::Flow>("flow");
2569     QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2570     QTest::addColumn<QPointF>("initialFooterPos");
2571     QTest::addColumn<QPointF>("changedFooterPos");
2572     QTest::addColumn<QPointF>("initialContentPos");
2573     QTest::addColumn<QPointF>("changedContentPos");
2574     QTest::addColumn<QPointF>("firstDelegatePos");
2575     QTest::addColumn<QPointF>("resizeContentPos");
2576
2577     // footer1 = 100 x 30
2578     // footer2 = 50 x 20
2579     // cells = 80 * 60
2580     // view width = 240
2581     // view height = 320
2582
2583     // footer below items, bottom left
2584     QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
2585         << QPointF(0, 3 * 60)  // 180 = height of 3 rows (cell height is 60)
2586         << QPointF(0, 10 * 60)  // 30 items = 10 rows
2587         << QPointF(0, 0)
2588         << QPointF(0, 0)
2589         << QPointF(0, 0)
2590         << QPointF(0, 10 * 60 - 320 + 10);
2591
2592     // footer below items, bottom right
2593     QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
2594         << QPointF(240 - 100, 3 * 60)
2595         << QPointF((240 - 100) + 50, 10 * 60)     // 50 = width diff between old and new footers
2596         << QPointF(0, 0)
2597         << QPointF(0, 0)
2598         << QPointF(240 - 80, 0)
2599         << QPointF(0, 10 * 60 - 320 + 10);
2600
2601     // footer to right of items
2602     QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
2603         << QPointF(2 * 80, 0)      // 2 columns, cell width 80
2604         << QPointF(6 * 80, 0)      // 30 items = 6 columns
2605         << QPointF(0, 0)
2606         << QPointF(0, 0)
2607         << QPointF(0, 0)
2608         << QPointF(6 * 80 - 240 + 40, 0);
2609
2610     // footer to left of items
2611     QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
2612         << QPointF(-(2 * 80) - 100, 0)
2613         << QPointF(-(6 * 80) - 50, 0)     // 50 = new footer width
2614         << QPointF(-240, 0)
2615         << QPointF(-240, 0)    // unchanged, footer change doesn't change content pos
2616         << QPointF(-80, 0)
2617         << QPointF(-(6 * 80) - 40, 0);
2618 }
2619
2620 void tst_QQuickGridView::header()
2621 {
2622     QFETCH(QQuickGridView::Flow, flow);
2623     QFETCH(Qt::LayoutDirection, layoutDirection);
2624     QFETCH(QPointF, initialHeaderPos);
2625     QFETCH(QPointF, changedHeaderPos);
2626     QFETCH(QPointF, initialContentPos);
2627     QFETCH(QPointF, changedContentPos);
2628     QFETCH(QPointF, firstDelegatePos);
2629     QFETCH(QPointF, resizeContentPos);
2630
2631     TestModel model;
2632     for (int i = 0; i < 30; i++)
2633         model.addItem("Item" + QString::number(i), "");
2634
2635     QQuickView *canvas = createView();
2636     canvas->rootContext()->setContextProperty("testModel", &model);
2637     canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2638     canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2639     canvas->setSource(QUrl::fromLocalFile(TESTDATA("header.qml")));
2640
2641     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2642     QTRY_VERIFY(gridview != 0);
2643     gridview->setFlow(flow);
2644     gridview->setLayoutDirection(layoutDirection);
2645
2646     QQuickItem *contentItem = gridview->contentItem();
2647     QTRY_VERIFY(contentItem != 0);
2648
2649     QQuickText *header = findItem<QQuickText>(contentItem, "header");
2650     QVERIFY(header);
2651
2652     QVERIFY(header == gridview->headerItem());
2653
2654     QCOMPARE(header->pos(), initialHeaderPos);
2655     QCOMPARE(header->width(), 100.);
2656     QCOMPARE(header->height(), 30.);
2657     QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2658
2659     QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2660     QVERIFY(item);
2661     QCOMPARE(item->pos(), firstDelegatePos);
2662
2663     model.clear();
2664     QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
2665
2666     for (int i = 0; i < 30; i++)
2667         model.addItem("Item" + QString::number(i), "");
2668
2669     QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
2670     QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
2671
2672     QCOMPARE(headerItemSpy.count(), 1);
2673
2674     header = findItem<QQuickText>(contentItem, "header");
2675     QVERIFY(!header);
2676     header = findItem<QQuickText>(contentItem, "header2");
2677     QVERIFY(header);
2678
2679     QVERIFY(header == gridview->headerItem());
2680
2681     QCOMPARE(header->pos(), changedHeaderPos);
2682     QCOMPARE(header->width(), 50.);
2683     QCOMPARE(header->height(), 20.);
2684     QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2685
2686     item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2687     QVERIFY(item);
2688     QCOMPARE(item->pos(), firstDelegatePos);
2689
2690     header->setHeight(10);
2691     header->setWidth(40);
2692     QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2693
2694     delete canvas;
2695
2696
2697     // QTBUG-21207 header should become visible if view resizes from initial empty size
2698
2699     canvas = createView();
2700     canvas->rootContext()->setContextProperty("testModel", &model);
2701     canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2702     canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2703     canvas->setSource(QUrl::fromLocalFile(TESTDATA("header.qml")));
2704
2705     gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2706     QTRY_VERIFY(gridview != 0);
2707     gridview->setFlow(flow);
2708     gridview->setLayoutDirection(layoutDirection);
2709
2710     gridview->setWidth(240);
2711     gridview->setHeight(320);
2712     QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
2713     QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2714
2715     delete canvas;
2716 }
2717
2718 void tst_QQuickGridView::header_data()
2719 {
2720     QTest::addColumn<QQuickGridView::Flow>("flow");
2721     QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2722     QTest::addColumn<QPointF>("initialHeaderPos");
2723     QTest::addColumn<QPointF>("changedHeaderPos");
2724     QTest::addColumn<QPointF>("initialContentPos");
2725     QTest::addColumn<QPointF>("changedContentPos");
2726     QTest::addColumn<QPointF>("firstDelegatePos");
2727     QTest::addColumn<QPointF>("resizeContentPos");
2728
2729     // header1 = 100 x 30
2730     // header2 = 50 x 20
2731     // cells = 80 x 60
2732     // view width = 240
2733
2734     // header above items, top left
2735     QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
2736         << QPointF(0, -30)
2737         << QPointF(0, -20)
2738         << QPointF(0, -30)
2739         << QPointF(0, -20)
2740         << QPointF(0, 0)
2741         << QPointF(0, -10);
2742
2743     // header above items, top right
2744     QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
2745         << QPointF(240 - 100, -30)
2746         << QPointF((240 - 100) + 50, -20)     // 50 = width diff between old and new headers
2747         << QPointF(0, -30)
2748         << QPointF(0, -20)
2749         << QPointF(160, 0)
2750         << QPointF(0, -10);
2751
2752     // header to left of items
2753     QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
2754         << QPointF(-100, 0)
2755         << QPointF(-50, 0)
2756         << QPointF(-100, 0)
2757         << QPointF(-50, 0)
2758         << QPointF(0, 0)
2759         << QPointF(-40, 0);
2760
2761     // header to right of items
2762     QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
2763         << QPointF(0, 0)
2764         << QPointF(0, 0)
2765         << QPointF(-(240 - 100), 0)
2766         << QPointF(-(240 - 50), 0)
2767         << QPointF(-80, 0)
2768         << QPointF(-(240 - 40), 0);
2769 }
2770
2771 void tst_QQuickGridView::resizeViewAndRepaint()
2772 {
2773     QQuickView *canvas = createView();
2774     canvas->show();
2775
2776     TestModel model;
2777     for (int i = 0; i < 40; i++)
2778         model.addItem("Item" + QString::number(i), "");
2779
2780     QDeclarativeContext *ctxt = canvas->rootContext();
2781     ctxt->setContextProperty("testModel", &model);
2782     ctxt->setContextProperty("initialHeight", 100);
2783
2784     canvas->setSource(QUrl::fromLocalFile(TESTDATA("resizeview.qml")));
2785     qApp->processEvents();
2786
2787     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2788     QTRY_VERIFY(gridview != 0);
2789     QQuickItem *contentItem = gridview->contentItem();
2790     QTRY_VERIFY(contentItem != 0);
2791
2792     // item at index 10 should not be currently visible
2793     QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
2794
2795     gridview->setHeight(320);
2796     QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", 10));
2797
2798     gridview->setHeight(100);
2799     QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
2800
2801     delete canvas;
2802 }
2803
2804 void tst_QQuickGridView::indexAt()
2805 {
2806     QQuickView *canvas = createView();
2807
2808     TestModel model;
2809     model.addItem("Fred", "12345");
2810     model.addItem("John", "2345");
2811     model.addItem("Bob", "54321");
2812     model.addItem("Billy", "22345");
2813     model.addItem("Sam", "2945");
2814     model.addItem("Ben", "04321");
2815     model.addItem("Jim", "0780");
2816
2817     QDeclarativeContext *ctxt = canvas->rootContext();
2818     ctxt->setContextProperty("testModel", &model);
2819     ctxt->setContextProperty("testRightToLeft", QVariant(false));
2820     ctxt->setContextProperty("testTopToBottom", QVariant(false));
2821
2822     canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2823     qApp->processEvents();
2824
2825     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2826     QTRY_VERIFY(gridview != 0);
2827
2828     QQuickItem *contentItem = gridview->contentItem();
2829     QTRY_VERIFY(contentItem != 0);
2830
2831     QTRY_COMPARE(gridview->count(), model.count());
2832
2833     QCOMPARE(gridview->indexAt(0, 0), 0);
2834     QCOMPARE(gridview->indexAt(79, 59), 0);
2835     QCOMPARE(gridview->indexAt(80, 0), 1);
2836     QCOMPARE(gridview->indexAt(0, 60), 3);
2837     QCOMPARE(gridview->indexAt(240, 0), -1);
2838
2839     delete canvas;
2840 }
2841
2842 void tst_QQuickGridView::onAdd()
2843 {
2844     QFETCH(int, initialItemCount);
2845     QFETCH(int, itemsToAdd);
2846
2847     const int delegateWidth = 50;
2848     const int delegateHeight = 100;
2849     TestModel model;
2850     QQuickView *canvas = createView();
2851     canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
2852
2853     // these initial items should not trigger GridView.onAdd
2854     for (int i=0; i<initialItemCount; i++)
2855         model.addItem("dummy value", "dummy value");
2856
2857     QDeclarativeContext *ctxt = canvas->rootContext();
2858     ctxt->setContextProperty("testModel", &model);
2859     ctxt->setContextProperty("delegateWidth", delegateWidth);
2860     ctxt->setContextProperty("delegateHeight", delegateHeight);
2861     canvas->setSource(QUrl::fromLocalFile(TESTDATA("attachedSignals.qml")));
2862
2863     QObject *object = canvas->rootObject();
2864     object->setProperty("width", canvas->width());
2865     object->setProperty("height", canvas->height());
2866     qApp->processEvents();
2867
2868     QList<QPair<QString, QString> > items;
2869     for (int i=0; i<itemsToAdd; i++)
2870         items << qMakePair(QString("value %1").arg(i), QString::number(i));
2871     model.addItems(items);
2872
2873     QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
2874     qApp->processEvents();
2875
2876     QVariantList result = object->property("addedDelegates").toList();
2877     QTRY_COMPARE(result.count(), items.count());
2878     for (int i=0; i<items.count(); i++)
2879         QCOMPARE(result[i].toString(), items[i].first);
2880
2881     delete canvas;
2882 }
2883
2884 void tst_QQuickGridView::onAdd_data()
2885 {
2886     QTest::addColumn<int>("initialItemCount");
2887     QTest::addColumn<int>("itemsToAdd");
2888
2889     QTest::newRow("0, add 1") << 0 << 1;
2890     QTest::newRow("0, add 2") << 0 << 2;
2891     QTest::newRow("0, add 10") << 0 << 10;
2892
2893     QTest::newRow("1, add 1") << 1 << 1;
2894     QTest::newRow("1, add 2") << 1 << 2;
2895     QTest::newRow("1, add 10") << 1 << 10;
2896
2897     QTest::newRow("5, add 1") << 5 << 1;
2898     QTest::newRow("5, add 2") << 5 << 2;
2899     QTest::newRow("5, add 10") << 5 << 10;
2900 }
2901
2902 void tst_QQuickGridView::onRemove()
2903 {
2904     QFETCH(int, initialItemCount);
2905     QFETCH(int, indexToRemove);
2906     QFETCH(int, removeCount);
2907
2908     const int delegateWidth = 50;
2909     const int delegateHeight = 100;
2910     TestModel model;
2911     for (int i=0; i<initialItemCount; i++)
2912         model.addItem(QString("value %1").arg(i), "dummy value");
2913
2914     QQuickView *canvas = createView();
2915     QDeclarativeContext *ctxt = canvas->rootContext();
2916     ctxt->setContextProperty("testModel", &model);
2917     ctxt->setContextProperty("delegateWidth", delegateWidth);
2918     ctxt->setContextProperty("delegateHeight", delegateHeight);
2919     canvas->setSource(QUrl::fromLocalFile(TESTDATA("attachedSignals.qml")));
2920     QObject *object = canvas->rootObject();
2921
2922     model.removeItems(indexToRemove, removeCount);
2923     QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
2924     QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2925
2926     delete canvas;
2927 }
2928
2929 void tst_QQuickGridView::onRemove_data()
2930 {
2931     QTest::addColumn<int>("initialItemCount");
2932     QTest::addColumn<int>("indexToRemove");
2933     QTest::addColumn<int>("removeCount");
2934
2935     QTest::newRow("remove first") << 1 << 0 << 1;
2936     QTest::newRow("two items, remove first") << 2 << 0 << 1;
2937     QTest::newRow("two items, remove last") << 2 << 1 << 1;
2938     QTest::newRow("two items, remove all") << 2 << 0 << 2;
2939
2940     QTest::newRow("four items, remove first") << 4 << 0 << 1;
2941     QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2942     QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2943     QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2944     QTest::newRow("four items, remove last") << 4 << 3 << 1;
2945     QTest::newRow("four items, remove all") << 4 << 0 << 4;
2946
2947     QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2948     QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2949     QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2950 }
2951
2952 void tst_QQuickGridView::testQtQuick11Attributes()
2953 {
2954     QFETCH(QString, code);
2955     QFETCH(QString, warning);
2956     QFETCH(QString, error);
2957
2958     QDeclarativeEngine engine;
2959     QObject *obj;
2960
2961     QDeclarativeComponent valid(&engine);
2962     valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
2963     obj = valid.create();
2964     QVERIFY(obj);
2965     QVERIFY(valid.errorString().isEmpty());
2966     delete obj;
2967
2968     QDeclarativeComponent invalid(&engine);
2969     invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
2970     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2971     obj = invalid.create();
2972     QCOMPARE(invalid.errorString(), error);
2973     delete obj;
2974 }
2975
2976 void tst_QQuickGridView::testQtQuick11Attributes_data()
2977 {
2978     QTest::addColumn<QString>("code");
2979     QTest::addColumn<QString>("warning");
2980     QTest::addColumn<QString>("error");
2981
2982     QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2983         << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2984         << "";
2985
2986     QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2987         << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2988         << "";
2989 }
2990
2991 void tst_QQuickGridView::columnCount()
2992 {
2993     QQuickView canvas;
2994     canvas.setSource(QUrl::fromLocalFile(TESTDATA("gridview4.qml")));
2995     canvas.show();
2996     canvas.requestActivateWindow();
2997     QTest::qWaitForWindowShown(&canvas);
2998
2999     QQuickGridView *view = qobject_cast<QQuickGridView*>(canvas.rootObject());
3000
3001     QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3002     QCOMPARE(view->cellHeight(), qreal(100));
3003
3004     QList<QQuickItem*> items = findItems<QQuickItem>(view, "delegate");
3005     QCOMPARE(items.size(), 18);
3006     QCOMPARE(items.at(8)->y(), qreal(0));
3007     QCOMPARE(items.at(9)->y(), qreal(100));
3008 }
3009
3010 void tst_QQuickGridView::margins()
3011 {
3012     {
3013         QQuickView *canvas = createView();
3014         canvas->show();
3015
3016         TestModel model;
3017         for (int i = 0; i < 40; i++)
3018             model.addItem("Item" + QString::number(i), "");
3019
3020         QDeclarativeContext *ctxt = canvas->rootContext();
3021         ctxt->setContextProperty("testModel", &model);
3022         ctxt->setContextProperty("testRightToLeft", QVariant(false));
3023
3024         canvas->setSource(QUrl::fromLocalFile(TESTDATA("margins.qml")));
3025         qApp->processEvents();
3026
3027         QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3028         QTRY_VERIFY(gridview != 0);
3029
3030         QQuickItem *contentItem = gridview->contentItem();
3031         QTRY_VERIFY(contentItem != 0);
3032
3033         QCOMPARE(gridview->contentX(), -30.);
3034         QCOMPARE(gridview->xOrigin(), 0.);
3035
3036         // check end bound
3037         gridview->positionViewAtEnd();
3038         qreal pos = gridview->contentX();
3039         gridview->setContentX(pos + 80);
3040         gridview->returnToBounds();
3041         QTRY_COMPARE(gridview->contentX(), pos + 50);
3042
3043         // remove item before visible and check that left margin is maintained
3044         // and xOrigin is updated
3045         gridview->setContentX(200);
3046         model.removeItems(0, 4);
3047         QTest::qWait(100);
3048         gridview->setContentX(-50);
3049         gridview->returnToBounds();
3050         QCOMPARE(gridview->xOrigin(), 100.);
3051         QTRY_COMPARE(gridview->contentX(), 70.);
3052
3053         // reduce left margin
3054         gridview->setLeftMargin(20);
3055         QCOMPARE(gridview->xOrigin(), 100.);
3056         QTRY_COMPARE(gridview->contentX(), 80.);
3057
3058         // check end bound
3059         gridview->positionViewAtEnd();
3060         QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3061         pos = gridview->contentX();
3062         gridview->setContentX(pos + 80);
3063         gridview->returnToBounds();
3064         QTRY_COMPARE(gridview->contentX(), pos + 50);
3065
3066         // reduce right margin
3067         pos = gridview->contentX();
3068         gridview->setRightMargin(40);
3069         QCOMPARE(gridview->xOrigin(), 0.);
3070         QTRY_COMPARE(gridview->contentX(), pos-10);
3071
3072         delete canvas;
3073     }
3074     {
3075         //RTL
3076         QQuickView *canvas = createView();
3077         canvas->show();
3078
3079         TestModel model;
3080         for (int i = 0; i < 40; i++)
3081             model.addItem("Item" + QString::number(i), "");
3082
3083         QDeclarativeContext *ctxt = canvas->rootContext();
3084         ctxt->setContextProperty("testModel", &model);
3085         ctxt->setContextProperty("testRightToLeft", QVariant(true));
3086
3087         canvas->setSource(QUrl::fromLocalFile(TESTDATA("margins.qml")));
3088         qApp->processEvents();
3089
3090         QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3091         QTRY_VERIFY(gridview != 0);
3092
3093         QQuickItem *contentItem = gridview->contentItem();
3094         QTRY_VERIFY(contentItem != 0);
3095
3096         QCOMPARE(gridview->contentX(), -240+30.);
3097         QCOMPARE(gridview->xOrigin(), 0.);
3098
3099         // check end bound
3100         gridview->positionViewAtEnd();
3101         qreal pos = gridview->contentX();
3102         gridview->setContentX(pos - 80);
3103         gridview->returnToBounds();
3104         QTRY_COMPARE(gridview->contentX(), pos - 50);
3105
3106         // remove item before visible and check that left margin is maintained
3107         // and xOrigin is updated
3108         gridview->setContentX(-400);
3109         model.removeItems(0, 4);
3110         QTest::qWait(100);
3111         gridview->setContentX(-240+50);
3112         gridview->returnToBounds();
3113         QCOMPARE(gridview->xOrigin(), -100.);
3114         QTRY_COMPARE(gridview->contentX(), -240-70.);
3115
3116         // reduce left margin (i.e. right side due to RTL)
3117         pos = gridview->contentX();
3118         gridview->setLeftMargin(20);
3119         QCOMPARE(gridview->xOrigin(), -100.);
3120         QTRY_COMPARE(gridview->contentX(), -240-80.);
3121
3122         // check end bound
3123         gridview->positionViewAtEnd();
3124         QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3125         pos = gridview->contentX();
3126         gridview->setContentX(pos - 80);
3127         gridview->returnToBounds();
3128         QTRY_COMPARE(gridview->contentX(), pos - 50);
3129
3130         // reduce right margin (i.e. left side due to RTL)
3131         pos = gridview->contentX();
3132         gridview->setRightMargin(40);
3133         QCOMPARE(gridview->xOrigin(), 0.);
3134         QTRY_COMPARE(gridview->contentX(), pos+10);
3135
3136         delete canvas;
3137     }
3138 }
3139
3140 void tst_QQuickGridView::creationContext()
3141 {
3142     QQuickView canvas;
3143     canvas.setGeometry(0,0,240,320);
3144     canvas.setSource(QUrl::fromLocalFile(TESTDATA("creationContext.qml")));
3145     qApp->processEvents();
3146
3147     QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
3148     QVERIFY(rootItem);
3149     QVERIFY(rootItem->property("count").toInt() > 0);
3150
3151     QQuickItem *item;
3152     QVERIFY(item = rootItem->findChild<QQuickItem *>("listItem"));
3153     QCOMPARE(item->property("text").toString(), QString("Hello!"));
3154     QVERIFY(item = rootItem->findChild<QQuickItem *>("header"));
3155     QCOMPARE(item->property("text").toString(), QString("Hello!"));
3156     QVERIFY(item = rootItem->findChild<QQuickItem *>("footer"));
3157     QCOMPARE(item->property("text").toString(), QString("Hello!"));
3158 }
3159
3160 void tst_QQuickGridView::snapToRow_data()
3161 {
3162     QTest::addColumn<QQuickGridView::Flow>("flow");
3163     QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3164     QTest::addColumn<int>("highlightRangeMode");
3165     QTest::addColumn<QPoint>("flickStart");
3166     QTest::addColumn<QPoint>("flickEnd");
3167     QTest::addColumn<qreal>("snapAlignment");
3168     QTest::addColumn<qreal>("endExtent");
3169     QTest::addColumn<qreal>("startExtent");
3170
3171     QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3172         << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3173
3174     QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3175         << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3176
3177     QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3178         << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 << -240.0;
3179
3180     QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3181         << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3182
3183     QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3184         << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3185
3186     QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3187         << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0;
3188 }
3189
3190 void tst_QQuickGridView::snapToRow()
3191 {
3192     QFETCH(QQuickGridView::Flow, flow);
3193     QFETCH(Qt::LayoutDirection, layoutDirection);
3194     QFETCH(int, highlightRangeMode);
3195     QFETCH(QPoint, flickStart);
3196     QFETCH(QPoint, flickEnd);
3197     QFETCH(qreal, snapAlignment);
3198     QFETCH(qreal, endExtent);
3199     QFETCH(qreal, startExtent);
3200
3201     QQuickView *canvas = createView();
3202
3203     canvas->setSource(QUrl::fromLocalFile(TESTDATA("snapToRow.qml")));
3204     canvas->show();
3205     qApp->processEvents();
3206
3207     QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3208     QTRY_VERIFY(gridview != 0);
3209
3210     gridview->setFlow(flow);
3211     gridview->setLayoutDirection(layoutDirection);
3212     gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3213
3214     QQuickItem *contentItem = gridview->contentItem();
3215     QTRY_VERIFY(contentItem != 0);
3216
3217     // confirm that a flick hits an item boundary
3218     flick(canvas, flickStart, flickEnd, 180);
3219     QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3220     if (flow == QQuickGridView::LeftToRight)
3221         QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
3222     else
3223         QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
3224
3225     // flick to end
3226     do {
3227         flick(canvas, flickStart, flickEnd, 180);
3228         QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3229     } while (flow == QQuickGridView::LeftToRight
3230            ? !gridview->isAtYEnd()
3231            : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3232
3233     if (flow == QQuickGridView::LeftToRight)
3234         QCOMPARE(gridview->contentY(), endExtent);
3235     else
3236         QCOMPARE(gridview->contentX(), endExtent);
3237
3238     // flick to start
3239     do {
3240         flick(canvas, flickEnd, flickStart, 180);
3241         QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3242     } while (flow == QQuickGridView::LeftToRight
3243            ? !gridview->isAtYBeginning()
3244            : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3245
3246     if (flow == QQuickGridView::LeftToRight)
3247         QCOMPARE(gridview->contentY(), startExtent);
3248     else
3249         QCOMPARE(gridview->contentX(), startExtent);
3250
3251     delete canvas;
3252 }
3253
3254
3255 QQuickView *tst_QQuickGridView::createView()
3256 {
3257     QQuickView *canvas = new QQuickView(0);
3258     canvas->setGeometry(0,0,240,320);
3259
3260     return canvas;
3261 }
3262
3263 void tst_QQuickGridView::flick(QQuickView *canvas, const QPoint &from, const QPoint &to, int duration)
3264 {
3265     const int pointCount = 5;
3266     QPoint diff = to - from;
3267
3268     // send press, five equally spaced moves, and release.
3269     QTest::mousePress(canvas, Qt::LeftButton, 0, from);
3270
3271     for (int i = 0; i < pointCount; ++i) {
3272         QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
3273         QApplication::sendEvent(canvas, &mv);
3274         QTest::qWait(duration/pointCount);
3275         QCoreApplication::processEvents();
3276     }
3277
3278     QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
3279 }
3280
3281 /*
3282    Find an item with the specified objectName.  If index is supplied then the
3283    item must also evaluate the {index} expression equal to index
3284 */
3285 template<typename T>
3286 T *tst_QQuickGridView::findItem(QQuickItem *parent, const QString &objectName, int index)
3287 {
3288     const QMetaObject &mo = T::staticMetaObject;
3289     //qDebug() << parent->childItems().count() << "children";
3290     for (int i = 0; i < parent->childItems().count(); ++i) {
3291         QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
3292         if (!item)
3293             continue;
3294         //qDebug() << "try" << item;
3295         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
3296             if (index != -1) {
3297                 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3298                 if (context) {
3299                     if (context->contextProperty("index").toInt() == index) {
3300                         return static_cast<T*>(item);
3301                     }
3302                 }
3303             } else {
3304                 return static_cast<T*>(item);
3305             }
3306         }
3307         item = findItem<T>(item, objectName, index);
3308         if (item)
3309             return static_cast<T*>(item);
3310     }
3311
3312     return 0;
3313 }
3314
3315 template<typename T>
3316 QList<T*> tst_QQuickGridView::findItems(QQuickItem *parent, const QString &objectName)
3317 {
3318     QList<T*> items;
3319     const QMetaObject &mo = T::staticMetaObject;
3320     //qDebug() << parent->childItems().count() << "children";
3321     for (int i = 0; i < parent->childItems().count(); ++i) {
3322         QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
3323         if (!item)
3324             continue;
3325         //qDebug() << "try" << item;
3326         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
3327             items.append(static_cast<T*>(item));
3328             //qDebug() << " found:" << item;
3329         }
3330         items += findItems<T>(item, objectName);
3331     }
3332
3333     return items;
3334 }
3335
3336 void tst_QQuickGridView::dumpTree(QQuickItem *parent, int depth)
3337 {
3338     static QString padding("                       ");
3339     for (int i = 0; i < parent->childItems().count(); ++i) {
3340         QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
3341         if (!item)
3342             continue;
3343         QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3344         qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
3345         dumpTree(item, depth+1);
3346     }
3347 }
3348
3349
3350 QTEST_MAIN(tst_QQuickGridView)
3351
3352 #include "tst_qquickgridview.moc"
3353