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 <QtGui/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();
82 void noCurrentIndex();
85 void propertyChanges();
86 void componentChanges();
88 void positionViewAtIndex();
89 void positionViewAtIndex_rightToLeft();
94 void enforceRange_rightToLeft();
96 void manualHighlight();
105 void onRemove_data();
106 void testQtQuick11Attributes();
107 void testQtQuick11Attributes_data();
110 QSGView *createView();
112 T *findItem(QSGItem *parent, const QString &id, int index=-1);
114 QList<T*> findItems(QSGItem *parent, const QString &objectName);
115 void dumpTree(QSGItem *parent, int depth = 0);
117 void tst_QSGGridView::initTestCase()
120 if (!QGLShaderProgram::hasOpenGLShaderPrograms(canvas.context()))
121 QSKIP("QSGGridView needs OpenGL 2.0", SkipAll);
124 void tst_QSGGridView::cleanupTestCase()
128 class TestModel : public QAbstractListModel
131 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
133 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
134 QHash<int, QByteArray> roles;
135 roles[Name] = "name";
136 roles[Number] = "number";
140 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
141 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
144 rv = list.at(index.row()).first;
145 else if (role == Number)
146 rv = list.at(index.row()).second;
151 int count() const { return rowCount(); }
152 QString name(int index) const { return list.at(index).first; }
153 QString number(int index) const { return list.at(index).second; }
155 void addItem(const QString &name, const QString &number) {
156 emit beginInsertRows(QModelIndex(), list.count(), list.count());
157 list.append(QPair<QString,QString>(name, number));
158 emit endInsertRows();
161 void addItems(const QList<QPair<QString, QString> > &items) {
162 emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
163 for (int i=0; i<items.count(); i++)
164 list.append(QPair<QString,QString>(items[i].first, items[i].second));
165 emit endInsertRows();
168 void insertItem(int index, const QString &name, const QString &number) {
169 emit beginInsertRows(QModelIndex(), index, index);
170 list.insert(index, QPair<QString,QString>(name, number));
171 emit endInsertRows();
174 void removeItem(int index) {
175 emit beginRemoveRows(QModelIndex(), index, index);
176 list.removeAt(index);
177 emit endRemoveRows();
180 void removeItems(int index, int count) {
181 emit beginRemoveRows(QModelIndex(), index, index+count-1);
183 list.removeAt(index);
184 emit endRemoveRows();
187 void moveItem(int from, int to) {
188 emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
193 void modifyItem(int idx, const QString &name, const QString &number) {
194 list[idx] = QPair<QString,QString>(name, number);
195 emit dataChanged(index(idx,0), index(idx,0));
199 int count = list.count();
200 emit beginRemoveRows(QModelIndex(), 0, count-1);
202 emit endRemoveRows();
207 QList<QPair<QString,QString> > list;
210 tst_QSGGridView::tst_QSGGridView()
214 void tst_QSGGridView::items()
216 QSGView *canvas = createView();
219 model.addItem("Fred", "12345");
220 model.addItem("John", "2345");
221 model.addItem("Bob", "54321");
222 model.addItem("Billy", "22345");
223 model.addItem("Sam", "2945");
224 model.addItem("Ben", "04321");
225 model.addItem("Jim", "0780");
227 QDeclarativeContext *ctxt = canvas->rootContext();
228 ctxt->setContextProperty("testModel", &model);
229 ctxt->setContextProperty("testRightToLeft", QVariant(false));
230 ctxt->setContextProperty("testTopToBottom", QVariant(false));
232 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
233 qApp->processEvents();
235 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
236 QTRY_VERIFY(gridview != 0);
238 QSGItem *contentItem = gridview->contentItem();
239 QTRY_VERIFY(contentItem != 0);
241 QTRY_COMPARE(gridview->count(), model.count());
242 QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
243 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
245 for (int i = 0; i < model.count(); ++i) {
246 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
247 QTRY_VERIFY(name != 0);
248 QTRY_COMPARE(name->text(), model.name(i));
249 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
250 QTRY_VERIFY(number != 0);
251 QTRY_COMPARE(number->text(), model.number(i));
254 // set an empty model and confirm that items are destroyed
256 ctxt->setContextProperty("testModel", &model2);
258 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
259 QTRY_VERIFY(itemCount == 0);
264 void tst_QSGGridView::changed()
266 QSGView *canvas = createView();
269 model.addItem("Fred", "12345");
270 model.addItem("John", "2345");
271 model.addItem("Bob", "54321");
272 model.addItem("Billy", "22345");
273 model.addItem("Sam", "2945");
274 model.addItem("Ben", "04321");
275 model.addItem("Jim", "0780");
277 QDeclarativeContext *ctxt = canvas->rootContext();
278 ctxt->setContextProperty("testModel", &model);
279 ctxt->setContextProperty("testRightToLeft", QVariant(false));
280 ctxt->setContextProperty("testTopToBottom", QVariant(false));
282 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
283 qApp->processEvents();
285 QSGFlickable *gridview = findItem<QSGFlickable>(canvas->rootObject(), "grid");
286 QTRY_VERIFY(gridview != 0);
288 QSGItem *contentItem = gridview->contentItem();
289 QTRY_VERIFY(contentItem != 0);
291 model.modifyItem(1, "Will", "9876");
292 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
293 QTRY_VERIFY(name != 0);
294 QTRY_COMPARE(name->text(), model.name(1));
295 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
296 QTRY_VERIFY(number != 0);
297 QTRY_COMPARE(number->text(), model.number(1));
302 void tst_QSGGridView::inserted()
304 QSGView *canvas = createView();
308 model.addItem("Fred", "12345");
309 model.addItem("John", "2345");
310 model.addItem("Bob", "54321");
312 QDeclarativeContext *ctxt = canvas->rootContext();
313 ctxt->setContextProperty("testModel", &model);
314 ctxt->setContextProperty("testRightToLeft", QVariant(false));
315 ctxt->setContextProperty("testTopToBottom", QVariant(false));
317 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
318 qApp->processEvents();
320 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
321 QTRY_VERIFY(gridview != 0);
323 QSGItem *contentItem = gridview->contentItem();
324 QTRY_VERIFY(contentItem != 0);
326 model.insertItem(1, "Will", "9876");
327 QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
329 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
331 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
332 QTRY_VERIFY(name != 0);
333 QTRY_COMPARE(name->text(), model.name(1));
334 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
335 QTRY_VERIFY(number != 0);
336 QTRY_COMPARE(number->text(), model.number(1));
338 // Checks that onAdd is called
339 int added = canvas->rootObject()->property("added").toInt();
340 QTRY_COMPARE(added, 1);
342 // Confirm items positioned correctly
343 for (int i = 0; i < model.count(); ++i) {
344 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
345 QTRY_COMPARE(item->x(), (i%3)*80.0);
346 QTRY_COMPARE(item->y(), (i/3)*60.0);
349 model.insertItem(0, "Foo", "1111"); // zero index, and current item
351 QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
353 name = findItem<QSGText>(contentItem, "textName", 0);
354 QTRY_VERIFY(name != 0);
355 QTRY_COMPARE(name->text(), model.name(0));
356 number = findItem<QSGText>(contentItem, "textNumber", 0);
357 QTRY_VERIFY(number != 0);
358 QTRY_COMPARE(number->text(), model.number(0));
360 QTRY_COMPARE(gridview->currentIndex(), 1);
362 // Confirm items positioned correctly
363 for (int i = 0; i < model.count(); ++i) {
364 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
365 QTRY_VERIFY(item->x() == (i%3)*80);
366 QTRY_VERIFY(item->y() == (i/3)*60);
369 for (int i = model.count(); i < 30; ++i)
370 model.insertItem(i, "Hello", QString::number(i));
372 gridview->setContentY(120);
374 // Insert item outside visible area
375 model.insertItem(1, "Hello", "1324");
377 QTRY_VERIFY(gridview->contentY() == 120);
382 void tst_QSGGridView::removed()
384 QSGView *canvas = createView();
388 for (int i = 0; i < 40; i++)
389 model.addItem("Item" + QString::number(i), "");
391 QDeclarativeContext *ctxt = canvas->rootContext();
392 ctxt->setContextProperty("testModel", &model);
393 ctxt->setContextProperty("testRightToLeft", QVariant(false));
394 ctxt->setContextProperty("testTopToBottom", QVariant(false));
396 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
397 qApp->processEvents();
399 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
400 QTRY_VERIFY(gridview != 0);
402 QSGItem *contentItem = gridview->contentItem();
403 QTRY_VERIFY(contentItem != 0);
406 QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
408 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
409 QTRY_VERIFY(name != 0);
410 QTRY_COMPARE(name->text(), model.name(1));
411 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
412 QTRY_VERIFY(number != 0);
413 QTRY_COMPARE(number->text(), model.number(1));
415 // Checks that onRemove is called
416 QString removed = canvas->rootObject()->property("removed").toString();
417 QTRY_COMPARE(removed, QString("Item1"));
419 // Confirm items positioned correctly
420 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
421 for (int i = 0; i < model.count() && i < itemCount; ++i) {
422 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
423 if (!item) qWarning() << "Item" << i << "not found";
425 QTRY_VERIFY(item->x() == (i%3)*80);
426 QTRY_VERIFY(item->y() == (i/3)*60);
429 // Remove first item (which is the current item);
432 name = findItem<QSGText>(contentItem, "textName", 0);
433 QTRY_VERIFY(name != 0);
434 QTRY_COMPARE(name->text(), model.name(0));
435 number = findItem<QSGText>(contentItem, "textNumber", 0);
436 QTRY_VERIFY(number != 0);
437 QTRY_COMPARE(number->text(), model.number(0));
439 // Confirm items positioned correctly
440 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
441 for (int i = 0; i < model.count() && i < itemCount; ++i) {
442 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
443 if (!item) qWarning() << "Item" << i << "not found";
445 QTRY_VERIFY(item->x() == (i%3)*80);
446 QTRY_VERIFY(item->y() == (i/3)*60);
449 // Remove items not visible
450 model.removeItem(25);
452 // Confirm items positioned correctly
453 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
454 for (int i = 0; i < model.count() && i < itemCount; ++i) {
455 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
456 if (!item) qWarning() << "Item" << i << "not found";
458 QTRY_VERIFY(item->x() == (i%3)*80);
459 QTRY_VERIFY(item->y() == (i/3)*60);
462 // Remove items before visible
463 gridview->setContentY(120);
464 gridview->setCurrentIndex(10);
466 // Setting currentIndex above shouldn't cause view to scroll
467 QTRY_COMPARE(gridview->contentY(), 120.0);
471 // Confirm items positioned correctly
472 for (int i = 6; i < 18; ++i) {
473 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
474 if (!item) qWarning() << "Item" << i << "not found";
476 QTRY_VERIFY(item->x() == (i%3)*80);
477 QTRY_VERIFY(item->y() == (i/3)*60);
480 // Remove currentIndex
481 QSGItem *oldCurrent = gridview->currentItem();
484 QTRY_COMPARE(gridview->currentIndex(), 9);
485 QTRY_VERIFY(gridview->currentItem() != oldCurrent);
487 gridview->setContentY(0);
488 // let transitions settle.
491 // Confirm items positioned correctly
492 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
493 for (int i = 0; i < model.count() && i < itemCount; ++i) {
494 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
495 if (!item) qWarning() << "Item" << i << "not found";
497 QTRY_VERIFY(item->x() == (i%3)*80);
498 QTRY_VERIFY(item->y() == (i/3)*60);
501 // remove item outside current view.
502 gridview->setCurrentIndex(32);
503 gridview->setContentY(240);
505 model.removeItem(30);
506 QTRY_VERIFY(gridview->currentIndex() == 31);
508 // remove current item beyond visible items.
509 gridview->setCurrentIndex(20);
510 gridview->setContentY(0);
511 model.removeItem(20);
513 QTRY_COMPARE(gridview->currentIndex(), 20);
514 QTRY_VERIFY(gridview->currentItem() != 0);
516 // remove item before current, but visible
517 gridview->setCurrentIndex(8);
518 gridview->setContentY(240);
519 oldCurrent = gridview->currentItem();
522 QTRY_COMPARE(gridview->currentIndex(), 7);
523 QTRY_VERIFY(gridview->currentItem() == oldCurrent);
528 void tst_QSGGridView::clear()
530 QSGView *canvas = createView();
533 for (int i = 0; i < 30; i++)
534 model.addItem("Item" + QString::number(i), "");
536 QDeclarativeContext *ctxt = canvas->rootContext();
537 ctxt->setContextProperty("testModel", &model);
538 ctxt->setContextProperty("testRightToLeft", QVariant(false));
539 ctxt->setContextProperty("testTopToBottom", QVariant(false));
541 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
542 qApp->processEvents();
544 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
545 QVERIFY(gridview != 0);
547 QSGItem *contentItem = gridview->contentItem();
548 QVERIFY(contentItem != 0);
552 QVERIFY(gridview->count() == 0);
553 QVERIFY(gridview->currentItem() == 0);
554 QVERIFY(gridview->contentY() == 0);
555 QVERIFY(gridview->currentIndex() == -1);
557 // confirm sanity when adding an item to cleared list
558 model.addItem("New", "1");
559 QVERIFY(gridview->count() == 1);
560 QVERIFY(gridview->currentItem() != 0);
561 QVERIFY(gridview->currentIndex() == 0);
566 void tst_QSGGridView::moved()
568 QSGView *canvas = createView();
571 for (int i = 0; i < 30; i++)
572 model.addItem("Item" + QString::number(i), "");
574 QDeclarativeContext *ctxt = canvas->rootContext();
575 ctxt->setContextProperty("testModel", &model);
576 ctxt->setContextProperty("testRightToLeft", QVariant(false));
577 ctxt->setContextProperty("testTopToBottom", QVariant(false));
579 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
580 qApp->processEvents();
582 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
583 QTRY_VERIFY(gridview != 0);
585 QSGItem *contentItem = gridview->contentItem();
586 QTRY_VERIFY(contentItem != 0);
588 model.moveItem(1, 8);
590 QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
591 QTRY_VERIFY(name != 0);
592 QTRY_COMPARE(name->text(), model.name(1));
593 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1);
594 QTRY_VERIFY(number != 0);
595 QTRY_COMPARE(number->text(), model.number(1));
597 name = findItem<QSGText>(contentItem, "textName", 8);
598 QTRY_VERIFY(name != 0);
599 QTRY_COMPARE(name->text(), model.name(8));
600 number = findItem<QSGText>(contentItem, "textNumber", 8);
601 QTRY_VERIFY(number != 0);
602 QTRY_COMPARE(number->text(), model.number(8));
604 // Confirm items positioned correctly
605 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
606 for (int i = 0; i < model.count() && i < itemCount; ++i) {
607 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
608 if (!item) qWarning() << "Item" << i << "not found";
610 QTRY_VERIFY(item->x() == (i%3)*80);
611 QTRY_VERIFY(item->y() == (i/3)*60);
614 gridview->setContentY(120);
616 // move outside visible area
617 model.moveItem(1, 25);
619 // Confirm items positioned correctly and indexes correct
620 itemCount = findItems<QSGItem>(contentItem, "wrapper").count()-1;
621 for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) {
622 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
623 if (!item) qWarning() << "Item" << i << "not found";
625 QTRY_COMPARE(item->x(), qreal((i%3)*80));
626 QTRY_COMPARE(item->y(), qreal((i/3)*60));
627 name = findItem<QSGText>(contentItem, "textName", i);
628 QTRY_VERIFY(name != 0);
629 QTRY_COMPARE(name->text(), model.name(i));
630 number = findItem<QSGText>(contentItem, "textNumber", i);
631 QTRY_VERIFY(number != 0);
632 QTRY_COMPARE(number->text(), model.number(i));
635 // move from outside visible into visible
636 model.moveItem(28, 8);
638 // Confirm items positioned correctly and indexes correct
639 for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) {
640 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
641 if (!item) qWarning() << "Item" << i << "not found";
643 QTRY_VERIFY(item->x() == (i%3)*80);
644 QTRY_VERIFY(item->y() == (i/3)*60);
645 name = findItem<QSGText>(contentItem, "textName", i);
646 QTRY_VERIFY(name != 0);
647 QTRY_COMPARE(name->text(), model.name(i));
648 number = findItem<QSGText>(contentItem, "textNumber", i);
649 QTRY_VERIFY(number != 0);
650 QTRY_COMPARE(number->text(), model.number(i));
653 // ensure content position is stable
654 gridview->setContentY(0);
655 model.moveItem(10, 0);
656 QTRY_VERIFY(gridview->contentY() == 0);
661 void tst_QSGGridView::currentIndex()
664 for (int i = 0; i < 60; i++)
665 model.addItem("Item" + QString::number(i), QString::number(i));
667 QSGView *canvas = new QSGView(0);
668 canvas->setFixedSize(240,320);
671 QDeclarativeContext *ctxt = canvas->rootContext();
672 ctxt->setContextProperty("testModel", &model);
674 QString filename(SRCDIR "/data/gridview-initCurrent.qml");
675 canvas->setSource(QUrl::fromLocalFile(filename));
677 qApp->processEvents();
679 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
680 QVERIFY(gridview != 0);
682 QSGItem *contentItem = gridview->contentItem();
683 QVERIFY(contentItem != 0);
685 // current item should be third item
686 QCOMPARE(gridview->currentIndex(), 35);
687 QCOMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 35));
688 QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y());
689 QCOMPARE(gridview->contentY(), 400.0);
691 gridview->moveCurrentIndexRight();
692 QCOMPARE(gridview->currentIndex(), 36);
693 gridview->moveCurrentIndexDown();
694 QCOMPARE(gridview->currentIndex(), 39);
695 gridview->moveCurrentIndexUp();
696 QCOMPARE(gridview->currentIndex(), 36);
697 gridview->moveCurrentIndexLeft();
698 QCOMPARE(gridview->currentIndex(), 35);
701 gridview->setCurrentIndex(0);
702 QCOMPARE(gridview->currentIndex(), 0);
703 // confirm that the velocity is updated
704 QTRY_VERIFY(gridview->verticalVelocity() != 0.0);
706 gridview->moveCurrentIndexUp();
707 QCOMPARE(gridview->currentIndex(), 0);
709 gridview->moveCurrentIndexLeft();
710 QCOMPARE(gridview->currentIndex(), 0);
712 gridview->setCurrentIndex(model.count()-1);
713 QCOMPARE(gridview->currentIndex(), model.count()-1);
715 gridview->moveCurrentIndexRight();
716 QCOMPARE(gridview->currentIndex(), model.count()-1);
718 gridview->moveCurrentIndexDown();
719 QCOMPARE(gridview->currentIndex(), model.count()-1);
722 gridview->setWrapEnabled(true);
724 gridview->setCurrentIndex(0);
725 QCOMPARE(gridview->currentIndex(), 0);
727 gridview->moveCurrentIndexLeft();
728 QCOMPARE(gridview->currentIndex(), model.count()-1);
730 qApp->processEvents();
731 QTRY_COMPARE(gridview->contentY(), 880.0);
733 gridview->moveCurrentIndexRight();
734 QCOMPARE(gridview->currentIndex(), 0);
736 QTRY_COMPARE(gridview->contentY(), 0.0);
739 qApp->setActiveWindow(canvas);
741 // to be safe and avoid failing setFocus with window managers
742 qt_x11_wait_for_window_manager(canvas);
744 QTRY_VERIFY(canvas->hasFocus());
745 qApp->processEvents();
747 QTest::keyClick(canvas, Qt::Key_Down);
748 QCOMPARE(gridview->currentIndex(), 3);
750 QTest::keyClick(canvas, Qt::Key_Up);
751 QCOMPARE(gridview->currentIndex(), 0);
753 gridview->setFlow(QSGGridView::TopToBottom);
755 qApp->setActiveWindow(canvas);
757 // to be safe and avoid failing setFocus with window managers
758 qt_x11_wait_for_window_manager(canvas);
760 QTRY_VERIFY(canvas->hasFocus());
761 qApp->processEvents();
763 QTest::keyClick(canvas, Qt::Key_Right);
764 QCOMPARE(gridview->currentIndex(), 5);
766 QTest::keyClick(canvas, Qt::Key_Left);
767 QCOMPARE(gridview->currentIndex(), 0);
769 QTest::keyClick(canvas, Qt::Key_Down);
770 QCOMPARE(gridview->currentIndex(), 1);
772 QTest::keyClick(canvas, Qt::Key_Up);
773 QCOMPARE(gridview->currentIndex(), 0);
776 // turn off auto highlight
777 gridview->setHighlightFollowsCurrentItem(false);
778 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
779 QVERIFY(gridview->highlightItem());
780 qreal hlPosX = gridview->highlightItem()->x();
781 qreal hlPosY = gridview->highlightItem()->y();
783 gridview->setCurrentIndex(5);
784 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
785 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
787 // insert item before currentIndex
788 gridview->setCurrentIndex(28);
789 model.insertItem(0, "Foo", "1111");
790 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
792 // check removing highlight by setting currentIndex to -1;
793 gridview->setCurrentIndex(-1);
795 QCOMPARE(gridview->currentIndex(), -1);
796 QVERIFY(!gridview->highlightItem());
797 QVERIFY(!gridview->currentItem());
799 gridview->setHighlightFollowsCurrentItem(true);
801 gridview->setFlow(QSGGridView::LeftToRight);
802 gridview->setLayoutDirection(Qt::RightToLeft);
804 qApp->setActiveWindow(canvas);
806 // to be safe and avoid failing setFocus with window managers
807 qt_x11_wait_for_window_manager(canvas);
809 QTRY_VERIFY(canvas->hasFocus());
810 qApp->processEvents();
812 gridview->setCurrentIndex(35);
814 QTest::keyClick(canvas, Qt::Key_Right);
815 QCOMPARE(gridview->currentIndex(), 34);
817 QTest::keyClick(canvas, Qt::Key_Down);
818 QCOMPARE(gridview->currentIndex(), 37);
820 QTest::keyClick(canvas, Qt::Key_Up);
821 QCOMPARE(gridview->currentIndex(), 34);
823 QTest::keyClick(canvas, Qt::Key_Left);
824 QCOMPARE(gridview->currentIndex(), 35);
827 // turn off auto highlight
828 gridview->setHighlightFollowsCurrentItem(false);
829 QVERIFY(gridview->highlightFollowsCurrentItem() == false);
830 QVERIFY(gridview->highlightItem());
831 hlPosX = gridview->highlightItem()->x();
832 hlPosY = gridview->highlightItem()->y();
834 gridview->setCurrentIndex(5);
835 QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX);
836 QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY);
838 // insert item before currentIndex
839 gridview->setCurrentIndex(28);
840 model.insertItem(0, "Foo", "1111");
841 QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
843 // check removing highlight by setting currentIndex to -1;
844 gridview->setCurrentIndex(-1);
846 QCOMPARE(gridview->currentIndex(), -1);
847 QVERIFY(!gridview->highlightItem());
848 QVERIFY(!gridview->currentItem());
853 void tst_QSGGridView::noCurrentIndex()
856 for (int i = 0; i < 60; i++)
857 model.addItem("Item" + QString::number(i), QString::number(i));
859 QSGView *canvas = new QSGView(0);
860 canvas->setFixedSize(240,320);
862 QDeclarativeContext *ctxt = canvas->rootContext();
863 ctxt->setContextProperty("testModel", &model);
865 QString filename(SRCDIR "/data/gridview-noCurrent.qml");
866 canvas->setSource(QUrl::fromLocalFile(filename));
868 qApp->processEvents();
870 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
871 QVERIFY(gridview != 0);
873 QSGItem *contentItem = gridview->contentItem();
874 QVERIFY(contentItem != 0);
876 // current index should be -1
877 QCOMPARE(gridview->currentIndex(), -1);
878 QVERIFY(!gridview->currentItem());
879 QVERIFY(!gridview->highlightItem());
880 QCOMPARE(gridview->contentY(), 0.0);
882 gridview->setCurrentIndex(5);
883 QCOMPARE(gridview->currentIndex(), 5);
884 QVERIFY(gridview->currentItem());
885 QVERIFY(gridview->highlightItem());
890 void tst_QSGGridView::changeFlow()
892 QSGView *canvas = createView();
895 for (int i = 0; i < 30; i++)
896 model.addItem("Item" + QString::number(i), QString::number(i));
898 QDeclarativeContext *ctxt = canvas->rootContext();
899 ctxt->setContextProperty("testModel", &model);
900 ctxt->setContextProperty("testRightToLeft", QVariant(false));
901 ctxt->setContextProperty("testTopToBottom", QVariant(false));
903 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
904 qApp->processEvents();
906 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
907 QTRY_VERIFY(gridview != 0);
909 QSGItem *contentItem = gridview->contentItem();
910 QTRY_VERIFY(contentItem != 0);
912 // Confirm items positioned correctly and indexes correct
913 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
914 for (int i = 0; i < model.count() && i < itemCount; ++i) {
915 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
916 if (!item) qWarning() << "Item" << i << "not found";
918 QTRY_COMPARE(item->x(), qreal((i%3)*80));
919 QTRY_COMPARE(item->y(), qreal((i/3)*60));
920 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
921 QTRY_VERIFY(name != 0);
922 QTRY_COMPARE(name->text(), model.name(i));
923 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
924 QTRY_VERIFY(number != 0);
925 QTRY_COMPARE(number->text(), model.number(i));
928 ctxt->setContextProperty("testTopToBottom", QVariant(true));
930 // Confirm items positioned correctly and indexes correct
931 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
932 for (int i = 0; i < model.count() && i < itemCount; ++i) {
933 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
934 if (!item) qWarning() << "Item" << i << "not found";
936 QTRY_COMPARE(item->x(), qreal((i/5)*80));
937 QTRY_COMPARE(item->y(), qreal((i%5)*60));
938 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
939 QTRY_VERIFY(name != 0);
940 QTRY_COMPARE(name->text(), model.name(i));
941 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
942 QTRY_VERIFY(number != 0);
943 QTRY_COMPARE(number->text(), model.number(i));
946 ctxt->setContextProperty("testRightToLeft", QVariant(true));
948 // Confirm items positioned correctly and indexes correct
949 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
950 for (int i = 0; i < model.count() && i < itemCount; ++i) {
951 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
952 if (!item) qWarning() << "Item" << i << "not found";
954 QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width()));
955 QTRY_COMPARE(item->y(), qreal((i%5)*60));
956 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
957 QTRY_VERIFY(name != 0);
958 QTRY_COMPARE(name->text(), model.name(i));
959 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
960 QTRY_VERIFY(number != 0);
961 QTRY_COMPARE(number->text(), model.number(i));
963 gridview->setContentX(100);
964 QTRY_COMPARE(gridview->contentX(), 100.);
965 ctxt->setContextProperty("testTopToBottom", QVariant(false));
966 QTRY_COMPARE(gridview->contentX(), 0.);
968 // Confirm items positioned correctly and indexes correct
969 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
970 for (int i = 0; i < model.count() && i < itemCount; ++i) {
971 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
972 if (!item) qWarning() << "Item" << i << "not found";
974 QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80));
975 QTRY_COMPARE(item->y(), qreal((i/3)*60));
976 QSGText *name = findItem<QSGText>(contentItem, "textName", i);
977 QTRY_VERIFY(name != 0);
978 QTRY_COMPARE(name->text(), model.name(i));
979 QSGText *number = findItem<QSGText>(contentItem, "textNumber", i);
980 QTRY_VERIFY(number != 0);
981 QTRY_COMPARE(number->text(), model.number(i));
987 void tst_QSGGridView::defaultValues()
989 QDeclarativeEngine engine;
990 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview3.qml"));
991 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
993 QTRY_VERIFY(obj != 0);
994 QTRY_VERIFY(obj->model() == QVariant());
995 QTRY_VERIFY(obj->delegate() == 0);
996 QTRY_COMPARE(obj->currentIndex(), -1);
997 QTRY_VERIFY(obj->currentItem() == 0);
998 QTRY_COMPARE(obj->count(), 0);
999 QTRY_VERIFY(obj->highlight() == 0);
1000 QTRY_VERIFY(obj->highlightItem() == 0);
1001 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true);
1002 QTRY_VERIFY(obj->flow() == 0);
1003 QTRY_COMPARE(obj->isWrapEnabled(), false);
1004 QTRY_COMPARE(obj->cacheBuffer(), 0);
1005 QTRY_COMPARE(obj->cellWidth(), 100); //### Should 100 be the default?
1006 QTRY_COMPARE(obj->cellHeight(), 100);
1010 void tst_QSGGridView::properties()
1012 QDeclarativeEngine engine;
1013 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/gridview2.qml"));
1014 QSGGridView *obj = qobject_cast<QSGGridView*>(c.create());
1016 QTRY_VERIFY(obj != 0);
1017 QTRY_VERIFY(obj->model() != QVariant());
1018 QTRY_VERIFY(obj->delegate() != 0);
1019 QTRY_COMPARE(obj->currentIndex(), 0);
1020 QTRY_VERIFY(obj->currentItem() != 0);
1021 QTRY_COMPARE(obj->count(), 4);
1022 QTRY_VERIFY(obj->highlight() != 0);
1023 QTRY_VERIFY(obj->highlightItem() != 0);
1024 QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false);
1025 QTRY_VERIFY(obj->flow() == 0);
1026 QTRY_COMPARE(obj->isWrapEnabled(), true);
1027 QTRY_COMPARE(obj->cacheBuffer(), 200);
1028 QTRY_COMPARE(obj->cellWidth(), 100);
1029 QTRY_COMPARE(obj->cellHeight(), 100);
1033 void tst_QSGGridView::propertyChanges()
1035 QSGView *canvas = createView();
1036 QTRY_VERIFY(canvas);
1037 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1039 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1040 QTRY_VERIFY(gridView);
1042 QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged()));
1043 QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged()));
1044 QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged()));
1045 QSignalSpy flowSpy(gridView, SIGNAL(flowChanged()));
1047 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1048 QTRY_COMPARE(gridView->cacheBuffer(), 10);
1049 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1051 gridView->setWrapEnabled(false);
1052 gridView->setCacheBuffer(3);
1053 gridView->setFlow(QSGGridView::TopToBottom);
1055 QTRY_COMPARE(gridView->isWrapEnabled(), false);
1056 QTRY_COMPARE(gridView->cacheBuffer(), 3);
1057 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1059 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1060 QTRY_COMPARE(cacheBufferSpy.count(),1);
1061 QTRY_COMPARE(flowSpy.count(),1);
1063 gridView->setWrapEnabled(false);
1064 gridView->setCacheBuffer(3);
1065 gridView->setFlow(QSGGridView::TopToBottom);
1067 QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1068 QTRY_COMPARE(cacheBufferSpy.count(),1);
1069 QTRY_COMPARE(flowSpy.count(),1);
1071 gridView->setFlow(QSGGridView::LeftToRight);
1072 QTRY_COMPARE(gridView->flow(), QSGGridView::LeftToRight);
1074 gridView->setWrapEnabled(true);
1075 gridView->setCacheBuffer(5);
1076 gridView->setLayoutDirection(Qt::RightToLeft);
1078 QTRY_COMPARE(gridView->isWrapEnabled(), true);
1079 QTRY_COMPARE(gridView->cacheBuffer(), 5);
1080 QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
1082 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1083 QTRY_COMPARE(cacheBufferSpy.count(),2);
1084 QTRY_COMPARE(layoutSpy.count(),1);
1085 QTRY_COMPARE(flowSpy.count(),2);
1087 gridView->setWrapEnabled(true);
1088 gridView->setCacheBuffer(5);
1089 gridView->setLayoutDirection(Qt::RightToLeft);
1091 QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
1092 QTRY_COMPARE(cacheBufferSpy.count(),2);
1093 QTRY_COMPARE(layoutSpy.count(),1);
1094 QTRY_COMPARE(flowSpy.count(),2);
1096 gridView->setFlow(QSGGridView::TopToBottom);
1097 QTRY_COMPARE(gridView->flow(), QSGGridView::TopToBottom);
1098 QTRY_COMPARE(flowSpy.count(),3);
1100 gridView->setFlow(QSGGridView::TopToBottom);
1101 QTRY_COMPARE(flowSpy.count(),3);
1106 void tst_QSGGridView::componentChanges()
1108 QSGView *canvas = createView();
1109 QTRY_VERIFY(canvas);
1110 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1112 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1113 QTRY_VERIFY(gridView);
1115 QDeclarativeComponent component(canvas->engine());
1116 component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1118 QDeclarativeComponent delegateComponent(canvas->engine());
1119 delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1121 QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged()));
1122 QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged()));
1123 QSignalSpy headerSpy(gridView, SIGNAL(headerChanged()));
1124 QSignalSpy footerSpy(gridView, SIGNAL(footerChanged()));
1126 gridView->setHighlight(&component);
1127 gridView->setDelegate(&delegateComponent);
1128 gridView->setHeader(&component);
1129 gridView->setFooter(&component);
1131 QTRY_COMPARE(gridView->highlight(), &component);
1132 QTRY_COMPARE(gridView->delegate(), &delegateComponent);
1133 QTRY_COMPARE(gridView->header(), &component);
1134 QTRY_COMPARE(gridView->footer(), &component);
1136 QTRY_COMPARE(highlightSpy.count(),1);
1137 QTRY_COMPARE(delegateSpy.count(),1);
1138 QTRY_COMPARE(headerSpy.count(),1);
1139 QTRY_COMPARE(footerSpy.count(),1);
1141 gridView->setHighlight(&component);
1142 gridView->setDelegate(&delegateComponent);
1143 gridView->setHeader(&component);
1144 gridView->setFooter(&component);
1146 QTRY_COMPARE(highlightSpy.count(),1);
1147 QTRY_COMPARE(delegateSpy.count(),1);
1148 QTRY_COMPARE(headerSpy.count(),1);
1149 QTRY_COMPARE(footerSpy.count(),1);
1154 void tst_QSGGridView::modelChanges()
1156 QSGView *canvas = createView();
1157 QTRY_VERIFY(canvas);
1158 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1160 QSGGridView *gridView = canvas->rootObject()->findChild<QSGGridView*>("gridView");
1161 QTRY_VERIFY(gridView);
1163 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1164 QTRY_VERIFY(alternateModel);
1165 QVariant modelVariant = QVariant::fromValue(alternateModel);
1166 QSignalSpy modelSpy(gridView, SIGNAL(modelChanged()));
1168 gridView->setModel(modelVariant);
1169 QTRY_COMPARE(gridView->model(), modelVariant);
1170 QTRY_COMPARE(modelSpy.count(),1);
1172 gridView->setModel(modelVariant);
1173 QTRY_COMPARE(modelSpy.count(),1);
1175 gridView->setModel(QVariant());
1176 QTRY_COMPARE(modelSpy.count(),2);
1180 void tst_QSGGridView::positionViewAtIndex()
1182 QSGView *canvas = createView();
1185 for (int i = 0; i < 40; i++)
1186 model.addItem("Item" + QString::number(i), "");
1188 QDeclarativeContext *ctxt = canvas->rootContext();
1189 ctxt->setContextProperty("testModel", &model);
1190 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1191 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1193 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1194 qApp->processEvents();
1196 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1197 QTRY_VERIFY(gridview != 0);
1199 QSGItem *contentItem = gridview->contentItem();
1200 QTRY_VERIFY(contentItem != 0);
1202 // Confirm items positioned correctly
1203 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1204 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1205 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1206 if (!item) qWarning() << "Item" << i << "not found";
1208 QTRY_COMPARE(item->x(), (i%3)*80.);
1209 QTRY_COMPARE(item->y(), (i/3)*60.);
1212 // Position on a currently visible item
1213 gridview->positionViewAtIndex(4, QSGGridView::Beginning);
1214 QTRY_COMPARE(gridview->indexAt(120, 90), 4);
1215 QTRY_COMPARE(gridview->contentY(), 60.);
1217 // Confirm items positioned correctly
1218 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1219 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1220 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1221 if (!item) qWarning() << "Item" << i << "not found";
1223 QTRY_COMPARE(item->x(), (i%3)*80.);
1224 QTRY_COMPARE(item->y(), (i/3)*60.);
1227 // Position on an item beyond the visible items
1228 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1229 QTRY_COMPARE(gridview->indexAt(40, 450), 21);
1230 QTRY_COMPARE(gridview->contentY(), 420.);
1232 // Confirm items positioned correctly
1233 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1234 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1235 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1236 if (!item) qWarning() << "Item" << i << "not found";
1238 QTRY_COMPARE(item->x(), (i%3)*80.);
1239 QTRY_COMPARE(item->y(), (i/3)*60.);
1242 // Position on an item that would leave empty space if positioned at the top
1243 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1244 QTRY_COMPARE(gridview->indexAt(120, 630), 31);
1245 QTRY_COMPARE(gridview->contentY(), 520.);
1247 // Confirm items positioned correctly
1248 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1249 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1250 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1251 if (!item) qWarning() << "Item" << i << "not found";
1253 QTRY_COMPARE(item->x(), (i%3)*80.);
1254 QTRY_COMPARE(item->y(), (i/3)*60.);
1257 // Position at the beginning again
1258 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1259 QTRY_COMPARE(gridview->indexAt(0, 0), 0);
1260 QTRY_COMPARE(gridview->indexAt(40, 30), 0);
1261 QTRY_COMPARE(gridview->indexAt(80, 60), 4);
1262 QTRY_COMPARE(gridview->contentY(), 0.);
1264 // Confirm items positioned correctly
1265 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1266 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1267 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1268 if (!item) qWarning() << "Item" << i << "not found";
1270 QTRY_COMPARE(item->x(), (i%3)*80.);
1271 QTRY_COMPARE(item->y(), (i/3)*60.);
1275 gridview->positionViewAtIndex(30, QSGGridView::End);
1276 QTRY_COMPARE(gridview->contentY(), 340.);
1278 // Position in Center
1279 gridview->positionViewAtIndex(15, QSGGridView::Center);
1280 QTRY_COMPARE(gridview->contentY(), 170.);
1282 // Ensure at least partially visible
1283 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1284 QTRY_COMPARE(gridview->contentY(), 170.);
1286 gridview->setContentY(302);
1287 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1288 QTRY_COMPARE(gridview->contentY(), 302.);
1290 gridview->setContentY(360);
1291 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1292 QTRY_COMPARE(gridview->contentY(), 300.);
1294 gridview->setContentY(60);
1295 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1296 QTRY_COMPARE(gridview->contentY(), 60.);
1298 gridview->setContentY(20);
1299 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1300 QTRY_COMPARE(gridview->contentY(), 100.);
1302 // Ensure completely visible
1303 gridview->setContentY(120);
1304 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1305 QTRY_COMPARE(gridview->contentY(), 120.);
1307 gridview->setContentY(302);
1308 gridview->positionViewAtIndex(15, QSGGridView::Contain);
1309 QTRY_COMPARE(gridview->contentY(), 300.);
1311 gridview->setContentY(60);
1312 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1313 QTRY_COMPARE(gridview->contentY(), 100.);
1315 // Test for Top To Bottom layout
1316 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1318 // Confirm items positioned correctly
1319 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1320 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1321 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1322 if (!item) qWarning() << "Item" << i << "not found";
1324 QTRY_COMPARE(item->x(), (i/5)*80.);
1325 QTRY_COMPARE(item->y(), (i%5)*60.);
1329 gridview->positionViewAtIndex(30, QSGGridView::End);
1330 QTRY_COMPARE(gridview->contentX(), 320.);
1331 QTRY_COMPARE(gridview->contentY(), 0.);
1333 // Position in Center
1334 gridview->positionViewAtIndex(15, QSGGridView::Center);
1335 QTRY_COMPARE(gridview->contentX(), 160.);
1337 // Ensure at least partially visible
1338 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1339 QTRY_COMPARE(gridview->contentX(), 160.);
1341 gridview->setContentX(170);
1342 gridview->positionViewAtIndex(25, QSGGridView::Visible);
1343 QTRY_COMPARE(gridview->contentX(), 170.);
1345 gridview->positionViewAtIndex(30, QSGGridView::Visible);
1346 QTRY_COMPARE(gridview->contentX(), 320.);
1348 gridview->setContentX(170);
1349 gridview->positionViewAtIndex(25, QSGGridView::Contain);
1350 QTRY_COMPARE(gridview->contentX(), 240.);
1352 // positionViewAtBeginning
1353 gridview->positionViewAtBeginning();
1354 QTRY_COMPARE(gridview->contentX(), 0.);
1356 gridview->setContentX(80);
1357 canvas->rootObject()->setProperty("showHeader", true);
1358 gridview->positionViewAtBeginning();
1359 QTRY_COMPARE(gridview->contentX(), -30.);
1361 // positionViewAtEnd
1362 gridview->positionViewAtEnd();
1363 QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns)
1365 gridview->setContentX(80);
1366 canvas->rootObject()->setProperty("showFooter", true);
1367 gridview->positionViewAtEnd();
1368 QTRY_COMPARE(gridview->contentX(), 430.);
1370 // set current item to outside visible view, position at beginning
1371 // and ensure highlight moves to current item
1372 gridview->setCurrentIndex(6);
1373 gridview->positionViewAtBeginning();
1374 QTRY_COMPARE(gridview->contentX(), -30.);
1375 QVERIFY(gridview->highlightItem());
1376 QCOMPARE(gridview->highlightItem()->x(), 80.);
1381 void tst_QSGGridView::snapping()
1383 QSGView *canvas = createView();
1386 for (int i = 0; i < 40; i++)
1387 model.addItem("Item" + QString::number(i), "");
1389 QDeclarativeContext *ctxt = canvas->rootContext();
1390 ctxt->setContextProperty("testModel", &model);
1391 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1392 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1394 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1395 qApp->processEvents();
1397 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1398 QTRY_VERIFY(gridview != 0);
1400 gridview->setHeight(220);
1401 QCOMPARE(gridview->height(), 220.);
1403 gridview->positionViewAtIndex(12, QSGGridView::Visible);
1404 QCOMPARE(gridview->contentY(), 80.);
1406 gridview->setContentY(0);
1407 QCOMPARE(gridview->contentY(), 0.);
1409 gridview->setSnapMode(QSGGridView::SnapToRow);
1410 QCOMPARE(gridview->snapMode(), QSGGridView::SnapToRow);
1412 gridview->positionViewAtIndex(12, QSGGridView::Visible);
1413 QCOMPARE(gridview->contentY(), 60.);
1415 gridview->positionViewAtIndex(15, QSGGridView::End);
1416 QCOMPARE(gridview->contentY(), 120.);
1422 void tst_QSGGridView::mirroring()
1424 QSGView *canvasA = createView();
1425 canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
1426 QSGGridView *gridviewA = findItem<QSGGridView>(canvasA->rootObject(), "view");
1427 QTRY_VERIFY(gridviewA != 0);
1429 QSGView *canvasB = createView();
1430 canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/mirroring.qml"));
1431 QSGGridView *gridviewB = findItem<QSGGridView>(canvasB->rootObject(), "view");
1432 QTRY_VERIFY(gridviewA != 0);
1433 qApp->processEvents();
1435 QList<QString> objectNames;
1436 objectNames << "item1" << "item2"; // << "item3"
1438 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1439 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
1440 QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
1443 foreach(const QString objectName, objectNames)
1444 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1446 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1447 gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
1450 foreach(const QString objectName, objectNames)
1451 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1453 QVERIFY(gridviewB->layoutDirection() == gridviewB->effectiveLayoutDirection());
1454 QSGItemPrivate::get(gridviewB)->setLayoutMirror(true);
1455 QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
1457 // LTR != LTR+mirror
1458 foreach(const QString objectName, objectNames)
1459 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1461 gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
1463 // RTL == LTR+mirror
1464 foreach(const QString objectName, objectNames)
1465 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1467 gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
1469 // RTL != RTL+mirror
1470 foreach(const QString objectName, objectNames)
1471 QVERIFY(findItem<QSGItem>(gridviewA, objectName)->x() != findItem<QSGItem>(gridviewB, objectName)->x());
1473 gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
1475 // LTR == RTL+mirror
1476 foreach(const QString objectName, objectNames)
1477 QCOMPARE(findItem<QSGItem>(gridviewA, objectName)->x(), findItem<QSGItem>(gridviewB, objectName)->x());
1483 void tst_QSGGridView::positionViewAtIndex_rightToLeft()
1485 QSGView *canvas = createView();
1488 for (int i = 0; i < 40; i++)
1489 model.addItem("Item" + QString::number(i), "");
1491 QDeclarativeContext *ctxt = canvas->rootContext();
1492 ctxt->setContextProperty("testModel", &model);
1493 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1494 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1496 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
1497 qApp->processEvents();
1499 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1500 QTRY_VERIFY(gridview != 0);
1502 QSGItem *contentItem = gridview->contentItem();
1503 QTRY_VERIFY(contentItem != 0);
1505 // Confirm items positioned correctly
1506 int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1507 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1508 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1509 if (!item) qWarning() << "Item" << i << "not found";
1511 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1512 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1515 // Position on a currently visible item
1516 gridview->positionViewAtIndex(6, QSGGridView::Beginning);
1517 QTRY_COMPARE(gridview->contentX(), -320.);
1519 // Confirm items positioned correctly
1520 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1521 for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1522 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1523 if (!item) qWarning() << "Item" << i << "not found";
1525 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1526 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1529 // Position on an item beyond the visible items
1530 gridview->positionViewAtIndex(21, QSGGridView::Beginning);
1531 QTRY_COMPARE(gridview->contentX(), -560.);
1533 // Confirm items positioned correctly
1534 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1535 for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1536 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1537 if (!item) qWarning() << "Item" << i << "not found";
1539 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1540 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1543 // Position on an item that would leave empty space if positioned at the top
1544 gridview->positionViewAtIndex(31, QSGGridView::Beginning);
1545 QTRY_COMPARE(gridview->contentX(), -640.);
1547 // Confirm items positioned correctly
1548 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1549 for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1550 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1551 if (!item) qWarning() << "Item" << i << "not found";
1553 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1554 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1557 // Position at the beginning again
1558 gridview->positionViewAtIndex(0, QSGGridView::Beginning);
1559 QTRY_COMPARE(gridview->contentX(), -240.);
1561 // Confirm items positioned correctly
1562 itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
1563 for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1564 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
1565 if (!item) qWarning() << "Item" << i << "not found";
1567 QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width()));
1568 QTRY_COMPARE(item->y(), qreal((i%5)*60));
1572 gridview->positionViewAtIndex(30, QSGGridView::End);
1573 QTRY_COMPARE(gridview->contentX(), -560.);
1575 // Position in Center
1576 gridview->positionViewAtIndex(15, QSGGridView::Center);
1577 QTRY_COMPARE(gridview->contentX(), -400.);
1579 // Ensure at least partially visible
1580 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1581 QTRY_COMPARE(gridview->contentX(), -400.);
1583 gridview->setContentX(-555.);
1584 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1585 QTRY_COMPARE(gridview->contentX(), -555.);
1587 gridview->setContentX(-239);
1588 gridview->positionViewAtIndex(15, QSGGridView::Visible);
1589 QTRY_COMPARE(gridview->contentX(), -320.);
1591 gridview->setContentX(-239);
1592 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1593 QTRY_COMPARE(gridview->contentX(), -400.);
1595 gridview->setContentX(-640);
1596 gridview->positionViewAtIndex(20, QSGGridView::Visible);
1597 QTRY_COMPARE(gridview->contentX(), -560.);
1599 // Ensure completely visible
1600 gridview->setContentX(-400);
1601 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1602 QTRY_COMPARE(gridview->contentX(), -400.);
1604 gridview->setContentX(-315);
1605 gridview->positionViewAtIndex(15, QSGGridView::Contain);
1606 QTRY_COMPARE(gridview->contentX(), -320.);
1608 gridview->setContentX(-640);
1609 gridview->positionViewAtIndex(20, QSGGridView::Contain);
1610 QTRY_COMPARE(gridview->contentX(), -560.);
1615 void tst_QSGGridView::resetModel()
1617 QSGView *canvas = createView();
1619 QStringList strings;
1620 strings << "one" << "two" << "three";
1621 QStringListModel model(strings);
1623 QDeclarativeContext *ctxt = canvas->rootContext();
1624 ctxt->setContextProperty("testModel", &model);
1626 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaygrid.qml"));
1627 qApp->processEvents();
1629 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1630 QTRY_VERIFY(gridview != 0);
1632 QSGItem *contentItem = gridview->contentItem();
1633 QTRY_VERIFY(contentItem != 0);
1635 QTRY_COMPARE(gridview->count(), model.rowCount());
1637 for (int i = 0; i < model.rowCount(); ++i) {
1638 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
1639 QTRY_VERIFY(display != 0);
1640 QTRY_COMPARE(display->text(), strings.at(i));
1644 strings << "four" << "five" << "six" << "seven";
1645 model.setStringList(strings);
1647 QTRY_COMPARE(gridview->count(), model.rowCount());
1649 for (int i = 0; i < model.rowCount(); ++i) {
1650 QSGText *display = findItem<QSGText>(contentItem, "displayText", i);
1651 QTRY_VERIFY(display != 0);
1652 QTRY_COMPARE(display->text(), strings.at(i));
1658 void tst_QSGGridView::enforceRange()
1660 QSGView *canvas = createView();
1663 for (int i = 0; i < 30; i++)
1664 model.addItem("Item" + QString::number(i), "");
1666 QDeclarativeContext *ctxt = canvas->rootContext();
1667 ctxt->setContextProperty("testModel", &model);
1668 ctxt->setContextProperty("testRightToLeft", QVariant(false));
1669 ctxt->setContextProperty("testTopToBottom", QVariant(false));
1671 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
1672 qApp->processEvents();
1673 QVERIFY(canvas->rootObject() != 0);
1675 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1676 QTRY_VERIFY(gridview != 0);
1678 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
1679 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
1680 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
1682 QSGItem *contentItem = gridview->contentItem();
1683 QTRY_VERIFY(contentItem != 0);
1685 // view should be positioned at the top of the range.
1686 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
1688 QTRY_COMPARE(gridview->contentY(), -100.0);
1690 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
1691 QTRY_VERIFY(name != 0);
1692 QTRY_COMPARE(name->text(), model.name(0));
1693 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
1694 QTRY_VERIFY(number != 0);
1695 QTRY_COMPARE(number->text(), model.number(0));
1697 // Check currentIndex is updated when contentItem moves
1698 gridview->setContentY(0);
1699 QTRY_COMPARE(gridview->currentIndex(), 2);
1701 gridview->setCurrentIndex(5);
1702 QTRY_COMPARE(gridview->contentY(), 100.);
1705 for (int i = 0; i < 5; i++)
1706 model2.addItem("Item" + QString::number(i), "");
1708 ctxt->setContextProperty("testModel", &model2);
1709 QCOMPARE(gridview->count(), 5);
1714 void tst_QSGGridView::enforceRange_rightToLeft()
1716 QSGView *canvas = createView();
1719 for (int i = 0; i < 30; i++)
1720 model.addItem("Item" + QString::number(i), "");
1722 QDeclarativeContext *ctxt = canvas->rootContext();
1723 ctxt->setContextProperty("testModel", &model);
1724 ctxt->setContextProperty("testRightToLeft", QVariant(true));
1725 ctxt->setContextProperty("testTopToBottom", QVariant(true));
1727 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview-enforcerange.qml"));
1728 qApp->processEvents();
1729 QVERIFY(canvas->rootObject() != 0);
1731 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1732 QTRY_VERIFY(gridview != 0);
1734 QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
1735 QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
1736 QTRY_COMPARE(gridview->highlightRangeMode(), QSGGridView::StrictlyEnforceRange);
1738 QSGItem *contentItem = gridview->contentItem();
1739 QTRY_VERIFY(contentItem != 0);
1741 // view should be positioned at the top of the range.
1742 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
1744 QTRY_COMPARE(gridview->contentX(), -100.);
1745 QTRY_COMPARE(gridview->contentY(), 0.0);
1747 QSGText *name = findItem<QSGText>(contentItem, "textName", 0);
1748 QTRY_VERIFY(name != 0);
1749 QTRY_COMPARE(name->text(), model.name(0));
1750 QSGText *number = findItem<QSGText>(contentItem, "textNumber", 0);
1751 QTRY_VERIFY(number != 0);
1752 QTRY_COMPARE(number->text(), model.number(0));
1754 // Check currentIndex is updated when contentItem moves
1755 gridview->setContentX(-200);
1756 QTRY_COMPARE(gridview->currentIndex(), 3);
1758 gridview->setCurrentIndex(7);
1759 QTRY_COMPARE(gridview->contentX(), -300.);
1760 QTRY_COMPARE(gridview->contentY(), 0.0);
1763 for (int i = 0; i < 5; i++)
1764 model2.addItem("Item" + QString::number(i), "");
1766 ctxt->setContextProperty("testModel", &model2);
1767 QCOMPARE(gridview->count(), 5);
1772 void tst_QSGGridView::QTBUG_8456()
1774 QSGView *canvas = createView();
1776 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/setindex.qml"));
1777 qApp->processEvents();
1779 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1780 QTRY_VERIFY(gridview != 0);
1782 QTRY_COMPARE(gridview->currentIndex(), 0);
1787 void tst_QSGGridView::manualHighlight()
1789 QSGView *canvas = createView();
1791 QString filename(SRCDIR "/data/manual-highlight.qml");
1792 canvas->setSource(QUrl::fromLocalFile(filename));
1794 qApp->processEvents();
1796 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1797 QTRY_VERIFY(gridview != 0);
1799 QSGItem *contentItem = gridview->contentItem();
1800 QTRY_VERIFY(contentItem != 0);
1802 QTRY_COMPARE(gridview->currentIndex(), 0);
1803 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
1804 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1805 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1807 gridview->setCurrentIndex(2);
1809 QTRY_COMPARE(gridview->currentIndex(), 2);
1810 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
1811 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1812 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1814 gridview->positionViewAtIndex(8, QSGGridView::Contain);
1816 QTRY_COMPARE(gridview->currentIndex(), 2);
1817 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 2));
1818 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1819 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1821 gridview->setFlow(QSGGridView::TopToBottom);
1822 QTRY_COMPARE(gridview->flow(), QSGGridView::TopToBottom);
1824 gridview->setCurrentIndex(0);
1825 QTRY_COMPARE(gridview->currentIndex(), 0);
1826 QTRY_COMPARE(gridview->currentItem(), findItem<QSGItem>(contentItem, "wrapper", 0));
1827 QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y());
1828 QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x());
1834 void tst_QSGGridView::footer()
1836 QFETCH(QSGGridView::Flow, flow);
1837 QFETCH(Qt::LayoutDirection, layoutDirection);
1838 QFETCH(QPointF, initialFooterPos);
1839 QFETCH(QPointF, changedFooterPos);
1840 QFETCH(QPointF, initialContentPos);
1841 QFETCH(QPointF, changedContentPos);
1842 QFETCH(QPointF, firstDelegatePos);
1844 QSGView *canvas = createView();
1848 for (int i = 0; i < 7; i++)
1849 model.addItem("Item" + QString::number(i), "");
1851 QDeclarativeContext *ctxt = canvas->rootContext();
1852 ctxt->setContextProperty("testModel", &model);
1854 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml"));
1855 qApp->processEvents();
1857 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1858 QTRY_VERIFY(gridview != 0);
1859 gridview->setFlow(flow);
1860 gridview->setLayoutDirection(layoutDirection);
1862 QSGItem *contentItem = gridview->contentItem();
1863 QTRY_VERIFY(contentItem != 0);
1865 QSGText *footer = findItem<QSGText>(contentItem, "footer");
1868 QCOMPARE(footer->pos(), initialFooterPos);
1869 QCOMPARE(footer->width(), 100.);
1870 QCOMPARE(footer->height(), 30.);
1871 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
1873 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
1875 QCOMPARE(item->pos(), firstDelegatePos);
1877 if (flow == QSGGridView::LeftToRight) {
1878 // shrink by one row
1879 model.removeItem(2);
1880 QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight());
1882 // shrink by one column
1883 model.removeItem(2);
1884 model.removeItem(3);
1885 if (layoutDirection == Qt::LeftToRight)
1886 QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth());
1888 QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth());
1894 QPointF posWhenNoItems(0, 0);
1895 if (layoutDirection == Qt::RightToLeft)
1896 posWhenNoItems.setX(flow == QSGGridView::LeftToRight ? gridview->width() - footer->width() : -footer->width());
1897 QTRY_COMPARE(footer->pos(), posWhenNoItems);
1899 // if header is present, it's at a negative pos, so the footer should not move
1900 canvas->rootObject()->setProperty("showHeader", true);
1901 QVERIFY(findItem<QSGItem>(contentItem, "header") != 0);
1902 QTRY_COMPARE(footer->pos(), posWhenNoItems);
1903 canvas->rootObject()->setProperty("showHeader", false);
1906 for (int i = 0; i < 30; i++)
1907 model.addItem("Item" + QString::number(i), "");
1908 QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
1910 footer = findItem<QSGText>(contentItem, "footer");
1912 footer = findItem<QSGText>(contentItem, "footer2");
1915 QCOMPARE(footer->pos(), changedFooterPos);
1916 QCOMPARE(footer->width(), 50.);
1917 QCOMPARE(footer->height(), 20.);
1918 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
1920 item = findItem<QSGItem>(contentItem, "wrapper", 0);
1922 QCOMPARE(item->pos(), firstDelegatePos);
1927 void tst_QSGGridView::footer_data()
1929 QTest::addColumn<QSGGridView::Flow>("flow");
1930 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
1931 QTest::addColumn<QPointF>("initialFooterPos");
1932 QTest::addColumn<QPointF>("changedFooterPos");
1933 QTest::addColumn<QPointF>("initialContentPos");
1934 QTest::addColumn<QPointF>("changedContentPos");
1935 QTest::addColumn<QPointF>("firstDelegatePos");
1937 // footer1 = 100 x 30
1938 // footer2 = 100 x 20
1942 // footer below items, bottom left
1943 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
1944 << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60)
1945 << QPointF(0, 10 * 60) // 30 items = 10 rows
1950 // footer below items, bottom right
1951 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
1952 << QPointF(240 - 100, 3 * 60)
1953 << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers
1956 << QPointF(240 - 80, 0);
1958 // footer to right of items
1959 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
1960 << QPointF(2 * 80, 0) // 2 columns, cell width 80
1961 << QPointF(6 * 80, 0) // 30 items = 6 columns
1966 // footer to left of items
1967 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
1968 << QPointF(-(2 * 80) - 100, 0)
1969 << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width
1971 << QPointF(-240, 0) // unchanged, footer change doesn't change content pos
1975 void tst_QSGGridView::header()
1977 QFETCH(QSGGridView::Flow, flow);
1978 QFETCH(Qt::LayoutDirection, layoutDirection);
1979 QFETCH(QPointF, initialHeaderPos);
1980 QFETCH(QPointF, changedHeaderPos);
1981 QFETCH(QPointF, initialContentPos);
1982 QFETCH(QPointF, changedContentPos);
1983 QFETCH(QPointF, firstDelegatePos);
1985 QSGView *canvas = createView();
1988 for (int i = 0; i < 30; i++)
1989 model.addItem("Item" + QString::number(i), "");
1991 QDeclarativeContext *ctxt = canvas->rootContext();
1992 ctxt->setContextProperty("testModel", &model);
1994 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
1995 qApp->processEvents();
1997 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
1998 QTRY_VERIFY(gridview != 0);
1999 gridview->setFlow(flow);
2000 gridview->setLayoutDirection(layoutDirection);
2002 QSGItem *contentItem = gridview->contentItem();
2003 QTRY_VERIFY(contentItem != 0);
2005 QSGText *header = findItem<QSGText>(contentItem, "header");
2008 QCOMPARE(header->pos(), initialHeaderPos);
2009 QCOMPARE(header->width(), 100.);
2010 QCOMPARE(header->height(), 30.);
2011 QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos);
2013 QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
2015 QCOMPARE(item->pos(), firstDelegatePos);
2018 QCOMPARE(header->pos(), initialHeaderPos); // header should stay where it is
2020 for (int i = 0; i < 30; i++)
2021 model.addItem("Item" + QString::number(i), "");
2023 QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
2025 header = findItem<QSGText>(contentItem, "header");
2027 header = findItem<QSGText>(contentItem, "header2");
2030 QCOMPARE(header->pos(), changedHeaderPos);
2031 QCOMPARE(header->width(), 50.);
2032 QCOMPARE(header->height(), 20.);
2033 QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos);
2035 item = findItem<QSGItem>(contentItem, "wrapper", 0);
2037 QCOMPARE(item->pos(), firstDelegatePos);
2042 void tst_QSGGridView::header_data()
2044 QTest::addColumn<QSGGridView::Flow>("flow");
2045 QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
2046 QTest::addColumn<QPointF>("initialHeaderPos");
2047 QTest::addColumn<QPointF>("changedHeaderPos");
2048 QTest::addColumn<QPointF>("initialContentPos");
2049 QTest::addColumn<QPointF>("changedContentPos");
2050 QTest::addColumn<QPointF>("firstDelegatePos");
2052 // header1 = 100 x 30
2053 // header2 = 100 x 20
2057 // header above items, top left
2058 QTest::newRow("flow left to right") << QSGGridView::LeftToRight << Qt::LeftToRight
2065 // header above items, top right
2066 QTest::newRow("flow left to right, layout right to left") << QSGGridView::LeftToRight << Qt::RightToLeft
2067 << QPointF(240 - 100, -30)
2068 << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers
2073 // header to left of items
2074 QTest::newRow("flow top to bottom, layout left to right") << QSGGridView::TopToBottom << Qt::LeftToRight
2081 // header to right of items
2082 QTest::newRow("flow top to bottom, layout right to left") << QSGGridView::TopToBottom << Qt::RightToLeft
2085 << QPointF(-(240 - 100), 0)
2086 << QPointF(-(240 - 50), 0)
2090 void tst_QSGGridView::indexAt()
2092 QSGView *canvas = createView();
2095 model.addItem("Fred", "12345");
2096 model.addItem("John", "2345");
2097 model.addItem("Bob", "54321");
2098 model.addItem("Billy", "22345");
2099 model.addItem("Sam", "2945");
2100 model.addItem("Ben", "04321");
2101 model.addItem("Jim", "0780");
2103 QDeclarativeContext *ctxt = canvas->rootContext();
2104 ctxt->setContextProperty("testModel", &model);
2105 ctxt->setContextProperty("testRightToLeft", QVariant(false));
2106 ctxt->setContextProperty("testTopToBottom", QVariant(false));
2108 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml"));
2109 qApp->processEvents();
2111 QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
2112 QTRY_VERIFY(gridview != 0);
2114 QSGItem *contentItem = gridview->contentItem();
2115 QTRY_VERIFY(contentItem != 0);
2117 QTRY_COMPARE(gridview->count(), model.count());
2119 QCOMPARE(gridview->indexAt(0, 0), 0);
2120 QCOMPARE(gridview->indexAt(79, 59), 0);
2121 QCOMPARE(gridview->indexAt(80, 0), 1);
2122 QCOMPARE(gridview->indexAt(0, 60), 3);
2123 QCOMPARE(gridview->indexAt(240, 0), -1);
2128 void tst_QSGGridView::onAdd()
2130 QFETCH(int, initialItemCount);
2131 QFETCH(int, itemsToAdd);
2133 const int delegateWidth = 50;
2134 const int delegateHeight = 100;
2136 QSGView *canvas = createView();
2137 canvas->setFixedSize(5 * delegateWidth, 5 * delegateHeight); // just ensure all items fit
2139 // these initial items should not trigger GridView.onAdd
2140 for (int i=0; i<initialItemCount; i++)
2141 model.addItem("dummy value", "dummy value");
2143 QDeclarativeContext *ctxt = canvas->rootContext();
2144 ctxt->setContextProperty("testModel", &model);
2145 ctxt->setContextProperty("delegateWidth", delegateWidth);
2146 ctxt->setContextProperty("delegateHeight", delegateHeight);
2147 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2149 QObject *object = canvas->rootObject();
2150 object->setProperty("width", canvas->width());
2151 object->setProperty("height", canvas->height());
2152 qApp->processEvents();
2154 QList<QPair<QString, QString> > items;
2155 for (int i=0; i<itemsToAdd; i++)
2156 items << qMakePair(QString("value %1").arg(i), QString::number(i));
2157 model.addItems(items);
2159 qApp->processEvents();
2161 QVariantList result = object->property("addedDelegates").toList();
2162 QCOMPARE(result.count(), items.count());
2163 for (int i=0; i<items.count(); i++)
2164 QCOMPARE(result[i].toString(), items[i].first);
2169 void tst_QSGGridView::onAdd_data()
2171 QTest::addColumn<int>("initialItemCount");
2172 QTest::addColumn<int>("itemsToAdd");
2174 QTest::newRow("0, add 1") << 0 << 1;
2175 QTest::newRow("0, add 2") << 0 << 2;
2176 QTest::newRow("0, add 10") << 0 << 10;
2178 QTest::newRow("1, add 1") << 1 << 1;
2179 QTest::newRow("1, add 2") << 1 << 2;
2180 QTest::newRow("1, add 10") << 1 << 10;
2182 QTest::newRow("5, add 1") << 5 << 1;
2183 QTest::newRow("5, add 2") << 5 << 2;
2184 QTest::newRow("5, add 10") << 5 << 10;
2187 void tst_QSGGridView::onRemove()
2189 QFETCH(int, initialItemCount);
2190 QFETCH(int, indexToRemove);
2191 QFETCH(int, removeCount);
2193 const int delegateWidth = 50;
2194 const int delegateHeight = 100;
2196 for (int i=0; i<initialItemCount; i++)
2197 model.addItem(QString("value %1").arg(i), "dummy value");
2199 QSGView *canvas = createView();
2200 QDeclarativeContext *ctxt = canvas->rootContext();
2201 ctxt->setContextProperty("testModel", &model);
2202 ctxt->setContextProperty("delegateWidth", delegateWidth);
2203 ctxt->setContextProperty("delegateHeight", delegateHeight);
2204 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2205 QObject *object = canvas->rootObject();
2207 qApp->processEvents();
2209 model.removeItems(indexToRemove, removeCount);
2210 qApp->processEvents();
2211 QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2216 void tst_QSGGridView::onRemove_data()
2218 QTest::addColumn<int>("initialItemCount");
2219 QTest::addColumn<int>("indexToRemove");
2220 QTest::addColumn<int>("removeCount");
2222 QTest::newRow("remove first") << 1 << 0 << 1;
2223 QTest::newRow("two items, remove first") << 2 << 0 << 1;
2224 QTest::newRow("two items, remove last") << 2 << 1 << 1;
2225 QTest::newRow("two items, remove all") << 2 << 0 << 2;
2227 QTest::newRow("four items, remove first") << 4 << 0 << 1;
2228 QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2229 QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2230 QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2231 QTest::newRow("four items, remove last") << 4 << 3 << 1;
2232 QTest::newRow("four items, remove all") << 4 << 0 << 4;
2234 QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2235 QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2236 QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2239 void tst_QSGGridView::testQtQuick11Attributes()
2241 QFETCH(QString, code);
2242 QFETCH(QString, warning);
2243 QFETCH(QString, error);
2245 QDeclarativeEngine engine;
2248 QDeclarativeComponent valid(&engine);
2249 valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
2250 obj = valid.create();
2252 QVERIFY(valid.errorString().isEmpty());
2255 QDeclarativeComponent invalid(&engine);
2256 invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
2257 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2258 obj = invalid.create();
2259 QCOMPARE(invalid.errorString(), error);
2263 void tst_QSGGridView::testQtQuick11Attributes_data()
2265 QTest::addColumn<QString>("code");
2266 QTest::addColumn<QString>("warning");
2267 QTest::addColumn<QString>("error");
2269 QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2270 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2273 QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2274 << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2278 QSGView *tst_QSGGridView::createView()
2280 QSGView *canvas = new QSGView(0);
2281 canvas->setFixedSize(240,320);
2287 Find an item with the specified objectName. If index is supplied then the
2288 item must also evaluate the {index} expression equal to index
2290 template<typename T>
2291 T *tst_QSGGridView::findItem(QSGItem *parent, const QString &objectName, int index)
2293 const QMetaObject &mo = T::staticMetaObject;
2294 //qDebug() << parent->childItems().count() << "children";
2295 for (int i = 0; i < parent->childItems().count(); ++i) {
2296 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2299 //qDebug() << "try" << item;
2300 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2302 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
2304 if (context->contextProperty("index").toInt() == index) {
2305 return static_cast<T*>(item);
2309 return static_cast<T*>(item);
2312 item = findItem<T>(item, objectName, index);
2314 return static_cast<T*>(item);
2320 template<typename T>
2321 QList<T*> tst_QSGGridView::findItems(QSGItem *parent, const QString &objectName)
2324 const QMetaObject &mo = T::staticMetaObject;
2325 //qDebug() << parent->childItems().count() << "children";
2326 for (int i = 0; i < parent->childItems().count(); ++i) {
2327 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2330 //qDebug() << "try" << item;
2331 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2332 items.append(static_cast<T*>(item));
2333 //qDebug() << " found:" << item;
2335 items += findItems<T>(item, objectName);
2341 void tst_QSGGridView::dumpTree(QSGItem *parent, int depth)
2343 static QString padding(" ");
2344 for (int i = 0; i < parent->childItems().count(); ++i) {
2345 QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
2348 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(item);
2349 qDebug() << padding.left(depth*2) << item << (context ? context->contextProperty("index").toInt() : -1);
2350 dumpTree(item, depth+1);
2355 QTEST_MAIN(tst_QSGGridView)
2357 #include "tst_qsggridview.moc"