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 "../../../shared/util.h"
56 #include <QtGui/qguiapplication.h>
58 Q_DECLARE_METATYPE(Qt::LayoutDirection)
59 Q_DECLARE_METATYPE(QSGGridView::Flow)
61 class tst_QSGGridView : public QObject
69 void cleanupTestCase();
74 void inserted_more_data();
79 void multipleChanges();
80 void multipleChanges_data();
81 void swapWithFirstItem();
84 void noCurrentIndex();
87 void propertyChanges();
88 void componentChanges();
90 void positionViewAtIndex();
91 void positionViewAtIndex_rightToLeft();
96 void enforceRange_rightToLeft();
98 void manualHighlight();
103 void resizeViewAndRepaint();
108 void onRemove_data();
109 void testQtQuick11Attributes();
110 void testQtQuick11Attributes_data();
113 void creationContext();
114 void snapToRow_data();
118 QSGView *createView();
119 void flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration);
121 T *findItem(QSGItem *parent, const QString &id, int index=-1);
123 QList<T*> findItems(QSGItem *parent, const QString &objectName);
124 void dumpTree(QSGItem *parent, int depth = 0);
128 void tst_qsggridview_move(int from, int to, int n, T *items)
131 items->move(from, to);
135 typename T::ConstIterator it=items->begin(); it += from+n;
136 for (; i<to-from; ++i,++it)
137 replaced.append(*it);
139 it=items->begin(); it += from;
140 for (; i<n; ++i,++it)
141 replaced.append(*it);
142 typename T::ConstIterator f=replaced.begin();
143 typename T::Iterator t=items->begin(); t += from;
144 for (; f != replaced.end(); ++f, ++t)
149 void tst_QSGGridView::initTestCase()
153 void tst_QSGGridView::cleanupTestCase()
159 class TestModel : public QAbstractListModel
162 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
164 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
165 QHash<int, QByteArray> roles;
166 roles[Name] = "name";
167 roles[Number] = "number";
171 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
172 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
175 rv = list.at(index.row()).first;
176 else if (role == Number)
177 rv = list.at(index.row()).second;
182 int count() const { return rowCount(); }
183 QString name(int index) const { return list.at(index).first; }
184 QString number(int index) const { return list.at(index).second; }
186 void addItem(const QString &name, const QString &number) {
187 emit beginInsertRows(QModelIndex(), list.count(), list.count());
188 list.append(QPair<QString,QString>(name, number));
189 emit endInsertRows();
192 void addItems(const QList<QPair<QString, QString> > &items) {
193 emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
194 for (int i=0; i<items.count(); i++)
195 list.append(QPair<QString,QString>(items[i].first, items[i].second));
196 emit endInsertRows();
199 void insertItem(int index, const QString &name, const QString &number) {
200 emit beginInsertRows(QModelIndex(), index, index);
201 list.insert(index, QPair<QString,QString>(name, number));
202 emit endInsertRows();
205 void insertItems(int index, const QList<QPair<QString, QString> > &items) {
206 emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
207 for (int i=0; i<items.count(); i++)
208 list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
209 emit endInsertRows();
212 void removeItem(int index) {
213 emit beginRemoveRows(QModelIndex(), index, index);
214 list.removeAt(index);
215 emit endRemoveRows();
218 void removeItems(int index, int count) {
219 emit beginRemoveRows(QModelIndex(), index, index+count-1);
221 list.removeAt(index);
222 emit endRemoveRows();
225 void moveItem(int from, int to) {
226 emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
231 void moveItems(int from, int to, int count) {
232 emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
233 tst_qsggridview_move(from, to, count, &list);
237 void modifyItem(int idx, const QString &name, const QString &number) {
238 list[idx] = QPair<QString,QString>(name, number);
239 emit dataChanged(index(idx,0), index(idx,0));
243 int count = list.count();
244 emit beginRemoveRows(QModelIndex(), 0, count-1);
246 emit endRemoveRows();
251 QList<QPair<QString,QString> > list;
254 tst_QSGGridView::tst_QSGGridView()
258 void tst_QSGGridView::items()
260 QSGView *canvas = createView();
263 model.addItem("Fred", "12345");
264 model.addItem("John", "2345");
265 model.addItem("Bob", "54321");
266 model.addItem("Billy", "22345");
267 model.addItem("Sam", "2945");
268 model.addItem("Ben", "04321");
269 model.addItem("Jim", "0780");
271 QDeclarativeContext *ctxt = canvas->rootContext();
272 ctxt->setContextProperty("testModel", &model);
273 ctxt->setContextProperty("testRightToLeft", QVariant(false));
274 ctxt->setContextProperty("testTopToBottom", QVariant(false));
276 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
277 qApp->processEvents();
279 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
280 QTRY_VERIFY(gridview != 0);
282 QSGItem *contentItem = gridview->contentItem();
283 QTRY_VERIFY(contentItem != 0);
285 QTRY_COMPARE(gridview->count(), model.count());
286 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
287 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
289 for (int i = 0; i < model.count(); ++i) {
290 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
291 QTRY_VERIFY(name != 0);
292 QTRY_COMPARE(name->text(), model.name(i));
293 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
294 QTRY_VERIFY(number != 0);
295 QTRY_COMPARE(number->text(), model.number(i));
298 // set an empty model and confirm that items are destroyed
300 ctxt->setContextProperty("testModel", &model2);
302 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
303 QTRY_VERIFY(itemCount == 0);
308 void tst_QSGGridView::changed()
310 QSGView *canvas = createView();
313 model.addItem("Fred", "12345");
314 model.addItem("John", "2345");
315 model.addItem("Bob", "54321");
316 model.addItem("Billy", "22345");
317 model.addItem("Sam", "2945");
318 model.addItem("Ben", "04321");
319 model.addItem("Jim", "0780");
321 QDeclarativeContext *ctxt = canvas->rootContext();
322 ctxt->setContextProperty("testModel", &model);
323 ctxt->setContextProperty("testRightToLeft", QVariant(false));
324 ctxt->setContextProperty("testTopToBottom", QVariant(false));
326 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
327 qApp->processEvents();
329 QSGFlickable *gridview = findItem<QSGFlickable>(canvas->rootObject(), "grid");
330 QTRY_VERIFY(gridview != 0);
332 QSGItem *contentItem = gridview->contentItem();
333 QTRY_VERIFY(contentItem != 0);
335 model.modifyItem(1, "Will", "9876");
336 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
337 QTRY_VERIFY(name != 0);
338 QTRY_COMPARE(name->text(), model.name(1));
339 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
340 QTRY_VERIFY(number != 0);
341 QTRY_COMPARE(number->text(), model.number(1));
346 void tst_QSGGridView::inserted()
348 QSGView *canvas = createView();
352 model.addItem("Fred", "12345");
353 model.addItem("John", "2345");
354 model.addItem("Bob", "54321");
356 QDeclarativeContext *ctxt = canvas->rootContext();
357 ctxt->setContextProperty("testModel", &model);
358 ctxt->setContextProperty("testRightToLeft", QVariant(false));
359 ctxt->setContextProperty("testTopToBottom", QVariant(false));
361 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
362 qApp->processEvents();
364 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
365 QTRY_VERIFY(gridview != 0);
367 QSGItem *contentItem = gridview->contentItem();
368 QTRY_VERIFY(contentItem != 0);
370 model.insertItem(1, "Will", "9876");
372 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
373 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
375 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
376 QTRY_VERIFY(name != 0);
377 QTRY_COMPARE(name->text(), model.name(1));
378 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
379 QTRY_VERIFY(number != 0);
380 QTRY_COMPARE(number->text(), model.number(1));
382 // Checks that onAdd is called
383 int added = canvas->rootObject()->property("added").toInt();
384 QTRY_COMPARE(added, 1);
386 // Confirm items positioned correctly
387 for (int i = 0; i < model.count(); ++i) {
388 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
389 QTRY_COMPARE(item->x(), (i%3)*80.0);
390 QTRY_COMPARE(item->y(), (i/3)*60.0);
393 model.insertItem(0, "Foo", "1111"); // zero index, and current item
395 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
397 name = findItem<QSGText>(contentItem, "textName", 0);
398 QTRY_VERIFY(name != 0);
399 QTRY_COMPARE(name->text(), model.name(0));
400 number = findItem<QSGText>(contentItem, "textNumber", 0);
401 QTRY_VERIFY(number != 0);
402 QTRY_COMPARE(number->text(), model.number(0));
404 QTRY_COMPARE(gridview->currentIndex(), 1);
406 // Confirm items positioned correctly
407 for (int i = 0; i < model.count(); ++i) {
408 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
409 QTRY_VERIFY(item->x() == (i%3)*80);
410 QTRY_VERIFY(item->y() == (i/3)*60);
413 for (int i = model.count(); i < 30; ++i)
414 model.insertItem(i, "Hello", QString::number(i));
416 gridview->setContentY(120);
418 // Insert item outside visible area
419 model.insertItem(1, "Hello", "1324");
421 QTRY_VERIFY(gridview->contentY() == 120);
426 void tst_QSGGridView::inserted_more()
428 QFETCH(qreal, contentY);
429 QFETCH(int, insertIndex);
430 QFETCH(int, insertCount);
431 QFETCH(qreal, itemsOffsetAfterMove);
435 QSGView *canvas = createView();
439 for (int i = 0; i < 30; i++)
440 model.addItem("Item" + QString::number(i), "");
442 QDeclarativeContext *ctxt = canvas->rootContext();
443 ctxt->setContextProperty("testModel", &model);
444 ctxt->setContextProperty("testRightToLeft", QVariant(false));
445 ctxt->setContextProperty("testTopToBottom", QVariant(false));
447 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
448 qApp->processEvents();
450 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
451 QTRY_VERIFY(gridview != 0);
452 QSGItem *contentItem = gridview->contentItem();
453 QTRY_VERIFY(contentItem != 0);
455 gridview->setContentY(contentY);
457 QList<QPair<QString, QString> > newData;
458 for (int i=0; i<insertCount; i++)
459 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
460 model.insertItems(insertIndex, newData);
461 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
463 // check visibleItems.first() is in correct position
464 QSGItem *item0 = findItem<QSGItem>(contentItem, "wrapper", 0);
466 QCOMPARE(item0->y(), itemsOffsetAfterMove);
468 QList<QSGItem*> items = findItems<QSGItem>(contentItem, "wrapper");
469 int firstVisibleIndex = -1;
470 for (int i=0; i<items.count(); i++) {
471 if (items[i]->y() >= contentY) {
472 QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
473 firstVisibleIndex = e.evaluate().toInt();
477 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
479 // Confirm items positioned correctly and indexes correct
480 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
481 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
482 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
483 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
485 QCOMPARE(item->x(), (i%3)*80.0);
486 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
488 name = findItem<QSGText>(contentItem, "textName", i);
490 QCOMPARE(name->text(), model.name(i));
491 number = findItem<QSGText>(contentItem, "textNumber", i);
492 QVERIFY(number != 0);
493 QCOMPARE(number->text(), model.number(i));
499 void tst_QSGGridView::inserted_more_data()
501 QTest::addColumn<qreal>("contentY");
502 QTest::addColumn<int>("insertIndex");
503 QTest::addColumn<int>("insertCount");
504 QTest::addColumn<qreal>("itemsOffsetAfterMove");
506 QTest::newRow("add 1, before visible items")
507 << 120.0 // show 6-23
509 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
510 // new 1st visible item is at 0
512 QTest::newRow("add 2, before visible items")
513 << 120.0 // show 6-23
515 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
517 QTest::newRow("add 3, before visible items")
518 << 120.0 // show 6-23
520 << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
522 QTest::newRow("add 5, before visible items")
523 << 120.0 // show 6-23
525 << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
526 // grid is rearranged and first visible moves forward within its row
528 QTest::newRow("add 6, before visible items")
529 << 120.0 // show 6-23
531 << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
535 QTest::newRow("add 1, at start of visible, content at start")
540 QTest::newRow("add multiple, at start of visible, content at start")
545 QTest::newRow("add 1, at start of visible, content not at start")
546 << 120.0 // show 6-23
550 QTest::newRow("add multiple, at start of visible, content not at start")
551 << 120.0 // show 6-23
556 QTest::newRow("add 1, at end of visible, content at start")
561 QTest::newRow("add 1, at end of visible, content at start")
566 QTest::newRow("add 1, at end of visible, content not at start")
567 << 120.0 // show 6-23
571 QTest::newRow("add multiple, at end of visible, content not at start")
572 << 120.0 // show 6-23
577 QTest::newRow("add 1, after visible, content at start")
582 QTest::newRow("add 1, after visible, content at start")
587 QTest::newRow("add 1, after visible, content not at start")
588 << 120.0 // show 6-23
592 QTest::newRow("add multiple, after visible, content not at start")
593 << 120.0 // show 6-23
598 void tst_QSGGridView::removed()
600 QSGView *canvas = createView();
604 for (int i = 0; i < 40; i++)
605 model.addItem("Item" + QString::number(i), "");
607 QDeclarativeContext *ctxt = canvas->rootContext();
608 ctxt->setContextProperty("testModel", &model);
609 ctxt->setContextProperty("testRightToLeft", QVariant(false));
610 ctxt->setContextProperty("testTopToBottom", QVariant(false));
612 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
613 qApp->processEvents();
615 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
616 QTRY_VERIFY(gridview != 0);
618 QSGItem *contentItem = gridview->contentItem();
619 QTRY_VERIFY(contentItem != 0);
622 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
624 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
625 QTRY_VERIFY(name != 0);
626 QTRY_COMPARE(name->text(), model.name(1));
627 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
628 QTRY_VERIFY(number != 0);
629 QTRY_COMPARE(number->text(), model.number(1));
632 // Checks that onRemove is called
633 QString removed = canvas->rootObject()->property("removed").toString();
634 QTRY_COMPARE(removed, QString("Item1"));
636 // Confirm items positioned correctly
637 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
638 for (int i = 0; i < model.count() && i < itemCount; ++i) {
639 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
640 if (!item) qWarning() << "Item" << i << "not found";
641 QTRY_VERIFY(item->x() == (i%3)*80);
642 QTRY_VERIFY(item->y() == (i/3)*60);
645 // Remove first item (which is the current item);
647 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
649 name = findItem<QSGText>(contentItem, "textName", 0);
650 QTRY_VERIFY(name != 0);
651 QTRY_COMPARE(name->text(), model.name(0));
652 number = findItem<QSGText>(contentItem, "textNumber", 0);
653 QTRY_VERIFY(number != 0);
654 QTRY_COMPARE(number->text(), model.number(0));
657 // Confirm items positioned correctly
658 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
659 for (int i = 0; i < model.count() && i < itemCount; ++i) {
660 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
661 if (!item) qWarning() << "Item" << i << "not found";
662 QTRY_VERIFY(item->x() == (i%3)*80);
663 QTRY_VERIFY(item->y() == (i/3)*60);
666 // Remove items not visible
667 model.removeItem(25);
668 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
670 // Confirm items positioned correctly
671 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
672 for (int i = 0; i < model.count() && i < itemCount; ++i) {
673 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
674 if (!item) qWarning() << "Item" << i << "not found";
675 QTRY_VERIFY(item->x() == (i%3)*80);
676 QTRY_VERIFY(item->y() == (i/3)*60);
679 // Remove items before visible
680 gridview->setContentY(120);
681 gridview->setCurrentIndex(10);
683 // Setting currentIndex above shouldn't cause view to scroll
684 QTRY_COMPARE(gridview->contentY(), 120.0);
687 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
689 // Confirm items positioned correctly
690 for (int i = 6; i < 18; ++i) {
691 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
692 if (!item) qWarning() << "Item" << i << "not found";
693 QTRY_VERIFY(item->x() == (i%3)*80);
694 QTRY_VERIFY(item->y() == (i/3)*60);
697 // Remove currentIndex
698 QSGItem *oldCurrent = gridview->currentItem();
700 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
702 QTRY_COMPARE(gridview->currentIndex(), 9);
703 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
705 gridview->setContentY(0);
706 // let transitions settle.
709 // Confirm items positioned correctly
710 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
711 for (int i = 0; i < model.count() && i < itemCount; ++i) {
712 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
713 QTRY_VERIFY(item->x() == (i%3)*80);
714 QTRY_VERIFY(item->y() == (i/3)*60);
717 // remove item outside current view.
718 gridview->setCurrentIndex(32);
719 gridview->setContentY(240);
721 model.removeItem(30);
722 QTRY_VERIFY(gridview->currentIndex() == 31);
724 // remove current item beyond visible items.
725 gridview->setCurrentIndex(20);
726 gridview->setContentY(0);
727 model.removeItem(20);
729 QTRY_COMPARE(gridview->currentIndex(), 20);
730 QTRY_VERIFY(gridview->currentItem() != 0);
732 // remove item before current, but visible
733 gridview->setCurrentIndex(8);
734 gridview->setContentY(240);
735 oldCurrent = gridview->currentItem();
738 QTRY_COMPARE(gridview->currentIndex(), 7);
739 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
744 void tst_QSGGridView::clear()
746 QSGView *canvas = createView();
749 for (int i = 0; i < 30; i++)
750 model.addItem("Item" + QString::number(i), "");
752 QDeclarativeContext *ctxt = canvas->rootContext();
753 ctxt->setContextProperty("testModel", &model);
754 ctxt->setContextProperty("testRightToLeft", QVariant(false));
755 ctxt->setContextProperty("testTopToBottom", QVariant(false));
757 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
758 qApp->processEvents();
760 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
761 QVERIFY(gridview != 0);
763 QSGItem *contentItem = gridview->contentItem();
764 QVERIFY(contentItem != 0);
768 QVERIFY(gridview->count() == 0);
769 QVERIFY(gridview->currentItem() == 0);
770 QVERIFY(gridview->contentY() == 0);
771 QVERIFY(gridview->currentIndex() == -1);
773 // confirm sanity when adding an item to cleared list
774 model.addItem("New", "1");
775 QTRY_COMPARE(gridview->count(), 1);
776 QVERIFY(gridview->currentItem() != 0);
777 QVERIFY(gridview->currentIndex() == 0);
782 void tst_QSGGridView::moved()
784 QFETCH(qreal, contentY);
788 QFETCH(qreal, itemsOffsetAfterMove);
792 QSGView *canvas = createView();
796 for (int i = 0; i < 30; i++)
797 model.addItem("Item" + QString::number(i), "");
799 QDeclarativeContext *ctxt = canvas->rootContext();
800 ctxt->setContextProperty("testModel", &model);
801 ctxt->setContextProperty("testRightToLeft", QVariant(false));
802 ctxt->setContextProperty("testTopToBottom", QVariant(false));
804 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
805 qApp->processEvents();
807 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
808 QTRY_VERIFY(gridview != 0);
810 QSGItem *contentItem = gridview->contentItem();
811 QTRY_VERIFY(contentItem != 0);
813 QSGItem *currentItem = gridview->currentItem();
814 QTRY_VERIFY(currentItem != 0);
816 gridview->setContentY(contentY);
817 model.moveItems(from, to, count);
819 // wait for items to move
822 // Confirm items positioned correctly and indexes correct
823 int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
824 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
825 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
826 if (i >= firstVisibleIndex + 18) // index has moved out of view
828 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
829 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
831 QTRY_COMPARE(item->x(), (i%3)*80.0);
832 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
834 name = findItem<QSGText>(contentItem, "textName", i);
836 QTRY_COMPARE(name->text(), model.name(i));
837 number = findItem<QSGText>(contentItem, "textNumber", i);
838 QVERIFY(number != 0);
839 QTRY_COMPARE(number->text(), model.number(i));
841 // current index should have been updated
842 if (item == currentItem)
843 QTRY_COMPARE(gridview->currentIndex(), i);
849 void tst_QSGGridView::moved_data()
851 QTest::addColumn<qreal>("contentY");
852 QTest::addColumn<int>("from");
853 QTest::addColumn<int>("to");
854 QTest::addColumn<int>("count");
855 QTest::addColumn<qreal>("itemsOffsetAfterMove");
857 // model starts with 30 items, each 80x60, in area 240x320
858 // 18 items should be visible at a time
860 QTest::newRow("move 1 forwards, within visible items")
865 QTest::newRow("move 1 forwards, from non-visible -> visible")
866 << 120.0 // show 6-23
868 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
870 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
871 << 120.0 // // show 6-23
873 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
875 QTest::newRow("move 1 forwards, from visible -> non-visible")
880 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
886 QTest::newRow("move 1 backwards, within visible items")
891 QTest::newRow("move 1 backwards, within visible items (to first index)")
896 QTest::newRow("move 1 backwards, from non-visible -> visible")
901 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
906 QTest::newRow("move 1 backwards, from visible -> non-visible")
907 << 120.0 // show 6-23
909 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
911 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
912 << 120.0 // show 6-23
914 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
917 QTest::newRow("move multiple forwards, within visible items")
922 QTest::newRow("move multiple forwards, before visible items")
923 << 120.0 // show 6-23
924 << 3 << 4 << 3 // 3, 4, 5 move to after 6
925 << 60.0; // row of 3,4,5 has moved down
927 QTest::newRow("move multiple forwards, from non-visible -> visible")
928 << 120.0 // show 6-23
930 << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
932 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
933 << 120.0 // show 6-23
935 << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
937 QTest::newRow("move multiple forwards, from visible -> non-visible")
942 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
948 QTest::newRow("move multiple backwards, within visible items")
953 QTest::newRow("move multiple backwards, from non-visible -> visible")
958 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
963 QTest::newRow("move multiple backwards, from visible -> non-visible")
964 << 120.0 // show 6-23
966 << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
968 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
969 << 120.0 // show 6-23
971 << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
975 enum { Inserted, Removed, Moved, SetCurrent } type;
980 static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
981 static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
982 static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
983 static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
985 Q_DECLARE_METATYPE(QList<ListChange>)
987 void tst_QSGGridView::multipleChanges()
989 QFETCH(int, startCount);
990 QFETCH(QList<ListChange>, changes);
991 QFETCH(int, newCount);
992 QFETCH(int, newCurrentIndex);
994 QSGView *canvas = createView();
998 for (int i = 0; i < startCount; i++)
999 model.addItem("Item" + QString::number(i), "");
1001 QDeclarativeContext *ctxt = canvas->rootContext();
1002 ctxt->setContextProperty("testModel", &model);
1003 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1004 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1006 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1007 qApp->processEvents();
1009 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1010 QTRY_VERIFY(gridview != 0);
1012 for (int i=0; i<changes.count(); i++) {
1013 switch (changes[i].type) {
1014 case ListChange::Inserted:
1016 QList<QPair<QString, QString> > items;
1017 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1018 items << qMakePair(QString("new item " + j), QString::number(j));
1019 model.insertItems(changes[i].index, items);
1022 case ListChange::Removed:
1023 model.removeItems(changes[i].index, changes[i].count);
1025 case ListChange::Moved:
1026 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1028 case ListChange::SetCurrent:
1029 gridview->setCurrentIndex(changes[i].index);
1034 QTRY_COMPARE(gridview->count(), newCount);
1035 QCOMPARE(gridview->count(), model.count());
1036 QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
1040 QSGItem *contentItem = gridview->contentItem();
1041 QTRY_VERIFY(contentItem != 0);
1042 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1043 for (int i=0; i < model.count() && i < itemCount; ++i) {
1044 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1045 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1046 name = findItem<QSGText>(contentItem, "textName", i);
1048 QTRY_COMPARE(name->text(), model.name(i));
1049 number = findItem<QSGText>(contentItem, "textNumber", i);
1050 QVERIFY(number != 0);
1051 QTRY_COMPARE(number->text(), model.number(i));
1057 void tst_QSGGridView::multipleChanges_data()
1059 QTest::addColumn<int>("startCount");
1060 QTest::addColumn<QList<ListChange> >("changes");
1061 QTest::addColumn<int>("newCount");
1062 QTest::addColumn<int>("newCurrentIndex");
1064 QList<ListChange> changes;
1066 for (int i=1; i<30; i++)
1067 changes << ListChange::remove(0);
1068 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1070 changes << ListChange::remove(0);
1071 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1074 changes << ListChange::setCurrent(29);
1075 for (int i=29; i>0; i--)
1076 changes << ListChange::remove(i);
1077 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1079 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1080 << ListChange::remove(0, 1)
1081 << ListChange::insert(0, 1)
1084 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1085 << ListChange::setCurrent(2)
1086 << ListChange::remove(2, 1)
1087 << ListChange::insert(2, 1)
1090 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1091 << ListChange::setCurrent(1)
1092 << ListChange::remove(1, 3)
1093 << ListChange::insert(2, 2)
1096 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1097 << ListChange::setCurrent(2)
1098 << ListChange::remove(1, 3)
1099 << ListChange::move(1, 5, 1)
1102 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1103 << ListChange::setCurrent(5)
1104 << ListChange::remove(4, 3)
1105 << ListChange::move(4, 1, 1)
1109 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1110 << ListChange::insert(0, 2)
1111 << ListChange::insert(0, 4)
1112 << ListChange::insert(0, 6)
1115 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1116 << ListChange::insert(0, 2)
1117 << ListChange::insert(0, 4)
1118 << ListChange::insert(0, 6)
1119 << ListChange::setCurrent(3)
1120 << ListChange::insert(3, 2)
1123 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1124 << ListChange::insert(0, 30)
1125 << ListChange::remove(0, 30)
1128 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1129 << ListChange::insert(1)
1130 << ListChange::setCurrent(1)
1131 << ListChange::remove(1)
1134 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1135 << ListChange::insert(0, 10)
1136 << ListChange::remove(5, 10)
1139 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1140 << ListChange::insert(0, 3)
1141 << ListChange::move(0, 10, 3)
1144 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1145 << ListChange::insert(0, 3)
1146 << ListChange::move(0, 8, 5)
1149 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1150 << ListChange::setCurrent(9)
1151 << ListChange::insert(10, 3)
1152 << ListChange::move(8, 0, 5)
1156 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1157 << ListChange::setCurrent(1)
1158 << ListChange::move(1, 2, 2)
1159 << ListChange::move(2, 1, 2)
1162 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1163 << ListChange::setCurrent(2)
1164 << ListChange::move(1, 2, 3)
1165 << ListChange::move(3, 0, 5)
1168 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1169 << ListChange::setCurrent(5)
1170 << ListChange::move(5, 0, 1)
1171 << ListChange::remove(0)
1174 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1175 << ListChange::setCurrent(5)
1176 << ListChange::move(5, 0, 1)
1177 << ListChange::insert(0)
1180 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1181 << ListChange::setCurrent(1)
1182 << ListChange::move(5, 1, 3)
1183 << ListChange::remove(1, 3)
1186 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1187 << ListChange::setCurrent(5)
1188 << ListChange::move(5, 1, 3)
1189 << ListChange::insert(1, 5)
1192 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1193 << ListChange::setCurrent(3)
1194 << ListChange::move(0, 1, 2)
1195 << ListChange::insert(3, 5)
1199 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1200 << ListChange::insert(0, 5)
1201 << ListChange::setCurrent(-1)
1202 << ListChange::remove(0, 5)
1203 << ListChange::insert(0, 5)
1208 void tst_QSGGridView::swapWithFirstItem()
1211 QSGView *canvas = createView();
1215 for (int i = 0; i < 30; i++)
1216 model.addItem("Item" + QString::number(i), "");
1218 QDeclarativeContext *ctxt = canvas->rootContext();
1219 ctxt->setContextProperty("testModel", &model);
1220 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1221 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1223 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1224 qApp->processEvents();
1226 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1227 QTRY_VERIFY(gridview != 0);
1229 // ensure content position is stable
1230 gridview->setContentY(0);
1231 model.moveItem(10, 0);
1232 QTRY_VERIFY(gridview->contentY() == 0);
1237 void tst_QSGGridView::currentIndex()
1240 for (int i = 0; i < 60; i++)
1241 model.addItem("Item" + QString::number(i), QString::number(i));
1243 QSGView *canvas = new QSGView(0);
1244 canvas->setGeometry(0,0,240,320);
1247 QDeclarativeContext *ctxt = canvas->rootContext();
1248 ctxt->setContextProperty("testModel", &model);
1250 QString filename(TESTDATA("gridview-initCurrent.qml"));
1251 canvas->setSource(QUrl::fromLocalFile(filename));
1253 qApp->processEvents();
1255 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1256 QVERIFY(gridview != 0);
1258 QSGItem *contentItem = gridview->contentItem();
1259 QVERIFY(contentItem != 0);
1261 // current item should be third item
1262 QCOMPARE(gridview->currentIndex(), 35);
1263 QCOMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 35));
1264 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1265 QCOMPARE(gridview->contentY(), 400.0);
1267 gridview->moveCurrentIndexRight();
1268 QCOMPARE(gridview->currentIndex(), 36);
1269 gridview->moveCurrentIndexDown();
1270 QCOMPARE(gridview->currentIndex(), 39);
1271 gridview->moveCurrentIndexUp();
1272 QCOMPARE(gridview->currentIndex(), 36);
1273 gridview->moveCurrentIndexLeft();
1274 QCOMPARE(gridview->currentIndex(), 35);
1277 gridview->setCurrentIndex(0);
1278 QCOMPARE(gridview->currentIndex(), 0);
1279 // confirm that the velocity is updated
1280 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1282 gridview->moveCurrentIndexUp();
1283 QCOMPARE(gridview->currentIndex(), 0);
1285 gridview->moveCurrentIndexLeft();
1286 QCOMPARE(gridview->currentIndex(), 0);
1288 gridview->setCurrentIndex(model.count()-1);
1289 QCOMPARE(gridview->currentIndex(), model.count()-1);
1291 gridview->moveCurrentIndexRight();
1292 QCOMPARE(gridview->currentIndex(), model.count()-1);
1294 gridview->moveCurrentIndexDown();
1295 QCOMPARE(gridview->currentIndex(), model.count()-1);
1298 gridview->setWrapEnabled(true);
1300 gridview->setCurrentIndex(0);
1301 QCOMPARE(gridview->currentIndex(), 0);
1303 gridview->moveCurrentIndexLeft();
1304 QCOMPARE(gridview->currentIndex(), model.count()-1);
1306 qApp->processEvents();
1307 QTRY_COMPARE(gridview->contentY(), 880.0);
1309 gridview->moveCurrentIndexRight();
1310 QCOMPARE(gridview->currentIndex(), 0);
1312 QTRY_COMPARE(gridview->contentY(), 0.0);
1315 // footer should become visible if it is out of view, and then current index moves to the first row
1316 canvas->rootObject()->setProperty("showFooter", true);
1317 QTRY_VERIFY(gridview->footerItem());
1318 gridview->setCurrentIndex(model.count()-3);
1319 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1320 gridview->setCurrentIndex(model.count()-2);
1321 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1322 canvas->rootObject()->setProperty("showFooter", false);
1324 // header should become visible if it is out of view, and then current index moves to the last row
1325 canvas->rootObject()->setProperty("showHeader", true);
1326 QTRY_VERIFY(gridview->headerItem());
1327 gridview->setCurrentIndex(3);
1328 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1329 gridview->setCurrentIndex(1);
1330 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1331 canvas->rootObject()->setProperty("showHeader", false);
1335 canvas->requestActivateWindow();
1336 QTest::qWaitForWindowShown(canvas);
1337 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1339 gridview->setCurrentIndex(0);
1341 QTest::keyClick(canvas, Qt::Key_Down);
1342 QCOMPARE(gridview->currentIndex(), 3);
1344 QTest::keyClick(canvas, Qt::Key_Up);
1345 QCOMPARE(gridview->currentIndex(), 0);
1347 // hold down Key_Down
1348 for (int i=0; i<(model.count() / 3) - 1; i++) {
1349 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1350 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1352 QTest::keyRelease(canvas, Qt::Key_Down);
1353 QTRY_COMPARE(gridview->currentIndex(), 57);
1354 QTRY_COMPARE(gridview->contentY(), 880.0);
1357 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1358 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1359 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1361 QTest::keyRelease(canvas, Qt::Key_Up);
1362 QTRY_COMPARE(gridview->currentIndex(), 0);
1363 QTRY_COMPARE(gridview->contentY(), 0.0);
1366 gridview->setFlow(QSGGridView::TopToBottom);
1368 canvas->requestActivateWindow();
1369 QTest::qWaitForWindowShown(canvas);
1370 QVERIFY(qGuiApp->focusWindow() == canvas);
1371 qApp->processEvents();
1373 QTest::keyClick(canvas, Qt::Key_Right);
1374 QCOMPARE(gridview->currentIndex(), 5);
1376 QTest::keyClick(canvas, Qt::Key_Left);
1377 QCOMPARE(gridview->currentIndex(), 0);
1379 QTest::keyClick(canvas, Qt::Key_Down);
1380 QCOMPARE(gridview->currentIndex(), 1);
1382 QTest::keyClick(canvas, Qt::Key_Up);
1383 QCOMPARE(gridview->currentIndex(), 0);
1385 // hold down Key_Right
1386 for (int i=0; i<(model.count() / 5) - 1; i++) {
1387 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1388 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1391 QTest::keyRelease(canvas, Qt::Key_Right);
1392 QTRY_COMPARE(gridview->currentIndex(), 55);
1393 QTRY_COMPARE(gridview->contentX(), 720.0);
1395 // hold down Key_Left
1396 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1397 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1398 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1400 QTest::keyRelease(canvas, Qt::Key_Left);
1401 QTRY_COMPARE(gridview->currentIndex(), 0);
1402 QTRY_COMPARE(gridview->contentX(), 0.0);
1405 // turn off auto highlight
1406 gridview->setHighlightFollowsCurrentItem(false);
1407 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1408 QVERIFY(gridview->highlightItem());
1409 qreal hlPosX = gridview->highlightItem()->x();
1410 qreal hlPosY = gridview->highlightItem()->y();
1412 gridview->setCurrentIndex(5);
1413 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1414 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1416 // insert item before currentIndex
1417 gridview->setCurrentIndex(28);
1418 model.insertItem(0, "Foo", "1111");
1419 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1421 // check removing highlight by setting currentIndex to -1;
1422 gridview->setCurrentIndex(-1);
1424 QCOMPARE(gridview->currentIndex(), -1);
1425 QVERIFY(!gridview->highlightItem());
1426 QVERIFY(!gridview->currentItem());
1428 gridview->setHighlightFollowsCurrentItem(true);
1430 gridview->setFlow(QSGGridView::LeftToRight);
1431 gridview->setLayoutDirection(Qt::RightToLeft);
1433 canvas->requestActivateWindow();
1434 QTest::qWaitForWindowShown(canvas);
1435 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1436 qApp->processEvents();
1438 gridview->setCurrentIndex(35);
1440 QTest::keyClick(canvas, Qt::Key_Right);
1441 QCOMPARE(gridview->currentIndex(), 34);
1443 QTest::keyClick(canvas, Qt::Key_Down);
1444 QCOMPARE(gridview->currentIndex(), 37);
1446 QTest::keyClick(canvas, Qt::Key_Up);
1447 QCOMPARE(gridview->currentIndex(), 34);
1449 QTest::keyClick(canvas, Qt::Key_Left);
1450 QCOMPARE(gridview->currentIndex(), 35);
1453 // turn off auto highlight
1454 gridview->setHighlightFollowsCurrentItem(false);
1455 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1456 QVERIFY(gridview->highlightItem());
1457 hlPosX = gridview->highlightItem()->x();
1458 hlPosY = gridview->highlightItem()->y();
1460 gridview->setCurrentIndex(5);
1461 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1462 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1464 // insert item before currentIndex
1465 gridview->setCurrentIndex(28);
1466 model.insertItem(0, "Foo", "1111");
1467 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1469 // check removing highlight by setting currentIndex to -1;
1470 gridview->setCurrentIndex(-1);
1472 QCOMPARE(gridview->currentIndex(), -1);
1473 QVERIFY(!gridview->highlightItem());
1474 QVERIFY(!gridview->currentItem());
1479 void tst_QSGGridView::noCurrentIndex()
1482 for (int i = 0; i < 60; i++)
1483 model.addItem("Item" + QString::number(i), QString::number(i));
1485 QSGView *canvas = new QSGView(0);
1486 canvas->setGeometry(0,0,240,320);
1488 QDeclarativeContext *ctxt = canvas->rootContext();
1489 ctxt->setContextProperty("testModel", &model);
1491 QString filename(TESTDATA("gridview-noCurrent.qml"));
1492 canvas->setSource(QUrl::fromLocalFile(filename));
1494 qApp->processEvents();
1496 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1497 QVERIFY(gridview != 0);
1499 QSGItem *contentItem = gridview->contentItem();
1500 QVERIFY(contentItem != 0);
1502 // current index should be -1
1503 QCOMPARE(gridview->currentIndex(), -1);
1504 QVERIFY(!gridview->currentItem());
1505 QVERIFY(!gridview->highlightItem());
1506 QCOMPARE(gridview->contentY(), 0.0);
1508 gridview->setCurrentIndex(5);
1509 QCOMPARE(gridview->currentIndex(), 5);
1510 QVERIFY(gridview->currentItem());
1511 QVERIFY(gridview->highlightItem());
1516 void tst_QSGGridView::changeFlow()
1518 QSGView *canvas = createView();
1521 for (int i = 0; i < 30; i++)
1522 model.addItem("Item" + QString::number(i), QString::number(i));
1524 QDeclarativeContext *ctxt = canvas->rootContext();
1525 ctxt->setContextProperty("testModel", &model);
1526 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1527 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1529 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1530 qApp->processEvents();
1532 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1533 QTRY_VERIFY(gridview != 0);
1535 QSGItem *contentItem = gridview->contentItem();
1536 QTRY_VERIFY(contentItem != 0);
1538 // Confirm items positioned correctly and indexes correct
1539 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1540 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1541 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1542 if (!item) qWarning() << "Item" << i << "not found";
1544 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1545 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1546 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1547 QTRY_VERIFY(name != 0);
1548 QTRY_COMPARE(name->text(), model.name(i));
1549 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1550 QTRY_VERIFY(number != 0);
1551 QTRY_COMPARE(number->text(), model.number(i));
1554 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1556 // Confirm items positioned correctly and indexes correct
1557 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1558 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1559 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1560 if (!item) qWarning() << "Item" << i << "not found";
1562 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1563 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1564 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1565 QTRY_VERIFY(name != 0);
1566 QTRY_COMPARE(name->text(), model.name(i));
1567 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1568 QTRY_VERIFY(number != 0);
1569 QTRY_COMPARE(number->text(), model.number(i));
1572 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1574 // Confirm items positioned correctly and indexes correct
1575 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1576 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1577 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1578 if (!item) qWarning() << "Item" << i << "not found";
1580 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1581 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1582 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1583 QTRY_VERIFY(name != 0);
1584 QTRY_COMPARE(name->text(), model.name(i));
1585 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1586 QTRY_VERIFY(number != 0);
1587 QTRY_COMPARE(number->text(), model.number(i));
1589 gridview->setContentX(100);
1590 QTRY_COMPARE(gridview->contentX(), 100.);
1591 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1592 QTRY_COMPARE(gridview->contentX(), 0.);
1594 // Confirm items positioned correctly and indexes correct
1595 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1596 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1597 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1598 if (!item) qWarning() << "Item" << i << "not found";
1600 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1601 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1602 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1603 QTRY_VERIFY(name != 0);
1604 QTRY_COMPARE(name->text(), model.name(i));
1605 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1606 QTRY_VERIFY(number != 0);
1607 QTRY_COMPARE(number->text(), model.number(i));
1613 void tst_QSGGridView::defaultValues()
1615 QDeclarativeEngine engine;
1616 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview3.qml")));
1617 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1619 QTRY_VERIFY(obj != 0);
1620 QTRY_VERIFY(obj->model() == QVariant());
1621 QTRY_VERIFY(obj->delegate() == 0);
1622 QTRY_COMPARE(obj->currentIndex(), -1);
1623 QTRY_VERIFY(obj->currentItem() == 0);
1624 QTRY_COMPARE(obj->count(), 0);
1625 QTRY_VERIFY(obj->highlight() == 0);
1626 QTRY_VERIFY(obj->highlightItem() == 0);
1627 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1628 QTRY_VERIFY(obj->flow() == 0);
1629 QTRY_COMPARE(obj->isWrapEnabled(), false);
1630 QTRY_COMPARE(obj->cacheBuffer(), 0);
1631 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
1632 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1636 void tst_QSGGridView::properties()
1638 QDeclarativeEngine engine;
1639 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview2.qml")));
1640 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1642 QTRY_VERIFY(obj != 0);
1643 QTRY_VERIFY(obj->model() != QVariant());
1644 QTRY_VERIFY(obj->delegate() != 0);
1645 QTRY_COMPARE(obj->currentIndex(), 0);
1646 QTRY_VERIFY(obj->currentItem() != 0);
1647 QTRY_COMPARE(obj->count(), 4);
1648 QTRY_VERIFY(obj->highlight() != 0);
1649 QTRY_VERIFY(obj->highlightItem() != 0);
1650 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1651 QTRY_VERIFY(obj->flow() == 0);
1652 QTRY_COMPARE(obj->isWrapEnabled(), true);
1653 QTRY_COMPARE(obj->cacheBuffer(), 200);
1654 QTRY_COMPARE(obj->cellWidth(), qreal(100));
1655 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1659 void tst_QSGGridView::propertyChanges()
1661 QSGView *canvas = createView();
1662 QTRY_VERIFY(canvas);
1663 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1665 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1666 QTRY_VERIFY(gridView);
1668 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1669 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1670 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1671 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1673 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1674 QTRY_COMPARE(gridView->cacheBuffer(), 10);
1675 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1677 gridView->setWrapEnabled(false);
1678 gridView->setCacheBuffer(3);
1679 gridView->setFlow(QSGGridView::TopToBottom);
1681 QTRY_COMPARE(gridView->isWrapEnabled(), false);
1682 QTRY_COMPARE(gridView->cacheBuffer(), 3);
1683 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1685 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1686 QTRY_COMPARE(cacheBufferSpy.count(),1);
1687 QTRY_COMPARE(flowSpy.count(),1);
1689 gridView->setWrapEnabled(false);
1690 gridView->setCacheBuffer(3);
1691 gridView->setFlow(QSGGridView::TopToBottom);
1693 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1694 QTRY_COMPARE(cacheBufferSpy.count(),1);
1695 QTRY_COMPARE(flowSpy.count(),1);
1697 gridView->setFlow(QSGGridView::LeftToRight);
1698 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1700 gridView->setWrapEnabled(true);
1701 gridView->setCacheBuffer(5);
1702 gridView->setLayoutDirection(Qt::RightToLeft);
1704 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1705 QTRY_COMPARE(gridView->cacheBuffer(), 5);
1706 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1708 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1709 QTRY_COMPARE(cacheBufferSpy.count(),2);
1710 QTRY_COMPARE(layoutSpy.count(),1);
1711 QTRY_COMPARE(flowSpy.count(),2);
1713 gridView->setWrapEnabled(true);
1714 gridView->setCacheBuffer(5);
1715 gridView->setLayoutDirection(Qt::RightToLeft);
1717 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1718 QTRY_COMPARE(cacheBufferSpy.count(),2);
1719 QTRY_COMPARE(layoutSpy.count(),1);
1720 QTRY_COMPARE(flowSpy.count(),2);
1722 gridView->setFlow(QSGGridView::TopToBottom);
1723 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1724 QTRY_COMPARE(flowSpy.count(),3);
1726 gridView->setFlow(QSGGridView::TopToBottom);
1727 QTRY_COMPARE(flowSpy.count(),3);
1732 void tst_QSGGridView::componentChanges()
1734 QSGView *canvas = createView();
1735 QTRY_VERIFY(canvas);
1736 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1738 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1739 QTRY_VERIFY(gridView);
1741 QDeclarativeComponent component(canvas->engine());
1742 component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1744 QDeclarativeComponent delegateComponent(canvas->engine());
1745 delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1747 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1748 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1749 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1750 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1752 gridView->setHighlight(&component);
1753 gridView->setDelegate(&delegateComponent);
1754 gridView->setHeader(&component);
1755 gridView->setFooter(&component);
1757 QTRY_COMPARE(gridView->highlight(), &component);
1758 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1759 QTRY_COMPARE(gridView->header(), &component);
1760 QTRY_COMPARE(gridView->footer(), &component);
1762 QTRY_COMPARE(highlightSpy.count(),1);
1763 QTRY_COMPARE(delegateSpy.count(),1);
1764 QTRY_COMPARE(headerSpy.count(),1);
1765 QTRY_COMPARE(footerSpy.count(),1);
1767 gridView->setHighlight(&component);
1768 gridView->setDelegate(&delegateComponent);
1769 gridView->setHeader(&component);
1770 gridView->setFooter(&component);
1772 QTRY_COMPARE(highlightSpy.count(),1);
1773 QTRY_COMPARE(delegateSpy.count(),1);
1774 QTRY_COMPARE(headerSpy.count(),1);
1775 QTRY_COMPARE(footerSpy.count(),1);
1780 void tst_QSGGridView::modelChanges()
1782 QSGView *canvas = createView();
1783 QTRY_VERIFY(canvas);
1784 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1786 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1787 QTRY_VERIFY(gridView);
1789 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1790 QTRY_VERIFY(alternateModel);
1791 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1792 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1794 gridView->setModel(modelVariant);
1795 QTRY_COMPARE(gridView->model(), modelVariant);
1796 QTRY_COMPARE(modelSpy.count(),1);
1798 gridView->setModel(modelVariant);
1799 QTRY_COMPARE(modelSpy.count(),1);
1801 gridView->setModel(QVariant());
1802 QTRY_COMPARE(modelSpy.count(),2);
1806 void tst_QSGGridView::positionViewAtIndex()
1808 QSGView *canvas = createView();
1811 for (int i = 0; i < 40; i++)
1812 model.addItem("Item" + QString::number(i), "");
1814 QDeclarativeContext *ctxt = canvas->rootContext();
1815 ctxt->setContextProperty("testModel", &model);
1816 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1817 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1819 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1820 qApp->processEvents();
1822 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1823 QTRY_VERIFY(gridview != 0);
1825 QSGItem *contentItem = gridview->contentItem();
1826 QTRY_VERIFY(contentItem != 0);
1828 // Confirm items positioned correctly
1829 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1830 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1831 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1832 if (!item) qWarning() << "Item" << i << "not found";
1834 QTRY_COMPARE(item->x(), (i%3)*80.);
1835 QTRY_COMPARE(item->y(), (i/3)*60.);
1838 // Position on a currently visible item
1839 gridview->positionViewAtIndex(4, QSGGridView::Beginning);
1840 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1841 QTRY_COMPARE(gridview->contentY(), 60.);
1843 // Confirm items positioned correctly
1844 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1845 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1846 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1847 if (!item) qWarning() << "Item" << i << "not found";
1849 QTRY_COMPARE(item->x(), (i%3)*80.);
1850 QTRY_COMPARE(item->y(), (i/3)*60.);
1853 // Position on an item beyond the visible items
1854 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1855 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1856 QTRY_COMPARE(gridview->contentY(), 420.);
1858 // Confirm items positioned correctly
1859 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1860 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1861 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1862 if (!item) qWarning() << "Item" << i << "not found";
1864 QTRY_COMPARE(item->x(), (i%3)*80.);
1865 QTRY_COMPARE(item->y(), (i/3)*60.);
1868 // Position on an item that would leave empty space if positioned at the top
1869 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1870 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1871 QTRY_COMPARE(gridview->contentY(), 520.);
1873 // Confirm items positioned correctly
1874 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1875 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1876 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1877 if (!item) qWarning() << "Item" << i << "not found";
1879 QTRY_COMPARE(item->x(), (i%3)*80.);
1880 QTRY_COMPARE(item->y(), (i/3)*60.);
1883 // Position at the beginning again
1884 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1885 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1886 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1887 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1888 QTRY_COMPARE(gridview->contentY(), 0.);
1890 // Confirm items positioned correctly
1891 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1892 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1893 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1894 if (!item) qWarning() << "Item" << i << "not found";
1896 QTRY_COMPARE(item->x(), (i%3)*80.);
1897 QTRY_COMPARE(item->y(), (i/3)*60.);
1901 gridview->positionViewAtIndex(30, QSGGridView::End);
1902 QTRY_COMPARE(gridview->contentY(), 340.);
1904 // Position in Center
1905 gridview->positionViewAtIndex(15, QSGGridView::Center);
1906 QTRY_COMPARE(gridview->contentY(), 170.);
1908 // Ensure at least partially visible
1909 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1910 QTRY_COMPARE(gridview->contentY(), 170.);
1912 gridview->setContentY(302);
1913 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1914 QTRY_COMPARE(gridview->contentY(), 302.);
1916 gridview->setContentY(360);
1917 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1918 QTRY_COMPARE(gridview->contentY(), 300.);
1920 gridview->setContentY(60);
1921 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1922 QTRY_COMPARE(gridview->contentY(), 60.);
1924 gridview->setContentY(20);
1925 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1926 QTRY_COMPARE(gridview->contentY(), 100.);
1928 // Ensure completely visible
1929 gridview->setContentY(120);
1930 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1931 QTRY_COMPARE(gridview->contentY(), 120.);
1933 gridview->setContentY(302);
1934 gridview->positionViewAtIndex(15, QSGGridView::Contain);
1935 QTRY_COMPARE(gridview->contentY(), 300.);
1937 gridview->setContentY(60);
1938 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1939 QTRY_COMPARE(gridview->contentY(), 100.);
1941 // Test for Top To Bottom layout
1942 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1944 // Confirm items positioned correctly
1945 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1946 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1947 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1948 if (!item) qWarning() << "Item" << i << "not found";
1950 QTRY_COMPARE(item->x(), (i/5)*80.);
1951 QTRY_COMPARE(item->y(), (i%5)*60.);
1955 gridview->positionViewAtIndex(30, QSGGridView::End);
1956 QTRY_COMPARE(gridview->contentX(), 320.);
1957 QTRY_COMPARE(gridview->contentY(), 0.);
1959 // Position in Center
1960 gridview->positionViewAtIndex(15, QSGGridView::Center);
1961 QTRY_COMPARE(gridview->contentX(), 160.);
1963 // Ensure at least partially visible
1964 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1965 QTRY_COMPARE(gridview->contentX(), 160.);
1967 gridview->setContentX(170);
1968 gridview->positionViewAtIndex(25, QSGGridView::Visible);
1969 QTRY_COMPARE(gridview->contentX(), 170.);
1971 gridview->positionViewAtIndex(30, QSGGridView::Visible);
1972 QTRY_COMPARE(gridview->contentX(), 320.);
1974 gridview->setContentX(170);
1975 gridview->positionViewAtIndex(25, QSGGridView::Contain);
1976 QTRY_COMPARE(gridview->contentX(), 240.);
1978 // positionViewAtBeginning
1979 gridview->positionViewAtBeginning();
1980 QTRY_COMPARE(gridview->contentX(), 0.);
1982 gridview->setContentX(80);
1983 canvas->rootObject()->setProperty("showHeader", true);
1984 gridview->positionViewAtBeginning();
1985 QTRY_COMPARE(gridview->contentX(), -30.);
1987 // positionViewAtEnd
1988 gridview->positionViewAtEnd();
1989 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
1991 gridview->setContentX(80);
1992 canvas->rootObject()->setProperty("showFooter", true);
1993 gridview->positionViewAtEnd();
1994 QTRY_COMPARE(gridview->contentX(), 430.);
1996 // set current item to outside visible view, position at beginning
1997 // and ensure highlight moves to current item
1998 gridview->setCurrentIndex(6);
1999 gridview->positionViewAtBeginning();
2000 QTRY_COMPARE(gridview->contentX(), -30.);
2001 QVERIFY(gridview->highlightItem());
2002 QCOMPARE(gridview->highlightItem()->x(), 80.);
2007 void tst_QSGGridView::snapping()
2009 QSGView *canvas = createView();
2012 for (int i = 0; i < 40; i++)
2013 model.addItem("Item" + QString::number(i), "");
2015 QDeclarativeContext *ctxt = canvas->rootContext();
2016 ctxt->setContextProperty("testModel", &model);
2017 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2018 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2020 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2021 qApp->processEvents();
2023 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2024 QTRY_VERIFY(gridview != 0);
2026 gridview->setHeight(220);
2027 QCOMPARE(gridview->height(), 220.);
2029 gridview->positionViewAtIndex(12, QSGGridView::Visible);
2030 QCOMPARE(gridview->contentY(), 80.);
2032 gridview->setContentY(0);
2033 QCOMPARE(gridview->contentY(), 0.);
2035 gridview->setSnapMode(QSGGridView::SnapToRow);
2036 QCOMPARE(gridview->snapMode(), QSGGridView::SnapToRow);
2038 gridview->positionViewAtIndex(12, QSGGridView::Visible);
2039 QCOMPARE(gridview->contentY(), 60.);
2041 gridview->positionViewAtIndex(15, QSGGridView::End);
2042 QCOMPARE(gridview->contentY(), 120.);
2048 void tst_QSGGridView::mirroring()
2050 QSGView *canvasA = createView();
2051 canvasA->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2052 QSGGridView *gridviewA = findItem<QSGGridView>(canvasA->rootObject(), "view");
2053 QTRY_VERIFY(gridviewA != 0);
2055 QSGView *canvasB = createView();
2056 canvasB->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2057 QSGGridView *gridviewB = findItem<QSGGridView>(canvasB->rootObject(), "view");
2058 QTRY_VERIFY(gridviewA != 0);
2059 qApp->processEvents();
2061 QList<QString> objectNames;
2062 objectNames << "item1" << "item2"; // << "item3"
2064 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2065 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2066 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2069 foreach (const QString objectName, objectNames)
2070 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
2072 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2073 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2076 foreach (const QString objectName, objectNames)
2077 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
2079 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2080 QSGItemPrivate::get(gridviewB)->setLayoutMirror(true);
2081 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2083 // LTR != LTR+mirror
2084 foreach (const QString objectName, objectNames)
2085 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
2087 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2089 // RTL == LTR+mirror
2090 foreach (const QString objectName, objectNames)
2091 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
2093 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2095 // RTL != RTL+mirror
2096 foreach (const QString objectName, objectNames)
2097 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
2099 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2101 // LTR == RTL+mirror
2102 foreach (const QString objectName, objectNames)
2103 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
2109 void tst_QSGGridView::positionViewAtIndex_rightToLeft()
2111 QSGView *canvas = createView();
2114 for (int i = 0; i < 40; i++)
2115 model.addItem("Item" + QString::number(i), "");
2117 QDeclarativeContext *ctxt = canvas->rootContext();
2118 ctxt->setContextProperty("testModel", &model);
2119 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2120 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2122 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2123 qApp->processEvents();
2125 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2126 QTRY_VERIFY(gridview != 0);
2128 QSGItem *contentItem = gridview->contentItem();
2129 QTRY_VERIFY(contentItem != 0);
2131 // Confirm items positioned correctly
2132 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2133 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2134 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2135 if (!item) qWarning() << "Item" << i << "not found";
2137 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2138 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2141 // Position on a currently visible item
2142 gridview->positionViewAtIndex(6, QSGGridView::Beginning);
2143 QTRY_COMPARE(gridview->contentX(), -320.);
2145 // Confirm items positioned correctly
2146 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2147 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2148 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2149 if (!item) qWarning() << "Item" << i << "not found";
2151 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2152 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2155 // Position on an item beyond the visible items
2156 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
2157 QTRY_COMPARE(gridview->contentX(), -560.);
2159 // Confirm items positioned correctly
2160 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2161 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2162 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2163 if (!item) qWarning() << "Item" << i << "not found";
2165 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2166 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2169 // Position on an item that would leave empty space if positioned at the top
2170 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
2171 QTRY_COMPARE(gridview->contentX(), -640.);
2173 // Confirm items positioned correctly
2174 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2175 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2176 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2177 if (!item) qWarning() << "Item" << i << "not found";
2179 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2180 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2183 // Position at the beginning again
2184 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
2185 QTRY_COMPARE(gridview->contentX(), -240.);
2187 // Confirm items positioned correctly
2188 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2189 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2190 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2191 if (!item) qWarning() << "Item" << i << "not found";
2193 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2194 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2198 gridview->positionViewAtIndex(30, QSGGridView::End);
2199 QTRY_COMPARE(gridview->contentX(), -560.);
2201 // Position in Center
2202 gridview->positionViewAtIndex(15, QSGGridView::Center);
2203 QTRY_COMPARE(gridview->contentX(), -400.);
2205 // Ensure at least partially visible
2206 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2207 QTRY_COMPARE(gridview->contentX(), -400.);
2209 gridview->setContentX(-555.);
2210 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2211 QTRY_COMPARE(gridview->contentX(), -555.);
2213 gridview->setContentX(-239);
2214 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2215 QTRY_COMPARE(gridview->contentX(), -320.);
2217 gridview->setContentX(-239);
2218 gridview->positionViewAtIndex(20, QSGGridView::Visible);
2219 QTRY_COMPARE(gridview->contentX(), -400.);
2221 gridview->setContentX(-640);
2222 gridview->positionViewAtIndex(20, QSGGridView::Visible);
2223 QTRY_COMPARE(gridview->contentX(), -560.);
2225 // Ensure completely visible
2226 gridview->setContentX(-400);
2227 gridview->positionViewAtIndex(20, QSGGridView::Contain);
2228 QTRY_COMPARE(gridview->contentX(), -400.);
2230 gridview->setContentX(-315);
2231 gridview->positionViewAtIndex(15, QSGGridView::Contain);
2232 QTRY_COMPARE(gridview->contentX(), -320.);
2234 gridview->setContentX(-640);
2235 gridview->positionViewAtIndex(20, QSGGridView::Contain);
2236 QTRY_COMPARE(gridview->contentX(), -560.);
2241 void tst_QSGGridView::resetModel()
2243 QSGView *canvas = createView();
2245 QStringList strings;
2246 strings << "one" << "two" << "three";
2247 QStringListModel model(strings);
2249 QDeclarativeContext *ctxt = canvas->rootContext();
2250 ctxt->setContextProperty("testModel", &model);
2252 canvas->setSource(QUrl::fromLocalFile(TESTDATA("displaygrid.qml")));
2253 qApp->processEvents();
2255 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2256 QTRY_VERIFY(gridview != 0);
2258 QSGItem *contentItem = gridview->contentItem();
2259 QTRY_VERIFY(contentItem != 0);
2261 QTRY_COMPARE(gridview->count(), model.rowCount());
2263 for (int i = 0; i < model.rowCount(); ++i) {
2264 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
2265 QTRY_VERIFY(display != 0);
2266 QTRY_COMPARE(display->text(), strings.at(i));
2270 strings << "four" << "five" << "six" << "seven";
2271 model.setStringList(strings);
2273 QTRY_COMPARE(gridview->count(), model.rowCount());
2275 for (int i = 0; i < model.rowCount(); ++i) {
2276 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
2277 QTRY_VERIFY(display != 0);
2278 QTRY_COMPARE(display->text(), strings.at(i));
2284 void tst_QSGGridView::enforceRange()
2286 QSGView *canvas = createView();
2289 for (int i = 0; i < 30; i++)
2290 model.addItem("Item" + QString::number(i), "");
2292 QDeclarativeContext *ctxt = canvas->rootContext();
2293 ctxt->setContextProperty("testModel", &model);
2294 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2295 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2297 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2298 qApp->processEvents();
2299 QVERIFY(canvas->rootObject() != 0);
2301 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2302 QTRY_VERIFY(gridview != 0);
2304 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2305 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2306 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
2308 QSGItem *contentItem = gridview->contentItem();
2309 QTRY_VERIFY(contentItem != 0);
2311 // view should be positioned at the top of the range.
2312 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2314 QTRY_COMPARE(gridview->contentY(), -100.0);
2316 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
2317 QTRY_VERIFY(name != 0);
2318 QTRY_COMPARE(name->text(), model.name(0));
2319 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
2320 QTRY_VERIFY(number != 0);
2321 QTRY_COMPARE(number->text(), model.number(0));
2323 // Check currentIndex is updated when contentItem moves
2324 gridview->setContentY(0);
2325 QTRY_COMPARE(gridview->currentIndex(), 2);
2327 gridview->setCurrentIndex(5);
2328 QTRY_COMPARE(gridview->contentY(), 100.);
2331 for (int i = 0; i < 5; i++)
2332 model2.addItem("Item" + QString::number(i), "");
2334 ctxt->setContextProperty("testModel", &model2);
2335 QCOMPARE(gridview->count(), 5);
2340 void tst_QSGGridView::enforceRange_rightToLeft()
2342 QSGView *canvas = createView();
2345 for (int i = 0; i < 30; i++)
2346 model.addItem("Item" + QString::number(i), "");
2348 QDeclarativeContext *ctxt = canvas->rootContext();
2349 ctxt->setContextProperty("testModel", &model);
2350 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2351 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2353 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2354 qApp->processEvents();
2355 QVERIFY(canvas->rootObject() != 0);
2357 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2358 QTRY_VERIFY(gridview != 0);
2360 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2361 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2362 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
2364 QSGItem *contentItem = gridview->contentItem();
2365 QTRY_VERIFY(contentItem != 0);
2367 // view should be positioned at the top of the range.
2368 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2370 QTRY_COMPARE(gridview->contentX(), -100.);
2371 QTRY_COMPARE(gridview->contentY(), 0.0);
2373 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
2374 QTRY_VERIFY(name != 0);
2375 QTRY_COMPARE(name->text(), model.name(0));
2376 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
2377 QTRY_VERIFY(number != 0);
2378 QTRY_COMPARE(number->text(), model.number(0));
2380 // Check currentIndex is updated when contentItem moves
2381 gridview->setContentX(-200);
2382 QTRY_COMPARE(gridview->currentIndex(), 3);
2384 gridview->setCurrentIndex(7);
2385 QTRY_COMPARE(gridview->contentX(), -300.);
2386 QTRY_COMPARE(gridview->contentY(), 0.0);
2389 for (int i = 0; i < 5; i++)
2390 model2.addItem("Item" + QString::number(i), "");
2392 ctxt->setContextProperty("testModel", &model2);
2393 QCOMPARE(gridview->count(), 5);
2398 void tst_QSGGridView::QTBUG_8456()
2400 QSGView *canvas = createView();
2402 canvas->setSource(QUrl::fromLocalFile(TESTDATA("setindex.qml")));
2403 qApp->processEvents();
2405 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2406 QTRY_VERIFY(gridview != 0);
2408 QTRY_COMPARE(gridview->currentIndex(), 0);
2413 void tst_QSGGridView::manualHighlight()
2415 QSGView *canvas = createView();
2417 QString filename(TESTDATA("manual-highlight.qml"));
2418 canvas->setSource(QUrl::fromLocalFile(filename));
2420 qApp->processEvents();
2422 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2423 QTRY_VERIFY(gridview != 0);
2425 QSGItem *contentItem = gridview->contentItem();
2426 QTRY_VERIFY(contentItem != 0);
2428 QTRY_COMPARE(gridview->currentIndex(), 0);
2429 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
2430 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2431 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2433 gridview->setCurrentIndex(2);
2435 QTRY_COMPARE(gridview->currentIndex(), 2);
2436 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
2437 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2438 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2440 gridview->positionViewAtIndex(8, QSGGridView::Contain);
2442 QTRY_COMPARE(gridview->currentIndex(), 2);
2443 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
2444 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2445 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2447 gridview->setFlow(QSGGridView::TopToBottom);
2448 QTRY_COMPARE(gridview->flow(), QSGGridView::TopToBottom);
2450 gridview->setCurrentIndex(0);
2451 QTRY_COMPARE(gridview->currentIndex(), 0);
2452 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
2453 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2454 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2460 void tst_QSGGridView::footer()
2462 QFETCH(QSGGridView::Flow, flow);
2463 QFETCH(Qt::LayoutDirection, layoutDirection);
2464 QFETCH(QPointF, initialFooterPos);
2465 QFETCH(QPointF, changedFooterPos);
2466 QFETCH(QPointF, initialContentPos);
2467 QFETCH(QPointF, changedContentPos);
2468 QFETCH(QPointF, firstDelegatePos);
2469 QFETCH(QPointF, resizeContentPos);
2471 QSGView *canvas = createView();
2475 for (int i = 0; i < 7; i++)
2476 model.addItem("Item" + QString::number(i), "");
2478 QDeclarativeContext *ctxt = canvas->rootContext();
2479 ctxt->setContextProperty("testModel", &model);
2481 canvas->setSource(QUrl::fromLocalFile(TESTDATA("footer.qml")));
2482 qApp->processEvents();
2484 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2485 QTRY_VERIFY(gridview != 0);
2486 gridview->setFlow(flow);
2487 gridview->setLayoutDirection(layoutDirection);
2489 QSGItem *contentItem = gridview->contentItem();
2490 QTRY_VERIFY(contentItem != 0);
2492 QSGText *footer = findItem<QSGText>(contentItem, "footer");
2495 QVERIFY(footer == gridview->footerItem());
2497 QCOMPARE(footer->pos(), initialFooterPos);
2498 QCOMPARE(footer->width(), 100.);
2499 QCOMPARE(footer->height(), 30.);
2500 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2502 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2504 QCOMPARE(item->pos(), firstDelegatePos);
2506 if (flow == QSGGridView::LeftToRight) {
2507 // shrink by one row
2508 model.removeItem(2);
2509 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2511 // shrink by one column
2512 model.removeItem(2);
2513 model.removeItem(3);
2514 if (layoutDirection == Qt::LeftToRight)
2515 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2517 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2523 QPointF posWhenNoItems(0, 0);
2524 if (layoutDirection == Qt::RightToLeft)
2525 posWhenNoItems.setX(flow == QSGGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2526 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2528 // if header is present, it's at a negative pos, so the footer should not move
2529 canvas->rootObject()->setProperty("showHeader", true);
2530 QVERIFY(findItem<QSGItem>(contentItem, "header") != 0);
2531 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2532 canvas->rootObject()->setProperty("showHeader", false);
2535 for (int i = 0; i < 30; i++)
2536 model.addItem("Item" + QString::number(i), "");
2538 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2539 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2541 QCOMPARE(footerItemSpy.count(), 1);
2543 footer = findItem<QSGText>(contentItem, "footer");
2545 footer = findItem<QSGText>(contentItem, "footer2");
2548 QVERIFY(footer == gridview->footerItem());
2550 QCOMPARE(footer->pos(), changedFooterPos);
2551 QCOMPARE(footer->width(), 50.);
2552 QCOMPARE(footer->height(), 20.);
2553 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2555 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2557 QCOMPARE(item->pos(), firstDelegatePos);
2559 gridview->positionViewAtEnd();
2560 footer->setHeight(10);
2561 footer->setWidth(40);
2562 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2567 void tst_QSGGridView::footer_data()
2569 QTest::addColumn<QSGGridView::Flow>("flow");
2570 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2571 QTest::addColumn<QPointF>("initialFooterPos");
2572 QTest::addColumn<QPointF>("changedFooterPos");
2573 QTest::addColumn<QPointF>("initialContentPos");
2574 QTest::addColumn<QPointF>("changedContentPos");
2575 QTest::addColumn<QPointF>("firstDelegatePos");
2576 QTest::addColumn<QPointF>("resizeContentPos");
2578 // footer1 = 100 x 30
2579 // footer2 = 50 x 20
2582 // view height = 320
2584 // footer below items, bottom left
2585 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2586 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
2587 << QPointF(0, 10 * 60) // 30 items = 10 rows
2591 << QPointF(0, 10 * 60 - 320 + 10);
2593 // footer below items, bottom right
2594 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2595 << QPointF(240 - 100, 3 * 60)
2596 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
2599 << QPointF(240 - 80, 0)
2600 << QPointF(0, 10 * 60 - 320 + 10);
2602 // footer to right of items
2603 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2604 << QPointF(2 * 80, 0) // 2 columns, cell width 80
2605 << QPointF(6 * 80, 0) // 30 items = 6 columns
2609 << QPointF(6 * 80 - 240 + 40, 0);
2611 // footer to left of items
2612 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2613 << QPointF(-(2 * 80) - 100, 0)
2614 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
2616 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
2618 << QPointF(-(6 * 80) - 40, 0);
2621 void tst_QSGGridView::header()
2623 QFETCH(QSGGridView::Flow, flow);
2624 QFETCH(Qt::LayoutDirection, layoutDirection);
2625 QFETCH(QPointF, initialHeaderPos);
2626 QFETCH(QPointF, changedHeaderPos);
2627 QFETCH(QPointF, initialContentPos);
2628 QFETCH(QPointF, changedContentPos);
2629 QFETCH(QPointF, firstDelegatePos);
2630 QFETCH(QPointF, resizeContentPos);
2633 for (int i = 0; i < 30; i++)
2634 model.addItem("Item" + QString::number(i), "");
2636 QSGView *canvas = createView();
2637 canvas->rootContext()->setContextProperty("testModel", &model);
2638 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2639 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2640 canvas->setSource(QUrl::fromLocalFile(TESTDATA("header.qml")));
2642 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2643 QTRY_VERIFY(gridview != 0);
2644 gridview->setFlow(flow);
2645 gridview->setLayoutDirection(layoutDirection);
2647 QSGItem *contentItem = gridview->contentItem();
2648 QTRY_VERIFY(contentItem != 0);
2650 QSGText *header = findItem<QSGText>(contentItem, "header");
2653 QVERIFY(header == gridview->headerItem());
2655 QCOMPARE(header->pos(), initialHeaderPos);
2656 QCOMPARE(header->width(), 100.);
2657 QCOMPARE(header->height(), 30.);
2658 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2660 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2662 QCOMPARE(item->pos(), firstDelegatePos);
2665 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
2667 for (int i = 0; i < 30; i++)
2668 model.addItem("Item" + QString::number(i), "");
2670 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
2671 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
2673 QCOMPARE(headerItemSpy.count(), 1);
2675 header = findItem<QSGText>(contentItem, "header");
2677 header = findItem<QSGText>(contentItem, "header2");
2680 QVERIFY(header == gridview->headerItem());
2682 QCOMPARE(header->pos(), changedHeaderPos);
2683 QCOMPARE(header->width(), 50.);
2684 QCOMPARE(header->height(), 20.);
2685 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2687 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2689 QCOMPARE(item->pos(), firstDelegatePos);
2691 header->setHeight(10);
2692 header->setWidth(40);
2693 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2698 // QTBUG-21207 header should become visible if view resizes from initial empty size
2700 canvas = createView();
2701 canvas->rootContext()->setContextProperty("testModel", &model);
2702 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2703 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2704 canvas->setSource(QUrl::fromLocalFile(TESTDATA("header.qml")));
2706 gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2707 QTRY_VERIFY(gridview != 0);
2708 gridview->setFlow(flow);
2709 gridview->setLayoutDirection(layoutDirection);
2711 gridview->setWidth(240);
2712 gridview->setHeight(320);
2713 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
2714 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2719 void tst_QSGGridView::header_data()
2721 QTest::addColumn<QSGGridView::Flow>("flow");
2722 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2723 QTest::addColumn<QPointF>("initialHeaderPos");
2724 QTest::addColumn<QPointF>("changedHeaderPos");
2725 QTest::addColumn<QPointF>("initialContentPos");
2726 QTest::addColumn<QPointF>("changedContentPos");
2727 QTest::addColumn<QPointF>("firstDelegatePos");
2728 QTest::addColumn<QPointF>("resizeContentPos");
2730 // header1 = 100 x 30
2731 // header2 = 50 x 20
2735 // header above items, top left
2736 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2744 // header above items, top right
2745 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2746 << QPointF(240 - 100, -30)
2747 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
2753 // header to left of items
2754 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2762 // header to right of items
2763 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2766 << QPointF(-(240 - 100), 0)
2767 << QPointF(-(240 - 50), 0)
2769 << QPointF(-(240 - 40), 0);
2772 void tst_QSGGridView::resizeViewAndRepaint()
2774 QSGView *canvas = createView();
2778 for (int i = 0; i < 40; i++)
2779 model.addItem("Item" + QString::number(i), "");
2781 QDeclarativeContext *ctxt = canvas->rootContext();
2782 ctxt->setContextProperty("testModel", &model);
2783 ctxt->setContextProperty("initialHeight", 100);
2785 canvas->setSource(QUrl::fromLocalFile(TESTDATA("resizeview.qml")));
2786 qApp->processEvents();
2788 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2789 QTRY_VERIFY(gridview != 0);
2790 QSGItem *contentItem = gridview->contentItem();
2791 QTRY_VERIFY(contentItem != 0);
2793 // item at index 10 should not be currently visible
2794 QVERIFY(!findItem<QSGItem>(contentItem, "wrapper", 10));
2796 gridview->setHeight(320);
2797 QTRY_VERIFY(findItem<QSGItem>(contentItem, "wrapper", 10));
2799 gridview->setHeight(100);
2800 QTRY_VERIFY(!findItem<QSGItem>(contentItem, "wrapper", 10));
2805 void tst_QSGGridView::indexAt()
2807 QSGView *canvas = createView();
2810 model.addItem("Fred", "12345");
2811 model.addItem("John", "2345");
2812 model.addItem("Bob", "54321");
2813 model.addItem("Billy", "22345");
2814 model.addItem("Sam", "2945");
2815 model.addItem("Ben", "04321");
2816 model.addItem("Jim", "0780");
2818 QDeclarativeContext *ctxt = canvas->rootContext();
2819 ctxt->setContextProperty("testModel", &model);
2820 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2821 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2823 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2824 qApp->processEvents();
2826 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2827 QTRY_VERIFY(gridview != 0);
2829 QSGItem *contentItem = gridview->contentItem();
2830 QTRY_VERIFY(contentItem != 0);
2832 QTRY_COMPARE(gridview->count(), model.count());
2834 QCOMPARE(gridview->indexAt(0, 0), 0);
2835 QCOMPARE(gridview->indexAt(79, 59), 0);
2836 QCOMPARE(gridview->indexAt(80, 0), 1);
2837 QCOMPARE(gridview->indexAt(0, 60), 3);
2838 QCOMPARE(gridview->indexAt(240, 0), -1);
2843 void tst_QSGGridView::onAdd()
2845 QFETCH(int, initialItemCount);
2846 QFETCH(int, itemsToAdd);
2848 const int delegateWidth = 50;
2849 const int delegateHeight = 100;
2851 QSGView *canvas = createView();
2852 canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
2854 // these initial items should not trigger GridView.onAdd
2855 for (int i=0; i<initialItemCount; i++)
2856 model.addItem("dummy value", "dummy value");
2858 QDeclarativeContext *ctxt = canvas->rootContext();
2859 ctxt->setContextProperty("testModel", &model);
2860 ctxt->setContextProperty("delegateWidth", delegateWidth);
2861 ctxt->setContextProperty("delegateHeight", delegateHeight);
2862 canvas->setSource(QUrl::fromLocalFile(TESTDATA("attachedSignals.qml")));
2864 QObject *object = canvas->rootObject();
2865 object->setProperty("width", canvas->width());
2866 object->setProperty("height", canvas->height());
2867 qApp->processEvents();
2869 QList<QPair<QString, QString> > items;
2870 for (int i=0; i<itemsToAdd; i++)
2871 items << qMakePair(QString("value %1").arg(i), QString::number(i));
2872 model.addItems(items);
2874 QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
2875 qApp->processEvents();
2877 QVariantList result = object->property("addedDelegates").toList();
2878 QTRY_COMPARE(result.count(), items.count());
2879 for (int i=0; i<items.count(); i++)
2880 QCOMPARE(result[i].toString(), items[i].first);
2885 void tst_QSGGridView::onAdd_data()
2887 QTest::addColumn<int>("initialItemCount");
2888 QTest::addColumn<int>("itemsToAdd");
2890 QTest::newRow("0, add 1") << 0 << 1;
2891 QTest::newRow("0, add 2") << 0 << 2;
2892 QTest::newRow("0, add 10") << 0 << 10;
2894 QTest::newRow("1, add 1") << 1 << 1;
2895 QTest::newRow("1, add 2") << 1 << 2;
2896 QTest::newRow("1, add 10") << 1 << 10;
2898 QTest::newRow("5, add 1") << 5 << 1;
2899 QTest::newRow("5, add 2") << 5 << 2;
2900 QTest::newRow("5, add 10") << 5 << 10;
2903 void tst_QSGGridView::onRemove()
2905 QFETCH(int, initialItemCount);
2906 QFETCH(int, indexToRemove);
2907 QFETCH(int, removeCount);
2909 const int delegateWidth = 50;
2910 const int delegateHeight = 100;
2912 for (int i=0; i<initialItemCount; i++)
2913 model.addItem(QString("value %1").arg(i), "dummy value");
2915 QSGView *canvas = createView();
2916 QDeclarativeContext *ctxt = canvas->rootContext();
2917 ctxt->setContextProperty("testModel", &model);
2918 ctxt->setContextProperty("delegateWidth", delegateWidth);
2919 ctxt->setContextProperty("delegateHeight", delegateHeight);
2920 canvas->setSource(QUrl::fromLocalFile(TESTDATA("attachedSignals.qml")));
2921 QObject *object = canvas->rootObject();
2923 model.removeItems(indexToRemove, removeCount);
2924 QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
2925 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2930 void tst_QSGGridView::onRemove_data()
2932 QTest::addColumn<int>("initialItemCount");
2933 QTest::addColumn<int>("indexToRemove");
2934 QTest::addColumn<int>("removeCount");
2936 QTest::newRow("remove first") << 1 << 0 << 1;
2937 QTest::newRow("two items, remove first") << 2 << 0 << 1;
2938 QTest::newRow("two items, remove last") << 2 << 1 << 1;
2939 QTest::newRow("two items, remove all") << 2 << 0 << 2;
2941 QTest::newRow("four items, remove first") << 4 << 0 << 1;
2942 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2943 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2944 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2945 QTest::newRow("four items, remove last") << 4 << 3 << 1;
2946 QTest::newRow("four items, remove all") << 4 << 0 << 4;
2948 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2949 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2950 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2953 void tst_QSGGridView::testQtQuick11Attributes()
2955 QFETCH(QString, code);
2956 QFETCH(QString, warning);
2957 QFETCH(QString, error);
2959 QDeclarativeEngine engine;
2962 QDeclarativeComponent valid(&engine);
2963 valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
2964 obj = valid.create();
2966 QVERIFY(valid.errorString().isEmpty());
2969 QDeclarativeComponent invalid(&engine);
2970 invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
2971 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2972 obj = invalid.create();
2973 QCOMPARE(invalid.errorString(), error);
2977 void tst_QSGGridView::testQtQuick11Attributes_data()
2979 QTest::addColumn<QString>("code");
2980 QTest::addColumn<QString>("warning");
2981 QTest::addColumn<QString>("error");
2983 QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2984 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2987 QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2988 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2992 void tst_QSGGridView::columnCount()
2995 canvas.setSource(QUrl::fromLocalFile(TESTDATA("gridview4.qml")));
2997 canvas.requestActivateWindow();
2998 QTest::qWaitForWindowShown(&canvas);
3000 QSGGridView *view = qobject_cast<QSGGridView*>(canvas.rootObject());
3002 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3003 QCOMPARE(view->cellHeight(), qreal(100));
3005 QList<QSGItem*> items = findItems<QSGItem>(view, "delegate");
3006 QCOMPARE(items.size(), 18);
3007 QCOMPARE(items.at(8)->y(), qreal(0));
3008 QCOMPARE(items.at(9)->y(), qreal(100));
3011 void tst_QSGGridView::margins()
3014 QSGView *canvas = createView();
3018 for (int i = 0; i < 40; i++)
3019 model.addItem("Item" + QString::number(i), "");
3021 QDeclarativeContext *ctxt = canvas->rootContext();
3022 ctxt->setContextProperty("testModel", &model);
3023 ctxt->setContextProperty("testRightToLeft", QVariant(false));
3025 canvas->setSource(QUrl::fromLocalFile(TESTDATA("margins.qml")));
3026 qApp->processEvents();
3028 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
3029 QTRY_VERIFY(gridview != 0);
3031 QSGItem *contentItem = gridview->contentItem();
3032 QTRY_VERIFY(contentItem != 0);
3034 QCOMPARE(gridview->contentX(), -30.);
3035 QCOMPARE(gridview->xOrigin(), 0.);
3038 gridview->positionViewAtEnd();
3039 qreal pos = gridview->contentX();
3040 gridview->setContentX(pos + 80);
3041 gridview->returnToBounds();
3042 QTRY_COMPARE(gridview->contentX(), pos + 50);
3044 // remove item before visible and check that left margin is maintained
3045 // and xOrigin is updated
3046 gridview->setContentX(200);
3047 model.removeItems(0, 4);
3049 gridview->setContentX(-50);
3050 gridview->returnToBounds();
3051 QCOMPARE(gridview->xOrigin(), 100.);
3052 QTRY_COMPARE(gridview->contentX(), 70.);
3054 // reduce left margin
3055 gridview->setLeftMargin(20);
3056 QCOMPARE(gridview->xOrigin(), 100.);
3057 QTRY_COMPARE(gridview->contentX(), 80.);
3060 gridview->positionViewAtEnd();
3061 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3062 pos = gridview->contentX();
3063 gridview->setContentX(pos + 80);
3064 gridview->returnToBounds();
3065 QTRY_COMPARE(gridview->contentX(), pos + 50);
3067 // reduce right margin
3068 pos = gridview->contentX();
3069 gridview->setRightMargin(40);
3070 QCOMPARE(gridview->xOrigin(), 0.);
3071 QTRY_COMPARE(gridview->contentX(), pos-10);
3077 QSGView *canvas = createView();
3081 for (int i = 0; i < 40; i++)
3082 model.addItem("Item" + QString::number(i), "");
3084 QDeclarativeContext *ctxt = canvas->rootContext();
3085 ctxt->setContextProperty("testModel", &model);
3086 ctxt->setContextProperty("testRightToLeft", QVariant(true));
3088 canvas->setSource(QUrl::fromLocalFile(TESTDATA("margins.qml")));
3089 qApp->processEvents();
3091 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
3092 QTRY_VERIFY(gridview != 0);
3094 QSGItem *contentItem = gridview->contentItem();
3095 QTRY_VERIFY(contentItem != 0);
3097 QCOMPARE(gridview->contentX(), -240+30.);
3098 QCOMPARE(gridview->xOrigin(), 0.);
3101 gridview->positionViewAtEnd();
3102 qreal pos = gridview->contentX();
3103 gridview->setContentX(pos - 80);
3104 gridview->returnToBounds();
3105 QTRY_COMPARE(gridview->contentX(), pos - 50);
3107 // remove item before visible and check that left margin is maintained
3108 // and xOrigin is updated
3109 gridview->setContentX(-400);
3110 model.removeItems(0, 4);
3112 gridview->setContentX(-240+50);
3113 gridview->returnToBounds();
3114 QCOMPARE(gridview->xOrigin(), -100.);
3115 QTRY_COMPARE(gridview->contentX(), -240-70.);
3117 // reduce left margin (i.e. right side due to RTL)
3118 pos = gridview->contentX();
3119 gridview->setLeftMargin(20);
3120 QCOMPARE(gridview->xOrigin(), -100.);
3121 QTRY_COMPARE(gridview->contentX(), -240-80.);
3124 gridview->positionViewAtEnd();
3125 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
3126 pos = gridview->contentX();
3127 gridview->setContentX(pos - 80);
3128 gridview->returnToBounds();
3129 QTRY_COMPARE(gridview->contentX(), pos - 50);
3131 // reduce right margin (i.e. left side due to RTL)
3132 pos = gridview->contentX();
3133 gridview->setRightMargin(40);
3134 QCOMPARE(gridview->xOrigin(), 0.);
3135 QTRY_COMPARE(gridview->contentX(), pos+10);
3141 void tst_QSGGridView::creationContext()
3144 canvas.setGeometry(0,0,240,320);
3145 canvas.setSource(QUrl::fromLocalFile(TESTDATA("creationContext.qml")));
3146 qApp->processEvents();
3148 QSGItem *rootItem = qobject_cast<QSGItem *>(canvas.rootObject());
3150 QVERIFY(rootItem->property("count").toInt() > 0);
3153 QVERIFY(item = rootItem->findChild<QSGItem *>("listItem"));
3154 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3155 QVERIFY(item = rootItem->findChild<QSGItem *>("header"));
3156 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3157 QVERIFY(item = rootItem->findChild<QSGItem *>("footer"));
3158 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3161 void tst_QSGGridView::snapToRow_data()
3163 QTest::addColumn<QSGGridView::Flow>("flow");
3164 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
3165 QTest::addColumn<int>("highlightRangeMode");
3166 QTest::addColumn<QPoint>("flickStart");
3167 QTest::addColumn<QPoint>("flickEnd");
3168 QTest::addColumn<qreal>("snapAlignment");
3169 QTest::addColumn<qreal>("endExtent");
3170 QTest::addColumn<qreal>("startExtent");
3172 QTest::newRow("vertical, left to right") << QSGGridView::LeftToRight << Qt::LeftToRight << int(QSGItemView::NoHighlightRange)
3173 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3175 QTest::newRow("horizontal, left to right") << QSGGridView::TopToBottom << Qt::LeftToRight << int(QSGItemView::NoHighlightRange)
3176 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3178 QTest::newRow("horizontal, right to left") << QSGGridView::TopToBottom << Qt::RightToLeft << int(QSGItemView::NoHighlightRange)
3179 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 << -240.0;
3181 QTest::newRow("vertical, left to right, enforce range") << QSGGridView::LeftToRight << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange)
3182 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3184 QTest::newRow("horizontal, left to right, enforce range") << QSGGridView::TopToBottom << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange)
3185 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3187 QTest::newRow("horizontal, right to left, enforce range") << QSGGridView::TopToBottom << Qt::RightToLeft << int(QSGItemView::StrictlyEnforceRange)
3188 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0;
3191 void tst_QSGGridView::snapToRow()
3193 QFETCH(QSGGridView::Flow, flow);
3194 QFETCH(Qt::LayoutDirection, layoutDirection);
3195 QFETCH(int, highlightRangeMode);
3196 QFETCH(QPoint, flickStart);
3197 QFETCH(QPoint, flickEnd);
3198 QFETCH(qreal, snapAlignment);
3199 QFETCH(qreal, endExtent);
3200 QFETCH(qreal, startExtent);
3202 QSGView *canvas = createView();
3204 canvas->setSource(QUrl::fromLocalFile(TESTDATA("snapToRow.qml")));
3206 qApp->processEvents();
3208 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
3209 QTRY_VERIFY(gridview != 0);
3211 gridview->setFlow(flow);
3212 gridview->setLayoutDirection(layoutDirection);
3213 gridview->setHighlightRangeMode(QSGItemView::HighlightRangeMode(highlightRangeMode));
3215 QSGItem *contentItem = gridview->contentItem();
3216 QTRY_VERIFY(contentItem != 0);
3218 // confirm that a flick hits an item boundary
3219 flick(canvas, flickStart, flickEnd, 180);
3220 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3221 if (flow == QSGGridView::LeftToRight)
3222 QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment);
3224 QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment);
3228 flick(canvas, flickStart, flickEnd, 180);
3229 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3230 } while (flow == QSGGridView::LeftToRight
3231 ? !gridview->isAtYEnd()
3232 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3234 if (flow == QSGGridView::LeftToRight)
3235 QCOMPARE(gridview->contentY(), endExtent);
3237 QCOMPARE(gridview->contentX(), endExtent);
3241 flick(canvas, flickEnd, flickStart, 180);
3242 QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops
3243 } while (flow == QSGGridView::LeftToRight
3244 ? !gridview->isAtYBeginning()
3245 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3247 if (flow == QSGGridView::LeftToRight)
3248 QCOMPARE(gridview->contentY(), startExtent);
3250 QCOMPARE(gridview->contentX(), startExtent);
3256 QSGView *tst_QSGGridView::createView()
3258 QSGView *canvas = new QSGView(0);
3259 canvas->setGeometry(0,0,240,320);
3264 void tst_QSGGridView::flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration)
3266 const int pointCount = 5;
3267 QPoint diff = to - from;
3269 // send press, five equally spaced moves, and release.
3270 QTest::mousePress(canvas, Qt::LeftButton, 0, from);
3272 for (int i = 0; i < pointCount; ++i) {
3273 QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
3274 QApplication::sendEvent(canvas, &mv);
3275 QTest::qWait(duration/pointCount);
3276 QCoreApplication::processEvents();
3279 QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
3283 Find an item with the specified objectName. If index is supplied then the
3284 item must also evaluate the {index} expression equal to index
3286 template<typename T>
3287 T *tst_QSGGridView::findItem(QSGItem *parent, const QString &objectName, int index)
3289 const QMetaObject &mo = T::staticMetaObject;
3290 //qDebug() << parent->childItems().count() << "children";
3291 for (int i = 0; i < parent->childItems().count(); ++i) {
3292 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3295 //qDebug() << "try" << item;
3296 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
3298 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3300 if (context->contextProperty("index").toInt() == index) {
3301 return static_cast<T*>(item);
3305 return static_cast<T*>(item);
3308 item = findItem<T>(item, objectName, index);
3310 return static_cast<T*>(item);
3316 template<typename T>
3317 QList<T*> tst_QSGGridView::findItems(QSGItem *parent, const QString &objectName)
3320 const QMetaObject &mo = T::staticMetaObject;
3321 //qDebug() << parent->childItems().count() << "children";
3322 for (int i = 0; i < parent->childItems().count(); ++i) {
3323 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3326 //qDebug() << "try" << item;
3327 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
3328 items.append(static_cast<T*>(item));
3329 //qDebug() << " found:" << item;
3331 items += findItems<T>(item, objectName);
3337 void tst_QSGGridView::dumpTree(QSGItem *parent, int depth)
3339 static QString padding(" ");
3340 for (int i = 0; i < parent->childItems().count(); ++i) {
3341 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3344 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3345 qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
3346 dumpTree(item, depth+1);
3351 QTEST_MAIN(tst_QSGGridView)
3353 #include "tst_qsggridview.moc"