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/qquickview.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/qquickitem_p.h>
50 #include <QtDeclarative/private/qlistmodelinterface_p.h>
51 #include <QtDeclarative/private/qquickgridview_p.h>
52 #include <QtDeclarative/private/qquicktext_p.h>
53 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
54 #include "../shared/util.h"
55 #include <QtGui/qguiapplication.h>
57 Q_DECLARE_METATYPE(Qt::LayoutDirection)
58 Q_DECLARE_METATYPE(QQuickGridView::Flow)
60 class tst_QQuickGridView : public QObject
68 void cleanupTestCase();
73 void inserted_more_data();
78 void multipleChanges();
79 void multipleChanges_data();
80 void swapWithFirstItem();
83 void noCurrentIndex();
86 void propertyChanges();
87 void componentChanges();
89 void positionViewAtIndex();
90 void positionViewAtIndex_rightToLeft();
95 void enforceRange_rightToLeft();
97 void manualHighlight();
102 void resizeViewAndRepaint();
107 void onRemove_data();
108 void testQtQuick11Attributes();
109 void testQtQuick11Attributes_data();
112 void creationContext();
113 void snapToRow_data();
117 QQuickView *createView();
118 void flick(QQuickView *canvas, const QPoint &from, const QPoint &to, int duration);
120 T *findItem(QQuickItem *parent, const QString &id, int index=-1);
122 QList<T*> findItems(QQuickItem *parent, const QString &objectName);
123 void dumpTree(QQuickItem *parent, int depth = 0);
127 void tst_qquickgridview_move(int from, int to, int n, T *items)
130 items->move(from, to);
134 typename T::ConstIterator it=items->begin(); it += from+n;
135 for (; i<to-from; ++i,++it)
136 replaced.append(*it);
138 it=items->begin(); it += from;
139 for (; i<n; ++i,++it)
140 replaced.append(*it);
141 typename T::ConstIterator f=replaced.begin();
142 typename T::Iterator t=items->begin(); t += from;
143 for (; f != replaced.end(); ++f, ++t)
148 void tst_QQuickGridView::initTestCase()
152 void tst_QQuickGridView::cleanupTestCase()
158 class TestModel : public QAbstractListModel
161 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
163 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
164 QHash<int, QByteArray> roles;
165 roles[Name] = "name";
166 roles[Number] = "number";
170 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
171 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
174 rv = list.at(index.row()).first;
175 else if (role == Number)
176 rv = list.at(index.row()).second;
181 int count() const { return rowCount(); }
182 QString name(int index) const { return list.at(index).first; }
183 QString number(int index) const { return list.at(index).second; }
185 void addItem(const QString &name, const QString &number) {
186 emit beginInsertRows(QModelIndex(), list.count(), list.count());
187 list.append(QPair<QString,QString>(name, number));
188 emit endInsertRows();
191 void addItems(const QList<QPair<QString, QString> > &items) {
192 emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
193 for (int i=0; i<items.count(); i++)
194 list.append(QPair<QString,QString>(items[i].first, items[i].second));
195 emit endInsertRows();
198 void insertItem(int index, const QString &name, const QString &number) {
199 emit beginInsertRows(QModelIndex(), index, index);
200 list.insert(index, QPair<QString,QString>(name, number));
201 emit endInsertRows();
204 void insertItems(int index, const QList<QPair<QString, QString> > &items) {
205 emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
206 for (int i=0; i<items.count(); i++)
207 list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
208 emit endInsertRows();
211 void removeItem(int index) {
212 emit beginRemoveRows(QModelIndex(), index, index);
213 list.removeAt(index);
214 emit endRemoveRows();
217 void removeItems(int index, int count) {
218 emit beginRemoveRows(QModelIndex(), index, index+count-1);
220 list.removeAt(index);
221 emit endRemoveRows();
224 void moveItem(int from, int to) {
225 emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
230 void moveItems(int from, int to, int count) {
231 emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
232 tst_qquickgridview_move(from, to, count, &list);
236 void modifyItem(int idx, const QString &name, const QString &number) {
237 list[idx] = QPair<QString,QString>(name, number);
238 emit dataChanged(index(idx,0), index(idx,0));
242 int count = list.count();
243 emit beginRemoveRows(QModelIndex(), 0, count-1);
245 emit endRemoveRows();
250 QList<QPair<QString,QString> > list;
253 tst_QQuickGridView::tst_QQuickGridView()
257 void tst_QQuickGridView::items()
259 QQuickView *canvas = createView();
262 model.addItem("Fred", "12345");
263 model.addItem("John", "2345");
264 model.addItem("Bob", "54321");
265 model.addItem("Billy", "22345");
266 model.addItem("Sam", "2945");
267 model.addItem("Ben", "04321");
268 model.addItem("Jim", "0780");
270 QDeclarativeContext *ctxt = canvas->rootContext();
271 ctxt->setContextProperty("testModel", &model);
272 ctxt->setContextProperty("testRightToLeft", QVariant(false));
273 ctxt->setContextProperty("testTopToBottom", QVariant(false));
275 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
276 qApp->processEvents();
278 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
279 QTRY_VERIFY(gridview != 0);
281 QQuickItem *contentItem = gridview->contentItem();
282 QTRY_VERIFY(contentItem != 0);
284 QTRY_COMPARE(gridview->count(), model.count());
285 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
286 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
288 for (int i = 0; i < model.count(); ++i) {
289 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
290 QTRY_VERIFY(name != 0);
291 QTRY_COMPARE(name->text(), model.name(i));
292 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
293 QTRY_VERIFY(number != 0);
294 QTRY_COMPARE(number->text(), model.number(i));
297 // set an empty model and confirm that items are destroyed
299 ctxt->setContextProperty("testModel", &model2);
301 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
302 QTRY_VERIFY(itemCount == 0);
307 void tst_QQuickGridView::changed()
309 QQuickView *canvas = createView();
312 model.addItem("Fred", "12345");
313 model.addItem("John", "2345");
314 model.addItem("Bob", "54321");
315 model.addItem("Billy", "22345");
316 model.addItem("Sam", "2945");
317 model.addItem("Ben", "04321");
318 model.addItem("Jim", "0780");
320 QDeclarativeContext *ctxt = canvas->rootContext();
321 ctxt->setContextProperty("testModel", &model);
322 ctxt->setContextProperty("testRightToLeft", QVariant(false));
323 ctxt->setContextProperty("testTopToBottom", QVariant(false));
325 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
326 qApp->processEvents();
328 QQuickFlickable *gridview = findItem<QQuickFlickable>(canvas->rootObject(), "grid");
329 QTRY_VERIFY(gridview != 0);
331 QQuickItem *contentItem = gridview->contentItem();
332 QTRY_VERIFY(contentItem != 0);
334 model.modifyItem(1, "Will", "9876");
335 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
336 QTRY_VERIFY(name != 0);
337 QTRY_COMPARE(name->text(), model.name(1));
338 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
339 QTRY_VERIFY(number != 0);
340 QTRY_COMPARE(number->text(), model.number(1));
345 void tst_QQuickGridView::inserted()
347 QQuickView *canvas = createView();
351 model.addItem("Fred", "12345");
352 model.addItem("John", "2345");
353 model.addItem("Bob", "54321");
355 QDeclarativeContext *ctxt = canvas->rootContext();
356 ctxt->setContextProperty("testModel", &model);
357 ctxt->setContextProperty("testRightToLeft", QVariant(false));
358 ctxt->setContextProperty("testTopToBottom", QVariant(false));
360 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
361 qApp->processEvents();
363 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
364 QTRY_VERIFY(gridview != 0);
366 QQuickItem *contentItem = gridview->contentItem();
367 QTRY_VERIFY(contentItem != 0);
369 model.insertItem(1, "Will", "9876");
371 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
372 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
374 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
375 QTRY_VERIFY(name != 0);
376 QTRY_COMPARE(name->text(), model.name(1));
377 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
378 QTRY_VERIFY(number != 0);
379 QTRY_COMPARE(number->text(), model.number(1));
381 // Checks that onAdd is called
382 int added = canvas->rootObject()->property("added").toInt();
383 QTRY_COMPARE(added, 1);
385 // Confirm items positioned correctly
386 for (int i = 0; i < model.count(); ++i) {
387 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
388 QTRY_COMPARE(item->x(), (i%3)*80.0);
389 QTRY_COMPARE(item->y(), (i/3)*60.0);
392 model.insertItem(0, "Foo", "1111"); // zero index, and current item
394 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
396 name = findItem<QQuickText>(contentItem, "textName", 0);
397 QTRY_VERIFY(name != 0);
398 QTRY_COMPARE(name->text(), model.name(0));
399 number = findItem<QQuickText>(contentItem, "textNumber", 0);
400 QTRY_VERIFY(number != 0);
401 QTRY_COMPARE(number->text(), model.number(0));
403 QTRY_COMPARE(gridview->currentIndex(), 1);
405 // Confirm items positioned correctly
406 for (int i = 0; i < model.count(); ++i) {
407 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
408 QTRY_VERIFY(item->x() == (i%3)*80);
409 QTRY_VERIFY(item->y() == (i/3)*60);
412 for (int i = model.count(); i < 30; ++i)
413 model.insertItem(i, "Hello", QString::number(i));
415 gridview->setContentY(120);
417 // Insert item outside visible area
418 model.insertItem(1, "Hello", "1324");
420 QTRY_VERIFY(gridview->contentY() == 120);
425 void tst_QQuickGridView::inserted_more()
427 QFETCH(qreal, contentY);
428 QFETCH(int, insertIndex);
429 QFETCH(int, insertCount);
430 QFETCH(qreal, itemsOffsetAfterMove);
434 QQuickView *canvas = createView();
438 for (int i = 0; i < 30; i++)
439 model.addItem("Item" + QString::number(i), "");
441 QDeclarativeContext *ctxt = canvas->rootContext();
442 ctxt->setContextProperty("testModel", &model);
443 ctxt->setContextProperty("testRightToLeft", QVariant(false));
444 ctxt->setContextProperty("testTopToBottom", QVariant(false));
446 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
447 qApp->processEvents();
449 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
450 QTRY_VERIFY(gridview != 0);
451 QQuickItem *contentItem = gridview->contentItem();
452 QTRY_VERIFY(contentItem != 0);
454 gridview->setContentY(contentY);
456 QList<QPair<QString, QString> > newData;
457 for (int i=0; i<insertCount; i++)
458 newData << qMakePair(QString("value %1").arg(i), QString::number(i));
459 model.insertItems(insertIndex, newData);
460 QTRY_COMPARE(gridview->property("count").toInt(), model.count());
462 // check visibleItems.first() is in correct position
463 QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
465 QCOMPARE(item0->y(), itemsOffsetAfterMove);
467 QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
468 int firstVisibleIndex = -1;
469 for (int i=0; i<items.count(); i++) {
470 if (items[i]->y() >= contentY) {
471 QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
472 firstVisibleIndex = e.evaluate().toInt();
476 QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
478 // Confirm items positioned correctly and indexes correct
479 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
480 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
481 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
482 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
484 QCOMPARE(item->x(), (i%3)*80.0);
485 QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
487 name = findItem<QQuickText>(contentItem, "textName", i);
489 QCOMPARE(name->text(), model.name(i));
490 number = findItem<QQuickText>(contentItem, "textNumber", i);
491 QVERIFY(number != 0);
492 QCOMPARE(number->text(), model.number(i));
498 void tst_QQuickGridView::inserted_more_data()
500 QTest::addColumn<qreal>("contentY");
501 QTest::addColumn<int>("insertIndex");
502 QTest::addColumn<int>("insertCount");
503 QTest::addColumn<qreal>("itemsOffsetAfterMove");
505 QTest::newRow("add 1, before visible items")
506 << 120.0 // show 6-23
508 << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row
509 // new 1st visible item is at 0
511 QTest::newRow("add 2, before visible items")
512 << 120.0 // show 6-23
514 << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row
516 QTest::newRow("add 3, before visible items")
517 << 120.0 // show 6-23
519 << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move
521 QTest::newRow("add 5, before visible items")
522 << 120.0 // show 6-23
524 << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos,
525 // grid is rearranged and first visible moves forward within its row
527 QTest::newRow("add 6, before visible items")
528 << 120.0 // show 6-23
530 << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move
534 QTest::newRow("add 1, at start of visible, content at start")
539 QTest::newRow("add multiple, at start of visible, content at start")
544 QTest::newRow("add 1, at start of visible, content not at start")
545 << 120.0 // show 6-23
549 QTest::newRow("add multiple, at start of visible, content not at start")
550 << 120.0 // show 6-23
555 QTest::newRow("add 1, at end of visible, content at start")
560 QTest::newRow("add 1, at end of visible, content at start")
565 QTest::newRow("add 1, at end of visible, content not at start")
566 << 120.0 // show 6-23
570 QTest::newRow("add multiple, at end of visible, content not at start")
571 << 120.0 // show 6-23
576 QTest::newRow("add 1, after visible, content at start")
581 QTest::newRow("add 1, after visible, content at start")
586 QTest::newRow("add 1, after visible, content not at start")
587 << 120.0 // show 6-23
591 QTest::newRow("add multiple, after visible, content not at start")
592 << 120.0 // show 6-23
597 void tst_QQuickGridView::removed()
599 QQuickView *canvas = createView();
603 for (int i = 0; i < 40; i++)
604 model.addItem("Item" + QString::number(i), "");
606 QDeclarativeContext *ctxt = canvas->rootContext();
607 ctxt->setContextProperty("testModel", &model);
608 ctxt->setContextProperty("testRightToLeft", QVariant(false));
609 ctxt->setContextProperty("testTopToBottom", QVariant(false));
611 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
612 qApp->processEvents();
614 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
615 QTRY_VERIFY(gridview != 0);
617 QQuickItem *contentItem = gridview->contentItem();
618 QTRY_VERIFY(contentItem != 0);
621 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
623 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
624 QTRY_VERIFY(name != 0);
625 QTRY_COMPARE(name->text(), model.name(1));
626 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1);
627 QTRY_VERIFY(number != 0);
628 QTRY_COMPARE(number->text(), model.number(1));
631 // Checks that onRemove is called
632 QString removed = canvas->rootObject()->property("removed").toString();
633 QTRY_COMPARE(removed, QString("Item1"));
635 // Confirm items positioned correctly
636 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
637 for (int i = 0; i < model.count() && i < itemCount; ++i) {
638 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
639 if (!item) qWarning() << "Item" << i << "not found";
640 QTRY_VERIFY(item->x() == (i%3)*80);
641 QTRY_VERIFY(item->y() == (i/3)*60);
644 // Remove first item (which is the current item);
646 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
648 name = findItem<QQuickText>(contentItem, "textName", 0);
649 QTRY_VERIFY(name != 0);
650 QTRY_COMPARE(name->text(), model.name(0));
651 number = findItem<QQuickText>(contentItem, "textNumber", 0);
652 QTRY_VERIFY(number != 0);
653 QTRY_COMPARE(number->text(), model.number(0));
656 // Confirm items positioned correctly
657 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
658 for (int i = 0; i < model.count() && i < itemCount; ++i) {
659 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
660 if (!item) qWarning() << "Item" << i << "not found";
661 QTRY_VERIFY(item->x() == (i%3)*80);
662 QTRY_VERIFY(item->y() == (i/3)*60);
665 // Remove items not visible
666 model.removeItem(25);
667 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
669 // Confirm items positioned correctly
670 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
671 for (int i = 0; i < model.count() && i < itemCount; ++i) {
672 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
673 if (!item) qWarning() << "Item" << i << "not found";
674 QTRY_VERIFY(item->x() == (i%3)*80);
675 QTRY_VERIFY(item->y() == (i/3)*60);
678 // Remove items before visible
679 gridview->setContentY(120);
680 gridview->setCurrentIndex(10);
682 // Setting currentIndex above shouldn't cause view to scroll
683 QTRY_COMPARE(gridview->contentY(), 120.0);
686 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
688 // Confirm items positioned correctly
689 for (int i = 6; i < 18; ++i) {
690 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
691 if (!item) qWarning() << "Item" << i << "not found";
692 QTRY_VERIFY(item->x() == (i%3)*80);
693 QTRY_VERIFY(item->y() == (i/3)*60);
696 // Remove currentIndex
697 QQuickItem *oldCurrent = gridview->currentItem();
699 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
701 QTRY_COMPARE(gridview->currentIndex(), 9);
702 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
704 gridview->setContentY(0);
705 // let transitions settle.
708 // Confirm items positioned correctly
709 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
710 for (int i = 0; i < model.count() && i < itemCount; ++i) {
711 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
712 QTRY_VERIFY(item->x() == (i%3)*80);
713 QTRY_VERIFY(item->y() == (i/3)*60);
716 // remove item outside current view.
717 gridview->setCurrentIndex(32);
718 gridview->setContentY(240);
720 model.removeItem(30);
721 QTRY_VERIFY(gridview->currentIndex() == 31);
723 // remove current item beyond visible items.
724 gridview->setCurrentIndex(20);
725 gridview->setContentY(0);
726 model.removeItem(20);
728 QTRY_COMPARE(gridview->currentIndex(), 20);
729 QTRY_VERIFY(gridview->currentItem() != 0);
731 // remove item before current, but visible
732 gridview->setCurrentIndex(8);
733 gridview->setContentY(240);
734 oldCurrent = gridview->currentItem();
737 QTRY_COMPARE(gridview->currentIndex(), 7);
738 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
743 void tst_QQuickGridView::clear()
745 QQuickView *canvas = createView();
748 for (int i = 0; i < 30; i++)
749 model.addItem("Item" + QString::number(i), "");
751 QDeclarativeContext *ctxt = canvas->rootContext();
752 ctxt->setContextProperty("testModel", &model);
753 ctxt->setContextProperty("testRightToLeft", QVariant(false));
754 ctxt->setContextProperty("testTopToBottom", QVariant(false));
756 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
757 qApp->processEvents();
759 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
760 QVERIFY(gridview != 0);
762 QQuickItem *contentItem = gridview->contentItem();
763 QVERIFY(contentItem != 0);
767 QVERIFY(gridview->count() == 0);
768 QVERIFY(gridview->currentItem() == 0);
769 QVERIFY(gridview->contentY() == 0);
770 QVERIFY(gridview->currentIndex() == -1);
772 // confirm sanity when adding an item to cleared list
773 model.addItem("New", "1");
774 QTRY_COMPARE(gridview->count(), 1);
775 QVERIFY(gridview->currentItem() != 0);
776 QVERIFY(gridview->currentIndex() == 0);
781 void tst_QQuickGridView::moved()
783 QFETCH(qreal, contentY);
787 QFETCH(qreal, itemsOffsetAfterMove);
791 QQuickView *canvas = createView();
795 for (int i = 0; i < 30; i++)
796 model.addItem("Item" + QString::number(i), "");
798 QDeclarativeContext *ctxt = canvas->rootContext();
799 ctxt->setContextProperty("testModel", &model);
800 ctxt->setContextProperty("testRightToLeft", QVariant(false));
801 ctxt->setContextProperty("testTopToBottom", QVariant(false));
803 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
804 qApp->processEvents();
806 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
807 QTRY_VERIFY(gridview != 0);
809 QQuickItem *contentItem = gridview->contentItem();
810 QTRY_VERIFY(contentItem != 0);
812 QQuickItem *currentItem = gridview->currentItem();
813 QTRY_VERIFY(currentItem != 0);
815 gridview->setContentY(contentY);
816 model.moveItems(from, to, count);
818 // wait for items to move
821 // Confirm items positioned correctly and indexes correct
822 int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
823 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
824 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
825 if (i >= firstVisibleIndex + 18) // index has moved out of view
827 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
828 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
830 QTRY_COMPARE(item->x(), (i%3)*80.0);
831 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
833 name = findItem<QQuickText>(contentItem, "textName", i);
835 QTRY_COMPARE(name->text(), model.name(i));
836 number = findItem<QQuickText>(contentItem, "textNumber", i);
837 QVERIFY(number != 0);
838 QTRY_COMPARE(number->text(), model.number(i));
840 // current index should have been updated
841 if (item == currentItem)
842 QTRY_COMPARE(gridview->currentIndex(), i);
848 void tst_QQuickGridView::moved_data()
850 QTest::addColumn<qreal>("contentY");
851 QTest::addColumn<int>("from");
852 QTest::addColumn<int>("to");
853 QTest::addColumn<int>("count");
854 QTest::addColumn<qreal>("itemsOffsetAfterMove");
856 // model starts with 30 items, each 80x60, in area 240x320
857 // 18 items should be visible at a time
859 QTest::newRow("move 1 forwards, within visible items")
864 QTest::newRow("move 1 forwards, from non-visible -> visible")
865 << 120.0 // show 6-23
867 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
869 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
870 << 120.0 // // show 6-23
872 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
874 QTest::newRow("move 1 forwards, from visible -> non-visible")
879 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
885 QTest::newRow("move 1 backwards, within visible items")
890 QTest::newRow("move 1 backwards, within visible items (to first index)")
895 QTest::newRow("move 1 backwards, from non-visible -> visible")
900 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
905 QTest::newRow("move 1 backwards, from visible -> non-visible")
906 << 120.0 // show 6-23
908 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
910 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
911 << 120.0 // show 6-23
913 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
916 QTest::newRow("move multiple forwards, within visible items")
921 QTest::newRow("move multiple forwards, before visible items")
922 << 120.0 // show 6-23
923 << 3 << 4 << 3 // 3, 4, 5 move to after 6
924 << 60.0; // row of 3,4,5 has moved down
926 QTest::newRow("move multiple forwards, from non-visible -> visible")
927 << 120.0 // show 6-23
929 << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
931 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
932 << 120.0 // show 6-23
934 << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
936 QTest::newRow("move multiple forwards, from visible -> non-visible")
941 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
947 QTest::newRow("move multiple backwards, within visible items")
952 QTest::newRow("move multiple backwards, from non-visible -> visible")
957 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
962 QTest::newRow("move multiple backwards, from visible -> non-visible")
963 << 120.0 // show 6-23
965 << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
967 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
968 << 120.0 // show 6-23
970 << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
974 enum { Inserted, Removed, Moved, SetCurrent } type;
979 static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
980 static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
981 static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
982 static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
984 Q_DECLARE_METATYPE(QList<ListChange>)
986 void tst_QQuickGridView::multipleChanges()
988 QFETCH(int, startCount);
989 QFETCH(QList<ListChange>, changes);
990 QFETCH(int, newCount);
991 QFETCH(int, newCurrentIndex);
993 QQuickView *canvas = createView();
997 for (int i = 0; i < startCount; i++)
998 model.addItem("Item" + QString::number(i), "");
1000 QDeclarativeContext *ctxt = canvas->rootContext();
1001 ctxt->setContextProperty("testModel", &model);
1002 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1003 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1005 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1006 qApp->processEvents();
1008 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1009 QTRY_VERIFY(gridview != 0);
1011 for (int i=0; i<changes.count(); i++) {
1012 switch (changes[i].type) {
1013 case ListChange::Inserted:
1015 QList<QPair<QString, QString> > items;
1016 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
1017 items << qMakePair(QString("new item " + j), QString::number(j));
1018 model.insertItems(changes[i].index, items);
1021 case ListChange::Removed:
1022 model.removeItems(changes[i].index, changes[i].count);
1024 case ListChange::Moved:
1025 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
1027 case ListChange::SetCurrent:
1028 gridview->setCurrentIndex(changes[i].index);
1033 QTRY_COMPARE(gridview->count(), newCount);
1034 QCOMPARE(gridview->count(), model.count());
1035 QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
1039 QQuickItem *contentItem = gridview->contentItem();
1040 QTRY_VERIFY(contentItem != 0);
1041 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1042 for (int i=0; i < model.count() && i < itemCount; ++i) {
1043 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1044 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
1045 name = findItem<QQuickText>(contentItem, "textName", i);
1047 QTRY_COMPARE(name->text(), model.name(i));
1048 number = findItem<QQuickText>(contentItem, "textNumber", i);
1049 QVERIFY(number != 0);
1050 QTRY_COMPARE(number->text(), model.number(i));
1056 void tst_QQuickGridView::multipleChanges_data()
1058 QTest::addColumn<int>("startCount");
1059 QTest::addColumn<QList<ListChange> >("changes");
1060 QTest::addColumn<int>("newCount");
1061 QTest::addColumn<int>("newCurrentIndex");
1063 QList<ListChange> changes;
1065 for (int i=1; i<30; i++)
1066 changes << ListChange::remove(0);
1067 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
1069 changes << ListChange::remove(0);
1070 QTest::newRow("remove all") << 30 << changes << 0 << -1;
1073 changes << ListChange::setCurrent(29);
1074 for (int i=29; i>0; i--)
1075 changes << ListChange::remove(i);
1076 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
1078 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
1079 << ListChange::remove(0, 1)
1080 << ListChange::insert(0, 1)
1083 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
1084 << ListChange::setCurrent(2)
1085 << ListChange::remove(2, 1)
1086 << ListChange::insert(2, 1)
1089 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
1090 << ListChange::setCurrent(1)
1091 << ListChange::remove(1, 3)
1092 << ListChange::insert(2, 2)
1095 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
1096 << ListChange::setCurrent(2)
1097 << ListChange::remove(1, 3)
1098 << ListChange::move(1, 5, 1)
1101 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
1102 << ListChange::setCurrent(5)
1103 << ListChange::remove(4, 3)
1104 << ListChange::move(4, 1, 1)
1108 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
1109 << ListChange::insert(0, 2)
1110 << ListChange::insert(0, 4)
1111 << ListChange::insert(0, 6)
1114 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
1115 << ListChange::insert(0, 2)
1116 << ListChange::insert(0, 4)
1117 << ListChange::insert(0, 6)
1118 << ListChange::setCurrent(3)
1119 << ListChange::insert(3, 2)
1122 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
1123 << ListChange::insert(0, 30)
1124 << ListChange::remove(0, 30)
1127 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
1128 << ListChange::insert(1)
1129 << ListChange::setCurrent(1)
1130 << ListChange::remove(1)
1133 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
1134 << ListChange::insert(0, 10)
1135 << ListChange::remove(5, 10)
1138 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
1139 << ListChange::insert(0, 3)
1140 << ListChange::move(0, 10, 3)
1143 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
1144 << ListChange::insert(0, 3)
1145 << ListChange::move(0, 8, 5)
1148 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
1149 << ListChange::setCurrent(9)
1150 << ListChange::insert(10, 3)
1151 << ListChange::move(8, 0, 5)
1155 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
1156 << ListChange::setCurrent(1)
1157 << ListChange::move(1, 2, 2)
1158 << ListChange::move(2, 1, 2)
1161 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
1162 << ListChange::setCurrent(2)
1163 << ListChange::move(1, 2, 3)
1164 << ListChange::move(3, 0, 5)
1167 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
1168 << ListChange::setCurrent(5)
1169 << ListChange::move(5, 0, 1)
1170 << ListChange::remove(0)
1173 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
1174 << ListChange::setCurrent(5)
1175 << ListChange::move(5, 0, 1)
1176 << ListChange::insert(0)
1179 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1180 << ListChange::setCurrent(1)
1181 << ListChange::move(5, 1, 3)
1182 << ListChange::remove(1, 3)
1185 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1186 << ListChange::setCurrent(5)
1187 << ListChange::move(5, 1, 3)
1188 << ListChange::insert(1, 5)
1191 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1192 << ListChange::setCurrent(3)
1193 << ListChange::move(0, 1, 2)
1194 << ListChange::insert(3, 5)
1198 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1199 << ListChange::insert(0, 5)
1200 << ListChange::setCurrent(-1)
1201 << ListChange::remove(0, 5)
1202 << ListChange::insert(0, 5)
1207 void tst_QQuickGridView::swapWithFirstItem()
1210 QQuickView *canvas = createView();
1214 for (int i = 0; i < 30; i++)
1215 model.addItem("Item" + QString::number(i), "");
1217 QDeclarativeContext *ctxt = canvas->rootContext();
1218 ctxt->setContextProperty("testModel", &model);
1219 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1220 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1222 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1223 qApp->processEvents();
1225 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1226 QTRY_VERIFY(gridview != 0);
1228 // ensure content position is stable
1229 gridview->setContentY(0);
1230 model.moveItem(10, 0);
1231 QTRY_VERIFY(gridview->contentY() == 0);
1236 void tst_QQuickGridView::currentIndex()
1239 for (int i = 0; i < 60; i++)
1240 model.addItem("Item" + QString::number(i), QString::number(i));
1242 QQuickView *canvas = new QQuickView(0);
1243 canvas->setGeometry(0,0,240,320);
1246 QDeclarativeContext *ctxt = canvas->rootContext();
1247 ctxt->setContextProperty("testModel", &model);
1249 QString filename(TESTDATA("gridview-initCurrent.qml"));
1250 canvas->setSource(QUrl::fromLocalFile(filename));
1252 qApp->processEvents();
1254 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1255 QVERIFY(gridview != 0);
1257 QQuickItem *contentItem = gridview->contentItem();
1258 QVERIFY(contentItem != 0);
1260 // current item should be third item
1261 QCOMPARE(gridview->currentIndex(), 35);
1262 QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35));
1263 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1264 QCOMPARE(gridview->contentY(), 400.0);
1266 gridview->moveCurrentIndexRight();
1267 QCOMPARE(gridview->currentIndex(), 36);
1268 gridview->moveCurrentIndexDown();
1269 QCOMPARE(gridview->currentIndex(), 39);
1270 gridview->moveCurrentIndexUp();
1271 QCOMPARE(gridview->currentIndex(), 36);
1272 gridview->moveCurrentIndexLeft();
1273 QCOMPARE(gridview->currentIndex(), 35);
1276 gridview->setCurrentIndex(0);
1277 QCOMPARE(gridview->currentIndex(), 0);
1278 // confirm that the velocity is updated
1279 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1281 gridview->moveCurrentIndexUp();
1282 QCOMPARE(gridview->currentIndex(), 0);
1284 gridview->moveCurrentIndexLeft();
1285 QCOMPARE(gridview->currentIndex(), 0);
1287 gridview->setCurrentIndex(model.count()-1);
1288 QCOMPARE(gridview->currentIndex(), model.count()-1);
1290 gridview->moveCurrentIndexRight();
1291 QCOMPARE(gridview->currentIndex(), model.count()-1);
1293 gridview->moveCurrentIndexDown();
1294 QCOMPARE(gridview->currentIndex(), model.count()-1);
1297 gridview->setWrapEnabled(true);
1299 gridview->setCurrentIndex(0);
1300 QCOMPARE(gridview->currentIndex(), 0);
1302 gridview->moveCurrentIndexLeft();
1303 QCOMPARE(gridview->currentIndex(), model.count()-1);
1305 qApp->processEvents();
1306 QTRY_COMPARE(gridview->contentY(), 880.0);
1308 gridview->moveCurrentIndexRight();
1309 QCOMPARE(gridview->currentIndex(), 0);
1311 QTRY_COMPARE(gridview->contentY(), 0.0);
1314 // footer should become visible if it is out of view, and then current index moves to the first row
1315 canvas->rootObject()->setProperty("showFooter", true);
1316 QTRY_VERIFY(gridview->footerItem());
1317 gridview->setCurrentIndex(model.count()-3);
1318 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1319 gridview->setCurrentIndex(model.count()-2);
1320 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1321 canvas->rootObject()->setProperty("showFooter", false);
1323 // header should become visible if it is out of view, and then current index moves to the last row
1324 canvas->rootObject()->setProperty("showHeader", true);
1325 QTRY_VERIFY(gridview->headerItem());
1326 gridview->setCurrentIndex(3);
1327 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1328 gridview->setCurrentIndex(1);
1329 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1330 canvas->rootObject()->setProperty("showHeader", false);
1334 canvas->requestActivateWindow();
1335 QTest::qWaitForWindowShown(canvas);
1336 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1338 gridview->setCurrentIndex(0);
1340 QTest::keyClick(canvas, Qt::Key_Down);
1341 QCOMPARE(gridview->currentIndex(), 3);
1343 QTest::keyClick(canvas, Qt::Key_Up);
1344 QCOMPARE(gridview->currentIndex(), 0);
1346 // hold down Key_Down
1347 for (int i=0; i<(model.count() / 3) - 1; i++) {
1348 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1349 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1351 QTest::keyRelease(canvas, Qt::Key_Down);
1352 QTRY_COMPARE(gridview->currentIndex(), 57);
1353 QTRY_COMPARE(gridview->contentY(), 880.0);
1356 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1357 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1358 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1360 QTest::keyRelease(canvas, Qt::Key_Up);
1361 QTRY_COMPARE(gridview->currentIndex(), 0);
1362 QTRY_COMPARE(gridview->contentY(), 0.0);
1365 gridview->setFlow(QQuickGridView::TopToBottom);
1367 canvas->requestActivateWindow();
1368 QTest::qWaitForWindowShown(canvas);
1369 QVERIFY(qGuiApp->focusWindow() == canvas);
1370 qApp->processEvents();
1372 QTest::keyClick(canvas, Qt::Key_Right);
1373 QCOMPARE(gridview->currentIndex(), 5);
1375 QTest::keyClick(canvas, Qt::Key_Left);
1376 QCOMPARE(gridview->currentIndex(), 0);
1378 QTest::keyClick(canvas, Qt::Key_Down);
1379 QCOMPARE(gridview->currentIndex(), 1);
1381 QTest::keyClick(canvas, Qt::Key_Up);
1382 QCOMPARE(gridview->currentIndex(), 0);
1384 // hold down Key_Right
1385 for (int i=0; i<(model.count() / 5) - 1; i++) {
1386 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1387 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1390 QTest::keyRelease(canvas, Qt::Key_Right);
1391 QTRY_COMPARE(gridview->currentIndex(), 55);
1392 QTRY_COMPARE(gridview->contentX(), 720.0);
1394 // hold down Key_Left
1395 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1396 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1397 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1399 QTest::keyRelease(canvas, Qt::Key_Left);
1400 QTRY_COMPARE(gridview->currentIndex(), 0);
1401 QTRY_COMPARE(gridview->contentX(), 0.0);
1404 // turn off auto highlight
1405 gridview->setHighlightFollowsCurrentItem(false);
1406 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1407 QVERIFY(gridview->highlightItem());
1408 qreal hlPosX = gridview->highlightItem()->x();
1409 qreal hlPosY = gridview->highlightItem()->y();
1411 gridview->setCurrentIndex(5);
1412 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1413 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1415 // insert item before currentIndex
1416 gridview->setCurrentIndex(28);
1417 model.insertItem(0, "Foo", "1111");
1418 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1420 // check removing highlight by setting currentIndex to -1;
1421 gridview->setCurrentIndex(-1);
1423 QCOMPARE(gridview->currentIndex(), -1);
1424 QVERIFY(!gridview->highlightItem());
1425 QVERIFY(!gridview->currentItem());
1427 gridview->setHighlightFollowsCurrentItem(true);
1429 gridview->setFlow(QQuickGridView::LeftToRight);
1430 gridview->setLayoutDirection(Qt::RightToLeft);
1432 canvas->requestActivateWindow();
1433 QTest::qWaitForWindowShown(canvas);
1434 QTRY_VERIFY(qGuiApp->focusWindow() == canvas);
1435 qApp->processEvents();
1437 gridview->setCurrentIndex(35);
1439 QTest::keyClick(canvas, Qt::Key_Right);
1440 QCOMPARE(gridview->currentIndex(), 34);
1442 QTest::keyClick(canvas, Qt::Key_Down);
1443 QCOMPARE(gridview->currentIndex(), 37);
1445 QTest::keyClick(canvas, Qt::Key_Up);
1446 QCOMPARE(gridview->currentIndex(), 34);
1448 QTest::keyClick(canvas, Qt::Key_Left);
1449 QCOMPARE(gridview->currentIndex(), 35);
1452 // turn off auto highlight
1453 gridview->setHighlightFollowsCurrentItem(false);
1454 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1455 QVERIFY(gridview->highlightItem());
1456 hlPosX = gridview->highlightItem()->x();
1457 hlPosY = gridview->highlightItem()->y();
1459 gridview->setCurrentIndex(5);
1460 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1461 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1463 // insert item before currentIndex
1464 gridview->setCurrentIndex(28);
1465 model.insertItem(0, "Foo", "1111");
1466 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1468 // check removing highlight by setting currentIndex to -1;
1469 gridview->setCurrentIndex(-1);
1471 QCOMPARE(gridview->currentIndex(), -1);
1472 QVERIFY(!gridview->highlightItem());
1473 QVERIFY(!gridview->currentItem());
1478 void tst_QQuickGridView::noCurrentIndex()
1481 for (int i = 0; i < 60; i++)
1482 model.addItem("Item" + QString::number(i), QString::number(i));
1484 QQuickView *canvas = new QQuickView(0);
1485 canvas->setGeometry(0,0,240,320);
1487 QDeclarativeContext *ctxt = canvas->rootContext();
1488 ctxt->setContextProperty("testModel", &model);
1490 QString filename(TESTDATA("gridview-noCurrent.qml"));
1491 canvas->setSource(QUrl::fromLocalFile(filename));
1493 qApp->processEvents();
1495 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1496 QVERIFY(gridview != 0);
1498 QQuickItem *contentItem = gridview->contentItem();
1499 QVERIFY(contentItem != 0);
1501 // current index should be -1
1502 QCOMPARE(gridview->currentIndex(), -1);
1503 QVERIFY(!gridview->currentItem());
1504 QVERIFY(!gridview->highlightItem());
1505 QCOMPARE(gridview->contentY(), 0.0);
1507 gridview->setCurrentIndex(5);
1508 QCOMPARE(gridview->currentIndex(), 5);
1509 QVERIFY(gridview->currentItem());
1510 QVERIFY(gridview->highlightItem());
1515 void tst_QQuickGridView::changeFlow()
1517 QQuickView *canvas = createView();
1520 for (int i = 0; i < 30; i++)
1521 model.addItem("Item" + QString::number(i), QString::number(i));
1523 QDeclarativeContext *ctxt = canvas->rootContext();
1524 ctxt->setContextProperty("testModel", &model);
1525 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1526 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1528 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1529 qApp->processEvents();
1531 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1532 QTRY_VERIFY(gridview != 0);
1534 QQuickItem *contentItem = gridview->contentItem();
1535 QTRY_VERIFY(contentItem != 0);
1537 // Confirm items positioned correctly and indexes correct
1538 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1539 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1540 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1541 if (!item) qWarning() << "Item" << i << "not found";
1543 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1544 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1545 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1546 QTRY_VERIFY(name != 0);
1547 QTRY_COMPARE(name->text(), model.name(i));
1548 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1549 QTRY_VERIFY(number != 0);
1550 QTRY_COMPARE(number->text(), model.number(i));
1553 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1555 // Confirm items positioned correctly and indexes correct
1556 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1557 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1558 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1559 if (!item) qWarning() << "Item" << i << "not found";
1561 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1562 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1563 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1564 QTRY_VERIFY(name != 0);
1565 QTRY_COMPARE(name->text(), model.name(i));
1566 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1567 QTRY_VERIFY(number != 0);
1568 QTRY_COMPARE(number->text(), model.number(i));
1571 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1573 // Confirm items positioned correctly and indexes correct
1574 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1575 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1576 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1577 if (!item) qWarning() << "Item" << i << "not found";
1579 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1580 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1581 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1582 QTRY_VERIFY(name != 0);
1583 QTRY_COMPARE(name->text(), model.name(i));
1584 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1585 QTRY_VERIFY(number != 0);
1586 QTRY_COMPARE(number->text(), model.number(i));
1588 gridview->setContentX(100);
1589 QTRY_COMPARE(gridview->contentX(), 100.);
1590 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1591 QTRY_COMPARE(gridview->contentX(), 0.);
1593 // Confirm items positioned correctly and indexes correct
1594 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1595 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1596 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1597 if (!item) qWarning() << "Item" << i << "not found";
1599 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1600 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1601 QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
1602 QTRY_VERIFY(name != 0);
1603 QTRY_COMPARE(name->text(), model.name(i));
1604 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i);
1605 QTRY_VERIFY(number != 0);
1606 QTRY_COMPARE(number->text(), model.number(i));
1612 void tst_QQuickGridView::defaultValues()
1614 QDeclarativeEngine engine;
1615 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview3.qml")));
1616 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
1618 QTRY_VERIFY(obj != 0);
1619 QTRY_VERIFY(obj->model() == QVariant());
1620 QTRY_VERIFY(obj->delegate() == 0);
1621 QTRY_COMPARE(obj->currentIndex(), -1);
1622 QTRY_VERIFY(obj->currentItem() == 0);
1623 QTRY_COMPARE(obj->count(), 0);
1624 QTRY_VERIFY(obj->highlight() == 0);
1625 QTRY_VERIFY(obj->highlightItem() == 0);
1626 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1627 QTRY_VERIFY(obj->flow() == 0);
1628 QTRY_COMPARE(obj->isWrapEnabled(), false);
1629 QTRY_COMPARE(obj->cacheBuffer(), 0);
1630 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
1631 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1635 void tst_QQuickGridView::properties()
1637 QDeclarativeEngine engine;
1638 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("gridview2.qml")));
1639 QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create());
1641 QTRY_VERIFY(obj != 0);
1642 QTRY_VERIFY(obj->model() != QVariant());
1643 QTRY_VERIFY(obj->delegate() != 0);
1644 QTRY_COMPARE(obj->currentIndex(), 0);
1645 QTRY_VERIFY(obj->currentItem() != 0);
1646 QTRY_COMPARE(obj->count(), 4);
1647 QTRY_VERIFY(obj->highlight() != 0);
1648 QTRY_VERIFY(obj->highlightItem() != 0);
1649 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1650 QTRY_VERIFY(obj->flow() == 0);
1651 QTRY_COMPARE(obj->isWrapEnabled(), true);
1652 QTRY_COMPARE(obj->cacheBuffer(), 200);
1653 QTRY_COMPARE(obj->cellWidth(), qreal(100));
1654 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1658 void tst_QQuickGridView::propertyChanges()
1660 QQuickView *canvas = createView();
1661 QTRY_VERIFY(canvas);
1662 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1664 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
1665 QTRY_VERIFY(gridView);
1667 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1668 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1669 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1670 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1672 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1673 QTRY_COMPARE(gridView->cacheBuffer(), 10);
1674 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
1676 gridView->setWrapEnabled(false);
1677 gridView->setCacheBuffer(3);
1678 gridView->setFlow(QQuickGridView::TopToBottom);
1680 QTRY_COMPARE(gridView->isWrapEnabled(), false);
1681 QTRY_COMPARE(gridView->cacheBuffer(), 3);
1682 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
1684 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1685 QTRY_COMPARE(cacheBufferSpy.count(),1);
1686 QTRY_COMPARE(flowSpy.count(),1);
1688 gridView->setWrapEnabled(false);
1689 gridView->setCacheBuffer(3);
1690 gridView->setFlow(QQuickGridView::TopToBottom);
1692 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1693 QTRY_COMPARE(cacheBufferSpy.count(),1);
1694 QTRY_COMPARE(flowSpy.count(),1);
1696 gridView->setFlow(QQuickGridView::LeftToRight);
1697 QTRY_COMPARE(gridView->flow(), QQuickGridView::LeftToRight);
1699 gridView->setWrapEnabled(true);
1700 gridView->setCacheBuffer(5);
1701 gridView->setLayoutDirection(Qt::RightToLeft);
1703 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1704 QTRY_COMPARE(gridView->cacheBuffer(), 5);
1705 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1707 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1708 QTRY_COMPARE(cacheBufferSpy.count(),2);
1709 QTRY_COMPARE(layoutSpy.count(),1);
1710 QTRY_COMPARE(flowSpy.count(),2);
1712 gridView->setWrapEnabled(true);
1713 gridView->setCacheBuffer(5);
1714 gridView->setLayoutDirection(Qt::RightToLeft);
1716 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1717 QTRY_COMPARE(cacheBufferSpy.count(),2);
1718 QTRY_COMPARE(layoutSpy.count(),1);
1719 QTRY_COMPARE(flowSpy.count(),2);
1721 gridView->setFlow(QQuickGridView::TopToBottom);
1722 QTRY_COMPARE(gridView->flow(), QQuickGridView::TopToBottom);
1723 QTRY_COMPARE(flowSpy.count(),3);
1725 gridView->setFlow(QQuickGridView::TopToBottom);
1726 QTRY_COMPARE(flowSpy.count(),3);
1731 void tst_QQuickGridView::componentChanges()
1733 QQuickView *canvas = createView();
1734 QTRY_VERIFY(canvas);
1735 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1737 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
1738 QTRY_VERIFY(gridView);
1740 QDeclarativeComponent component(canvas->engine());
1741 component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1743 QDeclarativeComponent delegateComponent(canvas->engine());
1744 delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1746 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1747 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1748 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1749 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1751 gridView->setHighlight(&component);
1752 gridView->setDelegate(&delegateComponent);
1753 gridView->setHeader(&component);
1754 gridView->setFooter(&component);
1756 QTRY_COMPARE(gridView->highlight(), &component);
1757 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1758 QTRY_COMPARE(gridView->header(), &component);
1759 QTRY_COMPARE(gridView->footer(), &component);
1761 QTRY_COMPARE(highlightSpy.count(),1);
1762 QTRY_COMPARE(delegateSpy.count(),1);
1763 QTRY_COMPARE(headerSpy.count(),1);
1764 QTRY_COMPARE(footerSpy.count(),1);
1766 gridView->setHighlight(&component);
1767 gridView->setDelegate(&delegateComponent);
1768 gridView->setHeader(&component);
1769 gridView->setFooter(&component);
1771 QTRY_COMPARE(highlightSpy.count(),1);
1772 QTRY_COMPARE(delegateSpy.count(),1);
1773 QTRY_COMPARE(headerSpy.count(),1);
1774 QTRY_COMPARE(footerSpy.count(),1);
1779 void tst_QQuickGridView::modelChanges()
1781 QQuickView *canvas = createView();
1782 QTRY_VERIFY(canvas);
1783 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychangestest.qml")));
1785 QQuickGridView *gridView = canvas->rootObject()->findChild<QQuickGridView*>("gridView");
1786 QTRY_VERIFY(gridView);
1788 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1789 QTRY_VERIFY(alternateModel);
1790 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1791 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1793 gridView->setModel(modelVariant);
1794 QTRY_COMPARE(gridView->model(), modelVariant);
1795 QTRY_COMPARE(modelSpy.count(),1);
1797 gridView->setModel(modelVariant);
1798 QTRY_COMPARE(modelSpy.count(),1);
1800 gridView->setModel(QVariant());
1801 QTRY_COMPARE(modelSpy.count(),2);
1805 void tst_QQuickGridView::positionViewAtIndex()
1807 QQuickView *canvas = createView();
1810 for (int i = 0; i < 40; i++)
1811 model.addItem("Item" + QString::number(i), "");
1813 QDeclarativeContext *ctxt = canvas->rootContext();
1814 ctxt->setContextProperty("testModel", &model);
1815 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1816 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1818 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
1819 qApp->processEvents();
1821 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
1822 QTRY_VERIFY(gridview != 0);
1824 QQuickItem *contentItem = gridview->contentItem();
1825 QTRY_VERIFY(contentItem != 0);
1827 // Confirm items positioned correctly
1828 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1829 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1830 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1831 if (!item) qWarning() << "Item" << i << "not found";
1833 QTRY_COMPARE(item->x(), (i%3)*80.);
1834 QTRY_COMPARE(item->y(), (i/3)*60.);
1837 // Position on a currently visible item
1838 gridview->positionViewAtIndex(4, QQuickGridView::Beginning);
1839 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1840 QTRY_COMPARE(gridview->contentY(), 60.);
1842 // Confirm items positioned correctly
1843 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1844 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1845 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1846 if (!item) qWarning() << "Item" << i << "not found";
1848 QTRY_COMPARE(item->x(), (i%3)*80.);
1849 QTRY_COMPARE(item->y(), (i/3)*60.);
1852 // Position on an item beyond the visible items
1853 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
1854 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1855 QTRY_COMPARE(gridview->contentY(), 420.);
1857 // Confirm items positioned correctly
1858 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1859 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1860 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1861 if (!item) qWarning() << "Item" << i << "not found";
1863 QTRY_COMPARE(item->x(), (i%3)*80.);
1864 QTRY_COMPARE(item->y(), (i/3)*60.);
1867 // Position on an item that would leave empty space if positioned at the top
1868 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
1869 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1870 QTRY_COMPARE(gridview->contentY(), 520.);
1872 // Confirm items positioned correctly
1873 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1874 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1875 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1876 if (!item) qWarning() << "Item" << i << "not found";
1878 QTRY_COMPARE(item->x(), (i%3)*80.);
1879 QTRY_COMPARE(item->y(), (i/3)*60.);
1882 // Position at the beginning again
1883 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
1884 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1885 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1886 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1887 QTRY_COMPARE(gridview->contentY(), 0.);
1889 // Confirm items positioned correctly
1890 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1891 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1892 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1893 if (!item) qWarning() << "Item" << i << "not found";
1895 QTRY_COMPARE(item->x(), (i%3)*80.);
1896 QTRY_COMPARE(item->y(), (i/3)*60.);
1900 gridview->positionViewAtIndex(30, QQuickGridView::End);
1901 QTRY_COMPARE(gridview->contentY(), 340.);
1903 // Position in Center
1904 gridview->positionViewAtIndex(15, QQuickGridView::Center);
1905 QTRY_COMPARE(gridview->contentY(), 170.);
1907 // Ensure at least partially visible
1908 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1909 QTRY_COMPARE(gridview->contentY(), 170.);
1911 gridview->setContentY(302);
1912 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1913 QTRY_COMPARE(gridview->contentY(), 302.);
1915 gridview->setContentY(360);
1916 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1917 QTRY_COMPARE(gridview->contentY(), 300.);
1919 gridview->setContentY(60);
1920 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
1921 QTRY_COMPARE(gridview->contentY(), 60.);
1923 gridview->setContentY(20);
1924 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
1925 QTRY_COMPARE(gridview->contentY(), 100.);
1927 // Ensure completely visible
1928 gridview->setContentY(120);
1929 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
1930 QTRY_COMPARE(gridview->contentY(), 120.);
1932 gridview->setContentY(302);
1933 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
1934 QTRY_COMPARE(gridview->contentY(), 300.);
1936 gridview->setContentY(60);
1937 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
1938 QTRY_COMPARE(gridview->contentY(), 100.);
1940 // Test for Top To Bottom layout
1941 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1943 // Confirm items positioned correctly
1944 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
1945 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1946 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
1947 if (!item) qWarning() << "Item" << i << "not found";
1949 QTRY_COMPARE(item->x(), (i/5)*80.);
1950 QTRY_COMPARE(item->y(), (i%5)*60.);
1954 gridview->positionViewAtIndex(30, QQuickGridView::End);
1955 QTRY_COMPARE(gridview->contentX(), 320.);
1956 QTRY_COMPARE(gridview->contentY(), 0.);
1958 // Position in Center
1959 gridview->positionViewAtIndex(15, QQuickGridView::Center);
1960 QTRY_COMPARE(gridview->contentX(), 160.);
1962 // Ensure at least partially visible
1963 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
1964 QTRY_COMPARE(gridview->contentX(), 160.);
1966 gridview->setContentX(170);
1967 gridview->positionViewAtIndex(25, QQuickGridView::Visible);
1968 QTRY_COMPARE(gridview->contentX(), 170.);
1970 gridview->positionViewAtIndex(30, QQuickGridView::Visible);
1971 QTRY_COMPARE(gridview->contentX(), 320.);
1973 gridview->setContentX(170);
1974 gridview->positionViewAtIndex(25, QQuickGridView::Contain);
1975 QTRY_COMPARE(gridview->contentX(), 240.);
1977 // positionViewAtBeginning
1978 gridview->positionViewAtBeginning();
1979 QTRY_COMPARE(gridview->contentX(), 0.);
1981 gridview->setContentX(80);
1982 canvas->rootObject()->setProperty("showHeader", true);
1983 gridview->positionViewAtBeginning();
1984 QTRY_COMPARE(gridview->contentX(), -30.);
1986 // positionViewAtEnd
1987 gridview->positionViewAtEnd();
1988 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
1990 gridview->setContentX(80);
1991 canvas->rootObject()->setProperty("showFooter", true);
1992 gridview->positionViewAtEnd();
1993 QTRY_COMPARE(gridview->contentX(), 430.);
1995 // set current item to outside visible view, position at beginning
1996 // and ensure highlight moves to current item
1997 gridview->setCurrentIndex(6);
1998 gridview->positionViewAtBeginning();
1999 QTRY_COMPARE(gridview->contentX(), -30.);
2000 QVERIFY(gridview->highlightItem());
2001 QCOMPARE(gridview->highlightItem()->x(), 80.);
2006 void tst_QQuickGridView::snapping()
2008 QQuickView *canvas = createView();
2011 for (int i = 0; i < 40; i++)
2012 model.addItem("Item" + QString::number(i), "");
2014 QDeclarativeContext *ctxt = canvas->rootContext();
2015 ctxt->setContextProperty("testModel", &model);
2016 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2017 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2019 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2020 qApp->processEvents();
2022 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2023 QTRY_VERIFY(gridview != 0);
2025 gridview->setHeight(220);
2026 QCOMPARE(gridview->height(), 220.);
2028 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2029 QCOMPARE(gridview->contentY(), 80.);
2031 gridview->setContentY(0);
2032 QCOMPARE(gridview->contentY(), 0.);
2034 gridview->setSnapMode(QQuickGridView::SnapToRow);
2035 QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow);
2037 gridview->positionViewAtIndex(12, QQuickGridView::Visible);
2038 QCOMPARE(gridview->contentY(), 60.);
2040 gridview->positionViewAtIndex(15, QQuickGridView::End);
2041 QCOMPARE(gridview->contentY(), 120.);
2047 void tst_QQuickGridView::mirroring()
2049 QQuickView *canvasA = createView();
2050 canvasA->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2051 QQuickGridView *gridviewA = findItem<QQuickGridView>(canvasA->rootObject(), "view");
2052 QTRY_VERIFY(gridviewA != 0);
2054 QQuickView *canvasB = createView();
2055 canvasB->setSource(QUrl::fromLocalFile(TESTDATA("mirroring.qml")));
2056 QQuickGridView *gridviewB = findItem<QQuickGridView>(canvasB->rootObject(), "view");
2057 QTRY_VERIFY(gridviewA != 0);
2058 qApp->processEvents();
2060 QList<QString> objectNames;
2061 objectNames << "item1" << "item2"; // << "item3"
2063 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2064 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2065 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
2068 foreach (const QString objectName, objectNames)
2069 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2071 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2072 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
2075 foreach (const QString objectName, objectNames)
2076 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2078 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
2079 QQuickItemPrivate::get(gridviewB)->setLayoutMirror(true);
2080 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
2082 // LTR != LTR+mirror
2083 foreach (const QString objectName, objectNames)
2084 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2086 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
2088 // RTL == LTR+mirror
2089 foreach (const QString objectName, objectNames)
2090 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2092 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
2094 // RTL != RTL+mirror
2095 foreach (const QString objectName, objectNames)
2096 QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
2098 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
2100 // LTR == RTL+mirror
2101 foreach (const QString objectName, objectNames)
2102 QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
2108 void tst_QQuickGridView::positionViewAtIndex_rightToLeft()
2110 QQuickView *canvas = createView();
2113 for (int i = 0; i < 40; i++)
2114 model.addItem("Item" + QString::number(i), "");
2116 QDeclarativeContext *ctxt = canvas->rootContext();
2117 ctxt->setContextProperty("testModel", &model);
2118 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2119 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2121 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
2122 qApp->processEvents();
2124 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2125 QTRY_VERIFY(gridview != 0);
2127 QQuickItem *contentItem = gridview->contentItem();
2128 QTRY_VERIFY(contentItem != 0);
2130 // Confirm items positioned correctly
2131 int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2132 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2133 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2134 if (!item) qWarning() << "Item" << i << "not found";
2136 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2137 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2140 // Position on a currently visible item
2141 gridview->positionViewAtIndex(6, QQuickGridView::Beginning);
2142 QTRY_COMPARE(gridview->contentX(), -320.);
2144 // Confirm items positioned correctly
2145 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2146 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
2147 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2148 if (!item) qWarning() << "Item" << i << "not found";
2150 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2151 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2154 // Position on an item beyond the visible items
2155 gridview->positionViewAtIndex(21, QQuickGridView::Beginning);
2156 QTRY_COMPARE(gridview->contentX(), -560.);
2158 // Confirm items positioned correctly
2159 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2160 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
2161 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2162 if (!item) qWarning() << "Item" << i << "not found";
2164 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2165 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2168 // Position on an item that would leave empty space if positioned at the top
2169 gridview->positionViewAtIndex(31, QQuickGridView::Beginning);
2170 QTRY_COMPARE(gridview->contentX(), -640.);
2172 // Confirm items positioned correctly
2173 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2174 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2175 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2176 if (!item) qWarning() << "Item" << i << "not found";
2178 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2179 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2182 // Position at the beginning again
2183 gridview->positionViewAtIndex(0, QQuickGridView::Beginning);
2184 QTRY_COMPARE(gridview->contentX(), -240.);
2186 // Confirm items positioned correctly
2187 itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
2188 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2189 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
2190 if (!item) qWarning() << "Item" << i << "not found";
2192 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2193 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2197 gridview->positionViewAtIndex(30, QQuickGridView::End);
2198 QTRY_COMPARE(gridview->contentX(), -560.);
2200 // Position in Center
2201 gridview->positionViewAtIndex(15, QQuickGridView::Center);
2202 QTRY_COMPARE(gridview->contentX(), -400.);
2204 // Ensure at least partially visible
2205 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2206 QTRY_COMPARE(gridview->contentX(), -400.);
2208 gridview->setContentX(-555.);
2209 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2210 QTRY_COMPARE(gridview->contentX(), -555.);
2212 gridview->setContentX(-239);
2213 gridview->positionViewAtIndex(15, QQuickGridView::Visible);
2214 QTRY_COMPARE(gridview->contentX(), -320.);
2216 gridview->setContentX(-239);
2217 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2218 QTRY_COMPARE(gridview->contentX(), -400.);
2220 gridview->setContentX(-640);
2221 gridview->positionViewAtIndex(20, QQuickGridView::Visible);
2222 QTRY_COMPARE(gridview->contentX(), -560.);
2224 // Ensure completely visible
2225 gridview->setContentX(-400);
2226 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2227 QTRY_COMPARE(gridview->contentX(), -400.);
2229 gridview->setContentX(-315);
2230 gridview->positionViewAtIndex(15, QQuickGridView::Contain);
2231 QTRY_COMPARE(gridview->contentX(), -320.);
2233 gridview->setContentX(-640);
2234 gridview->positionViewAtIndex(20, QQuickGridView::Contain);
2235 QTRY_COMPARE(gridview->contentX(), -560.);
2240 void tst_QQuickGridView::resetModel()
2242 QQuickView *canvas = createView();
2244 QStringList strings;
2245 strings << "one" << "two" << "three";
2246 QStringListModel model(strings);
2248 QDeclarativeContext *ctxt = canvas->rootContext();
2249 ctxt->setContextProperty("testModel", &model);
2251 canvas->setSource(QUrl::fromLocalFile(TESTDATA("displaygrid.qml")));
2252 qApp->processEvents();
2254 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2255 QTRY_VERIFY(gridview != 0);
2257 QQuickItem *contentItem = gridview->contentItem();
2258 QTRY_VERIFY(contentItem != 0);
2260 QTRY_COMPARE(gridview->count(), model.rowCount());
2262 for (int i = 0; i < model.rowCount(); ++i) {
2263 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2264 QTRY_VERIFY(display != 0);
2265 QTRY_COMPARE(display->text(), strings.at(i));
2269 strings << "four" << "five" << "six" << "seven";
2270 model.setStringList(strings);
2272 QTRY_COMPARE(gridview->count(), model.rowCount());
2274 for (int i = 0; i < model.rowCount(); ++i) {
2275 QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i);
2276 QTRY_VERIFY(display != 0);
2277 QTRY_COMPARE(display->text(), strings.at(i));
2283 void tst_QQuickGridView::enforceRange()
2285 QQuickView *canvas = createView();
2288 for (int i = 0; i < 30; i++)
2289 model.addItem("Item" + QString::number(i), "");
2291 QDeclarativeContext *ctxt = canvas->rootContext();
2292 ctxt->setContextProperty("testModel", &model);
2293 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2294 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2296 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2297 qApp->processEvents();
2298 QVERIFY(canvas->rootObject() != 0);
2300 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2301 QTRY_VERIFY(gridview != 0);
2303 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2304 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2305 QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2307 QQuickItem *contentItem = gridview->contentItem();
2308 QTRY_VERIFY(contentItem != 0);
2310 // view should be positioned at the top of the range.
2311 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2313 QTRY_COMPARE(gridview->contentY(), -100.0);
2315 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2316 QTRY_VERIFY(name != 0);
2317 QTRY_COMPARE(name->text(), model.name(0));
2318 QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0);
2319 QTRY_VERIFY(number != 0);
2320 QTRY_COMPARE(number->text(), model.number(0));
2322 // Check currentIndex is updated when contentItem moves
2323 gridview->setContentY(0);
2324 QTRY_COMPARE(gridview->currentIndex(), 2);
2326 gridview->setCurrentIndex(5);
2327 QTRY_COMPARE(gridview->contentY(), 100.);
2330 for (int i = 0; i < 5; i++)
2331 model2.addItem("Item" + QString::number(i), "");
2333 ctxt->setContextProperty("testModel", &model2);
2334 QCOMPARE(gridview->count(), 5);
2339 void tst_QQuickGridView::enforceRange_rightToLeft()
2341 QQuickView *canvas = createView();
2344 for (int i = 0; i < 30; i++)
2345 model.addItem("Item" + QString::number(i), "");
2347 QDeclarativeContext *ctxt = canvas->rootContext();
2348 ctxt->setContextProperty("testModel", &model);
2349 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2350 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2352 canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview-enforcerange.qml")));
2353 qApp->processEvents();
2354 QVERIFY(canvas->rootObject() != 0);
2356 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2357 QTRY_VERIFY(gridview != 0);
2359 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2360 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2361 QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
2363 QQuickItem *contentItem = gridview->contentItem();
2364 QTRY_VERIFY(contentItem != 0);
2366 // view should be positioned at the top of the range.
2367 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2369 QEXPECT_FAIL("", "QTBUG-22162", Abort);
2370 QTRY_COMPARE(gridview->contentX(), -100.);
2371 QTRY_COMPARE(gridview->contentY(), 0.0);
2373 QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0);
2374 QTRY_VERIFY(name != 0);
2375 QTRY_COMPARE(name->text(), model.name(0));
2376 QQuickText *number = findItem<QQuickText>(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_QQuickGridView::QTBUG_8456()
2400 QQuickView *canvas = createView();
2402 canvas->setSource(QUrl::fromLocalFile(TESTDATA("setindex.qml")));
2403 qApp->processEvents();
2405 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2406 QTRY_VERIFY(gridview != 0);
2408 QTRY_COMPARE(gridview->currentIndex(), 0);
2413 void tst_QQuickGridView::manualHighlight()
2415 QQuickView *canvas = createView();
2417 QString filename(TESTDATA("manual-highlight.qml"));
2418 canvas->setSource(QUrl::fromLocalFile(filename));
2420 qApp->processEvents();
2422 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2423 QTRY_VERIFY(gridview != 0);
2425 QQuickItem *contentItem = gridview->contentItem();
2426 QTRY_VERIFY(contentItem != 0);
2428 QTRY_COMPARE(gridview->currentIndex(), 0);
2429 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(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<QQuickItem>(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, QQuickGridView::Contain);
2442 QTRY_COMPARE(gridview->currentIndex(), 2);
2443 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(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(QQuickGridView::TopToBottom);
2448 QTRY_COMPARE(gridview->flow(), QQuickGridView::TopToBottom);
2450 gridview->setCurrentIndex(0);
2451 QTRY_COMPARE(gridview->currentIndex(), 0);
2452 QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(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_QQuickGridView::footer()
2462 QFETCH(QQuickGridView::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 QQuickView *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 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2485 QTRY_VERIFY(gridview != 0);
2486 gridview->setFlow(flow);
2487 gridview->setLayoutDirection(layoutDirection);
2489 QQuickItem *contentItem = gridview->contentItem();
2490 QTRY_VERIFY(contentItem != 0);
2492 QQuickText *footer = findItem<QQuickText>(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 QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
2504 QCOMPARE(item->pos(), firstDelegatePos);
2506 if (flow == QQuickGridView::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 == QQuickGridView::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<QQuickItem>(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<QQuickText>(contentItem, "footer");
2545 footer = findItem<QQuickText>(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<QQuickItem>(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_QQuickGridView::footer_data()
2569 QTest::addColumn<QQuickGridView::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") << QQuickGridView::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") << QQuickGridView::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") << QQuickGridView::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") << QQuickGridView::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_QQuickGridView::header()
2623 QFETCH(QQuickGridView::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 QQuickView *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 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2643 QTRY_VERIFY(gridview != 0);
2644 gridview->setFlow(flow);
2645 gridview->setLayoutDirection(layoutDirection);
2647 QQuickItem *contentItem = gridview->contentItem();
2648 QTRY_VERIFY(contentItem != 0);
2650 QQuickText *header = findItem<QQuickText>(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 QQuickItem *item = findItem<QQuickItem>(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<QQuickText>(contentItem, "header");
2677 header = findItem<QQuickText>(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<QQuickItem>(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<QQuickGridView>(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_QQuickGridView::header_data()
2721 QTest::addColumn<QQuickGridView::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") << QQuickGridView::LeftToRight << Qt::LeftToRight
2744 // header above items, top right
2745 QTest::newRow("flow left to right, layout right to left") << QQuickGridView::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") << QQuickGridView::TopToBottom << Qt::LeftToRight
2762 // header to right of items
2763 QTest::newRow("flow top to bottom, layout right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft
2766 << QPointF(-(240 - 100), 0)
2767 << QPointF(-(240 - 50), 0)
2769 << QPointF(-(240 - 40), 0);
2772 void tst_QQuickGridView::resizeViewAndRepaint()
2774 QQuickView *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 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2789 QTRY_VERIFY(gridview != 0);
2790 QQuickItem *contentItem = gridview->contentItem();
2791 QTRY_VERIFY(contentItem != 0);
2793 // item at index 10 should not be currently visible
2794 QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
2796 gridview->setHeight(320);
2797 QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", 10));
2799 gridview->setHeight(100);
2800 QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
2805 void tst_QQuickGridView::indexAt()
2807 QQuickView *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 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
2827 QTRY_VERIFY(gridview != 0);
2829 QQuickItem *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_QQuickGridView::onAdd()
2845 QFETCH(int, initialItemCount);
2846 QFETCH(int, itemsToAdd);
2848 const int delegateWidth = 50;
2849 const int delegateHeight = 100;
2851 QQuickView *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<QQuickGridView*>(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_QQuickGridView::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_QQuickGridView::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 QQuickView *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<QQuickGridView*>(canvas->rootObject())->count());
2925 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2930 void tst_QQuickGridView::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_QQuickGridView::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_QQuickGridView::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_QQuickGridView::columnCount()
2995 canvas.setSource(QUrl::fromLocalFile(TESTDATA("gridview4.qml")));
2997 canvas.requestActivateWindow();
2998 QTest::qWaitForWindowShown(&canvas);
3000 QQuickGridView *view = qobject_cast<QQuickGridView*>(canvas.rootObject());
3002 QCOMPARE(view->cellWidth(), qreal(405)/qreal(9));
3003 QCOMPARE(view->cellHeight(), qreal(100));
3005 QList<QQuickItem*> items = findItems<QQuickItem>(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_QQuickGridView::margins()
3014 QQuickView *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 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3029 QTRY_VERIFY(gridview != 0);
3031 QQuickItem *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 QQuickView *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 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3092 QTRY_VERIFY(gridview != 0);
3094 QQuickItem *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_QQuickGridView::creationContext()
3144 canvas.setGeometry(0,0,240,320);
3145 canvas.setSource(QUrl::fromLocalFile(TESTDATA("creationContext.qml")));
3146 qApp->processEvents();
3148 QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
3150 QVERIFY(rootItem->property("count").toInt() > 0);
3153 QVERIFY(item = rootItem->findChild<QQuickItem *>("listItem"));
3154 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3155 QVERIFY(item = rootItem->findChild<QQuickItem *>("header"));
3156 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3157 QVERIFY(item = rootItem->findChild<QQuickItem *>("footer"));
3158 QCOMPARE(item->property("text").toString(), QString("Hello!"));
3161 void tst_QQuickGridView::snapToRow_data()
3163 QTest::addColumn<QQuickGridView::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") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3173 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3175 QTest::newRow("horizontal, left to right") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange)
3176 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0;
3178 QTest::newRow("horizontal, right to left") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::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") << QQuickGridView::LeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3182 << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3184 QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::TopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange)
3185 << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0;
3187 QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::TopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange)
3188 << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0;
3191 void tst_QQuickGridView::snapToRow()
3193 QFETCH(QQuickGridView::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 QQuickView *canvas = createView();
3204 canvas->setSource(QUrl::fromLocalFile(TESTDATA("snapToRow.qml")));
3206 qApp->processEvents();
3208 QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
3209 QTRY_VERIFY(gridview != 0);
3211 gridview->setFlow(flow);
3212 gridview->setLayoutDirection(layoutDirection);
3213 gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
3215 QQuickItem *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 == QQuickGridView::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 == QQuickGridView::LeftToRight
3231 ? !gridview->isAtYEnd()
3232 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning());
3234 if (flow == QQuickGridView::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 == QQuickGridView::LeftToRight
3244 ? !gridview->isAtYBeginning()
3245 : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd());
3247 if (flow == QQuickGridView::LeftToRight)
3248 QCOMPARE(gridview->contentY(), startExtent);
3250 QCOMPARE(gridview->contentX(), startExtent);
3256 QQuickView *tst_QQuickGridView::createView()
3258 QQuickView *canvas = new QQuickView(0);
3259 canvas->setGeometry(0,0,240,320);
3264 void tst_QQuickGridView::flick(QQuickView *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_QQuickGridView::findItem(QQuickItem *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 QQuickItem *item = qobject_cast<QQuickItem*>(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_QQuickGridView::findItems(QQuickItem *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 QQuickItem *item = qobject_cast<QQuickItem*>(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_QQuickGridView::dumpTree(QQuickItem *parent, int depth)
3339 static QString padding(" ");
3340 for (int i = 0; i < parent->childItems().count(); ++i) {
3341 QQuickItem *item = qobject_cast<QQuickItem*>(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_QQuickGridView)
3353 #include "tst_qquickgridview.moc"