Merge remote branch 'gerrit/api_changes' into merge-master
[profile/ivi/qtdeclarative.git] / tests / auto / quick / qquickpathview / tst_qquickpathview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <QtQuick/qquickview.h>
44 #include <QtQml/qqmlengine.h>
45 #include <QtQml/qqmlcomponent.h>
46 #include <QtQml/qqmlcontext.h>
47 #include <QtQml/qqmlexpression.h>
48 #include <QtQml/qqmlincubator.h>
49 #include <QtQuick/private/qquickpathview_p.h>
50 #include <QtQuick/private/qquickpath_p.h>
51 #include <QtQuick/private/qquicktext_p.h>
52 #include <QtQuick/private/qquickrectangle_p.h>
53 #include <QtQml/private/qquicklistmodel_p.h>
54 #include <QtQml/private/qqmlvaluetype_p.h>
55 #include <QStringListModel>
56 #include <QStandardItemModel>
57 #include <QFile>
58
59 #include "../../shared/util.h"
60 #include "../shared/viewtestutil.h"
61 #include "../shared/visualtestutil.h"
62
63 using namespace QQuickViewTestUtil;
64 using namespace QQuickVisualTestUtil;
65
66
67 static void initStandardTreeModel(QStandardItemModel *model)
68 {
69     QStandardItem *item;
70     item = new QStandardItem(QLatin1String("Row 1 Item"));
71     model->insertRow(0, item);
72
73     item = new QStandardItem(QLatin1String("Row 2 Item"));
74     item->setCheckable(true);
75     model->insertRow(1, item);
76
77     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
78     item->setChild(0, childItem);
79
80     item = new QStandardItem(QLatin1String("Row 3 Item"));
81     item->setIcon(QIcon());
82     model->insertRow(2, item);
83 }
84
85
86 class tst_QQuickPathView : public QQmlDataTest
87 {
88     Q_OBJECT
89 public:
90     tst_QQuickPathView();
91
92 private slots:
93     void initValues();
94     void items();
95     void dataModel();
96     void pathview2();
97     void pathview3();
98     void insertModel_data();
99     void insertModel();
100     void removeModel_data();
101     void removeModel();
102     void moveModel_data();
103     void moveModel();
104     void path();
105     void pathMoved();
106     void setCurrentIndex();
107     void resetModel();
108     void propertyChanges();
109     void pathChanges();
110     void componentChanges();
111     void modelChanges();
112     void pathUpdateOnStartChanged();
113     void package();
114     void emptyModel();
115     void closed();
116     void pathUpdate();
117     void visualDataModel();
118     void undefinedPath();
119     void mouseDrag();
120     void treeModel();
121     void changePreferredHighlight();
122     void missingPercent();
123     void creationContext();
124     void currentOffsetOnInsertion();
125     void asynchronous();
126 };
127
128 class TestObject : public QObject
129 {
130     Q_OBJECT
131
132     Q_PROPERTY(bool error READ error WRITE setError)
133     Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
134     Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
135
136 public:
137     TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
138
139     bool error() const { return mError; }
140     void setError(bool err) { mError = err; }
141
142     bool useModel() const { return mUseModel; }
143     void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
144
145     int pathItemCount() const { return mPathItemCount; }
146     void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
147
148 signals:
149     void useModelChanged();
150     void pathItemCountChanged();
151
152 private:
153     bool mError;
154     bool mUseModel;
155     int mPathItemCount;
156 };
157
158 tst_QQuickPathView::tst_QQuickPathView()
159 {
160 }
161
162 void tst_QQuickPathView::initValues()
163 {
164     QQmlEngine engine;
165     QQmlComponent c(&engine, testFileUrl("pathview1.qml"));
166     QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
167
168     QVERIFY(obj != 0);
169     QVERIFY(obj->path() == 0);
170     QVERIFY(obj->delegate() == 0);
171     QCOMPARE(obj->model(), QVariant());
172     QCOMPARE(obj->currentIndex(), 0);
173     QCOMPARE(obj->offset(), 0.);
174     QCOMPARE(obj->preferredHighlightBegin(), 0.);
175     QCOMPARE(obj->dragMargin(), 0.);
176     QCOMPARE(obj->count(), 0);
177     QCOMPARE(obj->pathItemCount(), -1);
178
179     delete obj;
180 }
181
182 void tst_QQuickPathView::items()
183 {
184     QQuickView *canvas = createView();
185
186     QaimModel model;
187     model.addItem("Fred", "12345");
188     model.addItem("John", "2345");
189     model.addItem("Bob", "54321");
190     model.addItem("Bill", "4321");
191
192     QQmlContext *ctxt = canvas->rootContext();
193     ctxt->setContextProperty("testModel", &model);
194
195     canvas->setSource(testFileUrl("pathview0.qml"));
196     qApp->processEvents();
197
198     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
199     QVERIFY(pathview != 0);
200
201     QCOMPARE(pathview->count(), model.count());
202     QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
203     QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
204
205     for (int i = 0; i < model.count(); ++i) {
206         QQuickText *name = findItem<QQuickText>(pathview, "textName", i);
207         QVERIFY(name != 0);
208         QCOMPARE(name->text(), model.name(i));
209         QQuickText *number = findItem<QQuickText>(pathview, "textNumber", i);
210         QVERIFY(number != 0);
211         QCOMPARE(number->text(), model.number(i));
212     }
213
214     QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path());
215     QVERIFY(path);
216
217     QVERIFY(pathview->highlightItem());
218     QPointF start = path->pointAt(0.0);
219     QPointF offset;
220     offset.setX(pathview->highlightItem()->width()/2);
221     offset.setY(pathview->highlightItem()->height()/2);
222     QCOMPARE(pathview->highlightItem()->pos() + offset, start);
223
224     delete canvas;
225 }
226
227 void tst_QQuickPathView::pathview2()
228 {
229     QQmlEngine engine;
230     QQmlComponent c(&engine, testFileUrl("pathview2.qml"));
231     QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
232
233     QVERIFY(obj != 0);
234     QVERIFY(obj->path() != 0);
235     QVERIFY(obj->delegate() != 0);
236     QVERIFY(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(), 8);
242     QCOMPARE(obj->pathItemCount(), 10);
243
244     delete obj;
245 }
246
247 void tst_QQuickPathView::pathview3()
248 {
249     QQmlEngine engine;
250     QQmlComponent c(&engine, testFileUrl("pathview3.qml"));
251     QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
252
253     QVERIFY(obj != 0);
254     QVERIFY(obj->path() != 0);
255     QVERIFY(obj->delegate() != 0);
256     QVERIFY(obj->model() != QVariant());
257     QCOMPARE(obj->currentIndex(), 0);
258     QCOMPARE(obj->offset(), 1.0);
259     QCOMPARE(obj->preferredHighlightBegin(), 0.5);
260     QCOMPARE(obj->dragMargin(), 24.);
261     QCOMPARE(obj->count(), 8);
262     QCOMPARE(obj->pathItemCount(), 4);
263
264     delete obj;
265 }
266
267 void tst_QQuickPathView::insertModel_data()
268 {
269     QTest::addColumn<int>("mode");
270     QTest::addColumn<int>("idx");
271     QTest::addColumn<int>("count");
272     QTest::addColumn<qreal>("offset");
273
274     // We have 8 items, with currentIndex == 4
275     QTest::newRow("insert after current")
276         << int(QQuickPathView::StrictlyEnforceRange) << 6 << 1 << 5.;
277     QTest::newRow("insert before current")
278         << int(QQuickPathView::StrictlyEnforceRange) << 2 << 1 << 4.;
279     QTest::newRow("insert multiple after current")
280         << int(QQuickPathView::StrictlyEnforceRange) << 5 << 2 << 6.;
281     QTest::newRow("insert multiple before current")
282         << int(QQuickPathView::StrictlyEnforceRange) << 1 << 2 << 4.;
283     QTest::newRow("insert at end")
284         << int(QQuickPathView::StrictlyEnforceRange) << 8 << 1 << 5.;
285     QTest::newRow("insert at beginning")
286         << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 4.;
287     QTest::newRow("insert at current")
288         << int(QQuickPathView::StrictlyEnforceRange) << 4 << 1 << 4.;
289
290     QTest::newRow("no range - insert after current")
291         << int(QQuickPathView::NoHighlightRange) << 6 << 1 << 5.;
292     QTest::newRow("no range - insert before current")
293         << int(QQuickPathView::NoHighlightRange) << 2 << 1 << 4.;
294     QTest::newRow("no range - insert multiple after current")
295         << int(QQuickPathView::NoHighlightRange) << 5 << 2 << 6.;
296     QTest::newRow("no range - insert multiple before current")
297         << int(QQuickPathView::NoHighlightRange) << 1 << 2 << 4.;
298     QTest::newRow("no range - insert at end")
299         << int(QQuickPathView::NoHighlightRange) << 8 << 1 << 5.;
300     QTest::newRow("no range - insert at beginning")
301         << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 4.;
302     QTest::newRow("no range - insert at current")
303         << int(QQuickPathView::NoHighlightRange) << 4 << 1 << 4.;
304 }
305
306 void tst_QQuickPathView::insertModel()
307 {
308     QFETCH(int, mode);
309     QFETCH(int, idx);
310     QFETCH(int, count);
311     QFETCH(qreal, offset);
312
313     QQuickView *canvas = createView();
314     canvas->show();
315
316     QaimModel model;
317     model.addItem("Ben", "12345");
318     model.addItem("Bohn", "2345");
319     model.addItem("Bob", "54321");
320     model.addItem("Bill", "4321");
321     model.addItem("Jinny", "679");
322     model.addItem("Milly", "73378");
323     model.addItem("Jimmy", "3535");
324     model.addItem("Barb", "9039");
325
326     QQmlContext *ctxt = canvas->rootContext();
327     ctxt->setContextProperty("testModel", &model);
328
329     canvas->setSource(testFileUrl("pathview0.qml"));
330     qApp->processEvents();
331
332     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
333     QVERIFY(pathview != 0);
334
335     pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
336
337     pathview->setCurrentIndex(4);
338     if (mode == QQuickPathView::StrictlyEnforceRange)
339         QTRY_COMPARE(pathview->offset(), 4.0);
340     else
341         pathview->setOffset(4);
342
343     QList<QPair<QString, QString> > items;
344     for (int i = 0; i < count; ++i)
345         items.append(qMakePair(QString("New"), QString::number(i)));
346
347     model.insertItems(idx, items);
348     QTRY_COMPARE(pathview->offset(), offset);
349
350     delete canvas;
351 }
352
353 void tst_QQuickPathView::removeModel_data()
354 {
355     QTest::addColumn<int>("mode");
356     QTest::addColumn<int>("idx");
357     QTest::addColumn<int>("count");
358     QTest::addColumn<qreal>("offset");
359
360     // We have 8 items, with currentIndex == 4
361     QTest::newRow("remove after current")
362         << int(QQuickPathView::StrictlyEnforceRange) << 6 << 1 << 3.;
363     QTest::newRow("remove before current")
364         << int(QQuickPathView::StrictlyEnforceRange) << 2 << 1 << 4.;
365     QTest::newRow("remove multiple after current")
366         << int(QQuickPathView::StrictlyEnforceRange) << 5 << 2 << 2.;
367     QTest::newRow("remove multiple before current")
368         << int(QQuickPathView::StrictlyEnforceRange) << 1 << 2 << 4.;
369     QTest::newRow("remove last")
370         << int(QQuickPathView::StrictlyEnforceRange) << 7 << 1 << 3.;
371     QTest::newRow("remove first")
372         << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 4.;
373     QTest::newRow("remove current")
374         << int(QQuickPathView::StrictlyEnforceRange) << 4 << 1 << 3.;
375
376     QTest::newRow("no range - remove after current")
377         << int(QQuickPathView::NoHighlightRange) << 6 << 1 << 3.;
378     QTest::newRow("no range - remove before current")
379         << int(QQuickPathView::NoHighlightRange) << 2 << 1 << 4.;
380     QTest::newRow("no range - remove multiple after current")
381         << int(QQuickPathView::NoHighlightRange) << 5 << 2 << 2.;
382     QTest::newRow("no range - remove multiple before current")
383         << int(QQuickPathView::NoHighlightRange) << 1 << 2 << 4.;
384     QTest::newRow("no range - remove last")
385         << int(QQuickPathView::NoHighlightRange) << 7 << 1 << 3.;
386     QTest::newRow("no range - remove first")
387         << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 4.;
388     QTest::newRow("no range - remove current offset")
389         << int(QQuickPathView::NoHighlightRange) << 4 << 1 << 4.;
390 }
391
392 void tst_QQuickPathView::removeModel()
393 {
394     QFETCH(int, mode);
395     QFETCH(int, idx);
396     QFETCH(int, count);
397     QFETCH(qreal, offset);
398
399     QQuickView *canvas = createView();
400     canvas->show();
401
402     QaimModel model;
403     model.addItem("Ben", "12345");
404     model.addItem("Bohn", "2345");
405     model.addItem("Bob", "54321");
406     model.addItem("Bill", "4321");
407     model.addItem("Jinny", "679");
408     model.addItem("Milly", "73378");
409     model.addItem("Jimmy", "3535");
410     model.addItem("Barb", "9039");
411
412     QQmlContext *ctxt = canvas->rootContext();
413     ctxt->setContextProperty("testModel", &model);
414
415     canvas->setSource(testFileUrl("pathview0.qml"));
416     qApp->processEvents();
417
418     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
419     QVERIFY(pathview != 0);
420
421     pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
422
423     pathview->setCurrentIndex(4);
424     if (mode == QQuickPathView::StrictlyEnforceRange)
425         QTRY_COMPARE(pathview->offset(), 4.0);
426     else
427         pathview->setOffset(4);
428
429     model.removeItems(idx, count);
430     QTRY_COMPARE(pathview->offset(), offset);
431
432     delete canvas;
433 }
434
435
436 void tst_QQuickPathView::moveModel_data()
437 {
438     QTest::addColumn<int>("mode");
439     QTest::addColumn<int>("from");
440     QTest::addColumn<int>("to");
441     QTest::addColumn<int>("count");
442     QTest::addColumn<qreal>("offset");
443
444     // We have 8 items, with currentIndex == 4
445     QTest::newRow("move after current")
446         << int(QQuickPathView::StrictlyEnforceRange) << 5 << 6 << 1 << 4.;
447     QTest::newRow("move before current")
448         << int(QQuickPathView::StrictlyEnforceRange) << 2 << 3 << 1 << 4.;
449     QTest::newRow("move before current to after")
450         << int(QQuickPathView::StrictlyEnforceRange) << 2 << 6 << 1 << 5.;
451     QTest::newRow("move multiple after current")
452         << int(QQuickPathView::StrictlyEnforceRange) << 5 << 6 << 2 << 4.;
453     QTest::newRow("move multiple before current")
454         << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 2 << 4.;
455     QTest::newRow("move before current to end")
456         << int(QQuickPathView::StrictlyEnforceRange) << 2 << 7 << 1 << 5.;
457     QTest::newRow("move last to beginning")
458         << int(QQuickPathView::StrictlyEnforceRange) << 7 << 0 << 1 << 3.;
459     QTest::newRow("move current")
460         << int(QQuickPathView::StrictlyEnforceRange) << 4 << 6 << 1 << 2.;
461
462     QTest::newRow("no range - move after current")
463         << int(QQuickPathView::NoHighlightRange) << 5 << 6 << 1 << 4.;
464     QTest::newRow("no range - move before current")
465         << int(QQuickPathView::NoHighlightRange) << 2 << 3 << 1 << 4.;
466     QTest::newRow("no range - move before current to after")
467         << int(QQuickPathView::NoHighlightRange) << 2 << 6 << 1 << 5.;
468     QTest::newRow("no range - move multiple after current")
469         << int(QQuickPathView::NoHighlightRange) << 5 << 6 << 2 << 4.;
470     QTest::newRow("no range - move multiple before current")
471         << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 2 << 4.;
472     QTest::newRow("no range - move before current to end")
473         << int(QQuickPathView::NoHighlightRange) << 2 << 7 << 1 << 5.;
474     QTest::newRow("no range - move last to beginning")
475         << int(QQuickPathView::NoHighlightRange) << 7 << 0 << 1 << 3.;
476     QTest::newRow("no range - move current")
477         << int(QQuickPathView::NoHighlightRange) << 4 << 6 << 1 << 4.;
478     QTest::newRow("no range - move multiple incl. current")
479         << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 5 << 4.;
480 }
481
482 void tst_QQuickPathView::moveModel()
483 {
484     QFETCH(int, mode);
485     QFETCH(int, from);
486     QFETCH(int, to);
487     QFETCH(int, count);
488     QFETCH(qreal, offset);
489
490     QQuickView *canvas = createView();
491     canvas->show();
492
493     QaimModel model;
494     model.addItem("Ben", "12345");
495     model.addItem("Bohn", "2345");
496     model.addItem("Bob", "54321");
497     model.addItem("Bill", "4321");
498     model.addItem("Jinny", "679");
499     model.addItem("Milly", "73378");
500     model.addItem("Jimmy", "3535");
501     model.addItem("Barb", "9039");
502
503     QQmlContext *ctxt = canvas->rootContext();
504     ctxt->setContextProperty("testModel", &model);
505
506     canvas->setSource(testFileUrl("pathview0.qml"));
507     qApp->processEvents();
508
509     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
510     QVERIFY(pathview != 0);
511
512     pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
513
514     pathview->setCurrentIndex(4);
515     if (mode == QQuickPathView::StrictlyEnforceRange)
516         QTRY_COMPARE(pathview->offset(), 4.0);
517     else
518         pathview->setOffset(4);
519
520     model.moveItems(from, to, count);
521     QTRY_COMPARE(pathview->offset(), offset);
522
523     delete canvas;
524 }
525
526 void tst_QQuickPathView::path()
527 {
528     QQmlEngine engine;
529     QQmlComponent c(&engine, testFileUrl("pathtest.qml"));
530     QQuickPath *obj = qobject_cast<QQuickPath*>(c.create());
531
532     QVERIFY(obj != 0);
533     QCOMPARE(obj->startX(), 120.);
534     QCOMPARE(obj->startY(), 100.);
535     QVERIFY(obj->path() != QPainterPath());
536
537     QQmlListReference list(obj, "pathElements");
538     QCOMPARE(list.count(), 5);
539
540     QQuickPathAttribute* attr = qobject_cast<QQuickPathAttribute*>(list.at(0));
541     QVERIFY(attr != 0);
542     QCOMPARE(attr->name(), QString("scale"));
543     QCOMPARE(attr->value(), 1.0);
544
545     QQuickPathQuad* quad = qobject_cast<QQuickPathQuad*>(list.at(1));
546     QVERIFY(quad != 0);
547     QCOMPARE(quad->x(), 120.);
548     QCOMPARE(quad->y(), 25.);
549     QCOMPARE(quad->controlX(), 260.);
550     QCOMPARE(quad->controlY(), 75.);
551
552     QQuickPathPercent* perc = qobject_cast<QQuickPathPercent*>(list.at(2));
553     QVERIFY(perc != 0);
554     QCOMPARE(perc->value(), 0.3);
555
556     QQuickPathLine* line = qobject_cast<QQuickPathLine*>(list.at(3));
557     QVERIFY(line != 0);
558     QCOMPARE(line->x(), 120.);
559     QCOMPARE(line->y(), 100.);
560
561     QQuickPathCubic* cubic = qobject_cast<QQuickPathCubic*>(list.at(4));
562     QVERIFY(cubic != 0);
563     QCOMPARE(cubic->x(), 180.);
564     QCOMPARE(cubic->y(), 0.);
565     QCOMPARE(cubic->control1X(), -10.);
566     QCOMPARE(cubic->control1Y(), 90.);
567     QCOMPARE(cubic->control2X(), 210.);
568     QCOMPARE(cubic->control2Y(), 90.);
569
570     delete obj;
571 }
572
573 void tst_QQuickPathView::dataModel()
574 {
575     QQuickView *canvas = createView();
576     canvas->show();
577
578     QQmlContext *ctxt = canvas->rootContext();
579     TestObject *testObject = new TestObject;
580     ctxt->setContextProperty("testObject", testObject);
581
582     QaimModel model;
583     model.addItem("red", "1");
584     model.addItem("green", "2");
585     model.addItem("blue", "3");
586     model.addItem("purple", "4");
587     model.addItem("gray", "5");
588     model.addItem("brown", "6");
589     model.addItem("yellow", "7");
590     model.addItem("thistle", "8");
591     model.addItem("cyan", "9");
592     model.addItem("peachpuff", "10");
593     model.addItem("powderblue", "11");
594     model.addItem("gold", "12");
595     model.addItem("sandybrown", "13");
596
597     ctxt->setContextProperty("testData", &model);
598
599     canvas->setSource(testFileUrl("datamodel.qml"));
600     qApp->processEvents();
601
602     QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
603     QVERIFY(pathview != 0);
604
605     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
606     QVERIFY(testObject->error() == false);
607
608     QQuickItem *item = findItem<QQuickItem>(pathview, "wrapper", 0);
609     QVERIFY(item);
610     QCOMPARE(item->x(), 110.0);
611     QCOMPARE(item->y(), 10.0);
612
613     model.insertItem(4, "orange", "10");
614     QTest::qWait(100);
615
616     QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
617     QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 14);
618
619     QVERIFY(pathview->currentIndex() == 0);
620     QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
621
622     QQuickText *text = findItem<QQuickText>(pathview, "myText", 4);
623     QVERIFY(text);
624     QCOMPARE(text->text(), model.name(4));
625
626     model.removeItem(2);
627     QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
628     text = findItem<QQuickText>(pathview, "myText", 2);
629     QVERIFY(text);
630     QCOMPARE(text->text(), model.name(2));
631     QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
632
633     testObject->setPathItemCount(5);
634     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
635     QVERIFY(testObject->error() == false);
636
637     QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
638
639     QQuickRectangle *testItem = findItem<QQuickRectangle>(pathview, "wrapper", 4);
640     QVERIFY(testItem != 0);
641     testItem = findItem<QQuickRectangle>(pathview, "wrapper", 5);
642     QVERIFY(testItem == 0);
643
644     pathview->setCurrentIndex(1);
645     QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
646     QTest::qWait(100);
647
648     model.insertItem(2, "pink", "2");
649     QTest::qWait(100);
650
651     QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
652     QVERIFY(pathview->currentIndex() == 1);
653     QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
654
655     text = findItem<QQuickText>(pathview, "myText", 2);
656     QVERIFY(text);
657     QCOMPARE(text->text(), model.name(2));
658
659     model.removeItem(3);
660     QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
661     text = findItem<QQuickText>(pathview, "myText", 3);
662     QVERIFY(text);
663     QCOMPARE(text->text(), model.name(3));
664     QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
665
666     model.moveItem(3, 5);
667     QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
668     QList<QQuickItem*> items = findItems<QQuickItem>(pathview, "wrapper");
669     foreach (QQuickItem *item, items) {
670         QVERIFY(item->property("onPath").toBool());
671     }
672     QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
673
674     // QTBUG-14199
675     pathview->setOffset(7);
676     pathview->setOffset(0);
677     QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
678
679     pathview->setCurrentIndex(model.count()-1);
680     model.removeItem(model.count()-1);
681     QCOMPARE(pathview->currentIndex(), model.count()-1);
682
683     delete canvas;
684     delete testObject;
685 }
686
687 void tst_QQuickPathView::pathMoved()
688 {
689     QQuickView *canvas = createView();
690     canvas->show();
691
692     QaimModel model;
693     model.addItem("Ben", "12345");
694     model.addItem("Bohn", "2345");
695     model.addItem("Bob", "54321");
696     model.addItem("Bill", "4321");
697
698     QQmlContext *ctxt = canvas->rootContext();
699     ctxt->setContextProperty("testModel", &model);
700
701     canvas->setSource(testFileUrl("pathview0.qml"));
702     qApp->processEvents();
703
704     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
705     QVERIFY(pathview != 0);
706
707     QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
708     QVERIFY(firstItem);
709     QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path());
710     QVERIFY(path);
711     QPointF start = path->pointAt(0.0);
712     QPointF offset;//Center of item is at point, but pos is from corner
713     offset.setX(firstItem->width()/2);
714     offset.setY(firstItem->height()/2);
715     QTRY_COMPARE(firstItem->pos() + offset, start);
716     pathview->setOffset(1.0);
717
718     for (int i=0; i<model.count(); i++) {
719         QQuickRectangle *curItem = findItem<QQuickRectangle>(pathview, "wrapper", i);
720         QPointF itemPos(path->pointAt(0.25 + i*0.25));
721         QCOMPARE(curItem->pos() + offset, QPointF(itemPos.x(), itemPos.y()));
722     }
723
724     pathview->setOffset(0.0);
725     QCOMPARE(firstItem->pos() + offset, start);
726
727     // Change delegate size
728     pathview->setOffset(0.1);
729     pathview->setOffset(0.0);
730     canvas->rootObject()->setProperty("delegateWidth", 30);
731     QCOMPARE(firstItem->width(), 30.0);
732     offset.setX(firstItem->width()/2);
733     QTRY_COMPARE(firstItem->pos() + offset, start);
734
735     // Change delegate scale
736     pathview->setOffset(0.1);
737     pathview->setOffset(0.0);
738     canvas->rootObject()->setProperty("delegateScale", 1.2);
739     QTRY_COMPARE(firstItem->pos() + offset, start);
740
741     delete canvas;
742 }
743
744 void tst_QQuickPathView::setCurrentIndex()
745 {
746     QQuickView *canvas = createView();
747     canvas->show();
748
749     QaimModel model;
750     model.addItem("Ben", "12345");
751     model.addItem("Bohn", "2345");
752     model.addItem("Bob", "54321");
753     model.addItem("Bill", "4321");
754
755     QQmlContext *ctxt = canvas->rootContext();
756     ctxt->setContextProperty("testModel", &model);
757
758     canvas->setSource(testFileUrl("pathview0.qml"));
759     qApp->processEvents();
760
761     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
762     QVERIFY(pathview != 0);
763
764     QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
765     QVERIFY(firstItem);
766     QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path());
767     QVERIFY(path);
768     QPointF start = path->pointAt(0.0);
769     QPointF offset;//Center of item is at point, but pos is from corner
770     offset.setX(firstItem->width()/2);
771     offset.setY(firstItem->height()/2);
772     QCOMPARE(firstItem->pos() + offset, start);
773     QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
774     QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
775
776     pathview->setCurrentIndex(2);
777
778     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
779     QTRY_COMPARE(firstItem->pos() + offset, start);
780     QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
781     QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
782     QCOMPARE(pathview->currentItem(), firstItem);
783     QCOMPARE(firstItem->property("onPath"), QVariant(true));
784
785     pathview->decrementCurrentIndex();
786     QTRY_COMPARE(pathview->currentIndex(), 1);
787     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
788     QVERIFY(firstItem);
789     QTRY_COMPARE(firstItem->pos() + offset, start);
790     QCOMPARE(pathview->currentItem(), firstItem);
791     QCOMPARE(firstItem->property("onPath"), QVariant(true));
792
793     pathview->decrementCurrentIndex();
794     QTRY_COMPARE(pathview->currentIndex(), 0);
795     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
796     QVERIFY(firstItem);
797     QTRY_COMPARE(firstItem->pos() + offset, start);
798     QCOMPARE(pathview->currentItem(), firstItem);
799     QCOMPARE(firstItem->property("onPath"), QVariant(true));
800
801     pathview->decrementCurrentIndex();
802     QTRY_COMPARE(pathview->currentIndex(), 3);
803     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
804     QVERIFY(firstItem);
805     QTRY_COMPARE(firstItem->pos() + offset, start);
806     QCOMPARE(pathview->currentItem(), firstItem);
807     QCOMPARE(firstItem->property("onPath"), QVariant(true));
808
809     pathview->incrementCurrentIndex();
810     QTRY_COMPARE(pathview->currentIndex(), 0);
811     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
812     QVERIFY(firstItem);
813     QTRY_COMPARE(firstItem->pos() + offset, start);
814     QCOMPARE(pathview->currentItem(), firstItem);
815     QCOMPARE(firstItem->property("onPath"), QVariant(true));
816
817     // move an item, set move duration to 0, and change currentIndex to moved item. QTBUG-22786
818     model.moveItem(0, 3);
819     pathview->setHighlightMoveDuration(0);
820     pathview->setCurrentIndex(3);
821     QCOMPARE(pathview->currentIndex(), 3);
822     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
823     QVERIFY(firstItem);
824     QCOMPARE(pathview->currentItem(), firstItem);
825     QTRY_COMPARE(firstItem->pos() + offset, start);
826     model.moveItem(3, 0);
827     pathview->setCurrentIndex(0);
828     pathview->setHighlightMoveDuration(300);
829
830     // Check the current item is still created when outside the bounds of pathItemCount.
831     pathview->setPathItemCount(2);
832     pathview->setHighlightRangeMode(QQuickPathView::NoHighlightRange);
833     QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 0));
834     QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 1));
835     QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 2));
836     QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 3));
837
838     pathview->setCurrentIndex(2);
839     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
840     QCOMPARE(pathview->currentItem(), firstItem);
841     QCOMPARE(firstItem->property("onPath"), QVariant(false));
842
843     pathview->decrementCurrentIndex();
844     QTRY_COMPARE(pathview->currentIndex(), 1);
845     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
846     QVERIFY(firstItem);
847     QCOMPARE(pathview->currentItem(), firstItem);
848     QCOMPARE(firstItem->property("onPath"), QVariant(true));
849
850     pathview->decrementCurrentIndex();
851     QTRY_COMPARE(pathview->currentIndex(), 0);
852     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
853     QVERIFY(firstItem);
854     QCOMPARE(pathview->currentItem(), firstItem);
855     QCOMPARE(firstItem->property("onPath"), QVariant(true));
856
857     pathview->decrementCurrentIndex();
858     QTRY_COMPARE(pathview->currentIndex(), 3);
859     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
860     QVERIFY(firstItem);
861     QCOMPARE(pathview->currentItem(), firstItem);
862     QCOMPARE(firstItem->property("onPath"), QVariant(false));
863
864     pathview->incrementCurrentIndex();
865     QTRY_COMPARE(pathview->currentIndex(), 0);
866     firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
867     QVERIFY(firstItem);
868     QCOMPARE(pathview->currentItem(), firstItem);
869     QCOMPARE(firstItem->property("onPath"), QVariant(true));
870
871     delete canvas;
872 }
873
874 void tst_QQuickPathView::resetModel()
875 {
876     QQuickView *canvas = createView();
877
878     QStringList strings;
879     strings << "one" << "two" << "three";
880     QStringListModel model(strings);
881
882     QQmlContext *ctxt = canvas->rootContext();
883     ctxt->setContextProperty("testModel", &model);
884
885     canvas->setSource(testFileUrl("displaypath.qml"));
886     qApp->processEvents();
887
888     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
889     QVERIFY(pathview != 0);
890
891     QCOMPARE(pathview->count(), model.rowCount());
892
893     for (int i = 0; i < model.rowCount(); ++i) {
894         QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
895         QVERIFY(display != 0);
896         QCOMPARE(display->text(), strings.at(i));
897     }
898
899     strings.clear();
900     strings << "four" << "five" << "six" << "seven";
901     model.setStringList(strings);
902
903     QCOMPARE(pathview->count(), model.rowCount());
904
905     for (int i = 0; i < model.rowCount(); ++i) {
906         QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
907         QVERIFY(display != 0);
908         QCOMPARE(display->text(), strings.at(i));
909     }
910
911     delete canvas;
912 }
913
914 void tst_QQuickPathView::propertyChanges()
915 {
916     QQuickView *canvas = createView();
917     QVERIFY(canvas);
918     canvas->setSource(testFileUrl("propertychanges.qml"));
919
920     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
921     QVERIFY(pathView);
922
923     QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
924     QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
925
926     QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
927     QCOMPARE(pathView->dragMargin(), 5.0);
928
929     pathView->setPreferredHighlightBegin(0.4);
930     pathView->setPreferredHighlightEnd(0.4);
931     pathView->setDragMargin(20.0);
932
933     QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
934     QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
935     QCOMPARE(pathView->dragMargin(), 20.0);
936
937     QCOMPARE(snapPositionSpy.count(), 1);
938     QCOMPARE(dragMarginSpy.count(), 1);
939
940     pathView->setPreferredHighlightBegin(0.4);
941     pathView->setPreferredHighlightEnd(0.4);
942     pathView->setDragMargin(20.0);
943
944     QCOMPARE(snapPositionSpy.count(), 1);
945     QCOMPARE(dragMarginSpy.count(), 1);
946     delete canvas;
947 }
948
949 void tst_QQuickPathView::pathChanges()
950 {
951     QQuickView *canvas = createView();
952     QVERIFY(canvas);
953     canvas->setSource(testFileUrl("propertychanges.qml"));
954
955     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
956     QVERIFY(pathView);
957
958     QQuickPath *path = canvas->rootObject()->findChild<QQuickPath*>("path");
959     QVERIFY(path);
960
961     QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
962     QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
963
964     QCOMPARE(path->startX(), 220.0);
965     QCOMPARE(path->startY(), 200.0);
966
967     path->setStartX(240.0);
968     path->setStartY(220.0);
969
970     QCOMPARE(path->startX(), 240.0);
971     QCOMPARE(path->startY(), 220.0);
972
973     QCOMPARE(startXSpy.count(),1);
974     QCOMPARE(startYSpy.count(),1);
975
976     path->setStartX(240);
977     path->setStartY(220);
978
979     QCOMPARE(startXSpy.count(),1);
980     QCOMPARE(startYSpy.count(),1);
981
982     QQuickPath *alternatePath = canvas->rootObject()->findChild<QQuickPath*>("alternatePath");
983     QVERIFY(alternatePath);
984
985     QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
986
987     QCOMPARE(pathView->path(), path);
988
989     pathView->setPath(alternatePath);
990     QCOMPARE(pathView->path(), alternatePath);
991     QCOMPARE(pathSpy.count(),1);
992
993     pathView->setPath(alternatePath);
994     QCOMPARE(pathSpy.count(),1);
995
996     QQuickPathAttribute *pathAttribute = canvas->rootObject()->findChild<QQuickPathAttribute*>("pathAttribute");
997     QVERIFY(pathAttribute);
998
999     QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
1000     QCOMPARE(pathAttribute->name(), QString("opacity"));
1001
1002     pathAttribute->setName("scale");
1003     QCOMPARE(pathAttribute->name(), QString("scale"));
1004     QCOMPARE(nameSpy.count(),1);
1005
1006     pathAttribute->setName("scale");
1007     QCOMPARE(nameSpy.count(),1);
1008     delete canvas;
1009 }
1010
1011 void tst_QQuickPathView::componentChanges()
1012 {
1013     QQuickView *canvas = createView();
1014     QVERIFY(canvas);
1015     canvas->setSource(testFileUrl("propertychanges.qml"));
1016
1017     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1018     QVERIFY(pathView);
1019
1020     QQmlComponent delegateComponent(canvas->engine());
1021     delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1022
1023     QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
1024
1025     pathView->setDelegate(&delegateComponent);
1026     QCOMPARE(pathView->delegate(), &delegateComponent);
1027     QCOMPARE(delegateSpy.count(),1);
1028
1029     pathView->setDelegate(&delegateComponent);
1030     QCOMPARE(delegateSpy.count(),1);
1031     delete canvas;
1032 }
1033
1034 void tst_QQuickPathView::modelChanges()
1035 {
1036     QQuickView *canvas = createView();
1037     QVERIFY(canvas);
1038     canvas->setSource(testFileUrl("propertychanges.qml"));
1039
1040     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1041     QVERIFY(pathView);
1042
1043     QQuickListModel *alternateModel = canvas->rootObject()->findChild<QQuickListModel*>("alternateModel");
1044     QVERIFY(alternateModel);
1045     QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
1046     QSignalSpy modelSpy(pathView, SIGNAL(modelChanged()));
1047
1048     pathView->setModel(modelVariant);
1049     QCOMPARE(pathView->model(), modelVariant);
1050     QCOMPARE(modelSpy.count(),1);
1051
1052     pathView->setModel(modelVariant);
1053     QCOMPARE(modelSpy.count(),1);
1054
1055     pathView->setModel(QVariant());
1056     QCOMPARE(modelSpy.count(),2);
1057
1058     delete canvas;
1059 }
1060
1061 void tst_QQuickPathView::pathUpdateOnStartChanged()
1062 {
1063     QQuickView *canvas = createView();
1064     QVERIFY(canvas);
1065     canvas->setSource(testFileUrl("pathUpdateOnStartChanged.qml"));
1066
1067     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1068     QVERIFY(pathView);
1069
1070     QQuickPath *path = canvas->rootObject()->findChild<QQuickPath*>("path");
1071     QVERIFY(path);
1072     QCOMPARE(path->startX(), 400.0);
1073     QCOMPARE(path->startY(), 300.0);
1074
1075     QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
1076     QVERIFY(item);
1077     QCOMPARE(item->x(), path->startX() - item->width() / 2.0);
1078     QCOMPARE(item->y(), path->startY() - item->height() / 2.0);
1079
1080     delete canvas;
1081 }
1082
1083 void tst_QQuickPathView::package()
1084 {
1085     QQuickView *canvas = createView();
1086     QVERIFY(canvas);
1087     canvas->setSource(testFileUrl("pathview_package.qml"));
1088     canvas->show();
1089     QTest::qWaitForWindowShown(canvas);
1090
1091     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("photoPathView");
1092     QVERIFY(pathView);
1093
1094 #ifdef Q_OS_MAC
1095     QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
1096 #endif
1097
1098     QQuickItem *item = findItem<QQuickItem>(pathView, "pathItem");
1099     QVERIFY(item);
1100     QVERIFY(item->scale() != 1.0);
1101
1102     delete canvas;
1103 }
1104
1105 //QTBUG-13017
1106 void tst_QQuickPathView::emptyModel()
1107 {
1108     QQuickView *canvas = createView();
1109
1110     QStringListModel model;
1111
1112     QQmlContext *ctxt = canvas->rootContext();
1113     ctxt->setContextProperty("emptyModel", &model);
1114
1115     canvas->setSource(testFileUrl("emptymodel.qml"));
1116     qApp->processEvents();
1117
1118     QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1119     QVERIFY(pathview != 0);
1120
1121     QCOMPARE(pathview->offset(), qreal(0.0));
1122
1123     delete canvas;
1124 }
1125
1126 void tst_QQuickPathView::closed()
1127 {
1128     QQmlEngine engine;
1129
1130     {
1131         QQmlComponent c(&engine, testFileUrl("openPath.qml"));
1132         QQuickPath *obj = qobject_cast<QQuickPath*>(c.create());
1133         QVERIFY(obj);
1134         QCOMPARE(obj->isClosed(), false);
1135         delete obj;
1136     }
1137
1138     {
1139         QQmlComponent c(&engine, testFileUrl("closedPath.qml"));
1140         QQuickPath *obj = qobject_cast<QQuickPath*>(c.create());
1141         QVERIFY(obj);
1142         QCOMPARE(obj->isClosed(), true);
1143         delete obj;
1144     }
1145 }
1146
1147 // QTBUG-14239
1148 void tst_QQuickPathView::pathUpdate()
1149 {
1150     QQuickView *canvas = createView();
1151     QVERIFY(canvas);
1152     canvas->setSource(testFileUrl("pathUpdate.qml"));
1153
1154     QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
1155     QVERIFY(pathView);
1156
1157     QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
1158     QVERIFY(item);
1159     QCOMPARE(item->x(), 150.0);
1160
1161     delete canvas;
1162 }
1163
1164 void tst_QQuickPathView::visualDataModel()
1165 {
1166     QQmlEngine engine;
1167     QQmlComponent c(&engine, testFileUrl("vdm.qml"));
1168
1169     QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
1170     QVERIFY(obj != 0);
1171
1172     QCOMPARE(obj->count(), 3);
1173
1174     delete obj;
1175 }
1176
1177 void tst_QQuickPathView::undefinedPath()
1178 {
1179     QQmlEngine engine;
1180
1181     // QPainterPath warnings are only received if QT_NO_DEBUG is not defined
1182     if (QLibraryInfo::isDebugBuild()) {
1183         QString warning1("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
1184         QTest::ignoreMessage(QtWarningMsg,qPrintable(warning1));
1185
1186         QString warning2("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
1187         QTest::ignoreMessage(QtWarningMsg,qPrintable(warning2));
1188     }
1189
1190     QQmlComponent c(&engine, testFileUrl("undefinedpath.qml"));
1191
1192     QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
1193     QVERIFY(obj != 0);
1194
1195     QCOMPARE(obj->count(), 3);
1196
1197     delete obj;
1198 }
1199
1200 void tst_QQuickPathView::mouseDrag()
1201 {
1202     QQuickView *canvas = createView();
1203     canvas->setSource(testFileUrl("dragpath.qml"));
1204     canvas->show();
1205     canvas->requestActivateWindow();
1206     QTest::qWaitForWindowShown(canvas);
1207     QTRY_COMPARE(canvas, qGuiApp->focusWindow());
1208
1209     QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1210     QVERIFY(pathview != 0);
1211
1212     int current = pathview->currentIndex();
1213
1214     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10,100));
1215     QTest::qWait(100);
1216
1217     {
1218         QMouseEvent mv(QEvent::MouseMove, QPoint(30,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1219         QGuiApplication::sendEvent(canvas, &mv);
1220     }
1221     {
1222         QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1223         QGuiApplication::sendEvent(canvas, &mv);
1224     }
1225
1226     QVERIFY(pathview->currentIndex() != current);
1227
1228     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(40,100));
1229
1230     delete canvas;
1231 }
1232
1233 void tst_QQuickPathView::treeModel()
1234 {
1235     QQuickView *canvas = createView();
1236     canvas->show();
1237
1238     QStandardItemModel model;
1239     initStandardTreeModel(&model);
1240     canvas->engine()->rootContext()->setContextProperty("myModel", &model);
1241
1242     canvas->setSource(testFileUrl("treemodel.qml"));
1243
1244     QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1245     QVERIFY(pathview != 0);
1246     QCOMPARE(pathview->count(), 3);
1247
1248     QQuickText *item = findItem<QQuickText>(pathview, "wrapper", 0);
1249     QVERIFY(item);
1250     QCOMPARE(item->text(), QLatin1String("Row 1 Item"));
1251
1252     QVERIFY(QMetaObject::invokeMethod(pathview, "setRoot", Q_ARG(QVariant, 1)));
1253     QCOMPARE(pathview->count(), 1);
1254
1255     QTRY_VERIFY(item = findItem<QQuickText>(pathview, "wrapper", 0));
1256     QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
1257
1258     delete canvas;
1259 }
1260
1261 void tst_QQuickPathView::changePreferredHighlight()
1262 {
1263     QQuickView *canvas = createView();
1264     canvas->setGeometry(0,0,400,200);
1265     canvas->setSource(testFileUrl("dragpath.qml"));
1266     canvas->show();
1267     canvas->requestActivateWindow();
1268     QTest::qWaitForWindowShown(canvas);
1269     QTRY_COMPARE(canvas, qGuiApp->focusWindow());
1270
1271     QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
1272     QVERIFY(pathview != 0);
1273
1274     int current = pathview->currentIndex();
1275     QCOMPARE(current, 0);
1276
1277     QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
1278     QVERIFY(firstItem);
1279     QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path());
1280     QVERIFY(path);
1281     QPointF start = path->pointAt(0.5);
1282     QPointF offset;//Center of item is at point, but pos is from corner
1283     offset.setX(firstItem->width()/2);
1284     offset.setY(firstItem->height()/2);
1285     QTRY_COMPARE(firstItem->pos() + offset, start);
1286
1287     pathview->setPreferredHighlightBegin(0.8);
1288     pathview->setPreferredHighlightEnd(0.8);
1289     start = path->pointAt(0.8);
1290     QTRY_COMPARE(firstItem->pos() + offset, start);
1291     QCOMPARE(pathview->currentIndex(), 0);
1292
1293     delete canvas;
1294 }
1295
1296 void tst_QQuickPathView::creationContext()
1297 {
1298     QQuickView canvas;
1299     canvas.setGeometry(0,0,240,320);
1300     canvas.setSource(testFileUrl("creationContext.qml"));
1301
1302     QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
1303     QVERIFY(rootItem);
1304     QVERIFY(rootItem->property("count").toInt() > 0);
1305
1306     QQuickItem *item;
1307     QVERIFY(item = findItem<QQuickItem>(rootItem, "listItem", 0));
1308     QCOMPARE(item->property("text").toString(), QString("Hello!"));
1309 }
1310
1311 // QTBUG-21320
1312 void tst_QQuickPathView::currentOffsetOnInsertion()
1313 {
1314     QQuickView *canvas = createView();
1315     canvas->show();
1316
1317     QaimModel model;
1318
1319     QQmlContext *ctxt = canvas->rootContext();
1320     ctxt->setContextProperty("testModel", &model);
1321
1322     canvas->setSource(testFileUrl("pathline.qml"));
1323     qApp->processEvents();
1324
1325     QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
1326     QVERIFY(pathview != 0);
1327
1328     pathview->setPreferredHighlightBegin(0.5);
1329     pathview->setPreferredHighlightEnd(0.5);
1330
1331     QCOMPARE(pathview->count(), model.count());
1332
1333     model.addItem("item0", "0");
1334
1335     QCOMPARE(pathview->count(), model.count());
1336
1337     QQuickRectangle *item = 0;
1338     QTRY_VERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 0));
1339
1340     QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path());
1341     QVERIFY(path);
1342
1343     QPointF start = path->pointAt(0.5);
1344     QPointF offset;//Center of item is at point, but pos is from corner
1345     offset.setX(item->width()/2);
1346     offset.setY(item->height()/2);
1347     QCOMPARE(item->pos() + offset, start);
1348
1349     QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged()));
1350
1351     // insert an item at the beginning
1352     model.insertItem(0, "item1", "1");
1353     qApp->processEvents();
1354
1355     QCOMPARE(currentIndexSpy.count(), 1);
1356
1357     // currentIndex is now 1
1358     QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1));
1359
1360     // verify that current item (item 1) is still at offset 0.5
1361     QCOMPARE(item->pos() + offset, start);
1362
1363     // insert another item at the beginning
1364     model.insertItem(0, "item2", "2");
1365     qApp->processEvents();
1366
1367     QCOMPARE(currentIndexSpy.count(), 2);
1368
1369     // currentIndex is now 2
1370     QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 2));
1371
1372     // verify that current item (item 2) is still at offset 0.5
1373     QCOMPARE(item->pos() + offset, start);
1374
1375     // verify that remove before current maintains current item
1376     model.removeItem(0);
1377     qApp->processEvents();
1378
1379     QCOMPARE(currentIndexSpy.count(), 3);
1380
1381     // currentIndex is now 1
1382     QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1));
1383
1384     // verify that current item (item 1) is still at offset 0.5
1385     QCOMPARE(item->pos() + offset, start);
1386
1387     delete canvas;
1388 }
1389
1390 void tst_QQuickPathView::asynchronous()
1391 {
1392     QQuickView *canvas = createView();
1393     canvas->show();
1394     QQmlIncubationController controller;
1395     canvas->engine()->setIncubationController(&controller);
1396
1397     canvas->setSource(testFileUrl("asyncloader.qml"));
1398
1399     QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
1400     QVERIFY(rootObject);
1401
1402     QQuickPathView *pathview = 0;
1403     while (!pathview) {
1404         bool b = false;
1405         controller.incubateWhile(&b);
1406         pathview = rootObject->findChild<QQuickPathView*>("view");
1407     }
1408
1409     // items will be created one at a time
1410     for (int i = 0; i < 5; ++i) {
1411         QVERIFY(findItem<QQuickItem>(pathview, "wrapper", i) == 0);
1412         QQuickItem *item = 0;
1413         while (!item) {
1414             bool b = false;
1415             controller.incubateWhile(&b);
1416             item = findItem<QQuickItem>(pathview, "wrapper", i);
1417         }
1418     }
1419
1420     {
1421         bool b = true;
1422         controller.incubateWhile(&b);
1423     }
1424
1425     // verify positioning
1426     QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
1427     QVERIFY(firstItem);
1428     QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path());
1429     QVERIFY(path);
1430     QPointF start = path->pointAt(0.0);
1431     QPointF offset;//Center of item is at point, but pos is from corner
1432     offset.setX(firstItem->width()/2);
1433     offset.setY(firstItem->height()/2);
1434     QTRY_COMPARE(firstItem->pos() + offset, start);
1435     pathview->setOffset(1.0);
1436
1437     for (int i=0; i<5; i++) {
1438         QQuickItem *curItem = findItem<QQuickItem>(pathview, "wrapper", i);
1439         QPointF itemPos(path->pointAt(0.2 + i*0.2));
1440         QCOMPARE(curItem->pos() + offset, itemPos);
1441     }
1442
1443     delete canvas;
1444 }
1445
1446 void tst_QQuickPathView::missingPercent()
1447 {
1448     QQmlEngine engine;
1449     QQmlComponent c(&engine, testFileUrl("missingPercent.qml"));
1450     QQuickPath *obj = qobject_cast<QQuickPath*>(c.create());
1451     QVERIFY(obj);
1452     QCOMPARE(obj->attributeAt("_qfx_percent", 1.0), qreal(1.0));
1453     delete obj;
1454 }
1455
1456 QTEST_MAIN(tst_QQuickPathView)
1457
1458 #include "tst_qquickpathview.moc"