1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtWidgets/qstringlistmodel.h>
44 #include <QtDeclarative/qsgview.h>
45 #include <QtDeclarative/qdeclarativeengine.h>
46 #include <QtDeclarative/qdeclarativecomponent.h>
47 #include <QtDeclarative/qdeclarativecontext.h>
48 #include <QtDeclarative/qdeclarativeexpression.h>
49 #include <QtDeclarative/private/qsgitem_p.h>
50 #include <QtDeclarative/private/qlistmodelinterface_p.h>
51 #include <QtDeclarative/private/qsggridview_p.h>
52 #include <QtDeclarative/private/qsgtext_p.h>
53 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
54 #include "../shared/util.h"
55 #include <QtGui/qguiapplication.h>
57 Q_DECLARE_METATYPE(Qt::LayoutDirection)
58 Q_DECLARE_METATYPE(QSGGridView::Flow)
60 class tst_QSGGridView : public QObject
68 void cleanupTestCase();
73 void inserted_more_data();
78 void multipleChanges();
79 void multipleChanges_data();
80 void swapWithFirstItem();
83 void noCurrentIndex();
86 void propertyChanges();
87 void componentChanges();
89 void positionViewAtIndex();
90 void positionViewAtIndex_rightToLeft();
95 void enforceRange_rightToLeft();
97 void manualHighlight();
102 void resizeViewAndRepaint();
107 void onRemove_data();
108 void testQtQuick11Attributes();
109 void testQtQuick11Attributes_data();
112 void creationContext();
113 void snapToRow_data();
117 QSGView *createView();
118 void flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration);
120 T *findItem(QSGItem *parent, const QString &id, int index=-1);
122 QList<T*> findItems(QSGItem *parent, const QString &objectName);
123 void dumpTree(QSGItem *parent, int depth = 0);
127 void tst_qsggridview_move(int from, int to, int n, T *items)
130 items->move(from, to);
134 typename T::ConstIterator it=items->begin(); it += from+n;
135 for (; i<to-from; ++i,++it)
136 replaced.append(*it);
138 it=items->begin(); it += from;
139 for (; i<n; ++i,++it)
140 replaced.append(*it);
141 typename T::ConstIterator f=replaced.begin();
142 typename T::Iterator t=items->begin(); t += from;
143 for (; f != replaced.end(); ++f, ++t)
148 void tst_QSGGridView::initTestCase()
152 void tst_QSGGridView::cleanupTestCase()
158 class TestModel : public QAbstractListModel
161 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
163 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
164 QHash<int, QByteArray> roles;
165 roles[Name] = "name";
166 roles[Number] = "number";
170 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
171 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
174 rv = list.at(index.row()).first;
175 else if (role == Number)
176 rv = list.at(index.row()).second;
181 int count() const { return rowCount(); }
182 QString name(int index) const { return list.at(index).first; }
183 QString number(int index) const { return list.at(index).second; }
185 void addItem(const QString &name, const QString &number) {
186 emit beginInsertRows(QModelIndex(), list.count(), list.count());
187 list.append(QPair<QString,QString>(name, number));
188 emit endInsertRows();
191 void addItems(const QList<QPair<QString, QString> > &items) {
192 emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
193 for (int i=0; i<items.count(); i++)
194 list.append(QPair<QString,QString>(items[i].first, items[i].second));
195 emit endInsertRows();
198 void insertItem(int index, const QString &name, const QString &number) {
199 emit beginInsertRows(QModelIndex(), index, index);
200 list.insert(index, QPair<QString,QString>(name, number));
201 emit endInsertRows();
204 void insertItems(int index, const QList<QPair<QString, QString> > &items) {
205 emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
206 for (int i=0; i<items.count(); i++)
207 list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
208 emit endInsertRows();
211 void removeItem(int index) {
212 emit beginRemoveRows(QModelIndex(), index, index);
213 list.removeAt(index);
214 emit endRemoveRows();
217 void removeItems(int index, int count) {
218 emit beginRemoveRows(QModelIndex(), index, index+count-1);
220 list.removeAt(index);
221 emit endRemoveRows();
224 void moveItem(int from, int to) {
225 emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
230 void moveItems(int from, int to, int count) {
231 emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
232 tst_qsggridview_move(from, to, count, &list);
236 void modifyItem(int idx, const QString &name, const QString &number) {
237 list[idx] = QPair<QString,QString>(name, number);
238 emit dataChanged(index(idx,0), index(idx,0));
242 int count = list.count();
243 emit beginRemoveRows(QModelIndex(), 0, count-1);
245 emit endRemoveRows();
250 QList<QPair<QString,QString> > list;
253 tst_QSGGridView::tst_QSGGridView()
257 void tst_QSGGridView::items()
259 QSGView *canvas = createView();
262 model.addItem("Fred", "12345");
263 model.addItem("John", "2345");
264 model.addItem("Bob", "54321");
265 model.addItem("Billy", "22345");
266 model.addItem("Sam", "2945");
267 model.addItem("Ben", "04321");
268 model.addItem("Jim", "0780");
270 QDeclarativeContext *ctxt = canvas->rootContext();
271 ctxt->setContextProperty("testModel", &model);
272 ctxt->setContextProperty("testRightToLeft", QVariant(false));
273 ctxt->setContextProperty("testTopToBottom", QVariant(false));
275 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
276 qApp->processEvents();
278 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
279 QTRY_VERIFY(gridview != 0);
281 QSGItem *contentItem = gridview->contentItem();
282 QTRY_VERIFY(contentItem != 0);
284 QTRY_COMPARE(gridview->count(), model.count());
285 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
286 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
288 for (int i = 0; i < model.count(); ++i) {
289 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
290 QTRY_VERIFY(name != 0);
291 QTRY_COMPARE(name->text(), model.name(i));
292 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
293 QTRY_VERIFY(number != 0);
294 QTRY_COMPARE(number->text(), model.number(i));
297 // set an empty model and confirm that items are destroyed
299 ctxt->setContextProperty("testModel", &model2);
301 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
302 QTRY_VERIFY(itemCount == 0);
307 void tst_QSGGridView::changed()
309 QSGView *canvas = createView();
312 model.addItem("Fred", "12345");
313 model.addItem("John", "2345");
314 model.addItem("Bob", "54321");
315 model.addItem("Billy", "22345");
316 model.addItem("Sam", "2945");
317 model.addItem("Ben", "04321");
318 model.addItem("Jim", "0780");
320 QDeclarativeContext *ctxt = canvas->rootContext();
321 ctxt->setContextProperty("testModel", &model);
322 ctxt->setContextProperty("testRightToLeft", QVariant(false));
323 ctxt->setContextProperty("testTopToBottom", QVariant(false));
325 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
326 qApp->processEvents();
328 QSGFlickable *gridview = findItem<QSGFlickable>(canvas->rootObject(), "grid");
329 QTRY_VERIFY(gridview != 0);
331 QSGItem *contentItem = gridview->contentItem();
332 QTRY_VERIFY(contentItem != 0);
334 model.modifyItem(1, "Will", "9876");
335 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
336 QTRY_VERIFY(name != 0);
337 QTRY_COMPARE(name->text(), model.name(1));
338 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
339 QTRY_VERIFY(number != 0);
340 QTRY_COMPARE(number->text(), model.number(1));
345 void tst_QSGGridView::inserted()
347 QSGView *canvas = createView();
351 model.addItem("Fred", "12345");
352 model.addItem("John", "2345");
353 model.addItem("Bob", "54321");
355 QDeclarativeContext *ctxt = canvas->rootContext();
356 ctxt->setContextProperty("testModel", &model);
357 ctxt->setContextProperty("testRightToLeft", QVariant(false));
358 ctxt->setContextProperty("testTopToBottom", QVariant(false));
360 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
361 qApp->processEvents();
363 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
364 QTRY_VERIFY(gridview != 0);
366 QSGItem *contentItem = gridview->contentItem();
367 QTRY_VERIFY(contentItem != 0);
369 model.insertItem(1, "Will", "9876");
371 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
372 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
374 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
375 QTRY_VERIFY(name != 0);
376 QTRY_COMPARE(name->text(), model.name(1));
377 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
378 QTRY_VERIFY(number != 0);
379 QTRY_COMPARE(number->text(), model.number(1));
381 // Checks that onAdd is called
382 int added = canvas->rootObject()->property("added").toInt();
383 QTRY_COMPARE(added, 1);
385 // Confirm items positioned correctly
386 for (int i = 0; i < model.count(); ++i) {
387 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
388 QTRY_COMPARE(item->x(), (i%3)*80.0);
389 QTRY_COMPARE(item->y(), (i/3)*60.0);
392 model.insertItem(0, "Foo", "1111"); // zero index, and current item
394 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
396 name = findItem<QSGText>(contentItem, "textName", 0);
397 QTRY_VERIFY(name != 0);
398 QTRY_COMPARE(name->text(), model.name(0));
399 number = findItem<QSGText>(contentItem, "textNumber", 0);
400 QTRY_VERIFY(number != 0);
401 QTRY_COMPARE(number->text(), model.number(0));
403 QTRY_COMPARE(gridview->currentIndex(), 1);
405 // Confirm items positioned correctly
406 for (int i = 0; i < model.count(); ++i) {
407 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
408 QTRY_VERIFY(item->x() == (i%3)*80);
409 QTRY_VERIFY(item->y() == (i/3)*60);
412 for (int i = model.count(); i < 30; ++i)
413 model.insertItem(i, "Hello", QString::number(i));
415 gridview->setContentY(120);
417 // Insert item outside visible area
418 model.insertItem(1, "Hello", "1324");
420 QTRY_VERIFY(gridview->contentY() == 120);
425 void tst_QSGGridView::inserted_more()
427 QFETCH(qreal, contentY);
428 QFETCH(int, insertIndex);
429 QFETCH(int, insertCount);
430 QFETCH(qreal, itemsOffsetAfterMove);
434 QSGView *canvas = createView();
438 for (int i = 0; i < 30; i++)
439 model.addItem("Item" + QString::number(i), "");
441 QDeclarativeContext *ctxt = canvas->rootContext();
442 ctxt->setContextProperty("testModel", &model);
443 ctxt->setContextProperty("testRightToLeft", QVariant(false));
444 ctxt->setContextProperty("testTopToBottom", QVariant(false));
446 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
447 qApp->processEvents();
449 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
450 QTRY_VERIFY(gridview != 0);
451 QSGItem *contentItem = gridview->contentItem();
452 QTRY_VERIFY(contentItem != 0);
454 gridview->setContentY(contentY);
456 QList<QPair<QString, QString> > newData;
457 for (int i=0; i<insertCount; i++)
458 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
459 model.insertItems(insertIndex, newData);
460 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
462 // check visibleItems.first() is in correct position
463 QSGItem *item0 = findItem<QSGItem>(contentItem, "wrapper", 0);
465 QCOMPARE(item0->y(), itemsOffsetAfterMove);
467 QList<QSGItem*> items = findItems<QSGItem>(contentItem, "wrapper");
468 int firstVisibleIndex = -1;
469 for (int i=0; i<items.count(); i++) {
470 if (items[i]->y() >= contentY) {
471 QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
472 firstVisibleIndex = e.evaluate().toInt();
476 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
478 // Confirm items positioned correctly and indexes correct
479 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
480 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
481 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
482 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
484 QCOMPARE(item->x(), (i%3)*80.0);
485 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
487 name = findItem<QSGText>(contentItem, "textName", i);
489 QCOMPARE(name->text(), model.name(i));
490 number = findItem<QSGText>(contentItem, "textNumber", i);
491 QVERIFY(number != 0);
492 QCOMPARE(number->text(), model.number(i));
498 void tst_QSGGridView::inserted_more_data()
500 QTest::addColumn<qreal>("contentY");
501 QTest::addColumn<int>("insertIndex");
502 QTest::addColumn<int>("insertCount");
503 QTest::addColumn<qreal>("itemsOffsetAfterMove");
505 QTest::newRow("add 1, before visible items")
506 << 120.0 // show 6-23
508 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
509 // new 1st visible item is at 0
511 QTest::newRow("add 2, before visible items")
512 << 120.0 // show 6-23
514 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
516 QTest::newRow("add 3, before visible items")
517 << 120.0 // show 6-23
519 << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
521 QTest::newRow("add 5, before visible items")
522 << 120.0 // show 6-23
524 << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
525 // grid is rearranged and first visible moves forward within its row
527 QTest::newRow("add 6, before visible items")
528 << 120.0 // show 6-23
530 << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
534 QTest::newRow("add 1, at start of visible, content at start")
539 QTest::newRow("add multiple, at start of visible, content at start")
544 QTest::newRow("add 1, at start of visible, content not at start")
545 << 120.0 // show 6-23
549 QTest::newRow("add multiple, at start of visible, content not at start")
550 << 120.0 // show 6-23
555 QTest::newRow("add 1, at end of visible, content at start")
560 QTest::newRow("add 1, at end of visible, content at start")
565 QTest::newRow("add 1, at end of visible, content not at start")
566 << 120.0 // show 6-23
570 QTest::newRow("add multiple, at end of visible, content not at start")
571 << 120.0 // show 6-23
576 QTest::newRow("add 1, after visible, content at start")
581 QTest::newRow("add 1, after visible, content at start")
586 QTest::newRow("add 1, after visible, content not at start")
587 << 120.0 // show 6-23
591 QTest::newRow("add multiple, after visible, content not at start")
592 << 120.0 // show 6-23
597 void tst_QSGGridView::removed()
599 QSGView *canvas = createView();
603 for (int i = 0; i < 40; i++)
604 model.addItem("Item" + QString::number(i), "");
606 QDeclarativeContext *ctxt = canvas->rootContext();
607 ctxt->setContextProperty("testModel", &model);
608 ctxt->setContextProperty("testRightToLeft", QVariant(false));
609 ctxt->setContextProperty("testTopToBottom", QVariant(false));
611 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
612 qApp->processEvents();
614 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
615 QTRY_VERIFY(gridview != 0);
617 QSGItem *contentItem = gridview->contentItem();
618 QTRY_VERIFY(contentItem != 0);
621 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
623 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
624 QTRY_VERIFY(name != 0);
625 QTRY_COMPARE(name->text(), model.name(1));
626 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
627 QTRY_VERIFY(number != 0);
628 QTRY_COMPARE(number->text(), model.number(1));
631 // Checks that onRemove is called
632 QString removed = canvas->rootObject()->property("removed").toString();
633 QTRY_COMPARE(removed, QString("Item1"));
635 // Confirm items positioned correctly
636 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
637 for (int i = 0; i < model.count() && i < itemCount; ++i) {
638 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
639 if (!item) qWarning() << "Item" << i << "not found";
640 QTRY_VERIFY(item->x() == (i%3)*80);
641 QTRY_VERIFY(item->y() == (i/3)*60);
644 // Remove first item (which is the current item);
646 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
648 name = findItem<QSGText>(contentItem, "textName", 0);
649 QTRY_VERIFY(name != 0);
650 QTRY_COMPARE(name->text(), model.name(0));
651 number = findItem<QSGText>(contentItem, "textNumber", 0);
652 QTRY_VERIFY(number != 0);
653 QTRY_COMPARE(number->text(), model.number(0));
656 // Confirm items positioned correctly
657 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
658 for (int i = 0; i < model.count() && i < itemCount; ++i) {
659 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
660 if (!item) qWarning() << "Item" << i << "not found";
661 QTRY_VERIFY(item->x() == (i%3)*80);
662 QTRY_VERIFY(item->y() == (i/3)*60);
665 // Remove items not visible
666 model.removeItem(25);
667 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
669 // Confirm items positioned correctly
670 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
671 for (int i = 0; i < model.count() && i < itemCount; ++i) {
672 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
673 if (!item) qWarning() << "Item" << i << "not found";
674 QTRY_VERIFY(item->x() == (i%3)*80);
675 QTRY_VERIFY(item->y() == (i/3)*60);
678 // Remove items before visible
679 gridview->setContentY(120);
680 gridview->setCurrentIndex(10);
682 // Setting currentIndex above shouldn't cause view to scroll
683 QTRY_COMPARE(gridview->contentY(), 120.0);
686 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
688 // Confirm items positioned correctly
689 for (int i = 6; i < 18; ++i) {
690 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
691 if (!item) qWarning() << "Item" << i << "not found";
692 QTRY_VERIFY(item->x() == (i%3)*80);
693 QTRY_VERIFY(item->y() == (i/3)*60);
696 // Remove currentIndex
697 QSGItem *oldCurrent = gridview->currentItem();
699 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
701 QTRY_COMPARE(gridview->currentIndex(), 9);
702 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
704 gridview->setContentY(0);
705 // let transitions settle.
708 // Confirm items positioned correctly
709 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
710 for (int i = 0; i < model.count() && i < itemCount; ++i) {
711 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
712 QTRY_VERIFY(item->x() == (i%3)*80);
713 QTRY_VERIFY(item->y() == (i/3)*60);
716 // remove item outside current view.
717 gridview->setCurrentIndex(32);
718 gridview->setContentY(240);
720 model.removeItem(30);
721 QTRY_VERIFY(gridview->currentIndex() == 31);
723 // remove current item beyond visible items.
724 gridview->setCurrentIndex(20);
725 gridview->setContentY(0);
726 model.removeItem(20);
728 QTRY_COMPARE(gridview->currentIndex(), 20);
729 QTRY_VERIFY(gridview->currentItem() != 0);
731 // remove item before current, but visible
732 gridview->setCurrentIndex(8);
733 gridview->setContentY(240);
734 oldCurrent = gridview->currentItem();
737 QTRY_COMPARE(gridview->currentIndex(), 7);
738 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
743 void tst_QSGGridView::clear()
745 QSGView *canvas = createView();
748 for (int i = 0; i < 30; i++)
749 model.addItem("Item" + QString::number(i), "");
751 QDeclarativeContext *ctxt = canvas->rootContext();
752 ctxt->setContextProperty("testModel", &model);
753 ctxt->setContextProperty("testRightToLeft", QVariant(false));
754 ctxt->setContextProperty("testTopToBottom", QVariant(false));
756 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
757 qApp->processEvents();
759 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
760 QVERIFY(gridview != 0);
762 QSGItem *contentItem = gridview->contentItem();
763 QVERIFY(contentItem != 0);
767 QVERIFY(gridview->count() == 0);
768 QVERIFY(gridview->currentItem() == 0);
769 QVERIFY(gridview->contentY() == 0);
770 QVERIFY(gridview->currentIndex() == -1);
772 // confirm sanity when adding an item to cleared list
773 model.addItem("New", "1");
774 QTRY_COMPARE(gridview->count(), 1);
775 QVERIFY(gridview->currentItem() != 0);
776 QVERIFY(gridview->currentIndex() == 0);
781 void tst_QSGGridView::moved()
783 QFETCH(qreal, contentY);
787 QFETCH(qreal, itemsOffsetAfterMove);
791 QSGView *canvas = createView();
795 for (int i = 0; i < 30; i++)
796 model.addItem("Item" + QString::number(i), "");
798 QDeclarativeContext *ctxt = canvas->rootContext();
799 ctxt->setContextProperty("testModel", &model);
800 ctxt->setContextProperty("testRightToLeft", QVariant(false));
801 ctxt->setContextProperty("testTopToBottom", QVariant(false));
803 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
804 qApp->processEvents();
806 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
807 QTRY_VERIFY(gridview != 0);
809 QSGItem *contentItem = gridview->contentItem();
810 QTRY_VERIFY(contentItem != 0);
812 QSGItem *currentItem = gridview->currentItem();
813 QTRY_VERIFY(currentItem != 0);
815 gridview->setContentY(contentY);
816 model.moveItems(from, to, count);
818 // wait for items to move
821 // Confirm items positioned correctly and indexes correct
822 int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
823 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
824 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
825 if (i >= firstVisibleIndex + 18) // index has moved out of view
827 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
828 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
830 QTRY_COMPARE(item->x(), (i%3)*80.0);
831 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
833 name = findItem<QSGText>(contentItem, "textName", i);
835 QTRY_COMPARE(name->text(), model.name(i));
836 number = findItem<QSGText>(contentItem, "textNumber", i);
837 QVERIFY(number != 0);
838 QTRY_COMPARE(number->text(), model.number(i));
840 // current index should have been updated
841 if (item == currentItem)
842 QTRY_COMPARE(gridview->currentIndex(), i);
848 void tst_QSGGridView::moved_data()
850 QTest::addColumn<qreal>("contentY");
851 QTest::addColumn<int>("from");
852 QTest::addColumn<int>("to");
853 QTest::addColumn<int>("count");
854 QTest::addColumn<qreal>("itemsOffsetAfterMove");
856 // model starts with 30 items, each 80x60, in area 240x320
857 // 18 items should be visible at a time
859 QTest::newRow("move 1 forwards, within visible items")
864 QTest::newRow("move 1 forwards, from non-visible -> visible")
865 << 120.0 // show 6-23
867 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
869 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
870 << 120.0 // // show 6-23
872 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
874 QTest::newRow("move 1 forwards, from visible -> non-visible")
879 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
885 QTest::newRow("move 1 backwards, within visible items")
890 QTest::newRow("move 1 backwards, within visible items (to first index)")
895 QTest::newRow("move 1 backwards, from non-visible -> visible")
900 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
905 QTest::newRow("move 1 backwards, from visible -> non-visible")
906 << 120.0 // show 6-23
908 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
910 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
911 << 120.0 // show 6-23
913 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
916 QTest::newRow("move multiple forwards, within visible items")
921 QTest::newRow("move multiple forwards, before visible items")
922 << 120.0 // show 6-23
923 << 3 << 4 << 3 // 3, 4, 5 move to after 6
924 << 60.0; // row of 3,4,5 has moved down
926 QTest::newRow("move multiple forwards, from non-visible -> visible")
927 << 120.0 // show 6-23
929 << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
931 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
932 << 120.0 // show 6-23
934 << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
936 QTest::newRow("move multiple forwards, from visible -> non-visible")
941 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
947 QTest::newRow("move multiple backwards, within visible items")
952 QTest::newRow("move multiple backwards, from non-visible -> visible")
957 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
962 QTest::newRow("move multiple backwards, from visible -> non-visible")
963 << 120.0 // show 6-23
965 << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
967 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
968 << 120.0 // show 6-23
970 << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
974 enum { Inserted, Removed, Moved, SetCurrent } type;
979 static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
980 static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
981 static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
982 static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
984 Q_DECLARE_METATYPE(QList<ListChange>)
986 void tst_QSGGridView::multipleChanges()
988 QFETCH(int, startCount);
989 QFETCH(QList<ListChange>, changes);
990 QFETCH(int, newCount);
991 QFETCH(int, newCurrentIndex);
993 QSGView *canvas = createView();
997 for (int i = 0; i < startCount; i++)
998 model.addItem("Item" + QString::number(i), "");
1000 QDeclarativeContext *ctxt = canvas->rootContext();
1001 ctxt->setContextProperty("testModel", &model);
1002 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1003 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1005 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1006 qApp->processEvents();
1008 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1009 QTRY_VERIFY(gridview != 0);
1011 for (int i=0; i<changes.count(); i++) {
1012 switch (changes[i].type) {
1013 case ListChange::Inserted:
1015 QList<QPair<QString, QString> > items;
1016 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1017 items << qMakePair(QString("new item " + j), QString::number(j));
1018 model.insertItems(changes[i].index, items);
1021 case ListChange::Removed:
1022 model.removeItems(changes[i].index, changes[i].count);
1024 case ListChange::Moved:
1025 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1027 case ListChange::SetCurrent:
1028 gridview->setCurrentIndex(changes[i].index);
1033 QTRY_COMPARE(gridview->count(), newCount);
1034 QCOMPARE(gridview->count(), model.count());
1035 QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
1039 QSGItem *contentItem = gridview->contentItem();
1040 QTRY_VERIFY(contentItem != 0);
1041 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1042 for (int i=0; i < model.count() && i < itemCount; ++i) {
1043 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1044 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1045 name = findItem<QSGText>(contentItem, "textName", i);
1047 QTRY_COMPARE(name->text(), model.name(i));
1048 number = findItem<QSGText>(contentItem, "textNumber", i);
1049 QVERIFY(number != 0);
1050 QTRY_COMPARE(number->text(), model.number(i));
1056 void tst_QSGGridView::multipleChanges_data()
1058 QTest::addColumn<int>("startCount");
1059 QTest::addColumn<QList<ListChange> >("changes");
1060 QTest::addColumn<int>("newCount");
1061 QTest::addColumn<int>("newCurrentIndex");
1063 QList<ListChange> changes;
1065 for (int i=1; i<30; i++)
1066 changes << ListChange::remove(0);
1067 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1069 changes << ListChange::remove(0);
1070 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1073 changes << ListChange::setCurrent(29);
1074 for (int i=29; i>0; i--)
1075 changes << ListChange::remove(i);
1076 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1078 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1079 << ListChange::remove(0, 1)
1080 << ListChange::insert(0, 1)
1083 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1084 << ListChange::setCurrent(2)
1085 << ListChange::remove(2, 1)
1086 << ListChange::insert(2, 1)
1089 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1090 << ListChange::setCurrent(1)
1091 << ListChange::remove(1, 3)
1092 << ListChange::insert(2, 2)
1095 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1096 << ListChange::setCurrent(2)
1097 << ListChange::remove(1, 3)
1098 << ListChange::move(1, 5, 1)
1101 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1102 << ListChange::setCurrent(5)
1103 << ListChange::remove(4, 3)
1104 << ListChange::move(4, 1, 1)
1108 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1109 << ListChange::insert(0, 2)
1110 << ListChange::insert(0, 4)
1111 << ListChange::insert(0, 6)
1114 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1115 << ListChange::insert(0, 2)
1116 << ListChange::insert(0, 4)
1117 << ListChange::insert(0, 6)
1118 << ListChange::setCurrent(3)
1119 << ListChange::insert(3, 2)
1122 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1123 << ListChange::insert(0, 30)
1124 << ListChange::remove(0, 30)
1127 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1128 << ListChange::insert(1)
1129 << ListChange::setCurrent(1)
1130 << ListChange::remove(1)
1133 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1134 << ListChange::insert(0, 10)
1135 << ListChange::remove(5, 10)
1138 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1139 << ListChange::insert(0, 3)
1140 << ListChange::move(0, 10, 3)
1143 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1144 << ListChange::insert(0, 3)
1145 << ListChange::move(0, 8, 5)
1148 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1149 << ListChange::setCurrent(9)
1150 << ListChange::insert(10, 3)
1151 << ListChange::move(8, 0, 5)
1155 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1156 << ListChange::setCurrent(1)
1157 << ListChange::move(1, 2, 2)
1158 << ListChange::move(2, 1, 2)
1161 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1162 << ListChange::setCurrent(2)
1163 << ListChange::move(1, 2, 3)
1164 << ListChange::move(3, 0, 5)
1167 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1168 << ListChange::setCurrent(5)
1169 << ListChange::move(5, 0, 1)
1170 << ListChange::remove(0)
1173 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1174 << ListChange::setCurrent(5)
1175 << ListChange::move(5, 0, 1)
1176 << ListChange::insert(0)
1179 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1180 << ListChange::setCurrent(1)
1181 << ListChange::move(5, 1, 3)
1182 << ListChange::remove(1, 3)
1185 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1186 << ListChange::setCurrent(5)
1187 << ListChange::move(5, 1, 3)
1188 << ListChange::insert(1, 5)
1191 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1192 << ListChange::setCurrent(3)
1193 << ListChange::move(0, 1, 2)
1194 << ListChange::insert(3, 5)
1198 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1199 << ListChange::insert(0, 5)
1200 << ListChange::setCurrent(-1)
1201 << ListChange::remove(0, 5)
1202 << ListChange::insert(0, 5)
1207 void tst_QSGGridView::swapWithFirstItem()
1210 QSGView *canvas = createView();
1214 for (int i = 0; i < 30; i++)
1215 model.addItem("Item" + QString::number(i), "");
1217 QDeclarativeContext *ctxt = canvas->rootContext();
1218 ctxt->setContextProperty("testModel", &model);
1219 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1220 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1222 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1223 qApp->processEvents();
1225 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1226 QTRY_VERIFY(gridview != 0);
1228 // ensure content position is stable
1229 gridview->setContentY(0);
1230 model.moveItem(10, 0);
1231 QTRY_VERIFY(gridview->contentY() == 0);
1236 void tst_QSGGridView::currentIndex()
1239 for (int i = 0; i < 60; i++)
1240 model.addItem("Item" + QString::number(i), QString::number(i));
1242 QSGView *canvas = new QSGView(0);
1243 canvas->setGeometry(0,0,240,320);
1246 QDeclarativeContext *ctxt = canvas->rootContext();
1247 ctxt->setContextProperty("testModel", &model);
1249 QString filename(TESTDATA("gridview-initCurrent.qml"));
1250 canvas->setSource(QUrl::fromLocalFile(filename));
1252 qApp->processEvents();
1254 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1255 QVERIFY(gridview != 0);
1257 QSGItem *contentItem = gridview->contentItem();
1258 QVERIFY(contentItem != 0);
1260 // current item should be third item
1261 QCOMPARE(gridview->currentIndex(), 35);
1262 QCOMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 35));
1263 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1264 QCOMPARE(gridview->contentY(), 400.0);
1266 gridview->moveCurrentIndexRight();
1267 QCOMPARE(gridview->currentIndex(), 36);
1268 gridview->moveCurrentIndexDown();
1269 QCOMPARE(gridview->currentIndex(), 39);
1270 gridview->moveCurrentIndexUp();
1271 QCOMPARE(gridview->currentIndex(), 36);
1272 gridview->moveCurrentIndexLeft();
1273 QCOMPARE(gridview->currentIndex(), 35);
1276 gridview->setCurrentIndex(0);
1277 QCOMPARE(gridview->currentIndex(), 0);
1278 // confirm that the velocity is updated
1279 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1281 gridview->moveCurrentIndexUp();
1282 QCOMPARE(gridview->currentIndex(), 0);
1284 gridview->moveCurrentIndexLeft();
1285 QCOMPARE(gridview->currentIndex(), 0);
1287 gridview->setCurrentIndex(model.count()-1);
1288 QCOMPARE(gridview->currentIndex(), model.count()-1);
1290 gridview->moveCurrentIndexRight();
1291 QCOMPARE(gridview->currentIndex(), model.count()-1);
1293 gridview->moveCurrentIndexDown();
1294 QCOMPARE(gridview->currentIndex(), model.count()-1);
1297 gridview->setWrapEnabled(true);
1299 gridview->setCurrentIndex(0);
1300 QCOMPARE(gridview->currentIndex(), 0);
1302 gridview->moveCurrentIndexLeft();
1303 QCOMPARE(gridview->currentIndex(), model.count()-1);
1305 qApp->processEvents();
1306 QTRY_COMPARE(gridview->contentY(), 880.0);
1308 gridview->moveCurrentIndexRight();
1309 QCOMPARE(gridview->currentIndex(), 0);
1311 QTRY_COMPARE(gridview->contentY(), 0.0);
1314 // footer should become visible if it is out of view, and then current index moves to the first row
1315 canvas->rootObject()->setProperty("showFooter", true);
1316 QTRY_VERIFY(gridview->footerItem());
1317 gridview->setCurrentIndex(model.count()-3);
1318 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1319 gridview->setCurrentIndex(model.count()-2);
1320 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1321 canvas->rootObject()->setProperty("showFooter", false);
1323 // header should become visible if it is out of view, and then current index moves to the last row
1324 canvas->rootObject()->setProperty("showHeader", true);
1325 QTRY_VERIFY(gridview->headerItem());
1326 gridview->setCurrentIndex(3);
1327 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1328 gridview->setCurrentIndex(1);
1329 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1330 canvas->rootObject()->setProperty("showHeader", false);
1334 canvas->requestActivateWindow();
1335 QTest::qWaitForWindowShown(canvas);
1336 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1338 gridview->setCurrentIndex(0);
1340 QTest::keyClick(canvas, Qt::Key_Down);
1341 QCOMPARE(gridview->currentIndex(), 3);
1343 QTest::keyClick(canvas, Qt::Key_Up);
1344 QCOMPARE(gridview->currentIndex(), 0);
1346 // hold down Key_Down
1347 for (int i=0; i<(model.count() / 3) - 1; i++) {
1348 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1349 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1351 QTest::keyRelease(canvas, Qt::Key_Down);
1352 QTRY_COMPARE(gridview->currentIndex(), 57);
1353 QTRY_COMPARE(gridview->contentY(), 880.0);
1356 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1357 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1358 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1360 QTest::keyRelease(canvas, Qt::Key_Up);
1361 QTRY_COMPARE(gridview->currentIndex(), 0);
1362 QTRY_COMPARE(gridview->contentY(), 0.0);
1365 gridview->setFlow(QSGGridView::TopToBottom);
1367 canvas->requestActivateWindow();
1368 QTest::qWaitForWindowShown(canvas);
1369 QVERIFY(qGuiApp->focusWindow() == canvas);
1370 qApp->processEvents();
1372 QTest::keyClick(canvas, Qt::Key_Right);
1373 QCOMPARE(gridview->currentIndex(), 5);
1375 QTest::keyClick(canvas, Qt::Key_Left);
1376 QCOMPARE(gridview->currentIndex(), 0);
1378 QTest::keyClick(canvas, Qt::Key_Down);
1379 QCOMPARE(gridview->currentIndex(), 1);
1381 QTest::keyClick(canvas, Qt::Key_Up);
1382 QCOMPARE(gridview->currentIndex(), 0);
1384 // hold down Key_Right
1385 for (int i=0; i<(model.count() / 5) - 1; i++) {
1386 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1387 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1390 QTest::keyRelease(canvas, Qt::Key_Right);
1391 QTRY_COMPARE(gridview->currentIndex(), 55);
1392 QTRY_COMPARE(gridview->contentX(), 720.0);
1394 // hold down Key_Left
1395 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1396 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1397 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1399 QTest::keyRelease(canvas, Qt::Key_Left);
1400 QTRY_COMPARE(gridview->currentIndex(), 0);
1401 QTRY_COMPARE(gridview->contentX(), 0.0);
1404 // turn off auto highlight
1405 gridview->setHighlightFollowsCurrentItem(false);
1406 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1407 QVERIFY(gridview->highlightItem());
1408 qreal hlPosX = gridview->highlightItem()->x();
1409 qreal hlPosY = gridview->highlightItem()->y();
1411 gridview->setCurrentIndex(5);
1412 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1413 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1415 // insert item before currentIndex
1416 gridview->setCurrentIndex(28);
1417 model.insertItem(0, "Foo", "1111");
1418 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1420 // check removing highlight by setting currentIndex to -1;
1421 gridview->setCurrentIndex(-1);
1423 QCOMPARE(gridview->currentIndex(), -1);
1424 QVERIFY(!gridview->highlightItem());
1425 QVERIFY(!gridview->currentItem());
1427 gridview->setHighlightFollowsCurrentItem(true);
1429 gridview->setFlow(QSGGridView::LeftToRight);
1430 gridview->setLayoutDirection(Qt::RightToLeft);
1432 canvas->requestActivateWindow();
1433 QTest::qWaitForWindowShown(canvas);
1434 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1435 qApp->processEvents();
1437 gridview->setCurrentIndex(35);
1439 QTest::keyClick(canvas, Qt::Key_Right);
1440 QCOMPARE(gridview->currentIndex(), 34);
1442 QTest::keyClick(canvas, Qt::Key_Down);
1443 QCOMPARE(gridview->currentIndex(), 37);
1445 QTest::keyClick(canvas, Qt::Key_Up);
1446 QCOMPARE(gridview->currentIndex(), 34);
1448 QTest::keyClick(canvas, Qt::Key_Left);
1449 QCOMPARE(gridview->currentIndex(), 35);
1452 // turn off auto highlight
1453 gridview->setHighlightFollowsCurrentItem(false);
1454 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1455 QVERIFY(gridview->highlightItem());
1456 hlPosX = gridview->highlightItem()->x();
1457 hlPosY = gridview->highlightItem()->y();
1459 gridview->setCurrentIndex(5);
1460 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1461 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1463 // insert item before currentIndex
1464 gridview->setCurrentIndex(28);
1465 model.insertItem(0, "Foo", "1111");
1466 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1468 // check removing highlight by setting currentIndex to -1;
1469 gridview->setCurrentIndex(-1);
1471 QCOMPARE(gridview->currentIndex(), -1);
1472 QVERIFY(!gridview->highlightItem());
1473 QVERIFY(!gridview->currentItem());
1478 void tst_QSGGridView::noCurrentIndex()
1481 for (int i = 0; i < 60; i++)
1482 model.addItem("Item" + QString::number(i), QString::number(i));
1484 QSGView *canvas = new QSGView(0);
1485 canvas->setGeometry(0,0,240,320);
1487 QDeclarativeContext *ctxt = canvas->rootContext();
1488 ctxt->setContextProperty("testModel", &model);
1490 QString filename(TESTDATA("gridview-noCurrent.qml"));
1491 canvas->setSource(QUrl::fromLocalFile(filename));
1493 qApp->processEvents();
1495 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1496 QVERIFY(gridview != 0);
1498 QSGItem *contentItem = gridview->contentItem();
1499 QVERIFY(contentItem != 0);
1501 // current index should be -1
1502 QCOMPARE(gridview->currentIndex(), -1);
1503 QVERIFY(!gridview->currentItem());
1504 QVERIFY(!gridview->highlightItem());
1505 QCOMPARE(gridview->contentY(), 0.0);
1507 gridview->setCurrentIndex(5);
1508 QCOMPARE(gridview->currentIndex(), 5);
1509 QVERIFY(gridview->currentItem());
1510 QVERIFY(gridview->highlightItem());
1515 void tst_QSGGridView::changeFlow()
1517 QSGView *canvas = createView();
1520 for (int i = 0; i < 30; i++)
1521 model.addItem("Item" + QString::number(i), QString::number(i));
1523 QDeclarativeContext *ctxt = canvas->rootContext();
1524 ctxt->setContextProperty("testModel", &model);
1525 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1526 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1528 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1529 qApp->processEvents();
1531 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1532 QTRY_VERIFY(gridview != 0);
1534 QSGItem *contentItem = gridview->contentItem();
1535 QTRY_VERIFY(contentItem != 0);
1537 // Confirm items positioned correctly and indexes correct
1538 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1539 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1540 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1541 if (!item) qWarning() << "Item" << i << "not found";
1543 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1544 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1545 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1546 QTRY_VERIFY(name != 0);
1547 QTRY_COMPARE(name->text(), model.name(i));
1548 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1549 QTRY_VERIFY(number != 0);
1550 QTRY_COMPARE(number->text(), model.number(i));
1553 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1555 // Confirm items positioned correctly and indexes correct
1556 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1557 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1558 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1559 if (!item) qWarning() << "Item" << i << "not found";
1561 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1562 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1563 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1564 QTRY_VERIFY(name != 0);
1565 QTRY_COMPARE(name->text(), model.name(i));
1566 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1567 QTRY_VERIFY(number != 0);
1568 QTRY_COMPARE(number->text(), model.number(i));
1571 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1573 // Confirm items positioned correctly and indexes correct
1574 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1575 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1576 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1577 if (!item) qWarning() << "Item" << i << "not found";
1579 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1580 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1581 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1582 QTRY_VERIFY(name != 0);
1583 QTRY_COMPARE(name->text(), model.name(i));
1584 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1585 QTRY_VERIFY(number != 0);
1586 QTRY_COMPARE(number->text(), model.number(i));
1588 gridview->setContentX(100);
1589 QTRY_COMPARE(gridview->contentX(), 100.);
1590 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1591 QTRY_COMPARE(gridview->contentX(), 0.);
1593 // Confirm items positioned correctly and indexes correct
1594 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1595 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1596 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1597 if (!item) qWarning() << "Item" << i << "not found";
1599 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1600 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1601 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1602 QTRY_VERIFY(name != 0);
1603 QTRY_COMPARE(name->text(), model.name(i));
1604 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1605 QTRY_VERIFY(number != 0);
1606 QTRY_COMPARE(number->text(), model.number(i));
1612 void tst_QSGGridView::defaultValues()
1614 QDeclarativeEngine engine;
1615 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview3.qml")));
1616 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1618 QTRY_VERIFY(obj != 0);
1619 QTRY_VERIFY(obj->model() == QVariant());
1620 QTRY_VERIFY(obj->delegate() == 0);
1621 QTRY_COMPARE(obj->currentIndex(), -1);
1622 QTRY_VERIFY(obj->currentItem() == 0);
1623 QTRY_COMPARE(obj->count(), 0);
1624 QTRY_VERIFY(obj->highlight() == 0);
1625 QTRY_VERIFY(obj->highlightItem() == 0);
1626 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1627 QTRY_VERIFY(obj->flow() == 0);
1628 QTRY_COMPARE(obj->isWrapEnabled(), false);
1629 QTRY_COMPARE(obj->cacheBuffer(), 0);
1630 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
1631 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1635 void tst_QSGGridView::properties()
1637 QDeclarativeEngine engine;
1638 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview2.qml")));
1639 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1641 QTRY_VERIFY(obj != 0);
1642 QTRY_VERIFY(obj->model() != QVariant());
1643 QTRY_VERIFY(obj->delegate() != 0);
1644 QTRY_COMPARE(obj->currentIndex(), 0);
1645 QTRY_VERIFY(obj->currentItem() != 0);
1646 QTRY_COMPARE(obj->count(), 4);
1647 QTRY_VERIFY(obj->highlight() != 0);
1648 QTRY_VERIFY(obj->highlightItem() != 0);
1649 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1650 QTRY_VERIFY(obj->flow() == 0);
1651 QTRY_COMPARE(obj->isWrapEnabled(), true);
1652 QTRY_COMPARE(obj->cacheBuffer(), 200);
1653 QTRY_COMPARE(obj->cellWidth(), qreal(100));
1654 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1658 void tst_QSGGridView::propertyChanges()
1660 QSGView *canvas = createView();
1661 QTRY_VERIFY(canvas);
1662 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1664 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1665 QTRY_VERIFY(gridView);
1667 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1668 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1669 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1670 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1672 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1673 QTRY_COMPARE(gridView->cacheBuffer(), 10);
1674 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1676 gridView->setWrapEnabled(false);
1677 gridView->setCacheBuffer(3);
1678 gridView->setFlow(QSGGridView::TopToBottom);
1680 QTRY_COMPARE(gridView->isWrapEnabled(), false);
1681 QTRY_COMPARE(gridView->cacheBuffer(), 3);
1682 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1684 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1685 QTRY_COMPARE(cacheBufferSpy.count(),1);
1686 QTRY_COMPARE(flowSpy.count(),1);
1688 gridView->setWrapEnabled(false);
1689 gridView->setCacheBuffer(3);
1690 gridView->setFlow(QSGGridView::TopToBottom);
1692 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1693 QTRY_COMPARE(cacheBufferSpy.count(),1);
1694 QTRY_COMPARE(flowSpy.count(),1);
1696 gridView->setFlow(QSGGridView::LeftToRight);
1697 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1699 gridView->setWrapEnabled(true);
1700 gridView->setCacheBuffer(5);
1701 gridView->setLayoutDirection(Qt::RightToLeft);
1703 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1704 QTRY_COMPARE(gridView->cacheBuffer(), 5);
1705 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1707 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1708 QTRY_COMPARE(cacheBufferSpy.count(),2);
1709 QTRY_COMPARE(layoutSpy.count(),1);
1710 QTRY_COMPARE(flowSpy.count(),2);
1712 gridView->setWrapEnabled(true);
1713 gridView->setCacheBuffer(5);
1714 gridView->setLayoutDirection(Qt::RightToLeft);
1716 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1717 QTRY_COMPARE(cacheBufferSpy.count(),2);
1718 QTRY_COMPARE(layoutSpy.count(),1);
1719 QTRY_COMPARE(flowSpy.count(),2);
1721 gridView->setFlow(QSGGridView::TopToBottom);
1722 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1723 QTRY_COMPARE(flowSpy.count(),3);
1725 gridView->setFlow(QSGGridView::TopToBottom);
1726 QTRY_COMPARE(flowSpy.count(),3);
1731 void tst_QSGGridView::componentChanges()
1733 QSGView *canvas = createView();
1734 QTRY_VERIFY(canvas);
1735 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1737 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1738 QTRY_VERIFY(gridView);
1740 QDeclarativeComponent component(canvas->engine());
1741 component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1743 QDeclarativeComponent delegateComponent(canvas->engine());
1744 delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1746 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1747 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1748 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1749 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1751 gridView->setHighlight(&component);
1752 gridView->setDelegate(&delegateComponent);
1753 gridView->setHeader(&component);
1754 gridView->setFooter(&component);
1756 QTRY_COMPARE(gridView->highlight(), &component);
1757 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1758 QTRY_COMPARE(gridView->header(), &component);
1759 QTRY_COMPARE(gridView->footer(), &component);
1761 QTRY_COMPARE(highlightSpy.count(),1);
1762 QTRY_COMPARE(delegateSpy.count(),1);
1763 QTRY_COMPARE(headerSpy.count(),1);
1764 QTRY_COMPARE(footerSpy.count(),1);
1766 gridView->setHighlight(&component);
1767 gridView->setDelegate(&delegateComponent);
1768 gridView->setHeader(&component);
1769 gridView->setFooter(&component);
1771 QTRY_COMPARE(highlightSpy.count(),1);
1772 QTRY_COMPARE(delegateSpy.count(),1);
1773 QTRY_COMPARE(headerSpy.count(),1);
1774 QTRY_COMPARE(footerSpy.count(),1);
1779 void tst_QSGGridView::modelChanges()
1781 QSGView *canvas = createView();
1782 QTRY_VERIFY(canvas);
1783 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1785 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1786 QTRY_VERIFY(gridView);
1788 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1789 QTRY_VERIFY(alternateModel);
1790 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1791 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1793 gridView->setModel(modelVariant);
1794 QTRY_COMPARE(gridView->model(), modelVariant);
1795 QTRY_COMPARE(modelSpy.count(),1);
1797 gridView->setModel(modelVariant);
1798 QTRY_COMPARE(modelSpy.count(),1);
1800 gridView->setModel(QVariant());
1801 QTRY_COMPARE(modelSpy.count(),2);
1805 void tst_QSGGridView::positionViewAtIndex()
1807 QSGView *canvas = createView();
1810 for (int i = 0; i < 40; i++)
1811 model.addItem("Item" + QString::number(i), "");
1813 QDeclarativeContext *ctxt = canvas->rootContext();
1814 ctxt->setContextProperty("testModel", &model);
1815 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1816 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1818 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1819 qApp->processEvents();
1821 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1822 QTRY_VERIFY(gridview != 0);
1824 QSGItem *contentItem = gridview->contentItem();
1825 QTRY_VERIFY(contentItem != 0);
1827 // Confirm items positioned correctly
1828 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1829 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1830 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1831 if (!item) qWarning() << "Item" << i << "not found";
1833 QTRY_COMPARE(item->x(), (i%3)*80.);
1834 QTRY_COMPARE(item->y(), (i/3)*60.);
1837 // Position on a currently visible item
1838 gridview->positionViewAtIndex(4, QSGGridView::Beginning);
1839 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1840 QTRY_COMPARE(gridview->contentY(), 60.);
1842 // Confirm items positioned correctly
1843 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1844 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1845 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1846 if (!item) qWarning() << "Item" << i << "not found";
1848 QTRY_COMPARE(item->x(), (i%3)*80.);
1849 QTRY_COMPARE(item->y(), (i/3)*60.);
1852 // Position on an item beyond the visible items
1853 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1854 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1855 QTRY_COMPARE(gridview->contentY(), 420.);
1857 // Confirm items positioned correctly
1858 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1859 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1860 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1861 if (!item) qWarning() << "Item" << i << "not found";
1863 QTRY_COMPARE(item->x(), (i%3)*80.);
1864 QTRY_COMPARE(item->y(), (i/3)*60.);
1867 // Position on an item that would leave empty space if positioned at the top
1868 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1869 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1870 QTRY_COMPARE(gridview->contentY(), 520.);
1872 // Confirm items positioned correctly
1873 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1874 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1875 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1876 if (!item) qWarning() << "Item" << i << "not found";
1878 QTRY_COMPARE(item->x(), (i%3)*80.);
1879 QTRY_COMPARE(item->y(), (i/3)*60.);
1882 // Position at the beginning again
1883 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1884 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1885 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1886 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1887 QTRY_COMPARE(gridview->contentY(), 0.);
1889 // Confirm items positioned correctly
1890 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1891 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1892 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1893 if (!item) qWarning() << "Item" << i << "not found";
1895 QTRY_COMPARE(item->x(), (i%3)*80.);
1896 QTRY_COMPARE(item->y(), (i/3)*60.);
1900 gridview->positionViewAtIndex(30, QSGGridView::End);
1901 QTRY_COMPARE(gridview->contentY(), 340.);
1903 // Position in Center
1904 gridview->positionViewAtIndex(15, QSGGridView::Center);
1905 QTRY_COMPARE(gridview->contentY(), 170.);
1907 // Ensure at least partially visible
1908 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1909 QTRY_COMPARE(gridview->contentY(), 170.);
1911 gridview->setContentY(302);
1912 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1913 QTRY_COMPARE(gridview->contentY(), 302.);
1915 gridview->setContentY(360);
1916 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1917 QTRY_COMPARE(gridview->contentY(), 300.);
1919 gridview->setContentY(60);
1920 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1921 QTRY_COMPARE(gridview->contentY(), 60.);
1923 gridview->setContentY(20);
1924 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1925 QTRY_COMPARE(gridview->contentY(), 100.);
1927 // Ensure completely visible
1928 gridview->setContentY(120);
1929 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1930 QTRY_COMPARE(gridview->contentY(), 120.);
1932 gridview->setContentY(302);
1933 gridview->positionViewAtIndex(15, QSGGridView::Contain);
1934 QTRY_COMPARE(gridview->contentY(), 300.);
1936 gridview->setContentY(60);
1937 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1938 QTRY_COMPARE(gridview->contentY(), 100.);
1940 // Test for Top To Bottom layout
1941 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1943 // Confirm items positioned correctly
1944 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1945 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1946 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1947 if (!item) qWarning() << "Item" << i << "not found";
1949 QTRY_COMPARE(item->x(), (i/5)*80.);
1950 QTRY_COMPARE(item->y(), (i%5)*60.);
1954 gridview->positionViewAtIndex(30, QSGGridView::End);
1955 QTRY_COMPARE(gridview->contentX(), 320.);
1956 QTRY_COMPARE(gridview->contentY(), 0.);
1958 // Position in Center
1959 gridview->positionViewAtIndex(15, QSGGridView::Center);
1960 QTRY_COMPARE(gridview->contentX(), 160.);
1962 // Ensure at least partially visible
1963 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1964 QTRY_COMPARE(gridview->contentX(), 160.);
1966 gridview->setContentX(170);
1967 gridview->positionViewAtIndex(25, QSGGridView::Visible);
1968 QTRY_COMPARE(gridview->contentX(), 170.);
1970 gridview->positionViewAtIndex(30, QSGGridView::Visible);
1971 QTRY_COMPARE(gridview->contentX(), 320.);
1973 gridview->setContentX(170);
1974 gridview->positionViewAtIndex(25, QSGGridView::Contain);
1975 QTRY_COMPARE(gridview->contentX(), 240.);
1977 // positionViewAtBeginning
1978 gridview->positionViewAtBeginning();
1979 QTRY_COMPARE(gridview->contentX(), 0.);
1981 gridview->setContentX(80);
1982 canvas->rootObject()->setProperty("showHeader", true);
1983 gridview->positionViewAtBeginning();
1984 QTRY_COMPARE(gridview->contentX(), -30.);
1986 // positionViewAtEnd
1987 gridview->positionViewAtEnd();
1988 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
1990 gridview->setContentX(80);
1991 canvas->rootObject()->setProperty("showFooter", true);
1992 gridview->positionViewAtEnd();
1993 QTRY_COMPARE(gridview->contentX(), 430.);
1995 // set current item to outside visible view, position at beginning
1996 // and ensure highlight moves to current item
1997 gridview->setCurrentIndex(6);
1998 gridview->positionViewAtBeginning();
1999 QTRY_COMPARE(gridview->contentX(), -30.);
2000 QVERIFY(gridview->highlightItem());
2001 QCOMPARE(gridview->highlightItem()->x(), 80.);
2006 void tst_QSGGridView::snapping()
2008 QSGView *canvas = createView();
2011 for (int i = 0; i < 40; i++)
2012 model.addItem("Item" + QString::number(i), "");
2014 QDeclarativeContext *ctxt = canvas->rootContext();
2015 ctxt->setContextProperty("testModel", &model);
2016 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2017 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2019 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2020 qApp->processEvents();
2022 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2023 QTRY_VERIFY(gridview != 0);
2025 gridview->setHeight(220);
2026 QCOMPARE(gridview->height(), 220.);
2028 gridview->positionViewAtIndex(12, QSGGridView::Visible);
2029 QCOMPARE(gridview->contentY(), 80.);
2031 gridview->setContentY(0);
2032 QCOMPARE(gridview->contentY(), 0.);
2034 gridview->setSnapMode(QSGGridView::SnapToRow);
2035 QCOMPARE(gridview->snapMode(), QSGGridView::SnapToRow);
2037 gridview->positionViewAtIndex(12, QSGGridView::Visible);
2038 QCOMPARE(gridview->contentY(), 60.);
2040 gridview->positionViewAtIndex(15, QSGGridView::End);
2041 QCOMPARE(gridview->contentY(), 120.);
2047 void tst_QSGGridView::mirroring()
2049 QSGView *canvasA = createView();
2050 canvasA->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2051 QSGGridView *gridviewA = findItem<QSGGridView>(canvasA->rootObject(), "view");
2052 QTRY_VERIFY(gridviewA != 0);
2054 QSGView *canvasB = createView();
2055 canvasB->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2056 QSGGridView *gridviewB = findItem<QSGGridView>(canvasB->rootObject(), "view");
2057 QTRY_VERIFY(gridviewA != 0);
2058 qApp->processEvents();
2060 QList<QString> objectNames;
2061 objectNames << "item1" << "item2"; // << "item3"
2063 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2064 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2065 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2068 foreach (const QString objectName, objectNames)
2069 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
2071 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2072 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2075 foreach (const QString objectName, objectNames)
2076 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
2078 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2079 QSGItemPrivate::get(gridviewB)->setLayoutMirror(true);
2080 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2082 // LTR != LTR+mirror
2083 foreach (const QString objectName, objectNames)
2084 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
2086 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2088 // RTL == LTR+mirror
2089 foreach (const QString objectName, objectNames)
2090 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
2092 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2094 // RTL != RTL+mirror
2095 foreach (const QString objectName, objectNames)
2096 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
2098 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2100 // LTR == RTL+mirror
2101 foreach (const QString objectName, objectNames)
2102 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
2108 void tst_QSGGridView::positionViewAtIndex_rightToLeft()
2110 QSGView *canvas = createView();
2113 for (int i = 0; i < 40; i++)
2114 model.addItem("Item" + QString::number(i), "");
2116 QDeclarativeContext *ctxt = canvas->rootContext();
2117 ctxt->setContextProperty("testModel", &model);
2118 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2119 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2121 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2122 qApp->processEvents();
2124 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2125 QTRY_VERIFY(gridview != 0);
2127 QSGItem *contentItem = gridview->contentItem();
2128 QTRY_VERIFY(contentItem != 0);
2130 // Confirm items positioned correctly
2131 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2132 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2133 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2134 if (!item) qWarning() << "Item" << i << "not found";
2136 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2137 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2140 // Position on a currently visible item
2141 gridview->positionViewAtIndex(6, QSGGridView::Beginning);
2142 QTRY_COMPARE(gridview->contentX(), -320.);
2144 // Confirm items positioned correctly
2145 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2146 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2147 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2148 if (!item) qWarning() << "Item" << i << "not found";
2150 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2151 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2154 // Position on an item beyond the visible items
2155 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
2156 QTRY_COMPARE(gridview->contentX(), -560.);
2158 // Confirm items positioned correctly
2159 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2160 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2161 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2162 if (!item) qWarning() << "Item" << i << "not found";
2164 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2165 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2168 // Position on an item that would leave empty space if positioned at the top
2169 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
2170 QTRY_COMPARE(gridview->contentX(), -640.);
2172 // Confirm items positioned correctly
2173 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2174 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2175 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2176 if (!item) qWarning() << "Item" << i << "not found";
2178 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2179 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2182 // Position at the beginning again
2183 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
2184 QTRY_COMPARE(gridview->contentX(), -240.);
2186 // Confirm items positioned correctly
2187 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2188 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2189 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2190 if (!item) qWarning() << "Item" << i << "not found";
2192 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2193 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2197 gridview->positionViewAtIndex(30, QSGGridView::End);
2198 QTRY_COMPARE(gridview->contentX(), -560.);
2200 // Position in Center
2201 gridview->positionViewAtIndex(15, QSGGridView::Center);
2202 QTRY_COMPARE(gridview->contentX(), -400.);
2204 // Ensure at least partially visible
2205 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2206 QTRY_COMPARE(gridview->contentX(), -400.);
2208 gridview->setContentX(-555.);
2209 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2210 QTRY_COMPARE(gridview->contentX(), -555.);
2212 gridview->setContentX(-239);
2213 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2214 QTRY_COMPARE(gridview->contentX(), -320.);
2216 gridview->setContentX(-239);
2217 gridview->positionViewAtIndex(20, QSGGridView::Visible);
2218 QTRY_COMPARE(gridview->contentX(), -400.);
2220 gridview->setContentX(-640);
2221 gridview->positionViewAtIndex(20, QSGGridView::Visible);
2222 QTRY_COMPARE(gridview->contentX(), -560.);
2224 // Ensure completely visible
2225 gridview->setContentX(-400);
2226 gridview->positionViewAtIndex(20, QSGGridView::Contain);
2227 QTRY_COMPARE(gridview->contentX(), -400.);
2229 gridview->setContentX(-315);
2230 gridview->positionViewAtIndex(15, QSGGridView::Contain);
2231 QTRY_COMPARE(gridview->contentX(), -320.);
2233 gridview->setContentX(-640);
2234 gridview->positionViewAtIndex(20, QSGGridView::Contain);
2235 QTRY_COMPARE(gridview->contentX(), -560.);
2240 void tst_QSGGridView::resetModel()
2242 QSGView *canvas = createView();
2244 QStringList strings;
2245 strings << "one" << "two" << "three";
2246 QStringListModel model(strings);
2248 QDeclarativeContext *ctxt = canvas->rootContext();
2249 ctxt->setContextProperty("testModel", &model);
2251 canvas->setSource(QUrl::fromLocalFile(TESTDATA("displaygrid.qml")));
2252 qApp->processEvents();
2254 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2255 QTRY_VERIFY(gridview != 0);
2257 QSGItem *contentItem = gridview->contentItem();
2258 QTRY_VERIFY(contentItem != 0);
2260 QTRY_COMPARE(gridview->count(), model.rowCount());
2262 for (int i = 0; i < model.rowCount(); ++i) {
2263 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
2264 QTRY_VERIFY(display != 0);
2265 QTRY_COMPARE(display->text(), strings.at(i));
2269 strings << "four" << "five" << "six" << "seven";
2270 model.setStringList(strings);
2272 QTRY_COMPARE(gridview->count(), model.rowCount());
2274 for (int i = 0; i < model.rowCount(); ++i) {
2275 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
2276 QTRY_VERIFY(display != 0);
2277 QTRY_COMPARE(display->text(), strings.at(i));
2283 void tst_QSGGridView::enforceRange()
2285 QSGView *canvas = createView();
2288 for (int i = 0; i < 30; i++)
2289 model.addItem("Item" + QString::number(i), "");
2291 QDeclarativeContext *ctxt = canvas->rootContext();
2292 ctxt->setContextProperty("testModel", &model);
2293 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2294 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2296 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2297 qApp->processEvents();
2298 QVERIFY(canvas->rootObject() != 0);
2300 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2301 QTRY_VERIFY(gridview != 0);
2303 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2304 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2305 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
2307 QSGItem *contentItem = gridview->contentItem();
2308 QTRY_VERIFY(contentItem != 0);
2310 // view should be positioned at the top of the range.
2311 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2313 QTRY_COMPARE(gridview->contentY(), -100.0);
2315 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
2316 QTRY_VERIFY(name != 0);
2317 QTRY_COMPARE(name->text(), model.name(0));
2318 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
2319 QTRY_VERIFY(number != 0);
2320 QTRY_COMPARE(number->text(), model.number(0));
2322 // Check currentIndex is updated when contentItem moves
2323 gridview->setContentY(0);
2324 QTRY_COMPARE(gridview->currentIndex(), 2);
2326 gridview->setCurrentIndex(5);
2327 QTRY_COMPARE(gridview->contentY(), 100.);
2330 for (int i = 0; i < 5; i++)
2331 model2.addItem("Item" + QString::number(i), "");
2333 ctxt->setContextProperty("testModel", &model2);
2334 QCOMPARE(gridview->count(), 5);
2339 void tst_QSGGridView::enforceRange_rightToLeft()
2341 QSGView *canvas = createView();
2344 for (int i = 0; i < 30; i++)
2345 model.addItem("Item" + QString::number(i), "");
2347 QDeclarativeContext *ctxt = canvas->rootContext();
2348 ctxt->setContextProperty("testModel", &model);
2349 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2350 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2352 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2353 qApp->processEvents();
2354 QVERIFY(canvas->rootObject() != 0);
2356 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2357 QTRY_VERIFY(gridview != 0);
2359 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2360 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2361 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
2363 QSGItem *contentItem = gridview->contentItem();
2364 QTRY_VERIFY(contentItem != 0);
2366 // view should be positioned at the top of the range.
2367 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2369 QTRY_COMPARE(gridview->contentX(), -100.);
2370 QTRY_COMPARE(gridview->contentY(), 0.0);
2372 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
2373 QTRY_VERIFY(name != 0);
2374 QTRY_COMPARE(name->text(), model.name(0));
2375 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
2376 QTRY_VERIFY(number != 0);
2377 QTRY_COMPARE(number->text(), model.number(0));
2379 // Check currentIndex is updated when contentItem moves
2380 gridview->setContentX(-200);
2381 QTRY_COMPARE(gridview->currentIndex(), 3);
2383 gridview->setCurrentIndex(7);
2384 QTRY_COMPARE(gridview->contentX(), -300.);
2385 QTRY_COMPARE(gridview->contentY(), 0.0);
2388 for (int i = 0; i < 5; i++)
2389 model2.addItem("Item" + QString::number(i), "");
2391 ctxt->setContextProperty("testModel", &model2);
2392 QCOMPARE(gridview->count(), 5);
2397 void tst_QSGGridView::QTBUG_8456()
2399 QSGView *canvas = createView();
2401 canvas->setSource(QUrl::fromLocalFile(TESTDATA("setindex.qml")));
2402 qApp->processEvents();
2404 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2405 QTRY_VERIFY(gridview != 0);
2407 QTRY_COMPARE(gridview->currentIndex(), 0);
2412 void tst_QSGGridView::manualHighlight()
2414 QSGView *canvas = createView();
2416 QString filename(TESTDATA("manual-highlight.qml"));
2417 canvas->setSource(QUrl::fromLocalFile(filename));
2419 qApp->processEvents();
2421 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2422 QTRY_VERIFY(gridview != 0);
2424 QSGItem *contentItem = gridview->contentItem();
2425 QTRY_VERIFY(contentItem != 0);
2427 QTRY_COMPARE(gridview->currentIndex(), 0);
2428 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
2429 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2430 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2432 gridview->setCurrentIndex(2);
2434 QTRY_COMPARE(gridview->currentIndex(), 2);
2435 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
2436 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2437 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2439 gridview->positionViewAtIndex(8, QSGGridView::Contain);
2441 QTRY_COMPARE(gridview->currentIndex(), 2);
2442 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
2443 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2444 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2446 gridview->setFlow(QSGGridView::TopToBottom);
2447 QTRY_COMPARE(gridview->flow(), QSGGridView::TopToBottom);
2449 gridview->setCurrentIndex(0);
2450 QTRY_COMPARE(gridview->currentIndex(), 0);
2451 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
2452 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2453 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2459 void tst_QSGGridView::footer()
2461 QFETCH(QSGGridView::Flow, flow);
2462 QFETCH(Qt::LayoutDirection, layoutDirection);
2463 QFETCH(QPointF, initialFooterPos);
2464 QFETCH(QPointF, changedFooterPos);
2465 QFETCH(QPointF, initialContentPos);
2466 QFETCH(QPointF, changedContentPos);
2467 QFETCH(QPointF, firstDelegatePos);
2468 QFETCH(QPointF, resizeContentPos);
2470 QSGView *canvas = createView();
2474 for (int i = 0; i < 7; i++)
2475 model.addItem("Item" + QString::number(i), "");
2477 QDeclarativeContext *ctxt = canvas->rootContext();
2478 ctxt->setContextProperty("testModel", &model);
2480 canvas->setSource(QUrl::fromLocalFile(TESTDATA("footer.qml")));
2481 qApp->processEvents();
2483 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2484 QTRY_VERIFY(gridview != 0);
2485 gridview->setFlow(flow);
2486 gridview->setLayoutDirection(layoutDirection);
2488 QSGItem *contentItem = gridview->contentItem();
2489 QTRY_VERIFY(contentItem != 0);
2491 QSGText *footer = findItem<QSGText>(contentItem, "footer");
2494 QVERIFY(footer == gridview->footerItem());
2496 QCOMPARE(footer->pos(), initialFooterPos);
2497 QCOMPARE(footer->width(), 100.);
2498 QCOMPARE(footer->height(), 30.);
2499 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2501 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2503 QCOMPARE(item->pos(), firstDelegatePos);
2505 if (flow == QSGGridView::LeftToRight) {
2506 // shrink by one row
2507 model.removeItem(2);
2508 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2510 // shrink by one column
2511 model.removeItem(2);
2512 model.removeItem(3);
2513 if (layoutDirection == Qt::LeftToRight)
2514 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2516 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2522 QPointF posWhenNoItems(0, 0);
2523 if (layoutDirection == Qt::RightToLeft)
2524 posWhenNoItems.setX(flow == QSGGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2525 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2527 // if header is present, it's at a negative pos, so the footer should not move
2528 canvas->rootObject()->setProperty("showHeader", true);
2529 QVERIFY(findItem<QSGItem>(contentItem, "header") != 0);
2530 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2531 canvas->rootObject()->setProperty("showHeader", false);
2534 for (int i = 0; i < 30; i++)
2535 model.addItem("Item" + QString::number(i), "");
2537 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2538 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2540 QCOMPARE(footerItemSpy.count(), 1);
2542 footer = findItem<QSGText>(contentItem, "footer");
2544 footer = findItem<QSGText>(contentItem, "footer2");
2547 QVERIFY(footer == gridview->footerItem());
2549 QCOMPARE(footer->pos(), changedFooterPos);
2550 QCOMPARE(footer->width(), 50.);
2551 QCOMPARE(footer->height(), 20.);
2552 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2554 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2556 QCOMPARE(item->pos(), firstDelegatePos);
2558 gridview->positionViewAtEnd();
2559 footer->setHeight(10);
2560 footer->setWidth(40);
2561 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2566 void tst_QSGGridView::footer_data()
2568 QTest::addColumn<QSGGridView::Flow>("flow");
2569 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2570 QTest::addColumn<QPointF>("initialFooterPos");
2571 QTest::addColumn<QPointF>("changedFooterPos");
2572 QTest::addColumn<QPointF>("initialContentPos");
2573 QTest::addColumn<QPointF>("changedContentPos");
2574 QTest::addColumn<QPointF>("firstDelegatePos");
2575 QTest::addColumn<QPointF>("resizeContentPos");
2577 // footer1 = 100 x 30
2578 // footer2 = 50 x 20
2581 // view height = 320
2583 // footer below items, bottom left
2584 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2585 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
2586 << QPointF(0, 10 * 60) // 30 items = 10 rows
2590 << QPointF(0, 10 * 60 - 320 + 10);
2592 // footer below items, bottom right
2593 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2594 << QPointF(240 - 100, 3 * 60)
2595 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
2598 << QPointF(240 - 80, 0)
2599 << QPointF(0, 10 * 60 - 320 + 10);
2601 // footer to right of items
2602 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2603 << QPointF(2 * 80, 0) // 2 columns, cell width 80
2604 << QPointF(6 * 80, 0) // 30 items = 6 columns
2608 << QPointF(6 * 80 - 240 + 40, 0);
2610 // footer to left of items
2611 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2612 << QPointF(-(2 * 80) - 100, 0)
2613 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
2615 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
2617 << QPointF(-(6 * 80) - 40, 0);
2620 void tst_QSGGridView::header()
2622 QFETCH(QSGGridView::Flow, flow);
2623 QFETCH(Qt::LayoutDirection, layoutDirection);
2624 QFETCH(QPointF, initialHeaderPos);
2625 QFETCH(QPointF, changedHeaderPos);
2626 QFETCH(QPointF, initialContentPos);
2627 QFETCH(QPointF, changedContentPos);
2628 QFETCH(QPointF, firstDelegatePos);
2629 QFETCH(QPointF, resizeContentPos);
2632 for (int i = 0; i < 30; i++)
2633 model.addItem("Item" + QString::number(i), "");
2635 QSGView *canvas = createView();
2636 canvas->rootContext()->setContextProperty("testModel", &model);
2637 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2638 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2639 canvas->setSource(QUrl::fromLocalFile(TESTDATA("header.qml")));
2641 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2642 QTRY_VERIFY(gridview != 0);
2643 gridview->setFlow(flow);
2644 gridview->setLayoutDirection(layoutDirection);
2646 QSGItem *contentItem = gridview->contentItem();
2647 QTRY_VERIFY(contentItem != 0);
2649 QSGText *header = findItem<QSGText>(contentItem, "header");
2652 QVERIFY(header == gridview->headerItem());
2654 QCOMPARE(header->pos(), initialHeaderPos);
2655 QCOMPARE(header->width(), 100.);
2656 QCOMPARE(header->height(), 30.);
2657 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2659 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2661 QCOMPARE(item->pos(), firstDelegatePos);
2664 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
2666 for (int i = 0; i < 30; i++)
2667 model.addItem("Item" + QString::number(i), "");
2669 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
2670 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
2672 QCOMPARE(headerItemSpy.count(), 1);
2674 header = findItem<QSGText>(contentItem, "header");
2676 header = findItem<QSGText>(contentItem, "header2");
2679 QVERIFY(header == gridview->headerItem());
2681 QCOMPARE(header->pos(), changedHeaderPos);
2682 QCOMPARE(header->width(), 50.);
2683 QCOMPARE(header->height(), 20.);
2684 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2686 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2688 QCOMPARE(item->pos(), firstDelegatePos);
2690 header->setHeight(10);
2691 header->setWidth(40);
2692 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2697 // QTBUG-21207 header should become visible if view resizes from initial empty size
2699 canvas = createView();
2700 canvas->rootContext()->setContextProperty("testModel", &model);
2701 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2702 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2703 canvas->setSource(QUrl::fromLocalFile(TESTDATA("header.qml")));
2705 gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2706 QTRY_VERIFY(gridview != 0);
2707 gridview->setFlow(flow);
2708 gridview->setLayoutDirection(layoutDirection);
2710 gridview->setWidth(240);
2711 gridview->setHeight(320);
2712 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
2713 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2718 void tst_QSGGridView::header_data()
2720 QTest::addColumn<QSGGridView::Flow>("flow");
2721 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2722 QTest::addColumn<QPointF>("initialHeaderPos");
2723 QTest::addColumn<QPointF>("changedHeaderPos");
2724 QTest::addColumn<QPointF>("initialContentPos");
2725 QTest::addColumn<QPointF>("changedContentPos");
2726 QTest::addColumn<QPointF>("firstDelegatePos");
2727 QTest::addColumn<QPointF>("resizeContentPos");
2729 // header1 = 100 x 30
2730 // header2 = 50 x 20
2734 // header above items, top left
2735 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2743 // header above items, top right
2744 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2745 << QPointF(240 - 100, -30)
2746 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
2752 // header to left of items
2753 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2761 // header to right of items
2762 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2765 << QPointF(-(240 - 100), 0)
2766 << QPointF(-(240 - 50), 0)
2768 << QPointF(-(240 - 40), 0);
2771 void tst_QSGGridView::resizeViewAndRepaint()
2773 QSGView *canvas = createView();
2777 for (int i = 0; i < 40; i++)
2778 model.addItem("Item" + QString::number(i), "");
2780 QDeclarativeContext *ctxt = canvas->rootContext();
2781 ctxt->setContextProperty("testModel", &model);
2782 ctxt->setContextProperty("initialHeight", 100);
2784 canvas->setSource(QUrl::fromLocalFile(TESTDATA("resizeview.qml")));
2785 qApp->processEvents();
2787 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2788 QTRY_VERIFY(gridview != 0);
2789 QSGItem *contentItem = gridview->contentItem();
2790 QTRY_VERIFY(contentItem != 0);
2792 // item at index 10 should not be currently visible
2793 QVERIFY(!findItem<QSGItem>(contentItem, "wrapper", 10));
2795 gridview->setHeight(320);
2796 QTRY_VERIFY(findItem<QSGItem>(contentItem, "wrapper", 10));
2798 gridview->setHeight(100);
2799 QTRY_VERIFY(!findItem<QSGItem>(contentItem, "wrapper", 10));
2804 void tst_QSGGridView::indexAt()
2806 QSGView *canvas = createView();
2809 model.addItem("Fred", "12345");
2810 model.addItem("John", "2345");
2811 model.addItem("Bob", "54321");
2812 model.addItem("Billy", "22345");
2813 model.addItem("Sam", "2945");
2814 model.addItem("Ben", "04321");
2815 model.addItem("Jim", "0780");
2817 QDeclarativeContext *ctxt = canvas->rootContext();
2818 ctxt->setContextProperty("testModel", &model);
2819 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2820 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2822 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2823 qApp->processEvents();
2825 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2826 QTRY_VERIFY(gridview != 0);
2828 QSGItem *contentItem = gridview->contentItem();
2829 QTRY_VERIFY(contentItem != 0);
2831 QTRY_COMPARE(gridview->count(), model.count());
2833 QCOMPARE(gridview->indexAt(0, 0), 0);
2834 QCOMPARE(gridview->indexAt(79, 59), 0);
2835 QCOMPARE(gridview->indexAt(80, 0), 1);
2836 QCOMPARE(gridview->indexAt(0, 60), 3);
2837 QCOMPARE(gridview->indexAt(240, 0), -1);
2842 void tst_QSGGridView::onAdd()
2844 QFETCH(int, initialItemCount);
2845 QFETCH(int, itemsToAdd);
2847 const int delegateWidth = 50;
2848 const int delegateHeight = 100;
2850 QSGView *canvas = createView();
2851 canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
2853 // these initial items should not trigger GridView.onAdd
2854 for (int i=0; i<initialItemCount; i++)
2855 model.addItem("dummy value", "dummy value");
2857 QDeclarativeContext *ctxt = canvas->rootContext();
2858 ctxt->setContextProperty("testModel", &model);
2859 ctxt->setContextProperty("delegateWidth", delegateWidth);
2860 ctxt->setContextProperty("delegateHeight", delegateHeight);
2861 canvas->setSource(QUrl::fromLocalFile(TESTDATA("attachedSignals.qml")));
2863 QObject *object = canvas->rootObject();
2864 object->setProperty("width", canvas->width());
2865 object->setProperty("height", canvas->height());
2866 qApp->processEvents();
2868 QList<QPair<QString, QString> > items;
2869 for (int i=0; i<itemsToAdd; i++)
2870 items << qMakePair(QString("value %1").arg(i), QString::number(i));
2871 model.addItems(items);
2873 QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
2874 qApp->processEvents();
2876 QVariantList result = object->property("addedDelegates").toList();
2877 QTRY_COMPARE(result.count(), items.count());
2878 for (int i=0; i<items.count(); i++)
2879 QCOMPARE(result[i].toString(), items[i].first);
2884 void tst_QSGGridView::onAdd_data()
2886 QTest::addColumn<int>("initialItemCount");
2887 QTest::addColumn<int>("itemsToAdd");
2889 QTest::newRow("0, add 1") << 0 << 1;
2890 QTest::newRow("0, add 2") << 0 << 2;
2891 QTest::newRow("0, add 10") << 0 << 10;
2893 QTest::newRow("1, add 1") << 1 << 1;
2894 QTest::newRow("1, add 2") << 1 << 2;
2895 QTest::newRow("1, add 10") << 1 << 10;
2897 QTest::newRow("5, add 1") << 5 << 1;
2898 QTest::newRow("5, add 2") << 5 << 2;
2899 QTest::newRow("5, add 10") << 5 << 10;
2902 void tst_QSGGridView::onRemove()
2904 QFETCH(int, initialItemCount);
2905 QFETCH(int, indexToRemove);
2906 QFETCH(int, removeCount);
2908 const int delegateWidth = 50;
2909 const int delegateHeight = 100;
2911 for (int i=0; i<initialItemCount; i++)
2912 model.addItem(QString("value %1").arg(i), "dummy value");
2914 QSGView *canvas = createView();
2915 QDeclarativeContext *ctxt = canvas->rootContext();
2916 ctxt->setContextProperty("testModel", &model);
2917 ctxt->setContextProperty("delegateWidth", delegateWidth);
2918 ctxt->setContextProperty("delegateHeight", delegateHeight);
2919 canvas->setSource(QUrl::fromLocalFile(TESTDATA("attachedSignals.qml")));
2920 QObject *object = canvas->rootObject();
2922 model.removeItems(indexToRemove, removeCount);
2923 QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
2924 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2929 void tst_QSGGridView::onRemove_data()
2931 QTest::addColumn<int>("initialItemCount");
2932 QTest::addColumn<int>("indexToRemove");
2933 QTest::addColumn<int>("removeCount");
2935 QTest::newRow("remove first") << 1 << 0 << 1;
2936 QTest::newRow("two items, remove first") << 2 << 0 << 1;
2937 QTest::newRow("two items, remove last") << 2 << 1 << 1;
2938 QTest::newRow("two items, remove all") << 2 << 0 << 2;
2940 QTest::newRow("four items, remove first") << 4 << 0 << 1;
2941 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2942 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2943 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2944 QTest::newRow("four items, remove last") << 4 << 3 << 1;
2945 QTest::newRow("four items, remove all") << 4 << 0 << 4;
2947 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2948 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2949 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2952 void tst_QSGGridView::testQtQuick11Attributes()
2954 QFETCH(QString, code);
2955 QFETCH(QString, warning);
2956 QFETCH(QString, error);
2958 QDeclarativeEngine engine;
2961 QDeclarativeComponent valid(&engine);
2962 valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
2963 obj = valid.create();
2965 QVERIFY(valid.errorString().isEmpty());
2968 QDeclarativeComponent invalid(&engine);
2969 invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
2970 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2971 obj = invalid.create();
2972 QCOMPARE(invalid.errorString(), error);
2976 void tst_QSGGridView::testQtQuick11Attributes_data()
2978 QTest::addColumn<QString>("code");
2979 QTest::addColumn<QString>("warning");
2980 QTest::addColumn<QString>("error");
2982 QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2983 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2986 QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2987 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2991 void tst_QSGGridView::columnCount()
2994 canvas.setSource(QUrl::fromLocalFile(TESTDATA("gridview4.qml")));
2996 canvas.requestActivateWindow();
2997 QTest::qWaitForWindowShown(&canvas);
2999 QSGGridView *view = qobject_cast<QSGGridView*>(canvas.rootObject());
3001 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3002 QCOMPARE(view->cellHeight(), qreal(100));
3004 QList<QSGItem*> items = findItems<QSGItem>(view, "delegate");
3005 QCOMPARE(items.size(), 18);
3006 QCOMPARE(items.at(8)->y(), qreal(0));
3007 QCOMPARE(items.at(9)->y(), qreal(100));
3010 void tst_QSGGridView::margins()
3013 QSGView *canvas = createView();
3017 for (int i = 0; i < 40; i++)
3018 model.addItem("Item" + QString::number(i), "");
3020 QDeclarativeContext *ctxt = canvas->rootContext();
3021 ctxt->setContextProperty("testModel", &model);
3022 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3024 canvas->setSource(QUrl::fromLocalFile(TESTDATA("margins.qml")));
3025 qApp->processEvents();
3027 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
3028 QTRY_VERIFY(gridview != 0);
3030 QSGItem *contentItem = gridview->contentItem();
3031 QTRY_VERIFY(contentItem != 0);
3033 QCOMPARE(gridview->contentX(), -30.);
3034 QCOMPARE(gridview->xOrigin(), 0.);
3037 gridview->positionViewAtEnd();
3038 qreal pos = gridview->contentX();
3039 gridview->setContentX(pos + 80);
3040 gridview->returnToBounds();
3041 QTRY_COMPARE(gridview->contentX(), pos + 50);
3043 // remove item before visible and check that left margin is maintained
3044 // and xOrigin is updated
3045 gridview->setContentX(200);
3046 model.removeItems(0, 4);
3048 gridview->setContentX(-50);
3049 gridview->returnToBounds();
3050 QCOMPARE(gridview->xOrigin(), 100.);
3051 QTRY_COMPARE(gridview->contentX(), 70.);
3053 // reduce left margin
3054 gridview->setLeftMargin(20);
3055 QCOMPARE(gridview->xOrigin(), 100.);
3056 QTRY_COMPARE(gridview->contentX(), 80.);
3059 gridview->positionViewAtEnd();
3060 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3061 pos = gridview->contentX();
3062 gridview->setContentX(pos + 80);
3063 gridview->returnToBounds();
3064 QTRY_COMPARE(gridview->contentX(), pos + 50);
3066 // reduce right margin
3067 pos = gridview->contentX();
3068 gridview->setRightMargin(40);
3069 QCOMPARE(gridview->xOrigin(), 0.);
3070 QTRY_COMPARE(gridview->contentX(), pos-10);
3076 QSGView *canvas = createView();
3080 for (int i = 0; i < 40; i++)
3081 model.addItem("Item" + QString::number(i), "");
3083 QDeclarativeContext *ctxt = canvas->rootContext();
3084 ctxt->setContextProperty("testModel", &model);
3085 ctxt->setContextProperty("testRightToLeft", QVariant(true));
3087 canvas->setSource(QUrl::fromLocalFile(TESTDATA("margins.qml")));
3088 qApp->processEvents();
3090 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
3091 QTRY_VERIFY(gridview != 0);
3093 QSGItem *contentItem = gridview->contentItem();
3094 QTRY_VERIFY(contentItem != 0);
3096 QCOMPARE(gridview->contentX(), -240+30.);
3097 QCOMPARE(gridview->xOrigin(), 0.);
3100 gridview->positionViewAtEnd();
3101 qreal pos = gridview->contentX();
3102 gridview->setContentX(pos - 80);
3103 gridview->returnToBounds();
3104 QTRY_COMPARE(gridview->contentX(), pos - 50);
3106 // remove item before visible and check that left margin is maintained
3107 // and xOrigin is updated
3108 gridview->setContentX(-400);
3109 model.removeItems(0, 4);
3111 gridview->setContentX(-240+50);
3112 gridview->returnToBounds();
3113 QCOMPARE(gridview->xOrigin(), -100.);
3114 QTRY_COMPARE(gridview->contentX(), -240-70.);
3116 // reduce left margin (i.e. right side due to RTL)
3117 pos = gridview->contentX();
3118 gridview->setLeftMargin(20);
3119 QCOMPARE(gridview->xOrigin(), -100.);
3120 QTRY_COMPARE(gridview->contentX(), -240-80.);
3123 gridview->positionViewAtEnd();
3124 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3125 pos = gridview->contentX();
3126 gridview->setContentX(pos - 80);
3127 gridview->returnToBounds();
3128 QTRY_COMPARE(gridview->contentX(), pos - 50);
3130 // reduce right margin (i.e. left side due to RTL)
3131 pos = gridview->contentX();
3132 gridview->setRightMargin(40);
3133 QCOMPARE(gridview->xOrigin(), 0.);
3134 QTRY_COMPARE(gridview->contentX(), pos+10);
3140 void tst_QSGGridView::creationContext()
3143 canvas.setGeometry(0,0,240,320);
3144 canvas.setSource(QUrl::fromLocalFile(TESTDATA("creationContext.qml")));
3145 qApp->processEvents();
3147 QSGItem *rootItem = qobject_cast<QSGItem *>(canvas.rootObject());
3149 QVERIFY(rootItem->property("count").toInt() > 0);
3152 QVERIFY(item = rootItem->findChild<QSGItem *>("listItem"));
3153 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3154 QVERIFY(item = rootItem->findChild<QSGItem *>("header"));
3155 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3156 QVERIFY(item = rootItem->findChild<QSGItem *>("footer"));
3157 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3160 void tst_QSGGridView::snapToRow_data()
3162 QTest::addColumn<QSGGridView::Flow>("flow");
3163 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3164 QTest::addColumn<int>("highlightRangeMode");
3165 QTest::addColumn<QPoint>("flickStart");
3166 QTest::addColumn<QPoint>("flickEnd");
3167 QTest::addColumn<qreal>("snapAlignment");
3168 QTest::addColumn<qreal>("endExtent");
3169 QTest::addColumn<qreal>("startExtent");
3171 QTest::newRow("vertical, left to right") << QSGGridView::LeftToRight << Qt::LeftToRight << int(QSGItemView::NoHighlightRange)
3172 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3174 QTest::newRow("horizontal, left to right") << QSGGridView::TopToBottom << Qt::LeftToRight << int(QSGItemView::NoHighlightRange)
3175 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3177 QTest::newRow("horizontal, right to left") << QSGGridView::TopToBottom << Qt::RightToLeft << int(QSGItemView::NoHighlightRange)
3178 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 << -240.0;
3180 QTest::newRow("vertical, left to right, enforce range") << QSGGridView::LeftToRight << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange)
3181 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3183 QTest::newRow("horizontal, left to right, enforce range") << QSGGridView::TopToBottom << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange)
3184 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3186 QTest::newRow("horizontal, right to left, enforce range") << QSGGridView::TopToBottom << Qt::RightToLeft << int(QSGItemView::StrictlyEnforceRange)
3187 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0;
3190 void tst_QSGGridView::snapToRow()
3192 QFETCH(QSGGridView::Flow, flow);
3193 QFETCH(Qt::LayoutDirection, layoutDirection);
3194 QFETCH(int, highlightRangeMode);
3195 QFETCH(QPoint, flickStart);
3196 QFETCH(QPoint, flickEnd);
3197 QFETCH(qreal, snapAlignment);
3198 QFETCH(qreal, endExtent);
3199 QFETCH(qreal, startExtent);
3201 QSGView *canvas = createView();
3203 canvas->setSource(QUrl::fromLocalFile(TESTDATA("snapToRow.qml")));
3205 qApp->processEvents();
3207 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
3208 QTRY_VERIFY(gridview != 0);
3210 gridview->setFlow(flow);
3211 gridview->setLayoutDirection(layoutDirection);
3212 gridview->setHighlightRangeMode(QSGItemView::HighlightRangeMode(highlightRangeMode));
3214 QSGItem *contentItem = gridview->contentItem();
3215 QTRY_VERIFY(contentItem != 0);
3217 // confirm that a flick hits an item boundary
3218 flick(canvas, flickStart, flickEnd, 180);
3219 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3220 if (flow == QSGGridView::LeftToRight)
3221 QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
3223 QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
3227 flick(canvas, flickStart, flickEnd, 180);
3228 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3229 } while (flow == QSGGridView::LeftToRight
3230 ? !gridview->isAtYEnd()
3231 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3233 if (flow == QSGGridView::LeftToRight)
3234 QCOMPARE(gridview->contentY(), endExtent);
3236 QCOMPARE(gridview->contentX(), endExtent);
3240 flick(canvas, flickEnd, flickStart, 180);
3241 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3242 } while (flow == QSGGridView::LeftToRight
3243 ? !gridview->isAtYBeginning()
3244 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3246 if (flow == QSGGridView::LeftToRight)
3247 QCOMPARE(gridview->contentY(), startExtent);
3249 QCOMPARE(gridview->contentX(), startExtent);
3255 QSGView *tst_QSGGridView::createView()
3257 QSGView *canvas = new QSGView(0);
3258 canvas->setGeometry(0,0,240,320);
3263 void tst_QSGGridView::flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration)
3265 const int pointCount = 5;
3266 QPoint diff = to - from;
3268 // send press, five equally spaced moves, and release.
3269 QTest::mousePress(canvas, Qt::LeftButton, 0, from);
3271 for (int i = 0; i < pointCount; ++i) {
3272 QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
3273 QApplication::sendEvent(canvas, &mv);
3274 QTest::qWait(duration/pointCount);
3275 QCoreApplication::processEvents();
3278 QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
3282 Find an item with the specified objectName. If index is supplied then the
3283 item must also evaluate the {index} expression equal to index
3285 template<typename T>
3286 T *tst_QSGGridView::findItem(QSGItem *parent, const QString &objectName, int index)
3288 const QMetaObject &mo = T::staticMetaObject;
3289 //qDebug() << parent->childItems().count() << "children";
3290 for (int i = 0; i < parent->childItems().count(); ++i) {
3291 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3294 //qDebug() << "try" << item;
3295 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
3297 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3299 if (context->contextProperty("index").toInt() == index) {
3300 return static_cast<T*>(item);
3304 return static_cast<T*>(item);
3307 item = findItem<T>(item, objectName, index);
3309 return static_cast<T*>(item);
3315 template<typename T>
3316 QList<T*> tst_QSGGridView::findItems(QSGItem *parent, const QString &objectName)
3319 const QMetaObject &mo = T::staticMetaObject;
3320 //qDebug() << parent->childItems().count() << "children";
3321 for (int i = 0; i < parent->childItems().count(); ++i) {
3322 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3325 //qDebug() << "try" << item;
3326 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
3327 items.append(static_cast<T*>(item));
3328 //qDebug() << " found:" << item;
3330 items += findItems<T>(item, objectName);
3336 void tst_QSGGridView::dumpTree(QSGItem *parent, int depth)
3338 static QString padding(" ");
3339 for (int i = 0; i < parent->childItems().count(); ++i) {
3340 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3343 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3344 qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
3345 dumpTree(item, depth+1);
3350 QTEST_MAIN(tst_QSGGridView)
3352 #include "tst_qsggridview.moc"