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 <QtQml/qqmlcontext.h>
51 #include <QtQuick/private/qquickitem_p.h>
52 #include <QtQuick/private/qquickgridview_p.h>
53 #include <QtQuick/private/qquicktext_p.h>
54 #include <QtQuick/private/qquickvisualitemmodel_p.h>
55 #include <QtQml/private/qquicklistmodel_p.h>
56 #include "../../shared/util.h"
57 #include "../shared/viewtestutil.h"
58 #include "../shared/visualtestutil.h"
59 #include <QtGui/qguiapplication.h>
60 #include "qplatformdefs.h"
62 Q_DECLARE_METATYPE(QQuickGridView::Flow)
63 Q_DECLARE_METATYPE(Qt::LayoutDirection)
64 Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection)
65 Q_DECLARE_METATYPE(QQuickItemView::PositionMode)
66 Q_DECLARE_METATYPE(Qt::Key)
68 using namespace QQuickViewTestUtil;
69 using namespace QQuickVisualTestUtil;
73 class tst_QQuickGridView : public QQmlDataTest
81 void cleanupTestCase();
84 void inserted_basic();
85 void inserted_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom);
86 void inserted_defaultLayout_data();
87 void insertBeforeVisible();
88 void insertBeforeVisible_data();
90 void removed_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom);
91 void removed_defaultLayout_data();
92 void addOrRemoveBeforeVisible();
93 void addOrRemoveBeforeVisible_data();
95 void moved_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom);
96 void moved_defaultLayout_data();
97 void multipleChanges_condensed() { multipleChanges(true); }
98 void multipleChanges_condensed_data() { multipleChanges_data(); }
99 void multipleChanges_uncondensed() { multipleChanges(false); }
100 void multipleChanges_uncondensed_data() { multipleChanges_data(); }
101 void swapWithFirstItem();
104 void noCurrentIndex();
105 void keyNavigation();
106 void keyNavigation_data();
107 void defaultValues();
109 void propertyChanges();
110 void componentChanges();
112 void positionViewAtBeginningEnd();
113 void positionViewAtIndex();
114 void positionViewAtIndex_data();
119 void enforceRange_rightToLeft();
121 void manualHighlight();
124 void initialZValues();
129 void resetModel_headerFooter();
130 void resizeViewAndRepaint();
132 void resizeGrid_data();
133 void changeColumnCount();
134 void indexAt_itemAt_data();
135 void indexAt_itemAt();
139 void onRemove_data();
142 void creationContext();
143 void snapToRow_data();
145 void snapOneRow_data();
150 void unrequestedVisibility();
152 void populateTransitions();
153 void populateTransitions_data();
154 void addTransitions();
155 void addTransitions_data();
156 void moveTransitions();
157 void moveTransitions_data();
158 void removeTransitions();
159 void removeTransitions_data();
160 void displacedTransitions();
161 void displacedTransitions_data();
162 void multipleTransitions();
163 void multipleTransitions_data();
164 void multipleDisplaced();
166 void inserted_leftToRight_RtL_TtB();
167 void inserted_leftToRight_RtL_TtB_data();
168 void inserted_leftToRight_LtR_BtT();
169 void inserted_leftToRight_LtR_BtT_data();
170 void inserted_leftToRight_RtL_BtT();
171 void inserted_leftToRight_RtL_BtT_data();
172 void inserted_topToBottom_LtR_TtB();
173 void inserted_topToBottom_LtR_TtB_data();
174 void inserted_topToBottom_RtL_TtB();
175 void inserted_topToBottom_RtL_TtB_data();
176 void inserted_topToBottom_LtR_BtT();
177 void inserted_topToBottom_LtR_BtT_data();
178 void inserted_topToBottom_RtL_BtT();
179 void inserted_topToBottom_RtL_BtT_data();
181 void removed_leftToRight_RtL_TtB();
182 void removed_leftToRight_RtL_TtB_data();
183 void removed_leftToRight_LtR_BtT();
184 void removed_leftToRight_LtR_BtT_data();
185 void removed_leftToRight_RtL_BtT();
186 void removed_leftToRight_RtL_BtT_data();
187 void removed_topToBottom_LtR_TtB();
188 void removed_topToBottom_LtR_TtB_data();
189 void removed_topToBottom_RtL_TtB();
190 void removed_topToBottom_RtL_TtB_data();
191 void removed_topToBottom_LtR_BtT();
192 void removed_topToBottom_LtR_BtT_data();
193 void removed_topToBottom_RtL_BtT();
194 void removed_topToBottom_RtL_BtT_data();
196 void moved_leftToRight_RtL_TtB();
197 void moved_leftToRight_RtL_TtB_data();
198 void moved_leftToRight_LtR_BtT();
199 void moved_leftToRight_LtR_BtT_data();
200 void moved_leftToRight_RtL_BtT();
201 void moved_leftToRight_RtL_BtT_data();
202 void moved_topToBottom_LtR_TtB();
203 void moved_topToBottom_LtR_TtB_data();
204 void moved_topToBottom_RtL_TtB();
205 void moved_topToBottom_RtL_TtB_data();
206 void moved_topToBottom_LtR_BtT();
207 void moved_topToBottom_LtR_BtT_data();
208 void moved_topToBottom_RtL_BtT();
209 void moved_topToBottom_RtL_BtT_data();
212 QList<int> toIntList(const QVariantList &list);
213 void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes);
214 void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes);
215 void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems);
217 void multipleChanges(bool condensed);
218 void multipleChanges_data();
220 QPointF expectedItemPos(QQuickGridView *grid, int index, qreal rowOffset = 0) {
223 if (grid->flow() == QQuickGridView::FlowLeftToRight) {
224 int columns = grid->width() / grid->cellWidth();
225 x = (index % columns) * grid->cellWidth();
226 y = (index / columns) * grid->cellHeight();
227 if (grid->effectiveLayoutDirection() == Qt::RightToLeft) {
228 int col = (index % columns) * grid->cellWidth();
229 x = grid->cellWidth() * (columns - 1) - col;
232 qreal offset = grid->cellHeight() * rowOffset;
233 if (grid->verticalLayoutDirection() == QQuickItemView::TopToBottom)
236 y = -grid->cellHeight() - y - offset;
238 int rows = grid->height() / grid->cellHeight();
239 x = (index / rows) * grid->cellWidth();
240 y = (index % rows) * grid->cellHeight();
241 if (grid->effectiveLayoutDirection() == Qt::RightToLeft)
242 x = -x - grid->cellWidth();
244 qreal offset = grid->cellWidth() * rowOffset;
245 if (grid->effectiveLayoutDirection() == Qt::RightToLeft)
249 if (grid->verticalLayoutDirection() == QQuickItemView::BottomToTop)
250 y = -grid->cellHeight() - y;
252 return QPointF(x, y);
255 // Sets contentY (or contentX in TopToBottom flow) according to given row offset
256 // (in LeftToRight flow) or col offset (in TopToBottom).
257 bool setContentPos(QQuickGridView *gridview, qreal rowOrColOffset) {
258 bool contentPosChanged = (rowOrColOffset != 0);
259 qreal contentOffset = gridview->flow() == QQuickGridView::FlowLeftToRight
260 ? rowOrColOffset * gridview->cellHeight()
261 : rowOrColOffset * gridview->cellWidth();
263 if (gridview->flow() == QQuickGridView::FlowLeftToRight) {
264 if (gridview->verticalLayoutDirection() == QQuickItemView::BottomToTop)
265 contentOffset = -gridview->height() - contentOffset;
267 if (gridview->effectiveLayoutDirection() == Qt::RightToLeft)
268 contentOffset = -gridview->width() - contentOffset;
270 if (gridview->flow() == QQuickGridView::FlowLeftToRight)
271 gridview->setContentY(contentOffset);
273 gridview->setContentX(contentOffset);
274 return contentPosChanged;
278 QQuickView *getView() {
280 if (QString(QTest::currentTestFunction()) != testForView) {
284 m_view->setSource(QUrl());
289 testForView = QTest::currentTestFunction();
290 m_view = createView();
293 void releaseView(QQuickView *view) {
294 Q_ASSERT(view == m_view);
295 m_view->setSource(QUrl());
298 QQuickView *getView() {
301 void releaseView(QQuickView *view) {
310 tst_QQuickGridView::tst_QQuickGridView() : m_view(0)
314 void tst_QQuickGridView::init()
317 if (m_view && QString(QTest::currentTestFunction()) != testForView) {
318 testForView = QString();
325 void tst_QQuickGridView::cleanupTestCase()
328 testForView = QString();
334 void tst_QQuickGridView::items()
336 QQuickView *window = createView();
339 model.addItem("Fred", "12345");
340 model.addItem("John", "2345");
341 model.addItem("Bob", "54321");
342 model.addItem("Billy", "22345");
343 model.addItem("Sam", "2945");
344 model.addItem("Ben", "04321");
345 model.addItem("Jim", "0780");
347 QQmlContext *ctxt = window->rootContext();
348 ctxt->setContextProperty("testModel", &model);
350 window->setSource(testFileUrl("gridview1.qml"));
351 qApp->processEvents();
353 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
354 QTRY_VERIFY(gridview != 0);
356 QQuickItem *contentItem = gridview->contentItem();
357 QTRY_VERIFY(contentItem != 0);
359 QTRY_COMPARE(gridview->count(), model.count());
360 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
361 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
363 for (int i = 0; i < model.count(); ++i) {
364 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
365 QTRY_VERIFY(name != 0);
366 QTRY_COMPARE(name->text(), model.name(i));
367 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
368 QTRY_VERIFY(number != 0);
369 QTRY_COMPARE(number->text(), model.number(i));
372 // set an empty model and confirm that items are destroyed
374 ctxt->setContextProperty("testModel", &model2);
376 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
377 QTRY_VERIFY(itemCount == 0);
382 void tst_QQuickGridView::changed()
384 QQuickView *window = createView();
387 model.addItem("Fred", "12345");
388 model.addItem("John", "2345");
389 model.addItem("Bob", "54321");
390 model.addItem("Billy", "22345");
391 model.addItem("Sam", "2945");
392 model.addItem("Ben", "04321");
393 model.addItem("Jim", "0780");
395 QQmlContext *ctxt = window->rootContext();
396 ctxt->setContextProperty("testModel", &model);
398 window->setSource(testFileUrl("gridview1.qml"));
399 qApp->processEvents();
401 QQuickFlickable *gridview = findItem<QQuickFlickable>(window->rootObject(), "grid");
402 QTRY_VERIFY(gridview != 0);
404 QQuickItem *contentItem = gridview->contentItem();
405 QTRY_VERIFY(contentItem != 0);
407 model.modifyItem(1, "Will", "9876");
408 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
409 QTRY_VERIFY(name != 0);
410 QTRY_COMPARE(name->text(), model.name(1));
411 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
412 QTRY_VERIFY(number != 0);
413 QTRY_COMPARE(number->text(), model.number(1));
418 void tst_QQuickGridView::inserted_basic()
420 QQuickView *window = createView();
424 model.addItem("Fred", "12345");
425 model.addItem("John", "2345");
426 model.addItem("Bob", "54321");
428 window->rootContext()->setContextProperty("testModel", &model);
429 window->setSource(testFileUrl("gridview1.qml"));
430 qApp->processEvents();
432 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
433 QTRY_VERIFY(gridview != 0);
435 QQuickItem *contentItem = gridview->contentItem();
436 QTRY_VERIFY(contentItem != 0);
438 model.insertItem(1, "Will", "9876");
440 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
441 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
443 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
444 QTRY_VERIFY(name != 0);
445 QTRY_COMPARE(name->text(), model.name(1));
446 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
447 QTRY_VERIFY(number != 0);
448 QTRY_COMPARE(number->text(), model.number(1));
450 // Checks that onAdd is called
451 int added = window->rootObject()->property("added").toInt();
452 QTRY_COMPARE(added, 1);
454 // Confirm items positioned correctly
455 for (int i = 0; i < model.count(); ++i) {
456 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
457 QTRY_COMPARE(item->x(), (i%3)*80.0);
458 QTRY_COMPARE(item->y(), (i/3)*60.0);
461 model.insertItem(0, "Foo", "1111"); // zero index, and current item
463 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
465 name = findItem<QQuickText>(contentItem, "textName", 0);
466 QTRY_VERIFY(name != 0);
467 QTRY_COMPARE(name->text(), model.name(0));
468 number = findItem<QQuickText>(contentItem, "textNumber", 0);
469 QTRY_VERIFY(number != 0);
470 QTRY_COMPARE(number->text(), model.number(0));
472 QTRY_COMPARE(gridview->currentIndex(), 1);
474 // Confirm items positioned correctly
475 for (int i = 0; i < model.count(); ++i) {
476 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
477 QTRY_VERIFY(item->x() == (i%3)*80);
478 QTRY_VERIFY(item->y() == (i/3)*60);
481 for (int i = model.count(); i < 30; ++i)
482 model.insertItem(i, "Hello", QString::number(i));
484 gridview->setContentY(120);
486 // Insert item outside visible area
487 model.insertItem(1, "Hello", "1324");
489 QTRY_VERIFY(gridview->contentY() == 120);
494 void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow,
495 Qt::LayoutDirection horizLayout,
496 QQuickItemView::VerticalLayoutDirection verticalLayout)
498 QFETCH(qreal, contentYRowOffset);
499 QFETCH(int, insertIndex);
500 QFETCH(int, insertCount);
501 QFETCH(int, insertIndex_ttb);
502 QFETCH(int, insertCount_ttb);
503 QFETCH(qreal, rowOffsetAfterMove);
506 for (int i = 0; i < 30; i++)
507 model.addItem("Item" + QString::number(i), "");
509 QQuickView *window = getView();
510 QQmlContext *ctxt = window->rootContext();
511 ctxt->setContextProperty("testModel", &model);
512 ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom);
513 ctxt->setContextProperty("testRightToLeft", horizLayout == Qt::RightToLeft);
514 ctxt->setContextProperty("testBottomToTop", verticalLayout == QQuickGridView::BottomToTop);
515 window->setSource(testFileUrl("layouts.qml"));
517 qApp->processEvents();
519 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
520 QTRY_VERIFY(gridview != 0);
521 QQuickItem *contentItem = gridview->contentItem();
522 QTRY_VERIFY(contentItem != 0);
524 if (flow == QQuickGridView::FlowTopToBottom) {
525 insertIndex = insertIndex_ttb;
526 insertCount = insertCount_ttb;
528 if (setContentPos(gridview, contentYRowOffset))
529 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
531 QList<QPair<QString, QString> > newData;
532 for (int i=0; i<insertCount; i++)
533 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
534 model.insertItems(insertIndex, newData);
535 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
537 // check visibleItems.first() is in correct position
538 QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
540 QPointF firstPos(0, 0);
541 if (horizLayout == Qt::RightToLeft)
542 firstPos.rx() = flow == QQuickGridView::FlowLeftToRight ? gridview->width() - gridview->cellWidth() : -gridview->cellWidth();
543 if (verticalLayout == QQuickItemView::BottomToTop)
544 firstPos.ry() -= gridview->cellHeight();
545 QCOMPARE(item0->pos(), firstPos);
547 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
548 int firstVisibleIndex = -1;
549 for (int i=0; i<items.count(); i++) {
550 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
551 if (item && delegateVisible(item)) {
552 firstVisibleIndex = i;
556 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
558 // Confirm items positioned correctly and indexes correct
559 for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
560 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
561 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
562 QCOMPARE(item->pos(), expectedItemPos(gridview, i, rowOffsetAfterMove));
563 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
565 QCOMPARE(name->text(), model.name(i));
571 void tst_QQuickGridView::inserted_defaultLayout_data()
573 QTest::addColumn<qreal>("contentYRowOffset");
574 QTest::addColumn<int>("insertIndex");
575 QTest::addColumn<int>("insertCount");
576 QTest::addColumn<int>("insertIndex_ttb");
577 QTest::addColumn<int>("insertCount_ttb");
578 QTest::addColumn<qreal>("rowOffsetAfterMove");
580 QTest::newRow("add 1, before visible items")
584 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
585 // new 1st visible item is at 0
587 QTest::newRow("add 2, before visible items")
591 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
593 QTest::newRow("add 3, before visible items")
597 << -1.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
599 QTest::newRow("add 5, before visible items")
603 << -1.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
604 // grid is rearranged and first visible moves forward within its row
606 QTest::newRow("add 6, before visible items")
610 << -1.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
614 QTest::newRow("add 1, at start of visible, content at start")
620 QTest::newRow("add multiple, at start of visible, content at start")
626 QTest::newRow("add 1, at start of visible, content not at start")
632 QTest::newRow("add multiple, at start of visible, content not at start")
639 QTest::newRow("add 1, at end of visible, content at start")
645 QTest::newRow("add row, at end of visible, content at start")
651 QTest::newRow("add 1, at end of visible, content not at start")
657 QTest::newRow("add multiple, at end of visible, content not at start")
664 QTest::newRow("add 1, after visible, content at start")
670 QTest::newRow("add row, after visible, content at start")
676 QTest::newRow("add 1, after visible, content not at start")
682 QTest::newRow("add multiple, after visible, content not at start")
689 void tst_QQuickGridView::insertBeforeVisible()
691 QFETCH(int, insertIndex);
692 QFETCH(int, insertCount);
693 QFETCH(int, cacheBuffer);
696 QQuickView *window = getView();
699 for (int i = 0; i < 30; i++)
700 model.addItem("Item" + QString::number(i), "");
702 QQmlContext *ctxt = window->rootContext();
703 ctxt->setContextProperty("testModel", &model);
704 window->setSource(testFileUrl("gridview1.qml"));
706 qApp->processEvents();
708 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
709 QTRY_VERIFY(gridview != 0);
710 QQuickItem *contentItem = gridview->contentItem();
711 QTRY_VERIFY(contentItem != 0);
713 gridview->setCacheBuffer(cacheBuffer);
714 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
716 // trigger a refill (not just setting contentY) so that the visibleItems grid is updated
717 int firstVisibleIndex = 12; // move to an index where the top item is not visible
718 gridview->setContentY(firstVisibleIndex/3 * 60.0);
719 gridview->setCurrentIndex(firstVisibleIndex);
720 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
722 QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex);
723 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex);
725 QCOMPARE(item->y(), gridview->contentY());
727 QList<QPair<QString, QString> > newData;
728 for (int i=0; i<insertCount; i++)
729 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
730 model.insertItems(insertIndex, newData);
731 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
733 // now, moving to the top of the view should position the inserted items correctly
734 int itemsOffsetAfterMove = (insertCount / 3) * -60.0;
735 gridview->setCurrentIndex(0);
736 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
737 QTRY_COMPARE(gridview->currentIndex(), 0);
738 QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove);
740 // Confirm items positioned correctly and indexes correct
741 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
742 for (int i = 0; i < model.count() && i < itemCount; ++i) {
743 item = findItem<QQuickItem>(contentItem, "wrapper", i);
744 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
745 QCOMPARE(item->x(), (i%3)*80.0);
746 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
747 name = findItem<QQuickText>(contentItem, "textName", i);
749 QTRY_COMPARE(name->text(), model.name(i));
755 void tst_QQuickGridView::insertBeforeVisible_data()
757 QTest::addColumn<int>("insertIndex");
758 QTest::addColumn<int>("insertCount");
759 QTest::addColumn<int>("cacheBuffer");
761 QTest::newRow("insert 1 at 0, 0 buffer") << 0 << 1 << 0;
762 QTest::newRow("insert 1 at 0, 100 buffer") << 0 << 1 << 100;
763 QTest::newRow("insert 1 at 0, 500 buffer") << 0 << 1 << 500;
765 QTest::newRow("insert 1 at 1, 0 buffer") << 1 << 1 << 0;
766 QTest::newRow("insert 1 at 1, 100 buffer") << 1 << 1 << 100;
767 QTest::newRow("insert 1 at 1, 500 buffer") << 1 << 1 << 500;
769 QTest::newRow("insert multiple at 0, 0 buffer") << 0 << 6 << 0;
770 QTest::newRow("insert multiple at 0, 100 buffer") << 0 << 6 << 100;
771 QTest::newRow("insert multiple at 0, 500 buffer") << 0 << 6 << 500;
773 QTest::newRow("insert multiple at 1, 0 buffer") << 1 << 6 << 0;
774 QTest::newRow("insert multiple at 1, 100 buffer") << 1 << 6 << 100;
775 QTest::newRow("insert multiple at 1, 500 buffer") << 1 << 6 << 500;
778 void tst_QQuickGridView::removed_basic()
780 QQuickView *window = createView();
784 for (int i = 0; i < 40; i++)
785 model.addItem("Item" + QString::number(i), "");
787 window->rootContext()->setContextProperty("testModel", &model);
788 window->setSource(testFileUrl("gridview1.qml"));
789 qApp->processEvents();
791 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
792 QTRY_VERIFY(gridview != 0);
793 QQuickItem *contentItem = gridview->contentItem();
794 QTRY_VERIFY(contentItem != 0);
795 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
798 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
800 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
801 QTRY_VERIFY(name != 0);
802 QTRY_COMPARE(name->text(), model.name(1));
803 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
804 QTRY_VERIFY(number != 0);
805 QTRY_COMPARE(number->text(), model.number(1));
808 // Checks that onRemove is called
809 QString removed = window->rootObject()->property("removed").toString();
810 QTRY_COMPARE(removed, QString("Item1"));
812 // Confirm items positioned correctly
813 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
814 for (int i = 0; i < model.count() && i < itemCount; ++i) {
815 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
816 if (!item) qWarning() << "Item" << i << "not found";
817 QTRY_VERIFY(item->x() == (i%3)*80);
818 QTRY_VERIFY(item->y() == (i/3)*60);
821 // Remove first item (which is the current item);
823 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
825 name = findItem<QQuickText>(contentItem, "textName", 0);
826 QTRY_VERIFY(name != 0);
827 QTRY_COMPARE(name->text(), model.name(0));
828 number = findItem<QQuickText>(contentItem, "textNumber", 0);
829 QTRY_VERIFY(number != 0);
830 QTRY_COMPARE(number->text(), model.number(0));
833 // Confirm items positioned correctly
834 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
835 for (int i = 0; i < model.count() && i < itemCount; ++i) {
836 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
837 if (!item) qWarning() << "Item" << i << "not found";
838 QTRY_VERIFY(item->x() == (i%3)*80);
839 QTRY_VERIFY(item->y() == (i/3)*60);
842 // Remove items not visible
843 model.removeItem(25);
844 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
846 // Confirm items positioned correctly
847 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
848 for (int i = 0; i < model.count() && i < itemCount; ++i) {
849 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
850 if (!item) qWarning() << "Item" << i << "not found";
851 QTRY_VERIFY(item->x() == (i%3)*80);
852 QTRY_VERIFY(item->y() == (i/3)*60);
855 // Remove items before visible
856 gridview->setContentY(120);
857 gridview->setCurrentIndex(10);
859 // Setting currentIndex above shouldn't cause view to scroll
860 QTRY_COMPARE(gridview->contentY(), 120.0);
863 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
865 // Confirm items positioned correctly
866 for (int i = 6; i < 18; ++i) {
867 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
868 if (!item) qWarning() << "Item" << i << "not found";
869 QTRY_VERIFY(item->x() == (i%3)*80);
870 QTRY_VERIFY(item->y() == (i/3)*60);
873 // Remove currentIndex
874 QQuickItem *oldCurrent = gridview->currentItem();
876 QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
878 QTRY_COMPARE(gridview->currentIndex(), 9);
879 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
881 gridview->setContentY(0);
882 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
884 // Confirm items positioned correctly
885 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
886 for (int i = 0; i < model.count() && i < itemCount; ++i) {
887 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
888 QTRY_VERIFY(item->x() == (i%3)*80);
889 QTRY_VERIFY(item->y() == (i/3)*60);
892 // remove item outside current view.
893 gridview->setCurrentIndex(32);
894 gridview->setContentY(240);
896 model.removeItem(30);
897 QTRY_VERIFY(gridview->currentIndex() == 31);
899 // remove current item beyond visible items.
900 gridview->setCurrentIndex(20);
901 gridview->setContentY(0);
902 model.removeItem(20);
904 QTRY_COMPARE(gridview->currentIndex(), 20);
905 QTRY_VERIFY(gridview->currentItem() != 0);
907 // remove item before current, but visible
908 gridview->setCurrentIndex(8);
909 gridview->setContentY(240);
910 oldCurrent = gridview->currentItem();
913 QTRY_COMPARE(gridview->currentIndex(), 7);
914 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
919 void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow,
920 Qt::LayoutDirection horizLayout,
921 QQuickItemView::VerticalLayoutDirection verticalLayout)
923 QFETCH(qreal, contentYRowOffset);
924 QFETCH(int, removeIndex);
925 QFETCH(int, removeCount);
926 QFETCH(int, removeIndex_ttb);
927 QFETCH(int, removeCount_ttb);
928 QFETCH(qreal, rowOffsetAfterMove);
929 QFETCH(QString, firstVisible);
930 QFETCH(QString, firstVisible_ttb);
932 QQuickView *window = getView();
935 for (int i = 0; i < 30; i++)
936 model.addItem("Item" + QString::number(i), "");
938 QQmlContext *ctxt = window->rootContext();
939 ctxt->setContextProperty("testModel", &model);
940 ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom);
941 ctxt->setContextProperty("testRightToLeft", horizLayout == Qt::RightToLeft);
942 ctxt->setContextProperty("testBottomToTop", verticalLayout == QQuickGridView::BottomToTop);
943 window->setSource(testFileUrl("layouts.qml"));
945 qApp->processEvents();
947 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
948 QTRY_VERIFY(gridview != 0);
949 QQuickItem *contentItem = gridview->contentItem();
950 QTRY_VERIFY(contentItem != 0);
952 if (flow == QQuickGridView::FlowTopToBottom) {
953 removeIndex = removeIndex_ttb;
954 removeCount = removeCount_ttb;
955 firstVisible = firstVisible_ttb;
957 if (setContentPos(gridview, contentYRowOffset))
958 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
960 model.removeItems(removeIndex, removeCount);
961 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
964 int firstVisibleIndex = -1;
965 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
966 QRectF viewRect(gridview->contentX(), gridview->contentY(), gridview->width(), gridview->height());
967 for (int i=0; i<items.count(); i++) {
968 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
970 QRectF itemRect(item->x(), item->y(), item->width(), item->height());
971 if (delegateVisible(item) && viewRect.intersects(itemRect)) {
972 firstVisibleIndex = i;
973 QQmlExpression en(qmlContext(item), item, "name");
974 firstName = en.evaluate().toString();
979 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
980 QCOMPARE(firstName, firstVisible);
982 // Confirm items positioned correctly and indexes correct
983 for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
984 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
985 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
986 QCOMPARE(item->pos(), expectedItemPos(gridview, i, rowOffsetAfterMove));
987 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
989 QTRY_COMPARE(name->text(), model.name(i));
995 void tst_QQuickGridView::removed_defaultLayout_data()
997 QTest::addColumn<qreal>("contentYRowOffset");
998 QTest::addColumn<int>("removeIndex");
999 QTest::addColumn<int>("removeCount");
1000 QTest::addColumn<int>("removeIndex_ttb");
1001 QTest::addColumn<int>("removeCount_ttb");
1002 QTest::addColumn<qreal>("rowOffsetAfterMove");
1003 QTest::addColumn<QString>("firstVisible");
1004 QTest::addColumn<QString>("firstVisible_ttb");
1006 QTest::newRow("remove 1, before visible items")
1010 << 0.0 << "Item7" << "Item11";
1012 QTest::newRow("remove 1, before visible position")
1016 << 0.0 << "Item7" << "Item11";
1018 QTest::newRow("remove multiple (1 row), all before visible items")
1022 << 1.0 << "Item6" << "Item10"; // removed top row, slide down by 1 row
1024 QTest::newRow("remove multiple, all before visible items, remove item 0")
1028 << 1.0 << "Item7" << "Item11"; // removed top row, slide down by 1 row
1030 QTest::newRow("remove multiple rows, all before visible items")
1031 << 4.0 // show 12-29
1034 << 2.0 << "Item13" << "Item17";
1036 QTest::newRow("remove one row before visible, content y not on item border")
1040 << 1.0 << "Item3" << "Item5"; // 1 row removed
1042 QTest::newRow("remove mix of visible/non-visible")
1046 << 1.0 << "Item6" << "Item8"; // 1 row removed
1049 // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos,
1050 // items 6,7 are removed from view, item 8 slides up to original pos of item 6 (120px)
1051 QTest::newRow("remove multiple, mix of items from before and within visible items")
1055 << 1.0 << "Item8" << "Item12"; // adjust for the 1 row removed before the visible
1057 QTest::newRow("remove multiple, mix of items from before and within visible items, remove item 0")
1061 << 1.0 * 2 << "Item8" << "Item12"; // adjust for the 2 rows removed before the visible
1064 QTest::newRow("remove 1, from start of visible, content at start")
1068 << 0.0 << "Item1" << "Item1";
1070 QTest::newRow("remove multiple, from start of visible, content at start")
1074 << 0.0 << "Item3" << "Item5";
1076 QTest::newRow("remove 1, from start of visible, content not at start")
1080 << 0.0 << "Item7" << "Item11";
1082 QTest::newRow("remove multiple, from start of visible, content not at start")
1086 << 0.0 << "Item9" << "Item15";
1089 QTest::newRow("remove 1, from middle of visible, content at start")
1093 << 0.0 << "Item0" << "Item0";
1095 QTest::newRow("remove multiple, from middle of visible, content at start")
1099 << 0.0 << "Item0" << "Item0";
1101 QTest::newRow("remove 1, from middle of visible, content not at start")
1105 << 0.0 << "Item6" << "Item10";
1107 QTest::newRow("remove multiple, from middle of visible, content not at start")
1111 << 0.0 << "Item6" << "Item10";
1114 QTest::newRow("remove 1, after visible, content at start")
1118 << 0.0 << "Item0" << "Item0";
1120 QTest::newRow("remove multiple, after visible, content at start")
1124 << 0.0 << "Item0" << "Item0";
1126 QTest::newRow("remove 1, after visible, content not at start")
1130 << 0.0 << "Item6" << "Item10";
1132 QTest::newRow("remove multiple, after visible, content not at start")
1136 << 0.0 << "Item6" << "Item10";
1138 QTest::newRow("remove multiple, mix of items from within and after visible items")
1142 << 0.0 << "Item6" << "Item10";
1145 void tst_QQuickGridView::addOrRemoveBeforeVisible()
1147 // QTBUG-21588: ensure re-layout is done on grid after adding or removing
1148 // items from before the visible area
1150 QFETCH(bool, doAdd);
1151 QFETCH(qreal, newTopContentY);
1153 QQuickView *window = getView();
1157 for (int i = 0; i < 30; i++)
1158 model.addItem("Item" + QString::number(i), "");
1160 window->rootContext()->setContextProperty("testModel", &model);
1161 window->setSource(testFileUrl("gridview1.qml"));
1163 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1164 QTRY_VERIFY(gridview != 0);
1165 QQuickItem *contentItem = gridview->contentItem();
1166 QTRY_VERIFY(contentItem != 0);
1168 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
1169 QTRY_COMPARE(name->text(), QString("Item0"));
1171 gridview->setCurrentIndex(0);
1172 qApp->processEvents();
1173 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1175 // scroll down until item 0 is no longer drawn
1176 // (bug not triggered if we just move using content y, since that doesn't
1177 // refill and change the visible items)
1178 gridview->setCurrentIndex(24);
1179 qApp->processEvents();
1181 QTRY_COMPARE(gridview->currentIndex(), 24);
1182 QTRY_COMPARE(gridview->contentY(), 220.0);
1184 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1185 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible
1188 model.insertItem(0, "New Item", "New Item number");
1189 QTRY_COMPARE(gridview->count(), 31);
1191 model.removeItem(0);
1192 QTRY_COMPARE(gridview->count(), 29);
1195 // scroll back up and item 0 should be gone
1196 gridview->setCurrentIndex(0);
1197 qApp->processEvents();
1198 QTRY_COMPARE(gridview->currentIndex(), 0);
1199 QTRY_COMPARE(gridview->contentY(), newTopContentY);
1201 name = findItem<QQuickText>(contentItem, "textName", 0);
1203 QCOMPARE(name->text(), QString("New Item"));
1205 QCOMPARE(name->text(), QString("Item1"));
1207 // Confirm items positioned correctly
1208 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1209 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1210 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i));
1211 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1212 QTRY_VERIFY(item->x() == (i%3)*80);
1213 QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY);
1216 releaseView(window);
1219 void tst_QQuickGridView::addOrRemoveBeforeVisible_data()
1221 QTest::addColumn<bool>("doAdd");
1222 QTest::addColumn<qreal>("newTopContentY");
1224 QTest::newRow("add") << true << -60.0;
1225 QTest::newRow("remove") << false << -60.0;
1228 void tst_QQuickGridView::clear()
1230 QQuickView *window = createView();
1233 for (int i = 0; i < 30; i++)
1234 model.addItem("Item" + QString::number(i), "");
1236 window->rootContext()->setContextProperty("testModel", &model);
1237 window->setSource(testFileUrl("gridview1.qml"));
1239 qApp->processEvents();
1241 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1242 QVERIFY(gridview != 0);
1243 QQuickItem *contentItem = gridview->contentItem();
1244 QVERIFY(contentItem != 0);
1245 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1249 QVERIFY(gridview->count() == 0);
1250 QVERIFY(gridview->currentItem() == 0);
1251 QVERIFY(gridview->contentY() == 0);
1252 QVERIFY(gridview->currentIndex() == -1);
1253 QCOMPARE(gridview->contentHeight(), 0.0);
1255 // confirm sanity when adding an item to cleared list
1256 model.addItem("New", "1");
1257 QTRY_COMPARE(gridview->count(), 1);
1258 QVERIFY(gridview->currentItem() != 0);
1259 QVERIFY(gridview->currentIndex() == 0);
1264 void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow,
1265 Qt::LayoutDirection horizLayout,
1266 QQuickItemView::VerticalLayoutDirection verticalLayout)
1268 QFETCH(qreal, contentYRowOffset);
1272 QFETCH(int, from_ttb);
1273 QFETCH(int, to_ttb);
1274 QFETCH(int, count_ttb);
1275 QFETCH(qreal, rowOffsetAfterMove);
1277 QQuickView *window = getView();
1280 for (int i = 0; i < 30; i++)
1281 model.addItem("Item" + QString::number(i), "");
1283 QQmlContext *ctxt = window->rootContext();
1284 ctxt->setContextProperty("testModel", &model);
1285 ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom);
1286 ctxt->setContextProperty("testRightToLeft", horizLayout == Qt::RightToLeft);
1287 ctxt->setContextProperty("testBottomToTop", verticalLayout == QQuickGridView::BottomToTop);
1288 window->setSource(testFileUrl("layouts.qml"));
1290 qApp->processEvents();
1292 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1293 QTRY_VERIFY(gridview != 0);
1294 QQuickItem *contentItem = gridview->contentItem();
1295 QTRY_VERIFY(contentItem != 0);
1296 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1298 QQuickItem *currentItem = gridview->currentItem();
1299 QTRY_VERIFY(currentItem != 0);
1301 if (flow == QQuickGridView::FlowTopToBottom) {
1306 if (setContentPos(gridview, contentYRowOffset))
1307 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1309 model.moveItems(from, to, count);
1310 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1312 // Confirm items positioned correctly and indexes correct
1313 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
1314 int firstVisibleIndex = -1;
1315 for (int i=0; i<items.count(); i++) {
1316 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1317 if (item && delegateVisible(item)) {
1318 firstVisibleIndex = i;
1322 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
1324 for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
1325 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1327 ( (flow == QQuickGridView::FlowLeftToRight && i >= firstVisibleIndex + (3*6))
1328 || (flow == QQuickGridView::FlowTopToBottom && i >= firstVisibleIndex + (5*3)) ) ) {
1329 continue; // index has moved out of view
1331 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1332 QCOMPARE(item->pos(), expectedItemPos(gridview, i, rowOffsetAfterMove));
1333 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1335 QTRY_COMPARE(name->text(), model.name(i));
1337 // current index should have been updated
1338 if (item == currentItem)
1339 QTRY_COMPARE(gridview->currentIndex(), i);
1342 releaseView(window);
1345 void tst_QQuickGridView::moved_defaultLayout_data()
1347 QTest::addColumn<qreal>("contentYRowOffset");
1348 QTest::addColumn<int>("from");
1349 QTest::addColumn<int>("to");
1350 QTest::addColumn<int>("count");
1351 QTest::addColumn<int>("from_ttb");
1352 QTest::addColumn<int>("to_ttb");
1353 QTest::addColumn<int>("count_ttb");
1354 QTest::addColumn<qreal>("rowOffsetAfterMove");
1356 // model starts with 30 items, each 80x60, in area 240x320
1357 // 18 items should be visible at a time
1359 // The first visible item should not move upwards and out of the view
1360 // if items are moved/removed before it.
1363 QTest::newRow("move 1 forwards, within visible items")
1369 QTest::newRow("move 1 forwards, from non-visible -> visible")
1375 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
1376 << 2.0 // // show 6-23
1381 QTest::newRow("move 1 forwards, from visible -> non-visible")
1387 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
1394 QTest::newRow("move 1 backwards, within visible items")
1400 QTest::newRow("move 1 backwards, within visible items (to first index)")
1406 QTest::newRow("move 1 backwards, from non-visible -> visible")
1412 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
1418 QTest::newRow("move 1 backwards, from visible -> non-visible")
1422 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1424 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
1428 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
1431 QTest::newRow("move multiple forwards, within visible items")
1437 QTest::newRow("move multiple backwards, within visible items (move first item)")
1443 QTest::newRow("move multiple forwards, before visible items")
1445 << 3 << 4 << 3 // 3, 4, 5 move to after 6
1447 << 1.0; // row of 3,4,5 has moved down
1449 QTest::newRow("move multiple forwards, from non-visible -> visible")
1453 << 1.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
1455 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
1459 << 1.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
1461 QTest::newRow("move multiple forwards, mix of non-visible/visible")
1465 << 1.0; // top two rows removed, third row is now the first visible
1467 QTest::newRow("move multiple forwards, to bottom of view")
1473 QTest::newRow("move multiple forwards, to bottom of view, first row -> last")
1479 QTest::newRow("move multiple forwards, to bottom of view, content y not 0")
1485 QTest::newRow("move multiple forwards, from visible -> non-visible")
1491 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
1498 QTest::newRow("move multiple backwards, within visible items")
1504 QTest::newRow("move multiple backwards, from non-visible -> visible")
1510 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
1516 QTest::newRow("move multiple backwards, from visible -> non-visible")
1520 << -1.0; // to minimize movement, items are added above visible area, all items move up by 1 row
1522 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
1526 << -1.0; // 16,17,18 move to above item 0, all items move up by 1 row
1529 void tst_QQuickGridView::multipleChanges(bool condensed)
1531 QFETCH(int, startCount);
1532 QFETCH(QList<ListChange>, changes);
1533 QFETCH(int, newCount);
1534 QFETCH(int, newCurrentIndex);
1536 QQuickView *window = getView();
1539 for (int i = 0; i < startCount; i++)
1540 model.addItem("Item" + QString::number(i), "");
1542 window->rootContext()->setContextProperty("testModel", &model);
1543 window->setSource(testFileUrl("gridview1.qml"));
1545 qApp->processEvents();
1547 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1548 QTRY_VERIFY(gridview != 0);
1549 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1551 for (int i=0; i<changes.count(); i++) {
1552 switch (changes[i].type) {
1553 case ListChange::Inserted:
1555 QList<QPair<QString, QString> > items;
1556 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1557 items << qMakePair(QString("new item " + j), QString::number(j));
1558 model.insertItems(changes[i].index, items);
1561 case ListChange::Removed:
1562 model.removeItems(changes[i].index, changes[i].count);
1564 case ListChange::Moved:
1565 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1567 case ListChange::SetCurrent:
1568 gridview->setCurrentIndex(changes[i].index);
1570 case ListChange::SetContentY:
1571 gridview->setContentY(changes[i].pos);
1573 case ListChange::Polish:
1577 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1580 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1582 QCOMPARE(gridview->count(), newCount);
1583 QCOMPARE(gridview->count(), model.count());
1584 QCOMPARE(gridview->currentIndex(), newCurrentIndex);
1588 QQuickItem *contentItem = gridview->contentItem();
1589 QTRY_VERIFY(contentItem != 0);
1590 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1591 for (int i=0; i < model.count() && i < itemCount; ++i) {
1592 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1593 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1594 name = findItem<QQuickText>(contentItem, "textName", i);
1596 QTRY_COMPARE(name->text(), model.name(i));
1597 number = findItem<QQuickText>(contentItem, "textNumber", i);
1598 QVERIFY(number != 0);
1599 QTRY_COMPARE(number->text(), model.number(i));
1602 releaseView(window);
1605 void tst_QQuickGridView::multipleChanges_data()
1607 QTest::addColumn<int>("startCount");
1608 QTest::addColumn<QList<ListChange> >("changes");
1609 QTest::addColumn<int>("newCount");
1610 QTest::addColumn<int>("newCurrentIndex");
1612 QList<ListChange> changes;
1614 for (int i=1; i<30; i++)
1615 changes << ListChange::remove(0);
1616 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1618 changes << ListChange::remove(0);
1619 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1622 changes << ListChange::setCurrent(29);
1623 for (int i=29; i>0; i--)
1624 changes << ListChange::remove(i);
1625 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1627 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1628 << ListChange::remove(0, 1)
1629 << ListChange::insert(0, 1)
1632 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1633 << ListChange::setCurrent(2)
1634 << ListChange::remove(2, 1)
1635 << ListChange::insert(2, 1)
1638 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1639 << ListChange::setCurrent(1)
1640 << ListChange::remove(1, 3)
1641 << ListChange::insert(2, 2)
1644 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1645 << ListChange::setCurrent(2)
1646 << ListChange::remove(1, 3)
1647 << ListChange::move(1, 5, 1)
1650 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1651 << ListChange::setCurrent(5)
1652 << ListChange::remove(4, 3)
1653 << ListChange::move(4, 1, 1)
1657 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1658 << ListChange::insert(0, 2)
1659 << ListChange::insert(0, 4)
1660 << ListChange::insert(0, 6)
1663 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1664 << ListChange::insert(0, 2)
1665 << ListChange::insert(0, 4)
1666 << ListChange::insert(0, 6)
1667 << ListChange::setCurrent(3)
1668 << ListChange::insert(3, 2)
1671 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1672 << ListChange::insert(0, 30)
1673 << ListChange::remove(0, 30)
1676 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1677 << ListChange::insert(1)
1678 << ListChange::setCurrent(1)
1679 << ListChange::remove(1)
1682 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1683 << ListChange::insert(0, 10)
1684 << ListChange::remove(5, 10)
1687 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1688 << ListChange::insert(0, 3)
1689 << ListChange::move(0, 10, 3)
1692 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1693 << ListChange::insert(0, 3)
1694 << ListChange::move(0, 8, 5)
1697 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1698 << ListChange::setCurrent(9)
1699 << ListChange::insert(10, 3)
1700 << ListChange::move(8, 0, 5)
1704 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1705 << ListChange::setCurrent(1)
1706 << ListChange::move(1, 2, 2)
1707 << ListChange::move(2, 1, 2)
1710 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1711 << ListChange::setCurrent(2)
1712 << ListChange::move(1, 2, 3)
1713 << ListChange::move(3, 0, 5)
1716 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1717 << ListChange::setCurrent(5)
1718 << ListChange::move(5, 0, 1)
1719 << ListChange::remove(0)
1722 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1723 << ListChange::setCurrent(5)
1724 << ListChange::move(5, 0, 1)
1725 << ListChange::insert(0)
1728 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1729 << ListChange::setCurrent(1)
1730 << ListChange::move(5, 1, 3)
1731 << ListChange::remove(1, 3)
1734 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1735 << ListChange::setCurrent(5)
1736 << ListChange::move(5, 1, 3)
1737 << ListChange::insert(1, 5)
1740 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1741 << ListChange::setCurrent(3)
1742 << ListChange::move(0, 1, 2)
1743 << ListChange::insert(3, 5)
1747 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1748 << ListChange::insert(0, 5)
1749 << ListChange::setCurrent(-1)
1750 << ListChange::remove(0, 5)
1751 << ListChange::insert(0, 5)
1754 QTest::newRow("remove, scroll") << 30 << (QList<ListChange>()
1755 << ListChange::remove(20, 5)
1756 << ListChange::setContentY(20)
1759 QTest::newRow("insert, scroll") << 10 << (QList<ListChange>()
1760 << ListChange::insert(9, 5)
1761 << ListChange::setContentY(20)
1764 QTest::newRow("move, scroll") << 20 << (QList<ListChange>()
1765 << ListChange::move(15, 8, 3)
1766 << ListChange::setContentY(0)
1769 QTest::newRow("clear, insert, scroll") << 30 << (QList<ListChange>()
1770 << ListChange::setContentY(20)
1771 << ListChange::remove(0, 30)
1772 << ListChange::insert(0, 2)
1773 << ListChange::setContentY(0)
1778 void tst_QQuickGridView::swapWithFirstItem()
1781 QQuickView *window = createView();
1784 for (int i = 0; i < 30; i++)
1785 model.addItem("Item" + QString::number(i), "");
1787 window->rootContext()->setContextProperty("testModel", &model);
1788 window->setSource(testFileUrl("gridview1.qml"));
1790 qApp->processEvents();
1792 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1793 QTRY_VERIFY(gridview != 0);
1795 // ensure content position is stable
1796 gridview->setContentY(0);
1797 model.moveItem(10, 0);
1798 QTRY_VERIFY(gridview->contentY() == 0);
1803 void tst_QQuickGridView::currentIndex()
1805 QaimModel initModel;
1806 for (int i = 0; i < 60; i++)
1807 initModel.addItem("Item" + QString::number(i), QString::number(i));
1809 QQuickView *window = new QQuickView(0);
1810 window->setGeometry(0,0,240,320);
1813 QQmlContext *ctxt = window->rootContext();
1814 ctxt->setContextProperty("testModel", &initModel);
1816 QString filename(testFile("gridview-initCurrent.qml"));
1817 window->setSource(QUrl::fromLocalFile(filename));
1819 qApp->processEvents();
1821 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1822 QVERIFY(gridview != 0);
1823 QTRY_VERIFY(!QQuickItemPrivate::get(gridview)->polishScheduled);
1825 QQuickItem *contentItem = gridview->contentItem();
1826 QVERIFY(contentItem != 0);
1828 // currentIndex is initialized to 35
1829 // currentItem should be in view
1830 QCOMPARE(gridview->currentIndex(), 35);
1831 QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35));
1832 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1833 QCOMPARE(gridview->contentY(), 400.0);
1835 // changing model should reset currentIndex to 0
1837 for (int i = 0; i < 60; i++)
1838 model.addItem("Item" + QString::number(i), QString::number(i));
1839 ctxt->setContextProperty("testModel", &model);
1841 QCOMPARE(gridview->currentIndex(), 0);
1842 QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
1844 // confirm that the velocity is updated
1845 gridview->setCurrentIndex(35);
1846 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1847 gridview->setCurrentIndex(0);
1848 QTRY_VERIFY(gridview->verticalVelocity() == 0.0);
1850 // footer should become visible if it is out of view, and then current index moves to the first row
1851 window->rootObject()->setProperty("showFooter", true);
1852 QTRY_VERIFY(gridview->footerItem());
1853 gridview->setCurrentIndex(model.count()-3);
1854 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1855 gridview->setCurrentIndex(model.count()-2);
1856 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1857 window->rootObject()->setProperty("showFooter", false);
1859 // header should become visible if it is out of view, and then current index moves to the last row
1860 window->rootObject()->setProperty("showHeader", true);
1861 QTRY_VERIFY(gridview->headerItem());
1862 gridview->setCurrentIndex(3);
1863 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1864 gridview->setCurrentIndex(1);
1865 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1866 window->rootObject()->setProperty("showHeader", false);
1868 // turn off auto highlight
1869 gridview->setHighlightFollowsCurrentItem(false);
1870 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1871 QVERIFY(gridview->highlightItem());
1872 qreal hlPosX = gridview->highlightItem()->x();
1873 qreal hlPosY = gridview->highlightItem()->y();
1875 gridview->setCurrentIndex(5);
1876 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1877 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1879 // insert item before currentIndex
1880 gridview->setCurrentIndex(28);
1881 model.insertItem(0, "Foo", "1111");
1882 QTRY_COMPARE(window->rootObject()->property("current").toInt(), 29);
1884 // check removing highlight by setting currentIndex to -1;
1885 gridview->setCurrentIndex(-1);
1887 QCOMPARE(gridview->currentIndex(), -1);
1888 QVERIFY(!gridview->highlightItem());
1889 QVERIFY(!gridview->currentItem());
1891 // moving currentItem out of view should make it invisible
1892 gridview->setCurrentIndex(0);
1893 QTRY_VERIFY(delegateVisible(gridview->currentItem()));
1894 gridview->setContentY(200);
1895 QTRY_VERIFY(!delegateVisible(gridview->currentItem()));
1900 void tst_QQuickGridView::noCurrentIndex()
1903 for (int i = 0; i < 60; i++)
1904 model.addItem("Item" + QString::number(i), QString::number(i));
1906 QQuickView *window = new QQuickView(0);
1907 window->setGeometry(0,0,240,320);
1909 QQmlContext *ctxt = window->rootContext();
1910 ctxt->setContextProperty("testModel", &model);
1912 QString filename(testFile("gridview-noCurrent.qml"));
1913 window->setSource(QUrl::fromLocalFile(filename));
1915 qApp->processEvents();
1917 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1918 QVERIFY(gridview != 0);
1919 QQuickItem *contentItem = gridview->contentItem();
1920 QVERIFY(contentItem != 0);
1921 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1923 // current index should be -1
1924 QCOMPARE(gridview->currentIndex(), -1);
1925 QVERIFY(!gridview->currentItem());
1926 QVERIFY(!gridview->highlightItem());
1927 QCOMPARE(gridview->contentY(), 0.0);
1929 gridview->setCurrentIndex(5);
1930 QCOMPARE(gridview->currentIndex(), 5);
1931 QVERIFY(gridview->currentItem());
1932 QVERIFY(gridview->highlightItem());
1937 void tst_QQuickGridView::keyNavigation()
1939 QFETCH(QQuickGridView::Flow, flow);
1940 QFETCH(Qt::LayoutDirection, layoutDirection);
1941 QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection);
1942 QFETCH(Qt::Key, forwardsKey);
1943 QFETCH(Qt::Key, backwardsKey);
1944 QFETCH(QPointF, contentPosAtFirstItem);
1945 QFETCH(QPointF, contentPosAtLastItem);
1946 QFETCH(int, indexRightOf7);
1947 QFETCH(int, indexLeftOf7);
1948 QFETCH(int, indexUpFrom7);
1949 QFETCH(int, indexDownFrom7);
1952 for (int i = 0; i < 18; i++)
1953 model.addItem("Item" + QString::number(i), "");
1955 QQuickView *window = getView();
1956 window->rootContext()->setContextProperty("testModel", &model);
1957 window->setSource(testFileUrl("gridview1.qml"));
1959 QTest::qWaitForWindowActive(window);
1961 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
1962 QTRY_VERIFY(gridview != 0);
1963 gridview->setFlow(flow);
1964 gridview->setLayoutDirection(layoutDirection);
1965 gridview->setVerticalLayoutDirection(verticalLayoutDirection);
1966 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
1968 window->requestActivateWindow();
1969 QTest::qWaitForWindowActive(window);
1970 QTRY_VERIFY(qGuiApp->focusWindow() == window);
1971 QCOMPARE(gridview->currentIndex(), 0);
1973 QTest::keyClick(window, forwardsKey);
1974 QCOMPARE(gridview->currentIndex(), 1);
1976 QTest::keyClick(window, backwardsKey);
1977 QCOMPARE(gridview->currentIndex(), 0);
1979 gridview->setCurrentIndex(7);
1980 gridview->moveCurrentIndexRight();
1981 QCOMPARE(gridview->currentIndex(), indexRightOf7);
1982 gridview->moveCurrentIndexLeft();
1983 QCOMPARE(gridview->currentIndex(), 7);
1984 gridview->moveCurrentIndexLeft();
1985 QCOMPARE(gridview->currentIndex(), indexLeftOf7);
1986 gridview->moveCurrentIndexRight();
1987 QCOMPARE(gridview->currentIndex(), 7);
1988 gridview->moveCurrentIndexUp();
1989 QCOMPARE(gridview->currentIndex(), indexUpFrom7);
1990 gridview->moveCurrentIndexDown();
1991 QCOMPARE(gridview->currentIndex(), 7);
1992 gridview->moveCurrentIndexDown();
1993 QCOMPARE(gridview->currentIndex(), indexDownFrom7);
1995 gridview->setCurrentIndex(7);
1996 QTest::keyClick(window, Qt::Key_Right);
1997 QCOMPARE(gridview->currentIndex(), indexRightOf7);
1998 QTest::keyClick(window, Qt::Key_Left);
1999 QCOMPARE(gridview->currentIndex(), 7);
2000 QTest::keyClick(window, Qt::Key_Left);
2001 QCOMPARE(gridview->currentIndex(), indexLeftOf7);
2002 QTest::keyClick(window, Qt::Key_Right);
2003 QCOMPARE(gridview->currentIndex(), 7);
2004 QTest::keyClick(window, Qt::Key_Up);
2005 QCOMPARE(gridview->currentIndex(), indexUpFrom7);
2006 QTest::keyClick(window, Qt::Key_Down);
2007 QCOMPARE(gridview->currentIndex(), 7);
2008 QTest::keyClick(window, Qt::Key_Down);
2009 QCOMPARE(gridview->currentIndex(), indexDownFrom7);
2011 // hold down a key to go forwards
2012 gridview->setCurrentIndex(0);
2013 for (int i=0; i<model.count()-1; i++) {
2014 // QTest::qWait(500);
2015 QTest::simulateEvent(window, true, forwardsKey, Qt::NoModifier, "", true);
2016 QTRY_COMPARE(gridview->currentIndex(), i+1);
2018 QTest::keyRelease(window, forwardsKey);
2019 QTRY_COMPARE(gridview->currentIndex(), model.count()-1);
2020 QTRY_COMPARE(gridview->contentX(), contentPosAtLastItem.x());
2021 QTRY_COMPARE(gridview->contentY(), contentPosAtLastItem.y());
2023 // hold down a key to go backwards
2024 for (int i=model.count()-1; i > 0; i--) {
2025 QTest::simulateEvent(window, true, backwardsKey, Qt::NoModifier, "", true);
2026 QTRY_COMPARE(gridview->currentIndex(), i-1);
2028 QTest::keyRelease(window, backwardsKey);
2029 QTRY_COMPARE(gridview->currentIndex(), 0);
2030 QTRY_COMPARE(gridview->contentX(), contentPosAtFirstItem.x());
2031 QTRY_COMPARE(gridview->contentY(), contentPosAtFirstItem.y());
2034 QVERIFY(!gridview->isWrapEnabled());
2035 QTest::keyClick(window, forwardsKey);
2036 QCOMPARE(gridview->currentIndex(), 1);
2037 QTest::keyClick(window, backwardsKey);
2038 QCOMPARE(gridview->currentIndex(), 0);
2040 QTest::keyClick(window, backwardsKey);
2041 QCOMPARE(gridview->currentIndex(), 0);
2044 gridview->setWrapEnabled(true);
2045 QVERIFY(gridview->isWrapEnabled());
2047 QTest::keyClick(window, backwardsKey);
2048 QCOMPARE(gridview->currentIndex(), model.count()-1);
2049 QTRY_COMPARE(gridview->contentX(), contentPosAtLastItem.x());
2050 QTRY_COMPARE(gridview->contentY(), contentPosAtLastItem.y());
2052 QTest::keyClick(window, forwardsKey);
2053 QCOMPARE(gridview->currentIndex(), 0);
2054 QTRY_COMPARE(gridview->contentX(), contentPosAtFirstItem.x());
2055 QTRY_COMPARE(gridview->contentY(), contentPosAtFirstItem.y());
2057 // Test key press still accepted when position wraps to same index.
2058 window->rootObject()->setProperty("lastKey", 0);
2059 model.removeItems(1, model.count() - 1);
2061 QTest::keyClick(window, backwardsKey);
2062 QCOMPARE(window->rootObject()->property("lastKey").toInt(), 0);
2064 QTest::keyClick(window, forwardsKey);
2065 QCOMPARE(window->rootObject()->property("lastKey").toInt(), 0);
2067 // Test key press not accepted at limits when wrap is disabled.
2068 gridview->setWrapEnabled(false);
2070 QTest::keyClick(window, backwardsKey);
2071 QCOMPARE(window->rootObject()->property("lastKey").toInt(), int(backwardsKey));
2073 QTest::keyClick(window, forwardsKey);
2074 QCOMPARE(window->rootObject()->property("lastKey").toInt(), int(forwardsKey));
2076 releaseView(window);
2079 void tst_QQuickGridView::keyNavigation_data()
2081 QTest::addColumn<QQuickGridView::Flow>("flow");
2082 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2083 QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection");
2084 QTest::addColumn<Qt::Key>("forwardsKey");
2085 QTest::addColumn<Qt::Key>("backwardsKey");
2086 QTest::addColumn<QPointF>("contentPosAtFirstItem");
2087 QTest::addColumn<QPointF>("contentPosAtLastItem");
2088 QTest::addColumn<int>("indexRightOf7");
2089 QTest::addColumn<int>("indexLeftOf7");
2090 QTest::addColumn<int>("indexUpFrom7");
2091 QTest::addColumn<int>("indexDownFrom7");
2093 QTest::newRow("LeftToRight, LtR, TtB")
2094 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom
2095 << Qt::Key_Right << Qt::Key_Left
2098 << 8 << 6 << 4 << 10;
2100 QTest::newRow("LeftToRight, RtL, TtB")
2101 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom
2102 << Qt::Key_Left << Qt::Key_Right
2105 << 6 << 8 << 4 << 10;
2107 QTest::newRow("LeftToRight, LtR, BtT")
2108 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop
2109 << Qt::Key_Right << Qt::Key_Left
2112 << 8 << 6 << 10 << 4;
2114 QTest::newRow("LeftToRight, RtL, BtT")
2115 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop
2116 << Qt::Key_Left << Qt::Key_Right
2119 << 6 << 8 << 10 << 4;
2121 QTest::newRow("TopToBottom, LtR, TtB")
2122 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom
2123 << Qt::Key_Down << Qt::Key_Up
2126 << 12 << 2 << 6 << 8;
2128 QTest::newRow("TopToBottom, RtL, TtB")
2129 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom
2130 << Qt::Key_Down << Qt::Key_Up
2133 << 2 << 12 << 6 << 8;
2135 QTest::newRow("TopToBottom, LtR, BtT")
2136 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop
2137 << Qt::Key_Up << Qt::Key_Down
2139 << QPointF(80, -320)
2140 << 12 << 2 << 8 << 6;
2142 QTest::newRow("TopToBottom, RtL, BtT")
2143 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop
2144 << Qt::Key_Up << Qt::Key_Down
2145 << QPointF(-240, -320)
2146 << QPointF(-320, -320)
2147 << 2 << 12 << 8 << 6;
2150 void tst_QQuickGridView::changeFlow()
2152 QQuickView *window = createView();
2155 for (int i = 0; i < 30; i++)
2156 model.addItem("Item" + QString::number(i), QString::number(i));
2158 QQmlContext *ctxt = window->rootContext();
2159 ctxt->setContextProperty("testModel", &model);
2160 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2161 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2162 ctxt->setContextProperty("testBottomToTop", QVariant(false));
2164 window->setSource(testFileUrl("layouts.qml"));
2165 qApp->processEvents();
2167 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2168 QTRY_VERIFY(gridview != 0);
2170 QQuickItem *contentItem = gridview->contentItem();
2171 QTRY_VERIFY(contentItem != 0);
2173 // Confirm items positioned correctly and indexes correct
2174 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2175 for (int i = 0; i < model.count() && i < itemCount; ++i) {
2176 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2177 if (!item) qWarning() << "Item" << i << "not found";
2179 QTRY_COMPARE(item->x(), qreal((i%3)*80));
2180 QTRY_COMPARE(item->y(), qreal((i/3)*60));
2181 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
2182 QTRY_VERIFY(name != 0);
2183 QTRY_COMPARE(name->text(), model.name(i));
2184 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
2185 QTRY_VERIFY(number != 0);
2186 QTRY_COMPARE(number->text(), model.number(i));
2189 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2191 // Confirm items positioned correctly and indexes correct
2192 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2193 for (int i = 0; i < model.count() && i < itemCount; ++i) {
2194 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2195 if (!item) qWarning() << "Item" << i << "not found";
2197 QTRY_COMPARE(item->x(), qreal((i/5)*80));
2198 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2199 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
2200 QTRY_VERIFY(name != 0);
2201 QTRY_COMPARE(name->text(), model.name(i));
2202 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
2203 QTRY_VERIFY(number != 0);
2204 QTRY_COMPARE(number->text(), model.number(i));
2207 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2209 // Confirm items positioned correctly and indexes correct
2210 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2211 for (int i = 0; i < model.count() && i < itemCount; ++i) {
2212 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2213 if (!item) qWarning() << "Item" << i << "not found";
2215 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
2216 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2217 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
2218 QTRY_VERIFY(name != 0);
2219 QTRY_COMPARE(name->text(), model.name(i));
2220 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
2221 QTRY_VERIFY(number != 0);
2222 QTRY_COMPARE(number->text(), model.number(i));
2224 gridview->setContentX(100);
2225 QTRY_COMPARE(gridview->contentX(), 100.);
2226 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2227 QTRY_COMPARE(gridview->contentX(), 0.);
2229 // Confirm items positioned correctly and indexes correct
2230 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2231 for (int i = 0; i < model.count() && i < itemCount; ++i) {
2232 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2233 if (!item) qWarning() << "Item" << i << "not found";
2235 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
2236 QTRY_COMPARE(item->y(), qreal((i/3)*60));
2237 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
2238 QTRY_VERIFY(name != 0);
2239 QTRY_COMPARE(name->text(), model.name(i));
2240 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
2241 QTRY_VERIFY(number != 0);
2242 QTRY_COMPARE(number->text(), model.number(i));
2248 void tst_QQuickGridView::defaultValues()
2251 QQmlComponent c(&engine, testFileUrl("gridview3.qml"));
2252 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
2254 QTRY_VERIFY(obj != 0);
2255 QTRY_VERIFY(obj->model() == QVariant());
2256 QTRY_VERIFY(obj->delegate() == 0);
2257 QTRY_COMPARE(obj->currentIndex(), -1);
2258 QTRY_VERIFY(obj->currentItem() == 0);
2259 QTRY_COMPARE(obj->count(), 0);
2260 QTRY_VERIFY(obj->highlight() == 0);
2261 QTRY_VERIFY(obj->highlightItem() == 0);
2262 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
2263 QTRY_VERIFY(obj->flow() == 0);
2264 QTRY_COMPARE(obj->isWrapEnabled(), false);
2265 #ifdef QML_VIEW_DEFAULTCACHEBUFFER
2266 QTRY_COMPARE(obj->cacheBuffer(), QML_VIEW_DEFAULTCACHEBUFFER);
2268 QTRY_COMPARE(obj->cacheBuffer(), 320);
2270 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
2271 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2275 void tst_QQuickGridView::properties()
2278 QQmlComponent c(&engine, testFileUrl("gridview2.qml"));
2279 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
2281 QTRY_VERIFY(obj != 0);
2282 QTRY_VERIFY(obj->model() != QVariant());
2283 QTRY_VERIFY(obj->delegate() != 0);
2284 QTRY_COMPARE(obj->currentIndex(), 0);
2285 QTRY_VERIFY(obj->currentItem() != 0);
2286 QTRY_COMPARE(obj->count(), 4);
2287 QTRY_VERIFY(obj->highlight() != 0);
2288 QTRY_VERIFY(obj->highlightItem() != 0);
2289 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
2290 QTRY_VERIFY(obj->flow() == 0);
2291 QTRY_COMPARE(obj->isWrapEnabled(), true);
2292 QTRY_COMPARE(obj->cacheBuffer(), 200);
2293 QTRY_COMPARE(obj->cellWidth(), qreal(100));
2294 QTRY_COMPARE(obj->cellHeight(), qreal(100));
2298 void tst_QQuickGridView::propertyChanges()
2300 QQuickView *window = createView();
2301 QTRY_VERIFY(window);
2302 window->setSource(testFileUrl("propertychangestest.qml"));
2304 QQuickGridView *gridView = window->rootObject()->findChild<QQuickGridView*>("gridView");
2305 QTRY_VERIFY(gridView);
2307 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
2308 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
2309 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
2310 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
2312 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2313 QTRY_COMPARE(gridView->cacheBuffer(), 10);
2314 QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight);
2316 gridView->setWrapEnabled(false);
2317 gridView->setCacheBuffer(3);
2318 gridView->setFlow(QQuickGridView::FlowTopToBottom);
2320 QTRY_COMPARE(gridView->isWrapEnabled(), false);
2321 QTRY_COMPARE(gridView->cacheBuffer(), 3);
2322 QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom);
2324 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2325 QTRY_COMPARE(cacheBufferSpy.count(),1);
2326 QTRY_COMPARE(flowSpy.count(),1);
2328 gridView->setWrapEnabled(false);
2329 gridView->setCacheBuffer(3);
2330 gridView->setFlow(QQuickGridView::FlowTopToBottom);
2332 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
2333 QTRY_COMPARE(cacheBufferSpy.count(),1);
2334 QTRY_COMPARE(flowSpy.count(),1);
2336 gridView->setFlow(QQuickGridView::FlowLeftToRight);
2337 QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight);
2339 gridView->setWrapEnabled(true);
2340 gridView->setCacheBuffer(5);
2341 gridView->setLayoutDirection(Qt::RightToLeft);
2343 QTRY_COMPARE(gridView->isWrapEnabled(), true);
2344 QTRY_COMPARE(gridView->cacheBuffer(), 5);
2345 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
2347 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2348 QTRY_COMPARE(cacheBufferSpy.count(),2);
2349 QTRY_COMPARE(layoutSpy.count(),1);
2350 QTRY_COMPARE(flowSpy.count(),2);
2352 gridView->setWrapEnabled(true);
2353 gridView->setCacheBuffer(5);
2354 gridView->setLayoutDirection(Qt::RightToLeft);
2356 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
2357 QTRY_COMPARE(cacheBufferSpy.count(),2);
2358 QTRY_COMPARE(layoutSpy.count(),1);
2359 QTRY_COMPARE(flowSpy.count(),2);
2361 gridView->setFlow(QQuickGridView::FlowTopToBottom);
2362 QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom);
2363 QTRY_COMPARE(flowSpy.count(),3);
2365 gridView->setFlow(QQuickGridView::FlowTopToBottom);
2366 QTRY_COMPARE(flowSpy.count(),3);
2371 void tst_QQuickGridView::componentChanges()
2373 QQuickView *window = createView();
2374 QTRY_VERIFY(window);
2375 window->setSource(testFileUrl("propertychangestest.qml"));
2377 QQuickGridView *gridView = window->rootObject()->findChild<QQuickGridView*>("gridView");
2378 QTRY_VERIFY(gridView);
2380 QQmlComponent component(window->engine());
2381 component.setData("import QtQuick 2.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
2383 QQmlComponent delegateComponent(window->engine());
2384 delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
2386 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
2387 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
2388 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
2389 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
2390 QSignalSpy headerItemSpy(gridView, SIGNAL(headerItemChanged()));
2391 QSignalSpy footerItemSpy(gridView, SIGNAL(footerItemChanged()));
2393 gridView->setHighlight(&component);
2394 gridView->setDelegate(&delegateComponent);
2395 gridView->setHeader(&component);
2396 gridView->setFooter(&component);
2398 QTRY_COMPARE(gridView->highlight(), &component);
2399 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
2400 QTRY_COMPARE(gridView->header(), &component);
2401 QTRY_COMPARE(gridView->footer(), &component);
2403 QVERIFY(gridView->headerItem());
2404 QVERIFY(gridView->footerItem());
2406 QTRY_COMPARE(highlightSpy.count(),1);
2407 QTRY_COMPARE(delegateSpy.count(),1);
2408 QTRY_COMPARE(headerSpy.count(),1);
2409 QTRY_COMPARE(footerSpy.count(),1);
2410 QTRY_COMPARE(headerItemSpy.count(),1);
2411 QTRY_COMPARE(footerItemSpy.count(),1);
2413 gridView->setHighlight(&component);
2414 gridView->setDelegate(&delegateComponent);
2415 gridView->setHeader(&component);
2416 gridView->setFooter(&component);
2418 QTRY_COMPARE(highlightSpy.count(),1);
2419 QTRY_COMPARE(delegateSpy.count(),1);
2420 QTRY_COMPARE(headerSpy.count(),1);
2421 QTRY_COMPARE(footerSpy.count(),1);
2422 QTRY_COMPARE(headerItemSpy.count(),1);
2423 QTRY_COMPARE(footerItemSpy.count(),1);
2428 void tst_QQuickGridView::modelChanges()
2430 QQuickView *window = createView();
2431 QTRY_VERIFY(window);
2432 window->setSource(testFileUrl("propertychangestest.qml"));
2434 QQuickGridView *gridView = window->rootObject()->findChild<QQuickGridView*>("gridView");
2435 QTRY_VERIFY(gridView);
2437 QQuickListModel *alternateModel = window->rootObject()->findChild<QQuickListModel*>("alternateModel");
2438 QTRY_VERIFY(alternateModel);
2439 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
2440 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
2442 gridView->setModel(modelVariant);
2443 QTRY_COMPARE(gridView->model(), modelVariant);
2444 QTRY_COMPARE(modelSpy.count(),1);
2446 gridView->setModel(modelVariant);
2447 QTRY_COMPARE(modelSpy.count(),1);
2449 gridView->setModel(QVariant());
2450 QTRY_COMPARE(modelSpy.count(),2);
2454 void tst_QQuickGridView::positionViewAtBeginningEnd()
2456 QQuickView *window = createView();
2459 for (int i = 0; i < 40; i++)
2460 model.addItem("Item" + QString::number(i), "");
2462 QQmlContext *ctxt = window->rootContext();
2463 ctxt->setContextProperty("testModel", &model);
2464 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2465 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2466 ctxt->setContextProperty("testBottomToTop", QVariant(false));
2468 window->setSource(testFileUrl("layouts.qml"));
2470 qApp->processEvents();
2472 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2473 QTRY_VERIFY(gridview != 0);
2474 QQuickItem *contentItem = gridview->contentItem();
2475 QTRY_VERIFY(contentItem != 0);
2476 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2478 // positionViewAtBeginning
2479 gridview->setContentY(150);
2480 gridview->positionViewAtBeginning();
2481 QTRY_COMPARE(gridview->contentY(), 0.);
2483 gridview->setContentY(80);
2484 window->rootObject()->setProperty("showHeader", true);
2485 gridview->positionViewAtBeginning();
2486 QTRY_COMPARE(gridview->contentY(), -30.);
2488 // positionViewAtEnd
2489 gridview->setContentY(150);
2490 gridview->positionViewAtEnd();
2491 QTRY_COMPARE(gridview->contentY(), 520.); // 14*60 - 320 (14 rows)
2493 gridview->setContentY(80);
2494 window->rootObject()->setProperty("showFooter", true);
2495 gridview->positionViewAtEnd();
2496 QTRY_COMPARE(gridview->contentY(), 550.);
2498 // Test for Top To Bottom layout
2499 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2500 window->rootObject()->setProperty("showHeader", false);
2501 window->rootObject()->setProperty("showFooter", false);
2503 // positionViewAtBeginning
2504 gridview->setContentX(150);
2505 gridview->positionViewAtBeginning();
2506 QTRY_COMPARE(gridview->contentX(), 0.);
2508 gridview->setContentX(80);
2509 window->rootObject()->setProperty("showHeader", true);
2510 gridview->positionViewAtBeginning();
2511 QTRY_COMPARE(gridview->contentX(), -30.);
2513 // positionViewAtEnd
2514 gridview->positionViewAtEnd();
2515 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
2517 gridview->setContentX(80);
2518 window->rootObject()->setProperty("showFooter", true);
2519 gridview->positionViewAtEnd();
2520 QTRY_COMPARE(gridview->contentX(), 430.);
2522 // set current item to outside visible view, position at beginning
2523 // and ensure highlight moves to current item
2524 gridview->setCurrentIndex(6);
2525 gridview->positionViewAtBeginning();
2526 QTRY_COMPARE(gridview->contentX(), -30.);
2527 QVERIFY(gridview->highlightItem());
2528 QCOMPARE(gridview->highlightItem()->x(), 80.);
2533 void tst_QQuickGridView::positionViewAtIndex()
2535 QFETCH(bool, enforceRange);
2536 QFETCH(bool, topToBottom);
2537 QFETCH(bool, rightToLeft);
2538 QFETCH(qreal, initContentPos);
2540 QFETCH(QQuickGridView::PositionMode, mode);
2541 QFETCH(qreal, contentPos);
2543 QQuickView *window = getView();
2546 for (int i = 0; i < 40; i++)
2547 model.addItem("Item" + QString::number(i), "");
2549 QQmlContext *ctxt = window->rootContext();
2550 ctxt->setContextProperty("testModel", &model);
2551 ctxt->setContextProperty("testRightToLeft", QVariant(rightToLeft));
2552 ctxt->setContextProperty("testTopToBottom", QVariant(topToBottom));
2553 ctxt->setContextProperty("testBottomToTop", QVariant(false));
2555 window->setSource(testFileUrl("layouts.qml"));
2557 qApp->processEvents();
2559 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2560 QTRY_VERIFY(gridview != 0);
2561 QQuickItem *contentItem = gridview->contentItem();
2562 QTRY_VERIFY(contentItem != 0);
2563 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2565 window->rootObject()->setProperty("enforceRange", enforceRange);
2566 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2569 gridview->setContentX(initContentPos);
2571 gridview->setContentY(initContentPos);
2573 gridview->positionViewAtIndex(index, mode);
2575 QTRY_COMPARE(gridview->contentX(), contentPos);
2577 QTRY_COMPARE(gridview->contentY(), contentPos);
2579 // Confirm items positioned correctly
2580 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2581 for (int i = index; i < model.count() && i < itemCount-index-1; ++i) {
2582 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2583 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));
2590 QTRY_COMPARE(item->x(), (i/5)*80.);
2591 QTRY_COMPARE(item->y(), (i%5)*60.);
2594 QTRY_COMPARE(item->x(), (i%3)*80.);
2595 QTRY_COMPARE(item->y(), (i/3)*60.);
2599 releaseView(window);
2602 void tst_QQuickGridView::positionViewAtIndex_data()
2604 QTest::addColumn<bool>("enforceRange");
2605 QTest::addColumn<bool>("topToBottom");
2606 QTest::addColumn<bool>("rightToLeft");
2607 QTest::addColumn<qreal>("initContentPos");
2608 QTest::addColumn<int>("index");
2609 QTest::addColumn<QQuickGridView::PositionMode>("mode");
2610 QTest::addColumn<qreal>("contentPos");
2612 QTest::newRow("no range, 4 at Beginning") << false << false << false << 0. << 4 << QQuickGridView::Beginning << 60.;
2613 QTest::newRow("no range, 4 at End") << false << false << false << 0. << 4 << QQuickGridView::End << 0.;
2614 QTest::newRow("no range, 21 at Beginning") << false << false << false << 0. << 21 << QQuickGridView::Beginning << 420.;
2615 // Position on an item that would leave empty space if positioned at the top
2616 QTest::newRow("no range, 31 at Beginning") << false << false << false << 0. << 31 << QQuickGridView::Beginning << 520.;
2617 QTest::newRow("no range, 30 at End") << false << false << false << 0. << 30 << QQuickGridView::End << 340.;
2618 QTest::newRow("no range, 15 at Center") << false << false << false << 0. << 15 << QQuickGridView::Center << 170.;
2619 // Ensure at least partially visible
2620 QTest::newRow("no range, 15 visible => Visible") << false << false << false << 302. << 15 << QQuickGridView::Visible << 302.;
2621 QTest::newRow("no range, 15 after visible => Visible") << false << false << false << 360. << 15 << QQuickGridView::Visible << 300.;
2622 QTest::newRow("no range, 20 visible => Visible") << false << false << false << 60. << 20 << QQuickGridView::Visible << 60.;
2623 QTest::newRow("no range, 20 before visible => Visible") << false << false << false << 20. << 20 << QQuickGridView::Visible << 100.;
2624 // Ensure completely visible
2625 QTest::newRow("no range, 20 visible => Contain") << false << false << false << 120. << 20 << QQuickGridView::Contain << 120.;
2626 QTest::newRow("no range, 15 partially visible => Contain") << false << false << false << 302. << 15 << QQuickGridView::Contain << 300.;
2627 QTest::newRow("no range, 20 partially visible => Contain") << false << false << false << 60. << 20 << QQuickGridView::Contain << 100.;
2629 QTest::newRow("strict range, 4 at End") << true << false << false << 0. << 4 << QQuickGridView::End << -120.;
2630 QTest::newRow("strict range, 38 at Beginning") << true << false << false << 0. << 38 << QQuickGridView::Beginning << 660.;
2631 QTest::newRow("strict range, 15 at Center") << true << false << false << 0. << 15 << QQuickGridView::Center << 180.;
2632 QTest::newRow("strict range, 4 at SnapPosition") << true << false << false << 0. << 4 << QQuickGridView::SnapPosition << -60.;
2633 QTest::newRow("strict range, 10 at SnapPosition") << true << false << false << 0. << 10 << QQuickGridView::SnapPosition << 60.;
2634 QTest::newRow("strict range, 38 at SnapPosition") << true << false << false << 0. << 38 << QQuickGridView::SnapPosition << 600.;
2637 QTest::newRow("no range, ttb, 30 at End") << false << true << false << 0. << 30 << QQuickGridView::End << 320.;
2638 QTest::newRow("no range, ttb, 15 at Center") << false << true << false << 0. << 15 << QQuickGridView::Center << 160.;
2639 QTest::newRow("no range, ttb, 15 visible => Visible") << false << true << false << 160. << 15 << QQuickGridView::Visible << 160.;
2640 QTest::newRow("no range, ttb, 25 partially visible => Visible") << false << true << false << 170. << 25 << QQuickGridView::Visible << 170.;
2641 QTest::newRow("no range, ttb, 30 before visible => Visible") << false << true << false << 170. << 30 << QQuickGridView::Visible << 320.;
2642 QTest::newRow("no range, ttb, 25 partially visible => Contain") << false << true << false << 170. << 25 << QQuickGridView::Contain << 240.;
2645 QTest::newRow("no range, rtl, ttb, 6 at Beginning") << false << true << true << 0. << 6 << QQuickGridView::Beginning << -320.;
2646 QTest::newRow("no range, rtl, ttb, 21 at Beginning") << false << true << true << 0. << 21 << QQuickGridView::Beginning << -560.;
2647 // Position on an item that would leave empty space if positioned at the top
2648 QTest::newRow("no range, rtl, ttb, 31 at Beginning") << false << true << true << 0. << 31 << QQuickGridView::Beginning << -640.;
2649 QTest::newRow("no range, rtl, ttb, 0 at Beginning") << false << true << true << -400. << 0 << QQuickGridView::Beginning << -240.;
2650 QTest::newRow("no range, rtl, ttb, 30 at End") << false << true << true << 0. << 30 << QQuickGridView::End << -560.;
2651 QTest::newRow("no range, rtl, ttb, 15 at Center") << false << true << true << 0. << 15 << QQuickGridView::Center << -400.;
2652 QTest::newRow("no range, rtl, ttb, 15 visible => Visible") << false << true << true << -555. << 15 << QQuickGridView::Visible << -555.;
2653 QTest::newRow("no range, rtl, ttb, 15 not visible => Visible") << false << true << true << -239. << 15 << QQuickGridView::Visible << -320.;
2654 QTest::newRow("no range, rtl, ttb, 15 partially visible => Visible") << false << true << true << -300. << 15 << QQuickGridView::Visible << -300.;
2655 QTest::newRow("no range, rtl, ttb, 20 visible => Contain") << false << true << true << -400. << 20 << QQuickGridView::Contain << -400.;
2656 QTest::newRow("no range, rtl, ttb, 15 partially visible => Contain") << false << true << true << -315. << 15 << QQuickGridView::Contain << -320.;
2659 void tst_QQuickGridView::snapping()
2661 QQuickView *window = createView();
2664 for (int i = 0; i < 40; i++)
2665 model.addItem("Item" + QString::number(i), "");
2667 window->rootContext()->setContextProperty("testModel", &model);
2668 window->setSource(testFileUrl("gridview1.qml"));
2669 qApp->processEvents();
2671 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2672 QTRY_VERIFY(gridview != 0);
2674 gridview->setHeight(220);
2675 QCOMPARE(gridview->height(), 220.);
2677 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2678 QCOMPARE(gridview->contentY(), 80.);
2680 gridview->setContentY(0);
2681 QCOMPARE(gridview->contentY(), 0.);
2683 gridview->setSnapMode(QQuickGridView::SnapToRow);
2684 QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow);
2686 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2687 QCOMPARE(gridview->contentY(), 60.);
2689 gridview->positionViewAtIndex(15, QQuickGridView::End);
2690 QCOMPARE(gridview->contentY(), 120.);
2696 void tst_QQuickGridView::mirroring()
2698 QQuickView *windowA = createView();
2699 windowA->setSource(testFileUrl("mirroring.qml"));
2700 QQuickGridView *gridviewA = findItem<QQuickGridView>(windowA->rootObject(), "view");
2701 QTRY_VERIFY(gridviewA != 0);
2703 QQuickView *windowB = createView();
2704 windowB->setSource(testFileUrl("mirroring.qml"));
2705 QQuickGridView *gridviewB = findItem<QQuickGridView>(windowB->rootObject(), "view");
2706 QTRY_VERIFY(gridviewA != 0);
2707 qApp->processEvents();
2709 QList<QString> objectNames;
2710 objectNames << "item1" << "item2"; // << "item3"
2712 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2713 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2714 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2717 foreach (const QString objectName, objectNames)
2718 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2720 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2721 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2724 foreach (const QString objectName, objectNames)
2725 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2727 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2728 QQuickItemPrivate::get(gridviewB)->setLayoutMirror(true);
2729 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2731 // LTR != LTR+mirror
2732 foreach (const QString objectName, objectNames)
2733 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2735 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2737 // RTL == LTR+mirror
2738 foreach (const QString objectName, objectNames)
2739 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2741 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2743 // RTL != RTL+mirror
2744 foreach (const QString objectName, objectNames)
2745 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2747 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2749 // LTR == RTL+mirror
2750 foreach (const QString objectName, objectNames)
2751 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2757 void tst_QQuickGridView::resetModel()
2759 QQuickView *window = createView();
2761 QStringList strings;
2762 strings << "one" << "two" << "three";
2763 QStringListModel model(strings);
2765 QQmlContext *ctxt = window->rootContext();
2766 ctxt->setContextProperty("testModel", &model);
2768 window->setSource(testFileUrl("displaygrid.qml"));
2770 qApp->processEvents();
2772 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2773 QTRY_VERIFY(gridview != 0);
2774 QQuickItem *contentItem = gridview->contentItem();
2775 QTRY_VERIFY(contentItem != 0);
2776 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2778 QTRY_COMPARE(gridview->count(), model.rowCount());
2780 for (int i = 0; i < model.rowCount(); ++i) {
2781 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2782 QTRY_VERIFY(display != 0);
2783 QTRY_COMPARE(display->text(), strings.at(i));
2787 strings << "four" << "five" << "six" << "seven";
2788 model.setStringList(strings);
2790 QTRY_COMPARE(gridview->count(), model.rowCount());
2792 for (int i = 0; i < model.rowCount(); ++i) {
2793 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2794 QTRY_VERIFY(display != 0);
2795 QTRY_COMPARE(display->text(), strings.at(i));
2801 void tst_QQuickGridView::enforceRange()
2803 QQuickView *window = createView();
2806 for (int i = 0; i < 30; i++)
2807 model.addItem("Item" + QString::number(i), "");
2809 QQmlContext *ctxt = window->rootContext();
2810 ctxt->setContextProperty("testModel", &model);
2811 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2812 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2814 window->setSource(testFileUrl("gridview-enforcerange.qml"));
2816 qApp->processEvents();
2817 QVERIFY(window->rootObject() != 0);
2819 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2820 QTRY_VERIFY(gridview != 0);
2822 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2823 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2824 QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2825 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
2827 QQuickItem *contentItem = gridview->contentItem();
2828 QTRY_VERIFY(contentItem != 0);
2830 // view should be positioned at the top of the range.
2831 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2833 QTRY_COMPARE(gridview->contentY(), -100.0);
2835 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2836 QTRY_VERIFY(name != 0);
2837 QTRY_COMPARE(name->text(), model.name(0));
2838 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2839 QTRY_VERIFY(number != 0);
2840 QTRY_COMPARE(number->text(), model.number(0));
2842 // Check currentIndex is updated when contentItem moves
2843 gridview->setContentY(0);
2844 QTRY_COMPARE(gridview->currentIndex(), 2);
2846 gridview->setCurrentIndex(5);
2847 QTRY_COMPARE(gridview->contentY(), 100.);
2850 for (int i = 0; i < 5; i++)
2851 model2.addItem("Item" + QString::number(i), "");
2853 ctxt->setContextProperty("testModel", &model2);
2854 QCOMPARE(gridview->count(), 5);
2859 void tst_QQuickGridView::enforceRange_rightToLeft()
2861 QQuickView *window = createView();
2864 for (int i = 0; i < 30; i++)
2865 model.addItem("Item" + QString::number(i), "");
2867 QQmlContext *ctxt = window->rootContext();
2868 ctxt->setContextProperty("testModel", &model);
2869 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2870 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2872 window->setSource(testFileUrl("gridview-enforcerange.qml"));
2873 qApp->processEvents();
2874 QVERIFY(window->rootObject() != 0);
2876 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2877 QTRY_VERIFY(gridview != 0);
2879 QCOMPARE(gridview->preferredHighlightBegin(), 100.0);
2880 QCOMPARE(gridview->preferredHighlightEnd(), 100.0);
2881 QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2883 QQuickItem *contentItem = gridview->contentItem();
2884 QVERIFY(contentItem != 0);
2886 // view should be positioned at the top of the range.
2887 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2889 QTRY_COMPARE(gridview->contentX(), -140.);
2890 QTRY_COMPARE(gridview->contentY(), 0.0);
2892 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2893 QTRY_VERIFY(name != 0);
2894 QTRY_COMPARE(name->text(), model.name(0));
2895 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2896 QTRY_VERIFY(number != 0);
2897 QTRY_COMPARE(number->text(), model.number(0));
2899 // Check currentIndex is updated when contentItem moves
2900 gridview->setContentX(-240);
2901 QTRY_COMPARE(gridview->currentIndex(), 3);
2903 gridview->setCurrentIndex(7);
2904 QTRY_COMPARE(gridview->contentX(), -340.);
2905 QTRY_COMPARE(gridview->contentY(), 0.0);
2908 for (int i = 0; i < 5; i++)
2909 model2.addItem("Item" + QString::number(i), "");
2911 ctxt->setContextProperty("testModel", &model2);
2912 QCOMPARE(gridview->count(), 5);
2917 void tst_QQuickGridView::QTBUG_8456()
2919 QQuickView *window = createView();
2921 window->setSource(testFileUrl("setindex.qml"));
2922 qApp->processEvents();
2924 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2925 QTRY_VERIFY(gridview != 0);
2927 QTRY_COMPARE(gridview->currentIndex(), 0);
2932 void tst_QQuickGridView::manualHighlight()
2934 QQuickView *window = createView();
2936 QString filename(testFile("manual-highlight.qml"));
2937 window->setSource(QUrl::fromLocalFile(filename));
2939 qApp->processEvents();
2941 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
2942 QTRY_VERIFY(gridview != 0);
2944 QQuickItem *contentItem = gridview->contentItem();
2945 QTRY_VERIFY(contentItem != 0);
2947 QTRY_COMPARE(gridview->currentIndex(), 0);
2948 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2949 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2950 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2952 gridview->setCurrentIndex(2);
2954 QTRY_COMPARE(gridview->currentIndex(), 2);
2955 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2956 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2957 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2959 gridview->positionViewAtIndex(8, QQuickGridView::Contain);
2961 QTRY_COMPARE(gridview->currentIndex(), 2);
2962 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 2));
2963 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2964 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2966 gridview->setFlow(QQuickGridView::FlowTopToBottom);
2967 QTRY_COMPARE(gridview->flow(), QQuickGridView::FlowTopToBottom);
2969 gridview->setCurrentIndex(0);
2970 QTRY_COMPARE(gridview->currentIndex(), 0);
2971 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
2972 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2973 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2979 void tst_QQuickGridView::footer()
2981 QFETCH(QQuickGridView::Flow, flow);
2982 QFETCH(Qt::LayoutDirection, layoutDirection);
2983 QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection);
2984 QFETCH(QPointF, initialFooterPos);
2985 QFETCH(QPointF, changedFooterPos);
2986 QFETCH(QPointF, initialContentPos);
2987 QFETCH(QPointF, firstDelegatePos);
2988 QFETCH(QPointF, resizeContentPos);
2990 QQuickView *window = getView();
2994 for (int i = 0; i < 7; i++)
2995 model.addItem("Item" + QString::number(i), "");
2997 QQmlContext *ctxt = window->rootContext();
2998 ctxt->setContextProperty("testModel", &model);
2999 window->setSource(testFileUrl("footer.qml"));
3000 qApp->processEvents();
3002 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3003 QTRY_VERIFY(gridview != 0);
3004 gridview->setFlow(flow);
3005 gridview->setLayoutDirection(layoutDirection);
3006 gridview->setVerticalLayoutDirection(verticalLayoutDirection);
3007 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3009 QQuickItem *contentItem = gridview->contentItem();
3010 QTRY_VERIFY(contentItem != 0);
3012 QQuickText *footer = findItem<QQuickText>(contentItem, "footer");
3014 QVERIFY(footer == gridview->footerItem());
3016 QCOMPARE(footer->pos(), initialFooterPos);
3017 QCOMPARE(footer->width(), 100.);
3018 QCOMPARE(footer->height(), 30.);
3019 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3021 if (flow == QQuickGridView::FlowLeftToRight)
3022 QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + footer->height());
3024 QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + footer->width());
3026 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3028 QCOMPARE(item->pos(), firstDelegatePos);
3030 if (flow == QQuickGridView::FlowLeftToRight) {
3031 // shrink by one row
3032 model.removeItem(2);
3033 if (verticalLayoutDirection == QQuickItemView::TopToBottom)
3034 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
3036 QTRY_COMPARE(footer->y(), initialFooterPos.y() + gridview->cellHeight());
3038 // shrink by one column
3039 model.removeItem(2);
3040 model.removeItem(3);
3041 if (layoutDirection == Qt::LeftToRight)
3042 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
3044 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
3049 if (flow == QQuickGridView::FlowLeftToRight)
3050 QTRY_COMPARE(gridview->contentHeight(), footer->height());
3052 QTRY_COMPARE(gridview->contentWidth(), footer->width());
3054 QPointF posWhenNoItems(0, 0);
3055 if (layoutDirection == Qt::RightToLeft)
3056 posWhenNoItems.setX(flow == QQuickGridView::FlowLeftToRight ? gridview->width() - footer->width() : -footer->width());
3057 if (verticalLayoutDirection == QQuickItemView::BottomToTop)
3058 posWhenNoItems.setY(-footer->height());
3059 QTRY_COMPARE(footer->pos(), posWhenNoItems);
3061 // if header is toggled, it shouldn't affect the footer position
3062 window->rootObject()->setProperty("showHeader", true);
3063 QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0);
3064 QTRY_COMPARE(footer->pos(), posWhenNoItems);
3065 window->rootObject()->setProperty("showHeader", false);
3068 for (int i = 0; i < 30; i++)
3069 model.addItem("Item" + QString::number(i), "");
3071 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
3072 QMetaObject::invokeMethod(window->rootObject(), "changeFooter");
3074 QCOMPARE(footerItemSpy.count(), 1);
3076 footer = findItem<QQuickText>(contentItem, "footer");
3078 footer = findItem<QQuickText>(contentItem, "footer2");
3080 QVERIFY(footer == gridview->footerItem());
3082 QCOMPARE(footer->pos(), changedFooterPos);
3083 QCOMPARE(footer->width(), 50.);
3084 QCOMPARE(footer->height(), 20.);
3086 // changing the footer shouldn't change the content pos
3087 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3089 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3091 QCOMPARE(item->pos(), firstDelegatePos);
3093 gridview->positionViewAtEnd();
3094 footer->setHeight(10);
3095 footer->setWidth(40);
3096 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
3098 releaseView(window);
3101 void tst_QQuickGridView::footer_data()
3103 QTest::addColumn<QQuickGridView::Flow>("flow");
3104 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3105 QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection");
3106 QTest::addColumn<QPointF>("initialFooterPos");
3107 QTest::addColumn<QPointF>("changedFooterPos");
3108 QTest::addColumn<QPointF>("initialContentPos");
3109 QTest::addColumn<QPointF>("firstDelegatePos");
3110 QTest::addColumn<QPointF>("resizeContentPos");
3112 // footer1 = 100 x 30
3113 // footer2 = 50 x 20
3116 // view height = 320
3118 // footer below items, bottom left
3119 QTest::newRow("LeftToRight, LtR, TtB")
3120 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom
3121 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
3122 << QPointF(0, 10 * 60) // 30 items = 10 rows
3125 << QPointF(0, (10 * 60) - 320 + 10);
3127 // footer below items, bottom right
3128 QTest::newRow("LeftToRight, RtL, TtB")
3129 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom
3130 << QPointF(240 - 100, 3 * 60)
3131 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
3133 << QPointF(240 - 80, 0)
3134 << QPointF(0, (10 * 60) - 320 + 10);
3136 // footer above items, top left
3137 QTest::newRow("LeftToRight, LtR, BtT")
3138 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop
3139 << QPointF(0, -(3 * 60) - 30)
3140 << QPointF(0, -(10 * 60) - 20)
3143 << QPointF(0, -(10 * 60) - 10);
3145 // footer above items, top right
3146 QTest::newRow("LeftToRight, RtL, BtT")
3147 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop
3148 << QPointF(240 - 100, -(3 * 60) - 30)
3149 << QPointF((240 - 100) + 50, -(10 * 60) - 20)
3151 << QPointF(240 - 80, -60)
3152 << QPointF(0, -(10 * 60) - 10);
3155 // footer to right of items, bottom right
3156 QTest::newRow("TopToBottom, LtR, TtB")
3157 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom
3158 << QPointF(2 * 80, 0) // 2 columns, cell width 80
3159 << QPointF(6 * 80, 0) // 30 items = 6 columns
3162 << QPointF((6 * 80) - 240 + 40, 0);
3164 // footer to left of items, bottom right
3165 QTest::newRow("TopToBottom, RtL, TtB")
3166 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom
3167 << QPointF(-(2 * 80) - 100, 0)
3168 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
3171 << QPointF(-(6 * 80) - 40, 0);
3173 // footer to right of items, top right
3174 QTest::newRow("TopToBottom, LtR, BtT")
3175 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop
3176 << QPointF(2 * 80, -30)
3177 << QPointF(6 * 80, -20)
3180 << QPointF((6 * 80) - 240 + 40, -320);
3182 // footer to left of items, top left
3183 QTest::newRow("TopToBottom, RtL, BtT")
3184 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop
3185 << QPointF(-(2 * 80) - 100, -30)
3186 << QPointF(-(6 * 80) - 50, -20)
3187 << QPointF(-240, -320)
3188 << QPointF(-80, -60)
3189 << QPointF(-(6 * 80) - 40, -320);
3192 void tst_QQuickGridView::initialZValues()
3194 QQuickView *window = createView();
3195 window->setSource(testFileUrl("initialZValues.qml"));
3196 qApp->processEvents();
3198 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3199 QTRY_VERIFY(gridview != 0);
3200 QQuickItem *contentItem = gridview->contentItem();
3201 QTRY_VERIFY(contentItem != 0);
3203 QVERIFY(gridview->headerItem());
3204 QTRY_COMPARE(gridview->headerItem()->z(), gridview->property("initialZ").toReal());
3206 QVERIFY(gridview->footerItem());
3207 QTRY_COMPARE(gridview->footerItem()->z(), gridview->property("initialZ").toReal());
3212 void tst_QQuickGridView::header()
3214 QFETCH(QQuickGridView::Flow, flow);
3215 QFETCH(Qt::LayoutDirection, layoutDirection);
3216 QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection);
3217 QFETCH(QPointF, initialHeaderPos);
3218 QFETCH(QPointF, changedHeaderPos);
3219 QFETCH(QPointF, initialContentPos);
3220 QFETCH(QPointF, changedContentPos);
3221 QFETCH(QPointF, firstDelegatePos);
3222 QFETCH(QPointF, resizeContentPos);
3225 for (int i = 0; i < 30; i++)
3226 model.addItem("Item" + QString::number(i), "");
3228 QQuickView *window = getView();
3229 window->rootContext()->setContextProperty("testModel", &model);
3230 window->rootContext()->setContextProperty("initialViewWidth", 240);
3231 window->rootContext()->setContextProperty("initialViewHeight", 320);
3232 window->setSource(testFileUrl("header.qml"));
3234 qApp->processEvents();
3236 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3237 QTRY_VERIFY(gridview != 0);
3238 gridview->setFlow(flow);
3239 gridview->setLayoutDirection(layoutDirection);
3240 gridview->setVerticalLayoutDirection(verticalLayoutDirection);
3241 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3243 QQuickItem *contentItem = gridview->contentItem();
3244 QTRY_VERIFY(contentItem != 0);
3246 QQuickText *header = findItem<QQuickText>(contentItem, "header");
3248 QVERIFY(header == gridview->headerItem());
3250 QCOMPARE(header->pos(), initialHeaderPos);
3251 QCOMPARE(header->width(), 100.);
3252 QCOMPARE(header->height(), 30.);
3253 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3255 if (flow == QQuickGridView::FlowLeftToRight)
3256 QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + header->height());
3258 QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + header->width());
3260 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3262 QCOMPARE(item->pos(), firstDelegatePos);
3265 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3266 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
3267 if (flow == QQuickGridView::FlowLeftToRight)
3268 QCOMPARE(gridview->contentHeight(), header->height());
3270 QCOMPARE(gridview->contentWidth(), header->width());
3272 for (int i = 0; i < 30; i++)
3273 model.addItem("Item" + QString::number(i), "");
3275 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
3276 QMetaObject::invokeMethod(window->rootObject(), "changeHeader");
3278 QCOMPARE(headerItemSpy.count(), 1);
3280 header = findItem<QQuickText>(contentItem, "header");
3282 header = findItem<QQuickText>(contentItem, "header2");
3285 QVERIFY(header == gridview->headerItem());
3287 QCOMPARE(header->pos(), changedHeaderPos);
3288 QCOMPARE(header->width(), 50.);
3289 QCOMPARE(header->height(), 20.);
3290 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
3292 item = findItem<QQuickItem>(contentItem, "wrapper", 0);
3294 QCOMPARE(item->pos(), firstDelegatePos);
3296 header->setHeight(10);
3297 header->setWidth(40);
3298 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
3300 releaseView(window);
3303 // QTBUG-21207 header should become visible if view resizes from initial empty size
3306 window->rootContext()->setContextProperty("testModel", &model);
3307 window->rootContext()->setContextProperty("initialViewWidth", 240);
3308 window->rootContext()->setContextProperty("initialViewHeight", 320);
3309 window->setSource(testFileUrl("header.qml"));
3311 qApp->processEvents();
3313 gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3314 QTRY_VERIFY(gridview != 0);
3315 gridview->setFlow(flow);
3316 gridview->setLayoutDirection(layoutDirection);
3317 gridview->setVerticalLayoutDirection(verticalLayoutDirection);
3318 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3320 gridview->setWidth(240);
3321 gridview->setHeight(320);
3322 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
3323 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
3325 releaseView(window);
3328 void tst_QQuickGridView::header_data()
3330 QTest::addColumn<QQuickGridView::Flow>("flow");
3331 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3332 QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection");
3333 QTest::addColumn<QPointF>("initialHeaderPos");
3334 QTest::addColumn<QPointF>("changedHeaderPos");
3335 QTest::addColumn<QPointF>("initialContentPos");
3336 QTest::addColumn<QPointF>("changedContentPos");
3337 QTest::addColumn<QPointF>("firstDelegatePos");
3338 QTest::addColumn<QPointF>("resizeContentPos");
3340 // header1 = 100 x 30
3341 // header2 = 50 x 20
3345 // header above items, top left
3346 QTest::newRow("LeftToRight, LtR, TtB")
3347 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom
3355 // header above items, top right
3356 QTest::newRow("LeftToRight, RtL, TtB")
3357 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom
3358 << QPointF(240 - 100, -30)
3359 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
3365 // header below items, bottom left
3366 QTest::newRow("LeftToRight, LtR, BtT")
3367 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop
3370 << QPointF(0, -320 + 30)
3371 << QPointF(0, -320 + 20)
3373 << QPointF(0, -320 + 10);
3375 // header above items, top right
3376 QTest::newRow("LeftToRight, RtL, BtT")
3377 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop
3378 << QPointF(240 - 100, 0)
3379 << QPointF((240 - 100) + 50, 0)
3380 << QPointF(0, -320 + 30)
3381 << QPointF(0, -320 + 20)
3382 << QPointF(160, -60)
3383 << QPointF(0, -320 + 10);
3386 // header to left of items, bottom left
3387 QTest::newRow("TopToBottom, LtR, TtB")
3388 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom
3396 // header to right of items, bottom right
3397 QTest::newRow("TopToBottom, RtL, TtB")
3398 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom
3401 << QPointF(-(240 - 100), 0)
3402 << QPointF(-(240 - 50), 0)
3404 << QPointF(-(240 - 40), 0);
3406 // header to left of items, top left
3407 QTest::newRow("TopToBottom, LtR, BtT")
3408 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop
3409 << QPointF(-100, -30)
3410 << QPointF(-50, -20)
3411 << QPointF(-100, -320)
3412 << QPointF(-50, -320)
3414 << QPointF(-40, -320);
3416 // header to right of items, top right
3417 QTest::newRow("TopToBottom, RtL, BtT")
3418 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop
3421 << QPointF(-(240 - 100), -320)
3422 << QPointF(-(240 - 50), -320)
3423 << QPointF(-80, -60)
3424 << QPointF(-(240 - 40), -320);
3427 class GVAccessor : public QQuickGridView
3430 qreal minY() const { return minYExtent(); }
3431 qreal maxY() const { return maxYExtent(); }
3432 qreal minX() const { return minXExtent(); }
3433 qreal maxX() const { return maxXExtent(); }
3436 void tst_QQuickGridView::extents()
3438 QFETCH(QQuickGridView::Flow, flow);
3439 QFETCH(Qt::LayoutDirection, layoutDirection);
3440 QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection);
3441 QFETCH(QPointF, headerPos);
3442 QFETCH(QPointF, footerPos);
3443 QFETCH(QPointF, minPos);
3444 QFETCH(QPointF, maxPos);
3445 QFETCH(QPointF, origin_empty);
3446 QFETCH(QPointF, origin_nonEmpty);
3448 QQuickView *window = getView();
3451 QQmlContext *ctxt = window->rootContext();
3453 ctxt->setContextProperty("testModel", &model);
3454 window->setSource(testFileUrl("headerfooter.qml"));
3456 qApp->processEvents();
3458 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject());
3459 QTRY_VERIFY(gridview != 0);
3460 gridview->setFlow(flow);
3461 gridview->setLayoutDirection(layoutDirection);
3462 gridview->setVerticalLayoutDirection(verticalLayoutDirection);
3463 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3465 QQuickItem *contentItem = gridview->contentItem();
3466 QTRY_VERIFY(contentItem != 0);
3468 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3470 QCOMPARE(header->pos(), headerPos);
3472 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3474 QCOMPARE(footer->pos(), footerPos);
3476 QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), minPos.x());
3477 QCOMPARE(static_cast<GVAccessor*>(gridview)->minY(), minPos.y());
3478 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), maxPos.x());
3479 QCOMPARE(static_cast<GVAccessor*>(gridview)->maxY(), maxPos.y());
3481 QCOMPARE(gridview->originX(), origin_empty.x());
3482 QCOMPARE(gridview->originY(), origin_empty.y());
3483 for (int i=0; i<30; i++)
3484 model.addItem("Item" + QString::number(i), "");
3485 QTRY_COMPARE(gridview->count(), model.count());
3486 QCOMPARE(gridview->originX(), origin_nonEmpty.x());
3487 QCOMPARE(gridview->originY(), origin_nonEmpty.y());
3489 releaseView(window);
3492 void tst_QQuickGridView::extents_data()
3494 QTest::addColumn<QQuickGridView::Flow>("flow");
3495 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3496 QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection");
3497 QTest::addColumn<QPointF>("headerPos");
3498 QTest::addColumn<QPointF>("footerPos");
3499 QTest::addColumn<QPointF>("minPos");
3500 QTest::addColumn<QPointF>("maxPos");
3501 QTest::addColumn<QPointF>("origin_empty");
3502 QTest::addColumn<QPointF>("origin_nonEmpty");
3504 // header is 240x20 (or 20x320 in TopToBottom)
3505 // footer is 240x30 (or 30x320 in TopToBottom)
3506 // grid has 10 rows in LeftToRight mode and 6 columns in TopToBottom
3508 QTest::newRow("LeftToRight, LtR, TtB")
3509 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom
3510 << QPointF(0, -20) << QPointF(0, 0)
3511 << QPointF(0, 20) << QPointF(240, 20)
3512 << QPointF(0, -20) << QPointF(0, -20);
3514 QTest::newRow("LeftToRight, RtL, TtB")
3515 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom
3516 << QPointF(0, -20) << QPointF(0, 0)
3517 << QPointF(0, 20) << QPointF(240, 20)
3518 << QPointF(0, -20) << QPointF(0, -20);
3520 QTest::newRow("LeftToRight, LtR, BtT")
3521 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop
3522 << QPointF(0, 0) << QPointF(0, -30)
3523 << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed
3524 << QPointF(0, -30) << QPointF(0, (-60.0 * 10) - 30);
3526 QTest::newRow("LeftToRight, RtL, BtT")
3527 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop
3528 << QPointF(0, 0) << QPointF(0, -30)
3529 << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed
3530 << QPointF(0, -30) << QPointF(0, (-60.0 * 10) - 30);
3533 QTest::newRow("TopToBottom, LtR, TtB")
3534 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom
3535 << QPointF(-20, 0) << QPointF(0, 0)
3536 << QPointF(20, 0) << QPointF(20, 320)
3537 << QPointF(-20, 0) << QPointF(-20, 0);
3539 QTest::newRow("TopToBottom, RtL, TtB")
3540 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom
3541 << QPointF(0, 0) << QPointF(-30, 0)
3542 << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed
3543 << QPointF(-30, 0) << QPointF((-80.0 * 6) - 30, 0);
3545 QTest::newRow("TopToBottom, LtR, BtT")
3546 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop
3547 << QPointF(-20, -320) << QPointF(0, -320)
3548 << QPointF(20, 0) << QPointF(20, 320)
3549 << QPointF(-20, 0) << QPointF(-20, 0);
3551 QTest::newRow("TopToBottom, RtL, BtT")
3552 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop
3553 << QPointF(0, -320) << QPointF(-30, -320)
3554 << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed
3555 << QPointF(-30, 0) << QPointF((-80.0 * 6) - 30, 0);
3558 void tst_QQuickGridView::resetModel_headerFooter()
3560 // Resetting a model shouldn't crash in views with header/footer
3562 QQuickView *window = createView();
3565 for (int i = 0; i < 6; i++)
3566 model.addItem("Item" + QString::number(i), "");
3567 QQmlContext *ctxt = window->rootContext();
3568 ctxt->setContextProperty("testModel", &model);
3570 window->setSource(testFileUrl("headerfooter.qml"));
3571 qApp->processEvents();
3573 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject());
3574 QTRY_VERIFY(gridview != 0);
3576 QQuickItem *contentItem = gridview->contentItem();
3577 QTRY_VERIFY(contentItem != 0);
3579 QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
3581 QCOMPARE(header->y(), -header->height());
3583 QQuickItem *footer = findItem<QQuickItem>(contentItem, "footer");
3585 QCOMPARE(footer->y(), 60.*2);
3589 header = findItem<QQuickItem>(contentItem, "header");
3591 QCOMPARE(header->y(), -header->height());
3593 footer = findItem<QQuickItem>(contentItem, "footer");
3595 QCOMPARE(footer->y(), 60.*2);
3600 void tst_QQuickGridView::resizeViewAndRepaint()
3602 QQuickView *window = createView();
3606 for (int i = 0; i < 40; i++)
3607 model.addItem("Item" + QString::number(i), "");
3609 QQmlContext *ctxt = window->rootContext();
3610 ctxt->setContextProperty("testModel", &model);
3611 ctxt->setContextProperty("initialWidth", 240);
3612 ctxt->setContextProperty("initialHeight", 100);
3614 window->setSource(testFileUrl("resizeview.qml"));
3616 qApp->processEvents();
3618 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3619 QTRY_VERIFY(gridview != 0);
3620 QQuickItem *contentItem = gridview->contentItem();
3621 QTRY_VERIFY(contentItem != 0);
3622 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3624 // item at index 10 should not be currently visible
3625 QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3627 gridview->setHeight(320);
3628 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", 10));
3630 gridview->setHeight(100);
3631 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
3633 // Ensure we handle -ve sizes
3634 gridview->setHeight(-100);
3635 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 3);
3637 gridview->setCacheBuffer(120);
3638 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 9);
3640 // ensure items in cache become visible
3641 gridview->setHeight(120);
3642 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 15);
3644 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3645 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3646 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3647 if (!item) qWarning() << "Item" << i << "not found";
3649 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3650 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3651 QCOMPARE(delegateVisible(item), i < 9); // inside view visible, outside not visible
3654 // ensure items outside view become invisible
3655 gridview->setHeight(60);
3656 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 12);
3658 itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
3659 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3660 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3661 if (!item) qWarning() << "Item" << i << "not found";
3663 QTRY_COMPARE(item->x(), qreal((i%3)*80));
3664 QTRY_COMPARE(item->y(), qreal((i/3)*60));
3665 QCOMPARE(delegateVisible(item), i < 6); // inside view visible, outside not visible
3671 void tst_QQuickGridView::resizeGrid()
3673 QFETCH(QQuickGridView::Flow, flow);
3674 QFETCH(Qt::LayoutDirection, layoutDirection);
3675 QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection);
3676 QFETCH(QPointF, initialContentPos);
3677 QFETCH(QPointF, firstItemPos);
3680 for (int i = 0; i < 30; i++)
3681 model.addItem("Item" + QString::number(i), "");
3683 QQuickView *window = getView();
3684 QQmlContext *ctxt = window->rootContext();
3685 ctxt->setContextProperty("testModel", &model);
3686 ctxt->setContextProperty("testTopToBottom", flow == QQuickGridView::FlowTopToBottom);
3687 ctxt->setContextProperty("testRightToLeft", layoutDirection == Qt::RightToLeft);
3688 ctxt->setContextProperty("testBottomToTop", verticalLayoutDirection == QQuickGridView::BottomToTop);
3689 window->setSource(testFileUrl("resizegrid.qml"));
3691 qApp->processEvents();
3693 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3694 QTRY_VERIFY(gridview != 0);
3695 QQuickItem *contentItem = gridview->contentItem();
3696 QTRY_VERIFY(contentItem != 0);
3698 // set the width to slightly larger than 3 items across, to test
3699 // items are aligned correctly in right-to-left
3700 window->rootObject()->setWidth(260);
3701 window->rootObject()->setHeight(320);
3702 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3704 QCOMPARE(gridview->contentX(), initialContentPos.x());
3705 QCOMPARE(gridview->contentY(), initialContentPos.y());
3707 QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
3709 QCOMPARE(item0->pos(), firstItemPos);
3711 // Confirm items positioned correctly and indexes correct
3712 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
3713 QVERIFY(items.count() >= 18 && items.count() <= 21);
3714 for (int i = 0; i < model.count() && i < items.count(); ++i) {
3715 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3716 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3717 QCOMPARE(item->pos(), expectedItemPos(gridview, i, 0));
3718 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
3720 QCOMPARE(name->text(), model.name(i));
3723 // change from 3x5 grid to 4x7
3724 window->rootObject()->setWidth(window->rootObject()->width() + 80);
3725 window->rootObject()->setHeight(window->rootObject()->height() + 60*2);
3726 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3728 // other than in LeftToRight+RightToLeft layout, the first item should not move
3729 // if view is resized
3730 QCOMPARE(findItem<QQuickItem>(contentItem, "wrapper", 0), item0);
3731 if (flow == QQuickGridView::FlowLeftToRight && layoutDirection == Qt::RightToLeft)
3732 firstItemPos.rx() += 80;
3733 QCOMPARE(item0->pos(), firstItemPos);
3735 QPointF newContentPos = initialContentPos;
3736 if (flow == QQuickGridView::FlowTopToBottom && layoutDirection == Qt::RightToLeft)
3737 newContentPos.rx() -= 80.0;
3738 if (verticalLayoutDirection == QQuickItemView::BottomToTop)
3739 newContentPos.ry() -= 60.0 * 2;
3740 QCOMPARE(gridview->contentX(), newContentPos.x());
3741 QCOMPARE(gridview->contentY(), newContentPos.y());
3743 // Confirm items positioned correctly and indexes correct
3744 items = findItems<QQuickItem>(contentItem, "wrapper");
3745 QVERIFY(items.count() >= 28);
3746 for (int i = 0; i < model.count() && i < items.count(); ++i) {
3747 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3748 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3749 QCOMPARE(item->pos(), expectedItemPos(gridview, i, 0));
3750 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
3752 QCOMPARE(name->text(), model.name(i));
3755 releaseView(window);
3758 void tst_QQuickGridView::resizeGrid_data()
3760 QTest::addColumn<QQuickGridView::Flow>("flow");
3761 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3762 QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection");
3763 QTest::addColumn<QPointF>("initialContentPos");
3764 QTest::addColumn<QPointF>("firstItemPos");
3766 // Initial view width is 260, so in LeftToRight + right-to-left mode the
3767 // content x should be -20
3769 QTest::newRow("LeftToRight, LtR, TtB")
3770 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom
3774 QTest::newRow("LeftToRight, RtL, TtB")
3775 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom
3776 << QPointF(-20.0, 0)
3777 << QPointF(80.0 * 2, 0);
3779 QTest::newRow("LeftToRight, LtR, BtT")
3780 << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop
3782 << QPointF(0, -60.0);
3784 QTest::newRow("LeftToRight, RtL, BtT")
3785 << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop
3786 << QPointF(-20.0, -320)
3787 << QPointF(80.0 * 2, -60.0);
3790 QTest::newRow("TopToBottom, LtR, TtB")
3791 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom
3795 QTest::newRow("TopToBottom, RtL, TtB")
3796 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom
3798 << QPointF(-80.0, 0);
3800 QTest::newRow("TopToBottom, LtR, BtT")
3801 << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop
3803 << QPointF(0, -60.0);
3805 QTest::newRow("TopToBottom, RtL, BtT")
3806 << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop
3807 << QPointF(-260, -320)
3808 << QPointF(-80.0, -60.0);
3812 void tst_QQuickGridView::changeColumnCount()
3815 for (int i = 0; i < 40; i++)
3816 model.addItem("Item" + QString::number(i), "");
3818 QQuickView *window = createView();
3819 QQmlContext *ctxt = window->rootContext();
3820 ctxt->setContextProperty("testModel", &model);
3821 ctxt->setContextProperty("initialWidth", 100);
3822 ctxt->setContextProperty("initialHeight", 320);
3823 window->setSource(testFileUrl("resizeview.qml"));
3825 qApp->processEvents();
3827 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3828 QTRY_VERIFY(gridview != 0);
3829 QQuickItem *contentItem = gridview->contentItem();
3830 QTRY_VERIFY(contentItem != 0);
3831 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3833 // a single column of 6 items are visible
3834 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3835 QCOMPARE(itemCount, 6);
3836 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3837 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3838 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3839 QCOMPARE(item->x(), 0.0);
3840 QCOMPARE(item->y(), qreal(i*60));
3843 // now 6x3 grid is visible, plus 1 extra below for refill
3844 gridview->setWidth(240);
3845 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3846 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3847 QCOMPARE(itemCount, 6*3 + 1);
3848 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3849 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3850 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3851 QCOMPARE(item->x(), qreal((i%3)*80));
3852 QCOMPARE(item->y(), qreal((i/3)*60));
3855 // back to single column
3856 gridview->setWidth(100);
3857 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
3858 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
3859 QCOMPARE(itemCount, 6);
3860 for (int i = 0; i < model.count() && i < itemCount; ++i) {
3861 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
3862 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
3863 QCOMPARE(item->x(), 0.0);
3864 QCOMPARE(item->y(), qreal(i*60));
3870 void tst_QQuickGridView::indexAt_itemAt_data()
3872 QTest::addColumn<qreal>("x");
3873 QTest::addColumn<qreal>("y");
3874 QTest::addColumn<int>("index");
3876 QTest::newRow("Item 0 - 0, 0") << 0. << 0. << 0;
3877 QTest::newRow("Item 0 - 79, 59") << 79. << 59. << 0;
3878 QTest::newRow("Item 1 - 80, 0") << 80. << 0. << 1;
3879 QTest::newRow("Item 3 - 0, 60") << 0. << 60. << 3;
3880 QTest::newRow("No Item - 240, 0") << 240. << 0. << -1;
3883 void tst_QQuickGridView::indexAt_itemAt()
3889 QQuickView *window = getView();
3892 model.addItem("Fred", "12345");
3893 model.addItem("John", "2345");
3894 model.addItem("Bob", "54321");
3895 model.addItem("Billy", "22345");
3896 model.addItem("Sam", "2945");
3897 model.addItem("Ben", "04321");
3898 model.addItem("Jim", "0780");
3900 window->rootContext()->setContextProperty("testModel", &model);
3901 window->setSource(testFileUrl("gridview1.qml"));
3902 qApp->processEvents();
3904 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
3905 QTRY_VERIFY(gridview != 0);
3907 QQuickItem *contentItem = gridview->contentItem();
3908 QTRY_VERIFY(contentItem != 0);
3910 QTRY_COMPARE(gridview->count(), model.count());
3912 QQuickItem *item = 0;
3914 item = findItem<QQuickItem>(contentItem, "wrapper", index);
3917 QCOMPARE(gridview->indexAt(x, y), index);
3918 QVERIFY(gridview->itemAt(x, y) == item);
3920 releaseView(window);
3923 void tst_QQuickGridView::onAdd()
3925 QFETCH(int, initialItemCount);
3926 QFETCH(int, itemsToAdd);
3928 const int delegateWidth = 50;
3929 const int delegateHeight = 100;
3931 QQuickView *window = getView();
3932 window->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
3934 // these initial items should not trigger GridView.onAdd
3935 for (int i=0; i<initialItemCount; i++)
3936 model.addItem("dummy value", "dummy value");
3938 QQmlContext *ctxt = window->rootContext();
3939 ctxt->setContextProperty("testModel", &model);
3940 ctxt->setContextProperty("delegateWidth", delegateWidth);
3941 ctxt->setContextProperty("delegateHeight", delegateHeight);
3942 window->setSource(testFileUrl("attachedSignals.qml"));
3944 QObject *object = window->rootObject();
3945 object->setProperty("width", window->width());
3946 object->setProperty("height", window->height());
3947 qApp->processEvents();
3949 QList<QPair<QString, QString> > items;
3950 for (int i=0; i<itemsToAdd; i++)
3951 items << qMakePair(QString("value %1").arg(i), QString::number(i));
3952 model.addItems(items);
3954 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(window->rootObject())->count());
3955 qApp->processEvents();
3957 QVariantList result = object->property("addedDelegates").toList();
3958 QTRY_COMPARE(result.count(), items.count());
3959 for (int i=0; i<items.count(); i++)
3960 QCOMPARE(result[i].toString(), items[i].first);
3962 releaseView(window);
3965 void tst_QQuickGridView::onAdd_data()
3967 QTest::addColumn<int>("initialItemCount");
3968 QTest::addColumn<int>("itemsToAdd");
3970 QTest::newRow("0, add 1") << 0 << 1;
3971 QTest::newRow("0, add 2") << 0 << 2;
3972 QTest::newRow("0, add 10") << 0 << 10;
3974 QTest::newRow("1, add 1") << 1 << 1;
3975 QTest::newRow("1, add 2") << 1 << 2;
3976 QTest::newRow("1, add 10") << 1 << 10;
3978 QTest::newRow("5, add 1") << 5 << 1;
3979 QTest::newRow("5, add 2") << 5 << 2;
3980 QTest::newRow("5, add 10") << 5 << 10;
3983 void tst_QQuickGridView::onRemove()
3985 QFETCH(int, initialItemCount);
3986 QFETCH(int, indexToRemove);
3987 QFETCH(int, removeCount);
3989 const int delegateWidth = 50;
3990 const int delegateHeight = 100;
3992 for (int i=0; i<initialItemCount; i++)
3993 model.addItem(QString("value %1").arg(i), "dummy value");
3995 QQuickView *window = getView();
3996 QQmlContext *ctxt = window->rootContext();
3997 ctxt->setContextProperty("testModel", &model);
3998 ctxt->setContextProperty("delegateWidth", delegateWidth);
3999 ctxt->setContextProperty("delegateHeight", delegateHeight);
4000 window->setSource(testFileUrl("attachedSignals.qml"));
4001 QObject *object = window->rootObject();
4003 model.removeItems(indexToRemove, removeCount);
4004 QTRY_COMPARE(model.count(), qobject_cast<QQuickGridView*>(window->rootObject())->count());
4005 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
4007 releaseView(window);
4010 void tst_QQuickGridView::onRemove_data()
4012 QTest::addColumn<int>("initialItemCount");
4013 QTest::addColumn<int>("indexToRemove");
4014 QTest::addColumn<int>("removeCount");
4016 QTest::newRow("remove first") << 1 << 0 << 1;
4017 QTest::newRow("two items, remove first") << 2 << 0 << 1;
4018 QTest::newRow("two items, remove last") << 2 << 1 << 1;
4019 QTest::newRow("two items, remove all") << 2 << 0 << 2;
4021 QTest::newRow("four items, remove first") << 4 << 0 << 1;
4022 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
4023 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
4024 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
4025 QTest::newRow("four items, remove last") << 4 << 3 << 1;
4026 QTest::newRow("four items, remove all") << 4 << 0 << 4;
4028 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
4029 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
4030 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
4033 void tst_QQuickGridView::columnCount()
4036 window.setSource(testFileUrl("gridview4.qml"));
4038 window.requestActivateWindow();
4039 QVERIFY(QTest::qWaitForWindowActive(&window));
4041 QQuickGridView *view = qobject_cast<QQuickGridView*>(window.rootObject());
4043 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
4044 QCOMPARE(view->cellHeight(), qreal(100));
4046 QList<QQuickItem*> items = findItems<QQuickItem>(view, "delegate");
4047 QCOMPARE(items.size(), 18);
4048 QCOMPARE(items.at(8)->y(), qreal(0));
4049 QCOMPARE(items.at(9)->y(), qreal(100));
4052 void tst_QQuickGridView::margins()
4055 QQuickView *window = createView();
4058 for (int i = 0; i < 40; i++)
4059 model.addItem("Item" + QString::number(i), "");
4061 QQmlContext *ctxt = window->rootContext();
4062 ctxt->setContextProperty("testModel", &model);
4063 ctxt->setContextProperty("testRightToLeft", QVariant(false));
4065 window->setSource(testFileUrl("margins.qml"));
4067 qApp->processEvents();
4069 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4070 QTRY_VERIFY(gridview != 0);
4071 QQuickItem *contentItem = gridview->contentItem();
4072 QTRY_VERIFY(contentItem != 0);
4073 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4075 QCOMPARE(gridview->contentX(), -30.);
4076 QCOMPARE(gridview->originX(), 0.);
4079 gridview->positionViewAtEnd();
4080 qreal pos = gridview->contentX();
4081 gridview->setContentX(pos + 80);
4082 gridview->returnToBounds();
4083 QTRY_COMPARE(gridview->contentX(), pos + 50);
4085 // remove item before visible and check that left margin is maintained
4086 // and originX is updated
4087 gridview->setContentX(200);
4088 model.removeItems(0, 4);
4090 gridview->setContentX(-50);
4091 gridview->returnToBounds();
4092 QCOMPARE(gridview->originX(), 100.);
4093 QTRY_COMPARE(gridview->contentX(), 70.);
4095 // reduce left margin
4096 gridview->setLeftMargin(20);
4097 QCOMPARE(gridview->originX(), 100.);
4098 QTRY_COMPARE(gridview->contentX(), 80.);
4101 gridview->positionViewAtEnd();
4102 QCOMPARE(gridview->originX(), 0.); // positionViewAtEnd() resets origin
4103 pos = gridview->contentX();
4104 gridview->setContentX(pos + 80);
4105 gridview->returnToBounds();
4106 QTRY_COMPARE(gridview->contentX(), pos + 50);
4108 // reduce right margin
4109 pos = gridview->contentX();
4110 gridview->setRightMargin(40);
4111 QCOMPARE(gridview->originX(), 0.);
4112 QTRY_COMPARE(gridview->contentX(), pos-10);
4118 QQuickView *window = createView();
4122 for (int i = 0; i < 40; i++)
4123 model.addItem("Item" + QString::number(i), "");
4125 QQmlContext *ctxt = window->rootContext();
4126 ctxt->setContextProperty("testModel", &model);
4127 ctxt->setContextProperty("testRightToLeft", QVariant(true));
4129 window->setSource(testFileUrl("margins.qml"));
4130 qApp->processEvents();
4132 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4133 QTRY_VERIFY(gridview != 0);
4135 QQuickItem *contentItem = gridview->contentItem();
4136 QTRY_VERIFY(contentItem != 0);
4138 QTRY_COMPARE(gridview->contentX(), -240+50.);
4139 QTRY_COMPARE(gridview->originX(), -100. * 10);
4142 gridview->positionViewAtEnd();
4143 qreal pos = gridview->contentX();
4144 gridview->setContentX(pos - 80);
4145 gridview->returnToBounds();
4146 QTRY_COMPARE(gridview->contentX(), pos - 30);
4148 // remove item before visible and check that left margin is maintained
4149 // and originX is updated
4150 gridview->setContentX(-400);
4151 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4152 model.removeItems(0, 4);
4153 QTRY_COMPARE(model.count(), gridview->count());
4154 gridview->setContentX(-240+50);
4155 gridview->returnToBounds();
4156 QCOMPARE(gridview->originX(), -1000.);
4157 QTRY_COMPARE(gridview->contentX(), -240-50.);
4159 // reduce right margin
4160 pos = gridview->contentX();
4161 gridview->setRightMargin(40);
4162 QCOMPARE(gridview->originX(), -1000.);
4163 QTRY_COMPARE(gridview->contentX(), -240-100 + 40.);
4166 gridview->positionViewAtEnd();
4167 QCOMPARE(gridview->originX(), -900.); // positionViewAtEnd() resets origin
4168 pos = gridview->contentX();
4169 gridview->setContentX(pos - 80);
4170 gridview->returnToBounds();
4171 QTRY_COMPARE(gridview->contentX(), pos - 30);
4173 // reduce left margin
4174 pos = gridview->contentX();
4175 gridview->setLeftMargin(20);
4176 QCOMPARE(gridview->originX(), -900.);
4177 QTRY_COMPARE(gridview->contentX(), pos+10);
4183 void tst_QQuickGridView::creationContext()
4186 window.setGeometry(0,0,240,320);
4187 window.setSource(testFileUrl("creationContext.qml"));
4188 qApp->processEvents();
4190 QQuickItem *rootItem = qobject_cast<QQuickItem *>(window.rootObject());
4192 QVERIFY(rootItem->property("count").toInt() > 0);
4195 QVERIFY(item = findItem<QQuickItem>(rootItem, "listItem"));
4196 QCOMPARE(item->property("text").toString(), QString("Hello!"));
4197 QVERIFY(item = rootItem->findChild<QQuickItem *>("header"));
4198 QCOMPARE(item->property("text").toString(), QString("Hello!"));
4199 QVERIFY(item = rootItem->findChild<QQuickItem *>("footer"));
4200 QCOMPARE(item->property("text").toString(), QString("Hello!"));
4203 void tst_QQuickGridView::snapToRow_data()
4205 QTest::addColumn<QQuickGridView::Flow>("flow");
4206 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
4207 QTest::addColumn<int>("highlightRangeMode");
4208 QTest::addColumn<QPoint>("flickStart");
4209 QTest::addColumn<QPoint>("flickEnd");
4210 QTest::addColumn<qreal>("snapAlignment");
4211 QTest::addColumn<qreal>("endExtent");
4212 QTest::addColumn<qreal>("startExtent");
4214 QTest::newRow("vertical, left to right") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
4215 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 800.0 << 0.0;
4217 QTest::newRow("horizontal, left to right") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
4218 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 800.0 << 0.0;
4220 QTest::newRow("horizontal, right to left") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
4221 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 << -240.0;
4223 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
4224 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 940.0 << -20.0;
4226 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
4227 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 940.0 << -20.0;
4229 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
4230 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 - 140.0 << -220.0;
4233 void tst_QQuickGridView::snapToRow()
4235 QFETCH(QQuickGridView::Flow, flow);
4236 QFETCH(Qt::LayoutDirection, layoutDirection);
4237 QFETCH(int, highlightRangeMode);
4238 QFETCH(QPoint, flickStart);
4239 QFETCH(QPoint, flickEnd);
4240 QFETCH(qreal, snapAlignment);
4241 QFETCH(qreal, endExtent);
4242 QFETCH(qreal, startExtent);
4244 QQuickView *window = getView();
4246 window->setSource(testFileUrl("snapToRow.qml"));
4248 qApp->processEvents();
4250 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4251 QTRY_VERIFY(gridview != 0);
4253 gridview->setFlow(flow);
4254 gridview->setLayoutDirection(layoutDirection);
4255 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
4256 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4258 QQuickItem *contentItem = gridview->contentItem();
4259 QTRY_VERIFY(contentItem != 0);
4261 // confirm that a flick hits an item boundary
4262 flick(window, flickStart, flickEnd, 180);
4263 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
4264 if (flow == QQuickGridView::FlowLeftToRight)
4265 QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
4267 QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
4271 flick(window, flickStart, flickEnd, 180);
4272 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
4273 } while (flow == QQuickGridView::FlowLeftToRight
4274 ? !gridview->isAtYEnd()
4275 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
4277 if (flow == QQuickGridView::FlowLeftToRight)
4278 QCOMPARE(gridview->contentY(), endExtent);
4280 QCOMPARE(gridview->contentX(), endExtent);
4284 flick(window, flickEnd, flickStart, 180);
4285 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
4286 } while (flow == QQuickGridView::FlowLeftToRight
4287 ? !gridview->isAtYBeginning()
4288 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
4290 if (flow == QQuickGridView::FlowLeftToRight)
4291 QCOMPARE(gridview->contentY(), startExtent);
4293 QCOMPARE(gridview->contentX(), startExtent);
4295 releaseView(window);
4298 void tst_QQuickGridView::snapOneRow_data()
4300 QTest::addColumn<QQuickGridView::Flow>("flow");
4301 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
4302 QTest::addColumn<int>("highlightRangeMode");
4303 QTest::addColumn<QPoint>("flickStart");
4304 QTest::addColumn<QPoint>("flickEnd");
4305 QTest::addColumn<qreal>("snapAlignment");
4306 QTest::addColumn<qreal>("endExtent");
4307 QTest::addColumn<qreal>("startExtent");
4309 QTest::newRow("vertical, left to right") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
4310 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 240.0 << 0.0;
4312 QTest::newRow("horizontal, left to right") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
4313 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0;
4315 QTest::newRow("horizontal, right to left") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange)
4316 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 << -240.0;
4318 QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
4319 << QPoint(20, 200) << QPoint(20, 20) << 100.0 << 340.0 << -20.0;
4321 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
4322 << QPoint(200, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0;
4324 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
4325 << QPoint(20, 20) << QPoint(200, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0;
4328 void tst_QQuickGridView::snapOneRow()
4330 QFETCH(QQuickGridView::Flow, flow);
4331 QFETCH(Qt::LayoutDirection, layoutDirection);
4332 QFETCH(int, highlightRangeMode);
4333 QFETCH(QPoint, flickStart);
4334 QFETCH(QPoint, flickEnd);
4335 QFETCH(qreal, snapAlignment);
4336 QFETCH(qreal, endExtent);
4337 QFETCH(qreal, startExtent);
4339 QQuickView *window = getView();
4341 window->setSource(testFileUrl("snapOneRow.qml"));
4343 qApp->processEvents();
4345 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4346 QTRY_VERIFY(gridview != 0);
4348 gridview->setFlow(flow);
4349 gridview->setLayoutDirection(layoutDirection);
4350 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
4351 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4353 QQuickItem *contentItem = gridview->contentItem();
4354 QTRY_VERIFY(contentItem != 0);
4356 QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged()));
4358 // confirm that a flick hits next row boundary
4359 flick(window, flickStart, flickEnd, 180);
4360 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
4361 if (flow == QQuickGridView::FlowLeftToRight)
4362 QCOMPARE(gridview->contentY(), snapAlignment);
4364 QCOMPARE(gridview->contentX(), snapAlignment);
4366 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
4367 QCOMPARE(gridview->currentIndex(), 2);
4368 QCOMPARE(currentIndexSpy.count(), 1);
4373 flick(window, flickStart, flickEnd, 180);
4374 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
4375 } while (flow == QQuickGridView::FlowLeftToRight
4376 ? !gridview->isAtYEnd()
4377 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
4379 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
4380 QCOMPARE(gridview->currentIndex(), 6);
4381 QCOMPARE(currentIndexSpy.count(), 3);
4384 if (flow == QQuickGridView::FlowLeftToRight)
4385 QCOMPARE(gridview->contentY(), endExtent);
4387 QCOMPARE(gridview->contentX(), endExtent);
4391 flick(window, flickEnd, flickStart, 180);
4392 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
4393 } while (flow == QQuickGridView::FlowLeftToRight
4394 ? !gridview->isAtYBeginning()
4395 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
4397 if (flow == QQuickGridView::FlowLeftToRight)
4398 QCOMPARE(gridview->contentY(), startExtent);
4400 QCOMPARE(gridview->contentX(), startExtent);
4402 if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
4403 QCOMPARE(gridview->currentIndex(), 0);
4404 QCOMPARE(currentIndexSpy.count(), 6);
4407 releaseView(window);
4411 void tst_QQuickGridView::unaligned()
4413 QQuickView *window = createView();
4417 for (int i = 0; i < 10; i++)
4418 model.addItem("Item" + QString::number(i), "");
4420 QQmlContext *ctxt = window->rootContext();
4421 ctxt->setContextProperty("testModel", &model);
4423 window->setSource(testFileUrl("unaligned.qml"));
4424 qApp->processEvents();
4426 QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject());
4427 QVERIFY(gridview != 0);
4429 QQuickItem *contentItem = gridview->contentItem();
4430 QVERIFY(contentItem != 0);
4432 for (int i = 0; i < 10; ++i) {
4433 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4434 if (!item) qWarning() << "Item" << i << "not found";
4436 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4437 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4441 for (int i = 10; i < 18; ++i) {
4442 model.addItem("Item" + QString::number(i), "");
4443 QQuickItem *item = 0;
4444 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4445 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4446 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4450 for (int i = 0; i < 10; ++i) {
4451 model.insertItem(i, "Item" + QString::number(i), "");
4452 QQuickItem *item = 0;
4453 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4454 QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth()));
4455 QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight()));
4459 model.removeItems(7, 10);
4460 QTRY_COMPARE(model.count(), gridview->count());
4461 for (int i = 0; i < 18; ++i) {
4462 QQuickItem *item = 0;
4463 QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i));
4464 QCOMPARE(item->x(), qreal(i%9)*gridview->cellWidth());
4465 QCOMPARE(item->y(), qreal(i/9)*gridview->cellHeight());
4471 void tst_QQuickGridView::populateTransitions()
4473 QFETCH(bool, staticallyPopulate);
4474 QFETCH(bool, dynamicallyPopulate);
4475 QFETCH(bool, usePopulateTransition);
4477 QPointF transitionFrom(-50, -50);
4478 QPointF transitionVia(100, 100);
4479 QaimModel model_transitionFrom;
4480 QaimModel model_transitionVia;
4483 if (staticallyPopulate) {
4484 for (int i = 0; i < 30; i++)
4485 model.addItem("item" + QString::number(i), "");
4488 QQuickView *window = getView();
4489 window->rootContext()->setContextProperty("testModel", &model);
4490 window->rootContext()->setContextProperty("usePopulateTransition", usePopulateTransition);
4491 window->rootContext()->setContextProperty("dynamicallyPopulate", dynamicallyPopulate);
4492 window->rootContext()->setContextProperty("transitionFrom", transitionFrom);
4493 window->rootContext()->setContextProperty("transitionVia", transitionVia);
4494 window->rootContext()->setContextProperty("model_transitionFrom", &model_transitionFrom);
4495 window->rootContext()->setContextProperty("model_transitionVia", &model_transitionVia);
4496 window->setSource(testFileUrl("populateTransitions.qml"));
4499 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4501 QQuickItem *contentItem = gridview->contentItem();
4502 QVERIFY(contentItem);
4504 // check the populate transition is run
4505 if (staticallyPopulate && usePopulateTransition) {
4506 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 18);
4507 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4508 } else if (dynamicallyPopulate) {
4509 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
4510 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 18);
4512 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4513 QCOMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
4514 QCOMPARE(gridview->property("countAddTransitions").toInt(), 0);
4517 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4518 for (int i=0; i < model.count() && i < itemCount; ++i) {
4519 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4520 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4521 QTRY_COMPARE(item->x(), (i%3)*80.0);
4522 QTRY_COMPARE(item->y(), (i/3)*60.0);
4523 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4525 QTRY_COMPARE(name->text(), model.name(i));
4528 gridview->setProperty("countPopulateTransitions", 0);
4529 gridview->setProperty("countAddTransitions", 0);
4531 // add an item and check this is done with add transition, not populate
4532 model.insertItem(0, "another item", "");
4533 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 1);
4534 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
4537 window->rootContext()->setContextProperty("testModel", QVariant());
4538 QTRY_COMPARE(gridview->count(), 0);
4539 QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
4540 gridview->setProperty("countPopulateTransitions", 0);
4541 gridview->setProperty("countAddTransitions", 0);
4543 // set to a valid model and check populate transition is run a second time
4545 for (int i = 0; i < 30; i++)
4546 model.addItem("item" + QString::number(i), "");
4547 window->rootContext()->setContextProperty("testModel", &model);
4548 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4550 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 18 : 0);
4551 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4553 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4554 for (int i=0; i < model.count() && i < itemCount; ++i) {
4555 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4556 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4557 QTRY_COMPARE(item->x(), (i%3)*80.0);
4558 QTRY_COMPARE(item->y(), (i/3)*60.0);
4559 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4561 QTRY_COMPARE(name->text(), model.name(i));
4564 // reset model and check populate transition is run again
4565 gridview->setProperty("countPopulateTransitions", 0);
4566 gridview->setProperty("countAddTransitions", 0);
4568 QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 18 : 0);
4569 QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
4571 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
4572 for (int i=0; i < model.count() && i < itemCount; ++i) {
4573 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4574 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4575 QTRY_COMPARE(item->x(), (i%3)*80.0);
4576 QTRY_COMPARE(item->y(), (i/3)*60.0);
4577 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4579 QTRY_COMPARE(name->text(), model.name(i));
4582 releaseView(window);
4585 void tst_QQuickGridView::populateTransitions_data()
4587 QTest::addColumn<bool>("staticallyPopulate");
4588 QTest::addColumn<bool>("dynamicallyPopulate");
4589 QTest::addColumn<bool>("usePopulateTransition");
4591 QTest::newRow("static") << true << false << true;
4592 QTest::newRow("static, no populate") << true << false << false;
4594 QTest::newRow("dynamic") << false << true << true;
4595 QTest::newRow("dynamic, no populate") << false << true << false;
4597 QTest::newRow("empty to start with") << false << false << true;
4598 QTest::newRow("empty to start with, no populate") << false << false << false;
4601 void tst_QQuickGridView::addTransitions()
4603 QFETCH(int, initialItemCount);
4604 QFETCH(bool, shouldAnimateTargets);
4605 QFETCH(qreal, contentYRowOffset);
4606 QFETCH(int, insertionIndex);
4607 QFETCH(int, insertionCount);
4608 QFETCH(ListRange, expectedDisplacedIndexes);
4610 // added items should start here
4611 QPointF targetItems_transitionFrom(-50, -50);
4613 // displaced items should pass through this point
4614 QPointF displacedItems_transitionVia(100, 100);
4617 for (int i = 0; i < initialItemCount; i++)
4618 model.addItem("Original item" + QString::number(i), "");
4619 QaimModel model_targetItems_transitionFrom;
4620 QaimModel model_displacedItems_transitionVia;
4622 QQuickView *window = getView();
4623 QQmlContext *ctxt = window->rootContext();
4624 ctxt->setContextProperty("testModel", &model);
4625 ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
4626 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4627 ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
4628 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4629 window->setSource(testFileUrl("addTransitions.qml"));
4632 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4633 QTRY_VERIFY(gridview != 0);
4634 QQuickItem *contentItem = gridview->contentItem();
4635 QVERIFY(contentItem != 0);
4636 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4638 if (contentYRowOffset != 0) {
4639 gridview->setContentY(contentYRowOffset * 60.0);
4640 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4643 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4645 // only target items that will become visible should be animated
4646 QList<QPair<QString, QString> > newData;
4647 QList<QPair<QString, QString> > expectedTargetData;
4648 QList<int> targetIndexes;
4649 if (shouldAnimateTargets) {
4650 for (int i=insertionIndex; i<insertionIndex+insertionCount; i++) {
4651 newData << qMakePair(QString("New item %1").arg(i), QString(""));
4653 // last visible item is the first item of the row beneath the view
4654 if (i >= (gridview->contentY() / 60)*3 && i < qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) {
4655 expectedTargetData << newData.last();
4659 QVERIFY(expectedTargetData.count() > 0);
4663 if (!newData.isEmpty()) {
4664 model.insertItems(insertionIndex, newData);
4665 QTRY_COMPARE(model.count(), gridview->count());
4668 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4670 if (shouldAnimateTargets) {
4671 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4672 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4673 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4675 // check the target and displaced items were animated
4676 model_targetItems_transitionFrom.matchAgainst(expectedTargetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
4677 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4679 // check attached properties
4680 matchItemsAndIndexes(gridview->property("targetTrans_items").toMap(), model, targetIndexes);
4681 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4682 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4683 if (expectedDisplacedIndexes.isValid()) {
4684 // adjust expectedDisplacedIndexes to their final values after the move
4685 QList<int> displacedIndexes = adjustIndexesForAddDisplaced(expectedDisplacedIndexes.indexes, insertionIndex, insertionCount);
4686 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4687 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4688 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4691 QTRY_COMPARE(model_targetItems_transitionFrom.count(), 0);
4692 QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0);
4695 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4696 int firstVisibleIndex = -1;
4697 for (int i=0; i<items.count(); i++) {
4698 if (items[i]->y() >= gridview->contentY()) {
4699 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4700 firstVisibleIndex = e.evaluate().toInt();
4704 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4706 // verify all items moved to the correct final positions
4707 for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
4708 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4709 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4710 QCOMPARE(item->x(), (i%3)*80.0);
4711 QCOMPARE(item->y(), (i/3)*60.0);
4712 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
4714 QCOMPARE(name->text(), model.name(i));
4717 releaseView(window);
4720 void tst_QQuickGridView::addTransitions_data()
4722 QTest::addColumn<int>("initialItemCount");
4723 QTest::addColumn<qreal>("contentYRowOffset");
4724 QTest::addColumn<bool>("shouldAnimateTargets");
4725 QTest::addColumn<int>("insertionIndex");
4726 QTest::addColumn<int>("insertionCount");
4727 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4729 // if inserting a full row before visible index, items don't appear or animate in, even if there are > 1 new items
4730 QTest::newRow("insert 1, just before start")
4731 << 30 << 1.0 << false
4732 << 0 << 1 << ListRange();
4733 QTest::newRow("insert 1, way before start")
4734 << 30 << 1.0 << false
4735 << 0 << 1 << ListRange();
4736 QTest::newRow("insert multiple, just before start")
4737 << 30 << 1.0 << false
4738 << 0 << 3 << ListRange();
4739 QTest::newRow("insert multiple (< 1 row), just before start")
4740 << 30 << 1.0 << false
4741 << 0 << 2 << ListRange();
4742 QTest::newRow("insert multiple, way before start")
4743 << 30 << 3.0 << false
4744 << 0 << 3 << ListRange();
4746 QTest::newRow("insert 1 at start")
4747 << 30 << 0.0 << true
4748 << 0 << 1 << ListRange(0, 17);
4749 QTest::newRow("insert multiple at start")
4750 << 30 << 0.0 << true
4751 << 0 << 3 << ListRange(0, 17);
4752 QTest::newRow("insert multiple (> 1 row) at start")
4753 << 30 << 0.0 << true
4754 << 0 << 5 << ListRange(0, 17);
4755 QTest::newRow("insert 1 at start, content y not 0")
4756 << 30 << 1.0 << true // first visible is index 3
4757 << 3 << 1 << ListRange(0 + 3, 17 + 3);
4758 QTest::newRow("insert multiple at start, content y not 0")
4759 << 30 << 1.0 << true // first visible is index 3
4760 << 3 << 3 << ListRange(0 + 3, 17 + 3);
4761 QTest::newRow("insert multiple (> 1 row) at start, content y not 0")
4762 << 30 << 1.0 << true // first visible is index 3
4763 << 3 << 5 << ListRange(0 + 3, 17 + 3);
4765 QTest::newRow("insert 1 at start, to empty grid")
4767 << 0 << 1 << ListRange();
4768 QTest::newRow("insert multiple at start, to empty grid")
4770 << 0 << 3 << ListRange();
4772 QTest::newRow("insert 1 at middle")
4773 << 30 << 0.0 << true
4774 << 7 << 1 << ListRange(7, 17);
4775 QTest::newRow("insert multiple at middle")
4776 << 30 << 0.0 << true
4777 << 7 << 3 << ListRange(7, 17);
4778 QTest::newRow("insert multiple (> 1 row) at middle")
4779 << 30 << 0.0 << true
4780 << 7 << 5 << ListRange(7, 17);
4782 QTest::newRow("insert 1 at bottom")
4783 << 30 << 0.0 << true
4784 << 17 << 1 << ListRange(17, 17);
4785 QTest::newRow("insert multiple at bottom")
4786 << 30 << 0.0 << true
4787 << 17 << 3 << ListRange(17, 17);
4788 QTest::newRow("insert 1 at bottom, content y not 0")
4789 << 30 << 1.0 << true
4790 << 17 + 3 << 1 << ListRange(17 + 3, 17 + 3);
4791 QTest::newRow("insert multiple at bottom, content y not 0")
4792 << 30 << 1.0 << true
4793 << 17 + 3 << 3 << ListRange(17 + 3, 17 + 3);
4796 // items added after the last visible will not be animated in, since they
4797 // do not appear in the final view
4798 QTest::newRow("insert 1 after end")
4799 << 30 << 0.0 << false
4800 << 18 << 1 << ListRange();
4801 QTest::newRow("insert multiple after end")
4802 << 30 << 0.0 << false
4803 << 18 << 3 << ListRange();
4806 void tst_QQuickGridView::moveTransitions()
4808 QFETCH(int, initialItemCount);
4809 QFETCH(qreal, contentYRowOffset);
4810 QFETCH(qreal, rowOffsetAfterMove);
4811 QFETCH(int, moveFrom);
4812 QFETCH(int, moveTo);
4813 QFETCH(int, moveCount);
4814 QFETCH(ListRange, expectedDisplacedIndexes);
4816 // target and displaced items should pass through these points
4817 QPointF targetItems_transitionVia(-50, 50);
4818 QPointF displacedItems_transitionVia(100, 100);
4821 for (int i = 0; i < initialItemCount; i++)
4822 model.addItem("Original item" + QString::number(i), "");
4823 QaimModel model_targetItems_transitionVia;
4824 QaimModel model_displacedItems_transitionVia;
4826 QQuickView *window = getView();
4827 QQmlContext *ctxt = window->rootContext();
4828 ctxt->setContextProperty("testModel", &model);
4829 ctxt->setContextProperty("model_targetItems_transitionVia", &model_targetItems_transitionVia);
4830 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
4831 ctxt->setContextProperty("targetItems_transitionVia", targetItems_transitionVia);
4832 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
4833 window->setSource(testFileUrl("moveTransitions.qml"));
4836 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
4837 QTRY_VERIFY(gridview != 0);
4838 QQuickItem *contentItem = gridview->contentItem();
4839 QVERIFY(contentItem != 0);
4842 if (contentYRowOffset != 0) {
4843 gridview->setContentY(contentYRowOffset * 60.0);
4844 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
4847 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
4849 // Items moving to *or* from visible positions should be animated.
4850 // Otherwise, they should not be animated.
4851 QList<QPair<QString, QString> > expectedTargetData;
4852 QList<int> targetIndexes;
4853 for (int i=moveFrom; i<moveFrom+moveCount; i++) {
4854 int toIndex = moveTo + (i - moveFrom);
4855 int firstVisibleIndex = (gridview->contentY() / 60) * 3;
4856 int lastVisibleIndex = (qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) - 1;
4857 if ((i >= firstVisibleIndex && i <= lastVisibleIndex)
4858 || (toIndex >= firstVisibleIndex && toIndex <= lastVisibleIndex)) {
4859 expectedTargetData << qMakePair(model.name(i), model.number(i));
4863 // ViewTransition.index provides the indices that items are moving to, not from
4864 targetIndexes = adjustIndexesForMove(targetIndexes, moveFrom, moveTo, moveCount);
4867 model.moveItems(moveFrom, moveTo, moveCount);
4869 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
4870 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
4871 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
4873 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
4875 // check the target and displaced items were animated
4876 model_targetItems_transitionVia.matchAgainst(expectedTargetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
4877 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
4879 // check attached properties
4880 matchItemsAndIndexes(gridview->property("targetTrans_items").toMap(), model, targetIndexes);
4881 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
4882 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
4883 if (expectedDisplacedIndexes.isValid()) {
4884 // adjust expectedDisplacedIndexes to their final values after the move
4885 QList<int> displacedIndexes = adjustIndexesForMove(expectedDisplacedIndexes.indexes, moveFrom, moveTo, moveCount);
4886 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
4887 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
4888 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
4891 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
4892 int firstVisibleIndex = -1;
4893 for (int i=0; i<items.count(); i++) {
4894 if (items[i]->y() >= gridview->contentY()) {
4895 QQmlExpression e(qmlContext(items[i]), items[i], "index");
4896 firstVisibleIndex = e.evaluate().toInt();
4900 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
4902 // verify all items moved to the correct final positions
4903 qreal pixelOffset = 60 * rowOffsetAfterMove;
4904 for (int i=firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
4905 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
4906 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
4907 QCOMPARE(item->x(), (i%3)*80.0);
4908 QCOMPARE(item->y(), (i/3)*60.0 + pixelOffset);
4909 name = findItem<QQuickText>(contentItem, "textName", i);
4911 QTRY_COMPARE(name->text(), model.name(i));
4914 releaseView(window);
4917 void tst_QQuickGridView::moveTransitions_data()
4919 QTest::addColumn<int>("initialItemCount");
4920 QTest::addColumn<qreal>("contentYRowOffset");
4921 QTest::addColumn<qreal>("rowOffsetAfterMove");
4922 QTest::addColumn<int>("moveFrom");
4923 QTest::addColumn<int>("moveTo");
4924 QTest::addColumn<int>("moveCount");
4925 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
4927 QTest::newRow("move from above view, outside visible items, move 1")
4929 << 1 << 10 << 1 << ListRange(6, 10);
4930 QTest::newRow("move from above view, outside visible items, move 1 (first item)")
4932 << 0 << 10 << 1 << ListRange(6, 10);
4933 QTest::newRow("move from above view, outside visible items, move multiple")
4935 << 1 << 10 << 3 << ListRange(13, 23);
4936 QTest::newRow("move from above view, mix of visible/non-visible")
4938 << 1 << 10 << 6 << (ListRange(7, 15) + ListRange(16, 23));
4939 QTest::newRow("move from above view, mix of visible/non-visible (move first)")
4941 << 0 << 10 << 6 << ListRange(16, 23);
4943 QTest::newRow("move within view, move 1 down")
4945 << 1 << 10 << 1 << ListRange(2, 10);
4946 QTest::newRow("move within view, move 1 down, move first item")
4948 << 0 << 10 << 1 << ListRange(1, 10);
4949 QTest::newRow("move within view, move 1 down, move first item, contentY not 0")
4951 << 0+6 << 10+6 << 1 << ListRange(1+6, 10+6);
4952 QTest::newRow("move within view, move 1 down, to last item")
4954 << 10 << 17 << 1 << ListRange(11, 17);
4955 QTest::newRow("move within view, move first->last")
4957 << 0 << 17 << 1 << ListRange(1, 17);
4959 QTest::newRow("move within view, move multiple down")
4961 << 1 << 10 << 3 << ListRange(4, 12);
4962 QTest::newRow("move within view, move multiple down, move first item")
4964 << 0 << 10 << 3 << ListRange(3, 12);
4965 QTest::newRow("move within view, move multiple down, move first item, contentY not 0")
4967 << 0+3 << 10+3 << 3 << ListRange(3+3, 12+3);
4968 QTest::newRow("move within view, move multiple down, displace last item")
4970 << 5 << 15 << 3 << ListRange(8, 17);
4971 QTest::newRow("move within view, move multiple down, move first->last")
4973 << 0 << 15 << 3 << ListRange(3, 17);
4975 QTest::newRow("move within view, move 1 up")
4977 << 10 << 1 << 1 << ListRange(1, 9);
4978 QTest::newRow("move within view, move 1 up, move to first index")
4980 << 10 << 0 << 1 << ListRange(0, 9);
4981 QTest::newRow("move within view, move 1 up, move to first index, contentY not 0")
4983 << 10+6 << 0+6 << 1 << ListRange(0+6, 9+6);
4984 QTest::newRow("move within view, move 1 up, move to first index, contentY not on item border")
4986 << 10+3 << 0+3 << 1 << ListRange(0+3, 9+3);
4987 QTest::newRow("move within view, move 1 up, move last item")
4989 << 17 << 10 << 1 << ListRange(10, 16);
4990 QTest::newRow("move within view, move 1 up, move last->first")
4992 << 17 << 0 << 1 << ListRange(0, 16);
4994 QTest::newRow("move within view, move multiple up")
4996 << 10 << 1 << 3 << ListRange(1, 9);
4997 QTest::newRow("move within view, move multiple (> 1 row) up")
4999 << 10 << 1 << 5 << ListRange(1, 9);
5000 QTest::newRow("move within view, move multiple up, move to first index")
5002 << 10 << 0 << 3 << ListRange(0, 9);
5003 QTest::newRow("move within view, move multiple up, move to first index, contentY not 0")
5005 << 10+3 << 0+3 << 3 << ListRange(0+3, 9+3);
5006 QTest::newRow("move within view, move multiple up (> 1 row), move to first index, contentY not on border")
5008 << 10+3 << 0+3 << 5 << ListRange(0+3, 9+3);
5009 QTest::newRow("move within view, move multiple up, move last item")
5011 << 15 << 5 << 3 << ListRange(5, 14);
5012 QTest::newRow("move within view, move multiple up, move last->first")
5014 << 15 << 0 << 3 << ListRange(0, 14);
5016 QTest::newRow("move from below view, move 1 up")
5018 << 20 << 5 << 1 << ListRange(5, 17);
5019 QTest::newRow("move from below view, move 1 up, move to top")
5021 << 20 << 0 << 1 << ListRange(0, 17);
5022 QTest::newRow("move from below view, move 1 up, move to top, contentY not 0")
5024 << 25 << 3 << 1 << ListRange(0+3, 17+3);
5025 QTest::newRow("move from below view, move multiple (> 1 row) up")
5027 << 20 << 5 << 5 << ListRange(5, 17);
5028 QTest::newRow("move from below view, move multiple up, move to top")
5030 << 20 << 0 << 3 << ListRange(0, 17);
5031 QTest::newRow("move from below view, move multiple up, move to top, contentY not 0")
5033 << 25 << 3 << 3 << ListRange(0+3, 17+3);
5035 QTest::newRow("move from below view, move 1 up, move to bottom")
5037 << 20 << 17 << 1 << ListRange(17, 17);
5038 QTest::newRow("move from below view, move 1 up, move to bottom, contentY not 0")
5040 << 25 << 17+3 << 1 << ListRange(17+3, 17+3);
5041 QTest::newRow("move from below view, move multiple up, move to to bottom")
5043 << 20 << 17 << 3 << ListRange(17, 17);
5044 QTest::newRow("move from below view, move multiple up, move to bottom, contentY not 0")
5046 << 25 << 17+3 << 3 << ListRange(17+3, 17+3);
5049 void tst_QQuickGridView::removeTransitions()
5051 QFETCH(int, initialItemCount);
5052 QFETCH(bool, shouldAnimateTargets);
5053 QFETCH(qreal, contentYRowOffset);
5054 QFETCH(int, removalIndex);
5055 QFETCH(int, removalCount);
5056 QFETCH(ListRange, expectedDisplacedIndexes);
5058 // added items should end here
5059 QPointF targetItems_transitionTo(-50, -50);
5061 // displaced items should pass through this points
5062 QPointF displacedItems_transitionVia(100, 100);
5065 for (int i = 0; i < initialItemCount; i++)
5066 model.addItem("Original item" + QString::number(i), "");
5067 QaimModel model_targetItems_transitionTo;
5068 QaimModel model_displacedItems_transitionVia;
5070 QQuickView *window = getView();
5071 QQmlContext *ctxt = window->rootContext();
5072 ctxt->setContextProperty("testModel", &model);
5073 ctxt->setContextProperty("model_targetItems_transitionTo", &model_targetItems_transitionTo);
5074 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
5075 ctxt->setContextProperty("targetItems_transitionTo", targetItems_transitionTo);
5076 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
5077 window->setSource(testFileUrl("removeTransitions.qml"));
5080 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
5081 QTRY_VERIFY(gridview != 0);
5082 QQuickItem *contentItem = gridview->contentItem();
5083 QVERIFY(contentItem != 0);
5084 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5086 if (contentYRowOffset != 0) {
5087 gridview->setContentY(contentYRowOffset * 60.0);
5088 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5091 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
5093 // only target items that are visible should be animated
5094 QList<QPair<QString, QString> > expectedTargetData;
5095 QList<int> targetIndexes;
5096 if (shouldAnimateTargets) {
5097 for (int i=removalIndex; i<removalIndex+removalCount; i++) {
5098 int firstVisibleIndex = (gridview->contentY() / 60.0)*3;
5099 int lastVisibleIndex = (qCeil((gridview->contentY() + gridview->height()) / 60.0)*3) - 1;
5100 if (i >= firstVisibleIndex && i <= lastVisibleIndex) {
5101 expectedTargetData << qMakePair(model.name(i), model.number(i));
5105 QVERIFY(expectedTargetData.count() > 0);
5108 // calculate targetItems and expectedTargets before model changes
5109 QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
5110 QVariantMap expectedTargets;
5111 for (int i=0; i<targetIndexes.count(); i++)
5112 expectedTargets[model.name(targetIndexes[i])] = targetIndexes[i];
5115 model.removeItems(removalIndex, removalCount);
5116 QTRY_COMPARE(model.count(), gridview->count());
5118 if (shouldAnimateTargets || expectedDisplacedIndexes.isValid()) {
5119 QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
5120 QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
5121 expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
5123 // check the target and displaced items were animated
5124 model_targetItems_transitionTo.matchAgainst(expectedTargetData, "wasn't animated to target 'to' pos", "shouldn't have been animated to target 'to' pos");
5125 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
5127 // check attached properties
5128 QCOMPARE(gridview->property("targetTrans_items").toMap(), expectedTargets);
5129 matchIndexLists(gridview->property("targetTrans_targetIndexes").toList(), targetIndexes);
5130 matchItemLists(gridview->property("targetTrans_targetItems").toList(), targetItems);
5131 if (expectedDisplacedIndexes.isValid()) {
5132 // adjust expectedDisplacedIndexes to their final values after the move
5133 QList<int> displacedIndexes = adjustIndexesForRemoveDisplaced(expectedDisplacedIndexes.indexes, removalIndex, removalCount);
5134 matchItemsAndIndexes(gridview->property("displacedTrans_items").toMap(), model, displacedIndexes);
5135 matchIndexLists(gridview->property("displacedTrans_targetIndexes").toList(), targetIndexes);
5136 matchItemLists(gridview->property("displacedTrans_targetItems").toList(), targetItems);
5139 QTRY_COMPARE(model_targetItems_transitionTo.count(), 0);
5140 QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0);
5143 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5144 int itemCount = items.count();
5145 int firstVisibleIndex = -1;
5146 for (int i=0; i<items.count(); i++) {
5147 QQmlExpression e(qmlContext(items[i]), items[i], "index");
5148 int index = e.evaluate().toInt();
5149 if (firstVisibleIndex < 0 && items[i]->y() >= gridview->contentY())
5150 firstVisibleIndex = index;
5152 itemCount--; // exclude deleted items
5154 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
5156 // verify all items moved to the correct final positions
5157 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
5158 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5159 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5160 QCOMPARE(item->x(), (i%3)*80.0);
5161 QCOMPARE(item->y(), gridview->contentY() + ((i-firstVisibleIndex)/3) * 60.0);
5162 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5164 QTRY_COMPARE(name->text(), model.name(i));
5167 releaseView(window);
5170 void tst_QQuickGridView::removeTransitions_data()
5172 QTest::addColumn<int>("initialItemCount");
5173 QTest::addColumn<qreal>("contentYRowOffset");
5174 QTest::addColumn<bool>("shouldAnimateTargets");
5175 QTest::addColumn<int>("removalIndex");
5176 QTest::addColumn<int>("removalCount");
5177 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
5179 // All items that are visible following the remove operation should be animated.
5180 // Remove targets that are outside of the view should not be animated.
5182 // For a GridView, removing any number of items other than a full row before the start
5183 // should displace all items in the view
5184 QTest::newRow("remove 1 before start")
5185 << 30 << 2.0 << false
5186 << 2 << 1 << ListRange(6, 24); // 6-24 are displaced
5187 QTest::newRow("remove 1 row, before start")
5188 << 30 << 2.0 << false
5189 << 3 << 3 << ListRange();
5190 QTest::newRow("remove between 1-2 rows, before start")
5191 << 30 << 2.0 << false
5192 << 0 << 5 << ListRange(6, 25);
5193 QTest::newRow("remove 2 rows, before start")
5194 << 30 << 2.0 << false
5195 << 0 << 6 << ListRange();
5196 QTest::newRow("remove mix of before and after start")
5197 << 30 << 1.0 << true
5198 << 2 << 3 << ListRange(5, 23); // 5-23 are displaced into view
5201 QTest::newRow("remove 1 from start")
5202 << 30 << 0.0 << true
5203 << 0 << 1 << ListRange(1, 18); // 1-18 are displaced into view
5204 QTest::newRow("remove multiple from start")
5205 << 30 << 0.0 << true
5206 << 0 << 3 << ListRange(3, 20); // 3-18 are displaced into view
5207 QTest::newRow("remove 1 from start, content y not 0")
5208 << 30 << 1.0 << true
5209 << 3 << 1 << ListRange(1 + 3, 18 + 3);
5210 QTest::newRow("remove multiple from start, content y not 0")
5211 << 30 << 1.0 << true
5212 << 3 << 3 << ListRange(3 + 3, 20 + 3);
5215 QTest::newRow("remove 1 from middle")
5216 << 30 << 0.0 << true
5217 << 5 << 1 << ListRange(6, 18);
5218 QTest::newRow("remove multiple from middle")
5219 << 30 << 0.0 << true
5220 << 5 << 3 << ListRange(8, 20);
5223 QTest::newRow("remove 1 from bottom")
5224 << 30 << 0.0 << true
5225 << 17 << 1 << ListRange(18, 18);
5226 QTest::newRow("remove multiple (1 row) from bottom")
5227 << 30 << 0.0 << true
5228 << 15 << 3 << ListRange(18, 20);
5229 QTest::newRow("remove multiple (> 1 row) from bottom")
5230 << 30 << 0.0 << true
5231 << 15 << 5 << ListRange(20, 22);
5232 QTest::newRow("remove 1 from bottom, content y not 0")
5233 << 30 << 1.0 << true
5234 << 17 + 3 << 1 << ListRange(18 + 3, 18 + 3);
5235 QTest::newRow("remove multiple (1 row) from bottom, content y not 0")
5236 << 30 << 1.0 << true
5237 << 15 + 3 << 3 << ListRange(18 + 3, 20 + 3);
5240 QTest::newRow("remove 1 after end")
5241 << 30 << 0.0 << false
5242 << 18 << 1 << ListRange();
5243 QTest::newRow("remove multiple after end")
5244 << 30 << 0.0 << false
5245 << 18 << 3 << ListRange();
5248 void tst_QQuickGridView::displacedTransitions()
5250 QFETCH(bool, useDisplaced);
5251 QFETCH(bool, displacedEnabled);
5252 QFETCH(bool, useAddDisplaced);
5253 QFETCH(bool, addDisplacedEnabled);
5254 QFETCH(bool, useMoveDisplaced);
5255 QFETCH(bool, moveDisplacedEnabled);
5256 QFETCH(bool, useRemoveDisplaced);
5257 QFETCH(bool, removeDisplacedEnabled);
5258 QFETCH(ListChange, change);
5259 QFETCH(ListRange, expectedDisplacedIndexes);
5262 for (int i = 0; i < 30; i++)
5263 model.addItem("Original item" + QString::number(i), "");
5264 QaimModel model_displaced_transitionVia;
5265 QaimModel model_addDisplaced_transitionVia;
5266 QaimModel model_moveDisplaced_transitionVia;
5267 QaimModel model_removeDisplaced_transitionVia;
5269 QPointF displaced_transitionVia(-50, -100);
5270 QPointF addDisplaced_transitionVia(-150, 100);
5271 QPointF moveDisplaced_transitionVia(50, -100);
5272 QPointF removeDisplaced_transitionVia(150, 100);
5274 QQuickView *window = getView();
5275 QQmlContext *ctxt = window->rootContext();
5276 ctxt->setContextProperty("testModel", &model);
5277 ctxt->setContextProperty("model_displaced_transitionVia", &model_displaced_transitionVia);
5278 ctxt->setContextProperty("model_addDisplaced_transitionVia", &model_addDisplaced_transitionVia);
5279 ctxt->setContextProperty("model_moveDisplaced_transitionVia", &model_moveDisplaced_transitionVia);
5280 ctxt->setContextProperty("model_removeDisplaced_transitionVia", &model_removeDisplaced_transitionVia);
5281 ctxt->setContextProperty("displaced_transitionVia", displaced_transitionVia);
5282 ctxt->setContextProperty("addDisplaced_transitionVia", addDisplaced_transitionVia);
5283 ctxt->setContextProperty("moveDisplaced_transitionVia", moveDisplaced_transitionVia);
5284 ctxt->setContextProperty("removeDisplaced_transitionVia", removeDisplaced_transitionVia);
5285 ctxt->setContextProperty("useDisplaced", useDisplaced);
5286 ctxt->setContextProperty("displacedEnabled", displacedEnabled);
5287 ctxt->setContextProperty("useAddDisplaced", useAddDisplaced);
5288 ctxt->setContextProperty("addDisplacedEnabled", addDisplacedEnabled);
5289 ctxt->setContextProperty("useMoveDisplaced", useMoveDisplaced);
5290 ctxt->setContextProperty("moveDisplacedEnabled", moveDisplacedEnabled);
5291 ctxt->setContextProperty("useRemoveDisplaced", useRemoveDisplaced);
5292 ctxt->setContextProperty("removeDisplacedEnabled", removeDisplacedEnabled);
5293 window->setSource(testFileUrl("displacedTransitions.qml"));
5295 qApp->processEvents();
5297 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
5298 QTRY_VERIFY(gridview != 0);
5299 QQuickItem *contentItem = gridview->contentItem();
5300 QVERIFY(contentItem != 0);
5301 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5303 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
5304 gridview->setProperty("displaceTransitionsDone", false);
5306 switch (change.type) {
5307 case ListChange::Inserted:
5309 QList<QPair<QString, QString> > targetItemData;
5310 for (int i=change.index; i<change.index + change.count; ++i)
5311 targetItemData << qMakePair(QString("new item %1").arg(i), QString::number(i));
5312 model.insertItems(change.index, targetItemData);
5313 QTRY_COMPARE(model.count(), gridview->count());
5316 case ListChange::Removed:
5317 model.removeItems(change.index, change.count);
5318 QTRY_COMPARE(model.count(), gridview->count());
5320 case ListChange::Moved:
5321 model.moveItems(change.index, change.to, change.count);
5322 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5324 case ListChange::SetCurrent:
5325 case ListChange::SetContentY:
5326 case ListChange::Polish:
5330 QVariantList resultTargetIndexes = gridview->property("displacedTargetIndexes").toList();
5331 QVariantList resultTargetItems = gridview->property("displacedTargetItems").toList();
5333 if ((useDisplaced && displacedEnabled)
5334 || (useAddDisplaced && addDisplacedEnabled)
5335 || (useMoveDisplaced && moveDisplacedEnabled)
5336 || (useRemoveDisplaced && removeDisplacedEnabled)) {
5337 QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
5339 // check the correct number of target items and indexes were received
5340 QCOMPARE(resultTargetIndexes.count(), expectedDisplacedIndexes.count());
5341 for (int i=0; i<resultTargetIndexes.count(); i++)
5342 QCOMPARE(resultTargetIndexes[i].value<QList<int> >().count(), change.count);
5343 QCOMPARE(resultTargetItems.count(), expectedDisplacedIndexes.count());
5344 for (int i=0; i<resultTargetItems.count(); i++)
5345 QCOMPARE(resultTargetItems[i].toList().count(), change.count);
5347 QCOMPARE(resultTargetIndexes.count(), 0);
5348 QCOMPARE(resultTargetItems.count(), 0);
5351 if (change.type == ListChange::Inserted && useAddDisplaced && addDisplacedEnabled)
5352 model_addDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with add displaced", "shouldn't have been animated with add displaced");
5354 QCOMPARE(model_addDisplaced_transitionVia.count(), 0);
5355 if (change.type == ListChange::Moved && useMoveDisplaced && moveDisplacedEnabled)
5356 model_moveDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with move displaced", "shouldn't have been animated with move displaced");
5358 QCOMPARE(model_moveDisplaced_transitionVia.count(), 0);
5359 if (change.type == ListChange::Removed && useRemoveDisplaced && removeDisplacedEnabled)
5360 model_removeDisplaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with remove displaced", "shouldn't have been animated with remove displaced");
5362 QCOMPARE(model_removeDisplaced_transitionVia.count(), 0);
5364 if (useDisplaced && displacedEnabled
5365 && ( (change.type == ListChange::Inserted && (!useAddDisplaced || !addDisplacedEnabled))
5366 || (change.type == ListChange::Moved && (!useMoveDisplaced || !moveDisplacedEnabled))
5367 || (change.type == ListChange::Removed && (!useRemoveDisplaced || !removeDisplacedEnabled))) ) {
5368 model_displaced_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with generic displaced", "shouldn't have been animated with generic displaced");
5370 QCOMPARE(model_displaced_transitionVia.count(), 0);
5373 // verify all items moved to the correct final positions
5374 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5375 for (int i=0; i < model.count() && i < items.count(); ++i) {
5376 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5377 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5378 QCOMPARE(item->x(), (i%3)*80.0);
5379 QCOMPARE(item->y(), (i/3)*60.0);
5380 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5382 QTRY_COMPARE(name->text(), model.name(i));
5385 releaseView(window);
5388 void tst_QQuickGridView::displacedTransitions_data()
5390 QTest::addColumn<bool>("useDisplaced");
5391 QTest::addColumn<bool>("displacedEnabled");
5392 QTest::addColumn<bool>("useAddDisplaced");
5393 QTest::addColumn<bool>("addDisplacedEnabled");
5394 QTest::addColumn<bool>("useMoveDisplaced");
5395 QTest::addColumn<bool>("moveDisplacedEnabled");
5396 QTest::addColumn<bool>("useRemoveDisplaced");
5397 QTest::addColumn<bool>("removeDisplacedEnabled");
5398 QTest::addColumn<ListChange>("change");
5399 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
5401 QTest::newRow("no displaced transitions at all")
5406 << ListChange::insert(0, 1) << ListRange(0, 17);
5408 QTest::newRow("just displaced")
5413 << ListChange::insert(0, 1) << ListRange(0, 17);
5415 QTest::newRow("just displaced (not enabled)")
5420 << ListChange::insert(0, 1) << ListRange(0, 17);
5422 QTest::newRow("displaced + addDisplaced")
5427 << ListChange::insert(0, 1) << ListRange(0, 17);
5429 QTest::newRow("displaced + addDisplaced (not enabled)")
5434 << ListChange::insert(0, 1) << ListRange(0, 17);
5436 QTest::newRow("displaced + moveDisplaced")
5441 << ListChange::move(0, 10, 1) << ListRange(1, 10);
5443 QTest::newRow("displaced + moveDisplaced (not enabled)")
5448 << ListChange::move(0, 10, 1) << ListRange(1, 10);
5450 QTest::newRow("displaced + removeDisplaced")
5455 << ListChange::remove(0, 1) << ListRange(1, 18);
5457 QTest::newRow("displaced + removeDisplaced (not enabled)")
5462 << ListChange::remove(0, 1) << ListRange(1, 18);
5465 QTest::newRow("displaced + add, should use generic displaced for a remove")
5470 << ListChange::remove(0, 1) << ListRange(1, 18);
5473 void tst_QQuickGridView::multipleTransitions()
5475 // Tests that if you interrupt a transition in progress with another action that
5476 // cancels the previous transition, the resulting items are still placed correctly.
5478 QFETCH(int, initialCount);
5479 QFETCH(qreal, contentY);
5480 QFETCH(QList<ListChange>, changes);
5481 QFETCH(bool, enableAddTransitions);
5482 QFETCH(bool, enableMoveTransitions);
5483 QFETCH(bool, enableRemoveTransitions);
5484 QFETCH(bool, rippleAddDisplaced);
5486 // add transitions on the left, moves on the right
5487 QPointF addTargets_transitionFrom(-50, -50);
5488 QPointF addDisplaced_transitionFrom(-50, 50);
5489 QPointF moveTargets_transitionFrom(50, -50);
5490 QPointF moveDisplaced_transitionFrom(50, 50);
5491 QPointF removeTargets_transitionTo(-100, 300);
5492 QPointF removeDisplaced_transitionFrom(100, 300);
5495 for (int i = 0; i < initialCount; i++)
5496 model.addItem("Original item" + QString::number(i), "");
5498 QQuickView *window = getView();
5499 QQmlContext *ctxt = window->rootContext();
5500 ctxt->setContextProperty("testModel", &model);
5501 ctxt->setContextProperty("addTargets_transitionFrom", addTargets_transitionFrom);
5502 ctxt->setContextProperty("addDisplaced_transitionFrom", addDisplaced_transitionFrom);
5503 ctxt->setContextProperty("moveTargets_transitionFrom", moveTargets_transitionFrom);
5504 ctxt->setContextProperty("moveDisplaced_transitionFrom", moveDisplaced_transitionFrom);
5505 ctxt->setContextProperty("removeTargets_transitionTo", removeTargets_transitionTo);
5506 ctxt->setContextProperty("removeDisplaced_transitionFrom", removeDisplaced_transitionFrom);
5507 ctxt->setContextProperty("enableAddTransitions", enableAddTransitions);
5508 ctxt->setContextProperty("enableMoveTransitions", enableMoveTransitions);
5509 ctxt->setContextProperty("enableRemoveTransitions", enableRemoveTransitions);
5510 ctxt->setContextProperty("rippleAddDisplaced", rippleAddDisplaced);
5511 window->setSource(testFileUrl("multipleTransitions.qml"));
5513 QVERIFY(QTest::qWaitForWindowExposed(window));
5515 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
5516 QTRY_VERIFY(gridview != 0);
5517 QQuickItem *contentItem = gridview->contentItem();
5518 QVERIFY(contentItem != 0);
5519 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5521 if (contentY != 0) {
5522 gridview->setContentY(contentY);
5523 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5526 int timeBetweenActions = window->rootObject()->property("timeBetweenActions").toInt();
5528 for (int i=0; i<changes.count(); i++) {
5529 switch (changes[i].type) {
5530 case ListChange::Inserted:
5532 QList<QPair<QString, QString> > targetItems;
5533 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
5534 targetItems << qMakePair(QString("new item %1").arg(j), QString::number(j));
5535 model.insertItems(changes[i].index, targetItems);
5536 QTRY_COMPARE(model.count(), gridview->count());
5537 if (i == changes.count() - 1) {
5538 QTRY_VERIFY(!gridview->property("runningAddTargets").toBool());
5539 QTRY_VERIFY(!gridview->property("runningAddDisplaced").toBool());
5541 QTest::qWait(timeBetweenActions);
5545 case ListChange::Removed:
5546 model.removeItems(changes[i].index, changes[i].count);
5547 QTRY_COMPARE(model.count(), gridview->count());
5548 if (i == changes.count() - 1) {
5549 QTRY_VERIFY(!gridview->property("runningRemoveTargets").toBool());
5550 QTRY_VERIFY(!gridview->property("runningRemoveDisplaced").toBool());
5552 QTest::qWait(timeBetweenActions);
5555 case ListChange::Moved:
5556 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
5557 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5558 if (i == changes.count() - 1) {
5559 QTRY_VERIFY(!gridview->property("runningMoveTargets").toBool());
5560 QTRY_VERIFY(!gridview->property("runningMoveDisplaced").toBool());
5562 QTest::qWait(timeBetweenActions);
5565 case ListChange::SetCurrent:
5566 gridview->setCurrentIndex(changes[i].index);
5567 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5569 case ListChange::SetContentY:
5570 gridview->setContentY(changes[i].pos);
5571 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5573 case ListChange::Polish:
5577 QCOMPARE(gridview->count(), model.count());
5579 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5580 int firstVisibleIndex = -1;
5581 for (int i=0; i<items.count(); i++) {
5582 if (items[i]->y() >= contentY) {
5583 QQmlExpression e(qmlContext(items[i]), items[i], "index");
5584 firstVisibleIndex = e.evaluate().toInt();
5588 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
5590 // verify all items moved to the correct final positions
5591 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
5592 for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
5593 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5594 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5595 QTRY_COMPARE(item->x(), (i%3)*80.0);
5596 QTRY_COMPARE(item->y(), (i/3)*60.0);
5597 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5599 QTRY_COMPARE(name->text(), model.name(i));
5602 releaseView(window);
5605 void tst_QQuickGridView::multipleTransitions_data()
5607 QTest::addColumn<int>("initialCount");
5608 QTest::addColumn<qreal>("contentY");
5609 QTest::addColumn<QList<ListChange> >("changes");
5610 QTest::addColumn<bool>("enableAddTransitions");
5611 QTest::addColumn<bool>("enableMoveTransitions");
5612 QTest::addColumn<bool>("enableRemoveTransitions");
5613 QTest::addColumn<bool>("rippleAddDisplaced");
5615 // the added item and displaced items should move to final dest correctly
5616 QTest::newRow("add item, then move it immediately") << 10 << 0.0 << (QList<ListChange>()
5617 << ListChange::insert(0, 1)
5618 << ListChange::move(0, 3, 1)
5620 << true << true << true << false;
5622 // items affected by the add should change from move to add transition
5623 QTest::newRow("move, then insert item before the moved item") << 20 << 0.0 << (QList<ListChange>()
5624 << ListChange::move(1, 10, 3)
5625 << ListChange::insert(0, 1)
5627 << true << true << true << false;
5629 // items should be placed correctly if you trigger a transition then refill for that index
5630 QTest::newRow("add at 0, flick down, flick back to top and add at 0 again") << 20 << 0.0 << (QList<ListChange>()
5631 << ListChange::insert(0, 1)
5632 << ListChange::setContentY(160.0)
5633 << ListChange::setContentY(0.0)
5634 << ListChange::insert(0, 1)
5636 << true << true << true << false;
5638 QTest::newRow("insert then remove same index, with ripple effect on add displaced") << 20 << 0.0 << (QList<ListChange>()
5639 << ListChange::insert(1, 1)
5640 << ListChange::remove(1, 1)
5642 << true << true << true << true;
5644 // if item is removed while undergoing a displaced transition, all other items should end up at their correct positions,
5645 // even if a remove-displace transition is not present to re-animate them
5646 QTest::newRow("insert then remove, with remove disabled") << 20 << 0.0 << (QList<ListChange>()
5647 << ListChange::insert(0, 1)
5648 << ListChange::remove(2, 1)
5650 << true << true << false << false;
5652 // if last item is not flush with the edge of the view, it should still be refilled in correctly after a
5653 // remove has changed the position of where it will move to
5654 QTest::newRow("insert twice then remove, with remove disabled") << 20 << 0.0 << (QList<ListChange>()
5655 << ListChange::setContentY(-10.0)
5656 << ListChange::insert(0, 1)
5657 << ListChange::insert(0, 1)
5658 << ListChange::remove(2, 1)
5660 << true << true << false << false;
5663 void tst_QQuickGridView::multipleDisplaced()
5665 // multiple move() operations should only restart displace transitions for items that
5666 // moved from previously set positions, and not those that have moved from their current
5667 // item positions (which may e.g. still be changing from easing bounces in the last transition)
5670 for (int i = 0; i < 30; i++)
5671 model.addItem("Original item" + QString::number(i), "");
5673 QQuickView *window = createView();
5674 QQmlContext *ctxt = window->rootContext();
5675 ctxt->setContextProperty("testModel", &model);
5676 window->setSource(testFileUrl("multipleDisplaced.qml"));
5678 QVERIFY(QTest::qWaitForWindowExposed(window));
5680 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
5681 QTRY_VERIFY(gridview != 0);
5682 QQuickItem *contentItem = gridview->contentItem();
5683 QVERIFY(contentItem != 0);
5684 QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
5686 model.moveItems(12, 8, 1);
5687 QTest::qWait(window->rootObject()->property("duration").toInt() / 2);
5688 model.moveItems(8, 3, 1);
5689 QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
5691 QVariantMap transitionsStarted = gridview->property("displaceTransitionsStarted").toMap();
5692 foreach (const QString &name, transitionsStarted.keys()) {
5693 QVERIFY2(transitionsStarted[name] == 1,
5694 QTest::toString(QString("%1 was displaced %2 times").arg(name).arg(transitionsStarted[name].toInt())));
5697 // verify all items moved to the correct final positions
5698 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
5699 for (int i=0; i < model.count() && i < items.count(); ++i) {
5700 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5701 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
5702 QTRY_COMPARE(item->x(), (i%3)*80.0);
5703 QTRY_COMPARE(item->y(), (i/3)*60.0);
5704 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
5706 QTRY_COMPARE(name->text(), model.name(i));
5712 void tst_QQuickGridView::cacheBuffer()
5714 QQuickView *window = createView();
5717 for (int i = 0; i < 90; i++)
5718 model.addItem("Item" + QString::number(i), "");
5720 window->rootContext()->setContextProperty("testModel", &model);
5721 window->setSource(testFileUrl("gridview1.qml"));
5723 qApp->processEvents();
5725 QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
5726 QVERIFY(gridview != 0);
5728 QQuickItem *contentItem = gridview->contentItem();
5729 QVERIFY(contentItem != 0);
5730 QVERIFY(gridview->delegate() != 0);
5731 QVERIFY(gridview->model() != 0);
5733 // Confirm items positioned correctly
5734 int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
5735 for (int i = 0; i < model.count() && i < itemCount; ++i) {
5736 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5737 QTRY_COMPARE(item->x(), (i%3)*80.0);
5738 QTRY_COMPARE(item->y(), (i/3)*60.0);
5741 QQmlIncubationController controller;
5742 window->engine()->setIncubationController(&controller);
5744 window->rootObject()->setProperty("cacheBuffer", 200);
5745 QTRY_VERIFY(gridview->cacheBuffer() == 200);
5747 // items will be created one at a time
5748 for (int i = itemCount; i < qMin(itemCount+9,model.count()); ++i) {
5749 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
5750 QQuickItem *item = 0;
5753 controller.incubateWhile(&b);
5754 item = findItem<QQuickItem>(gridview, "wrapper", i);
5760 controller.incubateWhile(&b);
5763 int newItemCount = 0;
5764 newItemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
5766 // Confirm items positioned correctly
5767 for (int i = 0; i < model.count() && i < newItemCount; ++i) {
5768 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5770 QTRY_COMPARE(item->x(), (i%3)*80.0);
5771 QTRY_COMPARE(item->y(), (i/3)*60.0);
5774 // move view and confirm items in view are visible immediately and outside are created async
5775 gridview->setContentY(300);
5777 for (int i = 15; i < 34; ++i) { // 34 due to staggered item creation
5778 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5780 QTRY_COMPARE(item->x(), (i%3)*80.0);
5781 QTRY_COMPARE(item->y(), (i/3)*60.0);
5784 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == 0);
5786 // ensure buffered items are created
5787 for (int i = 34; i < qMin(44,model.count()); ++i) {
5788 QQuickItem *item = 0;
5790 qGuiApp->processEvents(); // allow refill to happen
5792 controller.incubateWhile(&b);
5793 item = findItem<QQuickItem>(gridview, "wrapper", i);
5799 controller.incubateWhile(&b);
5805 void tst_QQuickGridView::asynchronous()
5807 QQuickView *window = createView();
5809 QQmlIncubationController controller;
5810 window->engine()->setIncubationController(&controller);
5812 window->setSource(testFileUrl("asyncloader.qml"));
5814 QQuickItem *rootObject = qobject_cast<QQuickItem*>(window->rootObject());
5815 QVERIFY(rootObject);
5817 QQuickGridView *gridview = 0;
5820 controller.incubateWhile(&b);
5821 gridview = rootObject->findChild<QQuickGridView*>("view");
5824 // items will be created one at a time
5825 for (int i = 0; i < 12; ++i) {
5826 QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
5827 QQuickItem *item = 0;
5830 controller.incubateWhile(&b);
5831 item = findItem<QQuickItem>(gridview, "wrapper", i);
5837 controller.incubateWhile(&b);
5840 // verify positioning
5841 QQuickItem *contentItem = gridview->contentItem();
5842 for (int i = 0; i < 12; ++i) {
5843 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
5844 if (!item) qWarning() << "Item" << i << "not found";
5845 QVERIFY(item->x() == (i%3)*100);
5846 QVERIFY(item->y() == (i/3)*100);
5852 void tst_QQuickGridView::unrequestedVisibility()
5855 for (int i = 0; i < 30; i++)
5856 model.addItem("Item" + QString::number(i), QString::number(i));
5858 QQuickView *window = new QQuickView(0);
5859 window->setGeometry(0,0,240,320);
5861 QQmlContext *ctxt = window->rootContext();
5862 ctxt->setContextProperty("testModel", &model);
5863 ctxt->setContextProperty("testWrap", QVariant(false));
5865 window->setSource(testFileUrl("unrequestedItems.qml"));
5869 qApp->processEvents();
5871 QQuickGridView *leftview = findItem<QQuickGridView>(window->rootObject(), "leftGrid");
5872 QTRY_VERIFY(leftview != 0);
5874 QQuickGridView *rightview = findItem<QQuickGridView>(window->rootObject(), "rightGrid");
5875 QTRY_VERIFY(rightview != 0);
5877 QQuickItem *leftContent = leftview->contentItem();
5878 QTRY_VERIFY(leftContent != 0);
5880 QQuickItem *rightContent = rightview->contentItem();
5881 QTRY_VERIFY(rightContent != 0);
5883 rightview->setCurrentIndex(12);
5885 QTRY_COMPARE(leftview->contentY(), 0.0);
5886 QTRY_COMPARE(rightview->contentY(), 240.0);
5890 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5891 QCOMPARE(delegateVisible(item), true);
5892 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5893 QCOMPARE(delegateVisible(item), false);
5895 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5896 QCOMPARE(delegateVisible(item), false);
5897 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5898 QCOMPARE(delegateVisible(item), true);
5900 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 9));
5901 QCOMPARE(delegateVisible(item), true);
5902 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 10));
5903 QCOMPARE(delegateVisible(item), false);
5904 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 3));
5905 QCOMPARE(delegateVisible(item), false);
5906 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 4));
5907 QCOMPARE(delegateVisible(item), true);
5909 rightview->setCurrentIndex(0);
5911 QTRY_COMPARE(leftview->contentY(), 0.0);
5912 QTRY_COMPARE(rightview->contentY(), 0.0);
5914 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5915 QCOMPARE(delegateVisible(item), true);
5916 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5917 QTRY_COMPARE(delegateVisible(item), true);
5919 QVERIFY(!findItem<QQuickItem>(leftContent, "wrapper", 11));
5920 QVERIFY(!findItem<QQuickItem>(rightContent, "wrapper", 11));
5922 leftview->setCurrentIndex(12);
5924 QTRY_COMPARE(leftview->contentY(), 240.0);
5925 QTRY_COMPARE(rightview->contentY(), 0.0);
5927 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5928 QTRY_COMPARE(delegateVisible(item), false);
5929 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5930 QCOMPARE(delegateVisible(item), true);
5932 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5933 QCOMPARE(delegateVisible(item), true);
5934 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5935 QCOMPARE(delegateVisible(item), false);
5937 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5938 QCOMPARE(delegateVisible(item), false);
5939 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5940 QCOMPARE(delegateVisible(item), true);
5941 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5942 QCOMPARE(delegateVisible(item), true);
5943 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5944 QCOMPARE(delegateVisible(item), false);
5946 // move a non-visible item into view
5947 model.moveItems(10, 9, 1);
5948 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5950 QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
5951 QCOMPARE(delegateVisible(item), false);
5952 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
5953 QCOMPARE(delegateVisible(item), true);
5955 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
5956 QCOMPARE(delegateVisible(item), true);
5957 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
5958 QCOMPARE(delegateVisible(item), false);
5960 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5961 QCOMPARE(delegateVisible(item), false);
5962 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5963 QCOMPARE(delegateVisible(item), true);
5964 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5965 QCOMPARE(delegateVisible(item), true);
5966 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5967 QCOMPARE(delegateVisible(item), false);
5969 // move a visible item out of view
5970 model.moveItems(5, 3, 1);
5971 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5973 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5974 QCOMPARE(delegateVisible(item), false);
5975 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5976 QCOMPARE(delegateVisible(item), true);
5977 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5978 QCOMPARE(delegateVisible(item), true);
5979 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5980 QCOMPARE(delegateVisible(item), false);
5982 // move a non-visible item into view
5983 model.moveItems(3, 5, 1);
5984 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5986 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
5987 QCOMPARE(delegateVisible(item), false);
5988 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
5989 QCOMPARE(delegateVisible(item), true);
5990 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
5991 QCOMPARE(delegateVisible(item), true);
5992 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
5993 QCOMPARE(delegateVisible(item), false);
5995 // move a visible item out of view
5996 model.moveItems(9, 10, 1);
5997 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
5999 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
6000 QCOMPARE(delegateVisible(item), false);
6001 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
6002 QCOMPARE(delegateVisible(item), true);
6003 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
6004 QCOMPARE(delegateVisible(item), true);
6005 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
6006 QCOMPARE(delegateVisible(item), false);
6008 // move a non-visible item into view
6009 model.moveItems(10, 9, 1);
6010 QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false);
6012 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
6013 QCOMPARE(delegateVisible(item), false);
6014 QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
6015 QCOMPARE(delegateVisible(item), true);
6016 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
6017 QCOMPARE(delegateVisible(item), true);
6018 QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
6019 QCOMPARE(delegateVisible(item), false);
6025 void tst_QQuickGridView::inserted_leftToRight_RtL_TtB()
6027 inserted_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft);
6030 void tst_QQuickGridView::inserted_leftToRight_RtL_TtB_data()
6032 inserted_defaultLayout_data();
6035 void tst_QQuickGridView::inserted_topToBottom_LtR_TtB()
6037 inserted_defaultLayout(QQuickGridView::FlowTopToBottom);
6040 void tst_QQuickGridView::inserted_topToBottom_LtR_TtB_data()
6042 inserted_defaultLayout_data();
6045 void tst_QQuickGridView::inserted_topToBottom_RtL_TtB()
6047 inserted_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft);
6050 void tst_QQuickGridView::inserted_topToBottom_RtL_TtB_data()
6052 inserted_defaultLayout_data();
6055 void tst_QQuickGridView::inserted_leftToRight_LtR_BtT()
6057 inserted_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::LeftToRight, QQuickItemView::BottomToTop);
6060 void tst_QQuickGridView::inserted_leftToRight_LtR_BtT_data()
6062 inserted_defaultLayout_data();
6065 void tst_QQuickGridView::inserted_leftToRight_RtL_BtT()
6067 inserted_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft, QQuickItemView::BottomToTop);
6070 void tst_QQuickGridView::inserted_leftToRight_RtL_BtT_data()
6072 inserted_defaultLayout_data();
6075 void tst_QQuickGridView::inserted_topToBottom_LtR_BtT()
6077 inserted_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::LeftToRight, QQuickItemView::BottomToTop);
6080 void tst_QQuickGridView::inserted_topToBottom_LtR_BtT_data()
6082 inserted_defaultLayout_data();
6085 void tst_QQuickGridView::inserted_topToBottom_RtL_BtT()
6087 inserted_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft, QQuickItemView::BottomToTop);
6090 void tst_QQuickGridView::inserted_topToBottom_RtL_BtT_data()
6092 inserted_defaultLayout_data();
6096 void tst_QQuickGridView::removed_leftToRight_RtL_TtB()
6098 removed_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft);
6101 void tst_QQuickGridView::removed_leftToRight_RtL_TtB_data()
6103 removed_defaultLayout_data();
6106 void tst_QQuickGridView::removed_topToBottom_LtR_TtB()
6108 removed_defaultLayout(QQuickGridView::FlowTopToBottom);
6111 void tst_QQuickGridView::removed_topToBottom_LtR_TtB_data()
6113 removed_defaultLayout_data();
6116 void tst_QQuickGridView::removed_topToBottom_RtL_TtB()
6118 removed_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft);
6121 void tst_QQuickGridView::removed_topToBottom_RtL_TtB_data()
6123 removed_defaultLayout_data();
6126 void tst_QQuickGridView::removed_leftToRight_LtR_BtT()
6128 removed_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::LeftToRight, QQuickItemView::BottomToTop);
6131 void tst_QQuickGridView::removed_leftToRight_LtR_BtT_data()
6133 removed_defaultLayout_data();
6136 void tst_QQuickGridView::removed_leftToRight_RtL_BtT()
6138 removed_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft, QQuickItemView::BottomToTop);
6141 void tst_QQuickGridView::removed_leftToRight_RtL_BtT_data()
6143 removed_defaultLayout_data();
6146 void tst_QQuickGridView::removed_topToBottom_LtR_BtT()
6148 removed_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::LeftToRight, QQuickItemView::BottomToTop);
6151 void tst_QQuickGridView::removed_topToBottom_LtR_BtT_data()
6153 removed_defaultLayout_data();
6156 void tst_QQuickGridView::removed_topToBottom_RtL_BtT()
6158 removed_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft, QQuickItemView::BottomToTop);
6161 void tst_QQuickGridView::removed_topToBottom_RtL_BtT_data()
6163 removed_defaultLayout_data();
6167 void tst_QQuickGridView::moved_leftToRight_RtL_TtB()
6169 moved_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft);
6172 void tst_QQuickGridView::moved_leftToRight_RtL_TtB_data()
6174 moved_defaultLayout_data();
6177 void tst_QQuickGridView::moved_topToBottom_LtR_TtB()
6179 moved_defaultLayout(QQuickGridView::FlowTopToBottom);
6182 void tst_QQuickGridView::moved_topToBottom_LtR_TtB_data()
6184 moved_defaultLayout_data();
6187 void tst_QQuickGridView::moved_topToBottom_RtL_TtB()
6189 moved_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft);
6192 void tst_QQuickGridView::moved_topToBottom_RtL_TtB_data()
6194 moved_defaultLayout_data();
6197 void tst_QQuickGridView::moved_leftToRight_LtR_BtT()
6199 moved_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::LeftToRight, QQuickItemView::BottomToTop);
6202 void tst_QQuickGridView::moved_leftToRight_LtR_BtT_data()
6204 moved_defaultLayout_data();
6207 void tst_QQuickGridView::moved_leftToRight_RtL_BtT()
6209 moved_defaultLayout(QQuickGridView::FlowLeftToRight, Qt::RightToLeft, QQuickItemView::BottomToTop);
6212 void tst_QQuickGridView::moved_leftToRight_RtL_BtT_data()
6214 moved_defaultLayout_data();
6217 void tst_QQuickGridView::moved_topToBottom_LtR_BtT()
6219 moved_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::LeftToRight, QQuickItemView::BottomToTop);
6222 void tst_QQuickGridView::moved_topToBottom_LtR_BtT_data()
6224 moved_defaultLayout_data();
6227 void tst_QQuickGridView::moved_topToBottom_RtL_BtT()
6229 moved_defaultLayout(QQuickGridView::FlowTopToBottom, Qt::RightToLeft, QQuickItemView::BottomToTop);
6232 void tst_QQuickGridView::moved_topToBottom_RtL_BtT_data()
6234 moved_defaultLayout_data();
6238 QList<int> tst_QQuickGridView::toIntList(const QVariantList &list)
6242 for (int i=0; i<list.count(); i++) {
6243 ret << list[i].toInt(&ok);
6245 qWarning() << "tst_QQuickGridView::toIntList(): not a number:" << list[i];
6251 void tst_QQuickGridView::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
6253 for (int i=0; i<indexLists.count(); i++) {
6254 QSet<int> current = indexLists[i].value<QList<int> >().toSet();
6255 if (current != expectedIndexes.toSet())
6256 qDebug() << "Cannot match actual targets" << current << "with expected" << expectedIndexes;
6257 QCOMPARE(current, expectedIndexes.toSet());
6261 void tst_QQuickGridView::matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes)
6263 for (QVariantMap::const_iterator it = items.begin(); it != items.end(); ++it) {
6264 QVERIFY(it.value().type() == QVariant::Int);
6265 QString name = it.key();
6266 int itemIndex = it.value().toInt();
6267 QVERIFY2(expectedIndexes.contains(itemIndex), QTest::toString(QString("Index %1 not found in expectedIndexes").arg(itemIndex)));
6268 if (model.name(itemIndex) != name)
6269 qDebug() << itemIndex;
6270 QCOMPARE(model.name(itemIndex), name);
6272 QCOMPARE(items.count(), expectedIndexes.count());
6275 void tst_QQuickGridView::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
6277 for (int i=0; i<itemLists.count(); i++) {
6278 QVariantList current = itemLists[i].toList();
6279 for (int j=0; j<current.count(); j++) {
6280 QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
6281 QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1").arg(j)));
6282 QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1").arg(j)));
6284 QCOMPARE(current.count(), expectedItems.count());
6288 QTEST_MAIN(tst_QQuickGridView)
6290 #include "tst_qquickgridview.moc"