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 <QtDeclarative/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/private/qquickpathview_p.h>
49 #include <QtDeclarative/private/qdeclarativepath_p.h>
50 #include <QtDeclarative/private/qquicktext_p.h>
51 #include <QtDeclarative/private/qquickrectangle_p.h>
52 #include <QtDeclarative/private/qdeclarativelistmodel_p.h>
53 #include <QtDeclarative/private/qdeclarativevaluetype_p.h>
54 #include <QAbstractListModel>
55 #include <QStringListModel>
56 #include <QStandardItemModel>
59 #include "../shared/util.h"
61 static void initStandardTreeModel(QStandardItemModel *model)
64 item = new QStandardItem(QLatin1String("Row 1 Item"));
65 model->insertRow(0, item);
67 item = new QStandardItem(QLatin1String("Row 2 Item"));
68 item->setCheckable(true);
69 model->insertRow(1, item);
71 QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
72 item->setChild(0, childItem);
74 item = new QStandardItem(QLatin1String("Row 3 Item"));
75 item->setIcon(QIcon());
76 model->insertRow(2, item);
80 class tst_QQuickPathView : public QObject
88 void cleanupTestCase();
96 void setCurrentIndex();
98 void propertyChanges();
100 void componentChanges();
102 void pathUpdateOnStartChanged();
107 void visualDataModel();
108 void undefinedPath();
111 void changePreferredHighlight();
112 void missingPercent();
113 void creationContext();
116 QQuickView *createView();
118 T *findItem(QQuickItem *parent, const QString &objectName, int index=-1);
120 QList<T*> findItems(QQuickItem *parent, const QString &objectName);
123 void tst_QQuickPathView::initTestCase()
127 void tst_QQuickPathView::cleanupTestCase()
132 class TestObject : public QObject
136 Q_PROPERTY(bool error READ error WRITE setError)
137 Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
138 Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
141 TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
143 bool error() const { return mError; }
144 void setError(bool err) { mError = err; }
146 bool useModel() const { return mUseModel; }
147 void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
149 int pathItemCount() const { return mPathItemCount; }
150 void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
153 void useModelChanged();
154 void pathItemCountChanged();
162 class TestModel : public QAbstractListModel
165 enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
167 TestModel(QObject *parent=0) : QAbstractListModel(parent) {
168 QHash<int, QByteArray> roles;
169 roles[Name] = "name";
170 roles[Number] = "number";
174 int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
175 QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
178 rv = list.at(index.row()).first;
179 else if (role == Number)
180 rv = list.at(index.row()).second;
185 int count() const { return rowCount(); }
186 QString name(int index) const { return list.at(index).first; }
187 QString number(int index) const { return list.at(index).second; }
189 void addItem(const QString &name, const QString &number) {
190 beginInsertRows(QModelIndex(), list.count(), list.count());
191 list.append(QPair<QString,QString>(name, number));
195 void insertItem(int index, const QString &name, const QString &number) {
196 beginInsertRows(QModelIndex(), index, index);
197 list.insert(index, QPair<QString,QString>(name, number));
201 void removeItem(int index) {
202 beginRemoveRows(QModelIndex(), index, index);
203 list.removeAt(index);
207 void moveItem(int from, int to) {
208 beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
213 void modifyItem(int idx, const QString &name, const QString &number) {
214 list[idx] = QPair<QString,QString>(name, number);
215 emit dataChanged(index(idx,0), index(idx,0));
219 QList<QPair<QString,QString> > list;
223 tst_QQuickPathView::tst_QQuickPathView()
227 void tst_QQuickPathView::initValues()
229 QDeclarativeEngine engine;
230 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathview1.qml")));
231 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
234 QVERIFY(obj->path() == 0);
235 QVERIFY(obj->delegate() == 0);
236 QCOMPARE(obj->model(), QVariant());
237 QCOMPARE(obj->currentIndex(), 0);
238 QCOMPARE(obj->offset(), 0.);
239 QCOMPARE(obj->preferredHighlightBegin(), 0.);
240 QCOMPARE(obj->dragMargin(), 0.);
241 QCOMPARE(obj->count(), 0);
242 QCOMPARE(obj->pathItemCount(), -1);
245 void tst_QQuickPathView::items()
247 QQuickView *canvas = createView();
250 model.addItem("Fred", "12345");
251 model.addItem("John", "2345");
252 model.addItem("Bob", "54321");
253 model.addItem("Bill", "4321");
255 QDeclarativeContext *ctxt = canvas->rootContext();
256 ctxt->setContextProperty("testModel", &model);
258 canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
259 qApp->processEvents();
261 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
262 QVERIFY(pathview != 0);
264 QCOMPARE(pathview->count(), model.count());
265 QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
266 QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
268 for (int i = 0; i < model.count(); ++i) {
269 QQuickText *name = findItem<QQuickText>(pathview, "textName", i);
271 QCOMPARE(name->text(), model.name(i));
272 QQuickText *number = findItem<QQuickText>(pathview, "textNumber", i);
273 QVERIFY(number != 0);
274 QCOMPARE(number->text(), model.number(i));
277 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
280 QVERIFY(pathview->highlightItem());
281 QPointF start = path->pointAt(0.0);
283 offset.setX(pathview->highlightItem()->width()/2);
284 offset.setY(pathview->highlightItem()->height()/2);
285 QCOMPARE(pathview->highlightItem()->pos() + offset, start);
290 void tst_QQuickPathView::pathview2()
292 QDeclarativeEngine engine;
293 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathview2.qml")));
294 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
297 QVERIFY(obj->path() != 0);
298 QVERIFY(obj->delegate() != 0);
299 QVERIFY(obj->model() != QVariant());
300 QCOMPARE(obj->currentIndex(), 0);
301 QCOMPARE(obj->offset(), 0.);
302 QCOMPARE(obj->preferredHighlightBegin(), 0.);
303 QCOMPARE(obj->dragMargin(), 0.);
304 QCOMPARE(obj->count(), 8);
305 QCOMPARE(obj->pathItemCount(), 10);
308 void tst_QQuickPathView::pathview3()
310 QDeclarativeEngine engine;
311 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathview3.qml")));
312 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
315 QVERIFY(obj->path() != 0);
316 QVERIFY(obj->delegate() != 0);
317 QVERIFY(obj->model() != QVariant());
318 QCOMPARE(obj->currentIndex(), 0);
319 QCOMPARE(obj->offset(), 1.0);
320 QCOMPARE(obj->preferredHighlightBegin(), 0.5);
321 QCOMPARE(obj->dragMargin(), 24.);
322 QCOMPARE(obj->count(), 8);
323 QCOMPARE(obj->pathItemCount(), 4);
326 void tst_QQuickPathView::path()
328 QDeclarativeEngine engine;
329 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathtest.qml")));
330 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
333 QCOMPARE(obj->startX(), 120.);
334 QCOMPARE(obj->startY(), 100.);
335 QVERIFY(obj->path() != QPainterPath());
337 QDeclarativeListReference list(obj, "pathElements");
338 QCOMPARE(list.count(), 5);
340 QDeclarativePathAttribute* attr = qobject_cast<QDeclarativePathAttribute*>(list.at(0));
342 QCOMPARE(attr->name(), QString("scale"));
343 QCOMPARE(attr->value(), 1.0);
345 QDeclarativePathQuad* quad = qobject_cast<QDeclarativePathQuad*>(list.at(1));
347 QCOMPARE(quad->x(), 120.);
348 QCOMPARE(quad->y(), 25.);
349 QCOMPARE(quad->controlX(), 260.);
350 QCOMPARE(quad->controlY(), 75.);
352 QDeclarativePathPercent* perc = qobject_cast<QDeclarativePathPercent*>(list.at(2));
354 QCOMPARE(perc->value(), 0.3);
356 QDeclarativePathLine* line = qobject_cast<QDeclarativePathLine*>(list.at(3));
358 QCOMPARE(line->x(), 120.);
359 QCOMPARE(line->y(), 100.);
361 QDeclarativePathCubic* cubic = qobject_cast<QDeclarativePathCubic*>(list.at(4));
363 QCOMPARE(cubic->x(), 180.);
364 QCOMPARE(cubic->y(), 0.);
365 QCOMPARE(cubic->control1X(), -10.);
366 QCOMPARE(cubic->control1Y(), 90.);
367 QCOMPARE(cubic->control2X(), 210.);
368 QCOMPARE(cubic->control2Y(), 90.);
371 void tst_QQuickPathView::dataModel()
373 QQuickView *canvas = createView();
376 QDeclarativeContext *ctxt = canvas->rootContext();
377 TestObject *testObject = new TestObject;
378 ctxt->setContextProperty("testObject", testObject);
381 model.addItem("red", "1");
382 model.addItem("green", "2");
383 model.addItem("blue", "3");
384 model.addItem("purple", "4");
385 model.addItem("gray", "5");
386 model.addItem("brown", "6");
387 model.addItem("yellow", "7");
388 model.addItem("thistle", "8");
389 model.addItem("cyan", "9");
390 model.addItem("peachpuff", "10");
391 model.addItem("powderblue", "11");
392 model.addItem("gold", "12");
393 model.addItem("sandybrown", "13");
395 ctxt->setContextProperty("testData", &model);
397 canvas->setSource(QUrl::fromLocalFile(TESTDATA("datamodel.qml")));
398 qApp->processEvents();
400 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
401 QVERIFY(pathview != 0);
403 QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
404 QVERIFY(testObject->error() == false);
406 QQuickItem *item = findItem<QQuickItem>(pathview, "wrapper", 0);
408 QCOMPARE(item->x(), 110.0);
409 QCOMPARE(item->y(), 10.0);
411 model.insertItem(4, "orange", "10");
414 QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
415 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 14);
417 QVERIFY(pathview->currentIndex() == 0);
418 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
420 QQuickText *text = findItem<QQuickText>(pathview, "myText", 4);
422 QCOMPARE(text->text(), model.name(4));
425 QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
426 text = findItem<QQuickText>(pathview, "myText", 2);
428 QCOMPARE(text->text(), model.name(2));
429 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
431 testObject->setPathItemCount(5);
432 QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
433 QVERIFY(testObject->error() == false);
435 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
437 QQuickRectangle *testItem = findItem<QQuickRectangle>(pathview, "wrapper", 4);
438 QVERIFY(testItem != 0);
439 testItem = findItem<QQuickRectangle>(pathview, "wrapper", 5);
440 QVERIFY(testItem == 0);
442 pathview->setCurrentIndex(1);
443 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
446 model.insertItem(2, "pink", "2");
449 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
450 QVERIFY(pathview->currentIndex() == 1);
451 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
453 text = findItem<QQuickText>(pathview, "myText", 2);
455 QCOMPARE(text->text(), model.name(2));
458 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
459 text = findItem<QQuickText>(pathview, "myText", 3);
461 QCOMPARE(text->text(), model.name(3));
462 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
464 model.moveItem(3, 5);
465 QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
466 QList<QQuickItem*> items = findItems<QQuickItem>(pathview, "wrapper");
467 foreach (QQuickItem *item, items) {
468 QVERIFY(item->property("onPath").toBool());
470 QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
473 pathview->setOffset(7);
474 pathview->setOffset(0);
475 QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
477 pathview->setCurrentIndex(model.count()-1);
478 model.removeItem(model.count()-1);
479 QCOMPARE(pathview->currentIndex(), model.count()-1);
485 void tst_QQuickPathView::pathMoved()
487 QQuickView *canvas = createView();
491 model.addItem("Ben", "12345");
492 model.addItem("Bohn", "2345");
493 model.addItem("Bob", "54321");
494 model.addItem("Bill", "4321");
496 QDeclarativeContext *ctxt = canvas->rootContext();
497 ctxt->setContextProperty("testModel", &model);
499 canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
500 qApp->processEvents();
502 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
503 QVERIFY(pathview != 0);
505 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
507 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
509 QPointF start = path->pointAt(0.0);
510 QPointF offset;//Center of item is at point, but pos is from corner
511 offset.setX(firstItem->width()/2);
512 offset.setY(firstItem->height()/2);
513 QCOMPARE(firstItem->pos() + offset, start);
514 pathview->setOffset(1.0);
516 for (int i=0; i<model.count(); i++) {
517 QQuickRectangle *curItem = findItem<QQuickRectangle>(pathview, "wrapper", i);
518 QPointF itemPos(path->pointAt(0.25 + i*0.25));
519 QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
522 pathview->setOffset(0.0);
523 QCOMPARE(firstItem->pos() + offset, start);
525 // Change delegate size
526 pathview->setOffset(0.1);
527 pathview->setOffset(0.0);
528 canvas->rootObject()->setProperty("delegateWidth", 30);
529 QCOMPARE(firstItem->width(), 30.0);
530 offset.setX(firstItem->width()/2);
531 QTRY_COMPARE(firstItem->pos() + offset, start);
533 // Change delegate scale
534 pathview->setOffset(0.1);
535 pathview->setOffset(0.0);
536 canvas->rootObject()->setProperty("delegateScale", 1.2);
537 QTRY_COMPARE(firstItem->pos() + offset, start);
542 void tst_QQuickPathView::setCurrentIndex()
544 QQuickView *canvas = createView();
548 model.addItem("Ben", "12345");
549 model.addItem("Bohn", "2345");
550 model.addItem("Bob", "54321");
551 model.addItem("Bill", "4321");
553 QDeclarativeContext *ctxt = canvas->rootContext();
554 ctxt->setContextProperty("testModel", &model);
556 canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
557 qApp->processEvents();
559 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
560 QVERIFY(pathview != 0);
562 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
564 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
566 QPointF start = path->pointAt(0.0);
567 QPointF offset;//Center of item is at point, but pos is from corner
568 offset.setX(firstItem->width()/2);
569 offset.setY(firstItem->height()/2);
570 QCOMPARE(firstItem->pos() + offset, start);
571 QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
572 QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
574 pathview->setCurrentIndex(2);
576 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
577 QTRY_COMPARE(firstItem->pos() + offset, start);
578 QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
579 QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
580 QCOMPARE(pathview->currentItem(), firstItem);
581 QCOMPARE(firstItem->property("onPath"), QVariant(true));
583 pathview->decrementCurrentIndex();
584 QTRY_COMPARE(pathview->currentIndex(), 1);
585 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
587 QTRY_COMPARE(firstItem->pos() + offset, start);
588 QCOMPARE(pathview->currentItem(), firstItem);
589 QCOMPARE(firstItem->property("onPath"), QVariant(true));
591 pathview->decrementCurrentIndex();
592 QTRY_COMPARE(pathview->currentIndex(), 0);
593 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
595 QTRY_COMPARE(firstItem->pos() + offset, start);
596 QCOMPARE(pathview->currentItem(), firstItem);
597 QCOMPARE(firstItem->property("onPath"), QVariant(true));
599 pathview->decrementCurrentIndex();
600 QTRY_COMPARE(pathview->currentIndex(), 3);
601 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
603 QTRY_COMPARE(firstItem->pos() + offset, start);
604 QCOMPARE(pathview->currentItem(), firstItem);
605 QCOMPARE(firstItem->property("onPath"), QVariant(true));
607 pathview->incrementCurrentIndex();
608 QTRY_COMPARE(pathview->currentIndex(), 0);
609 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
611 QTRY_COMPARE(firstItem->pos() + offset, start);
612 QCOMPARE(pathview->currentItem(), firstItem);
613 QCOMPARE(firstItem->property("onPath"), QVariant(true));
615 // Check the current item is still created when outside the bounds of pathItemCount.
616 pathview->setPathItemCount(2);
617 pathview->setHighlightRangeMode(QQuickPathView::NoHighlightRange);
618 QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 0));
619 QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 1));
620 QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 2));
621 QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 3));
623 pathview->setCurrentIndex(2);
624 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
625 QCOMPARE(pathview->currentItem(), firstItem);
626 QCOMPARE(firstItem->property("onPath"), QVariant(false));
628 pathview->decrementCurrentIndex();
629 QTRY_COMPARE(pathview->currentIndex(), 1);
630 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
632 QCOMPARE(pathview->currentItem(), firstItem);
633 QCOMPARE(firstItem->property("onPath"), QVariant(true));
635 pathview->decrementCurrentIndex();
636 QTRY_COMPARE(pathview->currentIndex(), 0);
637 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
639 QCOMPARE(pathview->currentItem(), firstItem);
640 QCOMPARE(firstItem->property("onPath"), QVariant(true));
642 pathview->decrementCurrentIndex();
643 QTRY_COMPARE(pathview->currentIndex(), 3);
644 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
646 QCOMPARE(pathview->currentItem(), firstItem);
647 QCOMPARE(firstItem->property("onPath"), QVariant(false));
649 pathview->incrementCurrentIndex();
650 QTRY_COMPARE(pathview->currentIndex(), 0);
651 firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
653 QCOMPARE(pathview->currentItem(), firstItem);
654 QCOMPARE(firstItem->property("onPath"), QVariant(true));
659 void tst_QQuickPathView::resetModel()
661 QQuickView *canvas = createView();
664 strings << "one" << "two" << "three";
665 QStringListModel model(strings);
667 QDeclarativeContext *ctxt = canvas->rootContext();
668 ctxt->setContextProperty("testModel", &model);
670 canvas->setSource(QUrl::fromLocalFile(TESTDATA("displaypath.qml")));
671 qApp->processEvents();
673 QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
674 QVERIFY(pathview != 0);
676 QCOMPARE(pathview->count(), model.rowCount());
678 for (int i = 0; i < model.rowCount(); ++i) {
679 QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
680 QVERIFY(display != 0);
681 QCOMPARE(display->text(), strings.at(i));
685 strings << "four" << "five" << "six" << "seven";
686 model.setStringList(strings);
688 QCOMPARE(pathview->count(), model.rowCount());
690 for (int i = 0; i < model.rowCount(); ++i) {
691 QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
692 QVERIFY(display != 0);
693 QCOMPARE(display->text(), strings.at(i));
699 void tst_QQuickPathView::propertyChanges()
701 QQuickView *canvas = createView();
703 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
705 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
708 QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
709 QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
711 QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
712 QCOMPARE(pathView->dragMargin(), 5.0);
714 pathView->setPreferredHighlightBegin(0.4);
715 pathView->setPreferredHighlightEnd(0.4);
716 pathView->setDragMargin(20.0);
718 QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
719 QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
720 QCOMPARE(pathView->dragMargin(), 20.0);
722 QCOMPARE(snapPositionSpy.count(), 1);
723 QCOMPARE(dragMarginSpy.count(), 1);
725 pathView->setPreferredHighlightBegin(0.4);
726 pathView->setPreferredHighlightEnd(0.4);
727 pathView->setDragMargin(20.0);
729 QCOMPARE(snapPositionSpy.count(), 1);
730 QCOMPARE(dragMarginSpy.count(), 1);
734 void tst_QQuickPathView::pathChanges()
736 QQuickView *canvas = createView();
738 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
740 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
743 QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
746 QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
747 QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
749 QCOMPARE(path->startX(), 220.0);
750 QCOMPARE(path->startY(), 200.0);
752 path->setStartX(240.0);
753 path->setStartY(220.0);
755 QCOMPARE(path->startX(), 240.0);
756 QCOMPARE(path->startY(), 220.0);
758 QCOMPARE(startXSpy.count(),1);
759 QCOMPARE(startYSpy.count(),1);
761 path->setStartX(240);
762 path->setStartY(220);
764 QCOMPARE(startXSpy.count(),1);
765 QCOMPARE(startYSpy.count(),1);
767 QDeclarativePath *alternatePath = canvas->rootObject()->findChild<QDeclarativePath*>("alternatePath");
768 QVERIFY(alternatePath);
770 QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
772 QCOMPARE(pathView->path(), path);
774 pathView->setPath(alternatePath);
775 QCOMPARE(pathView->path(), alternatePath);
776 QCOMPARE(pathSpy.count(),1);
778 pathView->setPath(alternatePath);
779 QCOMPARE(pathSpy.count(),1);
781 QDeclarativePathAttribute *pathAttribute = canvas->rootObject()->findChild<QDeclarativePathAttribute*>("pathAttribute");
782 QVERIFY(pathAttribute);
784 QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
785 QCOMPARE(pathAttribute->name(), QString("opacity"));
787 pathAttribute->setName("scale");
788 QCOMPARE(pathAttribute->name(), QString("scale"));
789 QCOMPARE(nameSpy.count(),1);
791 pathAttribute->setName("scale");
792 QCOMPARE(nameSpy.count(),1);
796 void tst_QQuickPathView::componentChanges()
798 QQuickView *canvas = createView();
800 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
802 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
805 QDeclarativeComponent delegateComponent(canvas->engine());
806 delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
808 QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
810 pathView->setDelegate(&delegateComponent);
811 QCOMPARE(pathView->delegate(), &delegateComponent);
812 QCOMPARE(delegateSpy.count(),1);
814 pathView->setDelegate(&delegateComponent);
815 QCOMPARE(delegateSpy.count(),1);
819 void tst_QQuickPathView::modelChanges()
821 QQuickView *canvas = createView();
823 canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
825 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
828 QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
829 QVERIFY(alternateModel);
830 QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
831 QSignalSpy modelSpy(pathView, SIGNAL(modelChanged()));
833 pathView->setModel(modelVariant);
834 QCOMPARE(pathView->model(), modelVariant);
835 QCOMPARE(modelSpy.count(),1);
837 pathView->setModel(modelVariant);
838 QCOMPARE(modelSpy.count(),1);
840 pathView->setModel(QVariant());
841 QCOMPARE(modelSpy.count(),2);
846 void tst_QQuickPathView::pathUpdateOnStartChanged()
848 QQuickView *canvas = createView();
850 canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathUpdateOnStartChanged.qml")));
852 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
855 QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
857 QCOMPARE(path->startX(), 400.0);
858 QCOMPARE(path->startY(), 300.0);
860 QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
862 QCOMPARE(item->x(), path->startX() - item->width() / 2.0);
863 QCOMPARE(item->y(), path->startY() - item->height() / 2.0);
868 void tst_QQuickPathView::package()
870 QQuickView *canvas = createView();
872 canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview_package.qml")));
874 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("photoPathView");
877 QQuickItem *item = findItem<QQuickItem>(pathView, "pathItem");
879 QVERIFY(item->scale() != 1.0);
885 void tst_QQuickPathView::emptyModel()
887 QQuickView *canvas = createView();
889 QStringListModel model;
891 QDeclarativeContext *ctxt = canvas->rootContext();
892 ctxt->setContextProperty("emptyModel", &model);
894 canvas->setSource(QUrl::fromLocalFile(TESTDATA("emptymodel.qml")));
895 qApp->processEvents();
897 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
898 QVERIFY(pathview != 0);
900 QCOMPARE(pathview->offset(), qreal(0.0));
905 void tst_QQuickPathView::closed()
907 QDeclarativeEngine engine;
910 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("openPath.qml")));
911 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
913 QCOMPARE(obj->isClosed(), false);
918 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("closedPath.qml")));
919 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
921 QCOMPARE(obj->isClosed(), true);
927 void tst_QQuickPathView::pathUpdate()
929 QQuickView *canvas = createView();
931 canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathUpdate.qml")));
933 QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
936 QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
938 QCOMPARE(item->x(), 150.0);
943 void tst_QQuickPathView::visualDataModel()
945 QDeclarativeEngine engine;
946 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("vdm.qml")));
948 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
951 QCOMPARE(obj->count(), 3);
956 void tst_QQuickPathView::undefinedPath()
958 QDeclarativeEngine engine;
959 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("undefinedpath.qml")));
961 QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
964 QCOMPARE(obj->count(), 3);
969 void tst_QQuickPathView::mouseDrag()
971 QQuickView *canvas = createView();
972 canvas->setSource(QUrl::fromLocalFile(TESTDATA("dragpath.qml")));
974 canvas->requestActivateWindow();
975 QTest::qWaitForWindowShown(canvas);
976 QTRY_COMPARE(canvas, qGuiApp->focusWindow());
978 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
979 QVERIFY(pathview != 0);
981 int current = pathview->currentIndex();
983 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10,100));
987 QMouseEvent mv(QEvent::MouseMove, QPoint(30,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
988 QApplication::sendEvent(canvas, &mv);
991 QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
992 QApplication::sendEvent(canvas, &mv);
995 QVERIFY(pathview->currentIndex() != current);
997 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(40,100));
1002 void tst_QQuickPathView::treeModel()
1004 QQuickView *canvas = createView();
1007 QStandardItemModel model;
1008 initStandardTreeModel(&model);
1009 canvas->engine()->rootContext()->setContextProperty("myModel", &model);
1011 canvas->setSource(QUrl::fromLocalFile(TESTDATA("treemodel.qml")));
1013 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1014 QVERIFY(pathview != 0);
1015 QCOMPARE(pathview->count(), 3);
1017 QQuickText *item = findItem<QQuickText>(pathview, "wrapper", 0);
1019 QCOMPARE(item->text(), QLatin1String("Row 1 Item"));
1021 QVERIFY(QMetaObject::invokeMethod(pathview, "setRoot", Q_ARG(QVariant, 1)));
1022 QCOMPARE(pathview->count(), 1);
1024 QTRY_VERIFY(item = findItem<QQuickText>(pathview, "wrapper", 0));
1025 QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
1030 void tst_QQuickPathView::changePreferredHighlight()
1032 QQuickView *canvas = createView();
1033 canvas->setGeometry(0,0,400,200);
1034 canvas->setSource(QUrl::fromLocalFile(TESTDATA("dragpath.qml")));
1036 canvas->requestActivateWindow();
1037 QTest::qWaitForWindowShown(canvas);
1038 QTRY_COMPARE(canvas, qGuiApp->focusWindow());
1040 QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1041 QVERIFY(pathview != 0);
1043 int current = pathview->currentIndex();
1044 QCOMPARE(current, 0);
1046 QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
1048 QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
1050 QPointF start = path->pointAt(0.5);
1051 start.setX(qRound(start.x()));
1052 start.setY(qRound(start.y()));
1053 QPointF offset;//Center of item is at point, but pos is from corner
1054 offset.setX(firstItem->width()/2);
1055 offset.setY(firstItem->height()/2);
1056 QTRY_COMPARE(firstItem->pos() + offset, start);
1058 pathview->setPreferredHighlightBegin(0.8);
1059 pathview->setPreferredHighlightEnd(0.8);
1060 start = path->pointAt(0.8);
1061 start.setX(qRound(start.x()));
1062 start.setY(qRound(start.y()));
1063 QTRY_COMPARE(firstItem->pos() + offset, start);
1064 QCOMPARE(pathview->currentIndex(), 0);
1069 void tst_QQuickPathView::creationContext()
1072 canvas.setGeometry(0,0,240,320);
1073 canvas.setSource(QUrl::fromLocalFile(TESTDATA("creationContext.qml")));
1075 QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
1077 QVERIFY(rootItem->property("count").toInt() > 0);
1080 QVERIFY(item = findItem<QQuickItem>(rootItem, "listItem", 0));
1081 QCOMPARE(item->property("text").toString(), QString("Hello!"));
1084 QQuickView *tst_QQuickPathView::createView()
1086 QQuickView *canvas = new QQuickView(0);
1087 canvas->setGeometry(0,0,240,320);
1093 Find an item with the specified objectName. If index is supplied then the
1094 item must also evaluate the {index} expression equal to index
1096 template<typename T>
1097 T *tst_QQuickPathView::findItem(QQuickItem *parent, const QString &objectName, int index)
1099 const QMetaObject &mo = T::staticMetaObject;
1100 //qDebug() << parent->childItems().count() << "children";
1101 for (int i = 0; i < parent->childItems().count(); ++i) {
1102 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
1105 //qDebug() << "try" << item;
1106 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
1108 QDeclarativeExpression e(qmlContext(item), item, "index");
1109 if (e.evaluate().toInt() == index)
1110 return static_cast<T*>(item);
1112 return static_cast<T*>(item);
1115 item = findItem<T>(item, objectName, index);
1117 return static_cast<T*>(item);
1123 template<typename T>
1124 QList<T*> tst_QQuickPathView::findItems(QQuickItem *parent, const QString &objectName)
1127 const QMetaObject &mo = T::staticMetaObject;
1128 //qDebug() << parent->QQuickItem::children().count() << "children";
1129 for (int i = 0; i < parent->childItems().count(); ++i) {
1130 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
1133 //qDebug() << "try" << item;
1134 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
1135 items.append(static_cast<T*>(item));
1136 items += findItems<T>(item, objectName);
1142 void tst_QQuickPathView::missingPercent()
1144 QDeclarativeEngine engine;
1145 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("missingPercent.qml")));
1146 QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
1148 QCOMPARE(obj->attributeAt("_qfx_percent", 1.0), qreal(1.0));
1153 QTEST_MAIN(tst_QQuickPathView)
1155 #include "tst_qquickpathview.moc"