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 <QtQml/qqmlengine.h>
46 #include <QtQml/qqmlcomponent.h>
47 #include <QtQml/qqmlcontext.h>
48 #include <QtQml/qqmlexpression.h>
49 #include <QtQml/qqmlincubator.h>
50 #include <QtQuick/private/qquickitem_p.h>
51 #include <QtQuick/private/qquickgridview_p.h>
52 #include <QtQuick/private/qquicktext_p.h>
53 #include <QtQuick/private/qquickvisualitemmodel_p.h>
54 #include <QtQml/private/qquicklistmodel_p.h>
55 #include <QtQml/private/qlistmodelinterface_p.h>
56 #include "../../shared/util.h"
57 #include "../shared/viewtestutil.h"
58 #include "../shared/visualtestutil.h"
59 #include <QtGui/qguiapplication.h>
61 Q_DECLARE_METATYPE(Qt::LayoutDirection)
62 Q_DECLARE_METATYPE(QQuickGridView::Flow)
64 using namespace QQuickViewTestUtil;
65 using namespace QQuickVisualTestUtil;
69 class tst_QQuickGridView : public QQmlDataTest
81 void inserted_more_data();
82 void insertBeforeVisible();
83 void insertBeforeVisible_data();
86 void removed_more_data();
87 void addOrRemoveBeforeVisible();
88 void addOrRemoveBeforeVisible_data();
92 void multipleChanges();
93 void multipleChanges_data();
94 void swapWithFirstItem();
97 void noCurrentIndex();
100 void propertyChanges();
101 void componentChanges();
103 void positionViewAtIndex();
104 void positionViewAtIndex_rightToLeft();
109 void enforceRange_rightToLeft();
111 void manualHighlight();
117 void resizeViewAndRepaint();
118 void changeColumnCount();
119 void indexAt_itemAt_data();
120 void indexAt_itemAt();
124 void onRemove_data();
127 void creationContext();
128 void snapToRow_data();
130 void snapOneRow_data();
135 void unrequestedVisibility();
137 void populateTransitions();
138 void populateTransitions_data();
139 void addTransitions();
140 void addTransitions_data();
141 void moveTransitions();
142 void moveTransitions_data();
143 void removeTransitions();
144 void removeTransitions_data();
145 void displacedTransitions();
146 void displacedTransitions_data();
147 void multipleTransitions();
148 void multipleTransitions_data();
149 void multipleDisplaced();
152 QList<int> toIntList(const QVariantList &list);
153 void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes);
154 void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes);
155 void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems);
158 QQuickView *getView() {
160 if (QString(QTest::currentTestFunction()) != testForView) {
164 m_view->setSource(QUrl());
169 testForView = QTest::currentTestFunction();
170 m_view = createView();
173 void releaseView(QQuickView *view) {
174 Q_ASSERT(view == m_view);
175 m_view->setSource(QUrl());
178 QQuickView *getView() {
181 void releaseView(QQuickView *view) {
190 tst_QQuickGridView::tst_QQuickGridView() : m_view(0)
194 void tst_QQuickGridView::init()
197 if (m_view && QString(QTest::currentTestFunction()) != testForView) {
198 testForView = QString();
205 void tst_QQuickGridView::items()
207 QQuickView *canvas = createView();
210 model.addItem("Fred", "12345");
211 model.addItem("John", "2345");
212 model.addItem("Bob", "54321");
213 model.addItem("Billy", "22345");
214 model.addItem("Sam", "2945");
215 model.addItem("Ben", "04321");
216 model.addItem("Jim", "0780");
218 QQmlContext *ctxt = canvas->rootContext();
219 ctxt->setContextProperty("testModel", &model);
220 ctxt->setContextProperty("testRightToLeft", QVariant(false));
221 ctxt->setContextProperty("testTopToBottom", QVariant(false));
223 canvas->setSource(testFileUrl("gridview1.qml"));
224 qApp->processEvents();
226 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
227 QTRY_VERIFY(gridview != 0);
229 QQuickItem *contentItem = gridview->contentItem();
230 QTRY_VERIFY(contentItem != 0);
232 QTRY_COMPARE(gridview->count(), model.count());
233 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
234 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
236 for (int i = 0; i < model.count(); ++i) {
237 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
238 QTRY_VERIFY(name != 0);
239 QTRY_COMPARE(name->text(), model.name(i));
240 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
241 QTRY_VERIFY(number != 0);
242 QTRY_COMPARE(number->text(), model.number(i));
245 // set an empty model and confirm that items are destroyed
247 ctxt->setContextProperty("testModel", &model2);
249 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
250 QTRY_VERIFY(itemCount == 0);
255 void tst_QQuickGridView::changed()
257 QQuickView *canvas = createView();
260 model.addItem("Fred", "12345");
261 model.addItem("John", "2345");
262 model.addItem("Bob", "54321");
263 model.addItem("Billy", "22345");
264 model.addItem("Sam", "2945");
265 model.addItem("Ben", "04321");
266 model.addItem("Jim", "0780");
268 QQmlContext *ctxt = canvas->rootContext();
269 ctxt->setContextProperty("testModel", &model);
270 ctxt->setContextProperty("testRightToLeft", QVariant(false));
271 ctxt->setContextProperty("testTopToBottom", QVariant(false));
273 canvas->setSource(testFileUrl("gridview1.qml"));
274 qApp->processEvents();
276 QQuickFlickable *gridview = findItem<QQuickFlickable>(canvas->rootObject(), "grid");
277 QTRY_VERIFY(gridview != 0);
279 QQuickItem *contentItem = gridview->contentItem();
280 QTRY_VERIFY(contentItem != 0);
282 model.modifyItem(1, "Will", "9876");
283 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
284 QTRY_VERIFY(name != 0);
285 QTRY_COMPARE(name->text(), model.name(1));
286 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
287 QTRY_VERIFY(number != 0);
288 QTRY_COMPARE(number->text(), model.number(1));
293 void tst_QQuickGridView::inserted()
295 QQuickView *canvas = createView();
299 model.addItem("Fred", "12345");
300 model.addItem("John", "2345");
301 model.addItem("Bob", "54321");
303 QQmlContext *ctxt = canvas->rootContext();
304 ctxt->setContextProperty("testModel", &model);
305 ctxt->setContextProperty("testRightToLeft", QVariant(false));
306 ctxt->setContextProperty("testTopToBottom", QVariant(false));
308 canvas->setSource(testFileUrl("gridview1.qml"));
309 qApp->processEvents();
311 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
312 QTRY_VERIFY(gridview != 0);
314 QQuickItem *contentItem = gridview->contentItem();
315 QTRY_VERIFY(contentItem != 0);
317 model.insertItem(1, "Will", "9876");
319 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
320 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
322 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
323 QTRY_VERIFY(name != 0);
324 QTRY_COMPARE(name->text(), model.name(1));
325 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
326 QTRY_VERIFY(number != 0);
327 QTRY_COMPARE(number->text(), model.number(1));
329 // Checks that onAdd is called
330 int added = canvas->rootObject()->property("added").toInt();
331 QTRY_COMPARE(added, 1);
333 // Confirm items positioned correctly
334 for (int i = 0; i < model.count(); ++i) {
335 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
336 QTRY_COMPARE(item->x(), (i%3)*80.0);
337 QTRY_COMPARE(item->y(), (i/3)*60.0);
340 model.insertItem(0, "Foo", "1111"); // zero index, and current item
342 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
344 name = findItem<QQuickText>(contentItem, "textName", 0);
345 QTRY_VERIFY(name != 0);
346 QTRY_COMPARE(name->text(), model.name(0));
347 number = findItem<QQuickText>(contentItem, "textNumber", 0);
348 QTRY_VERIFY(number != 0);
349 QTRY_COMPARE(number->text(), model.number(0));
351 QTRY_COMPARE(gridview->currentIndex(), 1);
353 // Confirm items positioned correctly
354 for (int i = 0; i < model.count(); ++i) {
355 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
356 QTRY_VERIFY(item->x() == (i%3)*80);
357 QTRY_VERIFY(item->y() == (i/3)*60);
360 for (int i = model.count(); i < 30; ++i)
361 model.insertItem(i, "Hello", QString::number(i));
363 gridview->setContentY(120);
365 // Insert item outside visible area
366 model.insertItem(1, "Hello", "1324");
368 QTRY_VERIFY(gridview->contentY() == 120);
373 void tst_QQuickGridView::inserted_more()
375 QFETCH(qreal, contentY);
376 QFETCH(int, insertIndex);
377 QFETCH(int, insertCount);
378 QFETCH(qreal, itemsOffsetAfterMove);
381 for (int i = 0; i < 30; i++)
382 model.addItem("Item" + QString::number(i), "");
384 QQuickView *canvas = getView();
385 QQmlContext *ctxt = canvas->rootContext();
386 ctxt->setContextProperty("testModel", &model);
387 ctxt->setContextProperty("testRightToLeft", QVariant(false));
388 ctxt->setContextProperty("testTopToBottom", QVariant(false));
390 canvas->setSource(testFileUrl("gridview1.qml"));
392 qApp->processEvents();
394 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
395 QTRY_VERIFY(gridview != 0);
396 QQuickItem *contentItem = gridview->contentItem();
397 QTRY_VERIFY(contentItem != 0);
399 gridview->setContentY(contentY);
400 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
402 QList<QPair<QString, QString> > newData;
403 for (int i=0; i<insertCount; i++)
404 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
405 model.insertItems(insertIndex, newData);
406 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
408 // check visibleItems.first() is in correct position
409 QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
411 QCOMPARE(item0->y(), 0.0);
413 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
414 int firstVisibleIndex = -1;
415 for (int i=0; i<items.count(); i++) {
416 if (items[i]->y() >= contentY) {
417 QQmlExpression e(qmlContext(items[i]), items[i], "index");
418 firstVisibleIndex = e.evaluate().toInt();
422 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
424 // Confirm items positioned correctly and indexes correct
425 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
428 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
429 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
430 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
432 QCOMPARE(item->x(), (i%3)*80.0);
433 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
435 name = findItem<QQuickText>(contentItem, "textName", i);
437 QCOMPARE(name->text(), model.name(i));
438 number = findItem<QQuickText>(contentItem, "textNumber", i);
439 QVERIFY(number != 0);
440 QCOMPARE(number->text(), model.number(i));
446 void tst_QQuickGridView::inserted_more_data()
448 QTest::addColumn<qreal>("contentY");
449 QTest::addColumn<int>("insertIndex");
450 QTest::addColumn<int>("insertCount");
451 QTest::addColumn<qreal>("itemsOffsetAfterMove");
453 QTest::newRow("add 1, before visible items")
454 << 120.0 // show 6-23
456 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
457 // new 1st visible item is at 0
459 QTest::newRow("add 2, before visible items")
460 << 120.0 // show 6-23
462 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
464 QTest::newRow("add 3, before visible items")
465 << 120.0 // show 6-23
467 << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
469 QTest::newRow("add 5, before visible items")
470 << 120.0 // show 6-23
472 << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
473 // grid is rearranged and first visible moves forward within its row
475 QTest::newRow("add 6, before visible items")
476 << 120.0 // show 6-23
478 << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
482 QTest::newRow("add 1, at start of visible, content at start")
487 QTest::newRow("add multiple, at start of visible, content at start")
492 QTest::newRow("add 1, at start of visible, content not at start")
493 << 120.0 // show 6-23
497 QTest::newRow("add multiple, at start of visible, content not at start")
498 << 120.0 // show 6-23
503 QTest::newRow("add 1, at end of visible, content at start")
508 QTest::newRow("add 1, at end of visible, content at start")
513 QTest::newRow("add 1, at end of visible, content not at start")
514 << 120.0 // show 6-23
518 QTest::newRow("add multiple, at end of visible, content not at start")
519 << 120.0 // show 6-23
524 QTest::newRow("add 1, after visible, content at start")
529 QTest::newRow("add 1, after visible, content at start")
534 QTest::newRow("add 1, after visible, content not at start")
535 << 120.0 // show 6-23
539 QTest::newRow("add multiple, after visible, content not at start")
540 << 120.0 // show 6-23
545 void tst_QQuickGridView::insertBeforeVisible()
547 QFETCH(int, insertIndex);
548 QFETCH(int, insertCount);
549 QFETCH(int, cacheBuffer);
552 QQuickView *canvas = getView();
555 for (int i = 0; i < 30; i++)
556 model.addItem("Item" + QString::number(i), "");
558 QQmlContext *ctxt = canvas->rootContext();
559 ctxt->setContextProperty("testModel", &model);
560 ctxt->setContextProperty("testRightToLeft", QVariant(false));
561 ctxt->setContextProperty("testTopToBottom", QVariant(false));
562 canvas->setSource(testFileUrl("gridview1.qml"));
564 qApp->processEvents();
566 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
567 QTRY_VERIFY(gridview != 0);
568 QQuickItem *contentItem = gridview->contentItem();
569 QTRY_VERIFY(contentItem != 0);
571 gridview->setCacheBuffer(cacheBuffer);
572 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
574 // trigger a refill (not just setting contentY) so that the visibleItems grid is updated
575 int firstVisibleIndex = 12; // move to an index where the top item is not visible
576 gridview->setContentY(firstVisibleIndex/3 * 60.0);
577 gridview->setCurrentIndex(firstVisibleIndex);
578 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
580 QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex);
581 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex);
583 QCOMPARE(item->y(), gridview->contentY());
585 QList<QPair<QString, QString> > newData;
586 for (int i=0; i<insertCount; i++)
587 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
588 model.insertItems(insertIndex, newData);
589 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
591 // now, moving to the top of the view should position the inserted items correctly
592 int itemsOffsetAfterMove = (insertCount / 3) * -60.0;
593 gridview->setCurrentIndex(0);
594 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
595 QTRY_COMPARE(gridview->currentIndex(), 0);
596 QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove);
598 // Confirm items positioned correctly and indexes correct
599 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
600 for (int i = 0; i < model.count() && i < itemCount; ++i) {
601 item = findItem<QQuickItem>(contentItem, "wrapper", i);
602 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
603 QCOMPARE(item->x(), (i%3)*80.0);
604 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
605 name = findItem<QQuickText>(contentItem, "textName", i);
607 QTRY_COMPARE(name->text(), model.name(i));
613 void tst_QQuickGridView::insertBeforeVisible_data()
615 QTest::addColumn<int>("insertIndex");
616 QTest::addColumn<int>("insertCount");
617 QTest::addColumn<int>("cacheBuffer");
619 QTest::newRow("insert 1 at 0, 0 buffer") << 0 << 1 << 0;
620 QTest::newRow("insert 1 at 0, 100 buffer") << 0 << 1 << 100;
621 QTest::newRow("insert 1 at 0, 500 buffer") << 0 << 1 << 500;
623 QTest::newRow("insert 1 at 1, 0 buffer") << 1 << 1 << 0;
624 QTest::newRow("insert 1 at 1, 100 buffer") << 1 << 1 << 100;
625 QTest::newRow("insert 1 at 1, 500 buffer") << 1 << 1 << 500;
627 QTest::newRow("insert multiple at 0, 0 buffer") << 0 << 6 << 0;
628 QTest::newRow("insert multiple at 0, 100 buffer") << 0 << 6 << 100;
629 QTest::newRow("insert multiple at 0, 500 buffer") << 0 << 6 << 500;
631 QTest::newRow("insert multiple at 1, 0 buffer") << 1 << 6 << 0;
632 QTest::newRow("insert multiple at 1, 100 buffer") << 1 << 6 << 100;
633 QTest::newRow("insert multiple at 1, 500 buffer") << 1 << 6 << 500;
636 void tst_QQuickGridView::removed()
638 QQuickView *canvas = createView();
642 for (int i = 0; i < 40; i++)
643 model.addItem("Item" + QString::number(i), "");
645 QQmlContext *ctxt = canvas->rootContext();
646 ctxt->setContextProperty("testModel", &model);
647 ctxt->setContextProperty("testRightToLeft", QVariant(false));
648 ctxt->setContextProperty("testTopToBottom", QVariant(false));
650 canvas->setSource(testFileUrl("gridview1.qml"));
651 qApp->processEvents();
653 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
654 QTRY_VERIFY(gridview != 0);
655 QQuickItem *contentItem = gridview->contentItem();
656 QTRY_VERIFY(contentItem != 0);
657 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
660 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
662 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
663 QTRY_VERIFY(name != 0);
664 QTRY_COMPARE(name->text(), model.name(1));
665 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
666 QTRY_VERIFY(number != 0);
667 QTRY_COMPARE(number->text(), model.number(1));
670 // Checks that onRemove is called
671 QString removed = canvas->rootObject()->property("removed").toString();
672 QTRY_COMPARE(removed, QString("Item1"));
674 // Confirm items positioned correctly
675 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
676 for (int i = 0; i < model.count() && i < itemCount; ++i) {
677 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
678 if (!item) qWarning() << "Item" << i << "not found";
679 QTRY_VERIFY(item->x() == (i%3)*80);
680 QTRY_VERIFY(item->y() == (i/3)*60);
683 // Remove first item (which is the current item);
685 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
687 name = findItem<QQuickText>(contentItem, "textName", 0);
688 QTRY_VERIFY(name != 0);
689 QTRY_COMPARE(name->text(), model.name(0));
690 number = findItem<QQuickText>(contentItem, "textNumber", 0);
691 QTRY_VERIFY(number != 0);
692 QTRY_COMPARE(number->text(), model.number(0));
695 // Confirm items positioned correctly
696 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
697 for (int i = 0; i < model.count() && i < itemCount; ++i) {
698 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
699 if (!item) qWarning() << "Item" << i << "not found";
700 QTRY_VERIFY(item->x() == (i%3)*80);
701 QTRY_VERIFY(item->y() == (i/3)*60);
704 // Remove items not visible
705 model.removeItem(25);
706 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
708 // Confirm items positioned correctly
709 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
710 for (int i = 0; i < model.count() && i < itemCount; ++i) {
711 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
712 if (!item) qWarning() << "Item" << i << "not found";
713 QTRY_VERIFY(item->x() == (i%3)*80);
714 QTRY_VERIFY(item->y() == (i/3)*60);
717 // Remove items before visible
718 gridview->setContentY(120);
719 gridview->setCurrentIndex(10);
721 // Setting currentIndex above shouldn't cause view to scroll
722 QTRY_COMPARE(gridview->contentY(), 120.0);
725 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
727 // Confirm items positioned correctly
728 for (int i = 6; i < 18; ++i) {
729 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
730 if (!item) qWarning() << "Item" << i << "not found";
731 QTRY_VERIFY(item->x() == (i%3)*80);
732 QTRY_VERIFY(item->y() == (i/3)*60);
735 // Remove currentIndex
736 QQuickItem *oldCurrent = gridview->currentItem();
738 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
740 QTRY_COMPARE(gridview->currentIndex(), 9);
741 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
743 gridview->setContentY(0);
744 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
746 // Confirm items positioned correctly
747 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
748 for (int i = 0; i < model.count() && i < itemCount; ++i) {
749 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
750 QTRY_VERIFY(item->x() == (i%3)*80);
751 QTRY_VERIFY(item->y() == (i/3)*60);
754 // remove item outside current view.
755 gridview->setCurrentIndex(32);
756 gridview->setContentY(240);
758 model.removeItem(30);
759 QTRY_VERIFY(gridview->currentIndex() == 31);
761 // remove current item beyond visible items.
762 gridview->setCurrentIndex(20);
763 gridview->setContentY(0);
764 model.removeItem(20);
766 QTRY_COMPARE(gridview->currentIndex(), 20);
767 QTRY_VERIFY(gridview->currentItem() != 0);
769 // remove item before current, but visible
770 gridview->setCurrentIndex(8);
771 gridview->setContentY(240);
772 oldCurrent = gridview->currentItem();
775 QTRY_COMPARE(gridview->currentIndex(), 7);
776 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
781 void tst_QQuickGridView::removed_more()
783 QFETCH(qreal, contentY);
784 QFETCH(int, removeIndex);
785 QFETCH(int, removeCount);
786 QFETCH(qreal, itemsOffsetAfterMove);
787 QFETCH(QString, firstVisible);
791 QQuickView *canvas = getView();
794 for (int i = 0; i < 30; i++)
795 model.addItem("Item" + QString::number(i), "");
797 QQmlContext *ctxt = canvas->rootContext();
798 ctxt->setContextProperty("testModel", &model);
799 ctxt->setContextProperty("testRightToLeft", QVariant(false));
800 ctxt->setContextProperty("testTopToBottom", QVariant(false));
801 canvas->setSource(testFileUrl("gridview1.qml"));
803 qApp->processEvents();
805 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
806 QTRY_VERIFY(gridview != 0);
807 QQuickItem *contentItem = gridview->contentItem();
808 QTRY_VERIFY(contentItem != 0);
810 gridview->setContentY(contentY);
811 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
813 model.removeItems(removeIndex, removeCount);
814 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
817 int firstVisibleIndex = -1;
818 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
819 for (int i=0; i<items.count(); i++) {
820 if (items[i]->y() >= contentY) {
821 QQmlExpression e(qmlContext(items[i]), items[i], "index");
822 firstVisibleIndex = e.evaluate().toInt();
823 QQmlExpression en(qmlContext(items[i]), items[i], "name");
824 firstName = en.evaluate().toString();
828 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
829 QCOMPARE(firstName, firstVisible);
831 // Confirm items positioned correctly and indexes correct
832 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
833 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
834 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
835 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
837 QTRY_COMPARE(item->x(), (i%3)*80.0);
838 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
840 name = findItem<QQuickText>(contentItem, "textName", i);
842 QTRY_COMPARE(name->text(), model.name(i));
843 number = findItem<QQuickText>(contentItem, "textNumber", i);
844 QVERIFY(number != 0);
845 QTRY_COMPARE(number->text(), model.number(i));
851 void tst_QQuickGridView::removed_more_data()
853 QTest::addColumn<qreal>("contentY");
854 QTest::addColumn<int>("removeIndex");
855 QTest::addColumn<int>("removeCount");
856 QTest::addColumn<qreal>("itemsOffsetAfterMove");
857 QTest::addColumn<QString>("firstVisible");
859 QTest::newRow("remove 1, before visible items")
860 << 120.0 // show 6-23
864 QTest::newRow("remove 1, before visible position")
865 << 120.0 // show 6-23
869 QTest::newRow("remove multiple, all before visible items")
872 << 60.0 << "Item6"; // removed top row, slide down by 1 row
874 QTest::newRow("remove multiple, all before visible items, remove item 0")
877 << 60.0 << "Item7"; // removed top row, slide down by 1 row
879 QTest::newRow("remove multiple rows, all before visible items")
880 << 240.0 // show 12-29
882 << 120.0 << "Item13";
884 QTest::newRow("remove one row before visible, content y not on item border")
887 << 60.0 << "Item6"; // 1 row removed
889 QTest::newRow("remove mix of visible/non-visible")
890 << 120.0 // show 6-23
892 << 60.0 << "Item6"; // 1 row removed
895 // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos,
896 // items 6,7 are removed from view, item 8 slides up to original pos of item 6 (120px)
897 QTest::newRow("remove multiple, mix of items from before and within visible items")
900 << 60.0 << "Item8"; // adjust for the 1 row removed before the visible
902 QTest::newRow("remove multiple, mix of items from before and within visible items, remove item 0")
905 << 60.0 * 2 << "Item8"; // adjust for the 2 rows removed before the visible
908 QTest::newRow("remove 1, from start of visible, content at start")
913 QTest::newRow("remove multiple, from start of visible, content at start")
918 QTest::newRow("remove 1, from start of visible, content not at start")
919 << 120.0 // show 6-23
923 QTest::newRow("remove multiple, from start of visible, content not at start")
924 << 120.0 // show 6-23
929 QTest::newRow("remove 1, from middle of visible, content at start")
934 QTest::newRow("remove multiple, from middle of visible, content at start")
939 QTest::newRow("remove 1, from middle of visible, content not at start")
940 << 120.0 // show 6-23
944 QTest::newRow("remove multiple, from middle of visible, content not at start")
945 << 120.0 // show 6-23
950 QTest::newRow("remove 1, after visible, content at start")
955 QTest::newRow("remove multiple, after visible, content at start")
960 QTest::newRow("remove 1, after visible, content not at start")
961 << 120.0 // show 6-23
965 QTest::newRow("remove multiple, after visible, content not at start")
966 << 120.0 // show 6-23
970 QTest::newRow("remove multiple, mix of items from within and after visible items")
971 << 120.0 // show 6-23
976 void tst_QQuickGridView::addOrRemoveBeforeVisible()
978 // QTBUG-21588: ensure re-layout is done on grid after adding or removing
979 // items from before the visible area
982 QFETCH(qreal, newTopContentY);
984 QQuickView *canvas = getView();
988 for (int i = 0; i < 30; i++)
989 model.addItem("Item" + QString::number(i), "");
991 QQmlContext *ctxt = canvas->rootContext();
992 ctxt->setContextProperty("testModel", &model);
993 ctxt->setContextProperty("testRightToLeft", QVariant(false));
994 ctxt->setContextProperty("testTopToBottom", QVariant(false));
995 canvas->setSource(testFileUrl("gridview1.qml"));
997 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
998 QTRY_VERIFY(gridview != 0);
999 QQuickItem *contentItem = gridview->contentItem();
1000 QTRY_VERIFY(contentItem != 0);
1002 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
1003 QTRY_COMPARE(name->text(), QString("Item0"));
1005 gridview->setCurrentIndex(0);
1006 qApp->processEvents();
1007 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1009 // scroll down until item 0 is no longer drawn
1010 // (bug not triggered if we just move using content y, since that doesn't
1011 // refill and change the visible items)
1012 gridview->setCurrentIndex(24);
1013 qApp->processEvents();
1015 QTRY_COMPARE(gridview->currentIndex(), 24);
1016 QTRY_COMPARE(gridview->contentY(), 220.0);
1018 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1019 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible
1022 model.insertItem(0, "New Item", "New Item number");
1023 QTRY_COMPARE(gridview->count(), 31);
1025 model.removeItem(0);
1026 QTRY_COMPARE(gridview->count(), 29);
1029 // scroll back up and item 0 should be gone
1030 gridview->setCurrentIndex(0);
1031 qApp->processEvents();
1032 QTRY_COMPARE(gridview->currentIndex(), 0);
1033 QTRY_COMPARE(gridview->contentY(), newTopContentY);
1035 name = findItem<QQuickText>(contentItem, "textName", 0);
1037 QCOMPARE(name->text(), QString("New Item"));
1039 QCOMPARE(name->text(), QString("Item1"));
1041 // Confirm items positioned correctly
1042 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1043 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1044 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i));
1045 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1046 QTRY_VERIFY(item->x() == (i%3)*80);
1047 QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY);
1050 releaseView(canvas);
1053 void tst_QQuickGridView::addOrRemoveBeforeVisible_data()
1055 QTest::addColumn<bool>("doAdd");
1056 QTest::addColumn<qreal>("newTopContentY");
1058 QTest::newRow("add") << true << -60.0;
1059 QTest::newRow("remove") << false << -60.0;
1062 void tst_QQuickGridView::clear()
1064 QQuickView *canvas = createView();
1067 for (int i = 0; i < 30; i++)
1068 model.addItem("Item" + QString::number(i), "");
1070 QQmlContext *ctxt = canvas->rootContext();
1071 ctxt->setContextProperty("testModel", &model);
1072 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1073 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1075 canvas->setSource(testFileUrl("gridview1.qml"));
1077 qApp->processEvents();
1079 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1080 QVERIFY(gridview != 0);
1081 QQuickItem *contentItem = gridview->contentItem();
1082 QVERIFY(contentItem != 0);
1083 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1087 QVERIFY(gridview->count() == 0);
1088 QVERIFY(gridview->currentItem() == 0);
1089 QVERIFY(gridview->contentY() == 0);
1090 QVERIFY(gridview->currentIndex() == -1);
1092 // confirm sanity when adding an item to cleared list
1093 model.addItem("New", "1");
1094 QTRY_COMPARE(gridview->count(), 1);
1095 QVERIFY(gridview->currentItem() != 0);
1096 QVERIFY(gridview->currentIndex() == 0);
1101 void tst_QQuickGridView::moved()
1103 QFETCH(qreal, contentY);
1107 QFETCH(qreal, itemsOffsetAfterMove);
1111 QQuickView *canvas = getView();
1114 for (int i = 0; i < 30; i++)
1115 model.addItem("Item" + QString::number(i), "");
1117 QQmlContext *ctxt = canvas->rootContext();
1118 ctxt->setContextProperty("testModel", &model);
1119 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1120 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1122 canvas->setSource(testFileUrl("gridview1.qml"));
1124 qApp->processEvents();
1126 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1127 QTRY_VERIFY(gridview != 0);
1128 QQuickItem *contentItem = gridview->contentItem();
1129 QTRY_VERIFY(contentItem != 0);
1130 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1132 QQuickItem *currentItem = gridview->currentItem();
1133 QTRY_VERIFY(currentItem != 0);
1135 if (contentY != 0) {
1136 gridview->setContentY(contentY);
1137 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1140 model.moveItems(from, to, count);
1141 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1143 // Confirm items positioned correctly and indexes correct
1144 int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
1145 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1146 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
1147 if (i >= firstVisibleIndex + 18) // index has moved out of view
1149 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1150 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1152 QTRY_COMPARE(item->x(), (i%3)*80.0);
1153 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
1155 name = findItem<QQuickText>(contentItem, "textName", i);
1157 QTRY_COMPARE(name->text(), model.name(i));
1158 number = findItem<QQuickText>(contentItem, "textNumber", i);
1159 QVERIFY(number != 0);
1160 QTRY_COMPARE(number->text(), model.number(i));
1162 // current index should have been updated
1163 if (item == currentItem)
1164 QTRY_COMPARE(gridview->currentIndex(), i);
1167 releaseView(canvas);
1170 void tst_QQuickGridView::moved_data()
1172 QTest::addColumn<qreal>("contentY");
1173 QTest::addColumn<int>("from");
1174 QTest::addColumn<int>("to");
1175 QTest::addColumn<int>("count");
1176 QTest::addColumn<qreal>("itemsOffsetAfterMove");
1178 // model starts with 30 items, each 80x60, in area 240x320
1179 // 18 items should be visible at a time
1181 // The first visible item should not move upwards and out of the view
1182 // if items are moved/removed before it.
1185 QTest::newRow("move 1 forwards, within visible items")
1190 QTest::newRow("move 1 forwards, from non-visible -> visible")
1191 << 120.0 // show 6-23
1195 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
1196 << 120.0 // // show 6-23
1200 QTest::newRow("move 1 forwards, from visible -> non-visible")
1205 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
1211 QTest::newRow("move 1 backwards, within visible items")
1216 QTest::newRow("move 1 backwards, within visible items (to first index)")
1221 QTest::newRow("move 1 backwards, from non-visible -> visible")
1226 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
1231 QTest::newRow("move 1 backwards, from visible -> non-visible")
1232 << 120.0 // show 6-23
1234 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1236 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
1237 << 120.0 // show 6-23
1239 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1242 QTest::newRow("move multiple forwards, within visible items")
1247 QTest::newRow("move multiple backwards, within visible items (move first item)")
1252 QTest::newRow("move multiple forwards, before visible items")
1253 << 120.0 // show 6-23
1254 << 3 << 4 << 3 // 3, 4, 5 move to after 6
1255 << 60.0; // row of 3,4,5 has moved down
1257 QTest::newRow("move multiple forwards, from non-visible -> visible")
1258 << 120.0 // show 6-23
1260 << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
1262 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
1263 << 120.0 // show 6-23
1265 << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
1267 QTest::newRow("move multiple forwards, mix of non-visible/visible")
1270 << 60.0; // top two rows removed, third row is now the first visible
1272 QTest::newRow("move multiple forwards, to bottom of view")
1277 QTest::newRow("move multiple forwards, to bottom of view, first row -> last")
1282 QTest::newRow("move multiple forwards, to bottom of view, content y not 0")
1287 QTest::newRow("move multiple forwards, from visible -> non-visible")
1292 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
1298 QTest::newRow("move multiple backwards, within visible items")
1303 QTest::newRow("move multiple backwards, from non-visible -> visible")
1308 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
1313 QTest::newRow("move multiple backwards, from visible -> non-visible")
1314 << 120.0 // show 6-23
1316 << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
1318 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
1319 << 120.0 // show 6-23
1321 << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
1324 void tst_QQuickGridView::multipleChanges()
1326 QFETCH(int, startCount);
1327 QFETCH(QList<ListChange>, changes);
1328 QFETCH(int, newCount);
1329 QFETCH(int, newCurrentIndex);
1331 QQuickView *canvas = getView();
1334 for (int i = 0; i < startCount; i++)
1335 model.addItem("Item" + QString::number(i), "");
1337 QQmlContext *ctxt = canvas->rootContext();
1338 ctxt->setContextProperty("testModel", &model);
1339 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1340 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1342 canvas->setSource(testFileUrl("gridview1.qml"));
1344 qApp->processEvents();
1346 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1347 QTRY_VERIFY(gridview != 0);
1348 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1350 for (int i=0; i<changes.count(); i++) {
1351 switch (changes[i].type) {
1352 case ListChange::Inserted:
1354 QList<QPair<QString, QString> > items;
1355 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1356 items << qMakePair(QString("new item " + j), QString::number(j));
1357 model.insertItems(changes[i].index, items);
1360 case ListChange::Removed:
1361 model.removeItems(changes[i].index, changes[i].count);
1362 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1364 case ListChange::Moved:
1365 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1366 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1368 case ListChange::SetCurrent:
1369 gridview->setCurrentIndex(changes[i].index);
1370 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1372 case ListChange::SetContentY:
1373 gridview->setContentY(changes[i].pos);
1374 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1379 QTRY_COMPARE(gridview->count(), newCount);
1380 QCOMPARE(gridview->count(), model.count());
1381 QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
1385 QQuickItem *contentItem = gridview->contentItem();
1386 QTRY_VERIFY(contentItem != 0);
1387 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1388 for (int i=0; i < model.count() && i < itemCount; ++i) {
1389 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1390 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1391 name = findItem<QQuickText>(contentItem, "textName", i);
1393 QTRY_COMPARE(name->text(), model.name(i));
1394 number = findItem<QQuickText>(contentItem, "textNumber", i);
1395 QVERIFY(number != 0);
1396 QTRY_COMPARE(number->text(), model.number(i));
1399 releaseView(canvas);
1402 void tst_QQuickGridView::multipleChanges_data()
1404 QTest::addColumn<int>("startCount");
1405 QTest::addColumn<QList<ListChange> >("changes");
1406 QTest::addColumn<int>("newCount");
1407 QTest::addColumn<int>("newCurrentIndex");
1409 QList<ListChange> changes;
1411 for (int i=1; i<30; i++)
1412 changes << ListChange::remove(0);
1413 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1415 changes << ListChange::remove(0);
1416 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1419 changes << ListChange::setCurrent(29);
1420 for (int i=29; i>0; i--)
1421 changes << ListChange::remove(i);
1422 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1424 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1425 << ListChange::remove(0, 1)
1426 << ListChange::insert(0, 1)
1429 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1430 << ListChange::setCurrent(2)
1431 << ListChange::remove(2, 1)
1432 << ListChange::insert(2, 1)
1435 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1436 << ListChange::setCurrent(1)
1437 << ListChange::remove(1, 3)
1438 << ListChange::insert(2, 2)
1441 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1442 << ListChange::setCurrent(2)
1443 << ListChange::remove(1, 3)
1444 << ListChange::move(1, 5, 1)
1447 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1448 << ListChange::setCurrent(5)
1449 << ListChange::remove(4, 3)
1450 << ListChange::move(4, 1, 1)
1454 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1455 << ListChange::insert(0, 2)
1456 << ListChange::insert(0, 4)
1457 << ListChange::insert(0, 6)
1460 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1461 << ListChange::insert(0, 2)
1462 << ListChange::insert(0, 4)
1463 << ListChange::insert(0, 6)
1464 << ListChange::setCurrent(3)
1465 << ListChange::insert(3, 2)
1468 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1469 << ListChange::insert(0, 30)
1470 << ListChange::remove(0, 30)
1473 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1474 << ListChange::insert(1)
1475 << ListChange::setCurrent(1)
1476 << ListChange::remove(1)
1479 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1480 << ListChange::insert(0, 10)
1481 << ListChange::remove(5, 10)
1484 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1485 << ListChange::insert(0, 3)
1486 << ListChange::move(0, 10, 3)
1489 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1490 << ListChange::insert(0, 3)
1491 << ListChange::move(0, 8, 5)
1494 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1495 << ListChange::setCurrent(9)
1496 << ListChange::insert(10, 3)
1497 << ListChange::move(8, 0, 5)
1501 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1502 << ListChange::setCurrent(1)
1503 << ListChange::move(1, 2, 2)
1504 << ListChange::move(2, 1, 2)
1507 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1508 << ListChange::setCurrent(2)
1509 << ListChange::move(1, 2, 3)
1510 << ListChange::move(3, 0, 5)
1513 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1514 << ListChange::setCurrent(5)
1515 << ListChange::move(5, 0, 1)
1516 << ListChange::remove(0)
1519 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1520 << ListChange::setCurrent(5)
1521 << ListChange::move(5, 0, 1)
1522 << ListChange::insert(0)
1525 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1526 << ListChange::setCurrent(1)
1527 << ListChange::move(5, 1, 3)
1528 << ListChange::remove(1, 3)
1531 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1532 << ListChange::setCurrent(5)
1533 << ListChange::move(5, 1, 3)
1534 << ListChange::insert(1, 5)
1537 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1538 << ListChange::setCurrent(3)
1539 << ListChange::move(0, 1, 2)
1540 << ListChange::insert(3, 5)
1544 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1545 << ListChange::insert(0, 5)
1546 << ListChange::setCurrent(-1)
1547 << ListChange::remove(0, 5)
1548 << ListChange::insert(0, 5)
1553 void tst_QQuickGridView::swapWithFirstItem()
1556 QQuickView *canvas = createView();
1559 for (int i = 0; i < 30; i++)
1560 model.addItem("Item" + QString::number(i), "");
1562 QQmlContext *ctxt = canvas->rootContext();
1563 ctxt->setContextProperty("testModel", &model);
1564 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1565 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1567 canvas->setSource(testFileUrl("gridview1.qml"));
1569 qApp->processEvents();
1571 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1572 QTRY_VERIFY(gridview != 0);
1574 // ensure content position is stable
1575 gridview->setContentY(0);
1576 model.moveItem(10, 0);
1577 QTRY_VERIFY(gridview->contentY() == 0);
1582 void tst_QQuickGridView::currentIndex()
1585 for (int i = 0; i < 60; i++)
1586 model.addItem("Item" + QString::number(i), QString::number(i));
1588 QQuickView *canvas = new QQuickView(0);
1589 canvas->setGeometry(0,0,240,320);
1592 QQmlContext *ctxt = canvas->rootContext();
1593 ctxt->setContextProperty("testModel", &model);
1595 QString filename(testFile("gridview-initCurrent.qml"));
1596 canvas->setSource(QUrl::fromLocalFile(filename));
1598 qApp->processEvents();
1600 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1601 QVERIFY(gridview != 0);
1602 QTRY_VERIFY(!QQuickItemPrivate::get(gridview)->polishScheduled);
1604 QQuickItem *contentItem = gridview->contentItem();
1605 QVERIFY(contentItem != 0);
1607 // current item should be third item
1608 QCOMPARE(gridview->currentIndex(), 35);
1609 QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35));
1610 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1611 QCOMPARE(gridview->contentY(), 400.0);
1613 gridview->moveCurrentIndexRight();
1614 QCOMPARE(gridview->currentIndex(), 36);
1615 gridview->moveCurrentIndexDown();
1616 QCOMPARE(gridview->currentIndex(), 39);
1617 gridview->moveCurrentIndexUp();
1618 QCOMPARE(gridview->currentIndex(), 36);
1619 gridview->moveCurrentIndexLeft();
1620 QCOMPARE(gridview->currentIndex(), 35);
1622 // wait until motion stops
1623 QTRY_VERIFY(gridview->verticalVelocity() == 0.0);
1626 gridview->setCurrentIndex(0);
1627 QCOMPARE(gridview->currentIndex(), 0);
1628 // confirm that the velocity is updated
1629 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1631 gridview->moveCurrentIndexUp();
1632 QCOMPARE(gridview->currentIndex(), 0);
1634 gridview->moveCurrentIndexLeft();
1635 QCOMPARE(gridview->currentIndex(), 0);
1637 gridview->setCurrentIndex(model.count()-1);
1638 QCOMPARE(gridview->currentIndex(), model.count()-1);
1640 gridview->moveCurrentIndexRight();
1641 QCOMPARE(gridview->currentIndex(), model.count()-1);
1643 gridview->moveCurrentIndexDown();
1644 QCOMPARE(gridview->currentIndex(), model.count()-1);
1647 gridview->setWrapEnabled(true);
1649 gridview->setCurrentIndex(0);
1650 QCOMPARE(gridview->currentIndex(), 0);
1652 gridview->moveCurrentIndexLeft();
1653 QCOMPARE(gridview->currentIndex(), model.count()-1);
1655 qApp->processEvents();
1656 QTRY_COMPARE(gridview->contentY(), 880.0);
1658 gridview->moveCurrentIndexRight();
1659 QCOMPARE(gridview->currentIndex(), 0);
1661 QTRY_COMPARE(gridview->contentY(), 0.0);
1664 // footer should become visible if it is out of view, and then current index moves to the first row
1665 canvas->rootObject()->setProperty("showFooter", true);
1666 QTRY_VERIFY(gridview->footerItem());
1667 gridview->setCurrentIndex(model.count()-3);
1668 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1669 gridview->setCurrentIndex(model.count()-2);
1670 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1671 canvas->rootObject()->setProperty("showFooter", false);
1673 // header should become visible if it is out of view, and then current index moves to the last row
1674 canvas->rootObject()->setProperty("showHeader", true);
1675 QTRY_VERIFY(gridview->headerItem());
1676 gridview->setCurrentIndex(3);
1677 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1678 gridview->setCurrentIndex(1);
1679 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1680 canvas->rootObject()->setProperty("showHeader", false);
1684 canvas->requestActivateWindow();
1685 QTest::qWaitForWindowShown(canvas);
1686 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1688 gridview->setCurrentIndex(0);
1690 QTest::keyClick(canvas, Qt::Key_Down);
1691 QCOMPARE(gridview->currentIndex(), 3);
1693 QTest::keyClick(canvas, Qt::Key_Up);
1694 QCOMPARE(gridview->currentIndex(), 0);
1696 // hold down Key_Down
1697 for (int i=0; i<(model.count() / 3) - 1; i++) {
1698 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1699 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1701 QTest::keyRelease(canvas, Qt::Key_Down);
1702 QTRY_COMPARE(gridview->currentIndex(), 57);
1703 QTRY_COMPARE(gridview->contentY(), 880.0);
1706 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1707 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1708 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1710 QTest::keyRelease(canvas, Qt::Key_Up);
1711 QTRY_COMPARE(gridview->currentIndex(), 0);
1712 QTRY_COMPARE(gridview->contentY(), 0.0);
1715 gridview->setFlow(QQuickGridView::TopToBottom);
1717 canvas->requestActivateWindow();
1718 QTest::qWaitForWindowShown(canvas);
1719 QVERIFY(qGuiApp->focusWindow() == canvas);
1720 qApp->processEvents();
1722 QTest::keyClick(canvas, Qt::Key_Right);
1723 QCOMPARE(gridview->currentIndex(), 5);
1725 QTest::keyClick(canvas, Qt::Key_Left);
1726 QCOMPARE(gridview->currentIndex(), 0);
1728 QTest::keyClick(canvas, Qt::Key_Down);
1729 QCOMPARE(gridview->currentIndex(), 1);
1731 QTest::keyClick(canvas, Qt::Key_Up);
1732 QCOMPARE(gridview->currentIndex(), 0);
1734 // hold down Key_Right
1735 for (int i=0; i<(model.count() / 5) - 1; i++) {
1736 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1737 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1740 QTest::keyRelease(canvas, Qt::Key_Right);
1741 QTRY_COMPARE(gridview->currentIndex(), 55);
1742 QTRY_COMPARE(gridview->contentX(), 720.0);
1744 // hold down Key_Left
1745 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1746 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1747 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1749 QTest::keyRelease(canvas, Qt::Key_Left);
1750 QTRY_COMPARE(gridview->currentIndex(), 0);
1751 QTRY_COMPARE(gridview->contentX(), 0.0);
1754 // turn off auto highlight
1755 gridview->setHighlightFollowsCurrentItem(false);
1756 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1757 QVERIFY(gridview->highlightItem());
1758 qreal hlPosX = gridview->highlightItem()->x();
1759 qreal hlPosY = gridview->highlightItem()->y();
1761 gridview->setCurrentIndex(5);
1762 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1763 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1765 // insert item before currentIndex
1766 gridview->setCurrentIndex(28);
1767 model.insertItem(0, "Foo", "1111");
1768 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1770 // check removing highlight by setting currentIndex to -1;
1771 gridview->setCurrentIndex(-1);
1773 QCOMPARE(gridview->currentIndex(), -1);
1774 QVERIFY(!gridview->highlightItem());
1775 QVERIFY(!gridview->currentItem());
1777 gridview->setHighlightFollowsCurrentItem(true);
1779 gridview->setFlow(QQuickGridView::LeftToRight);
1780 gridview->setLayoutDirection(Qt::RightToLeft);
1782 canvas->requestActivateWindow();
1783 QTest::qWaitForWindowShown(canvas);
1784 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1785 qApp->processEvents();
1787 gridview->setCurrentIndex(35);
1789 QTest::keyClick(canvas, Qt::Key_Right);
1790 QCOMPARE(gridview->currentIndex(), 34);
1792 QTest::keyClick(canvas, Qt::Key_Down);
1793 QCOMPARE(gridview->currentIndex(), 37);
1795 QTest::keyClick(canvas, Qt::Key_Up);
1796 QCOMPARE(gridview->currentIndex(), 34);
1798 QTest::keyClick(canvas, Qt::Key_Left);
1799 QCOMPARE(gridview->currentIndex(), 35);
1802 // turn off auto highlight
1803 gridview->setHighlightFollowsCurrentItem(false);
1804 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1805 QVERIFY(gridview->highlightItem());
1806 hlPosX = gridview->highlightItem()->x();
1807 hlPosY = gridview->highlightItem()->y();
1809 gridview->setCurrentIndex(5);
1810 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1811 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1813 // insert item before currentIndex
1814 gridview->setCurrentIndex(28);
1815 model.insertItem(0, "Foo", "1111");
1816 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1818 // check removing highlight by setting currentIndex to -1;
1819 gridview->setCurrentIndex(-1);
1821 QCOMPARE(gridview->currentIndex(), -1);
1822 QVERIFY(!gridview->highlightItem());
1823 QVERIFY(!gridview->currentItem());
1825 // moving currentItem out of view should make it invisible
1826 gridview->setCurrentIndex(0);
1827 QTRY_VERIFY(gridview->currentItem()->isVisible());
1828 gridview->setContentY(200);
1829 QTRY_VERIFY(!gridview->currentItem()->isVisible());
1834 void tst_QQuickGridView::noCurrentIndex()
1837 for (int i = 0; i < 60; i++)
1838 model.addItem("Item" + QString::number(i), QString::number(i));
1840 QQuickView *canvas = new QQuickView(0);
1841 canvas->setGeometry(0,0,240,320);
1843 QQmlContext *ctxt = canvas->rootContext();
1844 ctxt->setContextProperty("testModel", &model);
1846 QString filename(testFile("gridview-noCurrent.qml"));
1847 canvas->setSource(QUrl::fromLocalFile(filename));
1849 qApp->processEvents();
1851 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1852 QVERIFY(gridview != 0);
1853 QQuickItem *contentItem = gridview->contentItem();
1854 QVERIFY(contentItem != 0);
1855 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1857 // current index should be -1
1858 QCOMPARE(gridview->currentIndex(), -1);
1859 QVERIFY(!gridview->currentItem());
1860 QVERIFY(!gridview->highlightItem());
1861 QCOMPARE(gridview->contentY(), 0.0);
1863 gridview->setCurrentIndex(5);
1864 QCOMPARE(gridview->currentIndex(), 5);
1865 QVERIFY(gridview->currentItem());
1866 QVERIFY(gridview->highlightItem());
1871 void tst_QQuickGridView::changeFlow()
1873 QQuickView *canvas = createView();
1876 for (int i = 0; i < 30; i++)
1877 model.addItem("Item" + QString::number(i), QString::number(i));
1879 QQmlContext *ctxt = canvas->rootContext();
1880 ctxt->setContextProperty("testModel", &model);
1881 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1882 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1884 canvas->setSource(testFileUrl("gridview1.qml"));
1885 qApp->processEvents();
1887 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1888 QTRY_VERIFY(gridview != 0);
1890 QQuickItem *contentItem = gridview->contentItem();
1891 QTRY_VERIFY(contentItem != 0);
1893 // Confirm items positioned correctly and indexes correct
1894 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1895 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1896 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1897 if (!item) qWarning() << "Item" << i << "not found";
1899 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1900 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1901 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1902 QTRY_VERIFY(name != 0);
1903 QTRY_COMPARE(name->text(), model.name(i));
1904 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1905 QTRY_VERIFY(number != 0);
1906 QTRY_COMPARE(number->text(), model.number(i));
1909 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1911 // Confirm items positioned correctly and indexes correct
1912 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1913 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1914 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1915 if (!item) qWarning() << "Item" << i << "not found";
1917 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1918 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1919 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1920 QTRY_VERIFY(name != 0);
1921 QTRY_COMPARE(name->text(), model.name(i));
1922 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1923 QTRY_VERIFY(number != 0);
1924 QTRY_COMPARE(number->text(), model.number(i));
1927 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1929 // Confirm items positioned correctly and indexes correct
1930 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1931 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1932 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1933 if (!item) qWarning() << "Item" << i << "not found";
1935 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1936 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1937 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1938 QTRY_VERIFY(name != 0);
1939 QTRY_COMPARE(name->text(), model.name(i));
1940 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1941 QTRY_VERIFY(number != 0);
1942 QTRY_COMPARE(number->text(), model.number(i));
1944 gridview->setContentX(100);
1945 QTRY_COMPARE(gridview->contentX(), 100.);
1946 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1947 QTRY_COMPARE(gridview->contentX(), 0.);
1949 // Confirm items positioned correctly and indexes correct
1950 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1951 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1952 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1953 if (!item) qWarning() << "Item" << i << "not found";
1955 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1956 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1957 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1958 QTRY_VERIFY(name != 0);
1959 QTRY_COMPARE(name->text(), model.name(i));
1960 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1961 QTRY_VERIFY(number != 0);
1962 QTRY_COMPARE(number->text(), model.number(i));
1968 void tst_QQuickGridView::defaultValues()
1971 QQmlComponent c(&engine, testFileUrl("gridview3.qml"));
1972 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
1974 QTRY_VERIFY(obj != 0);
1975 QTRY_VERIFY(obj->model() == QVariant());
1976 QTRY_VERIFY(obj->delegate() == 0);
1977 QTRY_COMPARE(obj->currentIndex(), -1);
1978 QTRY_VERIFY(obj->currentItem() == 0);
1979 QTRY_COMPARE(obj->count(), 0);
1980 QTRY_VERIFY(obj->highlight() == 0);
1981 QTRY_VERIFY(obj->highlightItem() == 0);
1982 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1983 QTRY_VERIFY(obj->flow() == 0);
1984 QTRY_COMPARE(obj->isWrapEnabled(), false);
1985 QTRY_COMPARE(obj->cacheBuffer(), 0);
1986 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
1987 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1991 void tst_QQuickGridView::properties()
1994 QQmlComponent c(&engine, testFileUrl("gridview2.qml"));
1995 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
1997 QTRY_VERIFY(obj != 0);
1998 QTRY_VERIFY(obj->model() != QVariant());
1999 QTRY_VERIFY(obj->delegate() != 0);
2000 QTRY_COMPARE(obj->currentIndex(), 0);
2001 QTRY_VERIFY(obj->currentItem() != 0);
2002 QTRY_COMPARE(obj->count(), 4);
2003 QTRY_VERIFY(obj->highlight() != 0);
2004 QTRY_VERIFY(obj->highlightItem() != 0);
2005 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
2006 QTRY_VERIFY(obj->flow() == 0);
2007 QTRY_COMPARE(obj->isWrapEnabled(), true);
2008 QTRY_COMPARE(obj->cacheBuffer(), 200);
2009 QTRY_COMPARE(obj->cellWidth(), qreal(100));
2010 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2014 void tst_QQuickGridView::propertyChanges()
2016 QQuickView *canvas = createView();
2017 QTRY_VERIFY(canvas);
2018 canvas->setSource(testFileUrl("propertychangestest.qml"));
2020 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2021 QTRY_VERIFY(gridView);
2023 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
2024 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
2025 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
2026 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
2028 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2029 QTRY_COMPARE(gridView->cacheBuffer(), 10);
2030 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
2032 gridView->setWrapEnabled(false);
2033 gridView->setCacheBuffer(3);
2034 gridView->setFlow(QQuickGridView::TopToBottom);
2036 QTRY_COMPARE(gridView->isWrapEnabled(), false);
2037 QTRY_COMPARE(gridView->cacheBuffer(), 3);
2038 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
2040 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2041 QTRY_COMPARE(cacheBufferSpy.count(),1);
2042 QTRY_COMPARE(flowSpy.count(),1);
2044 gridView->setWrapEnabled(false);
2045 gridView->setCacheBuffer(3);
2046 gridView->setFlow(QQuickGridView::TopToBottom);
2048 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2049 QTRY_COMPARE(cacheBufferSpy.count(),1);
2050 QTRY_COMPARE(flowSpy.count(),1);
2052 gridView->setFlow(QQuickGridView::LeftToRight);
2053 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
2055 gridView->setWrapEnabled(true);
2056 gridView->setCacheBuffer(5);
2057 gridView->setLayoutDirection(Qt::RightToLeft);
2059 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2060 QTRY_COMPARE(gridView->cacheBuffer(), 5);
2061 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
2063 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2064 QTRY_COMPARE(cacheBufferSpy.count(),2);
2065 QTRY_COMPARE(layoutSpy.count(),1);
2066 QTRY_COMPARE(flowSpy.count(),2);
2068 gridView->setWrapEnabled(true);
2069 gridView->setCacheBuffer(5);
2070 gridView->setLayoutDirection(Qt::RightToLeft);
2072 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2073 QTRY_COMPARE(cacheBufferSpy.count(),2);
2074 QTRY_COMPARE(layoutSpy.count(),1);
2075 QTRY_COMPARE(flowSpy.count(),2);
2077 gridView->setFlow(QQuickGridView::TopToBottom);
2078 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
2079 QTRY_COMPARE(flowSpy.count(),3);
2081 gridView->setFlow(QQuickGridView::TopToBottom);
2082 QTRY_COMPARE(flowSpy.count(),3);
2087 void tst_QQuickGridView::componentChanges()
2089 QQuickView *canvas = createView();
2090 QTRY_VERIFY(canvas);
2091 canvas->setSource(testFileUrl("propertychangestest.qml"));
2093 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2094 QTRY_VERIFY(gridView);
2096 QQmlComponent component(canvas->engine());
2097 component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
2099 QQmlComponent delegateComponent(canvas->engine());
2100 delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
2102 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
2103 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
2104 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
2105 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
2107 gridView->setHighlight(&component);
2108 gridView->setDelegate(&delegateComponent);
2109 gridView->setHeader(&component);
2110 gridView->setFooter(&component);
2112 QTRY_COMPARE(gridView->highlight(), &component);
2113 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
2114 QTRY_COMPARE(gridView->header(), &component);
2115 QTRY_COMPARE(gridView->footer(), &component);
2117 QTRY_COMPARE(highlightSpy.count(),1);
2118 QTRY_COMPARE(delegateSpy.count(),1);
2119 QTRY_COMPARE(headerSpy.count(),1);
2120 QTRY_COMPARE(footerSpy.count(),1);
2122 gridView->setHighlight(&component);
2123 gridView->setDelegate(&delegateComponent);
2124 gridView->setHeader(&component);
2125 gridView->setFooter(&component);
2127 QTRY_COMPARE(highlightSpy.count(),1);
2128 QTRY_COMPARE(delegateSpy.count(),1);
2129 QTRY_COMPARE(headerSpy.count(),1);
2130 QTRY_COMPARE(footerSpy.count(),1);
2135 void tst_QQuickGridView::modelChanges()
2137 QQuickView *canvas = createView();
2138 QTRY_VERIFY(canvas);
2139 canvas->setSource(testFileUrl("propertychangestest.qml"));
2141 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2142 QTRY_VERIFY(gridView);
2144 QQuickListModel *alternateModel = canvas->rootObject()->findChild<QQuickListModel*>("alternateModel");
2145 QTRY_VERIFY(alternateModel);
2146 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
2147 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
2149 gridView->setModel(modelVariant);
2150 QTRY_COMPARE(gridView->model(), modelVariant);
2151 QTRY_COMPARE(modelSpy.count(),1);
2153 gridView->setModel(modelVariant);
2154 QTRY_COMPARE(modelSpy.count(),1);
2156 gridView->setModel(QVariant());
2157 QTRY_COMPARE(modelSpy.count(),2);
2161 void tst_QQuickGridView::positionViewAtIndex()
2163 QQuickView *canvas = createView();
2166 for (int i = 0; i < 40; i++)
2167 model.addItem("Item" + QString::number(i), "");
2169 QQmlContext *ctxt = canvas->rootContext();
2170 ctxt->setContextProperty("testModel", &model);
2171 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2172 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2174 canvas->setSource(testFileUrl("gridview1.qml"));
2176 qApp->processEvents();
2178 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2179 QTRY_VERIFY(gridview != 0);
2180 QQuickItem *contentItem = gridview->contentItem();
2181 QTRY_VERIFY(contentItem != 0);
2182 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2184 // Confirm items positioned correctly
2185 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2186 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2187 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2188 if (!item) qWarning() << "Item" << i << "not found";
2190 QTRY_COMPARE(item->x(), (i%3)*80.);
2191 QTRY_COMPARE(item->y(), (i/3)*60.);
2194 // Position on a currently visible item
2195 gridview->positionViewAtIndex(4, QQuickGridView::Beginning);
2196 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
2197 QTRY_COMPARE(gridview->contentY(), 60.);
2199 // Confirm items positioned correctly
2200 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2201 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2202 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2203 if (!item) qWarning() << "Item" << i << "not found";
2205 QTRY_COMPARE(item->x(), (i%3)*80.);
2206 QTRY_COMPARE(item->y(), (i/3)*60.);
2209 // Position on an item beyond the visible items
2210 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2211 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
2212 QTRY_COMPARE(gridview->contentY(), 420.);
2214 // Confirm items positioned correctly
2215 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2216 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2217 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2218 if (!item) qWarning() << "Item" << i << "not found";
2220 QTRY_COMPARE(item->x(), (i%3)*80.);
2221 QTRY_COMPARE(item->y(), (i/3)*60.);
2224 // Position on an item that would leave empty space if positioned at the top
2225 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2226 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
2227 QTRY_COMPARE(gridview->contentY(), 520.);
2229 // Confirm items positioned correctly
2230 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2231 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2232 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2233 if (!item) qWarning() << "Item" << i << "not found";
2235 QTRY_COMPARE(item->x(), (i%3)*80.);
2236 QTRY_COMPARE(item->y(), (i/3)*60.);
2239 // Position at the beginning again
2240 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2241 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
2242 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
2243 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
2244 QTRY_COMPARE(gridview->contentY(), 0.);
2246 // Confirm items positioned correctly
2247 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2248 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2249 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2250 if (!item) qWarning() << "Item" << i << "not found";
2252 QTRY_COMPARE(item->x(), (i%3)*80.);
2253 QTRY_COMPARE(item->y(), (i/3)*60.);
2257 gridview->positionViewAtIndex(30, QQuickGridView::End);
2258 QTRY_COMPARE(gridview->contentY(), 340.);
2260 // Position in Center
2261 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2262 QTRY_COMPARE(gridview->contentY(), 170.);
2264 // Ensure at least partially visible
2265 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2266 QTRY_COMPARE(gridview->contentY(), 170.);
2268 gridview->setContentY(302);
2269 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2270 QTRY_COMPARE(gridview->contentY(), 302.);
2272 gridview->setContentY(360);
2273 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2274 QTRY_COMPARE(gridview->contentY(), 300.);
2276 gridview->setContentY(60);
2277 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2278 QTRY_COMPARE(gridview->contentY(), 60.);
2280 gridview->setContentY(20);
2281 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2282 QTRY_COMPARE(gridview->contentY(), 100.);
2284 // Ensure completely visible
2285 gridview->setContentY(120);
2286 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2287 QTRY_COMPARE(gridview->contentY(), 120.);
2289 gridview->setContentY(302);
2290 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2291 QTRY_COMPARE(gridview->contentY(), 300.);
2293 gridview->setContentY(60);
2294 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2295 QTRY_COMPARE(gridview->contentY(), 100.);
2297 // Test for Top To Bottom layout
2298 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2300 // Confirm items positioned correctly
2301 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2302 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2303 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2304 if (!item) qWarning() << "Item" << i << "not found";
2306 QTRY_COMPARE(item->x(), (i/5)*80.);
2307 QTRY_COMPARE(item->y(), (i%5)*60.);
2311 gridview->positionViewAtIndex(30, QQuickGridView::End);
2312 QTRY_COMPARE(gridview->contentX(), 320.);
2313 QTRY_COMPARE(gridview->contentY(), 0.);
2315 // Position in Center
2316 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2317 QTRY_COMPARE(gridview->contentX(), 160.);
2319 // Ensure at least partially visible
2320 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2321 QTRY_COMPARE(gridview->contentX(), 160.);
2323 gridview->setContentX(170);
2324 gridview->positionViewAtIndex(25, QQuickGridView::Visible);
2325 QTRY_COMPARE(gridview->contentX(), 170.);
2327 gridview->positionViewAtIndex(30, QQuickGridView::Visible);
2328 QTRY_COMPARE(gridview->contentX(), 320.);
2330 gridview->setContentX(170);
2331 gridview->positionViewAtIndex(25, QQuickGridView::Contain);
2332 QTRY_COMPARE(gridview->contentX(), 240.);
2334 // positionViewAtBeginning
2335 gridview->positionViewAtBeginning();
2336 QTRY_COMPARE(gridview->contentX(), 0.);
2338 gridview->setContentX(80);
2339 canvas->rootObject()->setProperty("showHeader", true);
2340 gridview->positionViewAtBeginning();
2341 QTRY_COMPARE(gridview->contentX(), -30.);
2343 // positionViewAtEnd
2344 gridview->positionViewAtEnd();
2345 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
2347 gridview->setContentX(80);
2348 canvas->rootObject()->setProperty("showFooter", true);
2349 gridview->positionViewAtEnd();
2350 QTRY_COMPARE(gridview->contentX(), 430.);
2352 // set current item to outside visible view, position at beginning
2353 // and ensure highlight moves to current item
2354 gridview->setCurrentIndex(6);
2355 gridview->positionViewAtBeginning();
2356 QTRY_COMPARE(gridview->contentX(), -30.);
2357 QVERIFY(gridview->highlightItem());
2358 QCOMPARE(gridview->highlightItem()->x(), 80.);
2363 void tst_QQuickGridView::snapping()
2365 QQuickView *canvas = createView();
2368 for (int i = 0; i < 40; i++)
2369 model.addItem("Item" + QString::number(i), "");
2371 QQmlContext *ctxt = canvas->rootContext();
2372 ctxt->setContextProperty("testModel", &model);
2373 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2374 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2376 canvas->setSource(testFileUrl("gridview1.qml"));
2377 qApp->processEvents();
2379 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2380 QTRY_VERIFY(gridview != 0);
2382 gridview->setHeight(220);
2383 QCOMPARE(gridview->height(), 220.);
2385 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2386 QCOMPARE(gridview->contentY(), 80.);
2388 gridview->setContentY(0);
2389 QCOMPARE(gridview->contentY(), 0.);
2391 gridview->setSnapMode(QQuickGridView::SnapToRow);
2392 QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow);
2394 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2395 QCOMPARE(gridview->contentY(), 60.);
2397 gridview->positionViewAtIndex(15, QQuickGridView::End);
2398 QCOMPARE(gridview->contentY(), 120.);
2404 void tst_QQuickGridView::mirroring()
2406 QQuickView *canvasA = createView();
2407 canvasA->setSource(testFileUrl("mirroring.qml"));
2408 QQuickGridView *gridviewA = findItem<QQuickGridView>(canvasA->rootObject(), "view");
2409 QTRY_VERIFY(gridviewA != 0);
2411 QQuickView *canvasB = createView();
2412 canvasB->setSource(testFileUrl("mirroring.qml"));
2413 QQuickGridView *gridviewB = findItem<QQuickGridView>(canvasB->rootObject(), "view");
2414 QTRY_VERIFY(gridviewA != 0);
2415 qApp->processEvents();
2417 QList<QString> objectNames;
2418 objectNames << "item1" << "item2"; // << "item3"
2420 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2421 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2422 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2425 foreach (const QString objectName, objectNames)
2426 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2428 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2429 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2432 foreach (const QString objectName, objectNames)
2433 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2435 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2436 QQuickItemPrivate::get(gridviewB)->setLayoutMirror(true);
2437 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2439 // LTR != LTR+mirror
2440 foreach (const QString objectName, objectNames)
2441 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2443 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2445 // RTL == LTR+mirror
2446 foreach (const QString objectName, objectNames)
2447 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2449 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2451 // RTL != RTL+mirror
2452 foreach (const QString objectName, objectNames)
2453 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2455 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2457 // LTR == RTL+mirror
2458 foreach (const QString objectName, objectNames)
2459 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2465 void tst_QQuickGridView::positionViewAtIndex_rightToLeft()
2467 QQuickView *canvas = createView();
2470 for (int i = 0; i < 40; i++)
2471 model.addItem("Item" + QString::number(i), "");
2473 QQmlContext *ctxt = canvas->rootContext();
2474 ctxt->setContextProperty("testModel", &model);
2475 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2476 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2478 canvas->setSource(testFileUrl("gridview1.qml"));
2479 qApp->processEvents();
2481 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2482 QTRY_VERIFY(gridview != 0);
2484 QQuickItem *contentItem = gridview->contentItem();
2485 QTRY_VERIFY(contentItem != 0);
2487 // Confirm items positioned correctly
2488 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2489 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2490 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2491 if (!item) qWarning() << "Item" << i << "not found";
2493 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2494 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2497 // Position on a currently visible item
2498 gridview->positionViewAtIndex(6, QQuickGridView::Beginning);
2499 QTRY_COMPARE(gridview->contentX(), -320.);
2501 // Confirm items positioned correctly
2502 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2503 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2504 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2505 if (!item) qWarning() << "Item" << i << "not found";
2507 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2508 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2511 // Position on an item beyond the visible items
2512 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2513 QTRY_COMPARE(gridview->contentX(), -560.);
2515 // Confirm items positioned correctly
2516 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2517 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2518 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2519 if (!item) qWarning() << "Item" << i << "not found";
2521 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2522 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2525 // Position on an item that would leave empty space if positioned at the top
2526 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2527 QTRY_COMPARE(gridview->contentX(), -640.);
2529 // Confirm items positioned correctly
2530 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2531 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2532 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2533 if (!item) qWarning() << "Item" << i << "not found";
2535 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2536 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2539 // Position at the beginning again
2540 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2541 QTRY_COMPARE(gridview->contentX(), -240.);
2543 // Confirm items positioned correctly
2544 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2545 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2546 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2547 if (!item) qWarning() << "Item" << i << "not found";
2549 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2550 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2554 gridview->positionViewAtIndex(30, QQuickGridView::End);
2555 QTRY_COMPARE(gridview->contentX(), -560.);
2557 // Position in Center
2558 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2559 QTRY_COMPARE(gridview->contentX(), -400.);
2561 // Ensure at least partially visible
2562 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2563 QTRY_COMPARE(gridview->contentX(), -400.);
2565 gridview->setContentX(-555.);
2566 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2567 QTRY_COMPARE(gridview->contentX(), -555.);
2569 gridview->setContentX(-239);
2570 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2571 QTRY_COMPARE(gridview->contentX(), -320.);
2573 gridview->setContentX(-239);
2574 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2575 QTRY_COMPARE(gridview->contentX(), -400.);
2577 gridview->setContentX(-640);
2578 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2579 QTRY_COMPARE(gridview->contentX(), -560.);
2581 // Ensure completely visible
2582 gridview->setContentX(-400);
2583 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2584 QTRY_COMPARE(gridview->contentX(), -400.);
2586 gridview->setContentX(-315);
2587 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2588 QTRY_COMPARE(gridview->contentX(), -320.);
2590 gridview->setContentX(-640);
2591 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2592 QTRY_COMPARE(gridview->contentX(), -560.);
2597 void tst_QQuickGridView::resetModel()
2599 QQuickView *canvas = createView();
2601 QStringList strings;
2602 strings << "one" << "two" << "three";
2603 QStringListModel model(strings);
2605 QQmlContext *ctxt = canvas->rootContext();
2606 ctxt->setContextProperty("testModel", &model);
2608 canvas->setSource(testFileUrl("displaygrid.qml"));
2610 qApp->processEvents();
2612 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2613 QTRY_VERIFY(gridview != 0);
2614 QQuickItem *contentItem = gridview->contentItem();
2615 QTRY_VERIFY(contentItem != 0);
2616 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2618 QTRY_COMPARE(gridview->count(), model.rowCount());
2620 for (int i = 0; i < model.rowCount(); ++i) {
2621 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2622 QTRY_VERIFY(display != 0);
2623 QTRY_COMPARE(display->text(), strings.at(i));
2627 strings << "four" << "five" << "six" << "seven";
2628 model.setStringList(strings);
2630 QTRY_COMPARE(gridview->count(), model.rowCount());
2632 for (int i = 0; i < model.rowCount(); ++i) {
2633 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2634 QTRY_VERIFY(display != 0);
2635 QTRY_COMPARE(display->text(), strings.at(i));
2641 void tst_QQuickGridView::enforceRange()
2643 QQuickView *canvas = createView();
2646 for (int i = 0; i < 30; i++)
2647 model.addItem("Item" + QString::number(i), "");
2649 QQmlContext *ctxt = canvas->rootContext();
2650 ctxt->setContextProperty("testModel", &model);
2651 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2652 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2654 canvas->setSource(testFileUrl("gridview-enforcerange.qml"));
2656 qApp->processEvents();
2657 QVERIFY(canvas->rootObject() != 0);
2659 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2660 QTRY_VERIFY(gridview != 0);
2662 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2663 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2664 QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2665 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2667 QQuickItem *contentItem = gridview->contentItem();
2668 QTRY_VERIFY(contentItem != 0);
2670 // view should be positioned at the top of the range.
2671 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2673 QTRY_COMPARE(gridview->contentY(), -100.0);
2675 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2676 QTRY_VERIFY(name != 0);
2677 QTRY_COMPARE(name->text(), model.name(0));
2678 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2679 QTRY_VERIFY(number != 0);
2680 QTRY_COMPARE(number->text(), model.number(0));
2682 // Check currentIndex is updated when contentItem moves
2683 gridview->setContentY(0);
2684 QTRY_COMPARE(gridview->currentIndex(), 2);
2686 gridview->setCurrentIndex(5);
2687 QTRY_COMPARE(gridview->contentY(), 100.);
2690 for (int i = 0; i < 5; i++)
2691 model2.addItem("Item" + QString::number(i), "");
2693 ctxt->setContextProperty("testModel", &model2);
2694 QCOMPARE(gridview->count(), 5);
2699 void tst_QQuickGridView::enforceRange_rightToLeft()
2701 QQuickView *canvas = createView();
2704 for (int i = 0; i < 30; i++)
2705 model.addItem("Item" + QString::number(i), "");
2707 QQmlContext *ctxt = canvas->rootContext();
2708 ctxt->setContextProperty("testModel", &model);
2709 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2710 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2712 canvas->setSource(testFileUrl("gridview-enforcerange.qml"));
2713 qApp->processEvents();
2714 QVERIFY(canvas->rootObject() != 0);
2716 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2717 QTRY_VERIFY(gridview != 0);
2719 QCOMPARE(gridview->preferredHighlightBegin(), 100.0);
2720 QCOMPARE(gridview->preferredHighlightEnd(), 100.0);
2721 QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2723 QQuickItem *contentItem = gridview->contentItem();
2724 QVERIFY(contentItem != 0);
2726 // view should be positioned at the top of the range.
2727 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2729 QTRY_COMPARE(gridview->contentX(), -140.);
2730 QTRY_COMPARE(gridview->contentY(), 0.0);
2732 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2733 QTRY_VERIFY(name != 0);
2734 QTRY_COMPARE(name->text(), model.name(0));
2735 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2736 QTRY_VERIFY(number != 0);
2737 QTRY_COMPARE(number->text(), model.number(0));
2739 // Check currentIndex is updated when contentItem moves
2740 gridview->setContentX(-240);
2741 QTRY_COMPARE(gridview->currentIndex(), 3);
2743 gridview->setCurrentIndex(7);
2744 QTRY_COMPARE(gridview->contentX(), -340.);
2745 QTRY_COMPARE(gridview->contentY(), 0.0);
2748 for (int i = 0; i < 5; i++)
2749 model2.addItem("Item" + QString::number(i), "");
2751 ctxt->setContextProperty("testModel", &model2);
2752 QCOMPARE(gridview->count(), 5);
2757 void tst_QQuickGridView::QTBUG_8456()
2759 QQuickView *canvas = createView();
2761 canvas->setSource(testFileUrl("setindex.qml"));
2762 qApp->processEvents();
2764 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2765 QTRY_VERIFY(gridview != 0);
2767 QTRY_COMPARE(gridview->currentIndex(), 0);
2772 void tst_QQuickGridView::manualHighlight()
2774 QQuickView *canvas = createView();
2776 QString filename(testFile("manual-highlight.qml"));
2777 canvas->setSource(QUrl::fromLocalFile(filename));
2779 qApp->processEvents();
2781 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2782 QTRY_VERIFY(gridview != 0);
2784 QQuickItem *contentItem = gridview->contentItem();
2785 QTRY_VERIFY(contentItem != 0);
2787 QTRY_COMPARE(gridview->currentIndex(), 0);
2788 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2789 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2790 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2792 gridview->setCurrentIndex(2);
2794 QTRY_COMPARE(gridview->currentIndex(), 2);
2795 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2796 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2797 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2799 gridview->positionViewAtIndex(8, QQuickGridView::Contain);
2801 QTRY_COMPARE(gridview->currentIndex(), 2);
2802 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2803 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2804 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2806 gridview->setFlow(QQuickGridView::TopToBottom);
2807 QTRY_COMPARE(gridview->flow(), QQuickGridView::TopToBottom);
2809 gridview->setCurrentIndex(0);
2810 QTRY_COMPARE(gridview->currentIndex(), 0);
2811 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2812 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2813 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2819 void tst_QQuickGridView::footer()
2821 QFETCH(QQuickGridView::Flow, flow);
2822 QFETCH(Qt::LayoutDirection, layoutDirection);
2823 QFETCH(QPointF, initialFooterPos);
2824 QFETCH(QPointF, changedFooterPos);
2825 QFETCH(QPointF, initialContentPos);
2826 QFETCH(QPointF, changedContentPos);
2827 QFETCH(QPointF, firstDelegatePos);
2828 QFETCH(QPointF, resizeContentPos);
2830 QQuickView *canvas = getView();
2834 for (int i = 0; i < 7; i++)
2835 model.addItem("Item" + QString::number(i), "");
2837 QQmlContext *ctxt = canvas->rootContext();
2838 ctxt->setContextProperty("testModel", &model);
2840 canvas->setSource(testFileUrl("footer.qml"));
2841 qApp->processEvents();
2843 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2844 QTRY_VERIFY(gridview != 0);
2845 gridview->setFlow(flow);
2846 gridview->setLayoutDirection(layoutDirection);
2848 QQuickItem *contentItem = gridview->contentItem();
2849 QTRY_VERIFY(contentItem != 0);
2851 QQuickText *footer = findItem<QQuickText>(contentItem, "footer");
2854 QVERIFY(footer == gridview->footerItem());
2856 QCOMPARE(footer->pos(), initialFooterPos);
2857 QCOMPARE(footer->width(), 100.);
2858 QCOMPARE(footer->height(), 30.);
2859 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2861 if (flow == QQuickGridView::LeftToRight)
2862 QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + footer->height());
2864 QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + footer->width());
2866 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2868 QCOMPARE(item->pos(), firstDelegatePos);
2870 if (flow == QQuickGridView::LeftToRight) {
2871 // shrink by one row
2872 model.removeItem(2);
2873 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2875 // shrink by one column
2876 model.removeItem(2);
2877 model.removeItem(3);
2878 if (layoutDirection == Qt::LeftToRight)
2879 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2881 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2887 QPointF posWhenNoItems(0, 0);
2888 if (layoutDirection == Qt::RightToLeft)
2889 posWhenNoItems.setX(flow == QQuickGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2890 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2892 // if header is present, it's at a negative pos, so the footer should not move
2893 canvas->rootObject()->setProperty("showHeader", true);
2894 QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0);
2895 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2896 canvas->rootObject()->setProperty("showHeader", false);
2899 for (int i = 0; i < 30; i++)
2900 model.addItem("Item" + QString::number(i), "");
2902 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2903 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2905 QCOMPARE(footerItemSpy.count(), 1);
2907 footer = findItem<QQuickText>(contentItem, "footer");
2909 footer = findItem<QQuickText>(contentItem, "footer2");
2912 QVERIFY(footer == gridview->footerItem());
2914 QCOMPARE(footer->pos(), changedFooterPos);
2915 QCOMPARE(footer->width(), 50.);
2916 QCOMPARE(footer->height(), 20.);
2917 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2919 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2921 QCOMPARE(item->pos(), firstDelegatePos);
2923 gridview->positionViewAtEnd();
2924 footer->setHeight(10);
2925 footer->setWidth(40);
2926 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2928 releaseView(canvas);
2931 void tst_QQuickGridView::footer_data()
2933 QTest::addColumn<QQuickGridView::Flow>("flow");
2934 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2935 QTest::addColumn<QPointF>("initialFooterPos");
2936 QTest::addColumn<QPointF>("changedFooterPos");
2937 QTest::addColumn<QPointF>("initialContentPos");
2938 QTest::addColumn<QPointF>("changedContentPos");
2939 QTest::addColumn<QPointF>("firstDelegatePos");
2940 QTest::addColumn<QPointF>("resizeContentPos");
2942 // footer1 = 100 x 30
2943 // footer2 = 50 x 20
2946 // view height = 320
2948 // footer below items, bottom left
2949 QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
2950 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
2951 << QPointF(0, 10 * 60) // 30 items = 10 rows
2955 << QPointF(0, 10 * 60 - 320 + 10);
2957 // footer below items, bottom right
2958 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
2959 << QPointF(240 - 100, 3 * 60)
2960 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
2963 << QPointF(240 - 80, 0)
2964 << QPointF(0, 10 * 60 - 320 + 10);
2966 // footer to right of items
2967 QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
2968 << QPointF(2 * 80, 0) // 2 columns, cell width 80
2969 << QPointF(6 * 80, 0) // 30 items = 6 columns
2973 << QPointF(6 * 80 - 240 + 40, 0);
2975 // footer to left of items
2976 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
2977 << QPointF(-(2 * 80) - 100, 0)
2978 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
2980 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
2982 << QPointF(-(6 * 80) - 40, 0);
2985 void tst_QQuickGridView::header()
2987 QFETCH(QQuickGridView::Flow, flow);
2988 QFETCH(Qt::LayoutDirection, layoutDirection);
2989 QFETCH(QPointF, initialHeaderPos);
2990 QFETCH(QPointF, changedHeaderPos);
2991 QFETCH(QPointF, initialContentPos);
2992 QFETCH(QPointF, changedContentPos);
2993 QFETCH(QPointF, firstDelegatePos);
2994 QFETCH(QPointF, resizeContentPos);
2997 for (int i = 0; i < 30; i++)
2998 model.addItem("Item" + QString::number(i), "");
3000 QQuickView *canvas = getView();
3001 canvas->rootContext()->setContextProperty("testModel", &model);
3002 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
3003 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
3004 canvas->setSource(testFileUrl("header.qml"));
3006 qApp->processEvents();
3008 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3009 QTRY_VERIFY(gridview != 0);
3010 gridview->setFlow(flow);
3011 gridview->setLayoutDirection(layoutDirection);
3012 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3014 QQuickItem *contentItem = gridview->contentItem();
3015 QTRY_VERIFY(contentItem != 0);
3017 QQuickText *header = findItem<QQuickText>(contentItem, "header");
3020 QVERIFY(header == gridview->headerItem());
3022 QCOMPARE(header->pos(), initialHeaderPos);
3023 QCOMPARE(header->width(), 100.);
3024 QCOMPARE(header->height(), 30.);
3025 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3027 if (flow == QQuickGridView::LeftToRight)
3028 QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + header->height());
3030 QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + header->width());
3032 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3034 QCOMPARE(item->pos(), firstDelegatePos);
3037 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3038 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
3040 for (int i = 0; i < 30; i++)
3041 model.addItem("Item" + QString::number(i), "");
3043 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
3044 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
3046 QCOMPARE(headerItemSpy.count(), 1);
3048 header = findItem<QQuickText>(contentItem, "header");
3050 header = findItem<QQuickText>(contentItem, "header2");
3053 QVERIFY(header == gridview->headerItem());
3055 QCOMPARE(header->pos(), changedHeaderPos);
3056 QCOMPARE(header->width(), 50.);
3057 QCOMPARE(header->height(), 20.);
3058 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
3060 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3062 QCOMPARE(item->pos(), firstDelegatePos);
3064 header->setHeight(10);
3065 header->setWidth(40);
3066 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
3068 releaseView(canvas);
3071 // QTBUG-21207 header should become visible if view resizes from initial empty size
3074 canvas->rootContext()->setContextProperty("testModel", &model);
3075 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
3076 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
3077 canvas->setSource(testFileUrl("header.qml"));
3079 qApp->processEvents();
3081 gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3082 QTRY_VERIFY(gridview != 0);
3083 gridview->setFlow(flow);
3084 gridview->setLayoutDirection(layoutDirection);
3085 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3087 gridview->setWidth(240);
3088 gridview->setHeight(320);
3089 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
3090 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3092 releaseView(canvas);
3095 void tst_QQuickGridView::header_data()
3097 QTest::addColumn<QQuickGridView::Flow>("flow");
3098 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3099 QTest::addColumn<QPointF>("initialHeaderPos");
3100 QTest::addColumn<QPointF>("changedHeaderPos");
3101 QTest::addColumn<QPointF>("initialContentPos");
3102 QTest::addColumn<QPointF>("changedContentPos");
3103 QTest::addColumn<QPointF>("firstDelegatePos");
3104 QTest::addColumn<QPointF>("resizeContentPos");
3106 // header1 = 100 x 30
3107 // header2 = 50 x 20
3111 // header above items, top left
3112 QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
3120 // header above items, top right
3121 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
3122 << QPointF(240 - 100, -30)
3123 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
3129 // header to left of items
3130 QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
3138 // header to right of items
3139 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
3142 << QPointF(-(240 - 100), 0)
3143 << QPointF(-(240 - 50), 0)
3145 << QPointF(-(240 - 40), 0);
3148 class GVAccessor : public QQuickGridView
3151 qreal minY() const { return minYExtent(); }
3152 qreal maxY() const { return maxYExtent(); }
3153 qreal minX() const { return minXExtent(); }
3154 qreal maxX() const { return maxXExtent(); }
3157 void tst_QQuickGridView::headerFooter()
3161 QQuickView *canvas = createView();
3164 QQmlContext *ctxt = canvas->rootContext();
3165 ctxt->setContextProperty("testModel", &model);
3167 canvas->setSource(testFileUrl("headerfooter.qml"));
3168 qApp->processEvents();
3170 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3171 QTRY_VERIFY(gridview != 0);
3173 QQuickItem *contentItem = gridview->contentItem();
3174 QTRY_VERIFY(contentItem != 0);
3176 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3178 QCOMPARE(header->y(), -header->height());
3180 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3182 QCOMPARE(footer->y(), 0.);
3184 QCOMPARE(static_cast<GVAccessor*>(gridview)->minY(), header->height());
3185 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxY(), header->height());
3191 QQuickView *canvas = createView();
3194 QQmlContext *ctxt = canvas->rootContext();
3195 ctxt->setContextProperty("testModel", &model);
3197 canvas->setSource(testFileUrl("headerfooter.qml"));
3198 canvas->rootObject()->setProperty("horizontal", true);
3199 qApp->processEvents();
3201 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3202 QTRY_VERIFY(gridview != 0);
3204 QQuickItem *contentItem = gridview->contentItem();
3205 QTRY_VERIFY(contentItem != 0);
3207 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3209 QCOMPARE(header->x(), -header->width());
3211 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3213 QCOMPARE(footer->x(), 0.);
3215 QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), header->width());
3216 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), header->width());
3222 QQuickView *canvas = createView();
3225 QQmlContext *ctxt = canvas->rootContext();
3226 ctxt->setContextProperty("testModel", &model);
3228 canvas->setSource(testFileUrl("headerfooter.qml"));
3229 canvas->rootObject()->setProperty("horizontal", true);
3230 canvas->rootObject()->setProperty("rtl", true);
3231 qApp->processEvents();
3233 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3234 QTRY_VERIFY(gridview != 0);
3236 QQuickItem *contentItem = gridview->contentItem();
3237 QTRY_VERIFY(contentItem != 0);
3239 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3241 QCOMPARE(header->x(), 0.);
3243 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3245 QCOMPARE(footer->x(), -footer->width());
3247 QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), 240. - header->width());
3248 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), 240. - header->width());
3254 QQuickView *canvas = createView();
3257 for (int i = 0; i < 6; i++)
3258 model.addItem("Item" + QString::number(i), "");
3259 QQmlContext *ctxt = canvas->rootContext();
3260 ctxt->setContextProperty("testModel", &model);
3262 canvas->setSource(testFileUrl("headerfooter.qml"));
3263 qApp->processEvents();
3265 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3266 QTRY_VERIFY(gridview != 0);
3268 QQuickItem *contentItem = gridview->contentItem();
3269 QTRY_VERIFY(contentItem != 0);
3271 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3273 QCOMPARE(header->y(), -header->height());
3275 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3277 QCOMPARE(footer->y(), 80.*2);
3281 header = findItem<QQuickItem>(contentItem, "header");
3283 QCOMPARE(header->y(), -header->height());
3285 footer = findItem<QQuickItem>(contentItem, "footer");
3287 QCOMPARE(footer->y(), 80.*2);
3293 void tst_QQuickGridView::resizeViewAndRepaint()
3295 QQuickView *canvas = createView();
3299 for (int i = 0; i < 40; i++)
3300 model.addItem("Item" + QString::number(i), "");
3302 QQmlContext *ctxt = canvas->rootContext();
3303 ctxt->setContextProperty("testModel", &model);
3304 ctxt->setContextProperty("initialWidth", 240);
3305 ctxt->setContextProperty("initialHeight", 100);
3307 canvas->setSource(testFileUrl("resizeview.qml"));
3309 qApp->processEvents();
3311 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3312 QTRY_VERIFY(gridview != 0);
3313 QQuickItem *contentItem = gridview->contentItem();
3314 QTRY_VERIFY(contentItem != 0);
3315 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3317 // item at index 10 should not be currently visible
3318 QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3320 gridview->setHeight(320);
3321 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", 10));
3323 gridview->setHeight(100);
3324 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3326 // Ensure we handle -ve sizes
3327 gridview->setHeight(-100);
3328 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 3);
3330 gridview->setCacheBuffer(120);
3331 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 9);
3333 // ensure items in cache become visible
3334 gridview->setHeight(120);
3335 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 15);
3337 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3338 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3339 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3340 if (!item) qWarning() << "Item" << i << "not found";
3342 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3343 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3344 QCOMPARE(item->isVisible(), i < 9); // inside view visible, outside not visible
3347 // ensure items outside view become invisible
3348 gridview->setHeight(60);
3349 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 12);
3351 itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
3352 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3353 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3354 if (!item) qWarning() << "Item" << i << "not found";
3356 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3357 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3358 QCOMPARE(item->isVisible(), i < 6); // inside view visible, outside not visible
3364 void tst_QQuickGridView::changeColumnCount()
3367 for (int i = 0; i < 40; i++)
3368 model.addItem("Item" + QString::number(i), "");
3370 QQuickView *canvas = createView();
3371 QQmlContext *ctxt = canvas->rootContext();
3372 ctxt->setContextProperty("testModel", &model);
3373 ctxt->setContextProperty("initialWidth", 100);
3374 ctxt->setContextProperty("initialHeight", 320);
3375 canvas->setSource(testFileUrl("resizeview.qml"));
3377 qApp->processEvents();
3379 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3380 QTRY_VERIFY(gridview != 0);
3381 QQuickItem *contentItem = gridview->contentItem();
3382 QTRY_VERIFY(contentItem != 0);
3383 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3385 // a single column of 6 items are visible
3386 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3387 QCOMPARE(itemCount, 6);
3388 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3389 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3390 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3391 QCOMPARE(item->x(), 0.0);
3392 QCOMPARE(item->y(), qreal(i*60));
3395 // now 6x3 grid is visible, plus 1 extra below for refill
3396 gridview->setWidth(240);
3397 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3398 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3399 QCOMPARE(itemCount, 6*3 + 1);
3400 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3401 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3402 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3403 QCOMPARE(item->x(), qreal((i%3)*80));
3404 QCOMPARE(item->y(), qreal((i/3)*60));
3407 // back to single column
3408 gridview->setWidth(100);
3409 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3410 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3411 QCOMPARE(itemCount, 6);
3412 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3413 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3414 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3415 QCOMPARE(item->x(), 0.0);
3416 QCOMPARE(item->y(), qreal(i*60));
3422 void tst_QQuickGridView::indexAt_itemAt_data()
3424 QTest::addColumn<qreal>("x");
3425 QTest::addColumn<qreal>("y");
3426 QTest::addColumn<int>("index");
3428 QTest::newRow("Item 0 - 0, 0") << 0. << 0. << 0;
3429 QTest::newRow("Item 0 - 79, 59") << 79. << 59. << 0;
3430 QTest::newRow("Item 1 - 80, 0") << 80. << 0. << 1;
3431 QTest::newRow("Item 3 - 0, 60") << 0. << 60. << 3;
3432 QTest::newRow("No Item - 240, 0") << 240. << 0. << -1;
3435 void tst_QQuickGridView::indexAt_itemAt()
3441 QQuickView *canvas = getView();
3444 model.addItem("Fred", "12345");
3445 model.addItem("John", "2345");
3446 model.addItem("Bob", "54321");
3447 model.addItem("Billy", "22345");
3448 model.addItem("Sam", "2945");
3449 model.addItem("Ben", "04321");
3450 model.addItem("Jim", "0780");
3452 QQmlContext *ctxt = canvas->rootContext();
3453 ctxt->setContextProperty("testModel", &model);
3454 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3455 ctxt->setContextProperty("testTopToBottom", QVariant(false));
3457 canvas->setSource(testFileUrl("gridview1.qml"));
3458 qApp->processEvents();
3460 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3461 QTRY_VERIFY(gridview != 0);
3463 QQuickItem *contentItem = gridview->contentItem();
3464 QTRY_VERIFY(contentItem != 0);
3466 QTRY_COMPARE(gridview->count(), model.count());
3468 QQuickItem *item = 0;
3470 item = findItem<QQuickItem>(contentItem, "wrapper", index);
3473 QCOMPARE(gridview->indexAt(x, y), index);
3474 QVERIFY(gridview->itemAt(x, y) == item);
3476 releaseView(canvas);
3479 void tst_QQuickGridView::onAdd()
3481 QFETCH(int, initialItemCount);
3482 QFETCH(int, itemsToAdd);
3484 const int delegateWidth = 50;
3485 const int delegateHeight = 100;
3487 QQuickView *canvas = getView();
3488 canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
3490 // these initial items should not trigger GridView.onAdd
3491 for (int i=0; i<initialItemCount; i++)
3492 model.addItem("dummy value", "dummy value");
3494 QQmlContext *ctxt = canvas->rootContext();
3495 ctxt->setContextProperty("testModel", &model);
3496 ctxt->setContextProperty("delegateWidth", delegateWidth);
3497 ctxt->setContextProperty("delegateHeight", delegateHeight);
3498 canvas->setSource(testFileUrl("attachedSignals.qml"));
3500 QObject *object = canvas->rootObject();
3501 object->setProperty("width", canvas->width());
3502 object->setProperty("height", canvas->height());
3503 qApp->processEvents();
3505 QList<QPair<QString, QString> > items;
3506 for (int i=0; i<itemsToAdd; i++)
3507 items << qMakePair(QString("value %1").arg(i), QString::number(i));
3508 model.addItems(items);
3510 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
3511 qApp->processEvents();
3513 QVariantList result = object->property("addedDelegates").toList();
3514 QTRY_COMPARE(result.count(), items.count());
3515 for (int i=0; i<items.count(); i++)
3516 QCOMPARE(result[i].toString(), items[i].first);
3518 releaseView(canvas);
3521 void tst_QQuickGridView::onAdd_data()
3523 QTest::addColumn<int>("initialItemCount");
3524 QTest::addColumn<int>("itemsToAdd");
3526 QTest::newRow("0, add 1") << 0 << 1;
3527 QTest::newRow("0, add 2") << 0 << 2;
3528 QTest::newRow("0, add 10") << 0 << 10;
3530 QTest::newRow("1, add 1") << 1 << 1;
3531 QTest::newRow("1, add 2") << 1 << 2;
3532 QTest::newRow("1, add 10") << 1 << 10;
3534 QTest::newRow("5, add 1") << 5 << 1;
3535 QTest::newRow("5, add 2") << 5 << 2;
3536 QTest::newRow("5, add 10") << 5 << 10;
3539 void tst_QQuickGridView::onRemove()
3541 QFETCH(int, initialItemCount);
3542 QFETCH(int, indexToRemove);
3543 QFETCH(int, removeCount);
3545 const int delegateWidth = 50;
3546 const int delegateHeight = 100;
3548 for (int i=0; i<initialItemCount; i++)
3549 model.addItem(QString("value %1").arg(i), "dummy value");
3551 QQuickView *canvas = getView();
3552 QQmlContext *ctxt = canvas->rootContext();
3553 ctxt->setContextProperty("testModel", &model);
3554 ctxt->setContextProperty("delegateWidth", delegateWidth);
3555 ctxt->setContextProperty("delegateHeight", delegateHeight);
3556 canvas->setSource(testFileUrl("attachedSignals.qml"));
3557 QObject *object = canvas->rootObject();
3559 model.removeItems(indexToRemove, removeCount);
3560 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
3561 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
3563 releaseView(canvas);
3566 void tst_QQuickGridView::onRemove_data()
3568 QTest::addColumn<int>("initialItemCount");
3569 QTest::addColumn<int>("indexToRemove");
3570 QTest::addColumn<int>("removeCount");
3572 QTest::newRow("remove first") << 1 << 0 << 1;
3573 QTest::newRow("two items, remove first") << 2 << 0 << 1;
3574 QTest::newRow("two items, remove last") << 2 << 1 << 1;
3575 QTest::newRow("two items, remove all") << 2 << 0 << 2;
3577 QTest::newRow("four items, remove first") << 4 << 0 << 1;
3578 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
3579 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
3580 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
3581 QTest::newRow("four items, remove last") << 4 << 3 << 1;
3582 QTest::newRow("four items, remove all") << 4 << 0 << 4;
3584 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
3585 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
3586 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
3589 void tst_QQuickGridView::columnCount()
3592 canvas.setSource(testFileUrl("gridview4.qml"));
3594 canvas.requestActivateWindow();
3595 QTest::qWaitForWindowShown(&canvas);
3597 QQuickGridView *view = qobject_cast<QQuickGridView*>(canvas.rootObject());
3599 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3600 QCOMPARE(view->cellHeight(), qreal(100));
3602 QList<QQuickItem*> items = findItems<QQuickItem>(view, "delegate");
3603 QCOMPARE(items.size(), 18);
3604 QCOMPARE(items.at(8)->y(), qreal(0));
3605 QCOMPARE(items.at(9)->y(), qreal(100));
3608 void tst_QQuickGridView::margins()
3611 QQuickView *canvas = createView();
3614 for (int i = 0; i < 40; i++)
3615 model.addItem("Item" + QString::number(i), "");
3617 QQmlContext *ctxt = canvas->rootContext();
3618 ctxt->setContextProperty("testModel", &model);
3619 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3621 canvas->setSource(testFileUrl("margins.qml"));
3623 qApp->processEvents();
3625 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3626 QTRY_VERIFY(gridview != 0);
3627 QQuickItem *contentItem = gridview->contentItem();
3628 QTRY_VERIFY(contentItem != 0);
3629 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3631 QCOMPARE(gridview->contentX(), -30.);
3632 QCOMPARE(gridview->xOrigin(), 0.);
3635 gridview->positionViewAtEnd();
3636 qreal pos = gridview->contentX();
3637 gridview->setContentX(pos + 80);
3638 gridview->returnToBounds();
3639 QTRY_COMPARE(gridview->contentX(), pos + 50);
3641 // remove item before visible and check that left margin is maintained
3642 // and xOrigin is updated
3643 gridview->setContentX(200);
3644 model.removeItems(0, 4);
3646 gridview->setContentX(-50);
3647 gridview->returnToBounds();
3648 QCOMPARE(gridview->xOrigin(), 100.);
3649 QTRY_COMPARE(gridview->contentX(), 70.);
3651 // reduce left margin
3652 gridview->setLeftMargin(20);
3653 QCOMPARE(gridview->xOrigin(), 100.);
3654 QTRY_COMPARE(gridview->contentX(), 80.);
3657 gridview->positionViewAtEnd();
3658 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3659 pos = gridview->contentX();
3660 gridview->setContentX(pos + 80);
3661 gridview->returnToBounds();
3662 QTRY_COMPARE(gridview->contentX(), pos + 50);
3664 // reduce right margin
3665 pos = gridview->contentX();
3666 gridview->setRightMargin(40);
3667 QCOMPARE(gridview->xOrigin(), 0.);
3668 QTRY_COMPARE(gridview->contentX(), pos-10);
3674 QQuickView *canvas = createView();
3678 for (int i = 0; i < 40; i++)
3679 model.addItem("Item" + QString::number(i), "");
3681 QQmlContext *ctxt = canvas->rootContext();
3682 ctxt->setContextProperty("testModel", &model);
3683 ctxt->setContextProperty("testRightToLeft", QVariant(true));
3685 canvas->setSource(testFileUrl("margins.qml"));
3686 qApp->processEvents();
3688 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3689 QTRY_VERIFY(gridview != 0);
3691 QQuickItem *contentItem = gridview->contentItem();
3692 QTRY_VERIFY(contentItem != 0);
3694 QTRY_COMPARE(gridview->contentX(), -240+50.);
3695 QTRY_COMPARE(gridview->xOrigin(), 0.);
3698 gridview->positionViewAtEnd();
3699 qreal pos = gridview->contentX();
3700 gridview->setContentX(pos - 80);
3701 gridview->returnToBounds();
3702 QTRY_COMPARE(gridview->contentX(), pos - 30);
3704 // remove item before visible and check that left margin is maintained
3705 // and xOrigin is updated
3706 gridview->setContentX(-400);
3707 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3708 model.removeItems(0, 4);
3709 QTRY_COMPARE(model.count(), gridview->count());
3710 gridview->setContentX(-240+50);
3711 gridview->returnToBounds();
3712 QCOMPARE(gridview->xOrigin(), -100.);
3713 QTRY_COMPARE(gridview->contentX(), -240-50.);
3715 // reduce right margin
3716 pos = gridview->contentX();
3717 gridview->setRightMargin(40);
3718 QCOMPARE(gridview->xOrigin(), -100.);
3719 QTRY_COMPARE(gridview->contentX(), -240-100 + 40.);
3722 gridview->positionViewAtEnd();
3723 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3724 pos = gridview->contentX();
3725 gridview->setContentX(pos - 80);
3726 gridview->returnToBounds();
3727 QTRY_COMPARE(gridview->contentX(), pos - 30);
3729 // reduce left margin
3730 pos = gridview->contentX();
3731 gridview->setLeftMargin(20);
3732 QCOMPARE(gridview->xOrigin(), 0.);
3733 QTRY_COMPARE(gridview->contentX(), pos+10);
3739 void tst_QQuickGridView::creationContext()
3742 canvas.setGeometry(0,0,240,320);
3743 canvas.setSource(testFileUrl("creationContext.qml"));
3744 qApp->processEvents();
3746 QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
3748 QVERIFY(rootItem->property("count").toInt() > 0);
3751 QVERIFY(item = rootItem->findChild<QQuickItem *>("listItem"));
3752 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3753 QVERIFY(item = rootItem->findChild<QQuickItem *>("header"));
3754 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3755 QVERIFY(item = rootItem->findChild<QQuickItem *>("footer"));
3756 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3759 void tst_QQuickGridView::snapToRow_data()
3761 QTest::addColumn<QQuickGridView::Flow>("flow");
3762 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3763 QTest::addColumn<int>("highlightRangeMode");
3764 QTest::addColumn<QPoint>("flickStart");
3765 QTest::addColumn<QPoint>("flickEnd");
3766 QTest::addColumn<qreal>("snapAlignment");
3767 QTest::addColumn<qreal>("endExtent");
3768 QTest::addColumn<qreal>("startExtent");
3770 QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3771 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 800.0 << 0.0;
3773 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3774 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 800.0 << 0.0;
3776 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3777 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 << -240.0;
3779 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3780 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 940.0 << -20.0;
3782 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3783 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 940.0 << -20.0;
3785 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3786 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 - 140.0 << -220.0;
3789 void tst_QQuickGridView::snapToRow()
3791 QFETCH(QQuickGridView::Flow, flow);
3792 QFETCH(Qt::LayoutDirection, layoutDirection);
3793 QFETCH(int, highlightRangeMode);
3794 QFETCH(QPoint, flickStart);
3795 QFETCH(QPoint, flickEnd);
3796 QFETCH(qreal, snapAlignment);
3797 QFETCH(qreal, endExtent);
3798 QFETCH(qreal, startExtent);
3800 QQuickView *canvas = getView();
3802 canvas->setSource(testFileUrl("snapToRow.qml"));
3804 qApp->processEvents();
3806 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3807 QTRY_VERIFY(gridview != 0);
3809 gridview->setFlow(flow);
3810 gridview->setLayoutDirection(layoutDirection);
3811 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3812 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3814 QQuickItem *contentItem = gridview->contentItem();
3815 QTRY_VERIFY(contentItem != 0);
3817 // confirm that a flick hits an item boundary
3818 flick(canvas, flickStart, flickEnd, 180);
3819 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3820 if (flow == QQuickGridView::LeftToRight)
3821 QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
3823 QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
3827 flick(canvas, flickStart, flickEnd, 180);
3828 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3829 } while (flow == QQuickGridView::LeftToRight
3830 ? !gridview->isAtYEnd()
3831 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3833 if (flow == QQuickGridView::LeftToRight)
3834 QCOMPARE(gridview->contentY(), endExtent);
3836 QCOMPARE(gridview->contentX(), endExtent);
3840 flick(canvas, flickEnd, flickStart, 180);
3841 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3842 } while (flow == QQuickGridView::LeftToRight
3843 ? !gridview->isAtYBeginning()
3844 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3846 if (flow == QQuickGridView::LeftToRight)
3847 QCOMPARE(gridview->contentY(), startExtent);
3849 QCOMPARE(gridview->contentX(), startExtent);
3851 releaseView(canvas);
3854 void tst_QQuickGridView::snapOneRow_data()
3856 QTest::addColumn<QQuickGridView::Flow>("flow");
3857 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3858 QTest::addColumn<int>("highlightRangeMode");
3859 QTest::addColumn<QPoint>("flickStart");
3860 QTest::addColumn<QPoint>("flickEnd");
3861 QTest::addColumn<qreal>("snapAlignment");
3862 QTest::addColumn<qreal>("endExtent");
3863 QTest::addColumn<qreal>("startExtent");
3865 QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3866 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 240.0 << 0.0;
3868 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3869 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0;
3871 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3872 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 << -240.0;
3874 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3875 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 340.0 << -20.0;
3877 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3878 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0;
3880 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3881 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0;
3884 void tst_QQuickGridView::snapOneRow()
3886 QFETCH(QQuickGridView::Flow, flow);
3887 QFETCH(Qt::LayoutDirection, layoutDirection);
3888 QFETCH(int, highlightRangeMode);
3889 QFETCH(QPoint, flickStart);
3890 QFETCH(QPoint, flickEnd);
3891 QFETCH(qreal, snapAlignment);
3892 QFETCH(qreal, endExtent);
3893 QFETCH(qreal, startExtent);
3895 QQuickView *canvas = getView();
3897 canvas->setSource(testFileUrl("snapOneRow.qml"));
3899 qApp->processEvents();
3901 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3902 QTRY_VERIFY(gridview != 0);
3904 gridview->setFlow(flow);
3905 gridview->setLayoutDirection(layoutDirection);
3906 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3907 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3909 QQuickItem *contentItem = gridview->contentItem();
3910 QTRY_VERIFY(contentItem != 0);
3912 QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged()));
3914 // confirm that a flick hits next row boundary
3915 flick(canvas, flickStart, flickEnd, 180);
3916 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3917 if (flow == QQuickGridView::LeftToRight)
3918 QCOMPARE(gridview->contentY(), snapAlignment);
3920 QCOMPARE(gridview->contentX(), snapAlignment);
3922 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3923 QCOMPARE(gridview->currentIndex(), 2);
3924 QCOMPARE(currentIndexSpy.count(), 1);
3929 flick(canvas, flickStart, flickEnd, 180);
3930 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3931 } while (flow == QQuickGridView::LeftToRight
3932 ? !gridview->isAtYEnd()
3933 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3935 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3936 QCOMPARE(gridview->currentIndex(), 6);
3937 QCOMPARE(currentIndexSpy.count(), 3);
3940 if (flow == QQuickGridView::LeftToRight)
3941 QCOMPARE(gridview->contentY(), endExtent);
3943 QCOMPARE(gridview->contentX(), endExtent);
3947 flick(canvas, flickEnd, flickStart, 180);
3948 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3949 } while (flow == QQuickGridView::LeftToRight
3950 ? !gridview->isAtYBeginning()
3951 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3953 if (flow == QQuickGridView::LeftToRight)
3954 QCOMPARE(gridview->contentY(), startExtent);
3956 QCOMPARE(gridview->contentX(), startExtent);
3958 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3959 QCOMPARE(gridview->currentIndex(), 0);
3960 QCOMPARE(currentIndexSpy.count(), 6);
3963 releaseView(canvas);
3967 void tst_QQuickGridView::unaligned()
3969 QQuickView *canvas = createView();
3973 for (int i = 0; i < 10; i++)
3974 model.addItem("Item" + QString::number(i), "");
3976 QQmlContext *ctxt = canvas->rootContext();
3977 ctxt->setContextProperty("testModel", &model);
3979 canvas->setSource(testFileUrl("unaligned.qml"));
3980 qApp->processEvents();
3982 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3983 QVERIFY(gridview != 0);
3985 QQuickItem *contentItem = gridview->contentItem();
3986 QVERIFY(contentItem != 0);
3988 for (int i = 0; i < 10; ++i) {
3989 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3990 if (!item) qWarning() << "Item" << i << "not found";
3992 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
3993 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
3997 for (int i = 10; i < 18; ++i) {
3998 model.addItem("Item" + QString::number(i), "");
3999 QQuickItem *item = 0;
4000 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4001 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4002 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4006 for (int i = 0; i < 10; ++i) {
4007 model.insertItem(i, "Item" + QString::number(i), "");
4008 QQuickItem *item = 0;
4009 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4010 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4011 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4015 model.removeItems(7, 10);
4016 QTRY_COMPARE(model.count(), gridview->count());
4017 for (int i = 0; i < 18; ++i) {
4018 QQuickItem *item = 0;
4019 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4020 QCOMPARE(item->x(), qreal(i%9)*gridview->cellWidth());
4021 QCOMPARE(item->y(), qreal(i/9)*gridview->cellHeight());
4027 void tst_QQuickGridView::populateTransitions()
4029 QFETCH(bool, staticallyPopulate);
4030 QFETCH(bool, dynamicallyPopulate);
4031 QFETCH(bool, usePopulateTransition);
4033 QPointF transitionFrom(-50, -50);
4034 QPointF transitionVia(100, 100);
4035 QaimModel model_transitionFrom;
4036 QaimModel model_transitionVia;
4039 if (staticallyPopulate) {
4040 for (int i = 0; i < 30; i++)
4041 model.addItem("item" + QString::number(i), "");
4044 QQuickView *canvas = getView();
4045 canvas->rootContext()->setContextProperty("testModel", &model);
4046 canvas->rootContext()->setContextProperty("usePopulateTransition", usePopulateTransition);
4047 canvas->rootContext()->setContextProperty("dynamicallyPopulate", dynamicallyPopulate);
4048 canvas->rootContext()->setContextProperty("transitionFrom", transitionFrom);
4049 canvas->rootContext()->setContextProperty("transitionVia", transitionVia);
4050 canvas->rootContext()->setContextProperty("model_transitionFrom", &model_transitionFrom);
4051 canvas->rootContext()->setContextProperty("model_transitionVia", &model_transitionVia);
4052 canvas->setSource(testFileUrl("populateTransitions.qml"));
4055 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4057 QQuickItem *contentItem = gridview->contentItem();
4058 QVERIFY(contentItem);
4060 if (staticallyPopulate || dynamicallyPopulate) {
4061 // check the populate transition is run
4062 if (usePopulateTransition) {
4063 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 19);
4065 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4066 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
4068 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4070 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4073 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4074 if (usePopulateTransition)
4075 QCOMPARE(itemCount, gridview->property("countPopulateTransitions").toInt());
4076 for (int i=0; i < model.count() && i < itemCount; ++i) {
4077 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4078 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4079 QCOMPARE(item->x(), (i%3)*80.0);
4080 QCOMPARE(item->y(), (i/3)*60.0);
4081 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4083 QTRY_COMPARE(name->text(), model.name(i));
4086 // add an item and check this is done with add transition, not populate
4087 model.insertItem(0, "another item", "");
4088 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 1);
4089 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(),
4090 (usePopulateTransition && (staticallyPopulate || dynamicallyPopulate)) ? 19 : 0);
4093 canvas->rootContext()->setContextProperty("testModel", QVariant());
4094 QTRY_COMPARE(gridview->count(), 0);
4095 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
4096 gridview->setProperty("countPopulateTransitions", 0);
4097 gridview->setProperty("countAddTransitions", 0);
4099 // set to a valid model and check populate transition is run a second time
4101 for (int i = 0; i < 30; i++)
4102 model.addItem("item" + QString::number(i), "");
4103 canvas->rootContext()->setContextProperty("testModel", &model);
4104 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4106 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 19 : 0);
4107 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4109 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4110 if (usePopulateTransition)
4111 QCOMPARE(itemCount, gridview->property("countPopulateTransitions").toInt());
4112 for (int i=0; i < model.count() && i < itemCount; ++i) {
4113 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4114 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4115 QCOMPARE(item->x(), (i%3)*80.0);
4116 QCOMPARE(item->y(), (i/3)*60.0);
4117 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4119 QTRY_COMPARE(name->text(), model.name(i));
4122 // reset model and check populate transition is run again
4123 gridview->setProperty("countPopulateTransitions", 0);
4124 gridview->setProperty("countAddTransitions", 0);
4126 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 19 : 0);
4127 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4129 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4130 if (usePopulateTransition)
4131 QCOMPARE(itemCount, gridview->property("countPopulateTransitions").toInt());
4132 for (int i=0; i < model.count() && i < itemCount; ++i) {
4133 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4134 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4135 QCOMPARE(item->x(), (i%3)*80.0);
4136 QCOMPARE(item->y(), (i/3)*60.0);
4137 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4139 QTRY_COMPARE(name->text(), model.name(i));
4142 releaseView(canvas);
4145 void tst_QQuickGridView::populateTransitions_data()
4147 QTest::addColumn<bool>("staticallyPopulate");
4148 QTest::addColumn<bool>("dynamicallyPopulate");
4149 QTest::addColumn<bool>("usePopulateTransition");
4151 QTest::newRow("static") << true << false << true;
4152 QTest::newRow("static, no populate") << true << false << false;
4154 QTest::newRow("dynamic") << false << true << true;
4155 QTest::newRow("dynamic, no populate") << false << true << false;
4157 QTest::newRow("empty to start with") << false << false << true;
4158 QTest::newRow("empty to start with, no populate") << false << false << false;
4161 void tst_QQuickGridView::addTransitions()
4163 QFETCH(int, initialItemCount);
4164 QFETCH(bool, shouldAnimateTargets);
4165 QFETCH(qreal, contentY);
4166 QFETCH(int, insertionIndex);
4167 QFETCH(int, insertionCount);
4168 QFETCH(ListRange, expectedDisplacedIndexes);
4170 // added items should start here
4171 QPointF targetItems_transitionFrom(-50, -50);
4173 // displaced items should pass through this point
4174 QPointF displacedItems_transitionVia(100, 100);
4177 for (int i = 0; i < initialItemCount; i++)
4178 model.addItem("Original item" + QString::number(i), "");
4179 QaimModel model_targetItems_transitionFrom;
4180 QaimModel model_displacedItems_transitionVia;
4182 QQuickView *canvas = getView();
4183 QQmlContext *ctxt = canvas->rootContext();
4184 ctxt->setContextProperty("testModel", &model);
4185 ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
4186 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4187 ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
4188 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4189 canvas->setSource(testFileUrl("addTransitions.qml"));
4192 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4193 QTRY_VERIFY(gridview != 0);
4194 QQuickItem *contentItem = gridview->contentItem();
4195 QVERIFY(contentItem != 0);
4196 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4198 if (contentY != 0) {
4199 gridview->setContentY(contentY);
4200 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4203 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4205 // only target items that will become visible should be animated
4206 QList<QPair<QString, QString> > newData;
4207 QList<QPair<QString, QString> > expectedTargetData;
4208 QList<int> targetIndexes;
4209 if (shouldAnimateTargets) {
4210 for (int i=insertionIndex; i<insertionIndex+insertionCount; i++) {
4211 newData << qMakePair(QString("New item %1").arg(i), QString(""));
4213 // last visible item is the first item of the row beneath the view
4214 if (i >= (contentY / 60)*3 && i < qCeil((contentY + gridview->height()) / 60.0)*3) {
4215 expectedTargetData << newData.last();
4219 QVERIFY(expectedTargetData.count() > 0);
4223 if (!newData.isEmpty()) {
4224 model.insertItems(insertionIndex, newData);
4225 QTRY_COMPARE(model.count(), gridview->count());
4228 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4230 if (shouldAnimateTargets) {
4231 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4232 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4233 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4235 // check the target and displaced items were animated
4236 model_targetItems_transitionFrom.matchAgainst(expectedTargetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
4237 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4239 // check attached properties
4240 matchItemsAndIndexes(gridview->property("targetTrans_items").toMap(), model, targetIndexes);
4241 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4242 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4243 if (expectedDisplacedIndexes.isValid()) {
4244 // adjust expectedDisplacedIndexes to their final values after the move
4245 QList<int> displacedIndexes = adjustIndexesForAddDisplaced(expectedDisplacedIndexes.indexes, insertionIndex, insertionCount);
4246 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4247 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4248 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4251 QTRY_COMPARE(model_targetItems_transitionFrom.count(), 0);
4252 QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0);
4255 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4256 int firstVisibleIndex = -1;
4257 for (int i=0; i<items.count(); i++) {
4258 if (items[i]->y() >= contentY) {
4259 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4260 firstVisibleIndex = e.evaluate().toInt();
4264 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4266 // verify all items moved to the correct final positions
4267 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4268 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
4269 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4270 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4271 QCOMPARE(item->x(), (i%3)*80.0);
4272 QCOMPARE(item->y(), (i/3)*60.0);
4273 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4275 QCOMPARE(name->text(), model.name(i));
4278 releaseView(canvas);
4281 void tst_QQuickGridView::addTransitions_data()
4283 QTest::addColumn<int>("initialItemCount");
4284 QTest::addColumn<qreal>("contentY");
4285 QTest::addColumn<bool>("shouldAnimateTargets");
4286 QTest::addColumn<int>("insertionIndex");
4287 QTest::addColumn<int>("insertionCount");
4288 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4290 // if inserting a full row before visible index, items don't appear or animate in, even if there are > 1 new items
4291 QTest::newRow("insert 1, just before start")
4292 << 30 << 20.0 << false
4293 << 0 << 1 << ListRange();
4294 QTest::newRow("insert 1, way before start")
4295 << 30 << 20.0 << false
4296 << 0 << 1 << ListRange();
4297 QTest::newRow("insert multiple, just before start")
4298 << 30 << 100.0 << false
4299 << 0 << 3 << ListRange();
4300 QTest::newRow("insert multiple (< 1 row), just before start")
4301 << 30 << 100.0 << false
4302 << 0 << 2 << ListRange();
4303 QTest::newRow("insert multiple, way before start")
4304 << 30 << 100.0 << false
4305 << 0 << 3 << ListRange();
4307 QTest::newRow("insert 1 at start")
4308 << 30 << 0.0 << true
4309 << 0 << 1 << ListRange(0, 17);
4310 QTest::newRow("insert multiple at start")
4311 << 30 << 0.0 << true
4312 << 0 << 3 << ListRange(0, 17);
4313 QTest::newRow("insert multiple (> 1 row) at start")
4314 << 30 << 0.0 << true
4315 << 0 << 5 << ListRange(0, 17);
4316 QTest::newRow("insert 1 at start, content y not 0")
4317 << 30 << 60.0 << true // first visible is index 3
4318 << 3 << 1 << ListRange(0 + 3, 17 + 3);
4319 QTest::newRow("insert multiple at start, content y not 0")
4320 << 30 << 60.0 << true // first visible is index 3
4321 << 3 << 3 << ListRange(0 + 3, 17 + 3);
4322 QTest::newRow("insert multiple (> 1 row) at start, content y not 0")
4323 << 30 << 60.0 << true // first visible is index 3
4324 << 3 << 5 << ListRange(0 + 3, 17 + 3);
4326 QTest::newRow("insert 1 at start, to empty grid")
4328 << 0 << 1 << ListRange();
4329 QTest::newRow("insert multiple at start, to empty grid")
4331 << 0 << 3 << ListRange();
4333 QTest::newRow("insert 1 at middle")
4334 << 30 << 0.0 << true
4335 << 7 << 1 << ListRange(7, 17);
4336 QTest::newRow("insert multiple at middle")
4337 << 30 << 0.0 << true
4338 << 7 << 3 << ListRange(7, 17);
4339 QTest::newRow("insert multiple (> 1 row) at middle")
4340 << 30 << 0.0 << true
4341 << 7 << 5 << ListRange(7, 17);
4343 QTest::newRow("insert 1 at bottom")
4344 << 30 << 0.0 << true
4345 << 17 << 1 << ListRange(17, 17);
4346 QTest::newRow("insert multiple at bottom")
4347 << 30 << 0.0 << true
4348 << 17 << 3 << ListRange(17, 17);
4349 QTest::newRow("insert 1 at bottom, content y not 0")
4350 << 30 << 20.0 * 3 << true
4351 << 17 + 3 << 1 << ListRange(17 + 3, 17 + 3);
4352 QTest::newRow("insert multiple at bottom, content y not 0")
4353 << 30 << 20.0 * 3 << true
4354 << 17 + 3 << 3 << ListRange(17 + 3, 17 + 3);
4357 // items added after the last visible will not be animated in, since they
4358 // do not appear in the final view
4359 QTest::newRow("insert 1 after end")
4360 << 30 << 0.0 << false
4361 << 18 << 1 << ListRange();
4362 QTest::newRow("insert multiple after end")
4363 << 30 << 0.0 << false
4364 << 18 << 3 << ListRange();
4367 void tst_QQuickGridView::moveTransitions()
4369 QFETCH(int, initialItemCount);
4370 QFETCH(qreal, contentY);
4371 QFETCH(qreal, itemsOffsetAfterMove);
4372 QFETCH(int, moveFrom);
4373 QFETCH(int, moveTo);
4374 QFETCH(int, moveCount);
4375 QFETCH(ListRange, expectedDisplacedIndexes);
4377 // target and displaced items should pass through these points
4378 QPointF targetItems_transitionVia(-50, 50);
4379 QPointF displacedItems_transitionVia(100, 100);
4382 for (int i = 0; i < initialItemCount; i++)
4383 model.addItem("Original item" + QString::number(i), "");
4384 QaimModel model_targetItems_transitionVia;
4385 QaimModel model_displacedItems_transitionVia;
4387 QQuickView *canvas = getView();
4388 QQmlContext *ctxt = canvas->rootContext();
4389 ctxt->setContextProperty("testModel", &model);
4390 ctxt->setContextProperty("model_targetItems_transitionVia", &model_targetItems_transitionVia);
4391 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4392 ctxt->setContextProperty("targetItems_transitionVia", targetItems_transitionVia);
4393 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4394 canvas->setSource(testFileUrl("moveTransitions.qml"));
4397 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4398 QTRY_VERIFY(gridview != 0);
4399 QQuickItem *contentItem = gridview->contentItem();
4400 QVERIFY(contentItem != 0);
4403 if (contentY != 0) {
4404 gridview->setContentY(contentY);
4405 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4408 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4410 // Items moving to *or* from visible positions should be animated.
4411 // Otherwise, they should not be animated.
4412 QList<QPair<QString, QString> > expectedTargetData;
4413 QList<int> targetIndexes;
4414 for (int i=moveFrom; i<moveFrom+moveCount; i++) {
4415 int toIndex = moveTo + (i - moveFrom);
4416 int firstVisibleIndex = (contentY / 60) * 3;
4417 int lastVisibleIndex = (qCeil((contentY + gridview->height()) / 60.0)*3) - 1;
4418 if ((i >= firstVisibleIndex && i <= lastVisibleIndex)
4419 || (toIndex >= firstVisibleIndex && toIndex <= lastVisibleIndex)) {
4420 expectedTargetData << qMakePair(model.name(i), model.number(i));
4424 // ViewTransition.index provides the indices that items are moving to, not from
4425 targetIndexes = adjustIndexesForMove(targetIndexes, moveFrom, moveTo, moveCount);
4428 model.moveItems(moveFrom, moveTo, moveCount);
4430 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4431 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4432 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4434 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4436 // check the target and displaced items were animated
4437 model_targetItems_transitionVia.matchAgainst(expectedTargetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
4438 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4440 // check attached properties
4441 matchItemsAndIndexes(gridview->property("targetTrans_items").toMap(), model, targetIndexes);
4442 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4443 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4444 if (expectedDisplacedIndexes.isValid()) {
4445 // adjust expectedDisplacedIndexes to their final values after the move
4446 QList<int> displacedIndexes = adjustIndexesForMove(expectedDisplacedIndexes.indexes, moveFrom, moveTo, moveCount);
4447 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4448 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4449 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4452 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4453 int firstVisibleIndex = -1;
4454 for (int i=0; i<items.count(); i++) {
4455 if (items[i]->y() >= contentY) {
4456 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4457 firstVisibleIndex = e.evaluate().toInt();
4461 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4463 // verify all items moved to the correct final positions
4464 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4465 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
4466 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4467 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4468 QCOMPARE(item->x(), (i%3)*80.0);
4469 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
4470 name = findItem<QQuickText>(contentItem, "textName", i);
4472 QTRY_COMPARE(name->text(), model.name(i));
4475 releaseView(canvas);
4478 void tst_QQuickGridView::moveTransitions_data()
4480 QTest::addColumn<int>("initialItemCount");
4481 QTest::addColumn<qreal>("contentY");
4482 QTest::addColumn<qreal>("itemsOffsetAfterMove");
4483 QTest::addColumn<int>("moveFrom");
4484 QTest::addColumn<int>("moveTo");
4485 QTest::addColumn<int>("moveCount");
4486 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4488 QTest::newRow("move from above view, outside visible items, move 1") << 30 << 120.0 << 0.0
4489 << 1 << 10 << 1 << ListRange(6, 10);
4490 QTest::newRow("move from above view, outside visible items, move 1 (first item)") << 30 << 120.0 << 0.0
4491 << 0 << 10 << 1 << ListRange(6, 10);
4492 QTest::newRow("move from above view, outside visible items, move multiple") << 30 << 120.0 << 60.0
4493 << 1 << 10 << 3 << ListRange(13, 23);
4494 QTest::newRow("move from above view, mix of visible/non-visible") << 30 << 120.0 << 60.0
4495 << 1 << 10 << 6 << (ListRange(7, 15) + ListRange(16, 23));
4496 QTest::newRow("move from above view, mix of visible/non-visible (move first)") << 30 << 120.0 << 120.0
4497 << 0 << 10 << 6 << ListRange(16, 23);
4499 QTest::newRow("move within view, move 1 down") << 30 << 0.0 << 0.0
4500 << 1 << 10 << 1 << ListRange(2, 10);
4501 QTest::newRow("move within view, move 1 down, move first item") << 30 << 0.0 << 0.0
4502 << 0 << 10 << 1 << ListRange(1, 10);
4503 QTest::newRow("move within view, move 1 down, move first item, contentY not 0") << 30 << 120.0 << 0.0
4504 << 0+6 << 10+6 << 1 << ListRange(1+6, 10+6);
4505 QTest::newRow("move within view, move 1 down, to last item") << 30 << 0.0 << 0.0
4506 << 10 << 17 << 1 << ListRange(11, 17);
4507 QTest::newRow("move within view, move first->last") << 30 << 0.0 << 0.0
4508 << 0 << 17 << 1 << ListRange(1, 17);
4510 QTest::newRow("move within view, move multiple down") << 30 << 0.0 << 0.0
4511 << 1 << 10 << 3 << ListRange(4, 12);
4512 QTest::newRow("move within view, move multiple down, move first item") << 30 << 0.0 << 0.0
4513 << 0 << 10 << 3 << ListRange(3, 12);
4514 QTest::newRow("move within view, move multiple down, move first item, contentY not 0") << 30 << 60.0 << 0.0
4515 << 0+3 << 10+3 << 3 << ListRange(3+3, 12+3);
4516 QTest::newRow("move within view, move multiple down, displace last item") << 30 << 0.0 << 0.0
4517 << 5 << 15 << 3 << ListRange(8, 17);
4518 QTest::newRow("move within view, move multiple down, move first->last") << 30 << 0.0 << 0.0
4519 << 0 << 15 << 3 << ListRange(3, 17);
4521 QTest::newRow("move within view, move 1 up") << 30 << 0.0 << 0.0
4522 << 10 << 1 << 1 << ListRange(1, 9);
4523 QTest::newRow("move within view, move 1 up, move to first index") << 30 << 0.0 << 0.0
4524 << 10 << 0 << 1 << ListRange(0, 9);
4525 QTest::newRow("move within view, move 1 up, move to first index, contentY not 0") << 30 << 120.0 << 0.0
4526 << 10+6 << 0+6 << 1 << ListRange(0+6, 9+6);
4527 QTest::newRow("move within view, move 1 up, move to first index, contentY not on item border") << 30 << 80.0 << 0.0
4528 << 10+3 << 0+3 << 1 << ListRange(0+3, 9+3);
4529 QTest::newRow("move within view, move 1 up, move last item") << 30 << 0.0 << 0.0
4530 << 17 << 10 << 1 << ListRange(10, 16);
4531 QTest::newRow("move within view, move 1 up, move last->first") << 30 << 0.0 << 0.0
4532 << 17 << 0 << 1 << ListRange(0, 16);
4534 QTest::newRow("move within view, move multiple up") << 30 << 0.0 << 0.0
4535 << 10 << 1 << 3 << ListRange(1, 9);
4536 QTest::newRow("move within view, move multiple (> 1 row) up") << 30 << 0.0 << 0.0
4537 << 10 << 1 << 5 << ListRange(1, 9);
4538 QTest::newRow("move within view, move multiple up, move to first index") << 30 << 0.0 << 0.0
4539 << 10 << 0 << 3 << ListRange(0, 9);
4540 QTest::newRow("move within view, move multiple up, move to first index, contentY not 0") << 30 << 60.0 << 0.0
4541 << 10+3 << 0+3 << 3 << ListRange(0+3, 9+3);
4542 QTest::newRow("move within view, move multiple up (> 1 row), move to first index, contentY not on border") << 30 << 80.0 << 0.0
4543 << 10+3 << 0+3 << 5 << ListRange(0+3, 9+3);
4544 QTest::newRow("move within view, move multiple up, move last item") << 30 << 0.0 << 0.0
4545 << 15 << 5 << 3 << ListRange(5, 14);
4546 QTest::newRow("move within view, move multiple up, move last->first") << 30 << 0.0 << 0.0
4547 << 15 << 0 << 3 << ListRange(0, 14);
4549 QTest::newRow("move from below view, move 1 up") << 30 << 0.0 << 0.0
4550 << 20 << 5 << 1 << ListRange(5, 17);
4551 QTest::newRow("move from below view, move 1 up, move to top") << 30 << 0.0 << 0.0
4552 << 20 << 0 << 1 << ListRange(0, 17);
4553 QTest::newRow("move from below view, move 1 up, move to top, contentY not 0") << 30 << 60.0 << 0.0
4554 << 25 << 3 << 1 << ListRange(0+3, 17+3);
4555 QTest::newRow("move from below view, move multiple (> 1 row) up") << 30 << 0.0 << 0.0
4556 << 20 << 5 << 5 << ListRange(5, 17);
4557 QTest::newRow("move from below view, move multiple up, move to top") << 30 << 0.0 << 0.0
4558 << 20 << 0 << 3 << ListRange(0, 17);
4559 QTest::newRow("move from below view, move multiple up, move to top, contentY not 0") << 30 << 60.0 << 0.0
4560 << 25 << 3 << 3 << ListRange(0+3, 17+3);
4562 QTest::newRow("move from below view, move 1 up, move to bottom") << 30 << 0.0 << 0.0
4563 << 20 << 17 << 1 << ListRange(17, 17);
4564 QTest::newRow("move from below view, move 1 up, move to bottom, contentY not 0") << 30 << 60.0 << 0.0
4565 << 25 << 17+3 << 1 << ListRange(17+3, 17+3);
4566 QTest::newRow("move from below view, move multiple up, move to to bottom") << 30 << 0.0 << 0.0
4567 << 20 << 17 << 3 << ListRange(17, 17);
4568 QTest::newRow("move from below view, move multiple up, move to bottom, contentY not 0") << 30 << 60.0 << 0.0
4569 << 25 << 17+3 << 3 << ListRange(17+3, 17+3);
4572 void tst_QQuickGridView::removeTransitions()
4574 QFETCH(int, initialItemCount);
4575 QFETCH(bool, shouldAnimateTargets);
4576 QFETCH(qreal, contentY);
4577 QFETCH(int, removalIndex);
4578 QFETCH(int, removalCount);
4579 QFETCH(ListRange, expectedDisplacedIndexes);
4581 // added items should end here
4582 QPointF targetItems_transitionTo(-50, -50);
4584 // displaced items should pass through this points
4585 QPointF displacedItems_transitionVia(100, 100);
4588 for (int i = 0; i < initialItemCount; i++)
4589 model.addItem("Original item" + QString::number(i), "");
4590 QaimModel model_targetItems_transitionTo;
4591 QaimModel model_displacedItems_transitionVia;
4593 QQuickView *canvas = getView();
4594 QQmlContext *ctxt = canvas->rootContext();
4595 ctxt->setContextProperty("testModel", &model);
4596 ctxt->setContextProperty("model_targetItems_transitionTo", &model_targetItems_transitionTo);
4597 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4598 ctxt->setContextProperty("targetItems_transitionTo", targetItems_transitionTo);
4599 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4600 canvas->setSource(testFileUrl("removeTransitions.qml"));
4603 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4604 QTRY_VERIFY(gridview != 0);
4605 QQuickItem *contentItem = gridview->contentItem();
4606 QVERIFY(contentItem != 0);
4607 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4609 if (contentY != 0) {
4610 gridview->setContentY(contentY);
4611 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4614 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4616 // only target items that are visible should be animated
4617 QList<QPair<QString, QString> > expectedTargetData;
4618 QList<int> targetIndexes;
4619 if (shouldAnimateTargets) {
4620 for (int i=removalIndex; i<removalIndex+removalCount; i++) {
4621 int firstVisibleIndex = (contentY / 60.0)*3;
4622 int lastVisibleIndex = (qCeil((contentY + gridview->height()) / 60.0)*3) - 1;
4623 if (i >= firstVisibleIndex && i <= lastVisibleIndex) {
4624 expectedTargetData << qMakePair(model.name(i), model.number(i));
4628 QVERIFY(expectedTargetData.count() > 0);
4631 // calculate targetItems and expectedTargets before model changes
4632 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4633 QVariantMap expectedTargets;
4634 for (int i=0; i<targetIndexes.count(); i++)
4635 expectedTargets[model.name(targetIndexes[i])] = targetIndexes[i];
4638 model.removeItems(removalIndex, removalCount);
4639 QTRY_COMPARE(model.count(), gridview->count());
4641 if (shouldAnimateTargets || expectedDisplacedIndexes.isValid()) {
4642 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4643 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4644 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4646 // check the target and displaced items were animated
4647 model_targetItems_transitionTo.matchAgainst(expectedTargetData, "wasn't animated to target 'to' pos", "shouldn't have been animated to target 'to' pos");
4648 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4650 // check attached properties
4651 QCOMPARE(gridview->property("targetTrans_items").toMap(), expectedTargets);
4652 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4653 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4654 if (expectedDisplacedIndexes.isValid()) {
4655 // adjust expectedDisplacedIndexes to their final values after the move
4656 QList<int> displacedIndexes = adjustIndexesForRemoveDisplaced(expectedDisplacedIndexes.indexes, removalIndex, removalCount);
4657 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4658 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4659 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4662 QTRY_COMPARE(model_targetItems_transitionTo.count(), 0);
4663 QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0);
4666 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4667 int itemCount = items.count();
4668 int firstVisibleIndex = -1;
4669 for (int i=0; i<items.count(); i++) {
4670 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4671 int index = e.evaluate().toInt();
4672 if (firstVisibleIndex < 0 && items[i]->y() >= contentY)
4673 firstVisibleIndex = index;
4675 itemCount--; // exclude deleted items
4677 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4679 // verify all items moved to the correct final positions
4680 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
4681 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4682 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4683 QCOMPARE(item->x(), (i%3)*80.0);
4684 QCOMPARE(item->y(), contentY + ((i-firstVisibleIndex)/3) * 60.0);
4685 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4687 QTRY_COMPARE(name->text(), model.name(i));
4690 releaseView(canvas);
4693 void tst_QQuickGridView::removeTransitions_data()
4695 QTest::addColumn<int>("initialItemCount");
4696 QTest::addColumn<qreal>("contentY");
4697 QTest::addColumn<bool>("shouldAnimateTargets");
4698 QTest::addColumn<int>("removalIndex");
4699 QTest::addColumn<int>("removalCount");
4700 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4702 // All items that are visible following the remove operation should be animated.
4703 // Remove targets that are outside of the view should not be animated.
4705 // For a GridView, removing any number of items other than a full row before the start
4706 // should displace all items in the view
4707 QTest::newRow("remove 1 before start")
4708 << 30 << 120.0 << false
4709 << 2 << 1 << ListRange(6, 24); // 6-24 are displaced
4710 QTest::newRow("remove 1 row, before start")
4711 << 30 << 120.0 << false
4712 << 3 << 3 << ListRange();
4713 QTest::newRow("remove between 1-2 rows, before start")
4714 << 30 << 120.0 << false
4715 << 0 << 5 << ListRange(6, 25);
4716 QTest::newRow("remove 2 rows, before start")
4717 << 30 << 120.0 << false
4718 << 0 << 6 << ListRange();
4719 QTest::newRow("remove mix of before and after start")
4720 << 30 << 60.0 << true
4721 << 2 << 3 << ListRange(5, 23); // 5-23 are displaced into view
4724 QTest::newRow("remove 1 from start")
4725 << 30 << 0.0 << true
4726 << 0 << 1 << ListRange(1, 18); // 1-18 are displaced into view
4727 QTest::newRow("remove multiple from start")
4728 << 30 << 0.0 << true
4729 << 0 << 3 << ListRange(3, 20); // 3-18 are displaced into view
4730 QTest::newRow("remove 1 from start, content y not 0")
4731 << 30 << 60.0 << true
4732 << 3 << 1 << ListRange(1 + 3, 18 + 3);
4733 QTest::newRow("remove multiple from start, content y not 0")
4734 << 30 << 60.0 << true
4735 << 3 << 3 << ListRange(3 + 3, 20 + 3);
4738 QTest::newRow("remove 1 from middle")
4739 << 30 << 0.0 << true
4740 << 5 << 1 << ListRange(6, 18);
4741 QTest::newRow("remove multiple from middle")
4742 << 30 << 0.0 << true
4743 << 5 << 3 << ListRange(8, 20);
4746 QTest::newRow("remove 1 from bottom")
4747 << 30 << 0.0 << true
4748 << 17 << 1 << ListRange(18, 18);
4749 QTest::newRow("remove multiple (1 row) from bottom")
4750 << 30 << 0.0 << true
4751 << 15 << 3 << ListRange(18, 20);
4752 QTest::newRow("remove multiple (> 1 row) from bottom")
4753 << 30 << 0.0 << true
4754 << 15 << 5 << ListRange(20, 22);
4755 QTest::newRow("remove 1 from bottom, content y not 0")
4756 << 30 << 60.0 << true
4757 << 17 + 3 << 1 << ListRange(18 + 3, 18 + 3);
4758 QTest::newRow("remove multiple (1 row) from bottom, content y not 0")
4759 << 30 << 60.0 << true
4760 << 15 + 3 << 3 << ListRange(18 + 3, 20 + 3);
4763 QTest::newRow("remove 1 after end")
4764 << 30 << 0.0 << false
4765 << 18 << 1 << ListRange();
4766 QTest::newRow("remove multiple after end")
4767 << 30 << 0.0 << false
4768 << 18 << 3 << ListRange();
4771 void tst_QQuickGridView::displacedTransitions()
4773 QFETCH(bool, useDisplaced);
4774 QFETCH(bool, displacedEnabled);
4775 QFETCH(bool, useAddDisplaced);
4776 QFETCH(bool, addDisplacedEnabled);
4777 QFETCH(bool, useMoveDisplaced);
4778 QFETCH(bool, moveDisplacedEnabled);
4779 QFETCH(bool, useRemoveDisplaced);
4780 QFETCH(bool, removeDisplacedEnabled);
4781 QFETCH(ListChange, change);
4782 QFETCH(ListRange, expectedDisplacedIndexes);
4785 for (int i = 0; i < 30; i++)
4786 model.addItem("Original item" + QString::number(i), "");
4787 QaimModel model_displaced_transitionVia;
4788 QaimModel model_addDisplaced_transitionVia;
4789 QaimModel model_moveDisplaced_transitionVia;
4790 QaimModel model_removeDisplaced_transitionVia;
4792 QPointF displaced_transitionVia(-50, -100);
4793 QPointF addDisplaced_transitionVia(-150, 100);
4794 QPointF moveDisplaced_transitionVia(50, -100);
4795 QPointF removeDisplaced_transitionVia(150, 100);
4797 QQuickView *canvas = getView();
4798 QQmlContext *ctxt = canvas->rootContext();
4799 ctxt->setContextProperty("testModel", &model);
4800 ctxt->setContextProperty("model_displaced_transitionVia", &model_displaced_transitionVia);
4801 ctxt->setContextProperty("model_addDisplaced_transitionVia", &model_addDisplaced_transitionVia);
4802 ctxt->setContextProperty("model_moveDisplaced_transitionVia", &model_moveDisplaced_transitionVia);
4803 ctxt->setContextProperty("model_removeDisplaced_transitionVia", &model_removeDisplaced_transitionVia);
4804 ctxt->setContextProperty("displaced_transitionVia", displaced_transitionVia);
4805 ctxt->setContextProperty("addDisplaced_transitionVia", addDisplaced_transitionVia);
4806 ctxt->setContextProperty("moveDisplaced_transitionVia", moveDisplaced_transitionVia);
4807 ctxt->setContextProperty("removeDisplaced_transitionVia", removeDisplaced_transitionVia);
4808 ctxt->setContextProperty("useDisplaced", useDisplaced);
4809 ctxt->setContextProperty("displacedEnabled", displacedEnabled);
4810 ctxt->setContextProperty("useAddDisplaced", useAddDisplaced);
4811 ctxt->setContextProperty("addDisplacedEnabled", addDisplacedEnabled);
4812 ctxt->setContextProperty("useMoveDisplaced", useMoveDisplaced);
4813 ctxt->setContextProperty("moveDisplacedEnabled", moveDisplacedEnabled);
4814 ctxt->setContextProperty("useRemoveDisplaced", useRemoveDisplaced);
4815 ctxt->setContextProperty("removeDisplacedEnabled", removeDisplacedEnabled);
4816 canvas->setSource(testFileUrl("displacedTransitions.qml"));
4818 qApp->processEvents();
4820 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4821 QTRY_VERIFY(gridview != 0);
4822 QQuickItem *contentItem = gridview->contentItem();
4823 QVERIFY(contentItem != 0);
4824 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4826 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4827 gridview->setProperty("displaceTransitionsDone", false);
4829 switch (change.type) {
4830 case ListChange::Inserted:
4832 QList<QPair<QString, QString> > targetItemData;
4833 for (int i=change.index; i<change.index + change.count; ++i)
4834 targetItemData << qMakePair(QString("new item %1").arg(i), QString::number(i));
4835 model.insertItems(change.index, targetItemData);
4836 QTRY_COMPARE(model.count(), gridview->count());
4839 case ListChange::Removed:
4840 model.removeItems(change.index, change.count);
4841 QTRY_COMPARE(model.count(), gridview->count());
4843 case ListChange::Moved:
4844 model.moveItems(change.index, change.to, change.count);
4845 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4847 case ListChange::SetCurrent:
4848 case ListChange::SetContentY:
4852 QVariantList resultTargetIndexes = gridview->property("displacedTargetIndexes").toList();
4853 QVariantList resultTargetItems = gridview->property("displacedTargetItems").toList();
4855 if ((useDisplaced && displacedEnabled)
4856 || (useAddDisplaced && addDisplacedEnabled)
4857 || (useMoveDisplaced && moveDisplacedEnabled)
4858 || (useRemoveDisplaced && removeDisplacedEnabled)) {
4859 QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
4861 // check the correct number of target items and indexes were received
4862 QCOMPARE(resultTargetIndexes.count(), expectedDisplacedIndexes.count());
4863 for (int i=0; i<resultTargetIndexes.count(); i++)
4864 QCOMPARE(resultTargetIndexes[i].value<QList<int> >().count(), change.count);
4865 QCOMPARE(resultTargetItems.count(), expectedDisplacedIndexes.count());
4866 for (int i=0; i<resultTargetItems.count(); i++)
4867 QCOMPARE(resultTargetItems[i].toList().count(), change.count);
4869 QCOMPARE(resultTargetIndexes.count(), 0);
4870 QCOMPARE(resultTargetItems.count(), 0);
4873 if (change.type == ListChange::Inserted && useAddDisplaced && addDisplacedEnabled)
4874 model_addDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with add displaced", "shouldn't have been animated with add displaced");
4876 QCOMPARE(model_addDisplaced_transitionVia.count(), 0);
4877 if (change.type == ListChange::Moved && useMoveDisplaced && moveDisplacedEnabled)
4878 model_moveDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with move displaced", "shouldn't have been animated with move displaced");
4880 QCOMPARE(model_moveDisplaced_transitionVia.count(), 0);
4881 if (change.type == ListChange::Removed && useRemoveDisplaced && removeDisplacedEnabled)
4882 model_removeDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with remove displaced", "shouldn't have been animated with remove displaced");
4884 QCOMPARE(model_removeDisplaced_transitionVia.count(), 0);
4886 if (useDisplaced && displacedEnabled
4887 && ( (change.type == ListChange::Inserted && (!useAddDisplaced || !addDisplacedEnabled))
4888 || (change.type == ListChange::Moved && (!useMoveDisplaced || !moveDisplacedEnabled))
4889 || (change.type == ListChange::Removed && (!useRemoveDisplaced || !removeDisplacedEnabled))) ) {
4890 model_displaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with generic displaced", "shouldn't have been animated with generic displaced");
4892 QCOMPARE(model_displaced_transitionVia.count(), 0);
4895 // verify all items moved to the correct final positions
4896 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4897 for (int i=0; i < model.count() && i < items.count(); ++i) {
4898 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4899 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4900 QCOMPARE(item->x(), (i%3)*80.0);
4901 QCOMPARE(item->y(), (i/3)*60.0);
4902 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4904 QTRY_COMPARE(name->text(), model.name(i));
4907 releaseView(canvas);
4910 void tst_QQuickGridView::displacedTransitions_data()
4912 QTest::addColumn<bool>("useDisplaced");
4913 QTest::addColumn<bool>("displacedEnabled");
4914 QTest::addColumn<bool>("useAddDisplaced");
4915 QTest::addColumn<bool>("addDisplacedEnabled");
4916 QTest::addColumn<bool>("useMoveDisplaced");
4917 QTest::addColumn<bool>("moveDisplacedEnabled");
4918 QTest::addColumn<bool>("useRemoveDisplaced");
4919 QTest::addColumn<bool>("removeDisplacedEnabled");
4920 QTest::addColumn<ListChange>("change");
4921 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4923 QTest::newRow("no displaced transitions at all")
4928 << ListChange::insert(0, 1) << ListRange(0, 17);
4930 QTest::newRow("just displaced")
4935 << ListChange::insert(0, 1) << ListRange(0, 17);
4937 QTest::newRow("just displaced (not enabled)")
4942 << ListChange::insert(0, 1) << ListRange(0, 17);
4944 QTest::newRow("displaced + addDisplaced")
4949 << ListChange::insert(0, 1) << ListRange(0, 17);
4951 QTest::newRow("displaced + addDisplaced (not enabled)")
4956 << ListChange::insert(0, 1) << ListRange(0, 17);
4958 QTest::newRow("displaced + moveDisplaced")
4963 << ListChange::move(0, 10, 1) << ListRange(1, 10);
4965 QTest::newRow("displaced + moveDisplaced (not enabled)")
4970 << ListChange::move(0, 10, 1) << ListRange(1, 10);
4972 QTest::newRow("displaced + removeDisplaced")
4977 << ListChange::remove(0, 1) << ListRange(1, 18);
4979 QTest::newRow("displaced + removeDisplaced (not enabled)")
4984 << ListChange::remove(0, 1) << ListRange(1, 18);
4987 QTest::newRow("displaced + add, should use generic displaced for a remove")
4992 << ListChange::remove(0, 1) << ListRange(1, 18);
4995 void tst_QQuickGridView::multipleTransitions()
4997 // Tests that if you interrupt a transition in progress with another action that
4998 // cancels the previous transition, the resulting items are still placed correctly.
5000 QFETCH(int, initialCount);
5001 QFETCH(qreal, contentY);
5002 QFETCH(QList<ListChange>, changes);
5003 QFETCH(bool, enableAddTransitions);
5004 QFETCH(bool, enableMoveTransitions);
5005 QFETCH(bool, enableRemoveTransitions);
5006 QFETCH(bool, rippleAddDisplaced);
5008 // add transitions on the left, moves on the right
5009 QPointF addTargets_transitionFrom(-50, -50);
5010 QPointF addDisplaced_transitionFrom(-50, 50);
5011 QPointF moveTargets_transitionFrom(50, -50);
5012 QPointF moveDisplaced_transitionFrom(50, 50);
5013 QPointF removeTargets_transitionTo(-100, 300);
5014 QPointF removeDisplaced_transitionFrom(100, 300);
5017 for (int i = 0; i < initialCount; i++)
5018 model.addItem("Original item" + QString::number(i), "");
5020 QQuickView *canvas = getView();
5021 QQmlContext *ctxt = canvas->rootContext();
5022 ctxt->setContextProperty("testModel", &model);
5023 ctxt->setContextProperty("addTargets_transitionFrom", addTargets_transitionFrom);
5024 ctxt->setContextProperty("addDisplaced_transitionFrom", addDisplaced_transitionFrom);
5025 ctxt->setContextProperty("moveTargets_transitionFrom", moveTargets_transitionFrom);
5026 ctxt->setContextProperty("moveDisplaced_transitionFrom", moveDisplaced_transitionFrom);
5027 ctxt->setContextProperty("removeTargets_transitionTo", removeTargets_transitionTo);
5028 ctxt->setContextProperty("removeDisplaced_transitionFrom", removeDisplaced_transitionFrom);
5029 ctxt->setContextProperty("enableAddTransitions", enableAddTransitions);
5030 ctxt->setContextProperty("enableMoveTransitions", enableMoveTransitions);
5031 ctxt->setContextProperty("enableRemoveTransitions", enableRemoveTransitions);
5032 ctxt->setContextProperty("rippleAddDisplaced", rippleAddDisplaced);
5033 canvas->setSource(testFileUrl("multipleTransitions.qml"));
5035 QTest::qWaitForWindowShown(canvas);
5037 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
5038 QTRY_VERIFY(gridview != 0);
5039 QQuickItem *contentItem = gridview->contentItem();
5040 QVERIFY(contentItem != 0);
5041 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5043 if (contentY != 0) {
5044 gridview->setContentY(contentY);
5045 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5048 int timeBetweenActions = canvas->rootObject()->property("timeBetweenActions").toInt();
5050 for (int i=0; i<changes.count(); i++) {
5051 switch (changes[i].type) {
5052 case ListChange::Inserted:
5054 QList<QPair<QString, QString> > targetItems;
5055 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
5056 targetItems << qMakePair(QString("new item %1").arg(j), QString::number(j));
5057 model.insertItems(changes[i].index, targetItems);
5058 QTRY_COMPARE(model.count(), gridview->count());
5059 if (i == changes.count() - 1) {
5060 QTRY_VERIFY(!gridview->property("runningAddTargets").toBool());
5061 QTRY_VERIFY(!gridview->property("runningAddDisplaced").toBool());
5063 QTest::qWait(timeBetweenActions);
5067 case ListChange::Removed:
5068 model.removeItems(changes[i].index, changes[i].count);
5069 QTRY_COMPARE(model.count(), gridview->count());
5070 if (i == changes.count() - 1) {
5071 QTRY_VERIFY(!gridview->property("runningRemoveTargets").toBool());
5072 QTRY_VERIFY(!gridview->property("runningRemoveDisplaced").toBool());
5074 QTest::qWait(timeBetweenActions);
5077 case ListChange::Moved:
5078 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
5079 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5080 if (i == changes.count() - 1) {
5081 QTRY_VERIFY(!gridview->property("runningMoveTargets").toBool());
5082 QTRY_VERIFY(!gridview->property("runningMoveDisplaced").toBool());
5084 QTest::qWait(timeBetweenActions);
5087 case ListChange::SetCurrent:
5088 gridview->setCurrentIndex(changes[i].index);
5089 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5091 case ListChange::SetContentY:
5092 gridview->setContentY(changes[i].pos);
5093 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5097 QCOMPARE(gridview->count(), model.count());
5099 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5100 int firstVisibleIndex = -1;
5101 for (int i=0; i<items.count(); i++) {
5102 if (items[i]->y() >= contentY) {
5103 QQmlExpression e(qmlContext(items[i]), items[i], "index");
5104 firstVisibleIndex = e.evaluate().toInt();
5108 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
5110 // verify all items moved to the correct final positions
5111 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
5112 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
5113 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5114 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5115 QTRY_COMPARE(item->x(), (i%3)*80.0);
5116 QTRY_COMPARE(item->y(), (i/3)*60.0);
5117 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5119 QTRY_COMPARE(name->text(), model.name(i));
5122 releaseView(canvas);
5125 void tst_QQuickGridView::multipleTransitions_data()
5127 QTest::addColumn<int>("initialCount");
5128 QTest::addColumn<qreal>("contentY");
5129 QTest::addColumn<QList<ListChange> >("changes");
5130 QTest::addColumn<bool>("enableAddTransitions");
5131 QTest::addColumn<bool>("enableMoveTransitions");
5132 QTest::addColumn<bool>("enableRemoveTransitions");
5133 QTest::addColumn<bool>("rippleAddDisplaced");
5135 // the added item and displaced items should move to final dest correctly
5136 QTest::newRow("add item, then move it immediately") << 10 << 0.0 << (QList<ListChange>()
5137 << ListChange::insert(0, 1)
5138 << ListChange::move(0, 3, 1)
5140 << true << true << true << false;
5142 // items affected by the add should change from move to add transition
5143 QTest::newRow("move, then insert item before the moved item") << 20 << 0.0 << (QList<ListChange>()
5144 << ListChange::move(1, 10, 3)
5145 << ListChange::insert(0, 1)
5147 << true << true << true << false;
5149 // items should be placed correctly if you trigger a transition then refill for that index
5150 QTest::newRow("add at 0, flick down, flick back to top and add at 0 again") << 20 << 0.0 << (QList<ListChange>()
5151 << ListChange::insert(0, 1)
5152 << ListChange::setContentY(160.0)
5153 << ListChange::setContentY(0.0)
5154 << ListChange::insert(0, 1)
5156 << true << true << true << false;
5158 QTest::newRow("insert then remove same index, with ripple effect on add displaced") << 20 << 0.0 << (QList<ListChange>()
5159 << ListChange::insert(1, 1)
5160 << ListChange::remove(1, 1)
5162 << true << true << true << true;
5164 // if item is removed while undergoing a displaced transition, all other items should end up at their correct positions,
5165 // even if a remove-displace transition is not present to re-animate them
5166 QTest::newRow("insert then remove, with remove disabled") << 20 << 0.0 << (QList<ListChange>()
5167 << ListChange::insert(0, 1)
5168 << ListChange::remove(2, 1)
5170 << true << true << false << false;
5172 // if last item is not flush with the edge of the view, it should still be refilled in correctly after a
5173 // remove has changed the position of where it will move to
5174 QTest::newRow("insert twice then remove, with remove disabled") << 20 << 0.0 << (QList<ListChange>()
5175 << ListChange::setContentY(-10.0)
5176 << ListChange::insert(0, 1)
5177 << ListChange::insert(0, 1)
5178 << ListChange::remove(2, 1)
5180 << true << true << false << false;
5183 void tst_QQuickGridView::multipleDisplaced()
5185 // multiple move() operations should only restart displace transitions for items that
5186 // moved from previously set positions, and not those that have moved from their current
5187 // item positions (which may e.g. still be changing from easing bounces in the last transition)
5190 for (int i = 0; i < 30; i++)
5191 model.addItem("Original item" + QString::number(i), "");
5193 QQuickView *canvas = createView();
5194 QQmlContext *ctxt = canvas->rootContext();
5195 ctxt->setContextProperty("testModel", &model);
5196 canvas->setSource(testFileUrl("multipleDisplaced.qml"));
5198 QTest::qWaitForWindowShown(canvas);
5200 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
5201 QTRY_VERIFY(gridview != 0);
5202 QQuickItem *contentItem = gridview->contentItem();
5203 QVERIFY(contentItem != 0);
5204 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5206 model.moveItems(12, 8, 1);
5207 QTest::qWait(canvas->rootObject()->property("duration").toInt() / 2);
5208 model.moveItems(8, 3, 1);
5209 QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
5211 QVariantMap transitionsStarted = gridview->property("displaceTransitionsStarted").toMap();
5212 foreach (const QString &name, transitionsStarted.keys()) {
5213 QVERIFY2(transitionsStarted[name] == 1,
5214 QTest::toString(QString("%1 was displaced %2 times").arg(name).arg(transitionsStarted[name].toInt())));
5217 // verify all items moved to the correct final positions
5218 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5219 for (int i=0; i < model.count() && i < items.count(); ++i) {
5220 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5221 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5222 QTRY_COMPARE(item->x(), (i%3)*80.0);
5223 QTRY_COMPARE(item->y(), (i/3)*60.0);
5224 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5226 QTRY_COMPARE(name->text(), model.name(i));
5232 void tst_QQuickGridView::cacheBuffer()
5234 QQuickView *canvas = createView();
5237 for (int i = 0; i < 90; i++)
5238 model.addItem("Item" + QString::number(i), "");
5240 QQmlContext *ctxt = canvas->rootContext();
5241 ctxt->setContextProperty("testModel", &model);
5242 ctxt->setContextProperty("testRightToLeft", QVariant(false));
5243 ctxt->setContextProperty("testTopToBottom", QVariant(false));
5245 canvas->setSource(testFileUrl("gridview1.qml"));
5247 qApp->processEvents();
5249 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
5250 QVERIFY(gridview != 0);
5252 QQuickItem *contentItem = gridview->contentItem();
5253 QVERIFY(contentItem != 0);
5254 QVERIFY(gridview->delegate() != 0);
5255 QVERIFY(gridview->model() != 0);
5257 // Confirm items positioned correctly
5258 int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
5259 for (int i = 0; i < model.count() && i < itemCount; ++i) {
5260 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5261 QTRY_COMPARE(item->x(), (i%3)*80.0);
5262 QTRY_COMPARE(item->y(), (i/3)*60.0);
5265 QQmlIncubationController controller;
5266 canvas->engine()->setIncubationController(&controller);
5268 canvas->rootObject()->setProperty("cacheBuffer", 200);
5269 QTRY_VERIFY(gridview->cacheBuffer() == 200);
5271 // items will be created one at a time
5272 for (int i = itemCount; i < qMin(itemCount+9,model.count()); ++i) {
5273 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
5274 QQuickItem *item = 0;
5277 controller.incubateWhile(&b);
5278 item = findItem<QQuickItem>(gridview, "wrapper", i);
5284 controller.incubateWhile(&b);
5287 int newItemCount = 0;
5288 newItemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
5290 // Confirm items positioned correctly
5291 for (int i = 0; i < model.count() && i < newItemCount; ++i) {
5292 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5294 QTRY_COMPARE(item->x(), (i%3)*80.0);
5295 QTRY_COMPARE(item->y(), (i/3)*60.0);
5298 // move view and confirm items in view are visible immediately and outside are created async
5299 gridview->setContentY(300);
5301 for (int i = 15; i < 34; ++i) { // 34 due to staggered item creation
5302 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5304 QTRY_COMPARE(item->x(), (i%3)*80.0);
5305 QTRY_COMPARE(item->y(), (i/3)*60.0);
5308 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == 0);
5310 // ensure buffered items are created
5311 for (int i = 34; i < qMin(44,model.count()); ++i) {
5312 QQuickItem *item = 0;
5314 qGuiApp->processEvents(); // allow refill to happen
5316 controller.incubateWhile(&b);
5317 item = findItem<QQuickItem>(gridview, "wrapper", i);
5323 controller.incubateWhile(&b);
5329 void tst_QQuickGridView::asynchronous()
5331 QQuickView *canvas = createView();
5333 QQmlIncubationController controller;
5334 canvas->engine()->setIncubationController(&controller);
5336 canvas->setSource(testFileUrl("asyncloader.qml"));
5338 QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
5339 QVERIFY(rootObject);
5341 QQuickGridView *gridview = 0;
5344 controller.incubateWhile(&b);
5345 gridview = rootObject->findChild<QQuickGridView*>("view");
5348 // items will be created one at a time
5349 for (int i = 0; i < 12; ++i) {
5350 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
5351 QQuickItem *item = 0;
5354 controller.incubateWhile(&b);
5355 item = findItem<QQuickItem>(gridview, "wrapper", i);
5361 controller.incubateWhile(&b);
5364 // verify positioning
5365 QQuickItem *contentItem = gridview->contentItem();
5366 for (int i = 0; i < 12; ++i) {
5367 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5368 if (!item) qWarning() << "Item" << i << "not found";
5369 QVERIFY(item->x() == (i%3)*100);
5370 QVERIFY(item->y() == (i/3)*100);
5376 void tst_QQuickGridView::unrequestedVisibility()
5379 for (int i = 0; i < 30; i++)
5380 model.addItem("Item" + QString::number(i), QString::number(i));
5382 QQuickView *canvas = new QQuickView(0);
5383 canvas->setGeometry(0,0,240,320);
5385 QQmlContext *ctxt = canvas->rootContext();
5386 ctxt->setContextProperty("testModel", &model);
5387 ctxt->setContextProperty("testWrap", QVariant(false));
5389 canvas->setSource(testFileUrl("unrequestedItems.qml"));
5393 qApp->processEvents();
5395 QQuickGridView *leftview = findItem<QQuickGridView>(canvas->rootObject(), "leftGrid");
5396 QTRY_VERIFY(leftview != 0);
5398 QQuickGridView *rightview = findItem<QQuickGridView>(canvas->rootObject(), "rightGrid");
5399 QTRY_VERIFY(rightview != 0);
5401 QQuickItem *leftContent = leftview->contentItem();
5402 QTRY_VERIFY(leftContent != 0);
5404 QQuickItem *rightContent = rightview->contentItem();
5405 QTRY_VERIFY(rightContent != 0);
5407 rightview->setCurrentIndex(12);
5409 QTRY_COMPARE(leftview->contentY(), 0.0);
5410 QTRY_COMPARE(rightview->contentY(), 240.0);
5414 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5415 QCOMPARE(item->isVisible(), true);
5416 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5417 QCOMPARE(item->isVisible(), false);
5419 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5420 QCOMPARE(item->isVisible(), false);
5421 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5422 QCOMPARE(item->isVisible(), true);
5424 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 9));
5425 QCOMPARE(item->isVisible(), true);
5426 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 10));
5427 QCOMPARE(item->isVisible(), false);
5428 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 3));
5429 QCOMPARE(item->isVisible(), false);
5430 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 4));
5431 QCOMPARE(item->isVisible(), true);
5433 rightview->setCurrentIndex(0);
5435 QTRY_COMPARE(leftview->contentY(), 0.0);
5436 QTRY_COMPARE(rightview->contentY(), 0.0);
5438 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5439 QCOMPARE(item->isVisible(), true);
5440 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5441 QTRY_COMPARE(item->isVisible(), true);
5443 QVERIFY(!findItem<QQuickItem>(leftContent, "wrapper", 11));
5444 QVERIFY(!findItem<QQuickItem>(rightContent, "wrapper", 11));
5446 leftview->setCurrentIndex(12);
5448 QTRY_COMPARE(leftview->contentY(), 240.0);
5449 QTRY_COMPARE(rightview->contentY(), 0.0);
5451 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5452 QTRY_COMPARE(item->isVisible(), false);
5453 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5454 QCOMPARE(item->isVisible(), true);
5456 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5457 QCOMPARE(item->isVisible(), true);
5458 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5459 QCOMPARE(item->isVisible(), false);
5461 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5462 QCOMPARE(item->isVisible(), false);
5463 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5464 QCOMPARE(item->isVisible(), true);
5465 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5466 QCOMPARE(item->isVisible(), true);
5467 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5468 QCOMPARE(item->isVisible(), false);
5470 // move a non-visible item into view
5471 model.moveItems(10, 9, 1);
5472 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5474 QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5475 QCOMPARE(item->isVisible(), false);
5476 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5477 QCOMPARE(item->isVisible(), true);
5479 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5480 QCOMPARE(item->isVisible(), true);
5481 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5482 QCOMPARE(item->isVisible(), false);
5484 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5485 QCOMPARE(item->isVisible(), false);
5486 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5487 QCOMPARE(item->isVisible(), true);
5488 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5489 QCOMPARE(item->isVisible(), true);
5490 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5491 QCOMPARE(item->isVisible(), false);
5493 // move a visible item out of view
5494 model.moveItems(5, 3, 1);
5495 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5497 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5498 QCOMPARE(item->isVisible(), false);
5499 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5500 QCOMPARE(item->isVisible(), true);
5501 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5502 QCOMPARE(item->isVisible(), true);
5503 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5504 QCOMPARE(item->isVisible(), false);
5506 // move a non-visible item into view
5507 model.moveItems(3, 5, 1);
5508 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5510 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5511 QCOMPARE(item->isVisible(), false);
5512 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5513 QCOMPARE(item->isVisible(), true);
5514 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5515 QCOMPARE(item->isVisible(), true);
5516 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5517 QCOMPARE(item->isVisible(), false);
5519 // move a visible item out of view
5520 model.moveItems(9, 10, 1);
5521 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5523 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5524 QCOMPARE(item->isVisible(), false);
5525 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5526 QCOMPARE(item->isVisible(), true);
5527 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5528 QCOMPARE(item->isVisible(), true);
5529 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5530 QCOMPARE(item->isVisible(), false);
5532 // move a non-visible item into view
5533 model.moveItems(10, 9, 1);
5534 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5536 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5537 QCOMPARE(item->isVisible(), false);
5538 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5539 QCOMPARE(item->isVisible(), true);
5540 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5541 QCOMPARE(item->isVisible(), true);
5542 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5543 QCOMPARE(item->isVisible(), false);
5548 QList<int> tst_QQuickGridView::toIntList(const QVariantList &list)
5552 for (int i=0; i<list.count(); i++) {
5553 ret << list[i].toInt(&ok);
5555 qWarning() << "tst_QQuickGridView::toIntList(): not a number:" << list[i];
5561 void tst_QQuickGridView::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
5563 for (int i=0; i<indexLists.count(); i++) {
5564 QSet<int> current = indexLists[i].value<QList<int> >().toSet();
5565 if (current != expectedIndexes.toSet())
5566 qDebug() << "Cannot match actual targets" << current << "with expected" << expectedIndexes;
5567 QCOMPARE(current, expectedIndexes.toSet());
5571 void tst_QQuickGridView::matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes)
5573 for (QVariantMap::const_iterator it = items.begin(); it != items.end(); ++it) {
5574 QVERIFY(it.value().type() == QVariant::Int);
5575 QString name = it.key();
5576 int itemIndex = it.value().toInt();
5577 QVERIFY2(expectedIndexes.contains(itemIndex), QTest::toString(QString("Index %1 not found in expectedIndexes").arg(itemIndex)));
5578 if (model.name(itemIndex) != name)
5579 qDebug() << itemIndex;
5580 QCOMPARE(model.name(itemIndex), name);
5582 QCOMPARE(items.count(), expectedIndexes.count());
5585 void tst_QQuickGridView::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
5587 for (int i=0; i<itemLists.count(); i++) {
5588 QVariantList current = itemLists[i].toList();
5589 for (int j=0; j<current.count(); j++) {
5590 QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
5591 QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1").arg(j)));
5592 QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1").arg(j)));
5594 QCOMPARE(current.count(), expectedItems.count());
5598 QTEST_MAIN(tst_QQuickGridView)
5600 #include "tst_qquickgridview.moc"