1 /****************************************************************************
3 ** Copyright (C) 2012 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 <QtQuick/qquickview.h>
44 #include <QtDeclarative/qdeclarativeengine.h>
45 #include <QtDeclarative/qdeclarativecomponent.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeexpression.h>
48 #include <QtDeclarative/qdeclarativeincubator.h>
49 #include <QtQuick/private/qquickpathview_p.h>
50 #include <QtQuick/private/qdeclarativepath_p.h>
51 #include <QtQuick/private/qquicktext_p.h>
52 #include <QtQuick/private/qquickrectangle_p.h>
53 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
54 #include <QtDeclarative/private/qdeclarativevaluetype_p.h>
55 #include <QAbstractListModel>
56 #include <QStringListModel>
57 #include <QStandardItemModel>
60 #include "../../shared/util.h"
62 static void initStandardTreeModel(QStandardItemModel *model)
65 item = new QStandardItem(QLatin1String("Row 1 Item"));
66 model->insertRow(0, item);
68 item = new QStandardItem(QLatin1String("Row 2 Item"));
69 item->setCheckable(true);
70 model->insertRow(1, item);
72 QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
73 item->setChild(0, childItem);
75 item = new QStandardItem(QLatin1String("Row 3 Item"));
76 item->setIcon(QIcon());
77 model->insertRow(2, item);
81 class tst_QQuickPathView : public QDeclarativeDataTest
93 void insertModel_data();
95 void removeModel_data();
97 void moveModel_data();
101 void setCurrentIndex();
103 void propertyChanges();
105 void componentChanges();
107 void pathUpdateOnStartChanged();
112 void visualDataModel();
113 void undefinedPath();
116 void changePreferredHighlight();
117 void missingPercent();
118 void creationContext();
119 void currentOffsetOnInsertion();
123 QQuickView *createView();
125 T *findItem(QQuickItem *parent, const QString &objectName, int index=-1);
127 QList<T*> findItems(QQuickItem *parent, const QString &objectName);
130 class TestObject : public QObject
134 Q_PROPERTY(bool error READ error WRITE setError)
135 Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
136 Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
139 TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
141 bool error() const { return mError; }
142 void setError(bool err) { mError = err; }
144 bool useModel() const { return mUseModel; }
145 void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
147 int pathItemCount() const { return mPathItemCount; }
148 void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
151 void useModelChanged();
152 void pathItemCountChanged();
160 class TestModel : public QAbstractListModel
163 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
165 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
166 QHash<int, QByteArray> roles;
167 roles[Name] = "name";
168 roles[Number] = "number";
172 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
173 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
176 rv = list.at(index.row()).first;
177 else if (role == Number)
178 rv = list.at(index.row()).second;
183 int count() const { return rowCount(); }
184 QString name(int index) const { return list.at(index).first; }
185 QString number(int index) const { return list.at(index).second; }
187 void addItem(const QString &name, const QString &number) {
188 beginInsertRows(QModelIndex(), list.count(), list.count());
189 list.append(QPair<QString,QString>(name, number));
193 void insertItem(int index, const QString &name, const QString &number) {
194 beginInsertRows(QModelIndex(), index, index);
195 list.insert(index, QPair<QString,QString>(name, number));
199 void insertItems(int index, const QList<QPair<QString, QString> > &items) {
200 beginInsertRows(QModelIndex(), index, index+items.count()-1);
201 for (int i=0; i<items.count(); i++)
202 list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
206 void removeItem(int index) {
207 beginRemoveRows(QModelIndex(), index, index);
208 list.removeAt(index);
212 void removeItems(int index, int count) {
213 emit beginRemoveRows(QModelIndex(), index, index+count-1);
215 list.removeAt(index);
216 emit endRemoveRows();
219 void moveItem(int from, int to) {
220 beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
225 void moveItems(int from, int to, int count) {
226 beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
227 move(from, to, count);
231 void modifyItem(int idx, const QString &name, const QString &number) {
232 list[idx] = QPair<QString,QString>(name, number);
233 emit dataChanged(index(idx,0), index(idx,0));
236 void move(int from, int to, int n)
239 // Only move forwards - flip if backwards moving
249 QList<QPair<QString,QString> > replaced;
251 QList<QPair<QString,QString> >::ConstIterator it=list.begin(); it += from+n;
252 for (; i<to-from; ++i,++it)
253 replaced.append(*it);
255 it=list.begin(); it += from;
256 for (; i<n; ++i,++it)
257 replaced.append(*it);
258 QList<QPair<QString,QString> >::ConstIterator f=replaced.begin();
259 QList<QPair<QString,QString> >::Iterator t=list.begin(); t += from;
260 for (; f != replaced.end(); ++f, ++t)
266 QList<QPair<QString,QString> > list;
270 tst_QQuickPathView::tst_QQuickPathView()
274 void tst_QQuickPathView::initValues()
276 QDeclarativeEngine engine;
277 QDeclarativeComponent c(&engine, testFileUrl("pathview1.qml"));
278 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
281 QVERIFY(obj->path() == 0);
282 QVERIFY(obj->delegate() == 0);
283 QCOMPARE(obj->model(), QVariant());
284 QCOMPARE(obj->currentIndex(), 0);
285 QCOMPARE(obj->offset(), 0.);
286 QCOMPARE(obj->preferredHighlightBegin(), 0.);
287 QCOMPARE(obj->dragMargin(), 0.);
288 QCOMPARE(obj->count(), 0);
289 QCOMPARE(obj->pathItemCount(), -1);
294 void tst_QQuickPathView::items()
296 QQuickView *canvas = createView();
299 model.addItem("Fred", "12345");
300 model.addItem("John", "2345");
301 model.addItem("Bob", "54321");
302 model.addItem("Bill", "4321");
304 QDeclarativeContext *ctxt = canvas->rootContext();
305 ctxt->setContextProperty("testModel", &model);
307 canvas->setSource(testFileUrl("pathview0.qml"));
308 qApp->processEvents();
310 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
311 QVERIFY(pathview != 0);
313 QCOMPARE(pathview->count(), model.count());
314 QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
315 QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
317 for (int i = 0; i < model.count(); ++i) {
318 QQuickText *name = findItem<QQuickText>(pathview, "textName", i);
320 QCOMPARE(name->text(), model.name(i));
321 QQuickText *number = findItem<QQuickText>(pathview, "textNumber", i);
322 QVERIFY(number != 0);
323 QCOMPARE(number->text(), model.number(i));
326 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
329 QVERIFY(pathview->highlightItem());
330 QPointF start = path->pointAt(0.0);
332 offset.setX(pathview->highlightItem()->width()/2);
333 offset.setY(pathview->highlightItem()->height()/2);
334 QCOMPARE(pathview->highlightItem()->pos() + offset, start);
339 void tst_QQuickPathView::pathview2()
341 QDeclarativeEngine engine;
342 QDeclarativeComponent c(&engine, testFileUrl("pathview2.qml"));
343 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
346 QVERIFY(obj->path() != 0);
347 QVERIFY(obj->delegate() != 0);
348 QVERIFY(obj->model() != QVariant());
349 QCOMPARE(obj->currentIndex(), 0);
350 QCOMPARE(obj->offset(), 0.);
351 QCOMPARE(obj->preferredHighlightBegin(), 0.);
352 QCOMPARE(obj->dragMargin(), 0.);
353 QCOMPARE(obj->count(), 8);
354 QCOMPARE(obj->pathItemCount(), 10);
359 void tst_QQuickPathView::pathview3()
361 QDeclarativeEngine engine;
362 QDeclarativeComponent c(&engine, testFileUrl("pathview3.qml"));
363 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
366 QVERIFY(obj->path() != 0);
367 QVERIFY(obj->delegate() != 0);
368 QVERIFY(obj->model() != QVariant());
369 QCOMPARE(obj->currentIndex(), 0);
370 QCOMPARE(obj->offset(), 1.0);
371 QCOMPARE(obj->preferredHighlightBegin(), 0.5);
372 QCOMPARE(obj->dragMargin(), 24.);
373 QCOMPARE(obj->count(), 8);
374 QCOMPARE(obj->pathItemCount(), 4);
379 void tst_QQuickPathView::insertModel_data()
381 QTest::addColumn<int>("mode");
382 QTest::addColumn<int>("idx");
383 QTest::addColumn<int>("count");
384 QTest::addColumn<qreal>("offset");
386 // We have 8 items, with currentIndex == 4
387 QTest::newRow("insert after current")
388 << int(QQuickPathView::StrictlyEnforceRange) << 6 << 1 << 5.;
389 QTest::newRow("insert before current")
390 << int(QQuickPathView::StrictlyEnforceRange) << 2 << 1 << 4.;
391 QTest::newRow("insert multiple after current")
392 << int(QQuickPathView::StrictlyEnforceRange) << 5 << 2 << 6.;
393 QTest::newRow("insert multiple before current")
394 << int(QQuickPathView::StrictlyEnforceRange) << 1 << 2 << 4.;
395 QTest::newRow("insert at end")
396 << int(QQuickPathView::StrictlyEnforceRange) << 8 << 1 << 5.;
397 QTest::newRow("insert at beginning")
398 << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 4.;
399 QTest::newRow("insert at current")
400 << int(QQuickPathView::StrictlyEnforceRange) << 4 << 1 << 4.;
402 QTest::newRow("no range - insert after current")
403 << int(QQuickPathView::NoHighlightRange) << 6 << 1 << 5.;
404 QTest::newRow("no range - insert before current")
405 << int(QQuickPathView::NoHighlightRange) << 2 << 1 << 4.;
406 QTest::newRow("no range - insert multiple after current")
407 << int(QQuickPathView::NoHighlightRange) << 5 << 2 << 6.;
408 QTest::newRow("no range - insert multiple before current")
409 << int(QQuickPathView::NoHighlightRange) << 1 << 2 << 4.;
410 QTest::newRow("no range - insert at end")
411 << int(QQuickPathView::NoHighlightRange) << 8 << 1 << 5.;
412 QTest::newRow("no range - insert at beginning")
413 << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 4.;
414 QTest::newRow("no range - insert at current")
415 << int(QQuickPathView::NoHighlightRange) << 4 << 1 << 4.;
418 void tst_QQuickPathView::insertModel()
423 QFETCH(qreal, offset);
425 QQuickView *canvas = createView();
429 model.addItem("Ben", "12345");
430 model.addItem("Bohn", "2345");
431 model.addItem("Bob", "54321");
432 model.addItem("Bill", "4321");
433 model.addItem("Jinny", "679");
434 model.addItem("Milly", "73378");
435 model.addItem("Jimmy", "3535");
436 model.addItem("Barb", "9039");
438 QDeclarativeContext *ctxt = canvas->rootContext();
439 ctxt->setContextProperty("testModel", &model);
441 canvas->setSource(testFileUrl("pathview0.qml"));
442 qApp->processEvents();
444 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
445 QVERIFY(pathview != 0);
447 pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
449 pathview->setCurrentIndex(4);
450 if (mode == QQuickPathView::StrictlyEnforceRange)
451 QTRY_COMPARE(pathview->offset(), 4.0);
453 pathview->setOffset(4);
455 QList<QPair<QString, QString> > items;
456 for (int i = 0; i < count; ++i)
457 items.append(qMakePair(QString("New"), QString::number(i)));
459 model.insertItems(idx, items);
460 QTRY_COMPARE(pathview->offset(), offset);
465 void tst_QQuickPathView::removeModel_data()
467 QTest::addColumn<int>("mode");
468 QTest::addColumn<int>("idx");
469 QTest::addColumn<int>("count");
470 QTest::addColumn<qreal>("offset");
472 // We have 8 items, with currentIndex == 4
473 QTest::newRow("remove after current")
474 << int(QQuickPathView::StrictlyEnforceRange) << 6 << 1 << 3.;
475 QTest::newRow("remove before current")
476 << int(QQuickPathView::StrictlyEnforceRange) << 2 << 1 << 4.;
477 QTest::newRow("remove multiple after current")
478 << int(QQuickPathView::StrictlyEnforceRange) << 5 << 2 << 2.;
479 QTest::newRow("remove multiple before current")
480 << int(QQuickPathView::StrictlyEnforceRange) << 1 << 2 << 4.;
481 QTest::newRow("remove last")
482 << int(QQuickPathView::StrictlyEnforceRange) << 7 << 1 << 3.;
483 QTest::newRow("remove first")
484 << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 4.;
485 QTest::newRow("remove current")
486 << int(QQuickPathView::StrictlyEnforceRange) << 4 << 1 << 3.;
488 QTest::newRow("no range - remove after current")
489 << int(QQuickPathView::NoHighlightRange) << 6 << 1 << 3.;
490 QTest::newRow("no range - remove before current")
491 << int(QQuickPathView::NoHighlightRange) << 2 << 1 << 4.;
492 QTest::newRow("no range - remove multiple after current")
493 << int(QQuickPathView::NoHighlightRange) << 5 << 2 << 2.;
494 QTest::newRow("no range - remove multiple before current")
495 << int(QQuickPathView::NoHighlightRange) << 1 << 2 << 4.;
496 QTest::newRow("no range - remove last")
497 << int(QQuickPathView::NoHighlightRange) << 7 << 1 << 3.;
498 QTest::newRow("no range - remove first")
499 << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 4.;
500 QTest::newRow("no range - remove current offset")
501 << int(QQuickPathView::NoHighlightRange) << 4 << 1 << 4.;
504 void tst_QQuickPathView::removeModel()
509 QFETCH(qreal, offset);
511 QQuickView *canvas = createView();
515 model.addItem("Ben", "12345");
516 model.addItem("Bohn", "2345");
517 model.addItem("Bob", "54321");
518 model.addItem("Bill", "4321");
519 model.addItem("Jinny", "679");
520 model.addItem("Milly", "73378");
521 model.addItem("Jimmy", "3535");
522 model.addItem("Barb", "9039");
524 QDeclarativeContext *ctxt = canvas->rootContext();
525 ctxt->setContextProperty("testModel", &model);
527 canvas->setSource(testFileUrl("pathview0.qml"));
528 qApp->processEvents();
530 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
531 QVERIFY(pathview != 0);
533 pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
535 pathview->setCurrentIndex(4);
536 if (mode == QQuickPathView::StrictlyEnforceRange)
537 QTRY_COMPARE(pathview->offset(), 4.0);
539 pathview->setOffset(4);
541 model.removeItems(idx, count);
542 QTRY_COMPARE(pathview->offset(), offset);
548 void tst_QQuickPathView::moveModel_data()
550 QTest::addColumn<int>("mode");
551 QTest::addColumn<int>("from");
552 QTest::addColumn<int>("to");
553 QTest::addColumn<int>("count");
554 QTest::addColumn<qreal>("offset");
556 // We have 8 items, with currentIndex == 4
557 QTest::newRow("move after current")
558 << int(QQuickPathView::StrictlyEnforceRange) << 5 << 6 << 1 << 4.;
559 QTest::newRow("move before current")
560 << int(QQuickPathView::StrictlyEnforceRange) << 2 << 3 << 1 << 4.;
561 QTest::newRow("move before current to after")
562 << int(QQuickPathView::StrictlyEnforceRange) << 2 << 6 << 1 << 5.;
563 QTest::newRow("move multiple after current")
564 << int(QQuickPathView::StrictlyEnforceRange) << 5 << 6 << 2 << 4.;
565 QTest::newRow("move multiple before current")
566 << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 2 << 4.;
567 QTest::newRow("move before current to end")
568 << int(QQuickPathView::StrictlyEnforceRange) << 2 << 7 << 1 << 5.;
569 QTest::newRow("move last to beginning")
570 << int(QQuickPathView::StrictlyEnforceRange) << 7 << 0 << 1 << 3.;
571 QTest::newRow("move current")
572 << int(QQuickPathView::StrictlyEnforceRange) << 4 << 6 << 1 << 2.;
574 QTest::newRow("no range - move after current")
575 << int(QQuickPathView::NoHighlightRange) << 5 << 6 << 1 << 4.;
576 QTest::newRow("no range - move before current")
577 << int(QQuickPathView::NoHighlightRange) << 2 << 3 << 1 << 4.;
578 QTest::newRow("no range - move before current to after")
579 << int(QQuickPathView::NoHighlightRange) << 2 << 6 << 1 << 5.;
580 QTest::newRow("no range - move multiple after current")
581 << int(QQuickPathView::NoHighlightRange) << 5 << 6 << 2 << 4.;
582 QTest::newRow("no range - move multiple before current")
583 << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 2 << 4.;
584 QTest::newRow("no range - move before current to end")
585 << int(QQuickPathView::NoHighlightRange) << 2 << 7 << 1 << 5.;
586 QTest::newRow("no range - move last to beginning")
587 << int(QQuickPathView::NoHighlightRange) << 7 << 0 << 1 << 3.;
588 QTest::newRow("no range - move current")
589 << int(QQuickPathView::NoHighlightRange) << 4 << 6 << 1 << 4.;
590 QTest::newRow("no range - move multiple incl. current")
591 << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 5 << 4.;
594 void tst_QQuickPathView::moveModel()
600 QFETCH(qreal, offset);
602 QQuickView *canvas = createView();
606 model.addItem("Ben", "12345");
607 model.addItem("Bohn", "2345");
608 model.addItem("Bob", "54321");
609 model.addItem("Bill", "4321");
610 model.addItem("Jinny", "679");
611 model.addItem("Milly", "73378");
612 model.addItem("Jimmy", "3535");
613 model.addItem("Barb", "9039");
615 QDeclarativeContext *ctxt = canvas->rootContext();
616 ctxt->setContextProperty("testModel", &model);
618 canvas->setSource(testFileUrl("pathview0.qml"));
619 qApp->processEvents();
621 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
622 QVERIFY(pathview != 0);
624 pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
626 pathview->setCurrentIndex(4);
627 if (mode == QQuickPathView::StrictlyEnforceRange)
628 QTRY_COMPARE(pathview->offset(), 4.0);
630 pathview->setOffset(4);
632 model.moveItems(from, to, count);
633 QTRY_COMPARE(pathview->offset(), offset);
638 void tst_QQuickPathView::path()
640 QDeclarativeEngine engine;
641 QDeclarativeComponent c(&engine, testFileUrl("pathtest.qml"));
642 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
645 QCOMPARE(obj->startX(), 120.);
646 QCOMPARE(obj->startY(), 100.);
647 QVERIFY(obj->path() != QPainterPath());
649 QDeclarativeListReference list(obj, "pathElements");
650 QCOMPARE(list.count(), 5);
652 QDeclarativePathAttribute* attr = qobject_cast<QDeclarativePathAttribute*>(list.at(0));
654 QCOMPARE(attr->name(), QString("scale"));
655 QCOMPARE(attr->value(), 1.0);
657 QDeclarativePathQuad* quad = qobject_cast<QDeclarativePathQuad*>(list.at(1));
659 QCOMPARE(quad->x(), 120.);
660 QCOMPARE(quad->y(), 25.);
661 QCOMPARE(quad->controlX(), 260.);
662 QCOMPARE(quad->controlY(), 75.);
664 QDeclarativePathPercent* perc = qobject_cast<QDeclarativePathPercent*>(list.at(2));
666 QCOMPARE(perc->value(), 0.3);
668 QDeclarativePathLine* line = qobject_cast<QDeclarativePathLine*>(list.at(3));
670 QCOMPARE(line->x(), 120.);
671 QCOMPARE(line->y(), 100.);
673 QDeclarativePathCubic* cubic = qobject_cast<QDeclarativePathCubic*>(list.at(4));
675 QCOMPARE(cubic->x(), 180.);
676 QCOMPARE(cubic->y(), 0.);
677 QCOMPARE(cubic->control1X(), -10.);
678 QCOMPARE(cubic->control1Y(), 90.);
679 QCOMPARE(cubic->control2X(), 210.);
680 QCOMPARE(cubic->control2Y(), 90.);
685 void tst_QQuickPathView::dataModel()
687 QQuickView *canvas = createView();
690 QDeclarativeContext *ctxt = canvas->rootContext();
691 TestObject *testObject = new TestObject;
692 ctxt->setContextProperty("testObject", testObject);
695 model.addItem("red", "1");
696 model.addItem("green", "2");
697 model.addItem("blue", "3");
698 model.addItem("purple", "4");
699 model.addItem("gray", "5");
700 model.addItem("brown", "6");
701 model.addItem("yellow", "7");
702 model.addItem("thistle", "8");
703 model.addItem("cyan", "9");
704 model.addItem("peachpuff", "10");
705 model.addItem("powderblue", "11");
706 model.addItem("gold", "12");
707 model.addItem("sandybrown", "13");
709 ctxt->setContextProperty("testData", &model);
711 canvas->setSource(testFileUrl("datamodel.qml"));
712 qApp->processEvents();
714 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
715 QVERIFY(pathview != 0);
717 QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
718 QVERIFY(testObject->error() == false);
720 QQuickItem *item = findItem<QQuickItem>(pathview, "wrapper", 0);
722 QCOMPARE(item->x(), 110.0);
723 QCOMPARE(item->y(), 10.0);
725 model.insertItem(4, "orange", "10");
728 QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
729 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 14);
731 QVERIFY(pathview->currentIndex() == 0);
732 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
734 QQuickText *text = findItem<QQuickText>(pathview, "myText", 4);
736 QCOMPARE(text->text(), model.name(4));
739 QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
740 text = findItem<QQuickText>(pathview, "myText", 2);
742 QCOMPARE(text->text(), model.name(2));
743 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
745 testObject->setPathItemCount(5);
746 QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
747 QVERIFY(testObject->error() == false);
749 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
751 QQuickRectangle *testItem = findItem<QQuickRectangle>(pathview, "wrapper", 4);
752 QVERIFY(testItem != 0);
753 testItem = findItem<QQuickRectangle>(pathview, "wrapper", 5);
754 QVERIFY(testItem == 0);
756 pathview->setCurrentIndex(1);
757 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
760 model.insertItem(2, "pink", "2");
763 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
764 QVERIFY(pathview->currentIndex() == 1);
765 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
767 text = findItem<QQuickText>(pathview, "myText", 2);
769 QCOMPARE(text->text(), model.name(2));
772 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
773 text = findItem<QQuickText>(pathview, "myText", 3);
775 QCOMPARE(text->text(), model.name(3));
776 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
778 model.moveItem(3, 5);
779 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
780 QList<QQuickItem*> items = findItems<QQuickItem>(pathview, "wrapper");
781 foreach (QQuickItem *item, items) {
782 QVERIFY(item->property("onPath").toBool());
784 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
787 pathview->setOffset(7);
788 pathview->setOffset(0);
789 QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
791 pathview->setCurrentIndex(model.count()-1);
792 model.removeItem(model.count()-1);
793 QCOMPARE(pathview->currentIndex(), model.count()-1);
799 void tst_QQuickPathView::pathMoved()
801 QQuickView *canvas = createView();
805 model.addItem("Ben", "12345");
806 model.addItem("Bohn", "2345");
807 model.addItem("Bob", "54321");
808 model.addItem("Bill", "4321");
810 QDeclarativeContext *ctxt = canvas->rootContext();
811 ctxt->setContextProperty("testModel", &model);
813 canvas->setSource(testFileUrl("pathview0.qml"));
814 qApp->processEvents();
816 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
817 QVERIFY(pathview != 0);
819 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
821 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
823 QPointF start = path->pointAt(0.0);
824 QPointF offset;//Center of item is at point, but pos is from corner
825 offset.setX(firstItem->width()/2);
826 offset.setY(firstItem->height()/2);
827 QTRY_COMPARE(firstItem->pos() + offset, start);
828 pathview->setOffset(1.0);
830 for (int i=0; i<model.count(); i++) {
831 QQuickRectangle *curItem = findItem<QQuickRectangle>(pathview, "wrapper", i);
832 QPointF itemPos(path->pointAt(0.25 + i*0.25));
833 QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
836 pathview->setOffset(0.0);
837 QCOMPARE(firstItem->pos() + offset, start);
839 // Change delegate size
840 pathview->setOffset(0.1);
841 pathview->setOffset(0.0);
842 canvas->rootObject()->setProperty("delegateWidth", 30);
843 QCOMPARE(firstItem->width(), 30.0);
844 offset.setX(firstItem->width()/2);
845 QTRY_COMPARE(firstItem->pos() + offset, start);
847 // Change delegate scale
848 pathview->setOffset(0.1);
849 pathview->setOffset(0.0);
850 canvas->rootObject()->setProperty("delegateScale", 1.2);
851 QTRY_COMPARE(firstItem->pos() + offset, start);
856 void tst_QQuickPathView::setCurrentIndex()
858 QQuickView *canvas = createView();
862 model.addItem("Ben", "12345");
863 model.addItem("Bohn", "2345");
864 model.addItem("Bob", "54321");
865 model.addItem("Bill", "4321");
867 QDeclarativeContext *ctxt = canvas->rootContext();
868 ctxt->setContextProperty("testModel", &model);
870 canvas->setSource(testFileUrl("pathview0.qml"));
871 qApp->processEvents();
873 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
874 QVERIFY(pathview != 0);
876 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
878 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
880 QPointF start = path->pointAt(0.0);
881 QPointF offset;//Center of item is at point, but pos is from corner
882 offset.setX(firstItem->width()/2);
883 offset.setY(firstItem->height()/2);
884 QCOMPARE(firstItem->pos() + offset, start);
885 QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
886 QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
888 pathview->setCurrentIndex(2);
890 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
891 QTRY_COMPARE(firstItem->pos() + offset, start);
892 QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
893 QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
894 QCOMPARE(pathview->currentItem(), firstItem);
895 QCOMPARE(firstItem->property("onPath"), QVariant(true));
897 pathview->decrementCurrentIndex();
898 QTRY_COMPARE(pathview->currentIndex(), 1);
899 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
901 QTRY_COMPARE(firstItem->pos() + offset, start);
902 QCOMPARE(pathview->currentItem(), firstItem);
903 QCOMPARE(firstItem->property("onPath"), QVariant(true));
905 pathview->decrementCurrentIndex();
906 QTRY_COMPARE(pathview->currentIndex(), 0);
907 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
909 QTRY_COMPARE(firstItem->pos() + offset, start);
910 QCOMPARE(pathview->currentItem(), firstItem);
911 QCOMPARE(firstItem->property("onPath"), QVariant(true));
913 pathview->decrementCurrentIndex();
914 QTRY_COMPARE(pathview->currentIndex(), 3);
915 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
917 QTRY_COMPARE(firstItem->pos() + offset, start);
918 QCOMPARE(pathview->currentItem(), firstItem);
919 QCOMPARE(firstItem->property("onPath"), QVariant(true));
921 pathview->incrementCurrentIndex();
922 QTRY_COMPARE(pathview->currentIndex(), 0);
923 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
925 QTRY_COMPARE(firstItem->pos() + offset, start);
926 QCOMPARE(pathview->currentItem(), firstItem);
927 QCOMPARE(firstItem->property("onPath"), QVariant(true));
929 // move an item, set move duration to 0, and change currentIndex to moved item. QTBUG-22786
930 model.moveItem(0, 3);
931 pathview->setHighlightMoveDuration(0);
932 pathview->setCurrentIndex(3);
933 QCOMPARE(pathview->currentIndex(), 3);
934 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
936 QCOMPARE(pathview->currentItem(), firstItem);
937 QTRY_COMPARE(firstItem->pos() + offset, start);
938 model.moveItem(3, 0);
939 pathview->setCurrentIndex(0);
940 pathview->setHighlightMoveDuration(300);
942 // Check the current item is still created when outside the bounds of pathItemCount.
943 pathview->setPathItemCount(2);
944 pathview->setHighlightRangeMode(QQuickPathView::NoHighlightRange);
945 QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 0));
946 QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 1));
947 QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 2));
948 QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 3));
950 pathview->setCurrentIndex(2);
951 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
952 QCOMPARE(pathview->currentItem(), firstItem);
953 QCOMPARE(firstItem->property("onPath"), QVariant(false));
955 pathview->decrementCurrentIndex();
956 QTRY_COMPARE(pathview->currentIndex(), 1);
957 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
959 QCOMPARE(pathview->currentItem(), firstItem);
960 QCOMPARE(firstItem->property("onPath"), QVariant(true));
962 pathview->decrementCurrentIndex();
963 QTRY_COMPARE(pathview->currentIndex(), 0);
964 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
966 QCOMPARE(pathview->currentItem(), firstItem);
967 QCOMPARE(firstItem->property("onPath"), QVariant(true));
969 pathview->decrementCurrentIndex();
970 QTRY_COMPARE(pathview->currentIndex(), 3);
971 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
973 QCOMPARE(pathview->currentItem(), firstItem);
974 QCOMPARE(firstItem->property("onPath"), QVariant(false));
976 pathview->incrementCurrentIndex();
977 QTRY_COMPARE(pathview->currentIndex(), 0);
978 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
980 QCOMPARE(pathview->currentItem(), firstItem);
981 QCOMPARE(firstItem->property("onPath"), QVariant(true));
986 void tst_QQuickPathView::resetModel()
988 QQuickView *canvas = createView();
991 strings << "one" << "two" << "three";
992 QStringListModel model(strings);
994 QDeclarativeContext *ctxt = canvas->rootContext();
995 ctxt->setContextProperty("testModel", &model);
997 canvas->setSource(testFileUrl("displaypath.qml"));
998 qApp->processEvents();
1000 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
1001 QVERIFY(pathview != 0);
1003 QCOMPARE(pathview->count(), model.rowCount());
1005 for (int i = 0; i < model.rowCount(); ++i) {
1006 QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
1007 QVERIFY(display != 0);
1008 QCOMPARE(display->text(), strings.at(i));
1012 strings << "four" << "five" << "six" << "seven";
1013 model.setStringList(strings);
1015 QCOMPARE(pathview->count(), model.rowCount());
1017 for (int i = 0; i < model.rowCount(); ++i) {
1018 QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
1019 QVERIFY(display != 0);
1020 QCOMPARE(display->text(), strings.at(i));
1026 void tst_QQuickPathView::propertyChanges()
1028 QQuickView *canvas = createView();
1030 canvas->setSource(testFileUrl("propertychanges.qml"));
1032 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1035 QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
1036 QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
1038 QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
1039 QCOMPARE(pathView->dragMargin(), 5.0);
1041 pathView->setPreferredHighlightBegin(0.4);
1042 pathView->setPreferredHighlightEnd(0.4);
1043 pathView->setDragMargin(20.0);
1045 QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
1046 QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
1047 QCOMPARE(pathView->dragMargin(), 20.0);
1049 QCOMPARE(snapPositionSpy.count(), 1);
1050 QCOMPARE(dragMarginSpy.count(), 1);
1052 pathView->setPreferredHighlightBegin(0.4);
1053 pathView->setPreferredHighlightEnd(0.4);
1054 pathView->setDragMargin(20.0);
1056 QCOMPARE(snapPositionSpy.count(), 1);
1057 QCOMPARE(dragMarginSpy.count(), 1);
1061 void tst_QQuickPathView::pathChanges()
1063 QQuickView *canvas = createView();
1065 canvas->setSource(testFileUrl("propertychanges.qml"));
1067 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1070 QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
1073 QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
1074 QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
1076 QCOMPARE(path->startX(), 220.0);
1077 QCOMPARE(path->startY(), 200.0);
1079 path->setStartX(240.0);
1080 path->setStartY(220.0);
1082 QCOMPARE(path->startX(), 240.0);
1083 QCOMPARE(path->startY(), 220.0);
1085 QCOMPARE(startXSpy.count(),1);
1086 QCOMPARE(startYSpy.count(),1);
1088 path->setStartX(240);
1089 path->setStartY(220);
1091 QCOMPARE(startXSpy.count(),1);
1092 QCOMPARE(startYSpy.count(),1);
1094 QDeclarativePath *alternatePath = canvas->rootObject()->findChild<QDeclarativePath*>("alternatePath");
1095 QVERIFY(alternatePath);
1097 QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
1099 QCOMPARE(pathView->path(), path);
1101 pathView->setPath(alternatePath);
1102 QCOMPARE(pathView->path(), alternatePath);
1103 QCOMPARE(pathSpy.count(),1);
1105 pathView->setPath(alternatePath);
1106 QCOMPARE(pathSpy.count(),1);
1108 QDeclarativePathAttribute *pathAttribute = canvas->rootObject()->findChild<QDeclarativePathAttribute*>("pathAttribute");
1109 QVERIFY(pathAttribute);
1111 QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
1112 QCOMPARE(pathAttribute->name(), QString("opacity"));
1114 pathAttribute->setName("scale");
1115 QCOMPARE(pathAttribute->name(), QString("scale"));
1116 QCOMPARE(nameSpy.count(),1);
1118 pathAttribute->setName("scale");
1119 QCOMPARE(nameSpy.count(),1);
1123 void tst_QQuickPathView::componentChanges()
1125 QQuickView *canvas = createView();
1127 canvas->setSource(testFileUrl("propertychanges.qml"));
1129 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1132 QDeclarativeComponent delegateComponent(canvas->engine());
1133 delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1135 QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
1137 pathView->setDelegate(&delegateComponent);
1138 QCOMPARE(pathView->delegate(), &delegateComponent);
1139 QCOMPARE(delegateSpy.count(),1);
1141 pathView->setDelegate(&delegateComponent);
1142 QCOMPARE(delegateSpy.count(),1);
1146 void tst_QQuickPathView::modelChanges()
1148 QQuickView *canvas = createView();
1150 canvas->setSource(testFileUrl("propertychanges.qml"));
1152 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1155 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
1156 QVERIFY(alternateModel);
1157 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1158 QSignalSpy modelSpy(pathView, SIGNAL(modelChanged()));
1160 pathView->setModel(modelVariant);
1161 QCOMPARE(pathView->model(), modelVariant);
1162 QCOMPARE(modelSpy.count(),1);
1164 pathView->setModel(modelVariant);
1165 QCOMPARE(modelSpy.count(),1);
1167 pathView->setModel(QVariant());
1168 QCOMPARE(modelSpy.count(),2);
1173 void tst_QQuickPathView::pathUpdateOnStartChanged()
1175 QQuickView *canvas = createView();
1177 canvas->setSource(testFileUrl("pathUpdateOnStartChanged.qml"));
1179 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1182 QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
1184 QCOMPARE(path->startX(), 400.0);
1185 QCOMPARE(path->startY(), 300.0);
1187 QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
1189 QCOMPARE(item->x(), path->startX() - item->width() / 2.0);
1190 QCOMPARE(item->y(), path->startY() - item->height() / 2.0);
1195 void tst_QQuickPathView::package()
1197 QQuickView *canvas = createView();
1199 canvas->setSource(testFileUrl("pathview_package.qml"));
1201 QTest::qWaitForWindowShown(canvas);
1203 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("photoPathView");
1206 QQuickItem *item = findItem<QQuickItem>(pathView, "pathItem");
1208 QVERIFY(item->scale() != 1.0);
1214 void tst_QQuickPathView::emptyModel()
1216 QQuickView *canvas = createView();
1218 QStringListModel model;
1220 QDeclarativeContext *ctxt = canvas->rootContext();
1221 ctxt->setContextProperty("emptyModel", &model);
1223 canvas->setSource(testFileUrl("emptymodel.qml"));
1224 qApp->processEvents();
1226 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1227 QVERIFY(pathview != 0);
1229 QCOMPARE(pathview->offset(), qreal(0.0));
1234 void tst_QQuickPathView::closed()
1236 QDeclarativeEngine engine;
1239 QDeclarativeComponent c(&engine, testFileUrl("openPath.qml"));
1240 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
1242 QCOMPARE(obj->isClosed(), false);
1247 QDeclarativeComponent c(&engine, testFileUrl("closedPath.qml"));
1248 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
1250 QCOMPARE(obj->isClosed(), true);
1256 void tst_QQuickPathView::pathUpdate()
1258 QQuickView *canvas = createView();
1260 canvas->setSource(testFileUrl("pathUpdate.qml"));
1262 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1265 QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
1267 QCOMPARE(item->x(), 150.0);
1272 void tst_QQuickPathView::visualDataModel()
1274 QDeclarativeEngine engine;
1275 QDeclarativeComponent c(&engine, testFileUrl("vdm.qml"));
1277 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
1280 QCOMPARE(obj->count(), 3);
1285 void tst_QQuickPathView::undefinedPath()
1287 QDeclarativeEngine engine;
1289 QString warning1("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
1290 QTest::ignoreMessage(QtWarningMsg,qPrintable(warning1));
1292 QString warning2("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
1293 QTest::ignoreMessage(QtWarningMsg,qPrintable(warning2));
1295 QDeclarativeComponent c(&engine, testFileUrl("undefinedpath.qml"));
1297 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
1300 QCOMPARE(obj->count(), 3);
1305 void tst_QQuickPathView::mouseDrag()
1307 QQuickView *canvas = createView();
1308 canvas->setSource(testFileUrl("dragpath.qml"));
1310 canvas->requestActivateWindow();
1311 QTest::qWaitForWindowShown(canvas);
1312 QTRY_COMPARE(canvas, qGuiApp->focusWindow());
1314 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1315 QVERIFY(pathview != 0);
1317 int current = pathview->currentIndex();
1319 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10,100));
1323 QMouseEvent mv(QEvent::MouseMove, QPoint(30,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1324 QApplication::sendEvent(canvas, &mv);
1327 QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1328 QApplication::sendEvent(canvas, &mv);
1331 QVERIFY(pathview->currentIndex() != current);
1333 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(40,100));
1338 void tst_QQuickPathView::treeModel()
1340 QQuickView *canvas = createView();
1343 QStandardItemModel model;
1344 initStandardTreeModel(&model);
1345 canvas->engine()->rootContext()->setContextProperty("myModel", &model);
1347 canvas->setSource(testFileUrl("treemodel.qml"));
1349 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1350 QVERIFY(pathview != 0);
1351 QCOMPARE(pathview->count(), 3);
1353 QQuickText *item = findItem<QQuickText>(pathview, "wrapper", 0);
1355 QCOMPARE(item->text(), QLatin1String("Row 1 Item"));
1357 QVERIFY(QMetaObject::invokeMethod(pathview, "setRoot", Q_ARG(QVariant, 1)));
1358 QCOMPARE(pathview->count(), 1);
1360 QTRY_VERIFY(item = findItem<QQuickText>(pathview, "wrapper", 0));
1361 QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
1366 void tst_QQuickPathView::changePreferredHighlight()
1368 QQuickView *canvas = createView();
1369 canvas->setGeometry(0,0,400,200);
1370 canvas->setSource(testFileUrl("dragpath.qml"));
1372 canvas->requestActivateWindow();
1373 QTest::qWaitForWindowShown(canvas);
1374 QTRY_COMPARE(canvas, qGuiApp->focusWindow());
1376 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1377 QVERIFY(pathview != 0);
1379 int current = pathview->currentIndex();
1380 QCOMPARE(current, 0);
1382 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
1384 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
1386 QPointF start = path->pointAt(0.5);
1387 start.setX(qRound(start.x()));
1388 start.setY(qRound(start.y()));
1389 QPointF offset;//Center of item is at point, but pos is from corner
1390 offset.setX(firstItem->width()/2);
1391 offset.setY(firstItem->height()/2);
1392 QTRY_COMPARE(firstItem->pos() + offset, start);
1394 pathview->setPreferredHighlightBegin(0.8);
1395 pathview->setPreferredHighlightEnd(0.8);
1396 start = path->pointAt(0.8);
1397 start.setX(qRound(start.x()));
1398 start.setY(qRound(start.y()));
1399 QTRY_COMPARE(firstItem->pos() + offset, start);
1400 QCOMPARE(pathview->currentIndex(), 0);
1405 void tst_QQuickPathView::creationContext()
1408 canvas.setGeometry(0,0,240,320);
1409 canvas.setSource(testFileUrl("creationContext.qml"));
1411 QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
1413 QVERIFY(rootItem->property("count").toInt() > 0);
1416 QVERIFY(item = findItem<QQuickItem>(rootItem, "listItem", 0));
1417 QCOMPARE(item->property("text").toString(), QString("Hello!"));
1421 void tst_QQuickPathView::currentOffsetOnInsertion()
1423 QQuickView *canvas = createView();
1428 QDeclarativeContext *ctxt = canvas->rootContext();
1429 ctxt->setContextProperty("testModel", &model);
1431 canvas->setSource(testFileUrl("pathline.qml"));
1432 qApp->processEvents();
1434 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
1435 QVERIFY(pathview != 0);
1437 pathview->setPreferredHighlightBegin(0.5);
1438 pathview->setPreferredHighlightEnd(0.5);
1440 QCOMPARE(pathview->count(), model.count());
1442 model.addItem("item0", "0");
1444 QCOMPARE(pathview->count(), model.count());
1446 QQuickRectangle *item = 0;
1447 QTRY_VERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 0));
1449 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
1452 QPointF start = path->pointAt(0.5);
1453 start = QPointF(qRound(start.x()), qRound(start.y()));
1454 QPointF offset;//Center of item is at point, but pos is from corner
1455 offset.setX(item->width()/2);
1456 offset.setY(item->height()/2);
1457 QCOMPARE(item->pos() + offset, start);
1459 QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged()));
1461 // insert an item at the beginning
1462 model.insertItem(0, "item1", "1");
1463 qApp->processEvents();
1465 QCOMPARE(currentIndexSpy.count(), 1);
1467 // currentIndex is now 1
1468 QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1));
1470 // verify that current item (item 1) is still at offset 0.5
1471 QCOMPARE(item->pos() + offset, start);
1473 // insert another item at the beginning
1474 model.insertItem(0, "item2", "2");
1475 qApp->processEvents();
1477 QCOMPARE(currentIndexSpy.count(), 2);
1479 // currentIndex is now 2
1480 QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 2));
1482 // verify that current item (item 2) is still at offset 0.5
1483 QCOMPARE(item->pos() + offset, start);
1485 // verify that remove before current maintains current item
1486 model.removeItem(0);
1487 qApp->processEvents();
1489 QCOMPARE(currentIndexSpy.count(), 3);
1491 // currentIndex is now 1
1492 QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1));
1494 // verify that current item (item 1) is still at offset 0.5
1495 QCOMPARE(item->pos() + offset, start);
1500 void tst_QQuickPathView::asynchronous()
1502 QQuickView *canvas = createView();
1504 QDeclarativeIncubationController controller;
1505 canvas->engine()->setIncubationController(&controller);
1507 canvas->setSource(testFileUrl("asyncloader.qml"));
1509 QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
1510 QVERIFY(rootObject);
1512 QQuickPathView *pathview = 0;
1515 controller.incubateWhile(&b);
1516 pathview = rootObject->findChild<QQuickPathView*>("view");
1519 // items will be created one at a time
1520 for (int i = 0; i < 5; ++i) {
1521 QVERIFY(findItem<QQuickItem>(pathview, "wrapper", i) == 0);
1522 QQuickItem *item = 0;
1525 controller.incubateWhile(&b);
1526 item = findItem<QQuickItem>(pathview, "wrapper", i);
1532 controller.incubateWhile(&b);
1535 // verify positioning
1536 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
1538 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
1540 QPointF start = path->pointAt(0.0);
1541 QPointF offset;//Center of item is at point, but pos is from corner
1542 offset.setX(firstItem->width()/2);
1543 offset.setY(firstItem->height()/2);
1544 QTRY_COMPARE(firstItem->pos() + offset, start);
1545 pathview->setOffset(1.0);
1547 for (int i=0; i<5; i++) {
1548 QQuickItem *curItem = findItem<QQuickItem>(pathview, "wrapper", i);
1549 QPointF itemPos(path->pointAt(0.2 + i*0.2));
1550 QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
1556 QQuickView *tst_QQuickPathView::createView()
1558 QQuickView *canvas = new QQuickView(0);
1559 canvas->setGeometry(0,0,240,320);
1565 Find an item with the specified objectName. If index is supplied then the
1566 item must also evaluate the {index} expression equal to index
1568 template<typename T>
1569 T *tst_QQuickPathView::findItem(QQuickItem *parent, const QString &objectName, int index)
1571 const QMetaObject &mo = T::staticMetaObject;
1572 //qDebug() << parent->childItems().count() << "children";
1573 for (int i = 0; i < parent->childItems().count(); ++i) {
1574 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
1577 //qDebug() << "try" << item;
1578 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
1580 QDeclarativeExpression e(qmlContext(item), item, "index");
1581 if (e.evaluate().toInt() == index)
1582 return static_cast<T*>(item);
1584 return static_cast<T*>(item);
1587 item = findItem<T>(item, objectName, index);
1589 return static_cast<T*>(item);
1595 template<typename T>
1596 QList<T*> tst_QQuickPathView::findItems(QQuickItem *parent, const QString &objectName)
1599 const QMetaObject &mo = T::staticMetaObject;
1600 //qDebug() << parent->QQuickItem::children().count() << "children";
1601 for (int i = 0; i < parent->childItems().count(); ++i) {
1602 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
1605 //qDebug() << "try" << item;
1606 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
1607 items.append(static_cast<T*>(item));
1608 items += findItems<T>(item, objectName);
1614 void tst_QQuickPathView::missingPercent()
1616 QDeclarativeEngine engine;
1617 QDeclarativeComponent c(&engine, testFileUrl("missingPercent.qml"));
1618 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
1620 QCOMPARE(obj->attributeAt("_qfx_percent", 1.0), qreal(1.0));
1625 QTEST_MAIN(tst_QQuickPathView)
1627 #include "tst_qquickpathview.moc"