1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtWidgets/qstringlistmodel.h>
44 #include <QtDeclarative/qsgview.h>
45 #include <QtDeclarative/qdeclarativeengine.h>
46 #include <QtDeclarative/qdeclarativecomponent.h>
47 #include <QtDeclarative/qdeclarativecontext.h>
48 #include <QtDeclarative/qdeclarativeexpression.h>
49 #include <QtDeclarative/private/qsgitem_p.h>
50 #include <QtDeclarative/private/qlistmodelinterface_p.h>
51 #include <QtDeclarative/private/qsggridview_p.h>
52 #include <QtDeclarative/private/qsgtext_p.h>
53 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
54 #include "../../../shared/util.h"
55 #include <QtOpenGL/QGLShaderProgram>
58 // In Symbian OS test data is located in applications private dir
62 Q_DECLARE_METATYPE(Qt::LayoutDirection)
63 Q_DECLARE_METATYPE(QSGGridView::Flow)
65 class tst_QSGGridView : public QObject
73 void cleanupTestCase();
81 void multipleChanges();
82 void multipleChanges_data();
83 void swapWithFirstItem();
86 void noCurrentIndex();
89 void propertyChanges();
90 void componentChanges();
92 void positionViewAtIndex();
93 void positionViewAtIndex_rightToLeft();
98 void enforceRange_rightToLeft();
100 void manualHighlight();
109 void onRemove_data();
110 void testQtQuick11Attributes();
111 void testQtQuick11Attributes_data();
116 QSGView *createView();
118 T *findItem(QSGItem *parent, const QString &id, int index=-1);
120 QList<T*> findItems(QSGItem *parent, const QString &objectName);
121 void dumpTree(QSGItem *parent, int depth = 0);
125 void tst_qsggridview_move(int from, int to, int n, T *items)
128 items->move(from, to);
132 typename T::ConstIterator it=items->begin(); it += from+n;
133 for (; i<to-from; ++i,++it)
134 replaced.append(*it);
136 it=items->begin(); it += from;
137 for (; i<n; ++i,++it)
138 replaced.append(*it);
139 typename T::ConstIterator f=replaced.begin();
140 typename T::Iterator t=items->begin(); t += from;
141 for (; f != replaced.end(); ++f, ++t)
146 void tst_QSGGridView::initTestCase()
150 void tst_QSGGridView::cleanupTestCase()
156 class TestModel : public QAbstractListModel
159 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
161 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
162 QHash<int, QByteArray> roles;
163 roles[Name] = "name";
164 roles[Number] = "number";
168 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
169 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
172 rv = list.at(index.row()).first;
173 else if (role == Number)
174 rv = list.at(index.row()).second;
179 int count() const { return rowCount(); }
180 QString name(int index) const { return list.at(index).first; }
181 QString number(int index) const { return list.at(index).second; }
183 void addItem(const QString &name, const QString &number) {
184 emit beginInsertRows(QModelIndex(), list.count(), list.count());
185 list.append(QPair<QString,QString>(name, number));
186 emit endInsertRows();
189 void addItems(const QList<QPair<QString, QString> > &items) {
190 emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
191 for (int i=0; i<items.count(); i++)
192 list.append(QPair<QString,QString>(items[i].first, items[i].second));
193 emit endInsertRows();
196 void insertItem(int index, const QString &name, const QString &number) {
197 emit beginInsertRows(QModelIndex(), index, index);
198 list.insert(index, QPair<QString,QString>(name, number));
199 emit endInsertRows();
202 void insertItems(int index, const QList<QPair<QString, QString> > &items) {
203 emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
204 for (int i=0; i<items.count(); i++)
205 list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
206 emit endInsertRows();
209 void removeItem(int index) {
210 emit beginRemoveRows(QModelIndex(), index, index);
211 list.removeAt(index);
212 emit endRemoveRows();
215 void removeItems(int index, int count) {
216 emit beginRemoveRows(QModelIndex(), index, index+count-1);
218 list.removeAt(index);
219 emit endRemoveRows();
222 void moveItem(int from, int to) {
223 emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
228 void moveItems(int from, int to, int count) {
229 emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
230 tst_qsggridview_move(from, to, count, &list);
234 void modifyItem(int idx, const QString &name, const QString &number) {
235 list[idx] = QPair<QString,QString>(name, number);
236 emit dataChanged(index(idx,0), index(idx,0));
240 int count = list.count();
241 emit beginRemoveRows(QModelIndex(), 0, count-1);
243 emit endRemoveRows();
248 QList<QPair<QString,QString> > list;
251 tst_QSGGridView::tst_QSGGridView()
255 void tst_QSGGridView::items()
257 QSGView *canvas = createView();
260 model.addItem("Fred", "12345");
261 model.addItem("John", "2345");
262 model.addItem("Bob", "54321");
263 model.addItem("Billy", "22345");
264 model.addItem("Sam", "2945");
265 model.addItem("Ben", "04321");
266 model.addItem("Jim", "0780");
268 QDeclarativeContext *ctxt = canvas->rootContext();
269 ctxt->setContextProperty("testModel", &model);
270 ctxt->setContextProperty("testRightToLeft", QVariant(false));
271 ctxt->setContextProperty("testTopToBottom", QVariant(false));
273 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
274 qApp->processEvents();
276 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
277 QTRY_VERIFY(gridview != 0);
279 QSGItem *contentItem = gridview->contentItem();
280 QTRY_VERIFY(contentItem != 0);
282 QTRY_COMPARE(gridview->count(), model.count());
283 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
284 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
286 for (int i = 0; i < model.count(); ++i) {
287 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
288 QTRY_VERIFY(name != 0);
289 QTRY_COMPARE(name->text(), model.name(i));
290 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
291 QTRY_VERIFY(number != 0);
292 QTRY_COMPARE(number->text(), model.number(i));
295 // set an empty model and confirm that items are destroyed
297 ctxt->setContextProperty("testModel", &model2);
299 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
300 QTRY_VERIFY(itemCount == 0);
305 void tst_QSGGridView::changed()
307 QSGView *canvas = createView();
310 model.addItem("Fred", "12345");
311 model.addItem("John", "2345");
312 model.addItem("Bob", "54321");
313 model.addItem("Billy", "22345");
314 model.addItem("Sam", "2945");
315 model.addItem("Ben", "04321");
316 model.addItem("Jim", "0780");
318 QDeclarativeContext *ctxt = canvas->rootContext();
319 ctxt->setContextProperty("testModel", &model);
320 ctxt->setContextProperty("testRightToLeft", QVariant(false));
321 ctxt->setContextProperty("testTopToBottom", QVariant(false));
323 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
324 qApp->processEvents();
326 QSGFlickable *gridview = findItem<QSGFlickable>(canvas->rootObject(), "grid");
327 QTRY_VERIFY(gridview != 0);
329 QSGItem *contentItem = gridview->contentItem();
330 QTRY_VERIFY(contentItem != 0);
332 model.modifyItem(1, "Will", "9876");
333 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
334 QTRY_VERIFY(name != 0);
335 QTRY_COMPARE(name->text(), model.name(1));
336 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
337 QTRY_VERIFY(number != 0);
338 QTRY_COMPARE(number->text(), model.number(1));
343 void tst_QSGGridView::inserted()
345 QSGView *canvas = createView();
349 model.addItem("Fred", "12345");
350 model.addItem("John", "2345");
351 model.addItem("Bob", "54321");
353 QDeclarativeContext *ctxt = canvas->rootContext();
354 ctxt->setContextProperty("testModel", &model);
355 ctxt->setContextProperty("testRightToLeft", QVariant(false));
356 ctxt->setContextProperty("testTopToBottom", QVariant(false));
358 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
359 qApp->processEvents();
361 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
362 QTRY_VERIFY(gridview != 0);
364 QSGItem *contentItem = gridview->contentItem();
365 QTRY_VERIFY(contentItem != 0);
367 model.insertItem(1, "Will", "9876");
369 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
370 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
372 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
373 QTRY_VERIFY(name != 0);
374 QTRY_COMPARE(name->text(), model.name(1));
375 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
376 QTRY_VERIFY(number != 0);
377 QTRY_COMPARE(number->text(), model.number(1));
379 // Checks that onAdd is called
380 int added = canvas->rootObject()->property("added").toInt();
381 QTRY_COMPARE(added, 1);
383 // Confirm items positioned correctly
384 for (int i = 0; i < model.count(); ++i) {
385 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
386 QTRY_COMPARE(item->x(), (i%3)*80.0);
387 QTRY_COMPARE(item->y(), (i/3)*60.0);
390 model.insertItem(0, "Foo", "1111"); // zero index, and current item
392 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
394 name = findItem<QSGText>(contentItem, "textName", 0);
395 QTRY_VERIFY(name != 0);
396 QTRY_COMPARE(name->text(), model.name(0));
397 number = findItem<QSGText>(contentItem, "textNumber", 0);
398 QTRY_VERIFY(number != 0);
399 QTRY_COMPARE(number->text(), model.number(0));
401 QTRY_COMPARE(gridview->currentIndex(), 1);
403 // Confirm items positioned correctly
404 for (int i = 0; i < model.count(); ++i) {
405 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
406 QTRY_VERIFY(item->x() == (i%3)*80);
407 QTRY_VERIFY(item->y() == (i/3)*60);
410 for (int i = model.count(); i < 30; ++i)
411 model.insertItem(i, "Hello", QString::number(i));
413 gridview->setContentY(120);
415 // Insert item outside visible area
416 model.insertItem(1, "Hello", "1324");
418 QTRY_VERIFY(gridview->contentY() == 120);
423 void tst_QSGGridView::removed()
425 QSGView *canvas = createView();
429 for (int i = 0; i < 40; i++)
430 model.addItem("Item" + QString::number(i), "");
432 QDeclarativeContext *ctxt = canvas->rootContext();
433 ctxt->setContextProperty("testModel", &model);
434 ctxt->setContextProperty("testRightToLeft", QVariant(false));
435 ctxt->setContextProperty("testTopToBottom", QVariant(false));
437 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
438 qApp->processEvents();
440 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
441 QTRY_VERIFY(gridview != 0);
443 QSGItem *contentItem = gridview->contentItem();
444 QTRY_VERIFY(contentItem != 0);
447 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
449 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
450 QTRY_VERIFY(name != 0);
451 QTRY_COMPARE(name->text(), model.name(1));
452 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
453 QTRY_VERIFY(number != 0);
454 QTRY_COMPARE(number->text(), model.number(1));
457 // Checks that onRemove is called
458 QString removed = canvas->rootObject()->property("removed").toString();
459 QTRY_COMPARE(removed, QString("Item1"));
461 // Confirm items positioned correctly
462 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
463 for (int i = 0; i < model.count() && i < itemCount; ++i) {
464 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
465 if (!item) qWarning() << "Item" << i << "not found";
466 QTRY_VERIFY(item->x() == (i%3)*80);
467 QTRY_VERIFY(item->y() == (i/3)*60);
470 // Remove first item (which is the current item);
472 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
474 name = findItem<QSGText>(contentItem, "textName", 0);
475 QTRY_VERIFY(name != 0);
476 QTRY_COMPARE(name->text(), model.name(0));
477 number = findItem<QSGText>(contentItem, "textNumber", 0);
478 QTRY_VERIFY(number != 0);
479 QTRY_COMPARE(number->text(), model.number(0));
482 // Confirm items positioned correctly
483 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
484 for (int i = 0; i < model.count() && i < itemCount; ++i) {
485 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
486 if (!item) qWarning() << "Item" << i << "not found";
487 QTRY_VERIFY(item->x() == (i%3)*80);
488 QTRY_VERIFY(item->y() == (i/3)*60);
491 // Remove items not visible
492 model.removeItem(25);
493 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
495 // Confirm items positioned correctly
496 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
497 for (int i = 0; i < model.count() && i < itemCount; ++i) {
498 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
499 if (!item) qWarning() << "Item" << i << "not found";
500 QTRY_VERIFY(item->x() == (i%3)*80);
501 QTRY_VERIFY(item->y() == (i/3)*60);
504 // Remove items before visible
505 gridview->setContentY(120);
506 gridview->setCurrentIndex(10);
508 // Setting currentIndex above shouldn't cause view to scroll
509 QTRY_COMPARE(gridview->contentY(), 120.0);
512 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
514 // Confirm items positioned correctly
515 for (int i = 6; i < 18; ++i) {
516 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
517 if (!item) qWarning() << "Item" << i << "not found";
518 QTRY_VERIFY(item->x() == (i%3)*80);
519 QTRY_VERIFY(item->y() == (i/3)*60);
522 // Remove currentIndex
523 QSGItem *oldCurrent = gridview->currentItem();
525 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
527 QTRY_COMPARE(gridview->currentIndex(), 9);
528 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
530 gridview->setContentY(0);
531 // let transitions settle.
534 // Confirm items positioned correctly
535 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
536 for (int i = 0; i < model.count() && i < itemCount; ++i) {
537 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
538 QTRY_VERIFY(item->x() == (i%3)*80);
539 QTRY_VERIFY(item->y() == (i/3)*60);
542 // remove item outside current view.
543 gridview->setCurrentIndex(32);
544 gridview->setContentY(240);
546 model.removeItem(30);
547 QTRY_VERIFY(gridview->currentIndex() == 31);
549 // remove current item beyond visible items.
550 gridview->setCurrentIndex(20);
551 gridview->setContentY(0);
552 model.removeItem(20);
554 QTRY_COMPARE(gridview->currentIndex(), 20);
555 QTRY_VERIFY(gridview->currentItem() != 0);
557 // remove item before current, but visible
558 gridview->setCurrentIndex(8);
559 gridview->setContentY(240);
560 oldCurrent = gridview->currentItem();
563 QTRY_COMPARE(gridview->currentIndex(), 7);
564 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
569 void tst_QSGGridView::clear()
571 QSGView *canvas = createView();
574 for (int i = 0; i < 30; i++)
575 model.addItem("Item" + QString::number(i), "");
577 QDeclarativeContext *ctxt = canvas->rootContext();
578 ctxt->setContextProperty("testModel", &model);
579 ctxt->setContextProperty("testRightToLeft", QVariant(false));
580 ctxt->setContextProperty("testTopToBottom", QVariant(false));
582 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
583 qApp->processEvents();
585 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
586 QVERIFY(gridview != 0);
588 QSGItem *contentItem = gridview->contentItem();
589 QVERIFY(contentItem != 0);
593 QVERIFY(gridview->count() == 0);
594 QVERIFY(gridview->currentItem() == 0);
595 QVERIFY(gridview->contentY() == 0);
596 QVERIFY(gridview->currentIndex() == -1);
598 // confirm sanity when adding an item to cleared list
599 model.addItem("New", "1");
600 QTRY_COMPARE(gridview->count(), 1);
601 QVERIFY(gridview->currentItem() != 0);
602 QVERIFY(gridview->currentIndex() == 0);
607 void tst_QSGGridView::moved()
609 QFETCH(qreal, contentY);
613 QFETCH(qreal, itemsOffsetAfterMove);
617 QSGView *canvas = createView();
621 for (int i = 0; i < 30; i++)
622 model.addItem("Item" + QString::number(i), "");
624 QDeclarativeContext *ctxt = canvas->rootContext();
625 ctxt->setContextProperty("testModel", &model);
626 ctxt->setContextProperty("testRightToLeft", QVariant(false));
627 ctxt->setContextProperty("testTopToBottom", QVariant(false));
629 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
630 qApp->processEvents();
632 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
633 QTRY_VERIFY(gridview != 0);
635 QSGItem *contentItem = gridview->contentItem();
636 QTRY_VERIFY(contentItem != 0);
638 QSGItem *currentItem = gridview->currentItem();
639 QTRY_VERIFY(currentItem != 0);
641 gridview->setContentY(contentY);
642 model.moveItems(from, to, count);
644 // wait for items to move
647 // Confirm items positioned correctly and indexes correct
648 int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
649 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
650 for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
651 if (i >= firstVisibleIndex + 18) // index has moved out of view
653 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
654 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
656 QTRY_COMPARE(item->x(), (i%3)*80.0);
657 QTRY_COMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove);
659 name = findItem<QSGText>(contentItem, "textName", i);
661 QTRY_COMPARE(name->text(), model.name(i));
662 number = findItem<QSGText>(contentItem, "textNumber", i);
663 QVERIFY(number != 0);
664 QTRY_COMPARE(number->text(), model.number(i));
666 // current index should have been updated
667 if (item == currentItem)
668 QTRY_COMPARE(gridview->currentIndex(), i);
674 void tst_QSGGridView::moved_data()
676 QTest::addColumn<qreal>("contentY");
677 QTest::addColumn<int>("from");
678 QTest::addColumn<int>("to");
679 QTest::addColumn<int>("count");
680 QTest::addColumn<qreal>("itemsOffsetAfterMove");
682 // model starts with 30 items, each 80x60, in area 240x320
683 // 18 items should be visible at a time
685 QTest::newRow("move 1 forwards, within visible items")
690 QTest::newRow("move 1 forwards, from non-visible -> visible")
691 << 120.0 // show 6-23
693 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
695 QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
696 << 120.0 // // show 6-23
698 << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
700 QTest::newRow("move 1 forwards, from visible -> non-visible")
705 QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)")
711 QTest::newRow("move 1 backwards, within visible items")
716 QTest::newRow("move 1 backwards, within visible items (to first index)")
721 QTest::newRow("move 1 backwards, from non-visible -> visible")
726 QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)")
731 QTest::newRow("move 1 backwards, from visible -> non-visible")
732 << 120.0 // show 6-23
734 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
736 QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
737 << 120.0 // show 6-23
739 << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
742 QTest::newRow("move multiple forwards, within visible items")
745 << 60.0; // moved 3 items (i.e. 1 row) down
747 QTest::newRow("move multiple forwards, from non-visible -> visible")
748 << 120.0 // show 6-23
750 << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
752 QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
753 << 120.0 // show 6-23
755 << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
757 QTest::newRow("move multiple forwards, from visible -> non-visible")
762 QTest::newRow("move multiple forwards, from visible -> non-visible (move first item)")
768 QTest::newRow("move multiple backwards, within visible items")
773 QTest::newRow("move multiple backwards, from non-visible -> visible")
778 QTest::newRow("move multiple backwards, from non-visible -> visible (move last item)")
783 QTest::newRow("move multiple backwards, from visible -> non-visible")
784 << 120.0 // show 6-23
786 << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
788 QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
789 << 120.0 // show 6-23
791 << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
795 enum { Inserted, Removed, Moved, SetCurrent } type;
800 static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
801 static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
802 static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
803 static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
805 Q_DECLARE_METATYPE(QList<ListChange>)
807 void tst_QSGGridView::multipleChanges()
809 QFETCH(int, startCount);
810 QFETCH(QList<ListChange>, changes);
811 QFETCH(int, newCount);
812 QFETCH(int, newCurrentIndex);
814 QSGView *canvas = createView();
818 for (int i = 0; i < startCount; i++)
819 model.addItem("Item" + QString::number(i), "");
821 QDeclarativeContext *ctxt = canvas->rootContext();
822 ctxt->setContextProperty("testModel", &model);
823 ctxt->setContextProperty("testRightToLeft", QVariant(false));
824 ctxt->setContextProperty("testTopToBottom", QVariant(false));
826 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
827 qApp->processEvents();
829 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
830 QTRY_VERIFY(gridview != 0);
832 for (int i=0; i<changes.count(); i++) {
833 switch (changes[i].type) {
834 case ListChange::Inserted:
836 QList<QPair<QString, QString> > items;
837 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
838 items << qMakePair(QString("new item " + j), QString::number(j));
839 model.insertItems(changes[i].index, items);
842 case ListChange::Removed:
843 model.removeItems(changes[i].index, changes[i].count);
845 case ListChange::Moved:
846 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
848 case ListChange::SetCurrent:
849 gridview->setCurrentIndex(changes[i].index);
854 QTRY_COMPARE(gridview->count(), newCount);
855 QCOMPARE(gridview->count(), model.count());
856 QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
860 QSGItem *contentItem = gridview->contentItem();
861 QTRY_VERIFY(contentItem != 0);
862 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
863 for (int i=0; i < model.count() && i < itemCount; ++i) {
864 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
865 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
866 name = findItem<QSGText>(contentItem, "textName", i);
868 QTRY_COMPARE(name->text(), model.name(i));
869 number = findItem<QSGText>(contentItem, "textNumber", i);
870 QVERIFY(number != 0);
871 QTRY_COMPARE(number->text(), model.number(i));
877 void tst_QSGGridView::multipleChanges_data()
879 QTest::addColumn<int>("startCount");
880 QTest::addColumn<QList<ListChange> >("changes");
881 QTest::addColumn<int>("newCount");
882 QTest::addColumn<int>("newCurrentIndex");
884 QList<ListChange> changes;
886 for (int i=1; i<30; i++)
887 changes << ListChange::remove(0);
888 QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
890 changes << ListChange::remove(0);
891 QTest::newRow("remove all") << 30 << changes << 0 << -1;
894 changes << ListChange::setCurrent(29);
895 for (int i=29; i>0; i--)
896 changes << ListChange::remove(i);
897 QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
899 QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
900 << ListChange::remove(0, 1)
901 << ListChange::insert(0, 1)
904 QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
905 << ListChange::setCurrent(2)
906 << ListChange::remove(2, 1)
907 << ListChange::insert(2, 1)
910 QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
911 << ListChange::setCurrent(1)
912 << ListChange::remove(1, 3)
913 << ListChange::insert(2, 2)
916 QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
917 << ListChange::setCurrent(2)
918 << ListChange::remove(1, 3)
919 << ListChange::move(1, 5, 1)
922 QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
923 << ListChange::setCurrent(5)
924 << ListChange::remove(4, 3)
925 << ListChange::move(4, 1, 1)
929 QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
930 << ListChange::insert(0, 2)
931 << ListChange::insert(0, 4)
932 << ListChange::insert(0, 6)
935 QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
936 << ListChange::insert(0, 2)
937 << ListChange::insert(0, 4)
938 << ListChange::insert(0, 6)
939 << ListChange::setCurrent(3)
940 << ListChange::insert(3, 2)
943 QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
944 << ListChange::insert(0, 30)
945 << ListChange::remove(0, 30)
948 QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
949 << ListChange::insert(1)
950 << ListChange::setCurrent(1)
951 << ListChange::remove(1)
954 QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
955 << ListChange::insert(0, 10)
956 << ListChange::remove(5, 10)
959 QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
960 << ListChange::insert(0, 3)
961 << ListChange::move(0, 10, 3)
964 QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
965 << ListChange::insert(0, 3)
966 << ListChange::move(0, 8, 5)
969 QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
970 << ListChange::setCurrent(9)
971 << ListChange::insert(10, 3)
972 << ListChange::move(8, 0, 5)
976 QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
977 << ListChange::setCurrent(1)
978 << ListChange::move(1, 2, 2)
979 << ListChange::move(2, 1, 2)
982 QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
983 << ListChange::setCurrent(2)
984 << ListChange::move(1, 2, 3)
985 << ListChange::move(3, 0, 5)
988 QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
989 << ListChange::setCurrent(5)
990 << ListChange::move(5, 0, 1)
991 << ListChange::remove(0)
994 QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
995 << ListChange::setCurrent(5)
996 << ListChange::move(5, 0, 1)
997 << ListChange::insert(0)
1000 QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
1001 << ListChange::setCurrent(1)
1002 << ListChange::move(5, 1, 3)
1003 << ListChange::remove(1, 3)
1006 QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
1007 << ListChange::setCurrent(5)
1008 << ListChange::move(5, 1, 3)
1009 << ListChange::insert(1, 5)
1012 QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
1013 << ListChange::setCurrent(3)
1014 << ListChange::move(0, 1, 2)
1015 << ListChange::insert(3, 5)
1019 QTest::newRow("clear current") << 0 << (QList<ListChange>()
1020 << ListChange::insert(0, 5)
1021 << ListChange::setCurrent(-1)
1022 << ListChange::remove(0, 5)
1023 << ListChange::insert(0, 5)
1028 void tst_QSGGridView::swapWithFirstItem()
1031 QSGView *canvas = createView();
1035 for (int i = 0; i < 30; i++)
1036 model.addItem("Item" + QString::number(i), "");
1038 QDeclarativeContext *ctxt = canvas->rootContext();
1039 ctxt->setContextProperty("testModel", &model);
1040 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1041 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1043 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1044 qApp->processEvents();
1046 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1047 QTRY_VERIFY(gridview != 0);
1049 // ensure content position is stable
1050 gridview->setContentY(0);
1051 model.moveItem(10, 0);
1052 QTRY_VERIFY(gridview->contentY() == 0);
1057 void tst_QSGGridView::currentIndex()
1060 for (int i = 0; i < 60; i++)
1061 model.addItem("Item" + QString::number(i), QString::number(i));
1063 QSGView *canvas = new QSGView(0);
1064 canvas->setGeometry(0,0,240,320);
1067 QDeclarativeContext *ctxt = canvas->rootContext();
1068 ctxt->setContextProperty("testModel", &model);
1070 QString filename(SRCDIR "/data/gridview-initCurrent.qml");
1071 canvas->setSource(QUrl::fromLocalFile(filename));
1073 qApp->processEvents();
1075 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1076 QVERIFY(gridview != 0);
1078 QSGItem *contentItem = gridview->contentItem();
1079 QVERIFY(contentItem != 0);
1081 // current item should be third item
1082 QCOMPARE(gridview->currentIndex(), 35);
1083 QCOMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 35));
1084 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
1085 QCOMPARE(gridview->contentY(), 400.0);
1087 gridview->moveCurrentIndexRight();
1088 QCOMPARE(gridview->currentIndex(), 36);
1089 gridview->moveCurrentIndexDown();
1090 QCOMPARE(gridview->currentIndex(), 39);
1091 gridview->moveCurrentIndexUp();
1092 QCOMPARE(gridview->currentIndex(), 36);
1093 gridview->moveCurrentIndexLeft();
1094 QCOMPARE(gridview->currentIndex(), 35);
1097 gridview->setCurrentIndex(0);
1098 QCOMPARE(gridview->currentIndex(), 0);
1099 // confirm that the velocity is updated
1100 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
1102 gridview->moveCurrentIndexUp();
1103 QCOMPARE(gridview->currentIndex(), 0);
1105 gridview->moveCurrentIndexLeft();
1106 QCOMPARE(gridview->currentIndex(), 0);
1108 gridview->setCurrentIndex(model.count()-1);
1109 QCOMPARE(gridview->currentIndex(), model.count()-1);
1111 gridview->moveCurrentIndexRight();
1112 QCOMPARE(gridview->currentIndex(), model.count()-1);
1114 gridview->moveCurrentIndexDown();
1115 QCOMPARE(gridview->currentIndex(), model.count()-1);
1118 gridview->setWrapEnabled(true);
1120 gridview->setCurrentIndex(0);
1121 QCOMPARE(gridview->currentIndex(), 0);
1123 gridview->moveCurrentIndexLeft();
1124 QCOMPARE(gridview->currentIndex(), model.count()-1);
1126 qApp->processEvents();
1127 QTRY_COMPARE(gridview->contentY(), 880.0);
1129 gridview->moveCurrentIndexRight();
1130 QCOMPARE(gridview->currentIndex(), 0);
1132 QTRY_COMPARE(gridview->contentY(), 0.0);
1135 // footer should become visible if it is out of view, and then current index moves to the first row
1136 canvas->rootObject()->setProperty("showFooter", true);
1137 QTRY_VERIFY(gridview->footerItem());
1138 gridview->setCurrentIndex(model.count()-3);
1139 QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height());
1140 gridview->setCurrentIndex(model.count()-2);
1141 QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height());
1142 canvas->rootObject()->setProperty("showFooter", false);
1144 // header should become visible if it is out of view, and then current index moves to the last row
1145 canvas->rootObject()->setProperty("showHeader", true);
1146 QTRY_VERIFY(gridview->headerItem());
1147 gridview->setCurrentIndex(3);
1148 QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY());
1149 gridview->setCurrentIndex(1);
1150 QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height());
1151 canvas->rootObject()->setProperty("showHeader", false);
1155 canvas->requestActivateWindow();
1157 // to be safe and avoid failing setFocus with window managers
1158 qt_x11_wait_for_window_manager(canvas);
1160 #ifdef QT_BUILD_INTERNAL
1161 QEXPECT_FAIL("", "QTBUG-21680 - Waiting for active window fails for Developer build", Abort);
1163 QTRY_VERIFY(canvas->windowState() == Qt::WindowActive);
1164 qApp->processEvents();
1166 gridview->setCurrentIndex(0);
1168 QTest::keyClick(canvas, Qt::Key_Down);
1169 QCOMPARE(gridview->currentIndex(), 3);
1171 QTest::keyClick(canvas, Qt::Key_Up);
1172 QCOMPARE(gridview->currentIndex(), 0);
1174 // hold down Key_Down
1175 for (int i=0; i<(model.count() / 3) - 1; i++) {
1176 QTest::simulateEvent(canvas, true, Qt::Key_Down, Qt::NoModifier, "", true);
1177 QTRY_COMPARE(gridview->currentIndex(), i*3 + 3);
1179 QTest::keyRelease(canvas, Qt::Key_Down);
1180 QTRY_COMPARE(gridview->currentIndex(), 57);
1181 QTRY_COMPARE(gridview->contentY(), 880.0);
1184 for (int i=(model.count() / 3) - 1; i > 0; i--) {
1185 QTest::simulateEvent(canvas, true, Qt::Key_Up, Qt::NoModifier, "", true);
1186 QTRY_COMPARE(gridview->currentIndex(), i*3 - 3);
1188 QTest::keyRelease(canvas, Qt::Key_Up);
1189 QTRY_COMPARE(gridview->currentIndex(), 0);
1190 QTRY_COMPARE(gridview->contentY(), 0.0);
1193 gridview->setFlow(QSGGridView::TopToBottom);
1195 canvas->requestActivateWindow();
1197 // to be safe and avoid failing setFocus with window managers
1198 qt_x11_wait_for_window_manager(canvas);
1200 QTRY_VERIFY((canvas->windowState() == Qt::WindowActive));
1201 qApp->processEvents();
1203 QTest::keyClick(canvas, Qt::Key_Right);
1204 QCOMPARE(gridview->currentIndex(), 5);
1206 QTest::keyClick(canvas, Qt::Key_Left);
1207 QCOMPARE(gridview->currentIndex(), 0);
1209 QTest::keyClick(canvas, Qt::Key_Down);
1210 QCOMPARE(gridview->currentIndex(), 1);
1212 QTest::keyClick(canvas, Qt::Key_Up);
1213 QCOMPARE(gridview->currentIndex(), 0);
1215 // hold down Key_Right
1216 for (int i=0; i<(model.count() / 5) - 1; i++) {
1217 QTest::simulateEvent(canvas, true, Qt::Key_Right, Qt::NoModifier, "", true);
1218 QTRY_COMPARE(gridview->currentIndex(), i*5 + 5);
1220 QTest::keyRelease(canvas, Qt::Key_Right);
1221 QTRY_COMPARE(gridview->currentIndex(), 55);
1222 QTRY_COMPARE(gridview->contentX(), 720.0);
1224 // hold down Key_Left
1225 for (int i=(model.count() / 5) - 1; i > 0; i--) {
1226 QTest::simulateEvent(canvas, true, Qt::Key_Left, Qt::NoModifier, "", true);
1227 QTRY_COMPARE(gridview->currentIndex(), i*5 - 5);
1229 QTest::keyRelease(canvas, Qt::Key_Left);
1230 QTRY_COMPARE(gridview->currentIndex(), 0);
1231 QTRY_COMPARE(gridview->contentX(), 0.0);
1234 // turn off auto highlight
1235 gridview->setHighlightFollowsCurrentItem(false);
1236 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1237 QVERIFY(gridview->highlightItem());
1238 qreal hlPosX = gridview->highlightItem()->x();
1239 qreal hlPosY = gridview->highlightItem()->y();
1241 gridview->setCurrentIndex(5);
1242 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1243 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1245 // insert item before currentIndex
1246 gridview->setCurrentIndex(28);
1247 model.insertItem(0, "Foo", "1111");
1248 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1250 // check removing highlight by setting currentIndex to -1;
1251 gridview->setCurrentIndex(-1);
1253 QCOMPARE(gridview->currentIndex(), -1);
1254 QVERIFY(!gridview->highlightItem());
1255 QVERIFY(!gridview->currentItem());
1257 gridview->setHighlightFollowsCurrentItem(true);
1259 gridview->setFlow(QSGGridView::LeftToRight);
1260 gridview->setLayoutDirection(Qt::RightToLeft);
1262 canvas->requestActivateWindow();
1264 // to be safe and avoid failing setFocus with window managers
1265 qt_x11_wait_for_window_manager(canvas);
1267 QTRY_VERIFY(canvas->windowState() == Qt::WindowActive);
1268 qApp->processEvents();
1270 gridview->setCurrentIndex(35);
1272 QTest::keyClick(canvas, Qt::Key_Right);
1273 QCOMPARE(gridview->currentIndex(), 34);
1275 QTest::keyClick(canvas, Qt::Key_Down);
1276 QCOMPARE(gridview->currentIndex(), 37);
1278 QTest::keyClick(canvas, Qt::Key_Up);
1279 QCOMPARE(gridview->currentIndex(), 34);
1281 QTest::keyClick(canvas, Qt::Key_Left);
1282 QCOMPARE(gridview->currentIndex(), 35);
1285 // turn off auto highlight
1286 gridview->setHighlightFollowsCurrentItem(false);
1287 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
1288 QVERIFY(gridview->highlightItem());
1289 hlPosX = gridview->highlightItem()->x();
1290 hlPosY = gridview->highlightItem()->y();
1292 gridview->setCurrentIndex(5);
1293 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
1294 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
1296 // insert item before currentIndex
1297 gridview->setCurrentIndex(28);
1298 model.insertItem(0, "Foo", "1111");
1299 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1301 // check removing highlight by setting currentIndex to -1;
1302 gridview->setCurrentIndex(-1);
1304 QCOMPARE(gridview->currentIndex(), -1);
1305 QVERIFY(!gridview->highlightItem());
1306 QVERIFY(!gridview->currentItem());
1311 void tst_QSGGridView::noCurrentIndex()
1314 for (int i = 0; i < 60; i++)
1315 model.addItem("Item" + QString::number(i), QString::number(i));
1317 QSGView *canvas = new QSGView(0);
1318 canvas->setGeometry(0,0,240,320);
1320 QDeclarativeContext *ctxt = canvas->rootContext();
1321 ctxt->setContextProperty("testModel", &model);
1323 QString filename(SRCDIR "/data/gridview-noCurrent.qml");
1324 canvas->setSource(QUrl::fromLocalFile(filename));
1326 qApp->processEvents();
1328 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1329 QVERIFY(gridview != 0);
1331 QSGItem *contentItem = gridview->contentItem();
1332 QVERIFY(contentItem != 0);
1334 // current index should be -1
1335 QCOMPARE(gridview->currentIndex(), -1);
1336 QVERIFY(!gridview->currentItem());
1337 QVERIFY(!gridview->highlightItem());
1338 QCOMPARE(gridview->contentY(), 0.0);
1340 gridview->setCurrentIndex(5);
1341 QCOMPARE(gridview->currentIndex(), 5);
1342 QVERIFY(gridview->currentItem());
1343 QVERIFY(gridview->highlightItem());
1348 void tst_QSGGridView::changeFlow()
1350 QSGView *canvas = createView();
1353 for (int i = 0; i < 30; i++)
1354 model.addItem("Item" + QString::number(i), QString::number(i));
1356 QDeclarativeContext *ctxt = canvas->rootContext();
1357 ctxt->setContextProperty("testModel", &model);
1358 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1359 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1361 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1362 qApp->processEvents();
1364 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1365 QTRY_VERIFY(gridview != 0);
1367 QSGItem *contentItem = gridview->contentItem();
1368 QTRY_VERIFY(contentItem != 0);
1370 // Confirm items positioned correctly and indexes correct
1371 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1372 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1373 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1374 if (!item) qWarning() << "Item" << i << "not found";
1376 QTRY_COMPARE(item->x(), qreal((i%3)*80));
1377 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1378 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1379 QTRY_VERIFY(name != 0);
1380 QTRY_COMPARE(name->text(), model.name(i));
1381 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1382 QTRY_VERIFY(number != 0);
1383 QTRY_COMPARE(number->text(), model.number(i));
1386 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1388 // Confirm items positioned correctly and indexes correct
1389 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1390 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1391 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1392 if (!item) qWarning() << "Item" << i << "not found";
1394 QTRY_COMPARE(item->x(), qreal((i/5)*80));
1395 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1396 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1397 QTRY_VERIFY(name != 0);
1398 QTRY_COMPARE(name->text(), model.name(i));
1399 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1400 QTRY_VERIFY(number != 0);
1401 QTRY_COMPARE(number->text(), model.number(i));
1404 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1406 // Confirm items positioned correctly and indexes correct
1407 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1408 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1409 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1410 if (!item) qWarning() << "Item" << i << "not found";
1412 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
1413 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1414 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1415 QTRY_VERIFY(name != 0);
1416 QTRY_COMPARE(name->text(), model.name(i));
1417 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1418 QTRY_VERIFY(number != 0);
1419 QTRY_COMPARE(number->text(), model.number(i));
1421 gridview->setContentX(100);
1422 QTRY_COMPARE(gridview->contentX(), 100.);
1423 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1424 QTRY_COMPARE(gridview->contentX(), 0.);
1426 // Confirm items positioned correctly and indexes correct
1427 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1428 for (int i = 0; i < model.count() && i < itemCount; ++i) {
1429 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1430 if (!item) qWarning() << "Item" << i << "not found";
1432 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
1433 QTRY_COMPARE(item->y(), qreal((i/3)*60));
1434 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
1435 QTRY_VERIFY(name != 0);
1436 QTRY_COMPARE(name->text(), model.name(i));
1437 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
1438 QTRY_VERIFY(number != 0);
1439 QTRY_COMPARE(number->text(), model.number(i));
1445 void tst_QSGGridView::defaultValues()
1447 QDeclarativeEngine engine;
1448 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview3.qml"));
1449 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1451 QTRY_VERIFY(obj != 0);
1452 QTRY_VERIFY(obj->model() == QVariant());
1453 QTRY_VERIFY(obj->delegate() == 0);
1454 QTRY_COMPARE(obj->currentIndex(), -1);
1455 QTRY_VERIFY(obj->currentItem() == 0);
1456 QTRY_COMPARE(obj->count(), 0);
1457 QTRY_VERIFY(obj->highlight() == 0);
1458 QTRY_VERIFY(obj->highlightItem() == 0);
1459 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1460 QTRY_VERIFY(obj->flow() == 0);
1461 QTRY_COMPARE(obj->isWrapEnabled(), false);
1462 QTRY_COMPARE(obj->cacheBuffer(), 0);
1463 QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default?
1464 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1468 void tst_QSGGridView::properties()
1470 QDeclarativeEngine engine;
1471 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview2.qml"));
1472 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1474 QTRY_VERIFY(obj != 0);
1475 QTRY_VERIFY(obj->model() != QVariant());
1476 QTRY_VERIFY(obj->delegate() != 0);
1477 QTRY_COMPARE(obj->currentIndex(), 0);
1478 QTRY_VERIFY(obj->currentItem() != 0);
1479 QTRY_COMPARE(obj->count(), 4);
1480 QTRY_VERIFY(obj->highlight() != 0);
1481 QTRY_VERIFY(obj->highlightItem() != 0);
1482 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1483 QTRY_VERIFY(obj->flow() == 0);
1484 QTRY_COMPARE(obj->isWrapEnabled(), true);
1485 QTRY_COMPARE(obj->cacheBuffer(), 200);
1486 QTRY_COMPARE(obj->cellWidth(), qreal(100));
1487 QTRY_COMPARE(obj->cellHeight(), qreal(100));
1491 void tst_QSGGridView::propertyChanges()
1493 QSGView *canvas = createView();
1494 QTRY_VERIFY(canvas);
1495 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1497 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1498 QTRY_VERIFY(gridView);
1500 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1501 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1502 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1503 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1505 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1506 QTRY_COMPARE(gridView->cacheBuffer(), 10);
1507 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1509 gridView->setWrapEnabled(false);
1510 gridView->setCacheBuffer(3);
1511 gridView->setFlow(QSGGridView::TopToBottom);
1513 QTRY_COMPARE(gridView->isWrapEnabled(), false);
1514 QTRY_COMPARE(gridView->cacheBuffer(), 3);
1515 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1517 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1518 QTRY_COMPARE(cacheBufferSpy.count(),1);
1519 QTRY_COMPARE(flowSpy.count(),1);
1521 gridView->setWrapEnabled(false);
1522 gridView->setCacheBuffer(3);
1523 gridView->setFlow(QSGGridView::TopToBottom);
1525 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1526 QTRY_COMPARE(cacheBufferSpy.count(),1);
1527 QTRY_COMPARE(flowSpy.count(),1);
1529 gridView->setFlow(QSGGridView::LeftToRight);
1530 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1532 gridView->setWrapEnabled(true);
1533 gridView->setCacheBuffer(5);
1534 gridView->setLayoutDirection(Qt::RightToLeft);
1536 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1537 QTRY_COMPARE(gridView->cacheBuffer(), 5);
1538 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1540 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1541 QTRY_COMPARE(cacheBufferSpy.count(),2);
1542 QTRY_COMPARE(layoutSpy.count(),1);
1543 QTRY_COMPARE(flowSpy.count(),2);
1545 gridView->setWrapEnabled(true);
1546 gridView->setCacheBuffer(5);
1547 gridView->setLayoutDirection(Qt::RightToLeft);
1549 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1550 QTRY_COMPARE(cacheBufferSpy.count(),2);
1551 QTRY_COMPARE(layoutSpy.count(),1);
1552 QTRY_COMPARE(flowSpy.count(),2);
1554 gridView->setFlow(QSGGridView::TopToBottom);
1555 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1556 QTRY_COMPARE(flowSpy.count(),3);
1558 gridView->setFlow(QSGGridView::TopToBottom);
1559 QTRY_COMPARE(flowSpy.count(),3);
1564 void tst_QSGGridView::componentChanges()
1566 QSGView *canvas = createView();
1567 QTRY_VERIFY(canvas);
1568 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1570 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1571 QTRY_VERIFY(gridView);
1573 QDeclarativeComponent component(canvas->engine());
1574 component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1576 QDeclarativeComponent delegateComponent(canvas->engine());
1577 delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1579 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1580 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1581 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1582 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1584 gridView->setHighlight(&component);
1585 gridView->setDelegate(&delegateComponent);
1586 gridView->setHeader(&component);
1587 gridView->setFooter(&component);
1589 QTRY_COMPARE(gridView->highlight(), &component);
1590 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1591 QTRY_COMPARE(gridView->header(), &component);
1592 QTRY_COMPARE(gridView->footer(), &component);
1594 QTRY_COMPARE(highlightSpy.count(),1);
1595 QTRY_COMPARE(delegateSpy.count(),1);
1596 QTRY_COMPARE(headerSpy.count(),1);
1597 QTRY_COMPARE(footerSpy.count(),1);
1599 gridView->setHighlight(&component);
1600 gridView->setDelegate(&delegateComponent);
1601 gridView->setHeader(&component);
1602 gridView->setFooter(&component);
1604 QTRY_COMPARE(highlightSpy.count(),1);
1605 QTRY_COMPARE(delegateSpy.count(),1);
1606 QTRY_COMPARE(headerSpy.count(),1);
1607 QTRY_COMPARE(footerSpy.count(),1);
1612 void tst_QSGGridView::modelChanges()
1614 QSGView *canvas = createView();
1615 QTRY_VERIFY(canvas);
1616 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1618 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1619 QTRY_VERIFY(gridView);
1621 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1622 QTRY_VERIFY(alternateModel);
1623 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1624 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1626 gridView->setModel(modelVariant);
1627 QTRY_COMPARE(gridView->model(), modelVariant);
1628 QTRY_COMPARE(modelSpy.count(),1);
1630 gridView->setModel(modelVariant);
1631 QTRY_COMPARE(modelSpy.count(),1);
1633 gridView->setModel(QVariant());
1634 QTRY_COMPARE(modelSpy.count(),2);
1638 void tst_QSGGridView::positionViewAtIndex()
1640 QSGView *canvas = createView();
1643 for (int i = 0; i < 40; i++)
1644 model.addItem("Item" + QString::number(i), "");
1646 QDeclarativeContext *ctxt = canvas->rootContext();
1647 ctxt->setContextProperty("testModel", &model);
1648 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1649 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1651 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1652 qApp->processEvents();
1654 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1655 QTRY_VERIFY(gridview != 0);
1657 QSGItem *contentItem = gridview->contentItem();
1658 QTRY_VERIFY(contentItem != 0);
1660 // Confirm items positioned correctly
1661 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1662 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1663 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1664 if (!item) qWarning() << "Item" << i << "not found";
1666 QTRY_COMPARE(item->x(), (i%3)*80.);
1667 QTRY_COMPARE(item->y(), (i/3)*60.);
1670 // Position on a currently visible item
1671 gridview->positionViewAtIndex(4, QSGGridView::Beginning);
1672 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1673 QTRY_COMPARE(gridview->contentY(), 60.);
1675 // Confirm items positioned correctly
1676 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1677 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1678 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1679 if (!item) qWarning() << "Item" << i << "not found";
1681 QTRY_COMPARE(item->x(), (i%3)*80.);
1682 QTRY_COMPARE(item->y(), (i/3)*60.);
1685 // Position on an item beyond the visible items
1686 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1687 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1688 QTRY_COMPARE(gridview->contentY(), 420.);
1690 // Confirm items positioned correctly
1691 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1692 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1693 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1694 if (!item) qWarning() << "Item" << i << "not found";
1696 QTRY_COMPARE(item->x(), (i%3)*80.);
1697 QTRY_COMPARE(item->y(), (i/3)*60.);
1700 // Position on an item that would leave empty space if positioned at the top
1701 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1702 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1703 QTRY_COMPARE(gridview->contentY(), 520.);
1705 // Confirm items positioned correctly
1706 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1707 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1708 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1709 if (!item) qWarning() << "Item" << i << "not found";
1711 QTRY_COMPARE(item->x(), (i%3)*80.);
1712 QTRY_COMPARE(item->y(), (i/3)*60.);
1715 // Position at the beginning again
1716 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1717 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1718 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1719 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1720 QTRY_COMPARE(gridview->contentY(), 0.);
1722 // Confirm items positioned correctly
1723 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1724 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1725 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1726 if (!item) qWarning() << "Item" << i << "not found";
1728 QTRY_COMPARE(item->x(), (i%3)*80.);
1729 QTRY_COMPARE(item->y(), (i/3)*60.);
1733 gridview->positionViewAtIndex(30, QSGGridView::End);
1734 QTRY_COMPARE(gridview->contentY(), 340.);
1736 // Position in Center
1737 gridview->positionViewAtIndex(15, QSGGridView::Center);
1738 QTRY_COMPARE(gridview->contentY(), 170.);
1740 // Ensure at least partially visible
1741 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1742 QTRY_COMPARE(gridview->contentY(), 170.);
1744 gridview->setContentY(302);
1745 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1746 QTRY_COMPARE(gridview->contentY(), 302.);
1748 gridview->setContentY(360);
1749 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1750 QTRY_COMPARE(gridview->contentY(), 300.);
1752 gridview->setContentY(60);
1753 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1754 QTRY_COMPARE(gridview->contentY(), 60.);
1756 gridview->setContentY(20);
1757 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1758 QTRY_COMPARE(gridview->contentY(), 100.);
1760 // Ensure completely visible
1761 gridview->setContentY(120);
1762 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1763 QTRY_COMPARE(gridview->contentY(), 120.);
1765 gridview->setContentY(302);
1766 gridview->positionViewAtIndex(15, QSGGridView::Contain);
1767 QTRY_COMPARE(gridview->contentY(), 300.);
1769 gridview->setContentY(60);
1770 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1771 QTRY_COMPARE(gridview->contentY(), 100.);
1773 // Test for Top To Bottom layout
1774 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1776 // Confirm items positioned correctly
1777 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1778 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1779 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1780 if (!item) qWarning() << "Item" << i << "not found";
1782 QTRY_COMPARE(item->x(), (i/5)*80.);
1783 QTRY_COMPARE(item->y(), (i%5)*60.);
1787 gridview->positionViewAtIndex(30, QSGGridView::End);
1788 QTRY_COMPARE(gridview->contentX(), 320.);
1789 QTRY_COMPARE(gridview->contentY(), 0.);
1791 // Position in Center
1792 gridview->positionViewAtIndex(15, QSGGridView::Center);
1793 QTRY_COMPARE(gridview->contentX(), 160.);
1795 // Ensure at least partially visible
1796 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1797 QTRY_COMPARE(gridview->contentX(), 160.);
1799 gridview->setContentX(170);
1800 gridview->positionViewAtIndex(25, QSGGridView::Visible);
1801 QTRY_COMPARE(gridview->contentX(), 170.);
1803 gridview->positionViewAtIndex(30, QSGGridView::Visible);
1804 QTRY_COMPARE(gridview->contentX(), 320.);
1806 gridview->setContentX(170);
1807 gridview->positionViewAtIndex(25, QSGGridView::Contain);
1808 QTRY_COMPARE(gridview->contentX(), 240.);
1810 // positionViewAtBeginning
1811 gridview->positionViewAtBeginning();
1812 QTRY_COMPARE(gridview->contentX(), 0.);
1814 gridview->setContentX(80);
1815 canvas->rootObject()->setProperty("showHeader", true);
1816 gridview->positionViewAtBeginning();
1817 QTRY_COMPARE(gridview->contentX(), -30.);
1819 // positionViewAtEnd
1820 gridview->positionViewAtEnd();
1821 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
1823 gridview->setContentX(80);
1824 canvas->rootObject()->setProperty("showFooter", true);
1825 gridview->positionViewAtEnd();
1826 QTRY_COMPARE(gridview->contentX(), 430.);
1828 // set current item to outside visible view, position at beginning
1829 // and ensure highlight moves to current item
1830 gridview->setCurrentIndex(6);
1831 gridview->positionViewAtBeginning();
1832 QTRY_COMPARE(gridview->contentX(), -30.);
1833 QVERIFY(gridview->highlightItem());
1834 QCOMPARE(gridview->highlightItem()->x(), 80.);
1839 void tst_QSGGridView::snapping()
1841 QSGView *canvas = createView();
1844 for (int i = 0; i < 40; i++)
1845 model.addItem("Item" + QString::number(i), "");
1847 QDeclarativeContext *ctxt = canvas->rootContext();
1848 ctxt->setContextProperty("testModel", &model);
1849 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1850 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1852 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1853 qApp->processEvents();
1855 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1856 QTRY_VERIFY(gridview != 0);
1858 gridview->setHeight(220);
1859 QCOMPARE(gridview->height(), 220.);
1861 gridview->positionViewAtIndex(12, QSGGridView::Visible);
1862 QCOMPARE(gridview->contentY(), 80.);
1864 gridview->setContentY(0);
1865 QCOMPARE(gridview->contentY(), 0.);
1867 gridview->setSnapMode(QSGGridView::SnapToRow);
1868 QCOMPARE(gridview->snapMode(), QSGGridView::SnapToRow);
1870 gridview->positionViewAtIndex(12, QSGGridView::Visible);
1871 QCOMPARE(gridview->contentY(), 60.);
1873 gridview->positionViewAtIndex(15, QSGGridView::End);
1874 QCOMPARE(gridview->contentY(), 120.);
1880 void tst_QSGGridView::mirroring()
1882 QSGView *canvasA = createView();
1883 canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
1884 QSGGridView *gridviewA = findItem<QSGGridView>(canvasA->rootObject(), "view");
1885 QTRY_VERIFY(gridviewA != 0);
1887 QSGView *canvasB = createView();
1888 canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
1889 QSGGridView *gridviewB = findItem<QSGGridView>(canvasB->rootObject(), "view");
1890 QTRY_VERIFY(gridviewA != 0);
1891 qApp->processEvents();
1893 QList<QString> objectNames;
1894 objectNames << "item1" << "item2"; // << "item3"
1896 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1897 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
1898 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
1901 foreach(const QString objectName, objectNames)
1902 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1904 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1905 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
1908 foreach(const QString objectName, objectNames)
1909 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1911 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
1912 QSGItemPrivate::get(gridviewB)->setLayoutMirror(true);
1913 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
1915 // LTR != LTR+mirror
1916 foreach(const QString objectName, objectNames)
1917 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1919 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
1921 // RTL == LTR+mirror
1922 foreach(const QString objectName, objectNames)
1923 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1925 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
1927 // RTL != RTL+mirror
1928 foreach(const QString objectName, objectNames)
1929 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1931 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1933 // LTR == RTL+mirror
1934 foreach(const QString objectName, objectNames)
1935 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1941 void tst_QSGGridView::positionViewAtIndex_rightToLeft()
1943 QSGView *canvas = createView();
1946 for (int i = 0; i < 40; i++)
1947 model.addItem("Item" + QString::number(i), "");
1949 QDeclarativeContext *ctxt = canvas->rootContext();
1950 ctxt->setContextProperty("testModel", &model);
1951 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1952 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1954 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1955 qApp->processEvents();
1957 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1958 QTRY_VERIFY(gridview != 0);
1960 QSGItem *contentItem = gridview->contentItem();
1961 QTRY_VERIFY(contentItem != 0);
1963 // Confirm items positioned correctly
1964 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1965 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1966 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1967 if (!item) qWarning() << "Item" << i << "not found";
1969 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1970 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1973 // Position on a currently visible item
1974 gridview->positionViewAtIndex(6, QSGGridView::Beginning);
1975 QTRY_COMPARE(gridview->contentX(), -320.);
1977 // Confirm items positioned correctly
1978 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1979 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1980 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1981 if (!item) qWarning() << "Item" << i << "not found";
1983 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1984 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1987 // Position on an item beyond the visible items
1988 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1989 QTRY_COMPARE(gridview->contentX(), -560.);
1991 // Confirm items positioned correctly
1992 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1993 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1994 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1995 if (!item) qWarning() << "Item" << i << "not found";
1997 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1998 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2001 // Position on an item that would leave empty space if positioned at the top
2002 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
2003 QTRY_COMPARE(gridview->contentX(), -640.);
2005 // Confirm items positioned correctly
2006 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2007 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
2008 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2009 if (!item) qWarning() << "Item" << i << "not found";
2011 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2012 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2015 // Position at the beginning again
2016 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
2017 QTRY_COMPARE(gridview->contentX(), -240.);
2019 // Confirm items positioned correctly
2020 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
2021 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
2022 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
2023 if (!item) qWarning() << "Item" << i << "not found";
2025 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
2026 QTRY_COMPARE(item->y(), qreal((i%5)*60));
2030 gridview->positionViewAtIndex(30, QSGGridView::End);
2031 QTRY_COMPARE(gridview->contentX(), -560.);
2033 // Position in Center
2034 gridview->positionViewAtIndex(15, QSGGridView::Center);
2035 QTRY_COMPARE(gridview->contentX(), -400.);
2037 // Ensure at least partially visible
2038 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2039 QTRY_COMPARE(gridview->contentX(), -400.);
2041 gridview->setContentX(-555.);
2042 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2043 QTRY_COMPARE(gridview->contentX(), -555.);
2045 gridview->setContentX(-239);
2046 gridview->positionViewAtIndex(15, QSGGridView::Visible);
2047 QTRY_COMPARE(gridview->contentX(), -320.);
2049 gridview->setContentX(-239);
2050 gridview->positionViewAtIndex(20, QSGGridView::Visible);
2051 QTRY_COMPARE(gridview->contentX(), -400.);
2053 gridview->setContentX(-640);
2054 gridview->positionViewAtIndex(20, QSGGridView::Visible);
2055 QTRY_COMPARE(gridview->contentX(), -560.);
2057 // Ensure completely visible
2058 gridview->setContentX(-400);
2059 gridview->positionViewAtIndex(20, QSGGridView::Contain);
2060 QTRY_COMPARE(gridview->contentX(), -400.);
2062 gridview->setContentX(-315);
2063 gridview->positionViewAtIndex(15, QSGGridView::Contain);
2064 QTRY_COMPARE(gridview->contentX(), -320.);
2066 gridview->setContentX(-640);
2067 gridview->positionViewAtIndex(20, QSGGridView::Contain);
2068 QTRY_COMPARE(gridview->contentX(), -560.);
2073 void tst_QSGGridView::resetModel()
2075 QSGView *canvas = createView();
2077 QStringList strings;
2078 strings << "one" << "two" << "three";
2079 QStringListModel model(strings);
2081 QDeclarativeContext *ctxt = canvas->rootContext();
2082 ctxt->setContextProperty("testModel", &model);
2084 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaygrid.qml"));
2085 qApp->processEvents();
2087 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2088 QTRY_VERIFY(gridview != 0);
2090 QSGItem *contentItem = gridview->contentItem();
2091 QTRY_VERIFY(contentItem != 0);
2093 QTRY_COMPARE(gridview->count(), model.rowCount());
2095 for (int i = 0; i < model.rowCount(); ++i) {
2096 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
2097 QTRY_VERIFY(display != 0);
2098 QTRY_COMPARE(display->text(), strings.at(i));
2102 strings << "four" << "five" << "six" << "seven";
2103 model.setStringList(strings);
2105 QTRY_COMPARE(gridview->count(), model.rowCount());
2107 for (int i = 0; i < model.rowCount(); ++i) {
2108 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
2109 QTRY_VERIFY(display != 0);
2110 QTRY_COMPARE(display->text(), strings.at(i));
2116 void tst_QSGGridView::enforceRange()
2118 QSGView *canvas = createView();
2121 for (int i = 0; i < 30; i++)
2122 model.addItem("Item" + QString::number(i), "");
2124 QDeclarativeContext *ctxt = canvas->rootContext();
2125 ctxt->setContextProperty("testModel", &model);
2126 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2127 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2129 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
2130 qApp->processEvents();
2131 QVERIFY(canvas->rootObject() != 0);
2133 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2134 QTRY_VERIFY(gridview != 0);
2136 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2137 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2138 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
2140 QSGItem *contentItem = gridview->contentItem();
2141 QTRY_VERIFY(contentItem != 0);
2143 // view should be positioned at the top of the range.
2144 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2146 QTRY_COMPARE(gridview->contentY(), -100.0);
2148 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
2149 QTRY_VERIFY(name != 0);
2150 QTRY_COMPARE(name->text(), model.name(0));
2151 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
2152 QTRY_VERIFY(number != 0);
2153 QTRY_COMPARE(number->text(), model.number(0));
2155 // Check currentIndex is updated when contentItem moves
2156 gridview->setContentY(0);
2157 QTRY_COMPARE(gridview->currentIndex(), 2);
2159 gridview->setCurrentIndex(5);
2160 QTRY_COMPARE(gridview->contentY(), 100.);
2163 for (int i = 0; i < 5; i++)
2164 model2.addItem("Item" + QString::number(i), "");
2166 ctxt->setContextProperty("testModel", &model2);
2167 QCOMPARE(gridview->count(), 5);
2172 void tst_QSGGridView::enforceRange_rightToLeft()
2174 QSGView *canvas = createView();
2177 for (int i = 0; i < 30; i++)
2178 model.addItem("Item" + QString::number(i), "");
2180 QDeclarativeContext *ctxt = canvas->rootContext();
2181 ctxt->setContextProperty("testModel", &model);
2182 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2183 ctxt->setContextProperty("testTopToBottom", QVariant(true));
2185 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
2186 qApp->processEvents();
2187 QVERIFY(canvas->rootObject() != 0);
2189 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2190 QTRY_VERIFY(gridview != 0);
2192 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
2193 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
2194 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
2196 QSGItem *contentItem = gridview->contentItem();
2197 QTRY_VERIFY(contentItem != 0);
2199 // view should be positioned at the top of the range.
2200 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2202 QTRY_COMPARE(gridview->contentX(), -100.);
2203 QTRY_COMPARE(gridview->contentY(), 0.0);
2205 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
2206 QTRY_VERIFY(name != 0);
2207 QTRY_COMPARE(name->text(), model.name(0));
2208 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
2209 QTRY_VERIFY(number != 0);
2210 QTRY_COMPARE(number->text(), model.number(0));
2212 // Check currentIndex is updated when contentItem moves
2213 gridview->setContentX(-200);
2214 QTRY_COMPARE(gridview->currentIndex(), 3);
2216 gridview->setCurrentIndex(7);
2217 QTRY_COMPARE(gridview->contentX(), -300.);
2218 QTRY_COMPARE(gridview->contentY(), 0.0);
2221 for (int i = 0; i < 5; i++)
2222 model2.addItem("Item" + QString::number(i), "");
2224 ctxt->setContextProperty("testModel", &model2);
2225 QCOMPARE(gridview->count(), 5);
2230 void tst_QSGGridView::QTBUG_8456()
2232 QSGView *canvas = createView();
2234 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/setindex.qml"));
2235 qApp->processEvents();
2237 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2238 QTRY_VERIFY(gridview != 0);
2240 QTRY_COMPARE(gridview->currentIndex(), 0);
2245 void tst_QSGGridView::manualHighlight()
2247 QSGView *canvas = createView();
2249 QString filename(SRCDIR "/data/manual-highlight.qml");
2250 canvas->setSource(QUrl::fromLocalFile(filename));
2252 qApp->processEvents();
2254 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2255 QTRY_VERIFY(gridview != 0);
2257 QSGItem *contentItem = gridview->contentItem();
2258 QTRY_VERIFY(contentItem != 0);
2260 QTRY_COMPARE(gridview->currentIndex(), 0);
2261 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
2262 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2263 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2265 gridview->setCurrentIndex(2);
2267 QTRY_COMPARE(gridview->currentIndex(), 2);
2268 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
2269 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2270 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2272 gridview->positionViewAtIndex(8, QSGGridView::Contain);
2274 QTRY_COMPARE(gridview->currentIndex(), 2);
2275 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
2276 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2277 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2279 gridview->setFlow(QSGGridView::TopToBottom);
2280 QTRY_COMPARE(gridview->flow(), QSGGridView::TopToBottom);
2282 gridview->setCurrentIndex(0);
2283 QTRY_COMPARE(gridview->currentIndex(), 0);
2284 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
2285 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
2286 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
2292 void tst_QSGGridView::footer()
2294 QFETCH(QSGGridView::Flow, flow);
2295 QFETCH(Qt::LayoutDirection, layoutDirection);
2296 QFETCH(QPointF, initialFooterPos);
2297 QFETCH(QPointF, changedFooterPos);
2298 QFETCH(QPointF, initialContentPos);
2299 QFETCH(QPointF, changedContentPos);
2300 QFETCH(QPointF, firstDelegatePos);
2301 QFETCH(QPointF, resizeContentPos);
2303 QSGView *canvas = createView();
2307 for (int i = 0; i < 7; i++)
2308 model.addItem("Item" + QString::number(i), "");
2310 QDeclarativeContext *ctxt = canvas->rootContext();
2311 ctxt->setContextProperty("testModel", &model);
2313 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml"));
2314 qApp->processEvents();
2316 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2317 QTRY_VERIFY(gridview != 0);
2318 gridview->setFlow(flow);
2319 gridview->setLayoutDirection(layoutDirection);
2321 QSGItem *contentItem = gridview->contentItem();
2322 QTRY_VERIFY(contentItem != 0);
2324 QSGText *footer = findItem<QSGText>(contentItem, "footer");
2327 QVERIFY(footer == gridview->footerItem());
2329 QCOMPARE(footer->pos(), initialFooterPos);
2330 QCOMPARE(footer->width(), 100.);
2331 QCOMPARE(footer->height(), 30.);
2332 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2334 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2336 QCOMPARE(item->pos(), firstDelegatePos);
2338 if (flow == QSGGridView::LeftToRight) {
2339 // shrink by one row
2340 model.removeItem(2);
2341 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
2343 // shrink by one column
2344 model.removeItem(2);
2345 model.removeItem(3);
2346 if (layoutDirection == Qt::LeftToRight)
2347 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
2349 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
2355 QPointF posWhenNoItems(0, 0);
2356 if (layoutDirection == Qt::RightToLeft)
2357 posWhenNoItems.setX(flow == QSGGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
2358 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2360 // if header is present, it's at a negative pos, so the footer should not move
2361 canvas->rootObject()->setProperty("showHeader", true);
2362 QVERIFY(findItem<QSGItem>(contentItem, "header") != 0);
2363 QTRY_COMPARE(footer->pos(), posWhenNoItems);
2364 canvas->rootObject()->setProperty("showHeader", false);
2367 for (int i = 0; i < 30; i++)
2368 model.addItem("Item" + QString::number(i), "");
2370 QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
2371 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2373 QCOMPARE(footerItemSpy.count(), 1);
2375 footer = findItem<QSGText>(contentItem, "footer");
2377 footer = findItem<QSGText>(contentItem, "footer2");
2380 QVERIFY(footer == gridview->footerItem());
2382 QCOMPARE(footer->pos(), changedFooterPos);
2383 QCOMPARE(footer->width(), 50.);
2384 QCOMPARE(footer->height(), 20.);
2385 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2387 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2389 QCOMPARE(item->pos(), firstDelegatePos);
2391 gridview->positionViewAtEnd();
2392 footer->setHeight(10);
2393 footer->setWidth(40);
2394 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2399 void tst_QSGGridView::footer_data()
2401 QTest::addColumn<QSGGridView::Flow>("flow");
2402 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2403 QTest::addColumn<QPointF>("initialFooterPos");
2404 QTest::addColumn<QPointF>("changedFooterPos");
2405 QTest::addColumn<QPointF>("initialContentPos");
2406 QTest::addColumn<QPointF>("changedContentPos");
2407 QTest::addColumn<QPointF>("firstDelegatePos");
2408 QTest::addColumn<QPointF>("resizeContentPos");
2410 // footer1 = 100 x 30
2411 // footer2 = 50 x 20
2414 // view height = 320
2416 // footer below items, bottom left
2417 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2418 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
2419 << QPointF(0, 10 * 60) // 30 items = 10 rows
2423 << QPointF(0, 10 * 60 - 320 + 10);
2425 // footer below items, bottom right
2426 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2427 << QPointF(240 - 100, 3 * 60)
2428 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
2431 << QPointF(240 - 80, 0)
2432 << QPointF(0, 10 * 60 - 320 + 10);
2434 // footer to right of items
2435 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2436 << QPointF(2 * 80, 0) // 2 columns, cell width 80
2437 << QPointF(6 * 80, 0) // 30 items = 6 columns
2441 << QPointF(6 * 80 - 240 + 40, 0);
2443 // footer to left of items
2444 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2445 << QPointF(-(2 * 80) - 100, 0)
2446 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
2448 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
2450 << QPointF(-(6 * 80) - 40, 0);
2453 void tst_QSGGridView::header()
2455 QFETCH(QSGGridView::Flow, flow);
2456 QFETCH(Qt::LayoutDirection, layoutDirection);
2457 QFETCH(QPointF, initialHeaderPos);
2458 QFETCH(QPointF, changedHeaderPos);
2459 QFETCH(QPointF, initialContentPos);
2460 QFETCH(QPointF, changedContentPos);
2461 QFETCH(QPointF, firstDelegatePos);
2462 QFETCH(QPointF, resizeContentPos);
2465 for (int i = 0; i < 30; i++)
2466 model.addItem("Item" + QString::number(i), "");
2468 QSGView *canvas = createView();
2469 canvas->rootContext()->setContextProperty("testModel", &model);
2470 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2471 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2472 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
2474 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2475 QTRY_VERIFY(gridview != 0);
2476 gridview->setFlow(flow);
2477 gridview->setLayoutDirection(layoutDirection);
2479 QSGItem *contentItem = gridview->contentItem();
2480 QTRY_VERIFY(contentItem != 0);
2482 QSGText *header = findItem<QSGText>(contentItem, "header");
2485 QVERIFY(header == gridview->headerItem());
2487 QCOMPARE(header->pos(), initialHeaderPos);
2488 QCOMPARE(header->width(), 100.);
2489 QCOMPARE(header->height(), 30.);
2490 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2492 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2494 QCOMPARE(item->pos(), firstDelegatePos);
2497 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
2499 for (int i = 0; i < 30; i++)
2500 model.addItem("Item" + QString::number(i), "");
2502 QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
2503 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
2505 QCOMPARE(headerItemSpy.count(), 1);
2507 header = findItem<QSGText>(contentItem, "header");
2509 header = findItem<QSGText>(contentItem, "header2");
2512 QVERIFY(header == gridview->headerItem());
2514 QCOMPARE(header->pos(), changedHeaderPos);
2515 QCOMPARE(header->width(), 50.);
2516 QCOMPARE(header->height(), 20.);
2517 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2519 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2521 QCOMPARE(item->pos(), firstDelegatePos);
2523 header->setHeight(10);
2524 header->setWidth(40);
2525 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos);
2530 // QTBUG-21207 header should become visible if view resizes from initial empty size
2532 canvas = createView();
2533 canvas->rootContext()->setContextProperty("testModel", &model);
2534 canvas->rootContext()->setContextProperty("initialViewWidth", 240);
2535 canvas->rootContext()->setContextProperty("initialViewHeight", 320);
2536 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
2538 gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2539 QTRY_VERIFY(gridview != 0);
2540 gridview->setFlow(flow);
2541 gridview->setLayoutDirection(layoutDirection);
2543 gridview->setWidth(240);
2544 gridview->setHeight(320);
2545 QTRY_COMPARE(gridview->headerItem()->pos(), initialHeaderPos);
2546 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2551 void tst_QSGGridView::header_data()
2553 QTest::addColumn<QSGGridView::Flow>("flow");
2554 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2555 QTest::addColumn<QPointF>("initialHeaderPos");
2556 QTest::addColumn<QPointF>("changedHeaderPos");
2557 QTest::addColumn<QPointF>("initialContentPos");
2558 QTest::addColumn<QPointF>("changedContentPos");
2559 QTest::addColumn<QPointF>("firstDelegatePos");
2560 QTest::addColumn<QPointF>("resizeContentPos");
2562 // header1 = 100 x 30
2563 // header2 = 50 x 20
2567 // header above items, top left
2568 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2576 // header above items, top right
2577 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2578 << QPointF(240 - 100, -30)
2579 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
2585 // header to left of items
2586 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2594 // header to right of items
2595 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2598 << QPointF(-(240 - 100), 0)
2599 << QPointF(-(240 - 50), 0)
2601 << QPointF(-(240 - 40), 0);
2604 void tst_QSGGridView::indexAt()
2606 QSGView *canvas = createView();
2609 model.addItem("Fred", "12345");
2610 model.addItem("John", "2345");
2611 model.addItem("Bob", "54321");
2612 model.addItem("Billy", "22345");
2613 model.addItem("Sam", "2945");
2614 model.addItem("Ben", "04321");
2615 model.addItem("Jim", "0780");
2617 QDeclarativeContext *ctxt = canvas->rootContext();
2618 ctxt->setContextProperty("testModel", &model);
2619 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2620 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2622 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
2623 qApp->processEvents();
2625 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2626 QTRY_VERIFY(gridview != 0);
2628 QSGItem *contentItem = gridview->contentItem();
2629 QTRY_VERIFY(contentItem != 0);
2631 QTRY_COMPARE(gridview->count(), model.count());
2633 QCOMPARE(gridview->indexAt(0, 0), 0);
2634 QCOMPARE(gridview->indexAt(79, 59), 0);
2635 QCOMPARE(gridview->indexAt(80, 0), 1);
2636 QCOMPARE(gridview->indexAt(0, 60), 3);
2637 QCOMPARE(gridview->indexAt(240, 0), -1);
2642 void tst_QSGGridView::onAdd()
2644 QFETCH(int, initialItemCount);
2645 QFETCH(int, itemsToAdd);
2647 const int delegateWidth = 50;
2648 const int delegateHeight = 100;
2650 QSGView *canvas = createView();
2651 canvas->setGeometry(0,0,5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
2653 // these initial items should not trigger GridView.onAdd
2654 for (int i=0; i<initialItemCount; i++)
2655 model.addItem("dummy value", "dummy value");
2657 QDeclarativeContext *ctxt = canvas->rootContext();
2658 ctxt->setContextProperty("testModel", &model);
2659 ctxt->setContextProperty("delegateWidth", delegateWidth);
2660 ctxt->setContextProperty("delegateHeight", delegateHeight);
2661 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2663 QObject *object = canvas->rootObject();
2664 object->setProperty("width", canvas->width());
2665 object->setProperty("height", canvas->height());
2666 qApp->processEvents();
2668 QList<QPair<QString, QString> > items;
2669 for (int i=0; i<itemsToAdd; i++)
2670 items << qMakePair(QString("value %1").arg(i), QString::number(i));
2671 model.addItems(items);
2673 QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
2674 qApp->processEvents();
2676 QVariantList result = object->property("addedDelegates").toList();
2677 QTRY_COMPARE(result.count(), items.count());
2678 for (int i=0; i<items.count(); i++)
2679 QCOMPARE(result[i].toString(), items[i].first);
2684 void tst_QSGGridView::onAdd_data()
2686 QTest::addColumn<int>("initialItemCount");
2687 QTest::addColumn<int>("itemsToAdd");
2689 QTest::newRow("0, add 1") << 0 << 1;
2690 QTest::newRow("0, add 2") << 0 << 2;
2691 QTest::newRow("0, add 10") << 0 << 10;
2693 QTest::newRow("1, add 1") << 1 << 1;
2694 QTest::newRow("1, add 2") << 1 << 2;
2695 QTest::newRow("1, add 10") << 1 << 10;
2697 QTest::newRow("5, add 1") << 5 << 1;
2698 QTest::newRow("5, add 2") << 5 << 2;
2699 QTest::newRow("5, add 10") << 5 << 10;
2702 void tst_QSGGridView::onRemove()
2704 QFETCH(int, initialItemCount);
2705 QFETCH(int, indexToRemove);
2706 QFETCH(int, removeCount);
2708 const int delegateWidth = 50;
2709 const int delegateHeight = 100;
2711 for (int i=0; i<initialItemCount; i++)
2712 model.addItem(QString("value %1").arg(i), "dummy value");
2714 QSGView *canvas = createView();
2715 QDeclarativeContext *ctxt = canvas->rootContext();
2716 ctxt->setContextProperty("testModel", &model);
2717 ctxt->setContextProperty("delegateWidth", delegateWidth);
2718 ctxt->setContextProperty("delegateHeight", delegateHeight);
2719 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2720 QObject *object = canvas->rootObject();
2722 model.removeItems(indexToRemove, removeCount);
2723 QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
2724 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2729 void tst_QSGGridView::onRemove_data()
2731 QTest::addColumn<int>("initialItemCount");
2732 QTest::addColumn<int>("indexToRemove");
2733 QTest::addColumn<int>("removeCount");
2735 QTest::newRow("remove first") << 1 << 0 << 1;
2736 QTest::newRow("two items, remove first") << 2 << 0 << 1;
2737 QTest::newRow("two items, remove last") << 2 << 1 << 1;
2738 QTest::newRow("two items, remove all") << 2 << 0 << 2;
2740 QTest::newRow("four items, remove first") << 4 << 0 << 1;
2741 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2742 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2743 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2744 QTest::newRow("four items, remove last") << 4 << 3 << 1;
2745 QTest::newRow("four items, remove all") << 4 << 0 << 4;
2747 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2748 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2749 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2752 void tst_QSGGridView::testQtQuick11Attributes()
2754 QFETCH(QString, code);
2755 QFETCH(QString, warning);
2756 QFETCH(QString, error);
2758 QDeclarativeEngine engine;
2761 QDeclarativeComponent valid(&engine);
2762 valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
2763 obj = valid.create();
2765 QVERIFY(valid.errorString().isEmpty());
2768 QDeclarativeComponent invalid(&engine);
2769 invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
2770 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2771 obj = invalid.create();
2772 QCOMPARE(invalid.errorString(), error);
2776 void tst_QSGGridView::testQtQuick11Attributes_data()
2778 QTest::addColumn<QString>("code");
2779 QTest::addColumn<QString>("warning");
2780 QTest::addColumn<QString>("error");
2782 QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2783 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2786 QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2787 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2791 void tst_QSGGridView::columnCount()
2794 canvas.setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview4.qml"));
2796 canvas.requestActivateWindow();
2797 QTest::qWaitForWindowShown(&canvas);
2799 QSGGridView *view = qobject_cast<QSGGridView*>(canvas.rootObject());
2801 QCOMPARE(view->cellWidth(), qreal(400)/qreal(9));
2802 QCOMPARE(view->cellHeight(), qreal(100));
2804 QList<QSGItem*> items = findItems<QSGItem>(view, "delegate");
2805 QCOMPARE(items.size(), 18);
2806 QCOMPARE(items.at(8)->y(), qreal(0));
2807 QCOMPARE(items.at(9)->y(), qreal(100));
2810 void tst_QSGGridView::margins()
2813 QSGView *canvas = createView();
2817 for (int i = 0; i < 40; i++)
2818 model.addItem("Item" + QString::number(i), "");
2820 QDeclarativeContext *ctxt = canvas->rootContext();
2821 ctxt->setContextProperty("testModel", &model);
2822 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2824 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
2825 qApp->processEvents();
2827 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2828 QTRY_VERIFY(gridview != 0);
2830 QSGItem *contentItem = gridview->contentItem();
2831 QTRY_VERIFY(contentItem != 0);
2833 QCOMPARE(gridview->contentX(), -30.);
2834 QCOMPARE(gridview->xOrigin(), 0.);
2837 gridview->positionViewAtEnd();
2838 qreal pos = gridview->contentX();
2839 gridview->setContentX(pos + 80);
2840 gridview->returnToBounds();
2841 QTRY_COMPARE(gridview->contentX(), pos + 50);
2843 // remove item before visible and check that left margin is maintained
2844 // and xOrigin is updated
2845 gridview->setContentX(200);
2846 model.removeItems(0, 4);
2848 gridview->setContentX(-50);
2849 gridview->returnToBounds();
2850 QCOMPARE(gridview->xOrigin(), 100.);
2851 QTRY_COMPARE(gridview->contentX(), 70.);
2853 // reduce left margin
2854 gridview->setLeftMargin(20);
2855 QCOMPARE(gridview->xOrigin(), 100.);
2856 QTRY_COMPARE(gridview->contentX(), 80.);
2859 gridview->positionViewAtEnd();
2860 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
2861 pos = gridview->contentX();
2862 gridview->setContentX(pos + 80);
2863 gridview->returnToBounds();
2864 QTRY_COMPARE(gridview->contentX(), pos + 50);
2866 // reduce right margin
2867 pos = gridview->contentX();
2868 gridview->setRightMargin(40);
2869 QCOMPARE(gridview->xOrigin(), 0.);
2870 QTRY_COMPARE(gridview->contentX(), pos-10);
2876 QSGView *canvas = createView();
2880 for (int i = 0; i < 40; i++)
2881 model.addItem("Item" + QString::number(i), "");
2883 QDeclarativeContext *ctxt = canvas->rootContext();
2884 ctxt->setContextProperty("testModel", &model);
2885 ctxt->setContextProperty("testRightToLeft", QVariant(true));
2887 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
2888 qApp->processEvents();
2890 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2891 QTRY_VERIFY(gridview != 0);
2893 QSGItem *contentItem = gridview->contentItem();
2894 QTRY_VERIFY(contentItem != 0);
2896 QCOMPARE(gridview->contentX(), -240+30.);
2897 QCOMPARE(gridview->xOrigin(), 0.);
2900 gridview->positionViewAtEnd();
2901 qreal pos = gridview->contentX();
2902 gridview->setContentX(pos - 80);
2903 gridview->returnToBounds();
2904 QTRY_COMPARE(gridview->contentX(), pos - 50);
2906 // remove item before visible and check that left margin is maintained
2907 // and xOrigin is updated
2908 gridview->setContentX(-400);
2909 model.removeItems(0, 4);
2911 gridview->setContentX(-240+50);
2912 gridview->returnToBounds();
2913 QCOMPARE(gridview->xOrigin(), -100.);
2914 QTRY_COMPARE(gridview->contentX(), -240-70.);
2916 // reduce left margin (i.e. right side due to RTL)
2917 pos = gridview->contentX();
2918 gridview->setLeftMargin(20);
2919 QCOMPARE(gridview->xOrigin(), -100.);
2920 QTRY_COMPARE(gridview->contentX(), -240-80.);
2923 gridview->positionViewAtEnd();
2924 QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
2925 pos = gridview->contentX();
2926 gridview->setContentX(pos - 80);
2927 gridview->returnToBounds();
2928 QTRY_COMPARE(gridview->contentX(), pos - 50);
2930 // reduce right margin (i.e. left side due to RTL)
2931 pos = gridview->contentX();
2932 gridview->setRightMargin(40);
2933 QCOMPARE(gridview->xOrigin(), 0.);
2934 QTRY_COMPARE(gridview->contentX(), pos+10);
2940 QSGView *tst_QSGGridView::createView()
2942 QSGView *canvas = new QSGView(0);
2943 canvas->setGeometry(0,0,240,320);
2949 Find an item with the specified objectName. If index is supplied then the
2950 item must also evaluate the {index} expression equal to index
2952 template<typename T>
2953 T *tst_QSGGridView::findItem(QSGItem *parent, const QString &objectName, int index)
2955 const QMetaObject &mo = T::staticMetaObject;
2956 //qDebug() << parent->childItems().count() << "children";
2957 for (int i = 0; i < parent->childItems().count(); ++i) {
2958 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2961 //qDebug() << "try" << item;
2962 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2964 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
2966 if (context->contextProperty("index").toInt() == index) {
2967 return static_cast<T*>(item);
2971 return static_cast<T*>(item);
2974 item = findItem<T>(item, objectName, index);
2976 return static_cast<T*>(item);
2982 template<typename T>
2983 QList<T*> tst_QSGGridView::findItems(QSGItem *parent, const QString &objectName)
2986 const QMetaObject &mo = T::staticMetaObject;
2987 //qDebug() << parent->childItems().count() << "children";
2988 for (int i = 0; i < parent->childItems().count(); ++i) {
2989 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2992 //qDebug() << "try" << item;
2993 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2994 items.append(static_cast<T*>(item));
2995 //qDebug() << " found:" << item;
2997 items += findItems<T>(item, objectName);
3003 void tst_QSGGridView::dumpTree(QSGItem *parent, int depth)
3005 static QString padding(" ");
3006 for (int i = 0; i < parent->childItems().count(); ++i) {
3007 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
3010 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
3011 qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
3012 dumpTree(item, depth+1);
3017 QTEST_MAIN(tst_QSGGridView)
3019 #include "tst_qsggridview.moc"