1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtCore/qstringlistmodel.h>
44 #include <QtQuick/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/qdeclarativeincubator.h>
50 #include <QtQuick/private/qquickitem_p.h>
51 #include <QtDeclarative/private/qlistmodelinterface_p.h>
52 #include <QtQuick/private/qquickgridview_p.h>
53 #include <QtQuick/private/qquicktext_p.h>
54 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
55 #include "../../shared/util.h"
56 #include <QtGui/qguiapplication.h>
58 Q_DECLARE_METATYPE(Qt::LayoutDirection)
59 Q_DECLARE_METATYPE(QQuickGridView::Flow)
61 class tst_QQuickGridView : public QDeclarativeDataTest
72 void inserted_more_data();
73 void insertBeforeVisible();
74 void insertBeforeVisible_data();
77 void removed_more_data();
78 void addOrRemoveBeforeVisible();
79 void addOrRemoveBeforeVisible_data();
83 void multipleChanges();
84 void multipleChanges_data();
85 void swapWithFirstItem();
88 void noCurrentIndex();
91 void propertyChanges();
92 void componentChanges();
94 void positionViewAtIndex();
95 void positionViewAtIndex_rightToLeft();
100 void enforceRange_rightToLeft();
102 void manualHighlight();
107 void resizeViewAndRepaint();
108 void indexAt_itemAt_data();
109 void indexAt_itemAt();
113 void onRemove_data();
116 void creationContext();
117 void snapToRow_data();
119 void snapOneRow_data();
124 void unrequestedVisibility();
127 QQuickView *createView();
128 void flick(QQuickView *canvas, const QPoint &from, const QPoint &to, int duration);
130 T *findItem(QQuickItem *parent, const QString &id, int index=-1);
132 QList<T*> findItems(QQuickItem *parent, const QString &objectName);
133 void dumpTree(QQuickItem *parent, int depth = 0);
137 void tst_qquickgridview_move(int from, int to, int n, T *items)
140 // Only move forwards - flip if backwards moving
150 typename T::ConstIterator it=items->begin(); it += from+n;
151 for (; i<to-from; ++i,++it)
152 replaced.append(*it);
154 it=items->begin(); it += from;
155 for (; i<n; ++i,++it)
156 replaced.append(*it);
157 typename T::ConstIterator f=replaced.begin();
158 typename T::Iterator t=items->begin(); t += from;
159 for (; f != replaced.end(); ++f, ++t)
163 class TestModel : public QAbstractListModel
166 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
168 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
169 QHash<int, QByteArray> roles;
170 roles[Name] = "name";
171 roles[Number] = "number";
175 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
176 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
179 rv = list.at(index.row()).first;
180 else if (role == Number)
181 rv = list.at(index.row()).second;
186 int count() const { return rowCount(); }
187 QString name(int index) const { return list.at(index).first; }
188 QString number(int index) const { return list.at(index).second; }
190 void addItem(const QString &name, const QString &number) {
191 emit beginInsertRows(QModelIndex(), list.count(), list.count());
192 list.append(QPair<QString,QString>(name, number));
193 emit endInsertRows();
196 void addItems(const QList<QPair<QString, QString> > &items) {
197 emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
198 for (int i=0; i<items.count(); i++)
199 list.append(QPair<QString,QString>(items[i].first, items[i].second));
200 emit endInsertRows();
203 void insertItem(int index, const QString &name, const QString &number) {
204 emit beginInsertRows(QModelIndex(), index, index);
205 list.insert(index, QPair<QString,QString>(name, number));
206 emit endInsertRows();
209 void insertItems(int index, const QList<QPair<QString, QString> > &items) {
210 emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
211 for (int i=0; i<items.count(); i++)
212 list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
213 emit endInsertRows();
216 void removeItem(int index) {
217 emit beginRemoveRows(QModelIndex(), index, index);
218 list.removeAt(index);
219 emit endRemoveRows();
222 void removeItems(int index, int count) {
223 emit beginRemoveRows(QModelIndex(), index, index+count-1);
225 list.removeAt(index);
226 emit endRemoveRows();
229 void moveItem(int from, int to) {
230 emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
235 void moveItems(int from, int to, int count) {
236 emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
237 tst_qquickgridview_move(from, to, count, &list);
241 void modifyItem(int idx, const QString &name, const QString &number) {
242 list[idx] = QPair<QString,QString>(name, number);
243 emit dataChanged(index(idx,0), index(idx,0));
247 int count = list.count();
248 emit beginRemoveRows(QModelIndex(), 0, count-1);
250 emit endRemoveRows();
255 QList<QPair<QString,QString> > list;
258 tst_QQuickGridView::tst_QQuickGridView()
262 void tst_QQuickGridView::items()
264 QQuickView *canvas = createView();
267 model.addItem("Fred", "12345");
268 model.addItem("John", "2345");
269 model.addItem("Bob", "54321");
270 model.addItem("Billy", "22345");
271 model.addItem("Sam", "2945");
272 model.addItem("Ben", "04321");
273 model.addItem("Jim", "0780");
275 QDeclarativeContext *ctxt = canvas->rootContext();
276 ctxt->setContextProperty("testModel", &model);
277 ctxt->setContextProperty("testRightToLeft", QVariant(false));
278 ctxt->setContextProperty("testTopToBottom", QVariant(false));
280 canvas->setSource(testFileUrl("gridview1.qml"));
281 qApp->processEvents();
283 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
284 QTRY_VERIFY(gridview != 0);
286 QQuickItem *contentItem = gridview->contentItem();
287 QTRY_VERIFY(contentItem != 0);
289 QTRY_COMPARE(gridview->count(), model.count());
290 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
291 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
293 for (int i = 0; i < model.count(); ++i) {
294 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
295 QTRY_VERIFY(name != 0);
296 QTRY_COMPARE(name->text(), model.name(i));
297 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
298 QTRY_VERIFY(number != 0);
299 QTRY_COMPARE(number->text(), model.number(i));
302 // set an empty model and confirm that items are destroyed
304 ctxt->setContextProperty("testModel", &model2);
306 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
307 QTRY_VERIFY(itemCount == 0);
312 void tst_QQuickGridView::changed()
314 QQuickView *canvas = createView();
317 model.addItem("Fred", "12345");
318 model.addItem("John", "2345");
319 model.addItem("Bob", "54321");
320 model.addItem("Billy", "22345");
321 model.addItem("Sam", "2945");
322 model.addItem("Ben", "04321");
323 model.addItem("Jim", "0780");
325 QDeclarativeContext *ctxt = canvas->rootContext();
326 ctxt->setContextProperty("testModel", &model);
327 ctxt->setContextProperty("testRightToLeft", QVariant(false));
328 ctxt->setContextProperty("testTopToBottom", QVariant(false));
330 canvas->setSource(testFileUrl("gridview1.qml"));
331 qApp->processEvents();
333 QQuickFlickable *gridview = findItem<QQuickFlickable>(canvas->rootObject(), "grid");
334 QTRY_VERIFY(gridview != 0);
336 QQuickItem *contentItem = gridview->contentItem();
337 QTRY_VERIFY(contentItem != 0);
339 model.modifyItem(1, "Will", "9876");
340 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
341 QTRY_VERIFY(name != 0);
342 QTRY_COMPARE(name->text(), model.name(1));
343 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
344 QTRY_VERIFY(number != 0);
345 QTRY_COMPARE(number->text(), model.number(1));
350 void tst_QQuickGridView::inserted()
352 QQuickView *canvas = createView();
356 model.addItem("Fred", "12345");
357 model.addItem("John", "2345");
358 model.addItem("Bob", "54321");
360 QDeclarativeContext *ctxt = canvas->rootContext();
361 ctxt->setContextProperty("testModel", &model);
362 ctxt->setContextProperty("testRightToLeft", QVariant(false));
363 ctxt->setContextProperty("testTopToBottom", QVariant(false));
365 canvas->setSource(testFileUrl("gridview1.qml"));
366 qApp->processEvents();
368 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
369 QTRY_VERIFY(gridview != 0);
371 QQuickItem *contentItem = gridview->contentItem();
372 QTRY_VERIFY(contentItem != 0);
374 model.insertItem(1, "Will", "9876");
376 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
377 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
379 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
380 QTRY_VERIFY(name != 0);
381 QTRY_COMPARE(name->text(), model.name(1));
382 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
383 QTRY_VERIFY(number != 0);
384 QTRY_COMPARE(number->text(), model.number(1));
386 // Checks that onAdd is called
387 int added = canvas->rootObject()->property("added").toInt();
388 QTRY_COMPARE(added, 1);
390 // Confirm items positioned correctly
391 for (int i = 0; i < model.count(); ++i) {
392 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
393 QTRY_COMPARE(item->x(), (i%3)*80.0);
394 QTRY_COMPARE(item->y(), (i/3)*60.0);
397 model.insertItem(0, "Foo", "1111"); // zero index, and current item
399 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
401 name = findItem<QQuickText>(contentItem, "textName", 0);
402 QTRY_VERIFY(name != 0);
403 QTRY_COMPARE(name->text(), model.name(0));
404 number = findItem<QQuickText>(contentItem, "textNumber", 0);
405 QTRY_VERIFY(number != 0);
406 QTRY_COMPARE(number->text(), model.number(0));
408 QTRY_COMPARE(gridview->currentIndex(), 1);
410 // Confirm items positioned correctly
411 for (int i = 0; i < model.count(); ++i) {
412 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
413 QTRY_VERIFY(item->x() == (i%3)*80);
414 QTRY_VERIFY(item->y() == (i/3)*60);
417 for (int i = model.count(); i < 30; ++i)
418 model.insertItem(i, "Hello", QString::number(i));
420 gridview->setContentY(120);
422 // Insert item outside visible area
423 model.insertItem(1, "Hello", "1324");
425 QTRY_VERIFY(gridview->contentY() == 120);
430 void tst_QQuickGridView::inserted_more()
432 QFETCH(qreal, contentY);
433 QFETCH(int, insertIndex);
434 QFETCH(int, insertCount);
435 QFETCH(qreal, itemsOffsetAfterMove);
439 QQuickView *canvas = createView();
443 for (int i = 0; i < 30; i++)
444 model.addItem("Item" + QString::number(i), "");
446 QDeclarativeContext *ctxt = canvas->rootContext();
447 ctxt->setContextProperty("testModel", &model);
448 ctxt->setContextProperty("testRightToLeft", QVariant(false));
449 ctxt->setContextProperty("testTopToBottom", QVariant(false));
451 canvas->setSource(testFileUrl("gridview1.qml"));
452 qApp->processEvents();
454 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
455 QTRY_VERIFY(gridview != 0);
456 QQuickItem *contentItem = gridview->contentItem();
457 QTRY_VERIFY(contentItem != 0);
459 gridview->setContentY(contentY);
461 QList<QPair<QString, QString> > newData;
462 for (int i=0; i<insertCount; i++)
463 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
464 model.insertItems(insertIndex, newData);
465 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
467 // check visibleItems.first() is in correct position
468 QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
470 QCOMPARE(item0->y(), 0.0);
472 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
473 int firstVisibleIndex = -1;
474 for (int i=0; i<items.count(); i++) {
475 if (items[i]->y() >= contentY) {
476 QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
477 firstVisibleIndex = e.evaluate().toInt();
481 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
483 // Confirm items positioned correctly and indexes correct
484 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
485 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
486 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
487 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
489 QCOMPARE(item->x(), (i%3)*80.0);
490 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
492 name = findItem<QQuickText>(contentItem, "textName", i);
494 QCOMPARE(name->text(), model.name(i));
495 number = findItem<QQuickText>(contentItem, "textNumber", i);
496 QVERIFY(number != 0);
497 QCOMPARE(number->text(), model.number(i));
503 void tst_QQuickGridView::inserted_more_data()
505 QTest::addColumn<qreal>("contentY");
506 QTest::addColumn<int>("insertIndex");
507 QTest::addColumn<int>("insertCount");
508 QTest::addColumn<qreal>("itemsOffsetAfterMove");
510 QTest::newRow("add 1, before visible items")
511 << 120.0 // show 6-23
513 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
514 // new 1st visible item is at 0
516 QTest::newRow("add 2, before visible items")
517 << 120.0 // show 6-23
519 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
521 QTest::newRow("add 3, before visible items")
522 << 120.0 // show 6-23
524 << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
526 QTest::newRow("add 5, before visible items")
527 << 120.0 // show 6-23
529 << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
530 // grid is rearranged and first visible moves forward within its row
532 QTest::newRow("add 6, before visible items")
533 << 120.0 // show 6-23
535 << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
539 QTest::newRow("add 1, at start of visible, content at start")
544 QTest::newRow("add multiple, at start of visible, content at start")
549 QTest::newRow("add 1, at start of visible, content not at start")
550 << 120.0 // show 6-23
554 QTest::newRow("add multiple, at start of visible, content not at start")
555 << 120.0 // show 6-23
560 QTest::newRow("add 1, at end of visible, content at start")
565 QTest::newRow("add 1, at end of visible, content at start")
570 QTest::newRow("add 1, at end of visible, content not at start")
571 << 120.0 // show 6-23
575 QTest::newRow("add multiple, at end of visible, content not at start")
576 << 120.0 // show 6-23
581 QTest::newRow("add 1, after visible, content at start")
586 QTest::newRow("add 1, after visible, content at start")
591 QTest::newRow("add 1, after visible, content not at start")
592 << 120.0 // show 6-23
596 QTest::newRow("add multiple, after visible, content not at start")
597 << 120.0 // show 6-23
602 void tst_QQuickGridView::insertBeforeVisible()
604 QFETCH(int, insertIndex);
605 QFETCH(int, insertCount);
606 QFETCH(int, cacheBuffer);
609 QQuickView *canvas = createView();
613 for (int i = 0; i < 30; i++)
614 model.addItem("Item" + QString::number(i), "");
616 QDeclarativeContext *ctxt = canvas->rootContext();
617 ctxt->setContextProperty("testModel", &model);
618 ctxt->setContextProperty("testRightToLeft", QVariant(false));
619 ctxt->setContextProperty("testTopToBottom", QVariant(false));
620 canvas->setSource(testFileUrl("gridview1.qml"));
621 qApp->processEvents();
623 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
624 QTRY_VERIFY(gridview != 0);
625 QQuickItem *contentItem = gridview->contentItem();
626 QTRY_VERIFY(contentItem != 0);
628 gridview->setCacheBuffer(cacheBuffer);
630 // trigger a refill (not just setting contentY) so that the visibleItems grid is updated
631 int firstVisibleIndex = 20; // move to an index where the top item is not visible
632 gridview->setContentY(firstVisibleIndex * 20.0);
633 gridview->setCurrentIndex(firstVisibleIndex);
635 qApp->processEvents();
636 QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex);
637 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex);
639 QCOMPARE(item->y(), gridview->contentY());
641 QList<QPair<QString, QString> > newData;
642 for (int i=0; i<insertCount; i++)
643 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
644 model.insertItems(insertIndex, newData);
645 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
647 // now, moving to the top of the view should position the inserted items correctly
648 int itemsOffsetAfterMove = (insertCount / 3) * -60.0;
649 gridview->setCurrentIndex(0);
650 QTRY_COMPARE(gridview->currentIndex(), 0);
651 QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove);
653 // Confirm items positioned correctly and indexes correct
654 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
655 for (int i = 0; i < model.count() && i < itemCount; ++i) {
656 item = findItem<QQuickItem>(contentItem, "wrapper", i);
657 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
658 QCOMPARE(item->x(), (i%3)*80.0);
659 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
660 name = findItem<QQuickText>(contentItem, "textName", i);
662 QTRY_COMPARE(name->text(), model.name(i));
668 void tst_QQuickGridView::insertBeforeVisible_data()
670 QTest::addColumn<int>("insertIndex");
671 QTest::addColumn<int>("insertCount");
672 QTest::addColumn<int>("cacheBuffer");
674 QTest::newRow("insert 1 at 0, 0 buffer") << 0 << 1 << 0;
675 QTest::newRow("insert 1 at 0, 100 buffer") << 0 << 1 << 100;
676 QTest::newRow("insert 1 at 0, 500 buffer") << 0 << 1 << 500;
678 QTest::newRow("insert 1 at 1, 0 buffer") << 1 << 1 << 0;
679 QTest::newRow("insert 1 at 1, 100 buffer") << 1 << 1 << 100;
680 QTest::newRow("insert 1 at 1, 500 buffer") << 1 << 1 << 500;
682 QTest::newRow("insert multiple at 0, 0 buffer") << 0 << 6 << 0;
683 QTest::newRow("insert multiple at 0, 100 buffer") << 0 << 6 << 100;
684 QTest::newRow("insert multiple at 0, 500 buffer") << 0 << 6 << 500;
686 QTest::newRow("insert multiple at 1, 0 buffer") << 1 << 6 << 0;
687 QTest::newRow("insert multiple at 1, 100 buffer") << 1 << 6 << 100;
688 QTest::newRow("insert multiple at 1, 500 buffer") << 1 << 6 << 500;
691 void tst_QQuickGridView::removed()
693 QQuickView *canvas = createView();
697 for (int i = 0; i < 40; i++)
698 model.addItem("Item" + QString::number(i), "");
700 QDeclarativeContext *ctxt = canvas->rootContext();
701 ctxt->setContextProperty("testModel", &model);
702 ctxt->setContextProperty("testRightToLeft", QVariant(false));
703 ctxt->setContextProperty("testTopToBottom", QVariant(false));
705 canvas->setSource(testFileUrl("gridview1.qml"));
706 qApp->processEvents();
708 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
709 QTRY_VERIFY(gridview != 0);
711 QQuickItem *contentItem = gridview->contentItem();
712 QTRY_VERIFY(contentItem != 0);
715 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
717 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
718 QTRY_VERIFY(name != 0);
719 QTRY_COMPARE(name->text(), model.name(1));
720 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
721 QTRY_VERIFY(number != 0);
722 QTRY_COMPARE(number->text(), model.number(1));
725 // Checks that onRemove is called
726 QString removed = canvas->rootObject()->property("removed").toString();
727 QTRY_COMPARE(removed, QString("Item1"));
729 // Confirm items positioned correctly
730 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
731 for (int i = 0; i < model.count() && i < itemCount; ++i) {
732 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
733 if (!item) qWarning() << "Item" << i << "not found";
734 QTRY_VERIFY(item->x() == (i%3)*80);
735 QTRY_VERIFY(item->y() == (i/3)*60);
738 // Remove first item (which is the current item);
740 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
742 name = findItem<QQuickText>(contentItem, "textName", 0);
743 QTRY_VERIFY(name != 0);
744 QTRY_COMPARE(name->text(), model.name(0));
745 number = findItem<QQuickText>(contentItem, "textNumber", 0);
746 QTRY_VERIFY(number != 0);
747 QTRY_COMPARE(number->text(), model.number(0));
750 // Confirm items positioned correctly
751 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
752 for (int i = 0; i < model.count() && i < itemCount; ++i) {
753 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
754 if (!item) qWarning() << "Item" << i << "not found";
755 QTRY_VERIFY(item->x() == (i%3)*80);
756 QTRY_VERIFY(item->y() == (i/3)*60);
759 // Remove items not visible
760 model.removeItem(25);
761 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
763 // Confirm items positioned correctly
764 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
765 for (int i = 0; i < model.count() && i < itemCount; ++i) {
766 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
767 if (!item) qWarning() << "Item" << i << "not found";
768 QTRY_VERIFY(item->x() == (i%3)*80);
769 QTRY_VERIFY(item->y() == (i/3)*60);
772 // Remove items before visible
773 gridview->setContentY(120);
774 gridview->setCurrentIndex(10);
776 // Setting currentIndex above shouldn't cause view to scroll
777 QTRY_COMPARE(gridview->contentY(), 120.0);
780 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
782 // Confirm items positioned correctly
783 for (int i = 6; i < 18; ++i) {
784 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
785 if (!item) qWarning() << "Item" << i << "not found";
786 QTRY_VERIFY(item->x() == (i%3)*80);
787 QTRY_VERIFY(item->y() == (i/3)*60);
790 // Remove currentIndex
791 QQuickItem *oldCurrent = gridview->currentItem();
793 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
795 QTRY_COMPARE(gridview->currentIndex(), 9);
796 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
798 gridview->setContentY(0);
799 // let transitions settle.
802 // Confirm items positioned correctly
803 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
804 for (int i = 0; i < model.count() && i < itemCount; ++i) {
805 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
806 QTRY_VERIFY(item->x() == (i%3)*80);
807 QTRY_VERIFY(item->y() == (i/3)*60);
810 // remove item outside current view.
811 gridview->setCurrentIndex(32);
812 gridview->setContentY(240);
814 model.removeItem(30);
815 QTRY_VERIFY(gridview->currentIndex() == 31);
817 // remove current item beyond visible items.
818 gridview->setCurrentIndex(20);
819 gridview->setContentY(0);
820 model.removeItem(20);
822 QTRY_COMPARE(gridview->currentIndex(), 20);
823 QTRY_VERIFY(gridview->currentItem() != 0);
825 // remove item before current, but visible
826 gridview->setCurrentIndex(8);
827 gridview->setContentY(240);
828 oldCurrent = gridview->currentItem();
831 QTRY_COMPARE(gridview->currentIndex(), 7);
832 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
837 void tst_QQuickGridView::removed_more()
839 QFETCH(qreal, contentY);
840 QFETCH(int, removeIndex);
841 QFETCH(int, removeCount);
842 QFETCH(qreal, itemsOffsetAfterMove);
843 QFETCH(QString, firstVisible);
847 QQuickView *canvas = createView();
851 for (int i = 0; i < 30; i++)
852 model.addItem("Item" + QString::number(i), "");
854 QDeclarativeContext *ctxt = canvas->rootContext();
855 ctxt->setContextProperty("testModel", &model);
856 ctxt->setContextProperty("testRightToLeft", QVariant(false));
857 ctxt->setContextProperty("testTopToBottom", QVariant(false));
858 canvas->setSource(testFileUrl("gridview1.qml"));
859 qApp->processEvents();
861 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
862 QTRY_VERIFY(gridview != 0);
863 QQuickItem *contentItem = gridview->contentItem();
864 QTRY_VERIFY(contentItem != 0);
866 gridview->setContentY(contentY);
867 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
869 model.removeItems(removeIndex, removeCount);
870 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
873 int firstVisibleIndex = -1;
874 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
875 for (int i=0; i<items.count(); i++) {
876 if (items[i]->y() >= contentY) {
877 QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
878 firstVisibleIndex = e.evaluate().toInt();
879 QDeclarativeExpression en(qmlContext(items[i]), items[i], "name");
880 firstName = en.evaluate().toString();
884 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
885 QCOMPARE(firstName, firstVisible);
887 // Confirm items positioned correctly and indexes correct
888 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
889 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
890 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
891 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
893 QTRY_COMPARE(item->x(), (i%3)*80.0);
894 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
896 name = findItem<QQuickText>(contentItem, "textName", i);
898 QTRY_COMPARE(name->text(), model.name(i));
899 number = findItem<QQuickText>(contentItem, "textNumber", i);
900 QVERIFY(number != 0);
901 QTRY_COMPARE(number->text(), model.number(i));
907 void tst_QQuickGridView::removed_more_data()
909 QTest::addColumn<qreal>("contentY");
910 QTest::addColumn<int>("removeIndex");
911 QTest::addColumn<int>("removeCount");
912 QTest::addColumn<qreal>("itemsOffsetAfterMove");
913 QTest::addColumn<QString>("firstVisible");
915 QTest::newRow("remove 1, before visible items")
916 << 120.0 // show 6-23
920 QTest::newRow("remove multiple, all before visible items")
923 << 60.0 << "Item6"; // removed top row, slide down by 1 row
925 QTest::newRow("remove multiple, all before visible items, remove item 0")
928 << 60.0 << "Item7"; // removed top row, slide down by 1 row
930 QTest::newRow("remove multiple rows, all before visible items")
931 << 240.0 // show 12-29
933 << 120.0 << "Item13";
936 // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos,
937 // items 6,7 are removed from view, item 8 slides up to original pos of item 6 (120px)
938 QTest::newRow("remove multiple, mix of items from before and within visible items")
941 << 60.0 << "Item8"; // adjust for the 1 row removed before the visible
943 QTest::newRow("remove multiple, mix of items from before and within visible items, remove item 0")
946 << 60.0 * 2 << "Item8"; // adjust for the 2 rows removed before the visible
949 QTest::newRow("remove 1, from start of visible, content at start")
954 QTest::newRow("remove multiple, from start of visible, content at start")
959 QTest::newRow("remove 1, from start of visible, content not at start")
960 << 120.0 // show 6-23
964 QTest::newRow("remove multiple, from start of visible, content not at start")
965 << 120.0 // show 6-23
970 QTest::newRow("remove 1, from middle of visible, content at start")
975 QTest::newRow("remove multiple, from middle of visible, content at start")
980 QTest::newRow("remove 1, from middle of visible, content not at start")
981 << 120.0 // show 6-23
985 QTest::newRow("remove multiple, from middle of visible, content not at start")
986 << 120.0 // show 6-23
991 QTest::newRow("remove 1, after visible, content at start")
996 QTest::newRow("remove multiple, after visible, content at start")
1001 QTest::newRow("remove 1, after visible, content not at start")
1002 << 120.0 // show 6-23
1006 QTest::newRow("remove multiple, after visible, content not at start")
1007 << 120.0 // show 6-23
1011 QTest::newRow("remove multiple, mix of items from within and after visible items")
1012 << 120.0 // show 6-23
1017 void tst_QQuickGridView::addOrRemoveBeforeVisible()
1019 // QTBUG-21588: ensure re-layout is done on grid after adding or removing
1020 // items from before the visible area
1022 QFETCH(bool, doAdd);
1023 QFETCH(qreal, newTopContentY);
1025 QQuickView *canvas = createView();
1029 for (int i = 0; i < 30; i++)
1030 model.addItem("Item" + QString::number(i), "");
1032 QDeclarativeContext *ctxt = canvas->rootContext();
1033 ctxt->setContextProperty("testModel", &model);
1034 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1035 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1036 canvas->setSource(testFileUrl("gridview1.qml"));
1038 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1039 QTRY_VERIFY(gridview != 0);
1040 QQuickItem *contentItem = gridview->contentItem();
1041 QTRY_VERIFY(contentItem != 0);
1043 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
1044 QTRY_COMPARE(name->text(), QString("Item0"));
1046 gridview->setCurrentIndex(0);
1047 qApp->processEvents();
1048 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1050 // scroll down until item 0 is no longer drawn
1051 // (bug not triggered if we just move using content y, since that doesn't
1052 // refill and change the visible items)
1053 gridview->setCurrentIndex(24);
1054 qApp->processEvents();
1056 QTRY_COMPARE(gridview->currentIndex(), 24);
1057 QTRY_COMPARE(gridview->contentY(), 220.0);
1059 QTest::qWait(100); // wait for refill to complete
1060 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible
1063 model.insertItem(0, "New Item", "New Item number");
1064 QTRY_COMPARE(gridview->count(), 31);
1066 model.removeItem(0);
1067 QTRY_COMPARE(gridview->count(), 29);
1070 // scroll back up and item 0 should be gone
1071 gridview->setCurrentIndex(0);
1072 qApp->processEvents();
1073 QTRY_COMPARE(gridview->currentIndex(), 0);
1074 QTRY_COMPARE(gridview->contentY(), newTopContentY);
1076 name = findItem<QQuickText>(contentItem, "textName", 0);
1078 QCOMPARE(name->text(), QString("New Item"));
1080 QCOMPARE(name->text(), QString("Item1"));
1082 // Confirm items positioned correctly
1083 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1084 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1085 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i));
1086 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1087 QTRY_VERIFY(item->x() == (i%3)*80);
1088 QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY);
1094 void tst_QQuickGridView::addOrRemoveBeforeVisible_data()
1096 QTest::addColumn<bool>("doAdd");
1097 QTest::addColumn<qreal>("newTopContentY");
1099 QTest::newRow("add") << true << -60.0;
1100 QTest::newRow("remove") << false << -60.0;
1103 void tst_QQuickGridView::clear()
1105 QQuickView *canvas = createView();
1108 for (int i = 0; i < 30; i++)
1109 model.addItem("Item" + QString::number(i), "");
1111 QDeclarativeContext *ctxt = canvas->rootContext();
1112 ctxt->setContextProperty("testModel", &model);
1113 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1114 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1116 canvas->setSource(testFileUrl("gridview1.qml"));
1117 qApp->processEvents();
1119 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1120 QVERIFY(gridview != 0);
1122 QQuickItem *contentItem = gridview->contentItem();
1123 QVERIFY(contentItem != 0);
1127 QVERIFY(gridview->count() == 0);
1128 QVERIFY(gridview->currentItem() == 0);
1129 QVERIFY(gridview->contentY() == 0);
1130 QVERIFY(gridview->currentIndex() == -1);
1132 // confirm sanity when adding an item to cleared list
1133 model.addItem("New", "1");
1134 QTRY_COMPARE(gridview->count(), 1);
1135 QVERIFY(gridview->currentItem() != 0);
1136 QVERIFY(gridview->currentIndex() == 0);
1141 void tst_QQuickGridView::moved()
1143 QFETCH(qreal, contentY);
1147 QFETCH(qreal, itemsOffsetAfterMove);
1151 QScopedPointer<QQuickView> canvas(createView());
1155 for (int i = 0; i < 30; i++)
1156 model.addItem("Item" + QString::number(i), "");
1158 QDeclarativeContext *ctxt = canvas->rootContext();
1159 ctxt->setContextProperty("testModel", &model);
1160 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1161 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1163 canvas->setSource(testFileUrl("gridview1.qml"));
1164 qApp->processEvents();
1166 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1167 QTRY_VERIFY(gridview != 0);
1169 QQuickItem *contentItem = gridview->contentItem();
1170 QTRY_VERIFY(contentItem != 0);
1172 QQuickItem *currentItem = gridview->currentItem();
1173 QTRY_VERIFY(currentItem != 0);
1175 gridview->setContentY(contentY);
1176 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1178 model.moveItems(from, to, count);
1179 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1181 // Confirm items positioned correctly and indexes correct
1182 int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
1183 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1184 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
1185 if (i >= firstVisibleIndex + 18) // index has moved out of view
1187 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1188 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1190 QTRY_COMPARE(item->x(), (i%3)*80.0);
1191 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
1193 name = findItem<QQuickText>(contentItem, "textName", i);
1195 QTRY_COMPARE(name->text(), model.name(i));
1196 number = findItem<QQuickText>(contentItem, "textNumber", i);
1197 QVERIFY(number != 0);
1198 QTRY_COMPARE(number->text(), model.number(i));
1200 // current index should have been updated
1201 if (item == currentItem)
1202 QTRY_COMPARE(gridview->currentIndex(), i);
1206 void tst_QQuickGridView::moved_data()
1208 QTest::addColumn<qreal>("contentY");
1209 QTest::addColumn<int>("from");
1210 QTest::addColumn<int>("to");
1211 QTest::addColumn<int>("count");
1212 QTest::addColumn<qreal>("itemsOffsetAfterMove");
1214 // model starts with 30 items, each 80x60, in area 240x320
1215 // 18 items should be visible at a time
1217 // The first visible item should not move upwards and out of the view
1218 // if items are moved/removed before it.
1221 QTest::newRow("move 1 forwards, within visible items")
1226 QTest::newRow("move 1 forwards, from non-visible -> visible")
1227 << 120.0 // show 6-23
1231 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
1232 << 120.0 // // show 6-23
1236 QTest::newRow("move 1 forwards, from visible -> non-visible")
1241 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
1247 QTest::newRow("move 1 backwards, within visible items")
1252 QTest::newRow("move 1 backwards, within visible items (to first index)")
1257 QTest::newRow("move 1 backwards, from non-visible -> visible")
1262 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
1267 QTest::newRow("move 1 backwards, from visible -> non-visible")
1268 << 120.0 // show 6-23
1270 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1272 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
1273 << 120.0 // show 6-23
1275 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1278 QTest::newRow("move multiple forwards, within visible items")
1283 QTest::newRow("move multiple backwards, within visible items (move first item)")
1288 QTest::newRow("move multiple forwards, before visible items")
1289 << 120.0 // show 6-23
1290 << 3 << 4 << 3 // 3, 4, 5 move to after 6
1291 << 60.0; // row of 3,4,5 has moved down
1293 QTest::newRow("move multiple forwards, from non-visible -> visible")
1294 << 120.0 // show 6-23
1296 << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
1298 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
1299 << 120.0 // show 6-23
1301 << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
1303 QTest::newRow("move multiple forwards, mix of non-visible/visible")
1306 << 60.0; // top two rows removed, third row is now the first visible
1308 QTest::newRow("move multiple forwards, to bottom of view")
1313 QTest::newRow("move multiple forwards, to bottom of view, first row -> last")
1318 QTest::newRow("move multiple forwards, to bottom of view, content y not 0")
1323 QTest::newRow("move multiple forwards, from visible -> non-visible")
1328 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
1334 QTest::newRow("move multiple backwards, within visible items")
1339 QTest::newRow("move multiple backwards, from non-visible -> visible")
1344 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
1349 QTest::newRow("move multiple backwards, from visible -> non-visible")
1350 << 120.0 // show 6-23
1352 << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
1354 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
1355 << 120.0 // show 6-23
1357 << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
1361 enum { Inserted, Removed, Moved, SetCurrent } type;
1366 static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
1367 static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
1368 static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
1369 static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
1371 Q_DECLARE_METATYPE(QList<ListChange>)
1373 void tst_QQuickGridView::multipleChanges()
1375 QFETCH(int, startCount);
1376 QFETCH(QList<ListChange>, changes);
1377 QFETCH(int, newCount);
1378 QFETCH(int, newCurrentIndex);
1380 QQuickView *canvas = createView();
1384 for (int i = 0; i < startCount; i++)
1385 model.addItem("Item" + QString::number(i), "");
1387 QDeclarativeContext *ctxt = canvas->rootContext();
1388 ctxt->setContextProperty("testModel", &model);
1389 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1390 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1392 canvas->setSource(testFileUrl("gridview1.qml"));
1393 qApp->processEvents();
1395 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1396 QTRY_VERIFY(gridview != 0);
1398 for (int i=0; i<changes.count(); i++) {
1399 switch (changes[i].type) {
1400 case ListChange::Inserted:
1402 QList<QPair<QString, QString> > items;
1403 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1404 items << qMakePair(QString("new item " + j), QString::number(j));
1405 model.insertItems(changes[i].index, items);
1408 case ListChange::Removed:
1409 model.removeItems(changes[i].index, changes[i].count);
1411 case ListChange::Moved:
1412 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1414 case ListChange::SetCurrent:
1415 gridview->setCurrentIndex(changes[i].index);
1420 QTRY_COMPARE(gridview->count(), newCount);
1421 QCOMPARE(gridview->count(), model.count());
1422 QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
1426 QQuickItem *contentItem = gridview->contentItem();
1427 QTRY_VERIFY(contentItem != 0);
1428 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1429 for (int i=0; i < model.count() && i < itemCount; ++i) {
1430 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1431 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1432 name = findItem<QQuickText>(contentItem, "textName", i);
1434 QTRY_COMPARE(name->text(), model.name(i));
1435 number = findItem<QQuickText>(contentItem, "textNumber", i);
1436 QVERIFY(number != 0);
1437 QTRY_COMPARE(number->text(), model.number(i));
1443 void tst_QQuickGridView::multipleChanges_data()
1445 QTest::addColumn<int>("startCount");
1446 QTest::addColumn<QList<ListChange> >("changes");
1447 QTest::addColumn<int>("newCount");
1448 QTest::addColumn<int>("newCurrentIndex");
1450 QList<ListChange> changes;
1452 for (int i=1; i<30; i++)
1453 changes << ListChange::remove(0);
1454 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1456 changes << ListChange::remove(0);
1457 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1460 changes << ListChange::setCurrent(29);
1461 for (int i=29; i>0; i--)
1462 changes << ListChange::remove(i);
1463 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1465 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1466 << ListChange::remove(0, 1)
1467 << ListChange::insert(0, 1)
1470 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1471 << ListChange::setCurrent(2)
1472 << ListChange::remove(2, 1)
1473 << ListChange::insert(2, 1)
1476 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1477 << ListChange::setCurrent(1)
1478 << ListChange::remove(1, 3)
1479 << ListChange::insert(2, 2)
1482 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1483 << ListChange::setCurrent(2)
1484 << ListChange::remove(1, 3)
1485 << ListChange::move(1, 5, 1)
1488 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1489 << ListChange::setCurrent(5)
1490 << ListChange::remove(4, 3)
1491 << ListChange::move(4, 1, 1)
1495 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1496 << ListChange::insert(0, 2)
1497 << ListChange::insert(0, 4)
1498 << ListChange::insert(0, 6)
1501 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1502 << ListChange::insert(0, 2)
1503 << ListChange::insert(0, 4)
1504 << ListChange::insert(0, 6)
1505 << ListChange::setCurrent(3)
1506 << ListChange::insert(3, 2)
1509 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1510 << ListChange::insert(0, 30)
1511 << ListChange::remove(0, 30)
1514 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1515 << ListChange::insert(1)
1516 << ListChange::setCurrent(1)
1517 << ListChange::remove(1)
1520 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1521 << ListChange::insert(0, 10)
1522 << ListChange::remove(5, 10)
1525 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1526 << ListChange::insert(0, 3)
1527 << ListChange::move(0, 10, 3)
1530 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1531 << ListChange::insert(0, 3)
1532 << ListChange::move(0, 8, 5)
1535 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1536 << ListChange::setCurrent(9)
1537 << ListChange::insert(10, 3)
1538 << ListChange::move(8, 0, 5)
1542 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1543 << ListChange::setCurrent(1)
1544 << ListChange::move(1, 2, 2)
1545 << ListChange::move(2, 1, 2)
1548 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1549 << ListChange::setCurrent(2)
1550 << ListChange::move(1, 2, 3)
1551 << ListChange::move(3, 0, 5)
1554 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1555 << ListChange::setCurrent(5)
1556 << ListChange::move(5, 0, 1)
1557 << ListChange::remove(0)
1560 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1561 << ListChange::setCurrent(5)
1562 << ListChange::move(5, 0, 1)
1563 << ListChange::insert(0)
1566 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1567 << ListChange::setCurrent(1)
1568 << ListChange::move(5, 1, 3)
1569 << ListChange::remove(1, 3)
1572 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1573 << ListChange::setCurrent(5)
1574 << ListChange::move(5, 1, 3)
1575 << ListChange::insert(1, 5)
1578 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1579 << ListChange::setCurrent(3)
1580 << ListChange::move(0, 1, 2)
1581 << ListChange::insert(3, 5)
1585 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1586 << ListChange::insert(0, 5)
1587 << ListChange::setCurrent(-1)
1588 << ListChange::remove(0, 5)
1589 << ListChange::insert(0, 5)
1594 void tst_QQuickGridView::swapWithFirstItem()
1597 QQuickView *canvas = createView();
1601 for (int i = 0; i < 30; i++)
1602 model.addItem("Item" + QString::number(i), "");
1604 QDeclarativeContext *ctxt = canvas->rootContext();
1605 ctxt->setContextProperty("testModel", &model);
1606 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1607 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1609 canvas->setSource(testFileUrl("gridview1.qml"));
1610 qApp->processEvents();
1612 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1613 QTRY_VERIFY(gridview != 0);
1615 // ensure content position is stable
1616 gridview->setContentY(0);
1617 model.moveItem(10, 0);
1618 QTRY_VERIFY(gridview->contentY() == 0);
1623 void tst_QQuickGridView::currentIndex()
1626 for (int i = 0; i < 60; i++)
1627 model.addItem("Item" + QString::number(i), QString::number(i));
1629 QQuickView *canvas = new QQuickView(0);
1630 canvas->setGeometry(0,0,240,320);
1633 QDeclarativeContext *ctxt = canvas->rootContext();
1634 ctxt->setContextProperty("testModel", &model);
1636 QString filename(testFile("gridview-initCurrent.qml"));
1637 canvas->setSource(QUrl::fromLocalFile(filename));
1639 qApp->processEvents();
1641 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1642 QVERIFY(gridview != 0);
1643 QTRY_VERIFY(!QQuickItemPrivate::get(gridview)->polishScheduled);
1645 QQuickItem *contentItem = gridview->contentItem();
1646 QVERIFY(contentItem != 0);
1648 // current item should be third item
1649 QCOMPARE(gridview->currentIndex(), 35);
1650 QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35));
1651 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1652 QCOMPARE(gridview->contentY(), 400.0);
1654 gridview->moveCurrentIndexRight();
1655 QCOMPARE(gridview->currentIndex(), 36);
1656 gridview->moveCurrentIndexDown();
1657 QCOMPARE(gridview->currentIndex(), 39);
1658 gridview->moveCurrentIndexUp();
1659 QCOMPARE(gridview->currentIndex(), 36);
1660 gridview->moveCurrentIndexLeft();
1661 QCOMPARE(gridview->currentIndex(), 35);
1663 // wait until motion stops
1664 QTRY_VERIFY(gridview->verticalVelocity() == 0.0);
1667 gridview->setCurrentIndex(0);
1668 QCOMPARE(gridview->currentIndex(), 0);
1669 // confirm that the velocity is updated
1670 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1672 gridview->moveCurrentIndexUp();
1673 QCOMPARE(gridview->currentIndex(), 0);
1675 gridview->moveCurrentIndexLeft();
1676 QCOMPARE(gridview->currentIndex(), 0);
1678 gridview->setCurrentIndex(model.count()-1);
1679 QCOMPARE(gridview->currentIndex(), model.count()-1);
1681 gridview->moveCurrentIndexRight();
1682 QCOMPARE(gridview->currentIndex(), model.count()-1);
1684 gridview->moveCurrentIndexDown();
1685 QCOMPARE(gridview->currentIndex(), model.count()-1);
1688 gridview->setWrapEnabled(true);
1690 gridview->setCurrentIndex(0);
1691 QCOMPARE(gridview->currentIndex(), 0);
1693 gridview->moveCurrentIndexLeft();
1694 QCOMPARE(gridview->currentIndex(), model.count()-1);
1696 qApp->processEvents();
1697 QTRY_COMPARE(gridview->contentY(), 880.0);
1699 gridview->moveCurrentIndexRight();
1700 QCOMPARE(gridview->currentIndex(), 0);
1702 QTRY_COMPARE(gridview->contentY(), 0.0);
1705 // footer should become visible if it is out of view, and then current index moves to the first row
1706 canvas->rootObject()->setProperty("showFooter", true);
1707 QTRY_VERIFY(gridview->footerItem());
1708 gridview->setCurrentIndex(model.count()-3);
1709 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1710 gridview->setCurrentIndex(model.count()-2);
1711 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1712 canvas->rootObject()->setProperty("showFooter", false);
1714 // header should become visible if it is out of view, and then current index moves to the last row
1715 canvas->rootObject()->setProperty("showHeader", true);
1716 QTRY_VERIFY(gridview->headerItem());
1717 gridview->setCurrentIndex(3);
1718 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1719 gridview->setCurrentIndex(1);
1720 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1721 canvas->rootObject()->setProperty("showHeader", false);
1725 canvas->requestActivateWindow();
1726 QTest::qWaitForWindowShown(canvas);
1727 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1729 gridview->setCurrentIndex(0);
1731 QTest::keyClick(canvas, Qt::Key_Down);
1732 QCOMPARE(gridview->currentIndex(), 3);
1734 QTest::keyClick(canvas, Qt::Key_Up);
1735 QCOMPARE(gridview->currentIndex(), 0);
1737 // hold down Key_Down
1738 for (int i=0; i<(model.count() / 3) - 1; i++) {
1739 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1740 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1742 QTest::keyRelease(canvas, Qt::Key_Down);
1743 QTRY_COMPARE(gridview->currentIndex(), 57);
1744 QTRY_COMPARE(gridview->contentY(), 880.0);
1747 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1748 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1749 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1751 QTest::keyRelease(canvas, Qt::Key_Up);
1752 QTRY_COMPARE(gridview->currentIndex(), 0);
1753 QTRY_COMPARE(gridview->contentY(), 0.0);
1756 gridview->setFlow(QQuickGridView::TopToBottom);
1758 canvas->requestActivateWindow();
1759 QTest::qWaitForWindowShown(canvas);
1760 QVERIFY(qGuiApp->focusWindow() == canvas);
1761 qApp->processEvents();
1763 QTest::keyClick(canvas, Qt::Key_Right);
1764 QCOMPARE(gridview->currentIndex(), 5);
1766 QTest::keyClick(canvas, Qt::Key_Left);
1767 QCOMPARE(gridview->currentIndex(), 0);
1769 QTest::keyClick(canvas, Qt::Key_Down);
1770 QCOMPARE(gridview->currentIndex(), 1);
1772 QTest::keyClick(canvas, Qt::Key_Up);
1773 QCOMPARE(gridview->currentIndex(), 0);
1775 // hold down Key_Right
1776 for (int i=0; i<(model.count() / 5) - 1; i++) {
1777 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1778 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1781 QTest::keyRelease(canvas, Qt::Key_Right);
1782 QTRY_COMPARE(gridview->currentIndex(), 55);
1783 QTRY_COMPARE(gridview->contentX(), 720.0);
1785 // hold down Key_Left
1786 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1787 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1788 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1790 QTest::keyRelease(canvas, Qt::Key_Left);
1791 QTRY_COMPARE(gridview->currentIndex(), 0);
1792 QTRY_COMPARE(gridview->contentX(), 0.0);
1795 // turn off auto highlight
1796 gridview->setHighlightFollowsCurrentItem(false);
1797 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1798 QVERIFY(gridview->highlightItem());
1799 qreal hlPosX = gridview->highlightItem()->x();
1800 qreal hlPosY = gridview->highlightItem()->y();
1802 gridview->setCurrentIndex(5);
1803 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1804 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1806 // insert item before currentIndex
1807 gridview->setCurrentIndex(28);
1808 model.insertItem(0, "Foo", "1111");
1809 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1811 // check removing highlight by setting currentIndex to -1;
1812 gridview->setCurrentIndex(-1);
1814 QCOMPARE(gridview->currentIndex(), -1);
1815 QVERIFY(!gridview->highlightItem());
1816 QVERIFY(!gridview->currentItem());
1818 gridview->setHighlightFollowsCurrentItem(true);
1820 gridview->setFlow(QQuickGridView::LeftToRight);
1821 gridview->setLayoutDirection(Qt::RightToLeft);
1823 canvas->requestActivateWindow();
1824 QTest::qWaitForWindowShown(canvas);
1825 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1826 qApp->processEvents();
1828 gridview->setCurrentIndex(35);
1830 QTest::keyClick(canvas, Qt::Key_Right);
1831 QCOMPARE(gridview->currentIndex(), 34);
1833 QTest::keyClick(canvas, Qt::Key_Down);
1834 QCOMPARE(gridview->currentIndex(), 37);
1836 QTest::keyClick(canvas, Qt::Key_Up);
1837 QCOMPARE(gridview->currentIndex(), 34);
1839 QTest::keyClick(canvas, Qt::Key_Left);
1840 QCOMPARE(gridview->currentIndex(), 35);
1843 // turn off auto highlight
1844 gridview->setHighlightFollowsCurrentItem(false);
1845 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1846 QVERIFY(gridview->highlightItem());
1847 hlPosX = gridview->highlightItem()->x();
1848 hlPosY = gridview->highlightItem()->y();
1850 gridview->setCurrentIndex(5);
1851 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1852 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1854 // insert item before currentIndex
1855 gridview->setCurrentIndex(28);
1856 model.insertItem(0, "Foo", "1111");
1857 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1859 // check removing highlight by setting currentIndex to -1;
1860 gridview->setCurrentIndex(-1);
1862 QCOMPARE(gridview->currentIndex(), -1);
1863 QVERIFY(!gridview->highlightItem());
1864 QVERIFY(!gridview->currentItem());
1869 void tst_QQuickGridView::noCurrentIndex()
1872 for (int i = 0; i < 60; i++)
1873 model.addItem("Item" + QString::number(i), QString::number(i));
1875 QQuickView *canvas = new QQuickView(0);
1876 canvas->setGeometry(0,0,240,320);
1878 QDeclarativeContext *ctxt = canvas->rootContext();
1879 ctxt->setContextProperty("testModel", &model);
1881 QString filename(testFile("gridview-noCurrent.qml"));
1882 canvas->setSource(QUrl::fromLocalFile(filename));
1884 qApp->processEvents();
1886 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1887 QVERIFY(gridview != 0);
1889 QQuickItem *contentItem = gridview->contentItem();
1890 QVERIFY(contentItem != 0);
1892 // current index should be -1
1893 QCOMPARE(gridview->currentIndex(), -1);
1894 QVERIFY(!gridview->currentItem());
1895 QVERIFY(!gridview->highlightItem());
1896 QCOMPARE(gridview->contentY(), 0.0);
1898 gridview->setCurrentIndex(5);
1899 QCOMPARE(gridview->currentIndex(), 5);
1900 QVERIFY(gridview->currentItem());
1901 QVERIFY(gridview->highlightItem());
1906 void tst_QQuickGridView::changeFlow()
1908 QQuickView *canvas = createView();
1911 for (int i = 0; i < 30; i++)
1912 model.addItem("Item" + QString::number(i), QString::number(i));
1914 QDeclarativeContext *ctxt = canvas->rootContext();
1915 ctxt->setContextProperty("testModel", &model);
1916 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1917 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1919 canvas->setSource(testFileUrl("gridview1.qml"));
1920 qApp->processEvents();
1922 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1923 QTRY_VERIFY(gridview != 0);
1925 QQuickItem *contentItem = gridview->contentItem();
1926 QTRY_VERIFY(contentItem != 0);
1928 // Confirm items positioned correctly and indexes correct
1929 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1930 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1931 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1932 if (!item) qWarning() << "Item" << i << "not found";
1934 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1935 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1936 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1937 QTRY_VERIFY(name != 0);
1938 QTRY_COMPARE(name->text(), model.name(i));
1939 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1940 QTRY_VERIFY(number != 0);
1941 QTRY_COMPARE(number->text(), model.number(i));
1944 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1946 // Confirm items positioned correctly and indexes correct
1947 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1948 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1949 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1950 if (!item) qWarning() << "Item" << i << "not found";
1952 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1953 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1954 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1955 QTRY_VERIFY(name != 0);
1956 QTRY_COMPARE(name->text(), model.name(i));
1957 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1958 QTRY_VERIFY(number != 0);
1959 QTRY_COMPARE(number->text(), model.number(i));
1962 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1964 // Confirm items positioned correctly and indexes correct
1965 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1966 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1967 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1968 if (!item) qWarning() << "Item" << i << "not found";
1970 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1971 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1972 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1973 QTRY_VERIFY(name != 0);
1974 QTRY_COMPARE(name->text(), model.name(i));
1975 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1976 QTRY_VERIFY(number != 0);
1977 QTRY_COMPARE(number->text(), model.number(i));
1979 gridview->setContentX(100);
1980 QTRY_COMPARE(gridview->contentX(), 100.);
1981 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1982 QTRY_COMPARE(gridview->contentX(), 0.);
1984 // Confirm items positioned correctly and indexes correct
1985 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1986 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1987 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1988 if (!item) qWarning() << "Item" << i << "not found";
1990 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1991 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1992 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1993 QTRY_VERIFY(name != 0);
1994 QTRY_COMPARE(name->text(), model.name(i));
1995 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1996 QTRY_VERIFY(number != 0);
1997 QTRY_COMPARE(number->text(), model.number(i));
2003 void tst_QQuickGridView::defaultValues()
2005 QDeclarativeEngine engine;
2006 QDeclarativeComponent c(&engine, testFileUrl("gridview3.qml"));
2007 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
2009 QTRY_VERIFY(obj != 0);
2010 QTRY_VERIFY(obj->model() == QVariant());
2011 QTRY_VERIFY(obj->delegate() == 0);
2012 QTRY_COMPARE(obj->currentIndex(), -1);
2013 QTRY_VERIFY(obj->currentItem() == 0);
2014 QTRY_COMPARE(obj->count(), 0);
2015 QTRY_VERIFY(obj->highlight() == 0);
2016 QTRY_VERIFY(obj->highlightItem() == 0);
2017 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
2018 QTRY_VERIFY(obj->flow() == 0);
2019 QTRY_COMPARE(obj->isWrapEnabled(), false);
2020 QTRY_COMPARE(obj->cacheBuffer(), 0);
2021 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
2022 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2026 void tst_QQuickGridView::properties()
2028 QDeclarativeEngine engine;
2029 QDeclarativeComponent c(&engine, testFileUrl("gridview2.qml"));
2030 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
2032 QTRY_VERIFY(obj != 0);
2033 QTRY_VERIFY(obj->model() != QVariant());
2034 QTRY_VERIFY(obj->delegate() != 0);
2035 QTRY_COMPARE(obj->currentIndex(), 0);
2036 QTRY_VERIFY(obj->currentItem() != 0);
2037 QTRY_COMPARE(obj->count(), 4);
2038 QTRY_VERIFY(obj->highlight() != 0);
2039 QTRY_VERIFY(obj->highlightItem() != 0);
2040 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
2041 QTRY_VERIFY(obj->flow() == 0);
2042 QTRY_COMPARE(obj->isWrapEnabled(), true);
2043 QTRY_COMPARE(obj->cacheBuffer(), 200);
2044 QTRY_COMPARE(obj->cellWidth(), qreal(100));
2045 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2049 void tst_QQuickGridView::propertyChanges()
2051 QQuickView *canvas = createView();
2052 QTRY_VERIFY(canvas);
2053 canvas->setSource(testFileUrl("propertychangestest.qml"));
2055 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2056 QTRY_VERIFY(gridView);
2058 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
2059 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
2060 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
2061 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
2063 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2064 QTRY_COMPARE(gridView->cacheBuffer(), 10);
2065 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
2067 gridView->setWrapEnabled(false);
2068 gridView->setCacheBuffer(3);
2069 gridView->setFlow(QQuickGridView::TopToBottom);
2071 QTRY_COMPARE(gridView->isWrapEnabled(), false);
2072 QTRY_COMPARE(gridView->cacheBuffer(), 3);
2073 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
2075 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2076 QTRY_COMPARE(cacheBufferSpy.count(),1);
2077 QTRY_COMPARE(flowSpy.count(),1);
2079 gridView->setWrapEnabled(false);
2080 gridView->setCacheBuffer(3);
2081 gridView->setFlow(QQuickGridView::TopToBottom);
2083 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2084 QTRY_COMPARE(cacheBufferSpy.count(),1);
2085 QTRY_COMPARE(flowSpy.count(),1);
2087 gridView->setFlow(QQuickGridView::LeftToRight);
2088 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
2090 gridView->setWrapEnabled(true);
2091 gridView->setCacheBuffer(5);
2092 gridView->setLayoutDirection(Qt::RightToLeft);
2094 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2095 QTRY_COMPARE(gridView->cacheBuffer(), 5);
2096 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
2098 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2099 QTRY_COMPARE(cacheBufferSpy.count(),2);
2100 QTRY_COMPARE(layoutSpy.count(),1);
2101 QTRY_COMPARE(flowSpy.count(),2);
2103 gridView->setWrapEnabled(true);
2104 gridView->setCacheBuffer(5);
2105 gridView->setLayoutDirection(Qt::RightToLeft);
2107 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2108 QTRY_COMPARE(cacheBufferSpy.count(),2);
2109 QTRY_COMPARE(layoutSpy.count(),1);
2110 QTRY_COMPARE(flowSpy.count(),2);
2112 gridView->setFlow(QQuickGridView::TopToBottom);
2113 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
2114 QTRY_COMPARE(flowSpy.count(),3);
2116 gridView->setFlow(QQuickGridView::TopToBottom);
2117 QTRY_COMPARE(flowSpy.count(),3);
2122 void tst_QQuickGridView::componentChanges()
2124 QQuickView *canvas = createView();
2125 QTRY_VERIFY(canvas);
2126 canvas->setSource(testFileUrl("propertychangestest.qml"));
2128 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2129 QTRY_VERIFY(gridView);
2131 QDeclarativeComponent component(canvas->engine());
2132 component.setData("import QtQuick 2.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
2134 QDeclarativeComponent delegateComponent(canvas->engine());
2135 delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
2137 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
2138 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
2139 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
2140 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
2142 gridView->setHighlight(&component);
2143 gridView->setDelegate(&delegateComponent);
2144 gridView->setHeader(&component);
2145 gridView->setFooter(&component);
2147 QTRY_COMPARE(gridView->highlight(), &component);
2148 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
2149 QTRY_COMPARE(gridView->header(), &component);
2150 QTRY_COMPARE(gridView->footer(), &component);
2152 QTRY_COMPARE(highlightSpy.count(),1);
2153 QTRY_COMPARE(delegateSpy.count(),1);
2154 QTRY_COMPARE(headerSpy.count(),1);
2155 QTRY_COMPARE(footerSpy.count(),1);
2157 gridView->setHighlight(&component);
2158 gridView->setDelegate(&delegateComponent);
2159 gridView->setHeader(&component);
2160 gridView->setFooter(&component);
2162 QTRY_COMPARE(highlightSpy.count(),1);
2163 QTRY_COMPARE(delegateSpy.count(),1);
2164 QTRY_COMPARE(headerSpy.count(),1);
2165 QTRY_COMPARE(footerSpy.count(),1);
2170 void tst_QQuickGridView::modelChanges()
2172 QQuickView *canvas = createView();
2173 QTRY_VERIFY(canvas);
2174 canvas->setSource(testFileUrl("propertychangestest.qml"));
2176 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2177 QTRY_VERIFY(gridView);
2179 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
2180 QTRY_VERIFY(alternateModel);
2181 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
2182 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
2184 gridView->setModel(modelVariant);
2185 QTRY_COMPARE(gridView->model(), modelVariant);
2186 QTRY_COMPARE(modelSpy.count(),1);
2188 gridView->setModel(modelVariant);
2189 QTRY_COMPARE(modelSpy.count(),1);
2191 gridView->setModel(QVariant());
2192 QTRY_COMPARE(modelSpy.count(),2);
2196 void tst_QQuickGridView::positionViewAtIndex()
2198 QQuickView *canvas = createView();
2201 for (int i = 0; i < 40; i++)
2202 model.addItem("Item" + QString::number(i), "");
2204 QDeclarativeContext *ctxt = canvas->rootContext();
2205 ctxt->setContextProperty("testModel", &model);
2206 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2207 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2209 canvas->setSource(testFileUrl("gridview1.qml"));
2210 qApp->processEvents();
2212 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2213 QTRY_VERIFY(gridview != 0);
2215 QQuickItem *contentItem = gridview->contentItem();
2216 QTRY_VERIFY(contentItem != 0);
2218 // Confirm items positioned correctly
2219 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2220 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2221 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2222 if (!item) qWarning() << "Item" << i << "not found";
2224 QTRY_COMPARE(item->x(), (i%3)*80.);
2225 QTRY_COMPARE(item->y(), (i/3)*60.);
2228 // Position on a currently visible item
2229 gridview->positionViewAtIndex(4, QQuickGridView::Beginning);
2230 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
2231 QTRY_COMPARE(gridview->contentY(), 60.);
2233 // Confirm items positioned correctly
2234 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2235 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2236 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2237 if (!item) qWarning() << "Item" << i << "not found";
2239 QTRY_COMPARE(item->x(), (i%3)*80.);
2240 QTRY_COMPARE(item->y(), (i/3)*60.);
2243 // Position on an item beyond the visible items
2244 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2245 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
2246 QTRY_COMPARE(gridview->contentY(), 420.);
2248 // Confirm items positioned correctly
2249 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2250 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2251 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2252 if (!item) qWarning() << "Item" << i << "not found";
2254 QTRY_COMPARE(item->x(), (i%3)*80.);
2255 QTRY_COMPARE(item->y(), (i/3)*60.);
2258 // Position on an item that would leave empty space if positioned at the top
2259 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2260 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
2261 QTRY_COMPARE(gridview->contentY(), 520.);
2263 // Confirm items positioned correctly
2264 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2265 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2266 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2267 if (!item) qWarning() << "Item" << i << "not found";
2269 QTRY_COMPARE(item->x(), (i%3)*80.);
2270 QTRY_COMPARE(item->y(), (i/3)*60.);
2273 // Position at the beginning again
2274 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2275 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
2276 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
2277 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
2278 QTRY_COMPARE(gridview->contentY(), 0.);
2280 // Confirm items positioned correctly
2281 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2282 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2283 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2284 if (!item) qWarning() << "Item" << i << "not found";
2286 QTRY_COMPARE(item->x(), (i%3)*80.);
2287 QTRY_COMPARE(item->y(), (i/3)*60.);
2291 gridview->positionViewAtIndex(30, QQuickGridView::End);
2292 QTRY_COMPARE(gridview->contentY(), 340.);
2294 // Position in Center
2295 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2296 QTRY_COMPARE(gridview->contentY(), 170.);
2298 // Ensure at least partially visible
2299 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2300 QTRY_COMPARE(gridview->contentY(), 170.);
2302 gridview->setContentY(302);
2303 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2304 QTRY_COMPARE(gridview->contentY(), 302.);
2306 gridview->setContentY(360);
2307 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2308 QTRY_COMPARE(gridview->contentY(), 300.);
2310 gridview->setContentY(60);
2311 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2312 QTRY_COMPARE(gridview->contentY(), 60.);
2314 gridview->setContentY(20);
2315 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2316 QTRY_COMPARE(gridview->contentY(), 100.);
2318 // Ensure completely visible
2319 gridview->setContentY(120);
2320 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2321 QTRY_COMPARE(gridview->contentY(), 120.);
2323 gridview->setContentY(302);
2324 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2325 QTRY_COMPARE(gridview->contentY(), 300.);
2327 gridview->setContentY(60);
2328 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2329 QTRY_COMPARE(gridview->contentY(), 100.);
2331 // Test for Top To Bottom layout
2332 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2334 // Confirm items positioned correctly
2335 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2336 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2337 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2338 if (!item) qWarning() << "Item" << i << "not found";
2340 QTRY_COMPARE(item->x(), (i/5)*80.);
2341 QTRY_COMPARE(item->y(), (i%5)*60.);
2345 gridview->positionViewAtIndex(30, QQuickGridView::End);
2346 QTRY_COMPARE(gridview->contentX(), 320.);
2347 QTRY_COMPARE(gridview->contentY(), 0.);
2349 // Position in Center
2350 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2351 QTRY_COMPARE(gridview->contentX(), 160.);
2353 // Ensure at least partially visible
2354 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2355 QTRY_COMPARE(gridview->contentX(), 160.);
2357 gridview->setContentX(170);
2358 gridview->positionViewAtIndex(25, QQuickGridView::Visible);
2359 QTRY_COMPARE(gridview->contentX(), 170.);
2361 gridview->positionViewAtIndex(30, QQuickGridView::Visible);
2362 QTRY_COMPARE(gridview->contentX(), 320.);
2364 gridview->setContentX(170);
2365 gridview->positionViewAtIndex(25, QQuickGridView::Contain);
2366 QTRY_COMPARE(gridview->contentX(), 240.);
2368 // positionViewAtBeginning
2369 gridview->positionViewAtBeginning();
2370 QTRY_COMPARE(gridview->contentX(), 0.);
2372 gridview->setContentX(80);
2373 canvas->rootObject()->setProperty("showHeader", true);
2374 gridview->positionViewAtBeginning();
2375 QTRY_COMPARE(gridview->contentX(), -30.);
2377 // positionViewAtEnd
2378 gridview->positionViewAtEnd();
2379 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
2381 gridview->setContentX(80);
2382 canvas->rootObject()->setProperty("showFooter", true);
2383 gridview->positionViewAtEnd();
2384 QTRY_COMPARE(gridview->contentX(), 430.);
2386 // set current item to outside visible view, position at beginning
2387 // and ensure highlight moves to current item
2388 gridview->setCurrentIndex(6);
2389 gridview->positionViewAtBeginning();
2390 QTRY_COMPARE(gridview->contentX(), -30.);
2391 QVERIFY(gridview->highlightItem());
2392 QCOMPARE(gridview->highlightItem()->x(), 80.);
2397 void tst_QQuickGridView::snapping()
2399 QQuickView *canvas = createView();
2402 for (int i = 0; i < 40; i++)
2403 model.addItem("Item" + QString::number(i), "");
2405 QDeclarativeContext *ctxt = canvas->rootContext();
2406 ctxt->setContextProperty("testModel", &model);
2407 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2408 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2410 canvas->setSource(testFileUrl("gridview1.qml"));
2411 qApp->processEvents();
2413 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2414 QTRY_VERIFY(gridview != 0);
2416 gridview->setHeight(220);
2417 QCOMPARE(gridview->height(), 220.);
2419 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2420 QCOMPARE(gridview->contentY(), 80.);
2422 gridview->setContentY(0);
2423 QCOMPARE(gridview->contentY(), 0.);
2425 gridview->setSnapMode(QQuickGridView::SnapToRow);
2426 QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow);
2428 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2429 QCOMPARE(gridview->contentY(), 60.);
2431 gridview->positionViewAtIndex(15, QQuickGridView::End);
2432 QCOMPARE(gridview->contentY(), 120.);
2438 void tst_QQuickGridView::mirroring()
2440 QQuickView *canvasA = createView();
2441 canvasA->setSource(testFileUrl("mirroring.qml"));
2442 QQuickGridView *gridviewA = findItem<QQuickGridView>(canvasA->rootObject(), "view");
2443 QTRY_VERIFY(gridviewA != 0);
2445 QQuickView *canvasB = createView();
2446 canvasB->setSource(testFileUrl("mirroring.qml"));
2447 QQuickGridView *gridviewB = findItem<QQuickGridView>(canvasB->rootObject(), "view");
2448 QTRY_VERIFY(gridviewA != 0);
2449 qApp->processEvents();
2451 QList<QString> objectNames;
2452 objectNames << "item1" << "item2"; // << "item3"
2454 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2455 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2456 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2459 foreach (const QString objectName, objectNames)
2460 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2462 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2463 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2466 foreach (const QString objectName, objectNames)
2467 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2469 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2470 QQuickItemPrivate::get(gridviewB)->setLayoutMirror(true);
2471 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2473 // LTR != LTR+mirror
2474 foreach (const QString objectName, objectNames)
2475 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2477 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2479 // RTL == LTR+mirror
2480 foreach (const QString objectName, objectNames)
2481 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2483 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2485 // RTL != RTL+mirror
2486 foreach (const QString objectName, objectNames)
2487 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2489 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2491 // LTR == RTL+mirror
2492 foreach (const QString objectName, objectNames)
2493 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2499 void tst_QQuickGridView::positionViewAtIndex_rightToLeft()
2501 QQuickView *canvas = createView();
2504 for (int i = 0; i < 40; i++)
2505 model.addItem("Item" + QString::number(i), "");
2507 QDeclarativeContext *ctxt = canvas->rootContext();
2508 ctxt->setContextProperty("testModel", &model);
2509 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2510 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2512 canvas->setSource(testFileUrl("gridview1.qml"));
2513 qApp->processEvents();
2515 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2516 QTRY_VERIFY(gridview != 0);
2518 QQuickItem *contentItem = gridview->contentItem();
2519 QTRY_VERIFY(contentItem != 0);
2521 // Confirm items positioned correctly
2522 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2523 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2524 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2525 if (!item) qWarning() << "Item" << i << "not found";
2527 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2528 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2531 // Position on a currently visible item
2532 gridview->positionViewAtIndex(6, QQuickGridView::Beginning);
2533 QTRY_COMPARE(gridview->contentX(), -320.);
2535 // Confirm items positioned correctly
2536 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2537 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2538 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2539 if (!item) qWarning() << "Item" << i << "not found";
2541 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2542 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2545 // Position on an item beyond the visible items
2546 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2547 QTRY_COMPARE(gridview->contentX(), -560.);
2549 // Confirm items positioned correctly
2550 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2551 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2552 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2553 if (!item) qWarning() << "Item" << i << "not found";
2555 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2556 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2559 // Position on an item that would leave empty space if positioned at the top
2560 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2561 QTRY_COMPARE(gridview->contentX(), -640.);
2563 // Confirm items positioned correctly
2564 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2565 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2566 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2567 if (!item) qWarning() << "Item" << i << "not found";
2569 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2570 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2573 // Position at the beginning again
2574 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2575 QTRY_COMPARE(gridview->contentX(), -240.);
2577 // Confirm items positioned correctly
2578 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2579 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2580 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2581 if (!item) qWarning() << "Item" << i << "not found";
2583 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2584 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2588 gridview->positionViewAtIndex(30, QQuickGridView::End);
2589 QTRY_COMPARE(gridview->contentX(), -560.);
2591 // Position in Center
2592 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2593 QTRY_COMPARE(gridview->contentX(), -400.);
2595 // Ensure at least partially visible
2596 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2597 QTRY_COMPARE(gridview->contentX(), -400.);
2599 gridview->setContentX(-555.);
2600 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2601 QTRY_COMPARE(gridview->contentX(), -555.);
2603 gridview->setContentX(-239);
2604 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2605 QTRY_COMPARE(gridview->contentX(), -320.);
2607 gridview->setContentX(-239);
2608 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2609 QTRY_COMPARE(gridview->contentX(), -400.);
2611 gridview->setContentX(-640);
2612 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2613 QTRY_COMPARE(gridview->contentX(), -560.);
2615 // Ensure completely visible
2616 gridview->setContentX(-400);
2617 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2618 QTRY_COMPARE(gridview->contentX(), -400.);
2620 gridview->setContentX(-315);
2621 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2622 QTRY_COMPARE(gridview->contentX(), -320.);
2624 gridview->setContentX(-640);
2625 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2626 QTRY_COMPARE(gridview->contentX(), -560.);
2631 void tst_QQuickGridView::resetModel()
2633 QQuickView *canvas = createView();
2635 QStringList strings;
2636 strings << "one" << "two" << "three";
2637 QStringListModel model(strings);
2639 QDeclarativeContext *ctxt = canvas->rootContext();
2640 ctxt->setContextProperty("testModel", &model);
2642 canvas->setSource(testFileUrl("displaygrid.qml"));
2643 qApp->processEvents();
2645 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2646 QTRY_VERIFY(gridview != 0);
2648 QQuickItem *contentItem = gridview->contentItem();
2649 QTRY_VERIFY(contentItem != 0);
2651 QTRY_COMPARE(gridview->count(), model.rowCount());
2653 for (int i = 0; i < model.rowCount(); ++i) {
2654 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2655 QTRY_VERIFY(display != 0);
2656 QTRY_COMPARE(display->text(), strings.at(i));
2660 strings << "four" << "five" << "six" << "seven";
2661 model.setStringList(strings);
2663 QTRY_COMPARE(gridview->count(), model.rowCount());
2665 for (int i = 0; i < model.rowCount(); ++i) {
2666 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2667 QTRY_VERIFY(display != 0);
2668 QTRY_COMPARE(display->text(), strings.at(i));
2674 void tst_QQuickGridView::enforceRange()
2676 QQuickView *canvas = createView();
2679 for (int i = 0; i < 30; i++)
2680 model.addItem("Item" + QString::number(i), "");
2682 QDeclarativeContext *ctxt = canvas->rootContext();
2683 ctxt->setContextProperty("testModel", &model);
2684 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2685 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2687 canvas->setSource(testFileUrl("gridview-enforcerange.qml"));
2688 qApp->processEvents();
2689 QVERIFY(canvas->rootObject() != 0);
2691 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2692 QTRY_VERIFY(gridview != 0);
2694 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2695 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2696 QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2698 QQuickItem *contentItem = gridview->contentItem();
2699 QTRY_VERIFY(contentItem != 0);
2701 // view should be positioned at the top of the range.
2702 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2704 QTRY_COMPARE(gridview->contentY(), -100.0);
2706 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2707 QTRY_VERIFY(name != 0);
2708 QTRY_COMPARE(name->text(), model.name(0));
2709 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2710 QTRY_VERIFY(number != 0);
2711 QTRY_COMPARE(number->text(), model.number(0));
2713 // Check currentIndex is updated when contentItem moves
2714 gridview->setContentY(0);
2715 QTRY_COMPARE(gridview->currentIndex(), 2);
2717 gridview->setCurrentIndex(5);
2718 QTRY_COMPARE(gridview->contentY(), 100.);
2721 for (int i = 0; i < 5; i++)
2722 model2.addItem("Item" + QString::number(i), "");
2724 ctxt->setContextProperty("testModel", &model2);
2725 QCOMPARE(gridview->count(), 5);
2730 void tst_QQuickGridView::enforceRange_rightToLeft()
2732 QQuickView *canvas = createView();
2735 for (int i = 0; i < 30; i++)
2736 model.addItem("Item" + QString::number(i), "");
2738 QDeclarativeContext *ctxt = canvas->rootContext();
2739 ctxt->setContextProperty("testModel", &model);
2740 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2741 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2743 canvas->setSource(testFileUrl("gridview-enforcerange.qml"));
2744 qApp->processEvents();
2745 QVERIFY(canvas->rootObject() != 0);
2747 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2748 QTRY_VERIFY(gridview != 0);
2750 QCOMPARE(gridview->preferredHighlightBegin(), 100.0);
2751 QCOMPARE(gridview->preferredHighlightEnd(), 100.0);
2752 QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2754 QQuickItem *contentItem = gridview->contentItem();
2755 QVERIFY(contentItem != 0);
2757 // view should be positioned at the top of the range.
2758 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2760 QTRY_COMPARE(gridview->contentX(), -140.);
2761 QTRY_COMPARE(gridview->contentY(), 0.0);
2763 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2764 QTRY_VERIFY(name != 0);
2765 QTRY_COMPARE(name->text(), model.name(0));
2766 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2767 QTRY_VERIFY(number != 0);
2768 QTRY_COMPARE(number->text(), model.number(0));
2770 // Check currentIndex is updated when contentItem moves
2771 gridview->setContentX(-240);
2772 QTRY_COMPARE(gridview->currentIndex(), 3);
2774 gridview->setCurrentIndex(7);
2775 QTRY_COMPARE(gridview->contentX(), -340.);
2776 QTRY_COMPARE(gridview->contentY(), 0.0);
2779 for (int i = 0; i < 5; i++)
2780 model2.addItem("Item" + QString::number(i), "");
2782 ctxt->setContextProperty("testModel", &model2);
2783 QCOMPARE(gridview->count(), 5);
2788 void tst_QQuickGridView::QTBUG_8456()
2790 QQuickView *canvas = createView();
2792 canvas->setSource(testFileUrl("setindex.qml"));
2793 qApp->processEvents();
2795 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2796 QTRY_VERIFY(gridview != 0);
2798 QTRY_COMPARE(gridview->currentIndex(), 0);
2803 void tst_QQuickGridView::manualHighlight()
2805 QQuickView *canvas = createView();
2807 QString filename(testFile("manual-highlight.qml"));
2808 canvas->setSource(QUrl::fromLocalFile(filename));
2810 qApp->processEvents();
2812 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2813 QTRY_VERIFY(gridview != 0);
2815 QQuickItem *contentItem = gridview->contentItem();
2816 QTRY_VERIFY(contentItem != 0);
2818 QTRY_COMPARE(gridview->currentIndex(), 0);
2819 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2820 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2821 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2823 gridview->setCurrentIndex(2);
2825 QTRY_COMPARE(gridview->currentIndex(), 2);
2826 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2827 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2828 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2830 gridview->positionViewAtIndex(8, QQuickGridView::Contain);
2832 QTRY_COMPARE(gridview->currentIndex(), 2);
2833 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2834 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2835 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2837 gridview->setFlow(QQuickGridView::TopToBottom);
2838 QTRY_COMPARE(gridview->flow(), QQuickGridView::TopToBottom);
2840 gridview->setCurrentIndex(0);
2841 QTRY_COMPARE(gridview->currentIndex(), 0);
2842 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2843 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2844 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2850 void tst_QQuickGridView::footer()
2852 QFETCH(QQuickGridView::Flow, flow);
2853 QFETCH(Qt::LayoutDirection, layoutDirection);
2854 QFETCH(QPointF, initialFooterPos);
2855 QFETCH(QPointF, changedFooterPos);
2856 QFETCH(QPointF, initialContentPos);
2857 QFETCH(QPointF, changedContentPos);
2858 QFETCH(QPointF, firstDelegatePos);
2859 QFETCH(QPointF, resizeContentPos);
2861 QQuickView *canvas = createView();
2865 for (int i = 0; i < 7; i++)
2866 model.addItem("Item" + QString::number(i), "");
2868 QDeclarativeContext *ctxt = canvas->rootContext();
2869 ctxt->setContextProperty("testModel", &model);
2871 canvas->setSource(testFileUrl("footer.qml"));
2872 qApp->processEvents();
2874 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2875 QTRY_VERIFY(gridview != 0);
2876 gridview->setFlow(flow);
2877 gridview->setLayoutDirection(layoutDirection);
2879 QQuickItem *contentItem = gridview->contentItem();
2880 QTRY_VERIFY(contentItem != 0);
2882 QQuickText *footer = findItem<QQuickText>(contentItem, "footer");
2885 QVERIFY(footer == gridview->footerItem());
2887 QCOMPARE(footer->pos(), initialFooterPos);
2888 QCOMPARE(footer->width(), 100.);
2889 QCOMPARE(footer->height(), 30.);
2890 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2892 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2894 QCOMPARE(item->pos(), firstDelegatePos);
2896 if (flow == QQuickGridView::LeftToRight) {
2897 // shrink by one row
2898 model.removeItem(2);
2899 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2901 // shrink by one column
2902 model.removeItem(2);
2903 model.removeItem(3);
2904 if (layoutDirection == Qt::LeftToRight)
2905 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2907 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2913 QPointF posWhenNoItems(0, 0);
2914 if (layoutDirection == Qt::RightToLeft)
2915 posWhenNoItems.setX(flow == QQuickGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2916 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2918 // if header is present, it's at a negative pos, so the footer should not move
2919 canvas->rootObject()->setProperty("showHeader", true);
2920 QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0);
2921 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2922 canvas->rootObject()->setProperty("showHeader", false);
2925 for (int i = 0; i < 30; i++)
2926 model.addItem("Item" + QString::number(i), "");
2928 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2929 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2931 QCOMPARE(footerItemSpy.count(), 1);
2933 footer = findItem<QQuickText>(contentItem, "footer");
2935 footer = findItem<QQuickText>(contentItem, "footer2");
2938 QVERIFY(footer == gridview->footerItem());
2940 QCOMPARE(footer->pos(), changedFooterPos);
2941 QCOMPARE(footer->width(), 50.);
2942 QCOMPARE(footer->height(), 20.);
2943 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2945 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2947 QCOMPARE(item->pos(), firstDelegatePos);
2949 gridview->positionViewAtEnd();
2950 footer->setHeight(10);
2951 footer->setWidth(40);
2952 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2957 void tst_QQuickGridView::footer_data()
2959 QTest::addColumn<QQuickGridView::Flow>("flow");
2960 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2961 QTest::addColumn<QPointF>("initialFooterPos");
2962 QTest::addColumn<QPointF>("changedFooterPos");
2963 QTest::addColumn<QPointF>("initialContentPos");
2964 QTest::addColumn<QPointF>("changedContentPos");
2965 QTest::addColumn<QPointF>("firstDelegatePos");
2966 QTest::addColumn<QPointF>("resizeContentPos");
2968 // footer1 = 100 x 30
2969 // footer2 = 50 x 20
2972 // view height = 320
2974 // footer below items, bottom left
2975 QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
2976 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
2977 << QPointF(0, 10 * 60) // 30 items = 10 rows
2981 << QPointF(0, 10 * 60 - 320 + 10);
2983 // footer below items, bottom right
2984 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
2985 << QPointF(240 - 100, 3 * 60)
2986 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
2989 << QPointF(240 - 80, 0)
2990 << QPointF(0, 10 * 60 - 320 + 10);
2992 // footer to right of items
2993 QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
2994 << QPointF(2 * 80, 0) // 2 columns, cell width 80
2995 << QPointF(6 * 80, 0) // 30 items = 6 columns
2999 << QPointF(6 * 80 - 240 + 40, 0);
3001 // footer to left of items
3002 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
3003 << QPointF(-(2 * 80) - 100, 0)
3004 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
3006 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
3008 << QPointF(-(6 * 80) - 40, 0);
3011 void tst_QQuickGridView::header()
3013 QFETCH(QQuickGridView::Flow, flow);
3014 QFETCH(Qt::LayoutDirection, layoutDirection);
3015 QFETCH(QPointF, initialHeaderPos);
3016 QFETCH(QPointF, changedHeaderPos);
3017 QFETCH(QPointF, initialContentPos);
3018 QFETCH(QPointF, changedContentPos);
3019 QFETCH(QPointF, firstDelegatePos);
3020 QFETCH(QPointF, resizeContentPos);
3023 for (int i = 0; i < 30; i++)
3024 model.addItem("Item" + QString::number(i), "");
3026 QQuickView *canvas = createView();
3027 canvas->rootContext()->setContextProperty("testModel", &model);
3028 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
3029 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
3030 canvas->setSource(testFileUrl("header.qml"));
3032 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3033 QTRY_VERIFY(gridview != 0);
3034 gridview->setFlow(flow);
3035 gridview->setLayoutDirection(layoutDirection);
3037 QQuickItem *contentItem = gridview->contentItem();
3038 QTRY_VERIFY(contentItem != 0);
3040 QQuickText *header = findItem<QQuickText>(contentItem, "header");
3043 QVERIFY(header == gridview->headerItem());
3045 QCOMPARE(header->pos(), initialHeaderPos);
3046 QCOMPARE(header->width(), 100.);
3047 QCOMPARE(header->height(), 30.);
3048 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3050 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3052 QCOMPARE(item->pos(), firstDelegatePos);
3055 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
3057 for (int i = 0; i < 30; i++)
3058 model.addItem("Item" + QString::number(i), "");
3060 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
3061 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
3063 QCOMPARE(headerItemSpy.count(), 1);
3065 header = findItem<QQuickText>(contentItem, "header");
3067 header = findItem<QQuickText>(contentItem, "header2");
3070 QVERIFY(header == gridview->headerItem());
3072 QCOMPARE(header->pos(), changedHeaderPos);
3073 QCOMPARE(header->width(), 50.);
3074 QCOMPARE(header->height(), 20.);
3075 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
3077 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3079 QCOMPARE(item->pos(), firstDelegatePos);
3081 header->setHeight(10);
3082 header->setWidth(40);
3083 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
3088 // QTBUG-21207 header should become visible if view resizes from initial empty size
3090 canvas = createView();
3091 canvas->rootContext()->setContextProperty("testModel", &model);
3092 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
3093 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
3094 canvas->setSource(testFileUrl("header.qml"));
3096 gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3097 QTRY_VERIFY(gridview != 0);
3098 gridview->setFlow(flow);
3099 gridview->setLayoutDirection(layoutDirection);
3101 gridview->setWidth(240);
3102 gridview->setHeight(320);
3103 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
3104 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3109 void tst_QQuickGridView::header_data()
3111 QTest::addColumn<QQuickGridView::Flow>("flow");
3112 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3113 QTest::addColumn<QPointF>("initialHeaderPos");
3114 QTest::addColumn<QPointF>("changedHeaderPos");
3115 QTest::addColumn<QPointF>("initialContentPos");
3116 QTest::addColumn<QPointF>("changedContentPos");
3117 QTest::addColumn<QPointF>("firstDelegatePos");
3118 QTest::addColumn<QPointF>("resizeContentPos");
3120 // header1 = 100 x 30
3121 // header2 = 50 x 20
3125 // header above items, top left
3126 QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
3134 // header above items, top right
3135 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
3136 << QPointF(240 - 100, -30)
3137 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
3143 // header to left of items
3144 QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
3152 // header to right of items
3153 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
3156 << QPointF(-(240 - 100), 0)
3157 << QPointF(-(240 - 50), 0)
3159 << QPointF(-(240 - 40), 0);
3162 void tst_QQuickGridView::resizeViewAndRepaint()
3164 QQuickView *canvas = createView();
3168 for (int i = 0; i < 40; i++)
3169 model.addItem("Item" + QString::number(i), "");
3171 QDeclarativeContext *ctxt = canvas->rootContext();
3172 ctxt->setContextProperty("testModel", &model);
3173 ctxt->setContextProperty("initialHeight", 100);
3175 canvas->setSource(testFileUrl("resizeview.qml"));
3176 qApp->processEvents();
3178 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3179 QTRY_VERIFY(gridview != 0);
3180 QQuickItem *contentItem = gridview->contentItem();
3181 QTRY_VERIFY(contentItem != 0);
3183 // item at index 10 should not be currently visible
3184 QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3186 gridview->setHeight(320);
3189 QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
3192 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", 10));
3194 gridview->setHeight(100);
3195 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3197 // Ensure we handle -ve sizes
3198 gridview->setHeight(-100);
3199 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 3);
3201 gridview->setCacheBuffer(120);
3202 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 9);
3204 // ensure items in cache become visible
3205 gridview->setHeight(120);
3206 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 15);
3208 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3209 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3210 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3211 if (!item) qWarning() << "Item" << i << "not found";
3213 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3214 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3215 QCOMPARE(item->isVisible(), i < 9); // inside view visible, outside not visible
3218 // ensure items outside view become invisible
3219 gridview->setHeight(60);
3220 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 12);
3222 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3223 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3224 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3225 if (!item) qWarning() << "Item" << i << "not found";
3227 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3228 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3229 QCOMPARE(item->isVisible(), i < 6); // inside view visible, outside not visible
3235 void tst_QQuickGridView::indexAt_itemAt_data()
3237 QTest::addColumn<qreal>("x");
3238 QTest::addColumn<qreal>("y");
3239 QTest::addColumn<int>("index");
3241 QTest::newRow("Item 0 - 0, 0") << 0. << 0. << 0;
3242 QTest::newRow("Item 0 - 79, 59") << 79. << 59. << 0;
3243 QTest::newRow("Item 1 - 80, 0") << 80. << 0. << 1;
3244 QTest::newRow("Item 3 - 0, 60") << 0. << 60. << 3;
3245 QTest::newRow("No Item - 240, 0") << 240. << 0. << -1;
3248 void tst_QQuickGridView::indexAt_itemAt()
3254 QQuickView *canvas = createView();
3257 model.addItem("Fred", "12345");
3258 model.addItem("John", "2345");
3259 model.addItem("Bob", "54321");
3260 model.addItem("Billy", "22345");
3261 model.addItem("Sam", "2945");
3262 model.addItem("Ben", "04321");
3263 model.addItem("Jim", "0780");
3265 QDeclarativeContext *ctxt = canvas->rootContext();
3266 ctxt->setContextProperty("testModel", &model);
3267 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3268 ctxt->setContextProperty("testTopToBottom", QVariant(false));
3270 canvas->setSource(testFileUrl("gridview1.qml"));
3271 qApp->processEvents();
3273 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3274 QTRY_VERIFY(gridview != 0);
3276 QQuickItem *contentItem = gridview->contentItem();
3277 QTRY_VERIFY(contentItem != 0);
3279 QTRY_COMPARE(gridview->count(), model.count());
3281 QQuickItem *item = 0;
3283 item = findItem<QQuickItem>(contentItem, "wrapper", index);
3286 QCOMPARE(gridview->indexAt(x, y), index);
3287 QVERIFY(gridview->itemAt(x, y) == item);
3292 void tst_QQuickGridView::onAdd()
3294 QFETCH(int, initialItemCount);
3295 QFETCH(int, itemsToAdd);
3297 const int delegateWidth = 50;
3298 const int delegateHeight = 100;
3300 QQuickView *canvas = createView();
3301 canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
3303 // these initial items should not trigger GridView.onAdd
3304 for (int i=0; i<initialItemCount; i++)
3305 model.addItem("dummy value", "dummy value");
3307 QDeclarativeContext *ctxt = canvas->rootContext();
3308 ctxt->setContextProperty("testModel", &model);
3309 ctxt->setContextProperty("delegateWidth", delegateWidth);
3310 ctxt->setContextProperty("delegateHeight", delegateHeight);
3311 canvas->setSource(testFileUrl("attachedSignals.qml"));
3313 QObject *object = canvas->rootObject();
3314 object->setProperty("width", canvas->width());
3315 object->setProperty("height", canvas->height());
3316 qApp->processEvents();
3318 QList<QPair<QString, QString> > items;
3319 for (int i=0; i<itemsToAdd; i++)
3320 items << qMakePair(QString("value %1").arg(i), QString::number(i));
3321 model.addItems(items);
3323 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
3324 qApp->processEvents();
3326 QVariantList result = object->property("addedDelegates").toList();
3327 QTRY_COMPARE(result.count(), items.count());
3328 for (int i=0; i<items.count(); i++)
3329 QCOMPARE(result[i].toString(), items[i].first);
3334 void tst_QQuickGridView::onAdd_data()
3336 QTest::addColumn<int>("initialItemCount");
3337 QTest::addColumn<int>("itemsToAdd");
3339 QTest::newRow("0, add 1") << 0 << 1;
3340 QTest::newRow("0, add 2") << 0 << 2;
3341 QTest::newRow("0, add 10") << 0 << 10;
3343 QTest::newRow("1, add 1") << 1 << 1;
3344 QTest::newRow("1, add 2") << 1 << 2;
3345 QTest::newRow("1, add 10") << 1 << 10;
3347 QTest::newRow("5, add 1") << 5 << 1;
3348 QTest::newRow("5, add 2") << 5 << 2;
3349 QTest::newRow("5, add 10") << 5 << 10;
3352 void tst_QQuickGridView::onRemove()
3354 QFETCH(int, initialItemCount);
3355 QFETCH(int, indexToRemove);
3356 QFETCH(int, removeCount);
3358 const int delegateWidth = 50;
3359 const int delegateHeight = 100;
3361 for (int i=0; i<initialItemCount; i++)
3362 model.addItem(QString("value %1").arg(i), "dummy value");
3364 QQuickView *canvas = createView();
3365 QDeclarativeContext *ctxt = canvas->rootContext();
3366 ctxt->setContextProperty("testModel", &model);
3367 ctxt->setContextProperty("delegateWidth", delegateWidth);
3368 ctxt->setContextProperty("delegateHeight", delegateHeight);
3369 canvas->setSource(testFileUrl("attachedSignals.qml"));
3370 QObject *object = canvas->rootObject();
3372 model.removeItems(indexToRemove, removeCount);
3373 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
3374 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
3379 void tst_QQuickGridView::onRemove_data()
3381 QTest::addColumn<int>("initialItemCount");
3382 QTest::addColumn<int>("indexToRemove");
3383 QTest::addColumn<int>("removeCount");
3385 QTest::newRow("remove first") << 1 << 0 << 1;
3386 QTest::newRow("two items, remove first") << 2 << 0 << 1;
3387 QTest::newRow("two items, remove last") << 2 << 1 << 1;
3388 QTest::newRow("two items, remove all") << 2 << 0 << 2;
3390 QTest::newRow("four items, remove first") << 4 << 0 << 1;
3391 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
3392 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
3393 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
3394 QTest::newRow("four items, remove last") << 4 << 3 << 1;
3395 QTest::newRow("four items, remove all") << 4 << 0 << 4;
3397 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
3398 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
3399 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
3402 void tst_QQuickGridView::columnCount()
3405 canvas.setSource(testFileUrl("gridview4.qml"));
3407 canvas.requestActivateWindow();
3408 QTest::qWaitForWindowShown(&canvas);
3410 QQuickGridView *view = qobject_cast<QQuickGridView*>(canvas.rootObject());
3412 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3413 QCOMPARE(view->cellHeight(), qreal(100));
3415 QList<QQuickItem*> items = findItems<QQuickItem>(view, "delegate");
3416 QCOMPARE(items.size(), 18);
3417 QCOMPARE(items.at(8)->y(), qreal(0));
3418 QCOMPARE(items.at(9)->y(), qreal(100));
3421 void tst_QQuickGridView::margins()
3424 QQuickView *canvas = createView();
3428 for (int i = 0; i < 40; i++)
3429 model.addItem("Item" + QString::number(i), "");
3431 QDeclarativeContext *ctxt = canvas->rootContext();
3432 ctxt->setContextProperty("testModel", &model);
3433 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3435 canvas->setSource(testFileUrl("margins.qml"));
3436 qApp->processEvents();
3438 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3439 QTRY_VERIFY(gridview != 0);
3441 QQuickItem *contentItem = gridview->contentItem();
3442 QTRY_VERIFY(contentItem != 0);
3444 QCOMPARE(gridview->contentX(), -30.);
3445 QCOMPARE(gridview->xOrigin(), 0.);
3448 gridview->positionViewAtEnd();
3449 qreal pos = gridview->contentX();
3450 gridview->setContentX(pos + 80);
3451 gridview->returnToBounds();
3452 QTRY_COMPARE(gridview->contentX(), pos + 50);
3454 // remove item before visible and check that left margin is maintained
3455 // and xOrigin is updated
3456 gridview->setContentX(200);
3457 model.removeItems(0, 4);
3459 gridview->setContentX(-50);
3460 gridview->returnToBounds();
3461 QCOMPARE(gridview->xOrigin(), 100.);
3462 QTRY_COMPARE(gridview->contentX(), 70.);
3464 // reduce left margin
3465 gridview->setLeftMargin(20);
3466 QCOMPARE(gridview->xOrigin(), 100.);
3467 QTRY_COMPARE(gridview->contentX(), 80.);
3470 gridview->positionViewAtEnd();
3471 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3472 pos = gridview->contentX();
3473 gridview->setContentX(pos + 80);
3474 gridview->returnToBounds();
3475 QTRY_COMPARE(gridview->contentX(), pos + 50);
3477 // reduce right margin
3478 pos = gridview->contentX();
3479 gridview->setRightMargin(40);
3480 QCOMPARE(gridview->xOrigin(), 0.);
3481 QTRY_COMPARE(gridview->contentX(), pos-10);
3487 QQuickView *canvas = createView();
3491 for (int i = 0; i < 40; i++)
3492 model.addItem("Item" + QString::number(i), "");
3494 QDeclarativeContext *ctxt = canvas->rootContext();
3495 ctxt->setContextProperty("testModel", &model);
3496 ctxt->setContextProperty("testRightToLeft", QVariant(true));
3498 canvas->setSource(testFileUrl("margins.qml"));
3499 qApp->processEvents();
3501 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3502 QTRY_VERIFY(gridview != 0);
3504 QQuickItem *contentItem = gridview->contentItem();
3505 QTRY_VERIFY(contentItem != 0);
3507 QCOMPARE(gridview->contentX(), -240+30.);
3508 QCOMPARE(gridview->xOrigin(), 0.);
3511 gridview->positionViewAtEnd();
3512 qreal pos = gridview->contentX();
3513 gridview->setContentX(pos - 80);
3514 gridview->returnToBounds();
3515 QTRY_COMPARE(gridview->contentX(), pos - 50);
3517 // remove item before visible and check that left margin is maintained
3518 // and xOrigin is updated
3519 gridview->setContentX(-400);
3520 model.removeItems(0, 4);
3522 gridview->setContentX(-240+50);
3523 gridview->returnToBounds();
3524 QCOMPARE(gridview->xOrigin(), -100.);
3525 QTRY_COMPARE(gridview->contentX(), -240-70.);
3527 // reduce left margin (i.e. right side due to RTL)
3528 pos = gridview->contentX();
3529 gridview->setLeftMargin(20);
3530 QCOMPARE(gridview->xOrigin(), -100.);
3531 QTRY_COMPARE(gridview->contentX(), -240-80.);
3534 gridview->positionViewAtEnd();
3535 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3536 pos = gridview->contentX();
3537 gridview->setContentX(pos - 80);
3538 gridview->returnToBounds();
3539 QTRY_COMPARE(gridview->contentX(), pos - 50);
3541 // reduce right margin (i.e. left side due to RTL)
3542 pos = gridview->contentX();
3543 gridview->setRightMargin(40);
3544 QCOMPARE(gridview->xOrigin(), 0.);
3545 QTRY_COMPARE(gridview->contentX(), pos+10);
3551 void tst_QQuickGridView::creationContext()
3554 canvas.setGeometry(0,0,240,320);
3555 canvas.setSource(testFileUrl("creationContext.qml"));
3556 qApp->processEvents();
3558 QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
3560 QVERIFY(rootItem->property("count").toInt() > 0);
3563 QVERIFY(item = rootItem->findChild<QQuickItem *>("listItem"));
3564 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3565 QVERIFY(item = rootItem->findChild<QQuickItem *>("header"));
3566 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3567 QVERIFY(item = rootItem->findChild<QQuickItem *>("footer"));
3568 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3571 void tst_QQuickGridView::snapToRow_data()
3573 QTest::addColumn<QQuickGridView::Flow>("flow");
3574 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3575 QTest::addColumn<int>("highlightRangeMode");
3576 QTest::addColumn<QPoint>("flickStart");
3577 QTest::addColumn<QPoint>("flickEnd");
3578 QTest::addColumn<qreal>("snapAlignment");
3579 QTest::addColumn<qreal>("endExtent");
3580 QTest::addColumn<qreal>("startExtent");
3582 QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3583 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3585 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3586 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3588 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3589 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 << -240.0;
3591 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3592 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3594 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3595 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3597 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3598 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0;
3601 void tst_QQuickGridView::snapToRow()
3603 QFETCH(QQuickGridView::Flow, flow);
3604 QFETCH(Qt::LayoutDirection, layoutDirection);
3605 QFETCH(int, highlightRangeMode);
3606 QFETCH(QPoint, flickStart);
3607 QFETCH(QPoint, flickEnd);
3608 QFETCH(qreal, snapAlignment);
3609 QFETCH(qreal, endExtent);
3610 QFETCH(qreal, startExtent);
3612 QQuickView *canvas = createView();
3614 canvas->setSource(testFileUrl("snapToRow.qml"));
3616 qApp->processEvents();
3618 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3619 QTRY_VERIFY(gridview != 0);
3621 gridview->setFlow(flow);
3622 gridview->setLayoutDirection(layoutDirection);
3623 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3625 QQuickItem *contentItem = gridview->contentItem();
3626 QTRY_VERIFY(contentItem != 0);
3628 // confirm that a flick hits an item boundary
3629 flick(canvas, flickStart, flickEnd, 180);
3630 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3631 if (flow == QQuickGridView::LeftToRight)
3632 QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
3634 QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
3638 flick(canvas, flickStart, flickEnd, 180);
3639 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3640 } while (flow == QQuickGridView::LeftToRight
3641 ? !gridview->isAtYEnd()
3642 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3644 if (flow == QQuickGridView::LeftToRight)
3645 QCOMPARE(gridview->contentY(), endExtent);
3647 QCOMPARE(gridview->contentX(), endExtent);
3651 flick(canvas, flickEnd, flickStart, 180);
3652 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3653 } while (flow == QQuickGridView::LeftToRight
3654 ? !gridview->isAtYBeginning()
3655 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3657 if (flow == QQuickGridView::LeftToRight)
3658 QCOMPARE(gridview->contentY(), startExtent);
3660 QCOMPARE(gridview->contentX(), startExtent);
3665 void tst_QQuickGridView::snapOneRow_data()
3667 QTest::addColumn<QQuickGridView::Flow>("flow");
3668 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3669 QTest::addColumn<int>("highlightRangeMode");
3670 QTest::addColumn<QPoint>("flickStart");
3671 QTest::addColumn<QPoint>("flickEnd");
3672 QTest::addColumn<qreal>("snapAlignment");
3673 QTest::addColumn<qreal>("endExtent");
3674 QTest::addColumn<qreal>("startExtent");
3676 QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3677 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 360.0 << 0.0;
3679 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3680 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 360.0 << 0.0;
3682 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3683 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -360.0 - 240.0 << -240.0;
3685 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3686 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 460.0 << -20.0;
3688 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3689 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 460.0 << -20.0;
3691 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3692 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -360.0 - 240.0 - 100.0 << -220.0;
3695 void tst_QQuickGridView::snapOneRow()
3697 QFETCH(QQuickGridView::Flow, flow);
3698 QFETCH(Qt::LayoutDirection, layoutDirection);
3699 QFETCH(int, highlightRangeMode);
3700 QFETCH(QPoint, flickStart);
3701 QFETCH(QPoint, flickEnd);
3702 QFETCH(qreal, snapAlignment);
3703 QFETCH(qreal, endExtent);
3704 QFETCH(qreal, startExtent);
3706 QQuickView *canvas = createView();
3708 canvas->setSource(testFileUrl("snapOneRow.qml"));
3710 qApp->processEvents();
3712 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3713 QTRY_VERIFY(gridview != 0);
3715 gridview->setFlow(flow);
3716 gridview->setLayoutDirection(layoutDirection);
3717 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3719 QQuickItem *contentItem = gridview->contentItem();
3720 QTRY_VERIFY(contentItem != 0);
3722 QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged()));
3724 // confirm that a flick hits next row boundary
3725 flick(canvas, flickStart, flickEnd, 180);
3726 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3727 if (flow == QQuickGridView::LeftToRight)
3728 QCOMPARE(gridview->contentY(), snapAlignment);
3730 QCOMPARE(gridview->contentX(), snapAlignment);
3732 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3733 QCOMPARE(gridview->currentIndex(), 2);
3734 QCOMPARE(currentIndexSpy.count(), 1);
3739 flick(canvas, flickStart, flickEnd, 180);
3740 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3741 } while (flow == QQuickGridView::LeftToRight
3742 ? !gridview->isAtYEnd()
3743 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3745 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3746 QCOMPARE(gridview->currentIndex(), 8);
3747 QCOMPARE(currentIndexSpy.count(), 4);
3750 if (flow == QQuickGridView::LeftToRight)
3751 QCOMPARE(gridview->contentY(), endExtent);
3753 QCOMPARE(gridview->contentX(), endExtent);
3757 flick(canvas, flickEnd, flickStart, 180);
3758 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3759 } while (flow == QQuickGridView::LeftToRight
3760 ? !gridview->isAtYBeginning()
3761 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3763 if (flow == QQuickGridView::LeftToRight)
3764 QCOMPARE(gridview->contentY(), startExtent);
3766 QCOMPARE(gridview->contentX(), startExtent);
3768 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3769 QCOMPARE(gridview->currentIndex(), 0);
3770 QCOMPARE(currentIndexSpy.count(), 8);
3777 void tst_QQuickGridView::unaligned()
3779 QQuickView *canvas = createView();
3783 for (int i = 0; i < 10; i++)
3784 model.addItem("Item" + QString::number(i), "");
3786 QDeclarativeContext *ctxt = canvas->rootContext();
3787 ctxt->setContextProperty("testModel", &model);
3789 canvas->setSource(testFileUrl("unaligned.qml"));
3790 qApp->processEvents();
3792 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3793 QVERIFY(gridview != 0);
3795 QQuickItem *contentItem = gridview->contentItem();
3796 QVERIFY(contentItem != 0);
3798 for (int i = 0; i < 10; ++i) {
3799 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3800 if (!item) qWarning() << "Item" << i << "not found";
3802 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
3803 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
3807 for (int i = 10; i < 18; ++i) {
3808 model.addItem("Item" + QString::number(i), "");
3809 QQuickItem *item = 0;
3810 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
3811 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
3812 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
3816 for (int i = 0; i < 10; ++i) {
3817 model.insertItem(i, "Item" + QString::number(i), "");
3818 QQuickItem *item = 0;
3819 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
3820 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
3821 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
3825 model.removeItems(7, 10);
3826 QTRY_COMPARE(model.count(), gridview->count());
3827 for (int i = 0; i < 18; ++i) {
3828 QQuickItem *item = 0;
3829 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
3830 QCOMPARE(item->x(), qreal(i%9)*gridview->cellWidth());
3831 QCOMPARE(item->y(), qreal(i/9)*gridview->cellHeight());
3837 QQuickView *tst_QQuickGridView::createView()
3839 QQuickView *canvas = new QQuickView(0);
3840 canvas->setGeometry(0,0,240,320);
3845 void tst_QQuickGridView::flick(QQuickView *canvas, const QPoint &from, const QPoint &to, int duration)
3847 const int pointCount = 5;
3848 QPoint diff = to - from;
3850 // send press, five equally spaced moves, and release.
3851 QTest::mousePress(canvas, Qt::LeftButton, 0, from);
3853 for (int i = 0; i < pointCount; ++i) {
3854 QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
3855 QGuiApplication::sendEvent(canvas, &mv);
3856 QTest::qWait(duration/pointCount);
3857 QCoreApplication::processEvents();
3860 QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
3863 void tst_QQuickGridView::cacheBuffer()
3865 QQuickView *canvas = createView();
3868 for (int i = 0; i < 90; i++)
3869 model.addItem("Item" + QString::number(i), "");
3871 QDeclarativeContext *ctxt = canvas->rootContext();
3872 ctxt->setContextProperty("testModel", &model);
3873 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3874 ctxt->setContextProperty("testTopToBottom", QVariant(false));
3876 canvas->setSource(testFileUrl("gridview1.qml"));
3878 qApp->processEvents();
3880 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3881 QVERIFY(gridview != 0);
3883 QQuickItem *contentItem = gridview->contentItem();
3884 QVERIFY(contentItem != 0);
3885 QVERIFY(gridview->delegate() != 0);
3886 QVERIFY(gridview->model() != 0);
3888 // Confirm items positioned correctly
3889 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3890 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3891 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3892 QTRY_COMPARE(item->x(), (i%3)*80.0);
3893 QTRY_COMPARE(item->y(), (i/3)*60.0);
3896 QDeclarativeIncubationController controller;
3897 canvas->engine()->setIncubationController(&controller);
3899 canvas->rootObject()->setProperty("cacheBuffer", 200);
3900 QTRY_VERIFY(gridview->cacheBuffer() == 200);
3902 // items will be created one at a time
3903 for (int i = itemCount; i < qMin(itemCount+9,model.count()); ++i) {
3904 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
3905 QQuickItem *item = 0;
3908 controller.incubateWhile(&b);
3909 item = findItem<QQuickItem>(gridview, "wrapper", i);
3915 controller.incubateWhile(&b);
3918 int newItemCount = 0;
3919 newItemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3921 // Confirm items positioned correctly
3922 for (int i = 0; i < model.count() && i < newItemCount; ++i) {
3923 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3925 QTRY_COMPARE(item->x(), (i%3)*80.0);
3926 QTRY_COMPARE(item->y(), (i/3)*60.0);
3929 // move view and confirm items in view are visible immediately and outside are created async
3930 gridview->setContentY(300);
3932 for (int i = 15; i < 34; ++i) { // 34 due to staggered item creation
3933 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3935 QTRY_COMPARE(item->x(), (i%3)*80.0);
3936 QTRY_COMPARE(item->y(), (i/3)*60.0);
3939 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == 0);
3941 // ensure buffered items are created
3942 for (int i = 34; i < qMin(44,model.count()); ++i) {
3943 QQuickItem *item = 0;
3945 qGuiApp->processEvents(); // allow refill to happen
3947 controller.incubateWhile(&b);
3948 item = findItem<QQuickItem>(gridview, "wrapper", i);
3954 controller.incubateWhile(&b);
3960 void tst_QQuickGridView::asynchronous()
3962 QQuickView *canvas = createView();
3964 QDeclarativeIncubationController controller;
3965 canvas->engine()->setIncubationController(&controller);
3967 canvas->setSource(testFile("asyncloader.qml"));
3969 QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
3970 QVERIFY(rootObject);
3972 QQuickGridView *gridview = 0;
3975 controller.incubateWhile(&b);
3976 gridview = rootObject->findChild<QQuickGridView*>("view");
3979 // items will be created one at a time
3980 for (int i = 0; i < 12; ++i) {
3981 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
3982 QQuickItem *item = 0;
3985 controller.incubateWhile(&b);
3986 item = findItem<QQuickItem>(gridview, "wrapper", i);
3992 controller.incubateWhile(&b);
3995 // verify positioning
3996 QQuickItem *contentItem = gridview->contentItem();
3997 for (int i = 0; i < 12; ++i) {
3998 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3999 if (!item) qWarning() << "Item" << i << "not found";
4000 QVERIFY(item->x() == (i%3)*100);
4001 QVERIFY(item->y() == (i/3)*100);
4007 void tst_QQuickGridView::unrequestedVisibility()
4010 for (int i = 0; i < 30; i++)
4011 model.addItem("Item" + QString::number(i), QString::number(i));
4013 QQuickView *canvas = new QQuickView(0);
4014 canvas->setGeometry(0,0,240,320);
4016 QDeclarativeContext *ctxt = canvas->rootContext();
4017 ctxt->setContextProperty("testModel", &model);
4018 ctxt->setContextProperty("testWrap", QVariant(false));
4020 canvas->setSource(testFileUrl("unrequestedItems.qml"));
4024 qApp->processEvents();
4026 QQuickGridView *leftview = findItem<QQuickGridView>(canvas->rootObject(), "leftGrid");
4027 QTRY_VERIFY(leftview != 0);
4029 QQuickGridView *rightview = findItem<QQuickGridView>(canvas->rootObject(), "rightGrid");
4030 QTRY_VERIFY(rightview != 0);
4032 QQuickItem *leftContent = leftview->contentItem();
4033 QTRY_VERIFY(leftContent != 0);
4035 QQuickItem *rightContent = rightview->contentItem();
4036 QTRY_VERIFY(rightContent != 0);
4038 rightview->setCurrentIndex(12);
4040 QTRY_COMPARE(leftview->contentY(), 0.0);
4041 QTRY_COMPARE(rightview->contentY(), 240.0);
4045 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4046 QCOMPARE(item->isVisible(), true);
4047 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
4048 QCOMPARE(item->isVisible(), false);
4050 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
4051 QCOMPARE(item->isVisible(), false);
4052 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
4053 QCOMPARE(item->isVisible(), true);
4055 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 9));
4056 QCOMPARE(item->isVisible(), true);
4057 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 10));
4058 QCOMPARE(item->isVisible(), false);
4059 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 3));
4060 QCOMPARE(item->isVisible(), false);
4061 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 4));
4062 QCOMPARE(item->isVisible(), true);
4064 rightview->setCurrentIndex(0);
4066 QTRY_COMPARE(leftview->contentY(), 0.0);
4067 QTRY_COMPARE(rightview->contentY(), 0.0);
4069 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4070 QCOMPARE(item->isVisible(), true);
4071 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
4072 QTRY_COMPARE(item->isVisible(), true);
4074 QVERIFY(!findItem<QQuickItem>(leftContent, "wrapper", 11));
4075 QVERIFY(!findItem<QQuickItem>(rightContent, "wrapper", 11));
4077 leftview->setCurrentIndex(12);
4079 QTRY_COMPARE(leftview->contentY(), 240.0);
4080 QTRY_COMPARE(rightview->contentY(), 0.0);
4082 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4083 QTRY_COMPARE(item->isVisible(), false);
4084 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
4085 QCOMPARE(item->isVisible(), true);
4087 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
4088 QCOMPARE(item->isVisible(), true);
4089 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
4090 QCOMPARE(item->isVisible(), false);
4092 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
4093 QCOMPARE(item->isVisible(), false);
4094 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 4));
4095 QCOMPARE(item->isVisible(), true);
4096 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
4097 QCOMPARE(item->isVisible(), true);
4098 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
4099 QCOMPARE(item->isVisible(), false);
4101 model.moveItems(19, 1, 1);
4102 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
4104 QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4105 QCOMPARE(item->isVisible(), false);
4106 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
4107 QCOMPARE(item->isVisible(), true);
4109 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
4110 QCOMPARE(item->isVisible(), true);
4111 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
4112 QCOMPARE(item->isVisible(), false);
4114 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
4115 QCOMPARE(item->isVisible(), false);
4116 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 4));
4117 QCOMPARE(item->isVisible(), true);
4118 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
4119 QCOMPARE(item->isVisible(), true);
4120 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
4121 QCOMPARE(item->isVisible(), false);
4123 model.moveItems(3, 4, 1);
4124 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
4126 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4127 QCOMPARE(item->isVisible(), false);
4128 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 2));
4129 QCOMPARE(item->isVisible(), true);
4130 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
4131 QCOMPARE(item->isVisible(), true);
4132 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
4133 QCOMPARE(item->isVisible(), false);
4135 model.moveItems(4, 5, 1);
4136 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
4138 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4139 QCOMPARE(item->isVisible(), false);
4140 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 2));
4141 QCOMPARE(item->isVisible(), true);
4142 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
4143 QCOMPARE(item->isVisible(), true);
4144 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
4145 QCOMPARE(item->isVisible(), false);
4147 model.moveItems(9, 10, 1);
4148 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
4150 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4151 QCOMPARE(item->isVisible(), false);
4152 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 2));
4153 QCOMPARE(item->isVisible(), true);
4154 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
4155 QCOMPARE(item->isVisible(), true);
4156 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
4157 QCOMPARE(item->isVisible(), false);
4159 model.moveItems(10, 9, 1);
4160 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
4162 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
4163 QCOMPARE(item->isVisible(), false);
4164 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 2));
4165 QCOMPARE(item->isVisible(), true);
4166 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
4167 QCOMPARE(item->isVisible(), true);
4168 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
4169 QCOMPARE(item->isVisible(), false);
4175 Find an item with the specified objectName. If index is supplied then the
4176 item must also evaluate the {index} expression equal to index
4178 template<typename T>
4179 T *tst_QQuickGridView::findItem(QQuickItem *parent, const QString &objectName, int index)
4181 const QMetaObject &mo = T::staticMetaObject;
4182 //qDebug() << parent->childItems().count() << "children";
4183 for (int i = 0; i < parent->childItems().count(); ++i) {
4184 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
4187 //qDebug() << "try" << item;
4188 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
4190 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
4192 if (context->contextProperty("index").toInt() == index) {
4193 return static_cast<T*>(item);
4197 return static_cast<T*>(item);
4200 item = findItem<T>(item, objectName, index);
4202 return static_cast<T*>(item);
4208 template<typename T>
4209 QList<T*> tst_QQuickGridView::findItems(QQuickItem *parent, const QString &objectName)
4212 const QMetaObject &mo = T::staticMetaObject;
4213 //qDebug() << parent->childItems().count() << "children";
4214 for (int i = 0; i < parent->childItems().count(); ++i) {
4215 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
4218 //qDebug() << "try" << item;
4219 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
4220 items.append(static_cast<T*>(item));
4221 //qDebug() << " found:" << item;
4223 items += findItems<T>(item, objectName);
4229 void tst_QQuickGridView::dumpTree(QQuickItem *parent, int depth)
4231 static QString padding(" ");
4232 for (int i = 0; i < parent->childItems().count(); ++i) {
4233 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
4236 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
4237 qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
4238 dumpTree(item, depth+1);
4243 QTEST_MAIN(tst_QQuickGridView)
4245 #include "tst_qquickgridview.moc"