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_condensed() { multipleChanges(true); }
93 void multipleChanges_condensed_data() { multipleChanges_data(); }
94 void multipleChanges_uncondensed() { multipleChanges(false); }
95 void multipleChanges_uncondensed_data() { multipleChanges_data(); }
96 void swapWithFirstItem();
99 void noCurrentIndex();
100 void defaultValues();
102 void propertyChanges();
103 void componentChanges();
105 void positionViewAtIndex();
106 void positionViewAtIndex_rightToLeft();
111 void enforceRange_rightToLeft();
113 void manualHighlight();
119 void resizeViewAndRepaint();
120 void changeColumnCount();
121 void indexAt_itemAt_data();
122 void indexAt_itemAt();
126 void onRemove_data();
129 void creationContext();
130 void snapToRow_data();
132 void snapOneRow_data();
137 void unrequestedVisibility();
139 void populateTransitions();
140 void populateTransitions_data();
141 void addTransitions();
142 void addTransitions_data();
143 void moveTransitions();
144 void moveTransitions_data();
145 void removeTransitions();
146 void removeTransitions_data();
147 void displacedTransitions();
148 void displacedTransitions_data();
149 void multipleTransitions();
150 void multipleTransitions_data();
151 void multipleDisplaced();
154 QList<int> toIntList(const QVariantList &list);
155 void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes);
156 void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes);
157 void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems);
159 void multipleChanges(bool condensed);
160 void multipleChanges_data();
163 QQuickView *getView() {
165 if (QString(QTest::currentTestFunction()) != testForView) {
169 m_view->setSource(QUrl());
174 testForView = QTest::currentTestFunction();
175 m_view = createView();
178 void releaseView(QQuickView *view) {
179 Q_ASSERT(view == m_view);
180 m_view->setSource(QUrl());
183 QQuickView *getView() {
186 void releaseView(QQuickView *view) {
195 tst_QQuickGridView::tst_QQuickGridView() : m_view(0)
199 void tst_QQuickGridView::init()
202 if (m_view && QString(QTest::currentTestFunction()) != testForView) {
203 testForView = QString();
210 void tst_QQuickGridView::items()
212 QQuickView *canvas = createView();
215 model.addItem("Fred", "12345");
216 model.addItem("John", "2345");
217 model.addItem("Bob", "54321");
218 model.addItem("Billy", "22345");
219 model.addItem("Sam", "2945");
220 model.addItem("Ben", "04321");
221 model.addItem("Jim", "0780");
223 QQmlContext *ctxt = canvas->rootContext();
224 ctxt->setContextProperty("testModel", &model);
225 ctxt->setContextProperty("testRightToLeft", QVariant(false));
226 ctxt->setContextProperty("testTopToBottom", QVariant(false));
228 canvas->setSource(testFileUrl("gridview1.qml"));
229 qApp->processEvents();
231 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
232 QTRY_VERIFY(gridview != 0);
234 QQuickItem *contentItem = gridview->contentItem();
235 QTRY_VERIFY(contentItem != 0);
237 QTRY_COMPARE(gridview->count(), model.count());
238 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
239 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
241 for (int i = 0; i < model.count(); ++i) {
242 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
243 QTRY_VERIFY(name != 0);
244 QTRY_COMPARE(name->text(), model.name(i));
245 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
246 QTRY_VERIFY(number != 0);
247 QTRY_COMPARE(number->text(), model.number(i));
250 // set an empty model and confirm that items are destroyed
252 ctxt->setContextProperty("testModel", &model2);
254 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
255 QTRY_VERIFY(itemCount == 0);
260 void tst_QQuickGridView::changed()
262 QQuickView *canvas = createView();
265 model.addItem("Fred", "12345");
266 model.addItem("John", "2345");
267 model.addItem("Bob", "54321");
268 model.addItem("Billy", "22345");
269 model.addItem("Sam", "2945");
270 model.addItem("Ben", "04321");
271 model.addItem("Jim", "0780");
273 QQmlContext *ctxt = canvas->rootContext();
274 ctxt->setContextProperty("testModel", &model);
275 ctxt->setContextProperty("testRightToLeft", QVariant(false));
276 ctxt->setContextProperty("testTopToBottom", QVariant(false));
278 canvas->setSource(testFileUrl("gridview1.qml"));
279 qApp->processEvents();
281 QQuickFlickable *gridview = findItem<QQuickFlickable>(canvas->rootObject(), "grid");
282 QTRY_VERIFY(gridview != 0);
284 QQuickItem *contentItem = gridview->contentItem();
285 QTRY_VERIFY(contentItem != 0);
287 model.modifyItem(1, "Will", "9876");
288 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
289 QTRY_VERIFY(name != 0);
290 QTRY_COMPARE(name->text(), model.name(1));
291 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
292 QTRY_VERIFY(number != 0);
293 QTRY_COMPARE(number->text(), model.number(1));
298 void tst_QQuickGridView::inserted()
300 QQuickView *canvas = createView();
304 model.addItem("Fred", "12345");
305 model.addItem("John", "2345");
306 model.addItem("Bob", "54321");
308 QQmlContext *ctxt = canvas->rootContext();
309 ctxt->setContextProperty("testModel", &model);
310 ctxt->setContextProperty("testRightToLeft", QVariant(false));
311 ctxt->setContextProperty("testTopToBottom", QVariant(false));
313 canvas->setSource(testFileUrl("gridview1.qml"));
314 qApp->processEvents();
316 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
317 QTRY_VERIFY(gridview != 0);
319 QQuickItem *contentItem = gridview->contentItem();
320 QTRY_VERIFY(contentItem != 0);
322 model.insertItem(1, "Will", "9876");
324 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
325 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
327 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
328 QTRY_VERIFY(name != 0);
329 QTRY_COMPARE(name->text(), model.name(1));
330 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
331 QTRY_VERIFY(number != 0);
332 QTRY_COMPARE(number->text(), model.number(1));
334 // Checks that onAdd is called
335 int added = canvas->rootObject()->property("added").toInt();
336 QTRY_COMPARE(added, 1);
338 // Confirm items positioned correctly
339 for (int i = 0; i < model.count(); ++i) {
340 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
341 QTRY_COMPARE(item->x(), (i%3)*80.0);
342 QTRY_COMPARE(item->y(), (i/3)*60.0);
345 model.insertItem(0, "Foo", "1111"); // zero index, and current item
347 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
349 name = findItem<QQuickText>(contentItem, "textName", 0);
350 QTRY_VERIFY(name != 0);
351 QTRY_COMPARE(name->text(), model.name(0));
352 number = findItem<QQuickText>(contentItem, "textNumber", 0);
353 QTRY_VERIFY(number != 0);
354 QTRY_COMPARE(number->text(), model.number(0));
356 QTRY_COMPARE(gridview->currentIndex(), 1);
358 // Confirm items positioned correctly
359 for (int i = 0; i < model.count(); ++i) {
360 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
361 QTRY_VERIFY(item->x() == (i%3)*80);
362 QTRY_VERIFY(item->y() == (i/3)*60);
365 for (int i = model.count(); i < 30; ++i)
366 model.insertItem(i, "Hello", QString::number(i));
368 gridview->setContentY(120);
370 // Insert item outside visible area
371 model.insertItem(1, "Hello", "1324");
373 QTRY_VERIFY(gridview->contentY() == 120);
378 void tst_QQuickGridView::inserted_more()
380 QFETCH(qreal, contentYRowOffset);
381 QFETCH(int, insertIndex);
382 QFETCH(int, insertCount);
383 QFETCH(qreal, rowOffsetAfterMove);
386 for (int i = 0; i < 30; i++)
387 model.addItem("Item" + QString::number(i), "");
389 QQuickView *canvas = getView();
390 QQmlContext *ctxt = canvas->rootContext();
391 ctxt->setContextProperty("testModel", &model);
392 ctxt->setContextProperty("testRightToLeft", QVariant(false));
393 ctxt->setContextProperty("testTopToBottom", QVariant(false));
395 canvas->setSource(testFileUrl("gridview1.qml"));
397 qApp->processEvents();
399 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
400 QTRY_VERIFY(gridview != 0);
401 QQuickItem *contentItem = gridview->contentItem();
402 QTRY_VERIFY(contentItem != 0);
404 gridview->setContentY(contentYRowOffset * 60.0);
405 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
407 QList<QPair<QString, QString> > newData;
408 for (int i=0; i<insertCount; i++)
409 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
410 model.insertItems(insertIndex, newData);
411 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
413 // check visibleItems.first() is in correct position
414 QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
416 QCOMPARE(item0->y(), 0.0);
418 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
419 int firstVisibleIndex = -1;
420 for (int i=0; i<items.count(); i++) {
421 if (items[i]->y() >= gridview->contentY()) {
422 QQmlExpression e(qmlContext(items[i]), items[i], "index");
423 firstVisibleIndex = e.evaluate().toInt();
427 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
429 // Confirm items positioned correctly and indexes correct
430 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
433 qreal pixelOffset = 60 * rowOffsetAfterMove;
434 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
435 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
436 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
438 QCOMPARE(item->x(), (i%3)*80.0);
439 QCOMPARE(item->y(), (i/3)*60.0 + pixelOffset);
441 name = findItem<QQuickText>(contentItem, "textName", i);
443 QCOMPARE(name->text(), model.name(i));
444 number = findItem<QQuickText>(contentItem, "textNumber", i);
445 QVERIFY(number != 0);
446 QCOMPARE(number->text(), model.number(i));
452 void tst_QQuickGridView::inserted_more_data()
454 QTest::addColumn<qreal>("contentYRowOffset");
455 QTest::addColumn<int>("insertIndex");
456 QTest::addColumn<int>("insertCount");
457 QTest::addColumn<qreal>("rowOffsetAfterMove");
459 QTest::newRow("add 1, before visible items")
462 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
463 // new 1st visible item is at 0
465 QTest::newRow("add 2, before visible items")
468 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
470 QTest::newRow("add 3, before visible items")
473 << -1.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
475 QTest::newRow("add 5, before visible items")
478 << -1.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
479 // grid is rearranged and first visible moves forward within its row
481 QTest::newRow("add 6, before visible items")
484 << -1.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
488 QTest::newRow("add 1, at start of visible, content at start")
493 QTest::newRow("add multiple, at start of visible, content at start")
498 QTest::newRow("add 1, at start of visible, content not at start")
503 QTest::newRow("add multiple, at start of visible, content not at start")
509 QTest::newRow("add 1, at end of visible, content at start")
514 QTest::newRow("add 1, at end of visible, content at start")
519 QTest::newRow("add 1, at end of visible, content not at start")
524 QTest::newRow("add multiple, at end of visible, content not at start")
530 QTest::newRow("add 1, after visible, content at start")
535 QTest::newRow("add 1, after visible, content at start")
540 QTest::newRow("add 1, after visible, content not at start")
545 QTest::newRow("add multiple, after visible, content not at start")
551 void tst_QQuickGridView::insertBeforeVisible()
553 QFETCH(int, insertIndex);
554 QFETCH(int, insertCount);
555 QFETCH(int, cacheBuffer);
558 QQuickView *canvas = getView();
561 for (int i = 0; i < 30; i++)
562 model.addItem("Item" + QString::number(i), "");
564 QQmlContext *ctxt = canvas->rootContext();
565 ctxt->setContextProperty("testModel", &model);
566 ctxt->setContextProperty("testRightToLeft", QVariant(false));
567 ctxt->setContextProperty("testTopToBottom", QVariant(false));
568 canvas->setSource(testFileUrl("gridview1.qml"));
570 qApp->processEvents();
572 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
573 QTRY_VERIFY(gridview != 0);
574 QQuickItem *contentItem = gridview->contentItem();
575 QTRY_VERIFY(contentItem != 0);
577 gridview->setCacheBuffer(cacheBuffer);
578 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
580 // trigger a refill (not just setting contentY) so that the visibleItems grid is updated
581 int firstVisibleIndex = 12; // move to an index where the top item is not visible
582 gridview->setContentY(firstVisibleIndex/3 * 60.0);
583 gridview->setCurrentIndex(firstVisibleIndex);
584 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
586 QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex);
587 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex);
589 QCOMPARE(item->y(), gridview->contentY());
591 QList<QPair<QString, QString> > newData;
592 for (int i=0; i<insertCount; i++)
593 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
594 model.insertItems(insertIndex, newData);
595 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
597 // now, moving to the top of the view should position the inserted items correctly
598 int itemsOffsetAfterMove = (insertCount / 3) * -60.0;
599 gridview->setCurrentIndex(0);
600 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
601 QTRY_COMPARE(gridview->currentIndex(), 0);
602 QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove);
604 // Confirm items positioned correctly and indexes correct
605 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
606 for (int i = 0; i < model.count() && i < itemCount; ++i) {
607 item = findItem<QQuickItem>(contentItem, "wrapper", i);
608 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
609 QCOMPARE(item->x(), (i%3)*80.0);
610 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
611 name = findItem<QQuickText>(contentItem, "textName", i);
613 QTRY_COMPARE(name->text(), model.name(i));
619 void tst_QQuickGridView::insertBeforeVisible_data()
621 QTest::addColumn<int>("insertIndex");
622 QTest::addColumn<int>("insertCount");
623 QTest::addColumn<int>("cacheBuffer");
625 QTest::newRow("insert 1 at 0, 0 buffer") << 0 << 1 << 0;
626 QTest::newRow("insert 1 at 0, 100 buffer") << 0 << 1 << 100;
627 QTest::newRow("insert 1 at 0, 500 buffer") << 0 << 1 << 500;
629 QTest::newRow("insert 1 at 1, 0 buffer") << 1 << 1 << 0;
630 QTest::newRow("insert 1 at 1, 100 buffer") << 1 << 1 << 100;
631 QTest::newRow("insert 1 at 1, 500 buffer") << 1 << 1 << 500;
633 QTest::newRow("insert multiple at 0, 0 buffer") << 0 << 6 << 0;
634 QTest::newRow("insert multiple at 0, 100 buffer") << 0 << 6 << 100;
635 QTest::newRow("insert multiple at 0, 500 buffer") << 0 << 6 << 500;
637 QTest::newRow("insert multiple at 1, 0 buffer") << 1 << 6 << 0;
638 QTest::newRow("insert multiple at 1, 100 buffer") << 1 << 6 << 100;
639 QTest::newRow("insert multiple at 1, 500 buffer") << 1 << 6 << 500;
642 void tst_QQuickGridView::removed()
644 QQuickView *canvas = createView();
648 for (int i = 0; i < 40; i++)
649 model.addItem("Item" + QString::number(i), "");
651 QQmlContext *ctxt = canvas->rootContext();
652 ctxt->setContextProperty("testModel", &model);
653 ctxt->setContextProperty("testRightToLeft", QVariant(false));
654 ctxt->setContextProperty("testTopToBottom", QVariant(false));
656 canvas->setSource(testFileUrl("gridview1.qml"));
657 qApp->processEvents();
659 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
660 QTRY_VERIFY(gridview != 0);
661 QQuickItem *contentItem = gridview->contentItem();
662 QTRY_VERIFY(contentItem != 0);
663 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
666 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
668 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
669 QTRY_VERIFY(name != 0);
670 QTRY_COMPARE(name->text(), model.name(1));
671 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
672 QTRY_VERIFY(number != 0);
673 QTRY_COMPARE(number->text(), model.number(1));
676 // Checks that onRemove is called
677 QString removed = canvas->rootObject()->property("removed").toString();
678 QTRY_COMPARE(removed, QString("Item1"));
680 // Confirm items positioned correctly
681 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
682 for (int i = 0; i < model.count() && i < itemCount; ++i) {
683 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
684 if (!item) qWarning() << "Item" << i << "not found";
685 QTRY_VERIFY(item->x() == (i%3)*80);
686 QTRY_VERIFY(item->y() == (i/3)*60);
689 // Remove first item (which is the current item);
691 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
693 name = findItem<QQuickText>(contentItem, "textName", 0);
694 QTRY_VERIFY(name != 0);
695 QTRY_COMPARE(name->text(), model.name(0));
696 number = findItem<QQuickText>(contentItem, "textNumber", 0);
697 QTRY_VERIFY(number != 0);
698 QTRY_COMPARE(number->text(), model.number(0));
701 // Confirm items positioned correctly
702 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
703 for (int i = 0; i < model.count() && i < itemCount; ++i) {
704 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
705 if (!item) qWarning() << "Item" << i << "not found";
706 QTRY_VERIFY(item->x() == (i%3)*80);
707 QTRY_VERIFY(item->y() == (i/3)*60);
710 // Remove items not visible
711 model.removeItem(25);
712 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
714 // Confirm items positioned correctly
715 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
716 for (int i = 0; i < model.count() && i < itemCount; ++i) {
717 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
718 if (!item) qWarning() << "Item" << i << "not found";
719 QTRY_VERIFY(item->x() == (i%3)*80);
720 QTRY_VERIFY(item->y() == (i/3)*60);
723 // Remove items before visible
724 gridview->setContentY(120);
725 gridview->setCurrentIndex(10);
727 // Setting currentIndex above shouldn't cause view to scroll
728 QTRY_COMPARE(gridview->contentY(), 120.0);
731 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
733 // Confirm items positioned correctly
734 for (int i = 6; i < 18; ++i) {
735 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
736 if (!item) qWarning() << "Item" << i << "not found";
737 QTRY_VERIFY(item->x() == (i%3)*80);
738 QTRY_VERIFY(item->y() == (i/3)*60);
741 // Remove currentIndex
742 QQuickItem *oldCurrent = gridview->currentItem();
744 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
746 QTRY_COMPARE(gridview->currentIndex(), 9);
747 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
749 gridview->setContentY(0);
750 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
752 // Confirm items positioned correctly
753 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
754 for (int i = 0; i < model.count() && i < itemCount; ++i) {
755 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
756 QTRY_VERIFY(item->x() == (i%3)*80);
757 QTRY_VERIFY(item->y() == (i/3)*60);
760 // remove item outside current view.
761 gridview->setCurrentIndex(32);
762 gridview->setContentY(240);
764 model.removeItem(30);
765 QTRY_VERIFY(gridview->currentIndex() == 31);
767 // remove current item beyond visible items.
768 gridview->setCurrentIndex(20);
769 gridview->setContentY(0);
770 model.removeItem(20);
772 QTRY_COMPARE(gridview->currentIndex(), 20);
773 QTRY_VERIFY(gridview->currentItem() != 0);
775 // remove item before current, but visible
776 gridview->setCurrentIndex(8);
777 gridview->setContentY(240);
778 oldCurrent = gridview->currentItem();
781 QTRY_COMPARE(gridview->currentIndex(), 7);
782 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
787 void tst_QQuickGridView::removed_more()
789 QFETCH(qreal, contentYRowOffset);
790 QFETCH(int, removeIndex);
791 QFETCH(int, removeCount);
792 QFETCH(qreal, rowOffsetAfterMove);
793 QFETCH(QString, firstVisible);
797 QQuickView *canvas = getView();
800 for (int i = 0; i < 30; i++)
801 model.addItem("Item" + QString::number(i), "");
803 QQmlContext *ctxt = canvas->rootContext();
804 ctxt->setContextProperty("testModel", &model);
805 ctxt->setContextProperty("testRightToLeft", QVariant(false));
806 ctxt->setContextProperty("testTopToBottom", QVariant(false));
807 canvas->setSource(testFileUrl("gridview1.qml"));
809 qApp->processEvents();
811 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
812 QTRY_VERIFY(gridview != 0);
813 QQuickItem *contentItem = gridview->contentItem();
814 QTRY_VERIFY(contentItem != 0);
816 gridview->setContentY(contentYRowOffset * 60.0);
817 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
819 model.removeItems(removeIndex, removeCount);
820 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
823 int firstVisibleIndex = -1;
824 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
825 for (int i=0; i<items.count(); i++) {
826 if (items[i]->y() >= gridview->contentY()) {
827 QQmlExpression e(qmlContext(items[i]), items[i], "index");
828 firstVisibleIndex = e.evaluate().toInt();
829 QQmlExpression en(qmlContext(items[i]), items[i], "name");
830 firstName = en.evaluate().toString();
834 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
835 QCOMPARE(firstName, firstVisible);
837 // Confirm items positioned correctly and indexes correct
838 qreal pixelOffset = 60 * rowOffsetAfterMove;
839 for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
840 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
841 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
843 QTRY_COMPARE(item->x(), (i%3)*80.0);
844 QTRY_COMPARE(item->y(), (i/3)*60.0 + pixelOffset);
846 name = findItem<QQuickText>(contentItem, "textName", i);
848 QTRY_COMPARE(name->text(), model.name(i));
849 number = findItem<QQuickText>(contentItem, "textNumber", i);
850 QVERIFY(number != 0);
851 QTRY_COMPARE(number->text(), model.number(i));
857 void tst_QQuickGridView::removed_more_data()
859 QTest::addColumn<qreal>("contentYRowOffset");
860 QTest::addColumn<int>("removeIndex");
861 QTest::addColumn<int>("removeCount");
862 QTest::addColumn<qreal>("rowOffsetAfterMove");
863 QTest::addColumn<QString>("firstVisible");
865 QTest::newRow("remove 1, before visible items")
870 QTest::newRow("remove 1, before visible position")
875 QTest::newRow("remove multiple, all before visible items")
878 << 1.0 << "Item6"; // removed top row, slide down by 1 row
880 QTest::newRow("remove multiple, all before visible items, remove item 0")
883 << 1.0 << "Item7"; // removed top row, slide down by 1 row
885 QTest::newRow("remove multiple rows, all before visible items")
890 QTest::newRow("remove one row before visible, content y not on item border")
893 << 1.0 << "Item6"; // 1 row removed
895 QTest::newRow("remove mix of visible/non-visible")
898 << 1.0 << "Item6"; // 1 row removed
901 // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos,
902 // items 6,7 are removed from view, item 8 slides up to original pos of item 6 (120px)
903 QTest::newRow("remove multiple, mix of items from before and within visible items")
906 << 1.0 << "Item8"; // adjust for the 1 row removed before the visible
908 QTest::newRow("remove multiple, mix of items from before and within visible items, remove item 0")
911 << 1.0 * 2 << "Item8"; // adjust for the 2 rows removed before the visible
914 QTest::newRow("remove 1, from start of visible, content at start")
919 QTest::newRow("remove multiple, from start of visible, content at start")
924 QTest::newRow("remove 1, from start of visible, content not at start")
929 QTest::newRow("remove multiple, from start of visible, content not at start")
935 QTest::newRow("remove 1, from middle of visible, content at start")
940 QTest::newRow("remove multiple, from middle of visible, content at start")
945 QTest::newRow("remove 1, from middle of visible, content not at start")
950 QTest::newRow("remove multiple, from middle of visible, content not at start")
956 QTest::newRow("remove 1, after visible, content at start")
961 QTest::newRow("remove multiple, after visible, content at start")
966 QTest::newRow("remove 1, after visible, content not at start")
971 QTest::newRow("remove multiple, after visible, content not at start")
976 QTest::newRow("remove multiple, mix of items from within and after visible items")
982 void tst_QQuickGridView::addOrRemoveBeforeVisible()
984 // QTBUG-21588: ensure re-layout is done on grid after adding or removing
985 // items from before the visible area
988 QFETCH(qreal, newTopContentY);
990 QQuickView *canvas = getView();
994 for (int i = 0; i < 30; i++)
995 model.addItem("Item" + QString::number(i), "");
997 QQmlContext *ctxt = canvas->rootContext();
998 ctxt->setContextProperty("testModel", &model);
999 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1000 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1001 canvas->setSource(testFileUrl("gridview1.qml"));
1003 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1004 QTRY_VERIFY(gridview != 0);
1005 QQuickItem *contentItem = gridview->contentItem();
1006 QTRY_VERIFY(contentItem != 0);
1008 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
1009 QTRY_COMPARE(name->text(), QString("Item0"));
1011 gridview->setCurrentIndex(0);
1012 qApp->processEvents();
1013 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1015 // scroll down until item 0 is no longer drawn
1016 // (bug not triggered if we just move using content y, since that doesn't
1017 // refill and change the visible items)
1018 gridview->setCurrentIndex(24);
1019 qApp->processEvents();
1021 QTRY_COMPARE(gridview->currentIndex(), 24);
1022 QTRY_COMPARE(gridview->contentY(), 220.0);
1024 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1025 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible
1028 model.insertItem(0, "New Item", "New Item number");
1029 QTRY_COMPARE(gridview->count(), 31);
1031 model.removeItem(0);
1032 QTRY_COMPARE(gridview->count(), 29);
1035 // scroll back up and item 0 should be gone
1036 gridview->setCurrentIndex(0);
1037 qApp->processEvents();
1038 QTRY_COMPARE(gridview->currentIndex(), 0);
1039 QTRY_COMPARE(gridview->contentY(), newTopContentY);
1041 name = findItem<QQuickText>(contentItem, "textName", 0);
1043 QCOMPARE(name->text(), QString("New Item"));
1045 QCOMPARE(name->text(), QString("Item1"));
1047 // Confirm items positioned correctly
1048 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1049 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1050 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i));
1051 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1052 QTRY_VERIFY(item->x() == (i%3)*80);
1053 QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY);
1056 releaseView(canvas);
1059 void tst_QQuickGridView::addOrRemoveBeforeVisible_data()
1061 QTest::addColumn<bool>("doAdd");
1062 QTest::addColumn<qreal>("newTopContentY");
1064 QTest::newRow("add") << true << -60.0;
1065 QTest::newRow("remove") << false << -60.0;
1068 void tst_QQuickGridView::clear()
1070 QQuickView *canvas = createView();
1073 for (int i = 0; i < 30; i++)
1074 model.addItem("Item" + QString::number(i), "");
1076 QQmlContext *ctxt = canvas->rootContext();
1077 ctxt->setContextProperty("testModel", &model);
1078 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1079 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1081 canvas->setSource(testFileUrl("gridview1.qml"));
1083 qApp->processEvents();
1085 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1086 QVERIFY(gridview != 0);
1087 QQuickItem *contentItem = gridview->contentItem();
1088 QVERIFY(contentItem != 0);
1089 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1093 QVERIFY(gridview->count() == 0);
1094 QVERIFY(gridview->currentItem() == 0);
1095 QVERIFY(gridview->contentY() == 0);
1096 QVERIFY(gridview->currentIndex() == -1);
1098 // confirm sanity when adding an item to cleared list
1099 model.addItem("New", "1");
1100 QTRY_COMPARE(gridview->count(), 1);
1101 QVERIFY(gridview->currentItem() != 0);
1102 QVERIFY(gridview->currentIndex() == 0);
1107 void tst_QQuickGridView::moved()
1109 QFETCH(qreal, contentYRowOffset);
1113 QFETCH(qreal, rowOffsetAfterMove);
1117 QQuickView *canvas = getView();
1120 for (int i = 0; i < 30; i++)
1121 model.addItem("Item" + QString::number(i), "");
1123 QQmlContext *ctxt = canvas->rootContext();
1124 ctxt->setContextProperty("testModel", &model);
1125 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1126 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1128 canvas->setSource(testFileUrl("gridview1.qml"));
1130 qApp->processEvents();
1132 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1133 QTRY_VERIFY(gridview != 0);
1134 QQuickItem *contentItem = gridview->contentItem();
1135 QTRY_VERIFY(contentItem != 0);
1136 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1138 QQuickItem *currentItem = gridview->currentItem();
1139 QTRY_VERIFY(currentItem != 0);
1141 if (contentYRowOffset != 0) {
1142 gridview->setContentY(contentYRowOffset * 60.0);
1143 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1146 model.moveItems(from, to, count);
1147 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1149 // Confirm items positioned correctly and indexes correct
1150 int firstVisibleIndex = qCeil(gridview->contentY() / 60.0) * 3;
1151 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1152 qreal pixelOffset = 60 * rowOffsetAfterMove;
1153 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
1154 if (i >= firstVisibleIndex + 18) // index has moved out of view
1156 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1157 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1159 QTRY_COMPARE(item->x(), (i%3)*80.0);
1160 QTRY_COMPARE(item->y(), (i/3)*60.0 + pixelOffset);
1162 name = findItem<QQuickText>(contentItem, "textName", i);
1164 QTRY_COMPARE(name->text(), model.name(i));
1165 number = findItem<QQuickText>(contentItem, "textNumber", i);
1166 QVERIFY(number != 0);
1167 QTRY_COMPARE(number->text(), model.number(i));
1169 // current index should have been updated
1170 if (item == currentItem)
1171 QTRY_COMPARE(gridview->currentIndex(), i);
1174 releaseView(canvas);
1177 void tst_QQuickGridView::moved_data()
1179 QTest::addColumn<qreal>("contentYRowOffset");
1180 QTest::addColumn<int>("from");
1181 QTest::addColumn<int>("to");
1182 QTest::addColumn<int>("count");
1183 QTest::addColumn<qreal>("rowOffsetAfterMove");
1185 // model starts with 30 items, each 80x60, in area 240x320
1186 // 18 items should be visible at a time
1188 // The first visible item should not move upwards and out of the view
1189 // if items are moved/removed before it.
1192 QTest::newRow("move 1 forwards, within visible items")
1197 QTest::newRow("move 1 forwards, from non-visible -> visible")
1202 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
1203 << 2.0 // // show 6-23
1207 QTest::newRow("move 1 forwards, from visible -> non-visible")
1212 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
1218 QTest::newRow("move 1 backwards, within visible items")
1223 QTest::newRow("move 1 backwards, within visible items (to first index)")
1228 QTest::newRow("move 1 backwards, from non-visible -> visible")
1233 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
1238 QTest::newRow("move 1 backwards, from visible -> non-visible")
1241 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1243 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
1246 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1249 QTest::newRow("move multiple forwards, within visible items")
1254 QTest::newRow("move multiple backwards, within visible items (move first item)")
1259 QTest::newRow("move multiple forwards, before visible items")
1261 << 3 << 4 << 3 // 3, 4, 5 move to after 6
1262 << 1.0; // row of 3,4,5 has moved down
1264 QTest::newRow("move multiple forwards, from non-visible -> visible")
1267 << 1.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
1269 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
1272 << 1.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
1274 QTest::newRow("move multiple forwards, mix of non-visible/visible")
1277 << 1.0; // top two rows removed, third row is now the first visible
1279 QTest::newRow("move multiple forwards, to bottom of view")
1284 QTest::newRow("move multiple forwards, to bottom of view, first row -> last")
1289 QTest::newRow("move multiple forwards, to bottom of view, content y not 0")
1294 QTest::newRow("move multiple forwards, from visible -> non-visible")
1299 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
1305 QTest::newRow("move multiple backwards, within visible items")
1310 QTest::newRow("move multiple backwards, from non-visible -> visible")
1315 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
1320 QTest::newRow("move multiple backwards, from visible -> non-visible")
1323 << -1.0; // to minimize movement, items are added above visible area, all items move up by 1 row
1325 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
1328 << -1.0; // 16,17,18 move to above item 0, all items move up by 1 row
1331 void tst_QQuickGridView::multipleChanges(bool condensed)
1333 QFETCH(int, startCount);
1334 QFETCH(QList<ListChange>, changes);
1335 QFETCH(int, newCount);
1336 QFETCH(int, newCurrentIndex);
1338 QQuickView *canvas = getView();
1341 for (int i = 0; i < startCount; i++)
1342 model.addItem("Item" + QString::number(i), "");
1344 QQmlContext *ctxt = canvas->rootContext();
1345 ctxt->setContextProperty("testModel", &model);
1346 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1347 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1349 canvas->setSource(testFileUrl("gridview1.qml"));
1351 qApp->processEvents();
1353 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1354 QTRY_VERIFY(gridview != 0);
1355 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1357 for (int i=0; i<changes.count(); i++) {
1358 switch (changes[i].type) {
1359 case ListChange::Inserted:
1361 QList<QPair<QString, QString> > items;
1362 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1363 items << qMakePair(QString("new item " + j), QString::number(j));
1364 model.insertItems(changes[i].index, items);
1367 case ListChange::Removed:
1368 model.removeItems(changes[i].index, changes[i].count);
1370 case ListChange::Moved:
1371 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1373 case ListChange::SetCurrent:
1374 gridview->setCurrentIndex(changes[i].index);
1376 case ListChange::SetContentY:
1377 gridview->setContentY(changes[i].pos);
1381 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1384 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1386 QCOMPARE(gridview->count(), newCount);
1387 QCOMPARE(gridview->count(), model.count());
1388 QCOMPARE(gridview->currentIndex(), newCurrentIndex);
1392 QQuickItem *contentItem = gridview->contentItem();
1393 QTRY_VERIFY(contentItem != 0);
1394 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1395 for (int i=0; i < model.count() && i < itemCount; ++i) {
1396 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1397 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1398 name = findItem<QQuickText>(contentItem, "textName", i);
1400 QTRY_COMPARE(name->text(), model.name(i));
1401 number = findItem<QQuickText>(contentItem, "textNumber", i);
1402 QVERIFY(number != 0);
1403 QTRY_COMPARE(number->text(), model.number(i));
1406 releaseView(canvas);
1409 void tst_QQuickGridView::multipleChanges_data()
1411 QTest::addColumn<int>("startCount");
1412 QTest::addColumn<QList<ListChange> >("changes");
1413 QTest::addColumn<int>("newCount");
1414 QTest::addColumn<int>("newCurrentIndex");
1416 QList<ListChange> changes;
1418 for (int i=1; i<30; i++)
1419 changes << ListChange::remove(0);
1420 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1422 changes << ListChange::remove(0);
1423 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1426 changes << ListChange::setCurrent(29);
1427 for (int i=29; i>0; i--)
1428 changes << ListChange::remove(i);
1429 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1431 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1432 << ListChange::remove(0, 1)
1433 << ListChange::insert(0, 1)
1436 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1437 << ListChange::setCurrent(2)
1438 << ListChange::remove(2, 1)
1439 << ListChange::insert(2, 1)
1442 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1443 << ListChange::setCurrent(1)
1444 << ListChange::remove(1, 3)
1445 << ListChange::insert(2, 2)
1448 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1449 << ListChange::setCurrent(2)
1450 << ListChange::remove(1, 3)
1451 << ListChange::move(1, 5, 1)
1454 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1455 << ListChange::setCurrent(5)
1456 << ListChange::remove(4, 3)
1457 << ListChange::move(4, 1, 1)
1461 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1462 << ListChange::insert(0, 2)
1463 << ListChange::insert(0, 4)
1464 << ListChange::insert(0, 6)
1467 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1468 << ListChange::insert(0, 2)
1469 << ListChange::insert(0, 4)
1470 << ListChange::insert(0, 6)
1471 << ListChange::setCurrent(3)
1472 << ListChange::insert(3, 2)
1475 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1476 << ListChange::insert(0, 30)
1477 << ListChange::remove(0, 30)
1480 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1481 << ListChange::insert(1)
1482 << ListChange::setCurrent(1)
1483 << ListChange::remove(1)
1486 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1487 << ListChange::insert(0, 10)
1488 << ListChange::remove(5, 10)
1491 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1492 << ListChange::insert(0, 3)
1493 << ListChange::move(0, 10, 3)
1496 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1497 << ListChange::insert(0, 3)
1498 << ListChange::move(0, 8, 5)
1501 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1502 << ListChange::setCurrent(9)
1503 << ListChange::insert(10, 3)
1504 << ListChange::move(8, 0, 5)
1508 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1509 << ListChange::setCurrent(1)
1510 << ListChange::move(1, 2, 2)
1511 << ListChange::move(2, 1, 2)
1514 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1515 << ListChange::setCurrent(2)
1516 << ListChange::move(1, 2, 3)
1517 << ListChange::move(3, 0, 5)
1520 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1521 << ListChange::setCurrent(5)
1522 << ListChange::move(5, 0, 1)
1523 << ListChange::remove(0)
1526 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1527 << ListChange::setCurrent(5)
1528 << ListChange::move(5, 0, 1)
1529 << ListChange::insert(0)
1532 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1533 << ListChange::setCurrent(1)
1534 << ListChange::move(5, 1, 3)
1535 << ListChange::remove(1, 3)
1538 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1539 << ListChange::setCurrent(5)
1540 << ListChange::move(5, 1, 3)
1541 << ListChange::insert(1, 5)
1544 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1545 << ListChange::setCurrent(3)
1546 << ListChange::move(0, 1, 2)
1547 << ListChange::insert(3, 5)
1551 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1552 << ListChange::insert(0, 5)
1553 << ListChange::setCurrent(-1)
1554 << ListChange::remove(0, 5)
1555 << ListChange::insert(0, 5)
1558 QTest::newRow("remove, scroll") << 30 << (QList<ListChange>()
1559 << ListChange::remove(20, 5)
1560 << ListChange::setContentY(20)
1563 QTest::newRow("insert, scroll") << 10 << (QList<ListChange>()
1564 << ListChange::insert(9, 5)
1565 << ListChange::setContentY(20)
1568 QTest::newRow("move, scroll") << 20 << (QList<ListChange>()
1569 << ListChange::move(15, 8, 3)
1570 << ListChange::setContentY(0)
1573 QTest::newRow("clear, insert, scroll") << 30 << (QList<ListChange>()
1574 << ListChange::setContentY(20)
1575 << ListChange::remove(0, 30)
1576 << ListChange::insert(0, 2)
1577 << ListChange::setContentY(0)
1582 void tst_QQuickGridView::swapWithFirstItem()
1585 QQuickView *canvas = createView();
1588 for (int i = 0; i < 30; i++)
1589 model.addItem("Item" + QString::number(i), "");
1591 QQmlContext *ctxt = canvas->rootContext();
1592 ctxt->setContextProperty("testModel", &model);
1593 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1594 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1596 canvas->setSource(testFileUrl("gridview1.qml"));
1598 qApp->processEvents();
1600 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1601 QTRY_VERIFY(gridview != 0);
1603 // ensure content position is stable
1604 gridview->setContentY(0);
1605 model.moveItem(10, 0);
1606 QTRY_VERIFY(gridview->contentY() == 0);
1611 void tst_QQuickGridView::currentIndex()
1614 for (int i = 0; i < 60; i++)
1615 model.addItem("Item" + QString::number(i), QString::number(i));
1617 QQuickView *canvas = new QQuickView(0);
1618 canvas->setGeometry(0,0,240,320);
1621 QQmlContext *ctxt = canvas->rootContext();
1622 ctxt->setContextProperty("testModel", &model);
1624 QString filename(testFile("gridview-initCurrent.qml"));
1625 canvas->setSource(QUrl::fromLocalFile(filename));
1627 qApp->processEvents();
1629 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1630 QVERIFY(gridview != 0);
1631 QTRY_VERIFY(!QQuickItemPrivate::get(gridview)->polishScheduled);
1633 QQuickItem *contentItem = gridview->contentItem();
1634 QVERIFY(contentItem != 0);
1636 // current item should be third item
1637 QCOMPARE(gridview->currentIndex(), 35);
1638 QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35));
1639 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1640 QCOMPARE(gridview->contentY(), 400.0);
1642 gridview->moveCurrentIndexRight();
1643 QCOMPARE(gridview->currentIndex(), 36);
1644 gridview->moveCurrentIndexDown();
1645 QCOMPARE(gridview->currentIndex(), 39);
1646 gridview->moveCurrentIndexUp();
1647 QCOMPARE(gridview->currentIndex(), 36);
1648 gridview->moveCurrentIndexLeft();
1649 QCOMPARE(gridview->currentIndex(), 35);
1651 // wait until motion stops
1652 QTRY_VERIFY(gridview->verticalVelocity() == 0.0);
1655 gridview->setCurrentIndex(0);
1656 QCOMPARE(gridview->currentIndex(), 0);
1657 // confirm that the velocity is updated
1658 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1660 gridview->moveCurrentIndexUp();
1661 QCOMPARE(gridview->currentIndex(), 0);
1663 gridview->moveCurrentIndexLeft();
1664 QCOMPARE(gridview->currentIndex(), 0);
1666 gridview->setCurrentIndex(model.count()-1);
1667 QCOMPARE(gridview->currentIndex(), model.count()-1);
1669 gridview->moveCurrentIndexRight();
1670 QCOMPARE(gridview->currentIndex(), model.count()-1);
1672 gridview->moveCurrentIndexDown();
1673 QCOMPARE(gridview->currentIndex(), model.count()-1);
1676 gridview->setWrapEnabled(true);
1678 gridview->setCurrentIndex(0);
1679 QCOMPARE(gridview->currentIndex(), 0);
1681 gridview->moveCurrentIndexLeft();
1682 QCOMPARE(gridview->currentIndex(), model.count()-1);
1684 qApp->processEvents();
1685 QTRY_COMPARE(gridview->contentY(), 880.0);
1687 gridview->moveCurrentIndexRight();
1688 QCOMPARE(gridview->currentIndex(), 0);
1690 QTRY_COMPARE(gridview->contentY(), 0.0);
1693 // footer should become visible if it is out of view, and then current index moves to the first row
1694 canvas->rootObject()->setProperty("showFooter", true);
1695 QTRY_VERIFY(gridview->footerItem());
1696 gridview->setCurrentIndex(model.count()-3);
1697 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1698 gridview->setCurrentIndex(model.count()-2);
1699 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1700 canvas->rootObject()->setProperty("showFooter", false);
1702 // header should become visible if it is out of view, and then current index moves to the last row
1703 canvas->rootObject()->setProperty("showHeader", true);
1704 QTRY_VERIFY(gridview->headerItem());
1705 gridview->setCurrentIndex(3);
1706 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1707 gridview->setCurrentIndex(1);
1708 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1709 canvas->rootObject()->setProperty("showHeader", false);
1713 canvas->requestActivateWindow();
1714 QTest::qWaitForWindowShown(canvas);
1715 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1717 gridview->setCurrentIndex(0);
1719 QTest::keyClick(canvas, Qt::Key_Down);
1720 QCOMPARE(gridview->currentIndex(), 3);
1722 QTest::keyClick(canvas, Qt::Key_Up);
1723 QCOMPARE(gridview->currentIndex(), 0);
1725 // hold down Key_Down
1726 for (int i=0; i<(model.count() / 3) - 1; i++) {
1727 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1728 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1730 QTest::keyRelease(canvas, Qt::Key_Down);
1731 QTRY_COMPARE(gridview->currentIndex(), 57);
1732 QTRY_COMPARE(gridview->contentY(), 880.0);
1735 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1736 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1737 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1739 QTest::keyRelease(canvas, Qt::Key_Up);
1740 QTRY_COMPARE(gridview->currentIndex(), 0);
1741 QTRY_COMPARE(gridview->contentY(), 0.0);
1744 gridview->setFlow(QQuickGridView::TopToBottom);
1746 canvas->requestActivateWindow();
1747 QTest::qWaitForWindowShown(canvas);
1748 QVERIFY(qGuiApp->focusWindow() == canvas);
1749 qApp->processEvents();
1751 QTest::keyClick(canvas, Qt::Key_Right);
1752 QCOMPARE(gridview->currentIndex(), 5);
1754 QTest::keyClick(canvas, Qt::Key_Left);
1755 QCOMPARE(gridview->currentIndex(), 0);
1757 QTest::keyClick(canvas, Qt::Key_Down);
1758 QCOMPARE(gridview->currentIndex(), 1);
1760 QTest::keyClick(canvas, Qt::Key_Up);
1761 QCOMPARE(gridview->currentIndex(), 0);
1763 // hold down Key_Right
1764 for (int i=0; i<(model.count() / 5) - 1; i++) {
1765 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1766 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1769 QTest::keyRelease(canvas, Qt::Key_Right);
1770 QTRY_COMPARE(gridview->currentIndex(), 55);
1771 QTRY_COMPARE(gridview->contentX(), 720.0);
1773 // hold down Key_Left
1774 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1775 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1776 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1778 QTest::keyRelease(canvas, Qt::Key_Left);
1779 QTRY_COMPARE(gridview->currentIndex(), 0);
1780 QTRY_COMPARE(gridview->contentX(), 0.0);
1783 // turn off auto highlight
1784 gridview->setHighlightFollowsCurrentItem(false);
1785 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1786 QVERIFY(gridview->highlightItem());
1787 qreal hlPosX = gridview->highlightItem()->x();
1788 qreal hlPosY = gridview->highlightItem()->y();
1790 gridview->setCurrentIndex(5);
1791 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1792 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1794 // insert item before currentIndex
1795 gridview->setCurrentIndex(28);
1796 model.insertItem(0, "Foo", "1111");
1797 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1799 // check removing highlight by setting currentIndex to -1;
1800 gridview->setCurrentIndex(-1);
1802 QCOMPARE(gridview->currentIndex(), -1);
1803 QVERIFY(!gridview->highlightItem());
1804 QVERIFY(!gridview->currentItem());
1806 gridview->setHighlightFollowsCurrentItem(true);
1808 gridview->setFlow(QQuickGridView::LeftToRight);
1809 gridview->setLayoutDirection(Qt::RightToLeft);
1811 canvas->requestActivateWindow();
1812 QTest::qWaitForWindowShown(canvas);
1813 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1814 qApp->processEvents();
1816 gridview->setCurrentIndex(35);
1818 QTest::keyClick(canvas, Qt::Key_Right);
1819 QCOMPARE(gridview->currentIndex(), 34);
1821 QTest::keyClick(canvas, Qt::Key_Down);
1822 QCOMPARE(gridview->currentIndex(), 37);
1824 QTest::keyClick(canvas, Qt::Key_Up);
1825 QCOMPARE(gridview->currentIndex(), 34);
1827 QTest::keyClick(canvas, Qt::Key_Left);
1828 QCOMPARE(gridview->currentIndex(), 35);
1831 // turn off auto highlight
1832 gridview->setHighlightFollowsCurrentItem(false);
1833 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1834 QVERIFY(gridview->highlightItem());
1835 hlPosX = gridview->highlightItem()->x();
1836 hlPosY = gridview->highlightItem()->y();
1838 gridview->setCurrentIndex(5);
1839 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1840 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1842 // insert item before currentIndex
1843 gridview->setCurrentIndex(28);
1844 model.insertItem(0, "Foo", "1111");
1845 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1847 // check removing highlight by setting currentIndex to -1;
1848 gridview->setCurrentIndex(-1);
1850 QCOMPARE(gridview->currentIndex(), -1);
1851 QVERIFY(!gridview->highlightItem());
1852 QVERIFY(!gridview->currentItem());
1854 // moving currentItem out of view should make it invisible
1855 gridview->setCurrentIndex(0);
1856 QTRY_VERIFY(gridview->currentItem()->isVisible());
1857 gridview->setContentY(200);
1858 QTRY_VERIFY(!gridview->currentItem()->isVisible());
1863 void tst_QQuickGridView::noCurrentIndex()
1866 for (int i = 0; i < 60; i++)
1867 model.addItem("Item" + QString::number(i), QString::number(i));
1869 QQuickView *canvas = new QQuickView(0);
1870 canvas->setGeometry(0,0,240,320);
1872 QQmlContext *ctxt = canvas->rootContext();
1873 ctxt->setContextProperty("testModel", &model);
1875 QString filename(testFile("gridview-noCurrent.qml"));
1876 canvas->setSource(QUrl::fromLocalFile(filename));
1878 qApp->processEvents();
1880 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1881 QVERIFY(gridview != 0);
1882 QQuickItem *contentItem = gridview->contentItem();
1883 QVERIFY(contentItem != 0);
1884 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1886 // current index should be -1
1887 QCOMPARE(gridview->currentIndex(), -1);
1888 QVERIFY(!gridview->currentItem());
1889 QVERIFY(!gridview->highlightItem());
1890 QCOMPARE(gridview->contentY(), 0.0);
1892 gridview->setCurrentIndex(5);
1893 QCOMPARE(gridview->currentIndex(), 5);
1894 QVERIFY(gridview->currentItem());
1895 QVERIFY(gridview->highlightItem());
1900 void tst_QQuickGridView::changeFlow()
1902 QQuickView *canvas = createView();
1905 for (int i = 0; i < 30; i++)
1906 model.addItem("Item" + QString::number(i), QString::number(i));
1908 QQmlContext *ctxt = canvas->rootContext();
1909 ctxt->setContextProperty("testModel", &model);
1910 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1911 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1913 canvas->setSource(testFileUrl("gridview1.qml"));
1914 qApp->processEvents();
1916 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1917 QTRY_VERIFY(gridview != 0);
1919 QQuickItem *contentItem = gridview->contentItem();
1920 QTRY_VERIFY(contentItem != 0);
1922 // Confirm items positioned correctly and indexes correct
1923 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1924 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1925 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1926 if (!item) qWarning() << "Item" << i << "not found";
1928 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1929 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1930 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1931 QTRY_VERIFY(name != 0);
1932 QTRY_COMPARE(name->text(), model.name(i));
1933 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1934 QTRY_VERIFY(number != 0);
1935 QTRY_COMPARE(number->text(), model.number(i));
1938 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1940 // Confirm items positioned correctly and indexes correct
1941 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1942 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1943 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1944 if (!item) qWarning() << "Item" << i << "not found";
1946 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1947 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1948 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1949 QTRY_VERIFY(name != 0);
1950 QTRY_COMPARE(name->text(), model.name(i));
1951 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1952 QTRY_VERIFY(number != 0);
1953 QTRY_COMPARE(number->text(), model.number(i));
1956 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1958 // Confirm items positioned correctly and indexes correct
1959 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1960 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1961 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1962 if (!item) qWarning() << "Item" << i << "not found";
1964 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1965 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1966 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1967 QTRY_VERIFY(name != 0);
1968 QTRY_COMPARE(name->text(), model.name(i));
1969 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1970 QTRY_VERIFY(number != 0);
1971 QTRY_COMPARE(number->text(), model.number(i));
1973 gridview->setContentX(100);
1974 QTRY_COMPARE(gridview->contentX(), 100.);
1975 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1976 QTRY_COMPARE(gridview->contentX(), 0.);
1978 // Confirm items positioned correctly and indexes correct
1979 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1980 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1981 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1982 if (!item) qWarning() << "Item" << i << "not found";
1984 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1985 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1986 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1987 QTRY_VERIFY(name != 0);
1988 QTRY_COMPARE(name->text(), model.name(i));
1989 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1990 QTRY_VERIFY(number != 0);
1991 QTRY_COMPARE(number->text(), model.number(i));
1997 void tst_QQuickGridView::defaultValues()
2000 QQmlComponent c(&engine, testFileUrl("gridview3.qml"));
2001 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
2003 QTRY_VERIFY(obj != 0);
2004 QTRY_VERIFY(obj->model() == QVariant());
2005 QTRY_VERIFY(obj->delegate() == 0);
2006 QTRY_COMPARE(obj->currentIndex(), -1);
2007 QTRY_VERIFY(obj->currentItem() == 0);
2008 QTRY_COMPARE(obj->count(), 0);
2009 QTRY_VERIFY(obj->highlight() == 0);
2010 QTRY_VERIFY(obj->highlightItem() == 0);
2011 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
2012 QTRY_VERIFY(obj->flow() == 0);
2013 QTRY_COMPARE(obj->isWrapEnabled(), false);
2014 QTRY_COMPARE(obj->cacheBuffer(), 0);
2015 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
2016 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2020 void tst_QQuickGridView::properties()
2023 QQmlComponent c(&engine, testFileUrl("gridview2.qml"));
2024 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
2026 QTRY_VERIFY(obj != 0);
2027 QTRY_VERIFY(obj->model() != QVariant());
2028 QTRY_VERIFY(obj->delegate() != 0);
2029 QTRY_COMPARE(obj->currentIndex(), 0);
2030 QTRY_VERIFY(obj->currentItem() != 0);
2031 QTRY_COMPARE(obj->count(), 4);
2032 QTRY_VERIFY(obj->highlight() != 0);
2033 QTRY_VERIFY(obj->highlightItem() != 0);
2034 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
2035 QTRY_VERIFY(obj->flow() == 0);
2036 QTRY_COMPARE(obj->isWrapEnabled(), true);
2037 QTRY_COMPARE(obj->cacheBuffer(), 200);
2038 QTRY_COMPARE(obj->cellWidth(), qreal(100));
2039 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2043 void tst_QQuickGridView::propertyChanges()
2045 QQuickView *canvas = createView();
2046 QTRY_VERIFY(canvas);
2047 canvas->setSource(testFileUrl("propertychangestest.qml"));
2049 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2050 QTRY_VERIFY(gridView);
2052 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
2053 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
2054 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
2055 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
2057 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2058 QTRY_COMPARE(gridView->cacheBuffer(), 10);
2059 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
2061 gridView->setWrapEnabled(false);
2062 gridView->setCacheBuffer(3);
2063 gridView->setFlow(QQuickGridView::TopToBottom);
2065 QTRY_COMPARE(gridView->isWrapEnabled(), false);
2066 QTRY_COMPARE(gridView->cacheBuffer(), 3);
2067 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
2069 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2070 QTRY_COMPARE(cacheBufferSpy.count(),1);
2071 QTRY_COMPARE(flowSpy.count(),1);
2073 gridView->setWrapEnabled(false);
2074 gridView->setCacheBuffer(3);
2075 gridView->setFlow(QQuickGridView::TopToBottom);
2077 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2078 QTRY_COMPARE(cacheBufferSpy.count(),1);
2079 QTRY_COMPARE(flowSpy.count(),1);
2081 gridView->setFlow(QQuickGridView::LeftToRight);
2082 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
2084 gridView->setWrapEnabled(true);
2085 gridView->setCacheBuffer(5);
2086 gridView->setLayoutDirection(Qt::RightToLeft);
2088 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2089 QTRY_COMPARE(gridView->cacheBuffer(), 5);
2090 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
2092 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2093 QTRY_COMPARE(cacheBufferSpy.count(),2);
2094 QTRY_COMPARE(layoutSpy.count(),1);
2095 QTRY_COMPARE(flowSpy.count(),2);
2097 gridView->setWrapEnabled(true);
2098 gridView->setCacheBuffer(5);
2099 gridView->setLayoutDirection(Qt::RightToLeft);
2101 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2102 QTRY_COMPARE(cacheBufferSpy.count(),2);
2103 QTRY_COMPARE(layoutSpy.count(),1);
2104 QTRY_COMPARE(flowSpy.count(),2);
2106 gridView->setFlow(QQuickGridView::TopToBottom);
2107 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
2108 QTRY_COMPARE(flowSpy.count(),3);
2110 gridView->setFlow(QQuickGridView::TopToBottom);
2111 QTRY_COMPARE(flowSpy.count(),3);
2116 void tst_QQuickGridView::componentChanges()
2118 QQuickView *canvas = createView();
2119 QTRY_VERIFY(canvas);
2120 canvas->setSource(testFileUrl("propertychangestest.qml"));
2122 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2123 QTRY_VERIFY(gridView);
2125 QQmlComponent component(canvas->engine());
2126 component.setData("import QtQuick 2.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
2128 QQmlComponent delegateComponent(canvas->engine());
2129 delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
2131 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
2132 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
2133 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
2134 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
2135 QSignalSpy headerItemSpy(gridView, SIGNAL(headerItemChanged()));
2136 QSignalSpy footerItemSpy(gridView, SIGNAL(footerItemChanged()));
2138 gridView->setHighlight(&component);
2139 gridView->setDelegate(&delegateComponent);
2140 gridView->setHeader(&component);
2141 gridView->setFooter(&component);
2143 QTRY_COMPARE(gridView->highlight(), &component);
2144 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
2145 QTRY_COMPARE(gridView->header(), &component);
2146 QTRY_COMPARE(gridView->footer(), &component);
2148 QVERIFY(gridView->headerItem());
2149 QVERIFY(gridView->footerItem());
2151 QTRY_COMPARE(highlightSpy.count(),1);
2152 QTRY_COMPARE(delegateSpy.count(),1);
2153 QTRY_COMPARE(headerSpy.count(),1);
2154 QTRY_COMPARE(footerSpy.count(),1);
2155 QTRY_COMPARE(headerItemSpy.count(),1);
2156 QTRY_COMPARE(footerItemSpy.count(),1);
2158 gridView->setHighlight(&component);
2159 gridView->setDelegate(&delegateComponent);
2160 gridView->setHeader(&component);
2161 gridView->setFooter(&component);
2163 QTRY_COMPARE(highlightSpy.count(),1);
2164 QTRY_COMPARE(delegateSpy.count(),1);
2165 QTRY_COMPARE(headerSpy.count(),1);
2166 QTRY_COMPARE(footerSpy.count(),1);
2167 QTRY_COMPARE(headerItemSpy.count(),1);
2168 QTRY_COMPARE(footerItemSpy.count(),1);
2173 void tst_QQuickGridView::modelChanges()
2175 QQuickView *canvas = createView();
2176 QTRY_VERIFY(canvas);
2177 canvas->setSource(testFileUrl("propertychangestest.qml"));
2179 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
2180 QTRY_VERIFY(gridView);
2182 QQuickListModel *alternateModel = canvas->rootObject()->findChild<QQuickListModel*>("alternateModel");
2183 QTRY_VERIFY(alternateModel);
2184 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
2185 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
2187 gridView->setModel(modelVariant);
2188 QTRY_COMPARE(gridView->model(), modelVariant);
2189 QTRY_COMPARE(modelSpy.count(),1);
2191 gridView->setModel(modelVariant);
2192 QTRY_COMPARE(modelSpy.count(),1);
2194 gridView->setModel(QVariant());
2195 QTRY_COMPARE(modelSpy.count(),2);
2199 void tst_QQuickGridView::positionViewAtIndex()
2201 QQuickView *canvas = createView();
2204 for (int i = 0; i < 40; i++)
2205 model.addItem("Item" + QString::number(i), "");
2207 QQmlContext *ctxt = canvas->rootContext();
2208 ctxt->setContextProperty("testModel", &model);
2209 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2210 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2212 canvas->setSource(testFileUrl("gridview1.qml"));
2214 qApp->processEvents();
2216 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2217 QTRY_VERIFY(gridview != 0);
2218 QQuickItem *contentItem = gridview->contentItem();
2219 QTRY_VERIFY(contentItem != 0);
2220 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2222 // Confirm items positioned correctly
2223 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2224 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2225 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2226 if (!item) qWarning() << "Item" << i << "not found";
2228 QTRY_COMPARE(item->x(), (i%3)*80.);
2229 QTRY_COMPARE(item->y(), (i/3)*60.);
2232 // Position on a currently visible item
2233 gridview->positionViewAtIndex(4, QQuickGridView::Beginning);
2234 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
2235 QTRY_COMPARE(gridview->contentY(), 60.);
2237 // Confirm items positioned correctly
2238 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2239 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2240 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2241 if (!item) qWarning() << "Item" << i << "not found";
2243 QTRY_COMPARE(item->x(), (i%3)*80.);
2244 QTRY_COMPARE(item->y(), (i/3)*60.);
2247 // Position on an item beyond the visible items
2248 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2249 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
2250 QTRY_COMPARE(gridview->contentY(), 420.);
2252 // Confirm items positioned correctly
2253 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2254 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2255 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2256 if (!item) qWarning() << "Item" << i << "not found";
2258 QTRY_COMPARE(item->x(), (i%3)*80.);
2259 QTRY_COMPARE(item->y(), (i/3)*60.);
2262 // Position on an item that would leave empty space if positioned at the top
2263 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2264 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
2265 QTRY_COMPARE(gridview->contentY(), 520.);
2267 // Confirm items positioned correctly
2268 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2269 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2270 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2271 if (!item) qWarning() << "Item" << i << "not found";
2273 QTRY_COMPARE(item->x(), (i%3)*80.);
2274 QTRY_COMPARE(item->y(), (i/3)*60.);
2277 // Position at the beginning again
2278 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2279 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
2280 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
2281 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
2282 QTRY_COMPARE(gridview->contentY(), 0.);
2284 // Confirm items positioned correctly
2285 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2286 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2287 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2288 if (!item) qWarning() << "Item" << i << "not found";
2290 QTRY_COMPARE(item->x(), (i%3)*80.);
2291 QTRY_COMPARE(item->y(), (i/3)*60.);
2295 gridview->positionViewAtIndex(30, QQuickGridView::End);
2296 QTRY_COMPARE(gridview->contentY(), 340.);
2298 // Position in Center
2299 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2300 QTRY_COMPARE(gridview->contentY(), 170.);
2302 // Ensure at least partially visible
2303 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2304 QTRY_COMPARE(gridview->contentY(), 170.);
2306 gridview->setContentY(302);
2307 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2308 QTRY_COMPARE(gridview->contentY(), 302.);
2310 gridview->setContentY(360);
2311 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2312 QTRY_COMPARE(gridview->contentY(), 300.);
2314 gridview->setContentY(60);
2315 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2316 QTRY_COMPARE(gridview->contentY(), 60.);
2318 gridview->setContentY(20);
2319 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2320 QTRY_COMPARE(gridview->contentY(), 100.);
2322 // Ensure completely visible
2323 gridview->setContentY(120);
2324 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2325 QTRY_COMPARE(gridview->contentY(), 120.);
2327 gridview->setContentY(302);
2328 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2329 QTRY_COMPARE(gridview->contentY(), 300.);
2331 gridview->setContentY(60);
2332 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2333 QTRY_COMPARE(gridview->contentY(), 100.);
2335 // Test for Top To Bottom layout
2336 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2338 // Confirm items positioned correctly
2339 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2340 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2341 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2342 if (!item) qWarning() << "Item" << i << "not found";
2344 QTRY_COMPARE(item->x(), (i/5)*80.);
2345 QTRY_COMPARE(item->y(), (i%5)*60.);
2349 gridview->positionViewAtIndex(30, QQuickGridView::End);
2350 QTRY_COMPARE(gridview->contentX(), 320.);
2351 QTRY_COMPARE(gridview->contentY(), 0.);
2353 // Position in Center
2354 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2355 QTRY_COMPARE(gridview->contentX(), 160.);
2357 // Ensure at least partially visible
2358 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2359 QTRY_COMPARE(gridview->contentX(), 160.);
2361 gridview->setContentX(170);
2362 gridview->positionViewAtIndex(25, QQuickGridView::Visible);
2363 QTRY_COMPARE(gridview->contentX(), 170.);
2365 gridview->positionViewAtIndex(30, QQuickGridView::Visible);
2366 QTRY_COMPARE(gridview->contentX(), 320.);
2368 gridview->setContentX(170);
2369 gridview->positionViewAtIndex(25, QQuickGridView::Contain);
2370 QTRY_COMPARE(gridview->contentX(), 240.);
2372 // positionViewAtBeginning
2373 gridview->positionViewAtBeginning();
2374 QTRY_COMPARE(gridview->contentX(), 0.);
2376 gridview->setContentX(80);
2377 canvas->rootObject()->setProperty("showHeader", true);
2378 gridview->positionViewAtBeginning();
2379 QTRY_COMPARE(gridview->contentX(), -30.);
2381 // positionViewAtEnd
2382 gridview->positionViewAtEnd();
2383 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
2385 gridview->setContentX(80);
2386 canvas->rootObject()->setProperty("showFooter", true);
2387 gridview->positionViewAtEnd();
2388 QTRY_COMPARE(gridview->contentX(), 430.);
2390 // set current item to outside visible view, position at beginning
2391 // and ensure highlight moves to current item
2392 gridview->setCurrentIndex(6);
2393 gridview->positionViewAtBeginning();
2394 QTRY_COMPARE(gridview->contentX(), -30.);
2395 QVERIFY(gridview->highlightItem());
2396 QCOMPARE(gridview->highlightItem()->x(), 80.);
2401 void tst_QQuickGridView::snapping()
2403 QQuickView *canvas = createView();
2406 for (int i = 0; i < 40; i++)
2407 model.addItem("Item" + QString::number(i), "");
2409 QQmlContext *ctxt = canvas->rootContext();
2410 ctxt->setContextProperty("testModel", &model);
2411 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2412 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2414 canvas->setSource(testFileUrl("gridview1.qml"));
2415 qApp->processEvents();
2417 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2418 QTRY_VERIFY(gridview != 0);
2420 gridview->setHeight(220);
2421 QCOMPARE(gridview->height(), 220.);
2423 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2424 QCOMPARE(gridview->contentY(), 80.);
2426 gridview->setContentY(0);
2427 QCOMPARE(gridview->contentY(), 0.);
2429 gridview->setSnapMode(QQuickGridView::SnapToRow);
2430 QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow);
2432 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2433 QCOMPARE(gridview->contentY(), 60.);
2435 gridview->positionViewAtIndex(15, QQuickGridView::End);
2436 QCOMPARE(gridview->contentY(), 120.);
2442 void tst_QQuickGridView::mirroring()
2444 QQuickView *canvasA = createView();
2445 canvasA->setSource(testFileUrl("mirroring.qml"));
2446 QQuickGridView *gridviewA = findItem<QQuickGridView>(canvasA->rootObject(), "view");
2447 QTRY_VERIFY(gridviewA != 0);
2449 QQuickView *canvasB = createView();
2450 canvasB->setSource(testFileUrl("mirroring.qml"));
2451 QQuickGridView *gridviewB = findItem<QQuickGridView>(canvasB->rootObject(), "view");
2452 QTRY_VERIFY(gridviewA != 0);
2453 qApp->processEvents();
2455 QList<QString> objectNames;
2456 objectNames << "item1" << "item2"; // << "item3"
2458 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2459 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2460 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2463 foreach (const QString objectName, objectNames)
2464 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2466 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2467 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2470 foreach (const QString objectName, objectNames)
2471 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2473 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2474 QQuickItemPrivate::get(gridviewB)->setLayoutMirror(true);
2475 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2477 // LTR != LTR+mirror
2478 foreach (const QString objectName, objectNames)
2479 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2481 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2483 // RTL == LTR+mirror
2484 foreach (const QString objectName, objectNames)
2485 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2487 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2489 // RTL != RTL+mirror
2490 foreach (const QString objectName, objectNames)
2491 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2493 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2495 // LTR == RTL+mirror
2496 foreach (const QString objectName, objectNames)
2497 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2503 void tst_QQuickGridView::positionViewAtIndex_rightToLeft()
2505 QQuickView *canvas = createView();
2508 for (int i = 0; i < 40; i++)
2509 model.addItem("Item" + QString::number(i), "");
2511 QQmlContext *ctxt = canvas->rootContext();
2512 ctxt->setContextProperty("testModel", &model);
2513 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2514 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2516 canvas->setSource(testFileUrl("gridview1.qml"));
2517 qApp->processEvents();
2519 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2520 QTRY_VERIFY(gridview != 0);
2522 QQuickItem *contentItem = gridview->contentItem();
2523 QTRY_VERIFY(contentItem != 0);
2525 // Confirm items positioned correctly
2526 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2527 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2528 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2529 if (!item) qWarning() << "Item" << i << "not found";
2531 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2532 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2535 // Position on a currently visible item
2536 gridview->positionViewAtIndex(6, QQuickGridView::Beginning);
2537 QTRY_COMPARE(gridview->contentX(), -320.);
2539 // Confirm items positioned correctly
2540 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2541 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2542 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2543 if (!item) qWarning() << "Item" << i << "not found";
2545 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2546 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2549 // Position on an item beyond the visible items
2550 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2551 QTRY_COMPARE(gridview->contentX(), -560.);
2553 // Confirm items positioned correctly
2554 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2555 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2556 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2557 if (!item) qWarning() << "Item" << i << "not found";
2559 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2560 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2563 // Position on an item that would leave empty space if positioned at the top
2564 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2565 QTRY_COMPARE(gridview->contentX(), -640.);
2567 // Confirm items positioned correctly
2568 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2569 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2570 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2571 if (!item) qWarning() << "Item" << i << "not found";
2573 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2574 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2577 // Position at the beginning again
2578 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2579 QTRY_COMPARE(gridview->contentX(), -240.);
2581 // Confirm items positioned correctly
2582 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2583 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2584 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2585 if (!item) qWarning() << "Item" << i << "not found";
2587 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2588 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2592 gridview->positionViewAtIndex(30, QQuickGridView::End);
2593 QTRY_COMPARE(gridview->contentX(), -560.);
2595 // Position in Center
2596 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2597 QTRY_COMPARE(gridview->contentX(), -400.);
2599 // Ensure at least partially visible
2600 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2601 QTRY_COMPARE(gridview->contentX(), -400.);
2603 gridview->setContentX(-555.);
2604 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2605 QTRY_COMPARE(gridview->contentX(), -555.);
2607 gridview->setContentX(-239);
2608 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2609 QTRY_COMPARE(gridview->contentX(), -320.);
2611 gridview->setContentX(-239);
2612 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2613 QTRY_COMPARE(gridview->contentX(), -400.);
2615 gridview->setContentX(-640);
2616 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2617 QTRY_COMPARE(gridview->contentX(), -560.);
2619 // Ensure completely visible
2620 gridview->setContentX(-400);
2621 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2622 QTRY_COMPARE(gridview->contentX(), -400.);
2624 gridview->setContentX(-315);
2625 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2626 QTRY_COMPARE(gridview->contentX(), -320.);
2628 gridview->setContentX(-640);
2629 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2630 QTRY_COMPARE(gridview->contentX(), -560.);
2635 void tst_QQuickGridView::resetModel()
2637 QQuickView *canvas = createView();
2639 QStringList strings;
2640 strings << "one" << "two" << "three";
2641 QStringListModel model(strings);
2643 QQmlContext *ctxt = canvas->rootContext();
2644 ctxt->setContextProperty("testModel", &model);
2646 canvas->setSource(testFileUrl("displaygrid.qml"));
2648 qApp->processEvents();
2650 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2651 QTRY_VERIFY(gridview != 0);
2652 QQuickItem *contentItem = gridview->contentItem();
2653 QTRY_VERIFY(contentItem != 0);
2654 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2656 QTRY_COMPARE(gridview->count(), model.rowCount());
2658 for (int i = 0; i < model.rowCount(); ++i) {
2659 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2660 QTRY_VERIFY(display != 0);
2661 QTRY_COMPARE(display->text(), strings.at(i));
2665 strings << "four" << "five" << "six" << "seven";
2666 model.setStringList(strings);
2668 QTRY_COMPARE(gridview->count(), model.rowCount());
2670 for (int i = 0; i < model.rowCount(); ++i) {
2671 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2672 QTRY_VERIFY(display != 0);
2673 QTRY_COMPARE(display->text(), strings.at(i));
2679 void tst_QQuickGridView::enforceRange()
2681 QQuickView *canvas = createView();
2684 for (int i = 0; i < 30; i++)
2685 model.addItem("Item" + QString::number(i), "");
2687 QQmlContext *ctxt = canvas->rootContext();
2688 ctxt->setContextProperty("testModel", &model);
2689 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2690 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2692 canvas->setSource(testFileUrl("gridview-enforcerange.qml"));
2694 qApp->processEvents();
2695 QVERIFY(canvas->rootObject() != 0);
2697 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2698 QTRY_VERIFY(gridview != 0);
2700 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2701 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2702 QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2703 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2705 QQuickItem *contentItem = gridview->contentItem();
2706 QTRY_VERIFY(contentItem != 0);
2708 // view should be positioned at the top of the range.
2709 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2711 QTRY_COMPARE(gridview->contentY(), -100.0);
2713 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2714 QTRY_VERIFY(name != 0);
2715 QTRY_COMPARE(name->text(), model.name(0));
2716 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2717 QTRY_VERIFY(number != 0);
2718 QTRY_COMPARE(number->text(), model.number(0));
2720 // Check currentIndex is updated when contentItem moves
2721 gridview->setContentY(0);
2722 QTRY_COMPARE(gridview->currentIndex(), 2);
2724 gridview->setCurrentIndex(5);
2725 QTRY_COMPARE(gridview->contentY(), 100.);
2728 for (int i = 0; i < 5; i++)
2729 model2.addItem("Item" + QString::number(i), "");
2731 ctxt->setContextProperty("testModel", &model2);
2732 QCOMPARE(gridview->count(), 5);
2737 void tst_QQuickGridView::enforceRange_rightToLeft()
2739 QQuickView *canvas = createView();
2742 for (int i = 0; i < 30; i++)
2743 model.addItem("Item" + QString::number(i), "");
2745 QQmlContext *ctxt = canvas->rootContext();
2746 ctxt->setContextProperty("testModel", &model);
2747 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2748 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2750 canvas->setSource(testFileUrl("gridview-enforcerange.qml"));
2751 qApp->processEvents();
2752 QVERIFY(canvas->rootObject() != 0);
2754 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2755 QTRY_VERIFY(gridview != 0);
2757 QCOMPARE(gridview->preferredHighlightBegin(), 100.0);
2758 QCOMPARE(gridview->preferredHighlightEnd(), 100.0);
2759 QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2761 QQuickItem *contentItem = gridview->contentItem();
2762 QVERIFY(contentItem != 0);
2764 // view should be positioned at the top of the range.
2765 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2767 QTRY_COMPARE(gridview->contentX(), -140.);
2768 QTRY_COMPARE(gridview->contentY(), 0.0);
2770 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2771 QTRY_VERIFY(name != 0);
2772 QTRY_COMPARE(name->text(), model.name(0));
2773 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2774 QTRY_VERIFY(number != 0);
2775 QTRY_COMPARE(number->text(), model.number(0));
2777 // Check currentIndex is updated when contentItem moves
2778 gridview->setContentX(-240);
2779 QTRY_COMPARE(gridview->currentIndex(), 3);
2781 gridview->setCurrentIndex(7);
2782 QTRY_COMPARE(gridview->contentX(), -340.);
2783 QTRY_COMPARE(gridview->contentY(), 0.0);
2786 for (int i = 0; i < 5; i++)
2787 model2.addItem("Item" + QString::number(i), "");
2789 ctxt->setContextProperty("testModel", &model2);
2790 QCOMPARE(gridview->count(), 5);
2795 void tst_QQuickGridView::QTBUG_8456()
2797 QQuickView *canvas = createView();
2799 canvas->setSource(testFileUrl("setindex.qml"));
2800 qApp->processEvents();
2802 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2803 QTRY_VERIFY(gridview != 0);
2805 QTRY_COMPARE(gridview->currentIndex(), 0);
2810 void tst_QQuickGridView::manualHighlight()
2812 QQuickView *canvas = createView();
2814 QString filename(testFile("manual-highlight.qml"));
2815 canvas->setSource(QUrl::fromLocalFile(filename));
2817 qApp->processEvents();
2819 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2820 QTRY_VERIFY(gridview != 0);
2822 QQuickItem *contentItem = gridview->contentItem();
2823 QTRY_VERIFY(contentItem != 0);
2825 QTRY_COMPARE(gridview->currentIndex(), 0);
2826 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2827 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2828 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2830 gridview->setCurrentIndex(2);
2832 QTRY_COMPARE(gridview->currentIndex(), 2);
2833 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2834 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2835 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2837 gridview->positionViewAtIndex(8, QQuickGridView::Contain);
2839 QTRY_COMPARE(gridview->currentIndex(), 2);
2840 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2841 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2842 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2844 gridview->setFlow(QQuickGridView::TopToBottom);
2845 QTRY_COMPARE(gridview->flow(), QQuickGridView::TopToBottom);
2847 gridview->setCurrentIndex(0);
2848 QTRY_COMPARE(gridview->currentIndex(), 0);
2849 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2850 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2851 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2857 void tst_QQuickGridView::footer()
2859 QFETCH(QQuickGridView::Flow, flow);
2860 QFETCH(Qt::LayoutDirection, layoutDirection);
2861 QFETCH(QPointF, initialFooterPos);
2862 QFETCH(QPointF, changedFooterPos);
2863 QFETCH(QPointF, initialContentPos);
2864 QFETCH(QPointF, changedContentPos);
2865 QFETCH(QPointF, firstDelegatePos);
2866 QFETCH(QPointF, resizeContentPos);
2868 QQuickView *canvas = getView();
2872 for (int i = 0; i < 7; i++)
2873 model.addItem("Item" + QString::number(i), "");
2875 QQmlContext *ctxt = canvas->rootContext();
2876 ctxt->setContextProperty("testModel", &model);
2878 canvas->setSource(testFileUrl("footer.qml"));
2879 qApp->processEvents();
2881 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2882 QTRY_VERIFY(gridview != 0);
2883 gridview->setFlow(flow);
2884 gridview->setLayoutDirection(layoutDirection);
2886 QQuickItem *contentItem = gridview->contentItem();
2887 QTRY_VERIFY(contentItem != 0);
2889 QQuickText *footer = findItem<QQuickText>(contentItem, "footer");
2892 QVERIFY(footer == gridview->footerItem());
2894 QCOMPARE(footer->pos(), initialFooterPos);
2895 QCOMPARE(footer->width(), 100.);
2896 QCOMPARE(footer->height(), 30.);
2897 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2899 if (flow == QQuickGridView::LeftToRight)
2900 QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + footer->height());
2902 QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + footer->width());
2904 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2906 QCOMPARE(item->pos(), firstDelegatePos);
2908 if (flow == QQuickGridView::LeftToRight) {
2909 // shrink by one row
2910 model.removeItem(2);
2911 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2913 // shrink by one column
2914 model.removeItem(2);
2915 model.removeItem(3);
2916 if (layoutDirection == Qt::LeftToRight)
2917 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2919 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2925 QPointF posWhenNoItems(0, 0);
2926 if (layoutDirection == Qt::RightToLeft)
2927 posWhenNoItems.setX(flow == QQuickGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2928 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2930 // if header is present, it's at a negative pos, so the footer should not move
2931 canvas->rootObject()->setProperty("showHeader", true);
2932 QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0);
2933 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2934 canvas->rootObject()->setProperty("showHeader", false);
2937 for (int i = 0; i < 30; i++)
2938 model.addItem("Item" + QString::number(i), "");
2940 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2941 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2943 QCOMPARE(footerItemSpy.count(), 1);
2945 footer = findItem<QQuickText>(contentItem, "footer");
2947 footer = findItem<QQuickText>(contentItem, "footer2");
2950 QVERIFY(footer == gridview->footerItem());
2952 QCOMPARE(footer->pos(), changedFooterPos);
2953 QCOMPARE(footer->width(), 50.);
2954 QCOMPARE(footer->height(), 20.);
2955 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2957 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2959 QCOMPARE(item->pos(), firstDelegatePos);
2961 gridview->positionViewAtEnd();
2962 footer->setHeight(10);
2963 footer->setWidth(40);
2964 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2966 releaseView(canvas);
2969 void tst_QQuickGridView::footer_data()
2971 QTest::addColumn<QQuickGridView::Flow>("flow");
2972 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2973 QTest::addColumn<QPointF>("initialFooterPos");
2974 QTest::addColumn<QPointF>("changedFooterPos");
2975 QTest::addColumn<QPointF>("initialContentPos");
2976 QTest::addColumn<QPointF>("changedContentPos");
2977 QTest::addColumn<QPointF>("firstDelegatePos");
2978 QTest::addColumn<QPointF>("resizeContentPos");
2980 // footer1 = 100 x 30
2981 // footer2 = 50 x 20
2984 // view height = 320
2986 // footer below items, bottom left
2987 QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
2988 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
2989 << QPointF(0, 10 * 60) // 30 items = 10 rows
2993 << QPointF(0, 10 * 60 - 320 + 10);
2995 // footer below items, bottom right
2996 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
2997 << QPointF(240 - 100, 3 * 60)
2998 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
3001 << QPointF(240 - 80, 0)
3002 << QPointF(0, 10 * 60 - 320 + 10);
3004 // footer to right of items
3005 QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
3006 << QPointF(2 * 80, 0) // 2 columns, cell width 80
3007 << QPointF(6 * 80, 0) // 30 items = 6 columns
3011 << QPointF(6 * 80 - 240 + 40, 0);
3013 // footer to left of items
3014 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
3015 << QPointF(-(2 * 80) - 100, 0)
3016 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
3018 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
3020 << QPointF(-(6 * 80) - 40, 0);
3023 void tst_QQuickGridView::header()
3025 QFETCH(QQuickGridView::Flow, flow);
3026 QFETCH(Qt::LayoutDirection, layoutDirection);
3027 QFETCH(QPointF, initialHeaderPos);
3028 QFETCH(QPointF, changedHeaderPos);
3029 QFETCH(QPointF, initialContentPos);
3030 QFETCH(QPointF, changedContentPos);
3031 QFETCH(QPointF, firstDelegatePos);
3032 QFETCH(QPointF, resizeContentPos);
3035 for (int i = 0; i < 30; i++)
3036 model.addItem("Item" + QString::number(i), "");
3038 QQuickView *canvas = getView();
3039 canvas->rootContext()->setContextProperty("testModel", &model);
3040 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
3041 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
3042 canvas->setSource(testFileUrl("header.qml"));
3044 qApp->processEvents();
3046 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3047 QTRY_VERIFY(gridview != 0);
3048 gridview->setFlow(flow);
3049 gridview->setLayoutDirection(layoutDirection);
3050 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3052 QQuickItem *contentItem = gridview->contentItem();
3053 QTRY_VERIFY(contentItem != 0);
3055 QQuickText *header = findItem<QQuickText>(contentItem, "header");
3058 QVERIFY(header == gridview->headerItem());
3060 QCOMPARE(header->pos(), initialHeaderPos);
3061 QCOMPARE(header->width(), 100.);
3062 QCOMPARE(header->height(), 30.);
3063 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3065 if (flow == QQuickGridView::LeftToRight)
3066 QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + header->height());
3068 QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + header->width());
3070 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3072 QCOMPARE(item->pos(), firstDelegatePos);
3075 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3076 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
3078 for (int i = 0; i < 30; i++)
3079 model.addItem("Item" + QString::number(i), "");
3081 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
3082 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
3084 QCOMPARE(headerItemSpy.count(), 1);
3086 header = findItem<QQuickText>(contentItem, "header");
3088 header = findItem<QQuickText>(contentItem, "header2");
3091 QVERIFY(header == gridview->headerItem());
3093 QCOMPARE(header->pos(), changedHeaderPos);
3094 QCOMPARE(header->width(), 50.);
3095 QCOMPARE(header->height(), 20.);
3096 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
3098 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3100 QCOMPARE(item->pos(), firstDelegatePos);
3102 header->setHeight(10);
3103 header->setWidth(40);
3104 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
3106 releaseView(canvas);
3109 // QTBUG-21207 header should become visible if view resizes from initial empty size
3112 canvas->rootContext()->setContextProperty("testModel", &model);
3113 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
3114 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
3115 canvas->setSource(testFileUrl("header.qml"));
3117 qApp->processEvents();
3119 gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3120 QTRY_VERIFY(gridview != 0);
3121 gridview->setFlow(flow);
3122 gridview->setLayoutDirection(layoutDirection);
3123 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3125 gridview->setWidth(240);
3126 gridview->setHeight(320);
3127 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
3128 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3130 releaseView(canvas);
3133 void tst_QQuickGridView::header_data()
3135 QTest::addColumn<QQuickGridView::Flow>("flow");
3136 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3137 QTest::addColumn<QPointF>("initialHeaderPos");
3138 QTest::addColumn<QPointF>("changedHeaderPos");
3139 QTest::addColumn<QPointF>("initialContentPos");
3140 QTest::addColumn<QPointF>("changedContentPos");
3141 QTest::addColumn<QPointF>("firstDelegatePos");
3142 QTest::addColumn<QPointF>("resizeContentPos");
3144 // header1 = 100 x 30
3145 // header2 = 50 x 20
3149 // header above items, top left
3150 QTest::newRow("flow left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight
3158 // header above items, top right
3159 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::LeftToRight << Qt::RightToLeft
3160 << QPointF(240 - 100, -30)
3161 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
3167 // header to left of items
3168 QTest::newRow("flow top to bottom, layout left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight
3176 // header to right of items
3177 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
3180 << QPointF(-(240 - 100), 0)
3181 << QPointF(-(240 - 50), 0)
3183 << QPointF(-(240 - 40), 0);
3186 class GVAccessor : public QQuickGridView
3189 qreal minY() const { return minYExtent(); }
3190 qreal maxY() const { return maxYExtent(); }
3191 qreal minX() const { return minXExtent(); }
3192 qreal maxX() const { return maxXExtent(); }
3195 void tst_QQuickGridView::headerFooter()
3199 QQuickView *canvas = createView();
3202 QQmlContext *ctxt = canvas->rootContext();
3203 ctxt->setContextProperty("testModel", &model);
3205 canvas->setSource(testFileUrl("headerfooter.qml"));
3206 qApp->processEvents();
3208 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3209 QTRY_VERIFY(gridview != 0);
3211 QQuickItem *contentItem = gridview->contentItem();
3212 QTRY_VERIFY(contentItem != 0);
3214 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3216 QCOMPARE(header->y(), -header->height());
3218 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3220 QCOMPARE(footer->y(), 0.);
3222 QCOMPARE(static_cast<GVAccessor*>(gridview)->minY(), header->height());
3223 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxY(), header->height());
3229 QQuickView *canvas = createView();
3232 QQmlContext *ctxt = canvas->rootContext();
3233 ctxt->setContextProperty("testModel", &model);
3235 canvas->setSource(testFileUrl("headerfooter.qml"));
3236 canvas->rootObject()->setProperty("horizontal", true);
3237 qApp->processEvents();
3239 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3240 QTRY_VERIFY(gridview != 0);
3242 QQuickItem *contentItem = gridview->contentItem();
3243 QTRY_VERIFY(contentItem != 0);
3245 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3247 QCOMPARE(header->x(), -header->width());
3249 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3251 QCOMPARE(footer->x(), 0.);
3253 QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), header->width());
3254 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), header->width());
3260 QQuickView *canvas = createView();
3263 QQmlContext *ctxt = canvas->rootContext();
3264 ctxt->setContextProperty("testModel", &model);
3266 canvas->setSource(testFileUrl("headerfooter.qml"));
3267 canvas->rootObject()->setProperty("horizontal", true);
3268 canvas->rootObject()->setProperty("rtl", true);
3269 qApp->processEvents();
3271 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3272 QTRY_VERIFY(gridview != 0);
3274 QQuickItem *contentItem = gridview->contentItem();
3275 QTRY_VERIFY(contentItem != 0);
3277 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3279 QCOMPARE(header->x(), 0.);
3281 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3283 QCOMPARE(footer->x(), -footer->width());
3285 QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), 240. - header->width());
3286 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), 240. - header->width());
3292 QQuickView *canvas = createView();
3295 for (int i = 0; i < 6; i++)
3296 model.addItem("Item" + QString::number(i), "");
3297 QQmlContext *ctxt = canvas->rootContext();
3298 ctxt->setContextProperty("testModel", &model);
3300 canvas->setSource(testFileUrl("headerfooter.qml"));
3301 qApp->processEvents();
3303 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
3304 QTRY_VERIFY(gridview != 0);
3306 QQuickItem *contentItem = gridview->contentItem();
3307 QTRY_VERIFY(contentItem != 0);
3309 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3311 QCOMPARE(header->y(), -header->height());
3313 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3315 QCOMPARE(footer->y(), 80.*2);
3319 header = findItem<QQuickItem>(contentItem, "header");
3321 QCOMPARE(header->y(), -header->height());
3323 footer = findItem<QQuickItem>(contentItem, "footer");
3325 QCOMPARE(footer->y(), 80.*2);
3331 void tst_QQuickGridView::resizeViewAndRepaint()
3333 QQuickView *canvas = createView();
3337 for (int i = 0; i < 40; i++)
3338 model.addItem("Item" + QString::number(i), "");
3340 QQmlContext *ctxt = canvas->rootContext();
3341 ctxt->setContextProperty("testModel", &model);
3342 ctxt->setContextProperty("initialWidth", 240);
3343 ctxt->setContextProperty("initialHeight", 100);
3345 canvas->setSource(testFileUrl("resizeview.qml"));
3347 qApp->processEvents();
3349 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3350 QTRY_VERIFY(gridview != 0);
3351 QQuickItem *contentItem = gridview->contentItem();
3352 QTRY_VERIFY(contentItem != 0);
3353 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3355 // item at index 10 should not be currently visible
3356 QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3358 gridview->setHeight(320);
3359 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", 10));
3361 gridview->setHeight(100);
3362 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3364 // Ensure we handle -ve sizes
3365 gridview->setHeight(-100);
3366 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 3);
3368 gridview->setCacheBuffer(120);
3369 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 9);
3371 // ensure items in cache become visible
3372 gridview->setHeight(120);
3373 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 15);
3375 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3376 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3377 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3378 if (!item) qWarning() << "Item" << i << "not found";
3380 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3381 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3382 QCOMPARE(item->isVisible(), i < 9); // inside view visible, outside not visible
3385 // ensure items outside view become invisible
3386 gridview->setHeight(60);
3387 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 12);
3389 itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
3390 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3391 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3392 if (!item) qWarning() << "Item" << i << "not found";
3394 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3395 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3396 QCOMPARE(item->isVisible(), i < 6); // inside view visible, outside not visible
3402 void tst_QQuickGridView::changeColumnCount()
3405 for (int i = 0; i < 40; i++)
3406 model.addItem("Item" + QString::number(i), "");
3408 QQuickView *canvas = createView();
3409 QQmlContext *ctxt = canvas->rootContext();
3410 ctxt->setContextProperty("testModel", &model);
3411 ctxt->setContextProperty("initialWidth", 100);
3412 ctxt->setContextProperty("initialHeight", 320);
3413 canvas->setSource(testFileUrl("resizeview.qml"));
3415 qApp->processEvents();
3417 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3418 QTRY_VERIFY(gridview != 0);
3419 QQuickItem *contentItem = gridview->contentItem();
3420 QTRY_VERIFY(contentItem != 0);
3421 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3423 // a single column of 6 items are visible
3424 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3425 QCOMPARE(itemCount, 6);
3426 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3427 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3428 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3429 QCOMPARE(item->x(), 0.0);
3430 QCOMPARE(item->y(), qreal(i*60));
3433 // now 6x3 grid is visible, plus 1 extra below for refill
3434 gridview->setWidth(240);
3435 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3436 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3437 QCOMPARE(itemCount, 6*3 + 1);
3438 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3439 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3440 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3441 QCOMPARE(item->x(), qreal((i%3)*80));
3442 QCOMPARE(item->y(), qreal((i/3)*60));
3445 // back to single column
3446 gridview->setWidth(100);
3447 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3448 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3449 QCOMPARE(itemCount, 6);
3450 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3451 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3452 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3453 QCOMPARE(item->x(), 0.0);
3454 QCOMPARE(item->y(), qreal(i*60));
3460 void tst_QQuickGridView::indexAt_itemAt_data()
3462 QTest::addColumn<qreal>("x");
3463 QTest::addColumn<qreal>("y");
3464 QTest::addColumn<int>("index");
3466 QTest::newRow("Item 0 - 0, 0") << 0. << 0. << 0;
3467 QTest::newRow("Item 0 - 79, 59") << 79. << 59. << 0;
3468 QTest::newRow("Item 1 - 80, 0") << 80. << 0. << 1;
3469 QTest::newRow("Item 3 - 0, 60") << 0. << 60. << 3;
3470 QTest::newRow("No Item - 240, 0") << 240. << 0. << -1;
3473 void tst_QQuickGridView::indexAt_itemAt()
3479 QQuickView *canvas = getView();
3482 model.addItem("Fred", "12345");
3483 model.addItem("John", "2345");
3484 model.addItem("Bob", "54321");
3485 model.addItem("Billy", "22345");
3486 model.addItem("Sam", "2945");
3487 model.addItem("Ben", "04321");
3488 model.addItem("Jim", "0780");
3490 QQmlContext *ctxt = canvas->rootContext();
3491 ctxt->setContextProperty("testModel", &model);
3492 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3493 ctxt->setContextProperty("testTopToBottom", QVariant(false));
3495 canvas->setSource(testFileUrl("gridview1.qml"));
3496 qApp->processEvents();
3498 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3499 QTRY_VERIFY(gridview != 0);
3501 QQuickItem *contentItem = gridview->contentItem();
3502 QTRY_VERIFY(contentItem != 0);
3504 QTRY_COMPARE(gridview->count(), model.count());
3506 QQuickItem *item = 0;
3508 item = findItem<QQuickItem>(contentItem, "wrapper", index);
3511 QCOMPARE(gridview->indexAt(x, y), index);
3512 QVERIFY(gridview->itemAt(x, y) == item);
3514 releaseView(canvas);
3517 void tst_QQuickGridView::onAdd()
3519 QFETCH(int, initialItemCount);
3520 QFETCH(int, itemsToAdd);
3522 const int delegateWidth = 50;
3523 const int delegateHeight = 100;
3525 QQuickView *canvas = getView();
3526 canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
3528 // these initial items should not trigger GridView.onAdd
3529 for (int i=0; i<initialItemCount; i++)
3530 model.addItem("dummy value", "dummy value");
3532 QQmlContext *ctxt = canvas->rootContext();
3533 ctxt->setContextProperty("testModel", &model);
3534 ctxt->setContextProperty("delegateWidth", delegateWidth);
3535 ctxt->setContextProperty("delegateHeight", delegateHeight);
3536 canvas->setSource(testFileUrl("attachedSignals.qml"));
3538 QObject *object = canvas->rootObject();
3539 object->setProperty("width", canvas->width());
3540 object->setProperty("height", canvas->height());
3541 qApp->processEvents();
3543 QList<QPair<QString, QString> > items;
3544 for (int i=0; i<itemsToAdd; i++)
3545 items << qMakePair(QString("value %1").arg(i), QString::number(i));
3546 model.addItems(items);
3548 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
3549 qApp->processEvents();
3551 QVariantList result = object->property("addedDelegates").toList();
3552 QTRY_COMPARE(result.count(), items.count());
3553 for (int i=0; i<items.count(); i++)
3554 QCOMPARE(result[i].toString(), items[i].first);
3556 releaseView(canvas);
3559 void tst_QQuickGridView::onAdd_data()
3561 QTest::addColumn<int>("initialItemCount");
3562 QTest::addColumn<int>("itemsToAdd");
3564 QTest::newRow("0, add 1") << 0 << 1;
3565 QTest::newRow("0, add 2") << 0 << 2;
3566 QTest::newRow("0, add 10") << 0 << 10;
3568 QTest::newRow("1, add 1") << 1 << 1;
3569 QTest::newRow("1, add 2") << 1 << 2;
3570 QTest::newRow("1, add 10") << 1 << 10;
3572 QTest::newRow("5, add 1") << 5 << 1;
3573 QTest::newRow("5, add 2") << 5 << 2;
3574 QTest::newRow("5, add 10") << 5 << 10;
3577 void tst_QQuickGridView::onRemove()
3579 QFETCH(int, initialItemCount);
3580 QFETCH(int, indexToRemove);
3581 QFETCH(int, removeCount);
3583 const int delegateWidth = 50;
3584 const int delegateHeight = 100;
3586 for (int i=0; i<initialItemCount; i++)
3587 model.addItem(QString("value %1").arg(i), "dummy value");
3589 QQuickView *canvas = getView();
3590 QQmlContext *ctxt = canvas->rootContext();
3591 ctxt->setContextProperty("testModel", &model);
3592 ctxt->setContextProperty("delegateWidth", delegateWidth);
3593 ctxt->setContextProperty("delegateHeight", delegateHeight);
3594 canvas->setSource(testFileUrl("attachedSignals.qml"));
3595 QObject *object = canvas->rootObject();
3597 model.removeItems(indexToRemove, removeCount);
3598 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(canvas->rootObject())->count());
3599 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
3601 releaseView(canvas);
3604 void tst_QQuickGridView::onRemove_data()
3606 QTest::addColumn<int>("initialItemCount");
3607 QTest::addColumn<int>("indexToRemove");
3608 QTest::addColumn<int>("removeCount");
3610 QTest::newRow("remove first") << 1 << 0 << 1;
3611 QTest::newRow("two items, remove first") << 2 << 0 << 1;
3612 QTest::newRow("two items, remove last") << 2 << 1 << 1;
3613 QTest::newRow("two items, remove all") << 2 << 0 << 2;
3615 QTest::newRow("four items, remove first") << 4 << 0 << 1;
3616 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
3617 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
3618 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
3619 QTest::newRow("four items, remove last") << 4 << 3 << 1;
3620 QTest::newRow("four items, remove all") << 4 << 0 << 4;
3622 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
3623 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
3624 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
3627 void tst_QQuickGridView::columnCount()
3630 canvas.setSource(testFileUrl("gridview4.qml"));
3632 canvas.requestActivateWindow();
3633 QTest::qWaitForWindowShown(&canvas);
3635 QQuickGridView *view = qobject_cast<QQuickGridView*>(canvas.rootObject());
3637 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3638 QCOMPARE(view->cellHeight(), qreal(100));
3640 QList<QQuickItem*> items = findItems<QQuickItem>(view, "delegate");
3641 QCOMPARE(items.size(), 18);
3642 QCOMPARE(items.at(8)->y(), qreal(0));
3643 QCOMPARE(items.at(9)->y(), qreal(100));
3646 void tst_QQuickGridView::margins()
3649 QQuickView *canvas = createView();
3652 for (int i = 0; i < 40; i++)
3653 model.addItem("Item" + QString::number(i), "");
3655 QQmlContext *ctxt = canvas->rootContext();
3656 ctxt->setContextProperty("testModel", &model);
3657 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3659 canvas->setSource(testFileUrl("margins.qml"));
3661 qApp->processEvents();
3663 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3664 QTRY_VERIFY(gridview != 0);
3665 QQuickItem *contentItem = gridview->contentItem();
3666 QTRY_VERIFY(contentItem != 0);
3667 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3669 QCOMPARE(gridview->contentX(), -30.);
3670 QCOMPARE(gridview->xOrigin(), 0.);
3673 gridview->positionViewAtEnd();
3674 qreal pos = gridview->contentX();
3675 gridview->setContentX(pos + 80);
3676 gridview->returnToBounds();
3677 QTRY_COMPARE(gridview->contentX(), pos + 50);
3679 // remove item before visible and check that left margin is maintained
3680 // and xOrigin is updated
3681 gridview->setContentX(200);
3682 model.removeItems(0, 4);
3684 gridview->setContentX(-50);
3685 gridview->returnToBounds();
3686 QCOMPARE(gridview->xOrigin(), 100.);
3687 QTRY_COMPARE(gridview->contentX(), 70.);
3689 // reduce left margin
3690 gridview->setLeftMargin(20);
3691 QCOMPARE(gridview->xOrigin(), 100.);
3692 QTRY_COMPARE(gridview->contentX(), 80.);
3695 gridview->positionViewAtEnd();
3696 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3697 pos = gridview->contentX();
3698 gridview->setContentX(pos + 80);
3699 gridview->returnToBounds();
3700 QTRY_COMPARE(gridview->contentX(), pos + 50);
3702 // reduce right margin
3703 pos = gridview->contentX();
3704 gridview->setRightMargin(40);
3705 QCOMPARE(gridview->xOrigin(), 0.);
3706 QTRY_COMPARE(gridview->contentX(), pos-10);
3712 QQuickView *canvas = createView();
3716 for (int i = 0; i < 40; i++)
3717 model.addItem("Item" + QString::number(i), "");
3719 QQmlContext *ctxt = canvas->rootContext();
3720 ctxt->setContextProperty("testModel", &model);
3721 ctxt->setContextProperty("testRightToLeft", QVariant(true));
3723 canvas->setSource(testFileUrl("margins.qml"));
3724 qApp->processEvents();
3726 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3727 QTRY_VERIFY(gridview != 0);
3729 QQuickItem *contentItem = gridview->contentItem();
3730 QTRY_VERIFY(contentItem != 0);
3732 QTRY_COMPARE(gridview->contentX(), -240+50.);
3733 QTRY_COMPARE(gridview->xOrigin(), 0.);
3736 gridview->positionViewAtEnd();
3737 qreal pos = gridview->contentX();
3738 gridview->setContentX(pos - 80);
3739 gridview->returnToBounds();
3740 QTRY_COMPARE(gridview->contentX(), pos - 30);
3742 // remove item before visible and check that left margin is maintained
3743 // and xOrigin is updated
3744 gridview->setContentX(-400);
3745 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3746 model.removeItems(0, 4);
3747 QTRY_COMPARE(model.count(), gridview->count());
3748 gridview->setContentX(-240+50);
3749 gridview->returnToBounds();
3750 QCOMPARE(gridview->xOrigin(), -100.);
3751 QTRY_COMPARE(gridview->contentX(), -240-50.);
3753 // reduce right margin
3754 pos = gridview->contentX();
3755 gridview->setRightMargin(40);
3756 QCOMPARE(gridview->xOrigin(), -100.);
3757 QTRY_COMPARE(gridview->contentX(), -240-100 + 40.);
3760 gridview->positionViewAtEnd();
3761 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3762 pos = gridview->contentX();
3763 gridview->setContentX(pos - 80);
3764 gridview->returnToBounds();
3765 QTRY_COMPARE(gridview->contentX(), pos - 30);
3767 // reduce left margin
3768 pos = gridview->contentX();
3769 gridview->setLeftMargin(20);
3770 QCOMPARE(gridview->xOrigin(), 0.);
3771 QTRY_COMPARE(gridview->contentX(), pos+10);
3777 void tst_QQuickGridView::creationContext()
3780 canvas.setGeometry(0,0,240,320);
3781 canvas.setSource(testFileUrl("creationContext.qml"));
3782 qApp->processEvents();
3784 QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
3786 QVERIFY(rootItem->property("count").toInt() > 0);
3789 QVERIFY(item = rootItem->findChild<QQuickItem *>("listItem"));
3790 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3791 QVERIFY(item = rootItem->findChild<QQuickItem *>("header"));
3792 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3793 QVERIFY(item = rootItem->findChild<QQuickItem *>("footer"));
3794 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3797 void tst_QQuickGridView::snapToRow_data()
3799 QTest::addColumn<QQuickGridView::Flow>("flow");
3800 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3801 QTest::addColumn<int>("highlightRangeMode");
3802 QTest::addColumn<QPoint>("flickStart");
3803 QTest::addColumn<QPoint>("flickEnd");
3804 QTest::addColumn<qreal>("snapAlignment");
3805 QTest::addColumn<qreal>("endExtent");
3806 QTest::addColumn<qreal>("startExtent");
3808 QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3809 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 800.0 << 0.0;
3811 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3812 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 800.0 << 0.0;
3814 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3815 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 << -240.0;
3817 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3818 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 940.0 << -20.0;
3820 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3821 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 940.0 << -20.0;
3823 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3824 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 - 140.0 << -220.0;
3827 void tst_QQuickGridView::snapToRow()
3829 QFETCH(QQuickGridView::Flow, flow);
3830 QFETCH(Qt::LayoutDirection, layoutDirection);
3831 QFETCH(int, highlightRangeMode);
3832 QFETCH(QPoint, flickStart);
3833 QFETCH(QPoint, flickEnd);
3834 QFETCH(qreal, snapAlignment);
3835 QFETCH(qreal, endExtent);
3836 QFETCH(qreal, startExtent);
3838 QQuickView *canvas = getView();
3840 canvas->setSource(testFileUrl("snapToRow.qml"));
3842 qApp->processEvents();
3844 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3845 QTRY_VERIFY(gridview != 0);
3847 gridview->setFlow(flow);
3848 gridview->setLayoutDirection(layoutDirection);
3849 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3850 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3852 QQuickItem *contentItem = gridview->contentItem();
3853 QTRY_VERIFY(contentItem != 0);
3855 // confirm that a flick hits an item boundary
3856 flick(canvas, flickStart, flickEnd, 180);
3857 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3858 if (flow == QQuickGridView::LeftToRight)
3859 QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
3861 QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
3865 flick(canvas, flickStart, flickEnd, 180);
3866 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3867 } while (flow == QQuickGridView::LeftToRight
3868 ? !gridview->isAtYEnd()
3869 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3871 if (flow == QQuickGridView::LeftToRight)
3872 QCOMPARE(gridview->contentY(), endExtent);
3874 QCOMPARE(gridview->contentX(), endExtent);
3878 flick(canvas, flickEnd, flickStart, 180);
3879 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3880 } while (flow == QQuickGridView::LeftToRight
3881 ? !gridview->isAtYBeginning()
3882 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3884 if (flow == QQuickGridView::LeftToRight)
3885 QCOMPARE(gridview->contentY(), startExtent);
3887 QCOMPARE(gridview->contentX(), startExtent);
3889 releaseView(canvas);
3892 void tst_QQuickGridView::snapOneRow_data()
3894 QTest::addColumn<QQuickGridView::Flow>("flow");
3895 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3896 QTest::addColumn<int>("highlightRangeMode");
3897 QTest::addColumn<QPoint>("flickStart");
3898 QTest::addColumn<QPoint>("flickEnd");
3899 QTest::addColumn<qreal>("snapAlignment");
3900 QTest::addColumn<qreal>("endExtent");
3901 QTest::addColumn<qreal>("startExtent");
3903 QTest::newRow("vertical, left to right") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3904 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 240.0 << 0.0;
3906 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3907 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0;
3909 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
3910 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 << -240.0;
3912 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3913 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 340.0 << -20.0;
3915 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3916 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0;
3918 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3919 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0;
3922 void tst_QQuickGridView::snapOneRow()
3924 QFETCH(QQuickGridView::Flow, flow);
3925 QFETCH(Qt::LayoutDirection, layoutDirection);
3926 QFETCH(int, highlightRangeMode);
3927 QFETCH(QPoint, flickStart);
3928 QFETCH(QPoint, flickEnd);
3929 QFETCH(qreal, snapAlignment);
3930 QFETCH(qreal, endExtent);
3931 QFETCH(qreal, startExtent);
3933 QQuickView *canvas = getView();
3935 canvas->setSource(testFileUrl("snapOneRow.qml"));
3937 qApp->processEvents();
3939 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3940 QTRY_VERIFY(gridview != 0);
3942 gridview->setFlow(flow);
3943 gridview->setLayoutDirection(layoutDirection);
3944 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3945 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3947 QQuickItem *contentItem = gridview->contentItem();
3948 QTRY_VERIFY(contentItem != 0);
3950 QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged()));
3952 // confirm that a flick hits next row boundary
3953 flick(canvas, flickStart, flickEnd, 180);
3954 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3955 if (flow == QQuickGridView::LeftToRight)
3956 QCOMPARE(gridview->contentY(), snapAlignment);
3958 QCOMPARE(gridview->contentX(), snapAlignment);
3960 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3961 QCOMPARE(gridview->currentIndex(), 2);
3962 QCOMPARE(currentIndexSpy.count(), 1);
3967 flick(canvas, flickStart, flickEnd, 180);
3968 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3969 } while (flow == QQuickGridView::LeftToRight
3970 ? !gridview->isAtYEnd()
3971 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3973 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3974 QCOMPARE(gridview->currentIndex(), 6);
3975 QCOMPARE(currentIndexSpy.count(), 3);
3978 if (flow == QQuickGridView::LeftToRight)
3979 QCOMPARE(gridview->contentY(), endExtent);
3981 QCOMPARE(gridview->contentX(), endExtent);
3985 flick(canvas, flickEnd, flickStart, 180);
3986 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3987 } while (flow == QQuickGridView::LeftToRight
3988 ? !gridview->isAtYBeginning()
3989 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3991 if (flow == QQuickGridView::LeftToRight)
3992 QCOMPARE(gridview->contentY(), startExtent);
3994 QCOMPARE(gridview->contentX(), startExtent);
3996 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
3997 QCOMPARE(gridview->currentIndex(), 0);
3998 QCOMPARE(currentIndexSpy.count(), 6);
4001 releaseView(canvas);
4005 void tst_QQuickGridView::unaligned()
4007 QQuickView *canvas = createView();
4011 for (int i = 0; i < 10; i++)
4012 model.addItem("Item" + QString::number(i), "");
4014 QQmlContext *ctxt = canvas->rootContext();
4015 ctxt->setContextProperty("testModel", &model);
4017 canvas->setSource(testFileUrl("unaligned.qml"));
4018 qApp->processEvents();
4020 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(canvas->rootObject());
4021 QVERIFY(gridview != 0);
4023 QQuickItem *contentItem = gridview->contentItem();
4024 QVERIFY(contentItem != 0);
4026 for (int i = 0; i < 10; ++i) {
4027 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4028 if (!item) qWarning() << "Item" << i << "not found";
4030 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4031 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4035 for (int i = 10; i < 18; ++i) {
4036 model.addItem("Item" + QString::number(i), "");
4037 QQuickItem *item = 0;
4038 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4039 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4040 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4044 for (int i = 0; i < 10; ++i) {
4045 model.insertItem(i, "Item" + QString::number(i), "");
4046 QQuickItem *item = 0;
4047 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4048 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4049 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4053 model.removeItems(7, 10);
4054 QTRY_COMPARE(model.count(), gridview->count());
4055 for (int i = 0; i < 18; ++i) {
4056 QQuickItem *item = 0;
4057 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4058 QCOMPARE(item->x(), qreal(i%9)*gridview->cellWidth());
4059 QCOMPARE(item->y(), qreal(i/9)*gridview->cellHeight());
4065 void tst_QQuickGridView::populateTransitions()
4067 QFETCH(bool, staticallyPopulate);
4068 QFETCH(bool, dynamicallyPopulate);
4069 QFETCH(bool, usePopulateTransition);
4071 QPointF transitionFrom(-50, -50);
4072 QPointF transitionVia(100, 100);
4073 QaimModel model_transitionFrom;
4074 QaimModel model_transitionVia;
4077 if (staticallyPopulate) {
4078 for (int i = 0; i < 30; i++)
4079 model.addItem("item" + QString::number(i), "");
4082 QQuickView *canvas = getView();
4083 canvas->rootContext()->setContextProperty("testModel", &model);
4084 canvas->rootContext()->setContextProperty("usePopulateTransition", usePopulateTransition);
4085 canvas->rootContext()->setContextProperty("dynamicallyPopulate", dynamicallyPopulate);
4086 canvas->rootContext()->setContextProperty("transitionFrom", transitionFrom);
4087 canvas->rootContext()->setContextProperty("transitionVia", transitionVia);
4088 canvas->rootContext()->setContextProperty("model_transitionFrom", &model_transitionFrom);
4089 canvas->rootContext()->setContextProperty("model_transitionVia", &model_transitionVia);
4090 canvas->setSource(testFileUrl("populateTransitions.qml"));
4093 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4095 QQuickItem *contentItem = gridview->contentItem();
4096 QVERIFY(contentItem);
4098 if (staticallyPopulate || dynamicallyPopulate) {
4099 // check the populate transition is run
4100 if (usePopulateTransition) {
4101 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 19);
4103 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4104 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
4106 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4108 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4111 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4112 if (usePopulateTransition)
4113 QCOMPARE(itemCount, gridview->property("countPopulateTransitions").toInt());
4114 for (int i=0; i < model.count() && i < itemCount; ++i) {
4115 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4116 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4117 QCOMPARE(item->x(), (i%3)*80.0);
4118 QCOMPARE(item->y(), (i/3)*60.0);
4119 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4121 QTRY_COMPARE(name->text(), model.name(i));
4124 // add an item and check this is done with add transition, not populate
4125 model.insertItem(0, "another item", "");
4126 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 1);
4127 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(),
4128 (usePopulateTransition && (staticallyPopulate || dynamicallyPopulate)) ? 19 : 0);
4131 canvas->rootContext()->setContextProperty("testModel", QVariant());
4132 QTRY_COMPARE(gridview->count(), 0);
4133 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
4134 gridview->setProperty("countPopulateTransitions", 0);
4135 gridview->setProperty("countAddTransitions", 0);
4137 // set to a valid model and check populate transition is run a second time
4139 for (int i = 0; i < 30; i++)
4140 model.addItem("item" + QString::number(i), "");
4141 canvas->rootContext()->setContextProperty("testModel", &model);
4142 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4144 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 19 : 0);
4145 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4147 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4148 if (usePopulateTransition)
4149 QCOMPARE(itemCount, gridview->property("countPopulateTransitions").toInt());
4150 for (int i=0; i < model.count() && i < itemCount; ++i) {
4151 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4152 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4153 QCOMPARE(item->x(), (i%3)*80.0);
4154 QCOMPARE(item->y(), (i/3)*60.0);
4155 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4157 QTRY_COMPARE(name->text(), model.name(i));
4160 // reset model and check populate transition is run again
4161 gridview->setProperty("countPopulateTransitions", 0);
4162 gridview->setProperty("countAddTransitions", 0);
4164 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 19 : 0);
4165 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4167 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4168 if (usePopulateTransition)
4169 QCOMPARE(itemCount, gridview->property("countPopulateTransitions").toInt());
4170 for (int i=0; i < model.count() && i < itemCount; ++i) {
4171 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4172 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4173 QCOMPARE(item->x(), (i%3)*80.0);
4174 QCOMPARE(item->y(), (i/3)*60.0);
4175 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4177 QTRY_COMPARE(name->text(), model.name(i));
4180 releaseView(canvas);
4183 void tst_QQuickGridView::populateTransitions_data()
4185 QTest::addColumn<bool>("staticallyPopulate");
4186 QTest::addColumn<bool>("dynamicallyPopulate");
4187 QTest::addColumn<bool>("usePopulateTransition");
4189 QTest::newRow("static") << true << false << true;
4190 QTest::newRow("static, no populate") << true << false << false;
4192 QTest::newRow("dynamic") << false << true << true;
4193 QTest::newRow("dynamic, no populate") << false << true << false;
4195 QTest::newRow("empty to start with") << false << false << true;
4196 QTest::newRow("empty to start with, no populate") << false << false << false;
4199 void tst_QQuickGridView::addTransitions()
4201 QFETCH(int, initialItemCount);
4202 QFETCH(bool, shouldAnimateTargets);
4203 QFETCH(qreal, contentYRowOffset);
4204 QFETCH(int, insertionIndex);
4205 QFETCH(int, insertionCount);
4206 QFETCH(ListRange, expectedDisplacedIndexes);
4208 // added items should start here
4209 QPointF targetItems_transitionFrom(-50, -50);
4211 // displaced items should pass through this point
4212 QPointF displacedItems_transitionVia(100, 100);
4215 for (int i = 0; i < initialItemCount; i++)
4216 model.addItem("Original item" + QString::number(i), "");
4217 QaimModel model_targetItems_transitionFrom;
4218 QaimModel model_displacedItems_transitionVia;
4220 QQuickView *canvas = getView();
4221 QQmlContext *ctxt = canvas->rootContext();
4222 ctxt->setContextProperty("testModel", &model);
4223 ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
4224 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4225 ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
4226 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4227 canvas->setSource(testFileUrl("addTransitions.qml"));
4230 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4231 QTRY_VERIFY(gridview != 0);
4232 QQuickItem *contentItem = gridview->contentItem();
4233 QVERIFY(contentItem != 0);
4234 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4236 if (contentYRowOffset != 0) {
4237 gridview->setContentY(contentYRowOffset * 60.0);
4238 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4241 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4243 // only target items that will become visible should be animated
4244 QList<QPair<QString, QString> > newData;
4245 QList<QPair<QString, QString> > expectedTargetData;
4246 QList<int> targetIndexes;
4247 if (shouldAnimateTargets) {
4248 for (int i=insertionIndex; i<insertionIndex+insertionCount; i++) {
4249 newData << qMakePair(QString("New item %1").arg(i), QString(""));
4251 // last visible item is the first item of the row beneath the view
4252 if (i >= (gridview->contentY() / 60)*3 && i < qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) {
4253 expectedTargetData << newData.last();
4257 QVERIFY(expectedTargetData.count() > 0);
4261 if (!newData.isEmpty()) {
4262 model.insertItems(insertionIndex, newData);
4263 QTRY_COMPARE(model.count(), gridview->count());
4266 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4268 if (shouldAnimateTargets) {
4269 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4270 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4271 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4273 // check the target and displaced items were animated
4274 model_targetItems_transitionFrom.matchAgainst(expectedTargetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
4275 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4277 // check attached properties
4278 matchItemsAndIndexes(gridview->property("targetTrans_items").toMap(), model, targetIndexes);
4279 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4280 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4281 if (expectedDisplacedIndexes.isValid()) {
4282 // adjust expectedDisplacedIndexes to their final values after the move
4283 QList<int> displacedIndexes = adjustIndexesForAddDisplaced(expectedDisplacedIndexes.indexes, insertionIndex, insertionCount);
4284 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4285 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4286 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4289 QTRY_COMPARE(model_targetItems_transitionFrom.count(), 0);
4290 QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0);
4293 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4294 int firstVisibleIndex = -1;
4295 for (int i=0; i<items.count(); i++) {
4296 if (items[i]->y() >= gridview->contentY()) {
4297 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4298 firstVisibleIndex = e.evaluate().toInt();
4302 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4304 // verify all items moved to the correct final positions
4305 for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
4306 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4307 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4308 QCOMPARE(item->x(), (i%3)*80.0);
4309 QCOMPARE(item->y(), (i/3)*60.0);
4310 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4312 QCOMPARE(name->text(), model.name(i));
4315 releaseView(canvas);
4318 void tst_QQuickGridView::addTransitions_data()
4320 QTest::addColumn<int>("initialItemCount");
4321 QTest::addColumn<qreal>("contentYRowOffset");
4322 QTest::addColumn<bool>("shouldAnimateTargets");
4323 QTest::addColumn<int>("insertionIndex");
4324 QTest::addColumn<int>("insertionCount");
4325 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4327 // if inserting a full row before visible index, items don't appear or animate in, even if there are > 1 new items
4328 QTest::newRow("insert 1, just before start")
4329 << 30 << 1.0 << false
4330 << 0 << 1 << ListRange();
4331 QTest::newRow("insert 1, way before start")
4332 << 30 << 1.0 << false
4333 << 0 << 1 << ListRange();
4334 QTest::newRow("insert multiple, just before start")
4335 << 30 << 1.0 << false
4336 << 0 << 3 << ListRange();
4337 QTest::newRow("insert multiple (< 1 row), just before start")
4338 << 30 << 1.0 << false
4339 << 0 << 2 << ListRange();
4340 QTest::newRow("insert multiple, way before start")
4341 << 30 << 3.0 << false
4342 << 0 << 3 << ListRange();
4344 QTest::newRow("insert 1 at start")
4345 << 30 << 0.0 << true
4346 << 0 << 1 << ListRange(0, 17);
4347 QTest::newRow("insert multiple at start")
4348 << 30 << 0.0 << true
4349 << 0 << 3 << ListRange(0, 17);
4350 QTest::newRow("insert multiple (> 1 row) at start")
4351 << 30 << 0.0 << true
4352 << 0 << 5 << ListRange(0, 17);
4353 QTest::newRow("insert 1 at start, content y not 0")
4354 << 30 << 1.0 << true // first visible is index 3
4355 << 3 << 1 << ListRange(0 + 3, 17 + 3);
4356 QTest::newRow("insert multiple at start, content y not 0")
4357 << 30 << 1.0 << true // first visible is index 3
4358 << 3 << 3 << ListRange(0 + 3, 17 + 3);
4359 QTest::newRow("insert multiple (> 1 row) at start, content y not 0")
4360 << 30 << 1.0 << true // first visible is index 3
4361 << 3 << 5 << ListRange(0 + 3, 17 + 3);
4363 QTest::newRow("insert 1 at start, to empty grid")
4365 << 0 << 1 << ListRange();
4366 QTest::newRow("insert multiple at start, to empty grid")
4368 << 0 << 3 << ListRange();
4370 QTest::newRow("insert 1 at middle")
4371 << 30 << 0.0 << true
4372 << 7 << 1 << ListRange(7, 17);
4373 QTest::newRow("insert multiple at middle")
4374 << 30 << 0.0 << true
4375 << 7 << 3 << ListRange(7, 17);
4376 QTest::newRow("insert multiple (> 1 row) at middle")
4377 << 30 << 0.0 << true
4378 << 7 << 5 << ListRange(7, 17);
4380 QTest::newRow("insert 1 at bottom")
4381 << 30 << 0.0 << true
4382 << 17 << 1 << ListRange(17, 17);
4383 QTest::newRow("insert multiple at bottom")
4384 << 30 << 0.0 << true
4385 << 17 << 3 << ListRange(17, 17);
4386 QTest::newRow("insert 1 at bottom, content y not 0")
4387 << 30 << 1.0 << true
4388 << 17 + 3 << 1 << ListRange(17 + 3, 17 + 3);
4389 QTest::newRow("insert multiple at bottom, content y not 0")
4390 << 30 << 1.0 << true
4391 << 17 + 3 << 3 << ListRange(17 + 3, 17 + 3);
4394 // items added after the last visible will not be animated in, since they
4395 // do not appear in the final view
4396 QTest::newRow("insert 1 after end")
4397 << 30 << 0.0 << false
4398 << 18 << 1 << ListRange();
4399 QTest::newRow("insert multiple after end")
4400 << 30 << 0.0 << false
4401 << 18 << 3 << ListRange();
4404 void tst_QQuickGridView::moveTransitions()
4406 QFETCH(int, initialItemCount);
4407 QFETCH(qreal, contentYRowOffset);
4408 QFETCH(qreal, rowOffsetAfterMove);
4409 QFETCH(int, moveFrom);
4410 QFETCH(int, moveTo);
4411 QFETCH(int, moveCount);
4412 QFETCH(ListRange, expectedDisplacedIndexes);
4414 // target and displaced items should pass through these points
4415 QPointF targetItems_transitionVia(-50, 50);
4416 QPointF displacedItems_transitionVia(100, 100);
4419 for (int i = 0; i < initialItemCount; i++)
4420 model.addItem("Original item" + QString::number(i), "");
4421 QaimModel model_targetItems_transitionVia;
4422 QaimModel model_displacedItems_transitionVia;
4424 QQuickView *canvas = getView();
4425 QQmlContext *ctxt = canvas->rootContext();
4426 ctxt->setContextProperty("testModel", &model);
4427 ctxt->setContextProperty("model_targetItems_transitionVia", &model_targetItems_transitionVia);
4428 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4429 ctxt->setContextProperty("targetItems_transitionVia", targetItems_transitionVia);
4430 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4431 canvas->setSource(testFileUrl("moveTransitions.qml"));
4434 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4435 QTRY_VERIFY(gridview != 0);
4436 QQuickItem *contentItem = gridview->contentItem();
4437 QVERIFY(contentItem != 0);
4440 if (contentYRowOffset != 0) {
4441 gridview->setContentY(contentYRowOffset * 60.0);
4442 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4445 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4447 // Items moving to *or* from visible positions should be animated.
4448 // Otherwise, they should not be animated.
4449 QList<QPair<QString, QString> > expectedTargetData;
4450 QList<int> targetIndexes;
4451 for (int i=moveFrom; i<moveFrom+moveCount; i++) {
4452 int toIndex = moveTo + (i - moveFrom);
4453 int firstVisibleIndex = (gridview->contentY() / 60) * 3;
4454 int lastVisibleIndex = (qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) - 1;
4455 if ((i >= firstVisibleIndex && i <= lastVisibleIndex)
4456 || (toIndex >= firstVisibleIndex && toIndex <= lastVisibleIndex)) {
4457 expectedTargetData << qMakePair(model.name(i), model.number(i));
4461 // ViewTransition.index provides the indices that items are moving to, not from
4462 targetIndexes = adjustIndexesForMove(targetIndexes, moveFrom, moveTo, moveCount);
4465 model.moveItems(moveFrom, moveTo, moveCount);
4467 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4468 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4469 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4471 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4473 // check the target and displaced items were animated
4474 model_targetItems_transitionVia.matchAgainst(expectedTargetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
4475 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4477 // check attached properties
4478 matchItemsAndIndexes(gridview->property("targetTrans_items").toMap(), model, targetIndexes);
4479 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4480 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4481 if (expectedDisplacedIndexes.isValid()) {
4482 // adjust expectedDisplacedIndexes to their final values after the move
4483 QList<int> displacedIndexes = adjustIndexesForMove(expectedDisplacedIndexes.indexes, moveFrom, moveTo, moveCount);
4484 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4485 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4486 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4489 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4490 int firstVisibleIndex = -1;
4491 for (int i=0; i<items.count(); i++) {
4492 if (items[i]->y() >= gridview->contentY()) {
4493 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4494 firstVisibleIndex = e.evaluate().toInt();
4498 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4500 // verify all items moved to the correct final positions
4501 qreal pixelOffset = 60 * rowOffsetAfterMove;
4502 for (int i=firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
4503 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4504 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4505 QCOMPARE(item->x(), (i%3)*80.0);
4506 QCOMPARE(item->y(), (i/3)*60.0 + pixelOffset);
4507 name = findItem<QQuickText>(contentItem, "textName", i);
4509 QTRY_COMPARE(name->text(), model.name(i));
4512 releaseView(canvas);
4515 void tst_QQuickGridView::moveTransitions_data()
4517 QTest::addColumn<int>("initialItemCount");
4518 QTest::addColumn<qreal>("contentYRowOffset");
4519 QTest::addColumn<qreal>("rowOffsetAfterMove");
4520 QTest::addColumn<int>("moveFrom");
4521 QTest::addColumn<int>("moveTo");
4522 QTest::addColumn<int>("moveCount");
4523 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4525 QTest::newRow("move from above view, outside visible items, move 1")
4527 << 1 << 10 << 1 << ListRange(6, 10);
4528 QTest::newRow("move from above view, outside visible items, move 1 (first item)")
4530 << 0 << 10 << 1 << ListRange(6, 10);
4531 QTest::newRow("move from above view, outside visible items, move multiple")
4533 << 1 << 10 << 3 << ListRange(13, 23);
4534 QTest::newRow("move from above view, mix of visible/non-visible")
4536 << 1 << 10 << 6 << (ListRange(7, 15) + ListRange(16, 23));
4537 QTest::newRow("move from above view, mix of visible/non-visible (move first)")
4539 << 0 << 10 << 6 << ListRange(16, 23);
4541 QTest::newRow("move within view, move 1 down")
4543 << 1 << 10 << 1 << ListRange(2, 10);
4544 QTest::newRow("move within view, move 1 down, move first item")
4546 << 0 << 10 << 1 << ListRange(1, 10);
4547 QTest::newRow("move within view, move 1 down, move first item, contentY not 0")
4549 << 0+6 << 10+6 << 1 << ListRange(1+6, 10+6);
4550 QTest::newRow("move within view, move 1 down, to last item")
4552 << 10 << 17 << 1 << ListRange(11, 17);
4553 QTest::newRow("move within view, move first->last")
4555 << 0 << 17 << 1 << ListRange(1, 17);
4557 QTest::newRow("move within view, move multiple down")
4559 << 1 << 10 << 3 << ListRange(4, 12);
4560 QTest::newRow("move within view, move multiple down, move first item")
4562 << 0 << 10 << 3 << ListRange(3, 12);
4563 QTest::newRow("move within view, move multiple down, move first item, contentY not 0")
4565 << 0+3 << 10+3 << 3 << ListRange(3+3, 12+3);
4566 QTest::newRow("move within view, move multiple down, displace last item")
4568 << 5 << 15 << 3 << ListRange(8, 17);
4569 QTest::newRow("move within view, move multiple down, move first->last")
4571 << 0 << 15 << 3 << ListRange(3, 17);
4573 QTest::newRow("move within view, move 1 up")
4575 << 10 << 1 << 1 << ListRange(1, 9);
4576 QTest::newRow("move within view, move 1 up, move to first index")
4578 << 10 << 0 << 1 << ListRange(0, 9);
4579 QTest::newRow("move within view, move 1 up, move to first index, contentY not 0")
4581 << 10+6 << 0+6 << 1 << ListRange(0+6, 9+6);
4582 QTest::newRow("move within view, move 1 up, move to first index, contentY not on item border")
4584 << 10+3 << 0+3 << 1 << ListRange(0+3, 9+3);
4585 QTest::newRow("move within view, move 1 up, move last item")
4587 << 17 << 10 << 1 << ListRange(10, 16);
4588 QTest::newRow("move within view, move 1 up, move last->first")
4590 << 17 << 0 << 1 << ListRange(0, 16);
4592 QTest::newRow("move within view, move multiple up")
4594 << 10 << 1 << 3 << ListRange(1, 9);
4595 QTest::newRow("move within view, move multiple (> 1 row) up")
4597 << 10 << 1 << 5 << ListRange(1, 9);
4598 QTest::newRow("move within view, move multiple up, move to first index")
4600 << 10 << 0 << 3 << ListRange(0, 9);
4601 QTest::newRow("move within view, move multiple up, move to first index, contentY not 0")
4603 << 10+3 << 0+3 << 3 << ListRange(0+3, 9+3);
4604 QTest::newRow("move within view, move multiple up (> 1 row), move to first index, contentY not on border")
4606 << 10+3 << 0+3 << 5 << ListRange(0+3, 9+3);
4607 QTest::newRow("move within view, move multiple up, move last item")
4609 << 15 << 5 << 3 << ListRange(5, 14);
4610 QTest::newRow("move within view, move multiple up, move last->first")
4612 << 15 << 0 << 3 << ListRange(0, 14);
4614 QTest::newRow("move from below view, move 1 up")
4616 << 20 << 5 << 1 << ListRange(5, 17);
4617 QTest::newRow("move from below view, move 1 up, move to top")
4619 << 20 << 0 << 1 << ListRange(0, 17);
4620 QTest::newRow("move from below view, move 1 up, move to top, contentY not 0")
4622 << 25 << 3 << 1 << ListRange(0+3, 17+3);
4623 QTest::newRow("move from below view, move multiple (> 1 row) up")
4625 << 20 << 5 << 5 << ListRange(5, 17);
4626 QTest::newRow("move from below view, move multiple up, move to top")
4628 << 20 << 0 << 3 << ListRange(0, 17);
4629 QTest::newRow("move from below view, move multiple up, move to top, contentY not 0")
4631 << 25 << 3 << 3 << ListRange(0+3, 17+3);
4633 QTest::newRow("move from below view, move 1 up, move to bottom")
4635 << 20 << 17 << 1 << ListRange(17, 17);
4636 QTest::newRow("move from below view, move 1 up, move to bottom, contentY not 0")
4638 << 25 << 17+3 << 1 << ListRange(17+3, 17+3);
4639 QTest::newRow("move from below view, move multiple up, move to to bottom")
4641 << 20 << 17 << 3 << ListRange(17, 17);
4642 QTest::newRow("move from below view, move multiple up, move to bottom, contentY not 0")
4644 << 25 << 17+3 << 3 << ListRange(17+3, 17+3);
4647 void tst_QQuickGridView::removeTransitions()
4649 QFETCH(int, initialItemCount);
4650 QFETCH(bool, shouldAnimateTargets);
4651 QFETCH(qreal, contentYRowOffset);
4652 QFETCH(int, removalIndex);
4653 QFETCH(int, removalCount);
4654 QFETCH(ListRange, expectedDisplacedIndexes);
4656 // added items should end here
4657 QPointF targetItems_transitionTo(-50, -50);
4659 // displaced items should pass through this points
4660 QPointF displacedItems_transitionVia(100, 100);
4663 for (int i = 0; i < initialItemCount; i++)
4664 model.addItem("Original item" + QString::number(i), "");
4665 QaimModel model_targetItems_transitionTo;
4666 QaimModel model_displacedItems_transitionVia;
4668 QQuickView *canvas = getView();
4669 QQmlContext *ctxt = canvas->rootContext();
4670 ctxt->setContextProperty("testModel", &model);
4671 ctxt->setContextProperty("model_targetItems_transitionTo", &model_targetItems_transitionTo);
4672 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4673 ctxt->setContextProperty("targetItems_transitionTo", targetItems_transitionTo);
4674 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4675 canvas->setSource(testFileUrl("removeTransitions.qml"));
4678 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4679 QTRY_VERIFY(gridview != 0);
4680 QQuickItem *contentItem = gridview->contentItem();
4681 QVERIFY(contentItem != 0);
4682 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4684 if (contentYRowOffset != 0) {
4685 gridview->setContentY(contentYRowOffset * 60.0);
4686 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4689 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4691 // only target items that are visible should be animated
4692 QList<QPair<QString, QString> > expectedTargetData;
4693 QList<int> targetIndexes;
4694 if (shouldAnimateTargets) {
4695 for (int i=removalIndex; i<removalIndex+removalCount; i++) {
4696 int firstVisibleIndex = (gridview->contentY() / 60.0)*3;
4697 int lastVisibleIndex = (qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) - 1;
4698 if (i >= firstVisibleIndex && i <= lastVisibleIndex) {
4699 expectedTargetData << qMakePair(model.name(i), model.number(i));
4703 QVERIFY(expectedTargetData.count() > 0);
4706 // calculate targetItems and expectedTargets before model changes
4707 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4708 QVariantMap expectedTargets;
4709 for (int i=0; i<targetIndexes.count(); i++)
4710 expectedTargets[model.name(targetIndexes[i])] = targetIndexes[i];
4713 model.removeItems(removalIndex, removalCount);
4714 QTRY_COMPARE(model.count(), gridview->count());
4716 if (shouldAnimateTargets || expectedDisplacedIndexes.isValid()) {
4717 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4718 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4719 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4721 // check the target and displaced items were animated
4722 model_targetItems_transitionTo.matchAgainst(expectedTargetData, "wasn't animated to target 'to' pos", "shouldn't have been animated to target 'to' pos");
4723 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4725 // check attached properties
4726 QCOMPARE(gridview->property("targetTrans_items").toMap(), expectedTargets);
4727 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4728 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4729 if (expectedDisplacedIndexes.isValid()) {
4730 // adjust expectedDisplacedIndexes to their final values after the move
4731 QList<int> displacedIndexes = adjustIndexesForRemoveDisplaced(expectedDisplacedIndexes.indexes, removalIndex, removalCount);
4732 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4733 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4734 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4737 QTRY_COMPARE(model_targetItems_transitionTo.count(), 0);
4738 QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0);
4741 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4742 int itemCount = items.count();
4743 int firstVisibleIndex = -1;
4744 for (int i=0; i<items.count(); i++) {
4745 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4746 int index = e.evaluate().toInt();
4747 if (firstVisibleIndex < 0 && items[i]->y() >= gridview->contentY())
4748 firstVisibleIndex = index;
4750 itemCount--; // exclude deleted items
4752 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4754 // verify all items moved to the correct final positions
4755 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
4756 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4757 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4758 QCOMPARE(item->x(), (i%3)*80.0);
4759 QCOMPARE(item->y(), gridview->contentY() + ((i-firstVisibleIndex)/3) * 60.0);
4760 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4762 QTRY_COMPARE(name->text(), model.name(i));
4765 releaseView(canvas);
4768 void tst_QQuickGridView::removeTransitions_data()
4770 QTest::addColumn<int>("initialItemCount");
4771 QTest::addColumn<qreal>("contentYRowOffset");
4772 QTest::addColumn<bool>("shouldAnimateTargets");
4773 QTest::addColumn<int>("removalIndex");
4774 QTest::addColumn<int>("removalCount");
4775 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4777 // All items that are visible following the remove operation should be animated.
4778 // Remove targets that are outside of the view should not be animated.
4780 // For a GridView, removing any number of items other than a full row before the start
4781 // should displace all items in the view
4782 QTest::newRow("remove 1 before start")
4783 << 30 << 2.0 << false
4784 << 2 << 1 << ListRange(6, 24); // 6-24 are displaced
4785 QTest::newRow("remove 1 row, before start")
4786 << 30 << 2.0 << false
4787 << 3 << 3 << ListRange();
4788 QTest::newRow("remove between 1-2 rows, before start")
4789 << 30 << 2.0 << false
4790 << 0 << 5 << ListRange(6, 25);
4791 QTest::newRow("remove 2 rows, before start")
4792 << 30 << 2.0 << false
4793 << 0 << 6 << ListRange();
4794 QTest::newRow("remove mix of before and after start")
4795 << 30 << 1.0 << true
4796 << 2 << 3 << ListRange(5, 23); // 5-23 are displaced into view
4799 QTest::newRow("remove 1 from start")
4800 << 30 << 0.0 << true
4801 << 0 << 1 << ListRange(1, 18); // 1-18 are displaced into view
4802 QTest::newRow("remove multiple from start")
4803 << 30 << 0.0 << true
4804 << 0 << 3 << ListRange(3, 20); // 3-18 are displaced into view
4805 QTest::newRow("remove 1 from start, content y not 0")
4806 << 30 << 1.0 << true
4807 << 3 << 1 << ListRange(1 + 3, 18 + 3);
4808 QTest::newRow("remove multiple from start, content y not 0")
4809 << 30 << 1.0 << true
4810 << 3 << 3 << ListRange(3 + 3, 20 + 3);
4813 QTest::newRow("remove 1 from middle")
4814 << 30 << 0.0 << true
4815 << 5 << 1 << ListRange(6, 18);
4816 QTest::newRow("remove multiple from middle")
4817 << 30 << 0.0 << true
4818 << 5 << 3 << ListRange(8, 20);
4821 QTest::newRow("remove 1 from bottom")
4822 << 30 << 0.0 << true
4823 << 17 << 1 << ListRange(18, 18);
4824 QTest::newRow("remove multiple (1 row) from bottom")
4825 << 30 << 0.0 << true
4826 << 15 << 3 << ListRange(18, 20);
4827 QTest::newRow("remove multiple (> 1 row) from bottom")
4828 << 30 << 0.0 << true
4829 << 15 << 5 << ListRange(20, 22);
4830 QTest::newRow("remove 1 from bottom, content y not 0")
4831 << 30 << 1.0 << true
4832 << 17 + 3 << 1 << ListRange(18 + 3, 18 + 3);
4833 QTest::newRow("remove multiple (1 row) from bottom, content y not 0")
4834 << 30 << 1.0 << true
4835 << 15 + 3 << 3 << ListRange(18 + 3, 20 + 3);
4838 QTest::newRow("remove 1 after end")
4839 << 30 << 0.0 << false
4840 << 18 << 1 << ListRange();
4841 QTest::newRow("remove multiple after end")
4842 << 30 << 0.0 << false
4843 << 18 << 3 << ListRange();
4846 void tst_QQuickGridView::displacedTransitions()
4848 QFETCH(bool, useDisplaced);
4849 QFETCH(bool, displacedEnabled);
4850 QFETCH(bool, useAddDisplaced);
4851 QFETCH(bool, addDisplacedEnabled);
4852 QFETCH(bool, useMoveDisplaced);
4853 QFETCH(bool, moveDisplacedEnabled);
4854 QFETCH(bool, useRemoveDisplaced);
4855 QFETCH(bool, removeDisplacedEnabled);
4856 QFETCH(ListChange, change);
4857 QFETCH(ListRange, expectedDisplacedIndexes);
4860 for (int i = 0; i < 30; i++)
4861 model.addItem("Original item" + QString::number(i), "");
4862 QaimModel model_displaced_transitionVia;
4863 QaimModel model_addDisplaced_transitionVia;
4864 QaimModel model_moveDisplaced_transitionVia;
4865 QaimModel model_removeDisplaced_transitionVia;
4867 QPointF displaced_transitionVia(-50, -100);
4868 QPointF addDisplaced_transitionVia(-150, 100);
4869 QPointF moveDisplaced_transitionVia(50, -100);
4870 QPointF removeDisplaced_transitionVia(150, 100);
4872 QQuickView *canvas = getView();
4873 QQmlContext *ctxt = canvas->rootContext();
4874 ctxt->setContextProperty("testModel", &model);
4875 ctxt->setContextProperty("model_displaced_transitionVia", &model_displaced_transitionVia);
4876 ctxt->setContextProperty("model_addDisplaced_transitionVia", &model_addDisplaced_transitionVia);
4877 ctxt->setContextProperty("model_moveDisplaced_transitionVia", &model_moveDisplaced_transitionVia);
4878 ctxt->setContextProperty("model_removeDisplaced_transitionVia", &model_removeDisplaced_transitionVia);
4879 ctxt->setContextProperty("displaced_transitionVia", displaced_transitionVia);
4880 ctxt->setContextProperty("addDisplaced_transitionVia", addDisplaced_transitionVia);
4881 ctxt->setContextProperty("moveDisplaced_transitionVia", moveDisplaced_transitionVia);
4882 ctxt->setContextProperty("removeDisplaced_transitionVia", removeDisplaced_transitionVia);
4883 ctxt->setContextProperty("useDisplaced", useDisplaced);
4884 ctxt->setContextProperty("displacedEnabled", displacedEnabled);
4885 ctxt->setContextProperty("useAddDisplaced", useAddDisplaced);
4886 ctxt->setContextProperty("addDisplacedEnabled", addDisplacedEnabled);
4887 ctxt->setContextProperty("useMoveDisplaced", useMoveDisplaced);
4888 ctxt->setContextProperty("moveDisplacedEnabled", moveDisplacedEnabled);
4889 ctxt->setContextProperty("useRemoveDisplaced", useRemoveDisplaced);
4890 ctxt->setContextProperty("removeDisplacedEnabled", removeDisplacedEnabled);
4891 canvas->setSource(testFileUrl("displacedTransitions.qml"));
4893 qApp->processEvents();
4895 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
4896 QTRY_VERIFY(gridview != 0);
4897 QQuickItem *contentItem = gridview->contentItem();
4898 QVERIFY(contentItem != 0);
4899 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4901 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4902 gridview->setProperty("displaceTransitionsDone", false);
4904 switch (change.type) {
4905 case ListChange::Inserted:
4907 QList<QPair<QString, QString> > targetItemData;
4908 for (int i=change.index; i<change.index + change.count; ++i)
4909 targetItemData << qMakePair(QString("new item %1").arg(i), QString::number(i));
4910 model.insertItems(change.index, targetItemData);
4911 QTRY_COMPARE(model.count(), gridview->count());
4914 case ListChange::Removed:
4915 model.removeItems(change.index, change.count);
4916 QTRY_COMPARE(model.count(), gridview->count());
4918 case ListChange::Moved:
4919 model.moveItems(change.index, change.to, change.count);
4920 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4922 case ListChange::SetCurrent:
4923 case ListChange::SetContentY:
4927 QVariantList resultTargetIndexes = gridview->property("displacedTargetIndexes").toList();
4928 QVariantList resultTargetItems = gridview->property("displacedTargetItems").toList();
4930 if ((useDisplaced && displacedEnabled)
4931 || (useAddDisplaced && addDisplacedEnabled)
4932 || (useMoveDisplaced && moveDisplacedEnabled)
4933 || (useRemoveDisplaced && removeDisplacedEnabled)) {
4934 QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
4936 // check the correct number of target items and indexes were received
4937 QCOMPARE(resultTargetIndexes.count(), expectedDisplacedIndexes.count());
4938 for (int i=0; i<resultTargetIndexes.count(); i++)
4939 QCOMPARE(resultTargetIndexes[i].value<QList<int> >().count(), change.count);
4940 QCOMPARE(resultTargetItems.count(), expectedDisplacedIndexes.count());
4941 for (int i=0; i<resultTargetItems.count(); i++)
4942 QCOMPARE(resultTargetItems[i].toList().count(), change.count);
4944 QCOMPARE(resultTargetIndexes.count(), 0);
4945 QCOMPARE(resultTargetItems.count(), 0);
4948 if (change.type == ListChange::Inserted && useAddDisplaced && addDisplacedEnabled)
4949 model_addDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with add displaced", "shouldn't have been animated with add displaced");
4951 QCOMPARE(model_addDisplaced_transitionVia.count(), 0);
4952 if (change.type == ListChange::Moved && useMoveDisplaced && moveDisplacedEnabled)
4953 model_moveDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with move displaced", "shouldn't have been animated with move displaced");
4955 QCOMPARE(model_moveDisplaced_transitionVia.count(), 0);
4956 if (change.type == ListChange::Removed && useRemoveDisplaced && removeDisplacedEnabled)
4957 model_removeDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with remove displaced", "shouldn't have been animated with remove displaced");
4959 QCOMPARE(model_removeDisplaced_transitionVia.count(), 0);
4961 if (useDisplaced && displacedEnabled
4962 && ( (change.type == ListChange::Inserted && (!useAddDisplaced || !addDisplacedEnabled))
4963 || (change.type == ListChange::Moved && (!useMoveDisplaced || !moveDisplacedEnabled))
4964 || (change.type == ListChange::Removed && (!useRemoveDisplaced || !removeDisplacedEnabled))) ) {
4965 model_displaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with generic displaced", "shouldn't have been animated with generic displaced");
4967 QCOMPARE(model_displaced_transitionVia.count(), 0);
4970 // verify all items moved to the correct final positions
4971 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4972 for (int i=0; i < model.count() && i < items.count(); ++i) {
4973 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4974 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4975 QCOMPARE(item->x(), (i%3)*80.0);
4976 QCOMPARE(item->y(), (i/3)*60.0);
4977 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4979 QTRY_COMPARE(name->text(), model.name(i));
4982 releaseView(canvas);
4985 void tst_QQuickGridView::displacedTransitions_data()
4987 QTest::addColumn<bool>("useDisplaced");
4988 QTest::addColumn<bool>("displacedEnabled");
4989 QTest::addColumn<bool>("useAddDisplaced");
4990 QTest::addColumn<bool>("addDisplacedEnabled");
4991 QTest::addColumn<bool>("useMoveDisplaced");
4992 QTest::addColumn<bool>("moveDisplacedEnabled");
4993 QTest::addColumn<bool>("useRemoveDisplaced");
4994 QTest::addColumn<bool>("removeDisplacedEnabled");
4995 QTest::addColumn<ListChange>("change");
4996 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4998 QTest::newRow("no displaced transitions at all")
5003 << ListChange::insert(0, 1) << ListRange(0, 17);
5005 QTest::newRow("just displaced")
5010 << ListChange::insert(0, 1) << ListRange(0, 17);
5012 QTest::newRow("just displaced (not enabled)")
5017 << ListChange::insert(0, 1) << ListRange(0, 17);
5019 QTest::newRow("displaced + addDisplaced")
5024 << ListChange::insert(0, 1) << ListRange(0, 17);
5026 QTest::newRow("displaced + addDisplaced (not enabled)")
5031 << ListChange::insert(0, 1) << ListRange(0, 17);
5033 QTest::newRow("displaced + moveDisplaced")
5038 << ListChange::move(0, 10, 1) << ListRange(1, 10);
5040 QTest::newRow("displaced + moveDisplaced (not enabled)")
5045 << ListChange::move(0, 10, 1) << ListRange(1, 10);
5047 QTest::newRow("displaced + removeDisplaced")
5052 << ListChange::remove(0, 1) << ListRange(1, 18);
5054 QTest::newRow("displaced + removeDisplaced (not enabled)")
5059 << ListChange::remove(0, 1) << ListRange(1, 18);
5062 QTest::newRow("displaced + add, should use generic displaced for a remove")
5067 << ListChange::remove(0, 1) << ListRange(1, 18);
5070 void tst_QQuickGridView::multipleTransitions()
5072 // Tests that if you interrupt a transition in progress with another action that
5073 // cancels the previous transition, the resulting items are still placed correctly.
5075 QFETCH(int, initialCount);
5076 QFETCH(qreal, contentY);
5077 QFETCH(QList<ListChange>, changes);
5078 QFETCH(bool, enableAddTransitions);
5079 QFETCH(bool, enableMoveTransitions);
5080 QFETCH(bool, enableRemoveTransitions);
5081 QFETCH(bool, rippleAddDisplaced);
5083 // add transitions on the left, moves on the right
5084 QPointF addTargets_transitionFrom(-50, -50);
5085 QPointF addDisplaced_transitionFrom(-50, 50);
5086 QPointF moveTargets_transitionFrom(50, -50);
5087 QPointF moveDisplaced_transitionFrom(50, 50);
5088 QPointF removeTargets_transitionTo(-100, 300);
5089 QPointF removeDisplaced_transitionFrom(100, 300);
5092 for (int i = 0; i < initialCount; i++)
5093 model.addItem("Original item" + QString::number(i), "");
5095 QQuickView *canvas = getView();
5096 QQmlContext *ctxt = canvas->rootContext();
5097 ctxt->setContextProperty("testModel", &model);
5098 ctxt->setContextProperty("addTargets_transitionFrom", addTargets_transitionFrom);
5099 ctxt->setContextProperty("addDisplaced_transitionFrom", addDisplaced_transitionFrom);
5100 ctxt->setContextProperty("moveTargets_transitionFrom", moveTargets_transitionFrom);
5101 ctxt->setContextProperty("moveDisplaced_transitionFrom", moveDisplaced_transitionFrom);
5102 ctxt->setContextProperty("removeTargets_transitionTo", removeTargets_transitionTo);
5103 ctxt->setContextProperty("removeDisplaced_transitionFrom", removeDisplaced_transitionFrom);
5104 ctxt->setContextProperty("enableAddTransitions", enableAddTransitions);
5105 ctxt->setContextProperty("enableMoveTransitions", enableMoveTransitions);
5106 ctxt->setContextProperty("enableRemoveTransitions", enableRemoveTransitions);
5107 ctxt->setContextProperty("rippleAddDisplaced", rippleAddDisplaced);
5108 canvas->setSource(testFileUrl("multipleTransitions.qml"));
5110 QTest::qWaitForWindowShown(canvas);
5112 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
5113 QTRY_VERIFY(gridview != 0);
5114 QQuickItem *contentItem = gridview->contentItem();
5115 QVERIFY(contentItem != 0);
5116 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5118 if (contentY != 0) {
5119 gridview->setContentY(contentY);
5120 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5123 int timeBetweenActions = canvas->rootObject()->property("timeBetweenActions").toInt();
5125 for (int i=0; i<changes.count(); i++) {
5126 switch (changes[i].type) {
5127 case ListChange::Inserted:
5129 QList<QPair<QString, QString> > targetItems;
5130 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
5131 targetItems << qMakePair(QString("new item %1").arg(j), QString::number(j));
5132 model.insertItems(changes[i].index, targetItems);
5133 QTRY_COMPARE(model.count(), gridview->count());
5134 if (i == changes.count() - 1) {
5135 QTRY_VERIFY(!gridview->property("runningAddTargets").toBool());
5136 QTRY_VERIFY(!gridview->property("runningAddDisplaced").toBool());
5138 QTest::qWait(timeBetweenActions);
5142 case ListChange::Removed:
5143 model.removeItems(changes[i].index, changes[i].count);
5144 QTRY_COMPARE(model.count(), gridview->count());
5145 if (i == changes.count() - 1) {
5146 QTRY_VERIFY(!gridview->property("runningRemoveTargets").toBool());
5147 QTRY_VERIFY(!gridview->property("runningRemoveDisplaced").toBool());
5149 QTest::qWait(timeBetweenActions);
5152 case ListChange::Moved:
5153 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
5154 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5155 if (i == changes.count() - 1) {
5156 QTRY_VERIFY(!gridview->property("runningMoveTargets").toBool());
5157 QTRY_VERIFY(!gridview->property("runningMoveDisplaced").toBool());
5159 QTest::qWait(timeBetweenActions);
5162 case ListChange::SetCurrent:
5163 gridview->setCurrentIndex(changes[i].index);
5164 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5166 case ListChange::SetContentY:
5167 gridview->setContentY(changes[i].pos);
5168 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5172 QCOMPARE(gridview->count(), model.count());
5174 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5175 int firstVisibleIndex = -1;
5176 for (int i=0; i<items.count(); i++) {
5177 if (items[i]->y() >= contentY) {
5178 QQmlExpression e(qmlContext(items[i]), items[i], "index");
5179 firstVisibleIndex = e.evaluate().toInt();
5183 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
5185 // verify all items moved to the correct final positions
5186 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
5187 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
5188 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5189 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5190 QTRY_COMPARE(item->x(), (i%3)*80.0);
5191 QTRY_COMPARE(item->y(), (i/3)*60.0);
5192 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5194 QTRY_COMPARE(name->text(), model.name(i));
5197 releaseView(canvas);
5200 void tst_QQuickGridView::multipleTransitions_data()
5202 QTest::addColumn<int>("initialCount");
5203 QTest::addColumn<qreal>("contentY");
5204 QTest::addColumn<QList<ListChange> >("changes");
5205 QTest::addColumn<bool>("enableAddTransitions");
5206 QTest::addColumn<bool>("enableMoveTransitions");
5207 QTest::addColumn<bool>("enableRemoveTransitions");
5208 QTest::addColumn<bool>("rippleAddDisplaced");
5210 // the added item and displaced items should move to final dest correctly
5211 QTest::newRow("add item, then move it immediately") << 10 << 0.0 << (QList<ListChange>()
5212 << ListChange::insert(0, 1)
5213 << ListChange::move(0, 3, 1)
5215 << true << true << true << false;
5217 // items affected by the add should change from move to add transition
5218 QTest::newRow("move, then insert item before the moved item") << 20 << 0.0 << (QList<ListChange>()
5219 << ListChange::move(1, 10, 3)
5220 << ListChange::insert(0, 1)
5222 << true << true << true << false;
5224 // items should be placed correctly if you trigger a transition then refill for that index
5225 QTest::newRow("add at 0, flick down, flick back to top and add at 0 again") << 20 << 0.0 << (QList<ListChange>()
5226 << ListChange::insert(0, 1)
5227 << ListChange::setContentY(160.0)
5228 << ListChange::setContentY(0.0)
5229 << ListChange::insert(0, 1)
5231 << true << true << true << false;
5233 QTest::newRow("insert then remove same index, with ripple effect on add displaced") << 20 << 0.0 << (QList<ListChange>()
5234 << ListChange::insert(1, 1)
5235 << ListChange::remove(1, 1)
5237 << true << true << true << true;
5239 // if item is removed while undergoing a displaced transition, all other items should end up at their correct positions,
5240 // even if a remove-displace transition is not present to re-animate them
5241 QTest::newRow("insert then remove, with remove disabled") << 20 << 0.0 << (QList<ListChange>()
5242 << ListChange::insert(0, 1)
5243 << ListChange::remove(2, 1)
5245 << true << true << false << false;
5247 // if last item is not flush with the edge of the view, it should still be refilled in correctly after a
5248 // remove has changed the position of where it will move to
5249 QTest::newRow("insert twice then remove, with remove disabled") << 20 << 0.0 << (QList<ListChange>()
5250 << ListChange::setContentY(-10.0)
5251 << ListChange::insert(0, 1)
5252 << ListChange::insert(0, 1)
5253 << ListChange::remove(2, 1)
5255 << true << true << false << false;
5258 void tst_QQuickGridView::multipleDisplaced()
5260 // multiple move() operations should only restart displace transitions for items that
5261 // moved from previously set positions, and not those that have moved from their current
5262 // item positions (which may e.g. still be changing from easing bounces in the last transition)
5265 for (int i = 0; i < 30; i++)
5266 model.addItem("Original item" + QString::number(i), "");
5268 QQuickView *canvas = createView();
5269 QQmlContext *ctxt = canvas->rootContext();
5270 ctxt->setContextProperty("testModel", &model);
5271 canvas->setSource(testFileUrl("multipleDisplaced.qml"));
5273 QTest::qWaitForWindowShown(canvas);
5275 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
5276 QTRY_VERIFY(gridview != 0);
5277 QQuickItem *contentItem = gridview->contentItem();
5278 QVERIFY(contentItem != 0);
5279 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5281 model.moveItems(12, 8, 1);
5282 QTest::qWait(canvas->rootObject()->property("duration").toInt() / 2);
5283 model.moveItems(8, 3, 1);
5284 QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
5286 QVariantMap transitionsStarted = gridview->property("displaceTransitionsStarted").toMap();
5287 foreach (const QString &name, transitionsStarted.keys()) {
5288 QVERIFY2(transitionsStarted[name] == 1,
5289 QTest::toString(QString("%1 was displaced %2 times").arg(name).arg(transitionsStarted[name].toInt())));
5292 // verify all items moved to the correct final positions
5293 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5294 for (int i=0; i < model.count() && i < items.count(); ++i) {
5295 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5296 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5297 QTRY_COMPARE(item->x(), (i%3)*80.0);
5298 QTRY_COMPARE(item->y(), (i/3)*60.0);
5299 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5301 QTRY_COMPARE(name->text(), model.name(i));
5307 void tst_QQuickGridView::cacheBuffer()
5309 QQuickView *canvas = createView();
5312 for (int i = 0; i < 90; i++)
5313 model.addItem("Item" + QString::number(i), "");
5315 QQmlContext *ctxt = canvas->rootContext();
5316 ctxt->setContextProperty("testModel", &model);
5317 ctxt->setContextProperty("testRightToLeft", QVariant(false));
5318 ctxt->setContextProperty("testTopToBottom", QVariant(false));
5320 canvas->setSource(testFileUrl("gridview1.qml"));
5322 qApp->processEvents();
5324 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
5325 QVERIFY(gridview != 0);
5327 QQuickItem *contentItem = gridview->contentItem();
5328 QVERIFY(contentItem != 0);
5329 QVERIFY(gridview->delegate() != 0);
5330 QVERIFY(gridview->model() != 0);
5332 // Confirm items positioned correctly
5333 int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
5334 for (int i = 0; i < model.count() && i < itemCount; ++i) {
5335 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5336 QTRY_COMPARE(item->x(), (i%3)*80.0);
5337 QTRY_COMPARE(item->y(), (i/3)*60.0);
5340 QQmlIncubationController controller;
5341 canvas->engine()->setIncubationController(&controller);
5343 canvas->rootObject()->setProperty("cacheBuffer", 200);
5344 QTRY_VERIFY(gridview->cacheBuffer() == 200);
5346 // items will be created one at a time
5347 for (int i = itemCount; i < qMin(itemCount+9,model.count()); ++i) {
5348 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
5349 QQuickItem *item = 0;
5352 controller.incubateWhile(&b);
5353 item = findItem<QQuickItem>(gridview, "wrapper", i);
5359 controller.incubateWhile(&b);
5362 int newItemCount = 0;
5363 newItemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
5365 // Confirm items positioned correctly
5366 for (int i = 0; i < model.count() && i < newItemCount; ++i) {
5367 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5369 QTRY_COMPARE(item->x(), (i%3)*80.0);
5370 QTRY_COMPARE(item->y(), (i/3)*60.0);
5373 // move view and confirm items in view are visible immediately and outside are created async
5374 gridview->setContentY(300);
5376 for (int i = 15; i < 34; ++i) { // 34 due to staggered item creation
5377 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5379 QTRY_COMPARE(item->x(), (i%3)*80.0);
5380 QTRY_COMPARE(item->y(), (i/3)*60.0);
5383 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == 0);
5385 // ensure buffered items are created
5386 for (int i = 34; i < qMin(44,model.count()); ++i) {
5387 QQuickItem *item = 0;
5389 qGuiApp->processEvents(); // allow refill to happen
5391 controller.incubateWhile(&b);
5392 item = findItem<QQuickItem>(gridview, "wrapper", i);
5398 controller.incubateWhile(&b);
5404 void tst_QQuickGridView::asynchronous()
5406 QQuickView *canvas = createView();
5408 QQmlIncubationController controller;
5409 canvas->engine()->setIncubationController(&controller);
5411 canvas->setSource(testFileUrl("asyncloader.qml"));
5413 QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
5414 QVERIFY(rootObject);
5416 QQuickGridView *gridview = 0;
5419 controller.incubateWhile(&b);
5420 gridview = rootObject->findChild<QQuickGridView*>("view");
5423 // items will be created one at a time
5424 for (int i = 0; i < 12; ++i) {
5425 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
5426 QQuickItem *item = 0;
5429 controller.incubateWhile(&b);
5430 item = findItem<QQuickItem>(gridview, "wrapper", i);
5436 controller.incubateWhile(&b);
5439 // verify positioning
5440 QQuickItem *contentItem = gridview->contentItem();
5441 for (int i = 0; i < 12; ++i) {
5442 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5443 if (!item) qWarning() << "Item" << i << "not found";
5444 QVERIFY(item->x() == (i%3)*100);
5445 QVERIFY(item->y() == (i/3)*100);
5451 void tst_QQuickGridView::unrequestedVisibility()
5454 for (int i = 0; i < 30; i++)
5455 model.addItem("Item" + QString::number(i), QString::number(i));
5457 QQuickView *canvas = new QQuickView(0);
5458 canvas->setGeometry(0,0,240,320);
5460 QQmlContext *ctxt = canvas->rootContext();
5461 ctxt->setContextProperty("testModel", &model);
5462 ctxt->setContextProperty("testWrap", QVariant(false));
5464 canvas->setSource(testFileUrl("unrequestedItems.qml"));
5468 qApp->processEvents();
5470 QQuickGridView *leftview = findItem<QQuickGridView>(canvas->rootObject(), "leftGrid");
5471 QTRY_VERIFY(leftview != 0);
5473 QQuickGridView *rightview = findItem<QQuickGridView>(canvas->rootObject(), "rightGrid");
5474 QTRY_VERIFY(rightview != 0);
5476 QQuickItem *leftContent = leftview->contentItem();
5477 QTRY_VERIFY(leftContent != 0);
5479 QQuickItem *rightContent = rightview->contentItem();
5480 QTRY_VERIFY(rightContent != 0);
5482 rightview->setCurrentIndex(12);
5484 QTRY_COMPARE(leftview->contentY(), 0.0);
5485 QTRY_COMPARE(rightview->contentY(), 240.0);
5489 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5490 QCOMPARE(item->isVisible(), true);
5491 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5492 QCOMPARE(item->isVisible(), false);
5494 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5495 QCOMPARE(item->isVisible(), false);
5496 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5497 QCOMPARE(item->isVisible(), true);
5499 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 9));
5500 QCOMPARE(item->isVisible(), true);
5501 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 10));
5502 QCOMPARE(item->isVisible(), false);
5503 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 3));
5504 QCOMPARE(item->isVisible(), false);
5505 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 4));
5506 QCOMPARE(item->isVisible(), true);
5508 rightview->setCurrentIndex(0);
5510 QTRY_COMPARE(leftview->contentY(), 0.0);
5511 QTRY_COMPARE(rightview->contentY(), 0.0);
5513 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5514 QCOMPARE(item->isVisible(), true);
5515 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5516 QTRY_COMPARE(item->isVisible(), true);
5518 QVERIFY(!findItem<QQuickItem>(leftContent, "wrapper", 11));
5519 QVERIFY(!findItem<QQuickItem>(rightContent, "wrapper", 11));
5521 leftview->setCurrentIndex(12);
5523 QTRY_COMPARE(leftview->contentY(), 240.0);
5524 QTRY_COMPARE(rightview->contentY(), 0.0);
5526 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5527 QTRY_COMPARE(item->isVisible(), false);
5528 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5529 QCOMPARE(item->isVisible(), true);
5531 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5532 QCOMPARE(item->isVisible(), true);
5533 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5534 QCOMPARE(item->isVisible(), 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);
5545 // move a non-visible item into view
5546 model.moveItems(10, 9, 1);
5547 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5549 QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5550 QCOMPARE(item->isVisible(), false);
5551 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5552 QCOMPARE(item->isVisible(), true);
5554 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5555 QCOMPARE(item->isVisible(), true);
5556 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5557 QCOMPARE(item->isVisible(), false);
5559 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5560 QCOMPARE(item->isVisible(), false);
5561 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5562 QCOMPARE(item->isVisible(), true);
5563 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5564 QCOMPARE(item->isVisible(), true);
5565 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5566 QCOMPARE(item->isVisible(), false);
5568 // move a visible item out of view
5569 model.moveItems(5, 3, 1);
5570 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5572 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5573 QCOMPARE(item->isVisible(), false);
5574 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5575 QCOMPARE(item->isVisible(), true);
5576 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5577 QCOMPARE(item->isVisible(), true);
5578 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5579 QCOMPARE(item->isVisible(), false);
5581 // move a non-visible item into view
5582 model.moveItems(3, 5, 1);
5583 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5585 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5586 QCOMPARE(item->isVisible(), false);
5587 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5588 QCOMPARE(item->isVisible(), true);
5589 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5590 QCOMPARE(item->isVisible(), true);
5591 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5592 QCOMPARE(item->isVisible(), false);
5594 // move a visible item out of view
5595 model.moveItems(9, 10, 1);
5596 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5598 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5599 QCOMPARE(item->isVisible(), false);
5600 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5601 QCOMPARE(item->isVisible(), true);
5602 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5603 QCOMPARE(item->isVisible(), true);
5604 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5605 QCOMPARE(item->isVisible(), false);
5607 // move a non-visible item into view
5608 model.moveItems(10, 9, 1);
5609 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5611 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5612 QCOMPARE(item->isVisible(), false);
5613 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5614 QCOMPARE(item->isVisible(), true);
5615 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5616 QCOMPARE(item->isVisible(), true);
5617 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5618 QCOMPARE(item->isVisible(), false);
5623 QList<int> tst_QQuickGridView::toIntList(const QVariantList &list)
5627 for (int i=0; i<list.count(); i++) {
5628 ret << list[i].toInt(&ok);
5630 qWarning() << "tst_QQuickGridView::toIntList(): not a number:" << list[i];
5636 void tst_QQuickGridView::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
5638 for (int i=0; i<indexLists.count(); i++) {
5639 QSet<int> current = indexLists[i].value<QList<int> >().toSet();
5640 if (current != expectedIndexes.toSet())
5641 qDebug() << "Cannot match actual targets" << current << "with expected" << expectedIndexes;
5642 QCOMPARE(current, expectedIndexes.toSet());
5646 void tst_QQuickGridView::matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes)
5648 for (QVariantMap::const_iterator it = items.begin(); it != items.end(); ++it) {
5649 QVERIFY(it.value().type() == QVariant::Int);
5650 QString name = it.key();
5651 int itemIndex = it.value().toInt();
5652 QVERIFY2(expectedIndexes.contains(itemIndex), QTest::toString(QString("Index %1 not found in expectedIndexes").arg(itemIndex)));
5653 if (model.name(itemIndex) != name)
5654 qDebug() << itemIndex;
5655 QCOMPARE(model.name(itemIndex), name);
5657 QCOMPARE(items.count(), expectedIndexes.count());
5660 void tst_QQuickGridView::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
5662 for (int i=0; i<itemLists.count(); i++) {
5663 QVariantList current = itemLists[i].toList();
5664 for (int j=0; j<current.count(); j++) {
5665 QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
5666 QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1").arg(j)));
5667 QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1").arg(j)));
5669 QCOMPARE(current.count(), expectedItems.count());
5673 QTEST_MAIN(tst_QQuickGridView)
5675 #include "tst_qquickgridview.moc"