Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativepathview / tst_qdeclarativepathview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <QtDeclarative/qdeclarativeview.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/qdeclarativepathview_p.h>
49 #include <QtDeclarative/private/qdeclarativepath_p.h>
50 #include <QtDeclarative/private/qdeclarativetext_p.h>
51 #include <QtDeclarative/private/qdeclarativerectangle_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>
57 #include <QFile>
58
59 #include "../../../shared/util.h"
60
61 #ifdef Q_OS_SYMBIAN
62 // In Symbian OS test data is located in applications private dir
63 #define SRCDIR "."
64 #endif
65
66 static void initStandardTreeModel(QStandardItemModel *model)
67 {
68     QStandardItem *item;
69     item = new QStandardItem(QLatin1String("Row 1 Item"));
70     model->insertRow(0, item);
71
72     item = new QStandardItem(QLatin1String("Row 2 Item"));
73     item->setCheckable(true);
74     model->insertRow(1, item);
75
76     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
77     item->setChild(0, childItem);
78
79     item = new QStandardItem(QLatin1String("Row 3 Item"));
80     item->setIcon(QIcon());
81     model->insertRow(2, item);
82 }
83
84
85 class tst_QDeclarativePathView : public QObject
86 {
87     Q_OBJECT
88 public:
89     tst_QDeclarativePathView();
90
91 private slots:
92     void initValues();
93     void items();
94     void dataModel();
95     void pathview2();
96     void pathview3();
97     void path();
98     void pathMoved();
99     void setCurrentIndex();
100     void resetModel();
101     void propertyChanges();
102     void pathChanges();
103     void componentChanges();
104     void modelChanges();
105     void pathUpdateOnStartChanged();
106     void package();
107     void emptyModel();
108     void closed();
109     void pathUpdate();
110     void visualDataModel();
111     void undefinedPath();
112     void mouseDrag();
113     void treeModel();
114     void changePreferredHighlight();
115
116 private:
117     QDeclarativeView *createView();
118     template<typename T>
119     T *findItem(QGraphicsObject *parent, const QString &objectName, int index=-1);
120     template<typename T>
121     QList<T*> findItems(QGraphicsObject *parent, const QString &objectName);
122 };
123
124 class TestObject : public QObject
125 {
126     Q_OBJECT
127
128     Q_PROPERTY(bool error READ error WRITE setError)
129     Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
130     Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
131
132 public:
133     TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
134
135     bool error() const { return mError; }
136     void setError(bool err) { mError = err; }
137
138     bool useModel() const { return mUseModel; }
139     void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
140
141     int pathItemCount() const { return mPathItemCount; }
142     void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
143
144 signals:
145     void useModelChanged();
146     void pathItemCountChanged();
147
148 private:
149     bool mError;
150     bool mUseModel;
151     int mPathItemCount;
152 };
153
154 class TestModel : public QAbstractListModel
155 {
156 public:
157     enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
158
159     TestModel(QObject *parent=0) : QAbstractListModel(parent) {
160         QHash<int, QByteArray> roles;
161         roles[Name] = "name";
162         roles[Number] = "number";
163         setRoleNames(roles);
164     }
165
166     int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
167     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
168         QVariant rv;
169         if (role == Name)
170             rv = list.at(index.row()).first;
171         else if (role == Number)
172             rv = list.at(index.row()).second;
173
174         return rv;
175     }
176
177     int count() const { return rowCount(); }
178     QString name(int index) const { return list.at(index).first; }
179     QString number(int index) const { return list.at(index).second; }
180
181     void addItem(const QString &name, const QString &number) {
182         beginInsertRows(QModelIndex(), list.count(), list.count());
183         list.append(QPair<QString,QString>(name, number));
184         endInsertRows();
185     }
186
187     void insertItem(int index, const QString &name, const QString &number) {
188         beginInsertRows(QModelIndex(), index, index);
189         list.insert(index, QPair<QString,QString>(name, number));
190         endInsertRows();
191     }
192
193     void removeItem(int index) {
194         beginRemoveRows(QModelIndex(), index, index);
195         list.removeAt(index);
196         endRemoveRows();
197     }
198
199     void moveItem(int from, int to) {
200         beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
201         list.move(from, to);
202         endMoveRows();
203     }
204
205     void modifyItem(int idx, const QString &name, const QString &number) {
206         list[idx] = QPair<QString,QString>(name, number);
207         emit dataChanged(index(idx,0), index(idx,0));
208     }
209
210 private:
211     QList<QPair<QString,QString> > list;
212 };
213
214
215 tst_QDeclarativePathView::tst_QDeclarativePathView()
216 {
217 }
218
219 void tst_QDeclarativePathView::initValues()
220 {
221     QDeclarativeEngine engine;
222     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview1.qml"));
223     QDeclarativePathView *obj = qobject_cast<QDeclarativePathView*>(c.create());
224
225     QVERIFY(obj != 0);
226     QVERIFY(obj->path() == 0);
227     QVERIFY(obj->delegate() == 0);
228     QCOMPARE(obj->model(), QVariant());
229     QCOMPARE(obj->currentIndex(), 0);
230     QCOMPARE(obj->offset(), 0.);
231     QCOMPARE(obj->preferredHighlightBegin(), 0.);
232     QCOMPARE(obj->dragMargin(), 0.);
233     QCOMPARE(obj->count(), 0);
234     QCOMPARE(obj->pathItemCount(), -1);
235 }
236
237 void tst_QDeclarativePathView::items()
238 {
239     QDeclarativeView *canvas = createView();
240
241     TestModel model;
242     model.addItem("Fred", "12345");
243     model.addItem("John", "2345");
244     model.addItem("Bob", "54321");
245     model.addItem("Bill", "4321");
246
247     QDeclarativeContext *ctxt = canvas->rootContext();
248     ctxt->setContextProperty("testModel", &model);
249
250     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
251     qApp->processEvents();
252
253     QDeclarativePathView *pathview = findItem<QDeclarativePathView>(canvas->rootObject(), "view");
254     QVERIFY(pathview != 0);
255
256     QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
257
258     for (int i = 0; i < model.count(); ++i) {
259         QDeclarativeText *name = findItem<QDeclarativeText>(pathview, "textName", i);
260         QVERIFY(name != 0);
261         QCOMPARE(name->text(), model.name(i));
262         QDeclarativeText *number = findItem<QDeclarativeText>(pathview, "textNumber", i);
263         QVERIFY(number != 0);
264         QCOMPARE(number->text(), model.number(i));
265     }
266
267     QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
268     QVERIFY(path);
269
270     QVERIFY(pathview->highlightItem());
271     QPointF start = path->pointAt(0.0);
272     QPointF offset;
273     offset.setX(pathview->highlightItem()->width()/2);
274     offset.setY(pathview->highlightItem()->height()/2);
275     QCOMPARE(pathview->highlightItem()->pos() + offset, start);
276
277     delete canvas;
278 }
279
280 void tst_QDeclarativePathView::pathview2()
281 {
282     QDeclarativeEngine engine;
283     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview2.qml"));
284     QDeclarativePathView *obj = qobject_cast<QDeclarativePathView*>(c.create());
285
286     QVERIFY(obj != 0);
287     QVERIFY(obj->path() != 0);
288     QVERIFY(obj->delegate() != 0);
289     QVERIFY(obj->model() != QVariant());
290     QCOMPARE(obj->currentIndex(), 0);
291     QCOMPARE(obj->offset(), 0.);
292     QCOMPARE(obj->preferredHighlightBegin(), 0.);
293     QCOMPARE(obj->dragMargin(), 0.);
294     QCOMPARE(obj->count(), 8);
295     QCOMPARE(obj->pathItemCount(), 10);
296 }
297
298 void tst_QDeclarativePathView::pathview3()
299 {
300     QDeclarativeEngine engine;
301     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview3.qml"));
302     QDeclarativePathView *obj = qobject_cast<QDeclarativePathView*>(c.create());
303
304     QVERIFY(obj != 0);
305     QVERIFY(obj->path() != 0);
306     QVERIFY(obj->delegate() != 0);
307     QVERIFY(obj->model() != QVariant());
308     QCOMPARE(obj->currentIndex(), 0);
309     QCOMPARE(obj->offset(), 1.0);
310     QCOMPARE(obj->preferredHighlightBegin(), 0.5);
311     QCOMPARE(obj->dragMargin(), 24.);
312     QCOMPARE(obj->count(), 8);
313     QCOMPARE(obj->pathItemCount(), 4);
314 }
315
316 void tst_QDeclarativePathView::path()
317 {
318     QDeclarativeEngine engine;
319     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathtest.qml"));
320     QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
321
322     QVERIFY(obj != 0);
323     QCOMPARE(obj->startX(), 120.);
324     QCOMPARE(obj->startY(), 100.);
325     QVERIFY(obj->path() != QPainterPath());
326
327     QDeclarativeListReference list(obj, "pathElements");
328     QCOMPARE(list.count(), 5);
329
330     QDeclarativePathAttribute* attr = qobject_cast<QDeclarativePathAttribute*>(list.at(0));
331     QVERIFY(attr != 0);
332     QCOMPARE(attr->name(), QString("scale"));
333     QCOMPARE(attr->value(), 1.0);
334
335     QDeclarativePathQuad* quad = qobject_cast<QDeclarativePathQuad*>(list.at(1));
336     QVERIFY(quad != 0);
337     QCOMPARE(quad->x(), 120.);
338     QCOMPARE(quad->y(), 25.);
339     QCOMPARE(quad->controlX(), 260.);
340     QCOMPARE(quad->controlY(), 75.);
341
342     QDeclarativePathPercent* perc = qobject_cast<QDeclarativePathPercent*>(list.at(2));
343     QVERIFY(perc != 0);
344     QCOMPARE(perc->value(), 0.3);
345
346     QDeclarativePathLine* line = qobject_cast<QDeclarativePathLine*>(list.at(3));
347     QVERIFY(line != 0);
348     QCOMPARE(line->x(), 120.);
349     QCOMPARE(line->y(), 100.);
350
351     QDeclarativePathCubic* cubic = qobject_cast<QDeclarativePathCubic*>(list.at(4));
352     QVERIFY(cubic != 0);
353     QCOMPARE(cubic->x(), 180.);
354     QCOMPARE(cubic->y(), 0.);
355     QCOMPARE(cubic->control1X(), -10.);
356     QCOMPARE(cubic->control1Y(), 90.);
357     QCOMPARE(cubic->control2X(), 210.);
358     QCOMPARE(cubic->control2Y(), 90.);
359 }
360
361 void tst_QDeclarativePathView::dataModel()
362 {
363     QDeclarativeView *canvas = createView();
364
365     QDeclarativeContext *ctxt = canvas->rootContext();
366     TestObject *testObject = new TestObject;
367     ctxt->setContextProperty("testObject", testObject);
368
369     TestModel model;
370     model.addItem("red", "1");
371     model.addItem("green", "2");
372     model.addItem("blue", "3");
373     model.addItem("purple", "4");
374     model.addItem("gray", "5");
375     model.addItem("brown", "6");
376     model.addItem("yellow", "7");
377     model.addItem("thistle", "8");
378     model.addItem("cyan", "9");
379     model.addItem("peachpuff", "10");
380     model.addItem("powderblue", "11");
381     model.addItem("gold", "12");
382     model.addItem("sandybrown", "13");
383
384     ctxt->setContextProperty("testData", &model);
385
386     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/datamodel.qml"));
387     qApp->processEvents();
388
389     QDeclarativePathView *pathview = qobject_cast<QDeclarativePathView*>(canvas->rootObject());
390     QVERIFY(pathview != 0);
391
392     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
393     QVERIFY(testObject->error() == false);
394
395     QDeclarativeItem *item = findItem<QDeclarativeItem>(pathview, "wrapper", 0);
396     QVERIFY(item);
397     QCOMPARE(item->x(), 110.0);
398     QCOMPARE(item->y(), 10.0);
399
400     model.insertItem(4, "orange", "10");
401     QTest::qWait(100);
402
403     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 14);
404
405     QVERIFY(pathview->currentIndex() == 0);
406
407     QDeclarativeText *text = findItem<QDeclarativeText>(pathview, "myText", 4);
408     QVERIFY(text);
409     QCOMPARE(text->text(), model.name(4));
410
411     model.removeItem(2);
412     text = findItem<QDeclarativeText>(pathview, "myText", 2);
413     QVERIFY(text);
414     QCOMPARE(text->text(), model.name(2));
415
416     testObject->setPathItemCount(5);
417     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
418     QVERIFY(testObject->error() == false);
419
420     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
421
422     QDeclarativeRectangle *testItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 4);
423     QVERIFY(testItem != 0);
424     testItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 5);
425     QVERIFY(testItem == 0);
426
427     pathview->setCurrentIndex(1);
428
429     model.insertItem(2, "pink", "2");
430     QTest::qWait(100);
431
432     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
433     QVERIFY(pathview->currentIndex() == 1);
434
435     text = findItem<QDeclarativeText>(pathview, "myText", 2);
436     QVERIFY(text);
437     QCOMPARE(text->text(), model.name(2));
438
439     model.removeItem(3);
440     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
441     text = findItem<QDeclarativeText>(pathview, "myText", 3);
442     QVERIFY(text);
443     QCOMPARE(text->text(), model.name(3));
444
445     model.moveItem(3, 5);
446     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
447     QList<QDeclarativeItem*> items = findItems<QDeclarativeItem>(pathview, "wrapper");
448     foreach (QDeclarativeItem *item, items) {
449         QVERIFY(item->property("onPath").toBool());
450     }
451
452     // QTBUG-14199
453     pathview->setOffset(7);
454     pathview->setOffset(0);
455     QCOMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
456
457     pathview->setCurrentIndex(model.count()-1);
458     model.removeItem(model.count()-1);
459     QCOMPARE(pathview->currentIndex(), model.count()-1);
460
461     // QTBUG-18825
462     // Confirm that the target offset is adjusted when removing items
463     pathview->setCurrentIndex(model.count()-1);
464     QTRY_COMPARE(pathview->offset(), 1.);
465     pathview->setCurrentIndex(model.count()-5);
466     model.removeItem(model.count()-1);
467     model.removeItem(model.count()-1);
468     model.removeItem(model.count()-1);
469     QTRY_COMPARE(pathview->offset(), 2.);
470
471     delete canvas;
472 }
473
474 void tst_QDeclarativePathView::pathMoved()
475 {
476     QDeclarativeView *canvas = createView();
477
478     TestModel model;
479     model.addItem("Ben", "12345");
480     model.addItem("Bohn", "2345");
481     model.addItem("Bob", "54321");
482     model.addItem("Bill", "4321");
483
484     QDeclarativeContext *ctxt = canvas->rootContext();
485     ctxt->setContextProperty("testModel", &model);
486
487     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
488     qApp->processEvents();
489
490     QDeclarativePathView *pathview = findItem<QDeclarativePathView>(canvas->rootObject(), "view");
491     QVERIFY(pathview != 0);
492
493     QDeclarativeRectangle *firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 0);
494     QVERIFY(firstItem);
495     QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
496     QVERIFY(path);
497     QPointF start = path->pointAt(0.0);
498     QPointF offset;//Center of item is at point, but pos is from corner
499     offset.setX(firstItem->width()/2);
500     offset.setY(firstItem->height()/2);
501     QCOMPARE(firstItem->pos() + offset, start);
502     pathview->setOffset(1.0);
503
504     for(int i=0; i<model.count(); i++){
505         QDeclarativeRectangle *curItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", i);
506         QPointF itemPos(path->pointAt(0.25 + i*0.25));
507         QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
508     }
509
510     pathview->setOffset(0.0);
511     QCOMPARE(firstItem->pos() + offset, start);
512
513     // Change delegate size
514     pathview->setOffset(0.1);
515     pathview->setOffset(0.0);
516     canvas->rootObject()->setProperty("delegateWidth", 30);
517     QCOMPARE(firstItem->width(), 30.0);
518     offset.setX(firstItem->width()/2);
519     QTRY_COMPARE(firstItem->pos() + offset, start);
520
521     // Change delegate scale
522     pathview->setOffset(0.1);
523     pathview->setOffset(0.0);
524     canvas->rootObject()->setProperty("delegateScale", 1.2);
525     QTRY_COMPARE(firstItem->pos() + offset, start);
526
527     delete canvas;
528 }
529
530 void tst_QDeclarativePathView::setCurrentIndex()
531 {
532     QDeclarativeView *canvas = createView();
533
534     TestModel model;
535     model.addItem("Ben", "12345");
536     model.addItem("Bohn", "2345");
537     model.addItem("Bob", "54321");
538     model.addItem("Bill", "4321");
539
540     QDeclarativeContext *ctxt = canvas->rootContext();
541     ctxt->setContextProperty("testModel", &model);
542
543     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
544     qApp->processEvents();
545
546     QDeclarativePathView *pathview = findItem<QDeclarativePathView>(canvas->rootObject(), "view");
547     QVERIFY(pathview != 0);
548
549     QDeclarativeRectangle *firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 0);
550     QVERIFY(firstItem);
551     QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
552     QVERIFY(path);
553     QPointF start = path->pointAt(0.0);
554     QPointF offset;//Center of item is at point, but pos is from corner
555     offset.setX(firstItem->width()/2);
556     offset.setY(firstItem->height()/2);
557     QCOMPARE(firstItem->pos() + offset, start);
558     QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
559     QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
560
561     pathview->setCurrentIndex(2);
562
563     firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 2);
564     QTRY_COMPARE(firstItem->pos() + offset, start);
565     QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
566     QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
567
568     pathview->decrementCurrentIndex();
569     QTRY_COMPARE(pathview->currentIndex(), 1);
570     firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 1);
571     QVERIFY(firstItem);
572     QTRY_COMPARE(firstItem->pos() + offset, start);
573
574     pathview->decrementCurrentIndex();
575     QTRY_COMPARE(pathview->currentIndex(), 0);
576     firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 0);
577     QVERIFY(firstItem);
578     QTRY_COMPARE(firstItem->pos() + offset, start);
579
580     pathview->decrementCurrentIndex();
581     QTRY_COMPARE(pathview->currentIndex(), 3);
582     firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 3);
583     QVERIFY(firstItem);
584     QTRY_COMPARE(firstItem->pos() + offset, start);
585
586     pathview->incrementCurrentIndex();
587     QTRY_COMPARE(pathview->currentIndex(), 0);
588     firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 0);
589     QVERIFY(firstItem);
590     QTRY_COMPARE(firstItem->pos() + offset, start);
591
592     delete canvas;
593 }
594
595 void tst_QDeclarativePathView::resetModel()
596 {
597     QDeclarativeView *canvas = createView();
598
599     QStringList strings;
600     strings << "one" << "two" << "three";
601     QStringListModel model(strings);
602
603     QDeclarativeContext *ctxt = canvas->rootContext();
604     ctxt->setContextProperty("testModel", &model);
605
606     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaypath.qml"));
607     qApp->processEvents();
608
609     QDeclarativePathView *pathview = findItem<QDeclarativePathView>(canvas->rootObject(), "view");
610     QVERIFY(pathview != 0);
611
612     QCOMPARE(pathview->count(), model.rowCount());
613
614     for (int i = 0; i < model.rowCount(); ++i) {
615         QDeclarativeText *display = findItem<QDeclarativeText>(pathview, "displayText", i);
616         QVERIFY(display != 0);
617         QCOMPARE(display->text(), strings.at(i));
618     }
619
620     strings.clear();
621     strings << "four" << "five" << "six" << "seven";
622     model.setStringList(strings);
623
624     QCOMPARE(pathview->count(), model.rowCount());
625
626     for (int i = 0; i < model.rowCount(); ++i) {
627         QDeclarativeText *display = findItem<QDeclarativeText>(pathview, "displayText", i);
628         QVERIFY(display != 0);
629         QCOMPARE(display->text(), strings.at(i));
630     }
631 }
632
633 void tst_QDeclarativePathView::propertyChanges()
634 {
635     QDeclarativeView *canvas = createView();
636     QVERIFY(canvas);
637     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
638
639     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("pathView");
640     QVERIFY(pathView);
641
642     QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
643     QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
644
645     QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
646     QCOMPARE(pathView->dragMargin(), 5.0);
647
648     pathView->setPreferredHighlightBegin(0.4);
649     pathView->setPreferredHighlightEnd(0.4);
650     pathView->setDragMargin(20.0);
651
652     QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
653     QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
654     QCOMPARE(pathView->dragMargin(), 20.0);
655
656     QCOMPARE(snapPositionSpy.count(), 1);
657     QCOMPARE(dragMarginSpy.count(), 1);
658
659     pathView->setPreferredHighlightBegin(0.4);
660     pathView->setPreferredHighlightEnd(0.4);
661     pathView->setDragMargin(20.0);
662
663     QCOMPARE(snapPositionSpy.count(), 1);
664     QCOMPARE(dragMarginSpy.count(), 1);
665     delete canvas;
666 }
667
668 void tst_QDeclarativePathView::pathChanges()
669 {
670     QDeclarativeView *canvas = createView();
671     QVERIFY(canvas);
672     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
673
674     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("pathView");
675     QVERIFY(pathView);
676
677     QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
678     QVERIFY(path);
679
680     QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
681     QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
682
683     QCOMPARE(path->startX(), 220.0);
684     QCOMPARE(path->startY(), 200.0);
685
686     path->setStartX(240.0);
687     path->setStartY(220.0);
688
689     QCOMPARE(path->startX(), 240.0);
690     QCOMPARE(path->startY(), 220.0);
691
692     QCOMPARE(startXSpy.count(),1);
693     QCOMPARE(startYSpy.count(),1);
694
695     path->setStartX(240);
696     path->setStartY(220);
697
698     QCOMPARE(startXSpy.count(),1);
699     QCOMPARE(startYSpy.count(),1);
700
701     QDeclarativePath *alternatePath = canvas->rootObject()->findChild<QDeclarativePath*>("alternatePath");
702     QVERIFY(alternatePath);
703
704     QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
705
706     QCOMPARE(pathView->path(), path);
707
708     pathView->setPath(alternatePath);
709     QCOMPARE(pathView->path(), alternatePath);
710     QCOMPARE(pathSpy.count(),1);
711
712     pathView->setPath(alternatePath);
713     QCOMPARE(pathSpy.count(),1);
714
715     QDeclarativePathAttribute *pathAttribute = canvas->rootObject()->findChild<QDeclarativePathAttribute*>("pathAttribute");
716     QVERIFY(pathAttribute);
717
718     QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
719     QCOMPARE(pathAttribute->name(), QString("opacity"));
720
721     pathAttribute->setName("scale");
722     QCOMPARE(pathAttribute->name(), QString("scale"));
723     QCOMPARE(nameSpy.count(),1);
724
725     pathAttribute->setName("scale");
726     QCOMPARE(nameSpy.count(),1);
727     delete canvas;
728 }
729
730 void tst_QDeclarativePathView::componentChanges()
731 {
732     QDeclarativeView *canvas = createView();
733     QVERIFY(canvas);
734     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
735
736     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("pathView");
737     QVERIFY(pathView);
738
739     QDeclarativeComponent delegateComponent(canvas->engine());
740     delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
741
742     QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
743
744     pathView->setDelegate(&delegateComponent);
745     QCOMPARE(pathView->delegate(), &delegateComponent);
746     QCOMPARE(delegateSpy.count(),1);
747
748     pathView->setDelegate(&delegateComponent);
749     QCOMPARE(delegateSpy.count(),1);
750     delete canvas;
751 }
752
753 void tst_QDeclarativePathView::modelChanges()
754 {
755     QDeclarativeView *canvas = createView();
756     QVERIFY(canvas);
757     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
758
759     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("pathView");
760     QVERIFY(pathView);
761
762     QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
763     QVERIFY(alternateModel);
764     QVariant modelVariant = QVariant::fromValue(alternateModel);
765     QSignalSpy modelSpy(pathView, SIGNAL(modelChanged()));
766
767     pathView->setModel(modelVariant);
768     QCOMPARE(pathView->model(), modelVariant);
769     QCOMPARE(modelSpy.count(),1);
770
771     pathView->setModel(modelVariant);
772     QCOMPARE(modelSpy.count(),1);
773
774     pathView->setModel(QVariant());
775     QCOMPARE(modelSpy.count(),2);
776
777     delete canvas;
778 }
779
780 void tst_QDeclarativePathView::pathUpdateOnStartChanged()
781 {
782     QDeclarativeView *canvas = createView();
783     QVERIFY(canvas);
784     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathUpdateOnStartChanged.qml"));
785
786     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("pathView");
787     QVERIFY(pathView);
788
789     QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
790     QVERIFY(path);
791     QCOMPARE(path->startX(), 400.0);
792     QCOMPARE(path->startY(), 300.0);
793
794     QDeclarativeItem *item = findItem<QDeclarativeItem>(pathView, "wrapper", 0);
795     QVERIFY(item);
796     QCOMPARE(item->x(), path->startX() - item->width() / 2.0);
797     QCOMPARE(item->y(), path->startY() - item->height() / 2.0);
798
799     delete canvas;
800 }
801
802 void tst_QDeclarativePathView::package()
803 {
804     QDeclarativeView *canvas = createView();
805     QVERIFY(canvas);
806     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview_package.qml"));
807
808     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("photoPathView");
809     QVERIFY(pathView);
810
811     QDeclarativeItem *item = findItem<QDeclarativeItem>(pathView, "pathItem");
812     QVERIFY(item);
813     QVERIFY(item->scale() != 1.0);
814
815     delete canvas;
816 }
817
818 //QTBUG-13017
819 void tst_QDeclarativePathView::emptyModel()
820 {
821     QDeclarativeView *canvas = createView();
822
823     QStringListModel model;
824
825     QDeclarativeContext *ctxt = canvas->rootContext();
826     ctxt->setContextProperty("emptyModel", &model);
827
828     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/emptymodel.qml"));
829     qApp->processEvents();
830
831     QDeclarativePathView *pathview = qobject_cast<QDeclarativePathView*>(canvas->rootObject());
832     QVERIFY(pathview != 0);
833
834     QCOMPARE(pathview->offset(), qreal(0.0));
835
836     delete canvas;
837 }
838
839 void tst_QDeclarativePathView::closed()
840 {
841     QDeclarativeEngine engine;
842
843     {
844         QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/openPath.qml"));
845         QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
846         QVERIFY(obj);
847         QCOMPARE(obj->isClosed(), false);
848         delete obj;
849     }
850
851     {
852         QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/closedPath.qml"));
853         QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
854         QVERIFY(obj);
855         QCOMPARE(obj->isClosed(), true);
856         delete obj;
857     }
858 }
859
860 // QTBUG-14239
861 void tst_QDeclarativePathView::pathUpdate()
862 {
863     QDeclarativeView *canvas = createView();
864     QVERIFY(canvas);
865     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathUpdate.qml"));
866
867     QDeclarativePathView *pathView = canvas->rootObject()->findChild<QDeclarativePathView*>("pathView");
868     QVERIFY(pathView);
869
870     QDeclarativeItem *item = findItem<QDeclarativeItem>(pathView, "wrapper", 0);
871     QVERIFY(item);
872     QCOMPARE(item->x(), 150.0);
873
874     delete canvas;
875 }
876
877 void tst_QDeclarativePathView::visualDataModel()
878 {
879     QDeclarativeEngine engine;
880     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/vdm.qml"));
881
882     QDeclarativePathView *obj = qobject_cast<QDeclarativePathView*>(c.create());
883     QVERIFY(obj != 0);
884
885     QCOMPARE(obj->count(), 3);
886
887     delete obj;
888 }
889
890 void tst_QDeclarativePathView::undefinedPath()
891 {
892     QDeclarativeEngine engine;
893     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/undefinedpath.qml"));
894
895     QDeclarativePathView *obj = qobject_cast<QDeclarativePathView*>(c.create());
896     QVERIFY(obj != 0);
897
898     QCOMPARE(obj->count(), 3);
899
900     delete obj;
901 }
902
903 void tst_QDeclarativePathView::mouseDrag()
904 {
905     QDeclarativeView *canvas = createView();
906     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragpath.qml"));
907     canvas->show();
908     QApplication::setActiveWindow(canvas);
909     QTest::qWaitForWindowShown(canvas);
910     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
911
912     QDeclarativePathView *pathview = qobject_cast<QDeclarativePathView*>(canvas->rootObject());
913     QVERIFY(pathview != 0);
914
915     int current = pathview->currentIndex();
916
917     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(10,100)));
918
919     {
920         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(30,100)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
921         QApplication::sendEvent(canvas->viewport(), &mv);
922     }
923     {
924         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(90,100)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
925         QApplication::sendEvent(canvas->viewport(), &mv);
926     }
927
928     QVERIFY(pathview->currentIndex() != current);
929
930     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(40,100)));
931
932     delete canvas;
933 }
934
935 void tst_QDeclarativePathView::treeModel()
936 {
937     QDeclarativeView *canvas = createView();
938
939     QStandardItemModel model;
940     initStandardTreeModel(&model);
941     canvas->engine()->rootContext()->setContextProperty("myModel", &model);
942
943     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/treemodel.qml"));
944
945     QDeclarativePathView *pathview = qobject_cast<QDeclarativePathView*>(canvas->rootObject());
946     QVERIFY(pathview != 0);
947     QCOMPARE(pathview->count(), 3);
948
949     QDeclarativeText *item = findItem<QDeclarativeText>(pathview, "wrapper", 0);
950     QVERIFY(item);
951     QCOMPARE(item->text(), QLatin1String("Row 1 Item"));
952
953     QVERIFY(QMetaObject::invokeMethod(pathview, "setRoot", Q_ARG(QVariant, 1)));
954     QCOMPARE(pathview->count(), 1);
955
956     QTRY_VERIFY(item = findItem<QDeclarativeText>(pathview, "wrapper", 0));
957     QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
958
959     delete canvas;
960 }
961
962 void tst_QDeclarativePathView::changePreferredHighlight()
963 {
964     QDeclarativeView *canvas = createView();
965     canvas->setFixedSize(400,200);
966     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/dragpath.qml"));
967     canvas->show();
968     QApplication::setActiveWindow(canvas);
969     QTest::qWaitForWindowShown(canvas);
970     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
971
972     QDeclarativePathView *pathview = qobject_cast<QDeclarativePathView*>(canvas->rootObject());
973     QVERIFY(pathview != 0);
974
975     int current = pathview->currentIndex();
976     QCOMPARE(current, 0);
977
978     QDeclarativeRectangle *firstItem = findItem<QDeclarativeRectangle>(pathview, "wrapper", 0);
979     QVERIFY(firstItem);
980     QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
981     QVERIFY(path);
982     QPointF start = path->pointAt(0.5);
983     start.setX(qRound(start.x()));
984     start.setY(qRound(start.y()));
985     QPointF offset;//Center of item is at point, but pos is from corner
986     offset.setX(firstItem->width()/2);
987     offset.setY(firstItem->height()/2);
988     QTRY_COMPARE(firstItem->pos() + offset, start);
989
990     pathview->setPreferredHighlightBegin(0.8);
991     pathview->setPreferredHighlightEnd(0.8);
992     start = path->pointAt(0.8);
993     start.setX(qRound(start.x()));
994     start.setY(qRound(start.y()));
995     QTRY_COMPARE(firstItem->pos() + offset, start);
996     QCOMPARE(pathview->currentIndex(), 0);
997
998     delete canvas;
999 }
1000
1001 QDeclarativeView *tst_QDeclarativePathView::createView()
1002 {
1003     QDeclarativeView *canvas = new QDeclarativeView(0);
1004     canvas->setFixedSize(240,320);
1005
1006     return canvas;
1007 }
1008
1009 /*
1010    Find an item with the specified objectName.  If index is supplied then the
1011    item must also evaluate the {index} expression equal to index
1012  */
1013 template<typename T>
1014 T *tst_QDeclarativePathView::findItem(QGraphicsObject *parent, const QString &objectName, int index)
1015 {
1016     const QMetaObject &mo = T::staticMetaObject;
1017     //qDebug() << parent->childItems().count() << "children";
1018     for (int i = 0; i < parent->childItems().count(); ++i) {
1019         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
1020         if(!item)
1021             continue;
1022         //qDebug() << "try" << item;
1023         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
1024             if (index != -1) {
1025                 QDeclarativeExpression e(qmlContext(item), item, "index");
1026                 if (e.evaluate().toInt() == index)
1027                     return static_cast<T*>(item);
1028             } else {
1029                 return static_cast<T*>(item);
1030             }
1031         }
1032         item = findItem<T>(item, objectName, index);
1033         if (item)
1034             return static_cast<T*>(item);
1035     }
1036
1037     return 0;
1038 }
1039
1040 template<typename T>
1041 QList<T*> tst_QDeclarativePathView::findItems(QGraphicsObject *parent, const QString &objectName)
1042 {
1043     QList<T*> items;
1044     const QMetaObject &mo = T::staticMetaObject;
1045     //qDebug() << parent->QGraphicsObject::children().count() << "children";
1046     for (int i = 0; i < parent->childItems().count(); ++i) {
1047         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
1048         if(!item)
1049             continue;
1050         //qDebug() << "try" << item;
1051         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
1052             items.append(static_cast<T*>(item));
1053         items += findItems<T>(item, objectName);
1054     }
1055
1056     return items;
1057 }
1058
1059 QTEST_MAIN(tst_QDeclarativePathView)
1060
1061 #include "tst_qdeclarativepathview.moc"