87d48250143a2a514f35dce57531d58e3656a6eb
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick1 / qdeclarativepathview / tst_qdeclarativepathview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <QtQuick1/qdeclarativeview.h>
44 #include <QtDeclarative/qdeclarativeengine.h>
45 #include <QtDeclarative/qdeclarativecomponent.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeexpression.h>
48 #include <QtQuick1/private/qdeclarativepathview_p.h>
49 #include <QtQuick1/private/qdeclarativepath_p.h>
50 #include <QtQuick1/private/qdeclarativetext_p.h>
51 #include <QtQuick1/private/qdeclarativerectangle_p.h>
52 #include <QtDeclarative/private/qdeclarativevaluetype_p.h>
53 #include <QAbstractListModel>
54 #include <QStringListModel>
55 #include <QStandardItemModel>
56 #include <QFile>
57
58 static void initStandardTreeModel(QStandardItemModel *model)
59 {
60     QStandardItem *item;
61     item = new QStandardItem(QLatin1String("Row 1 Item"));
62     model->insertRow(0, item);
63
64     item = new QStandardItem(QLatin1String("Row 2 Item"));
65     item->setCheckable(true);
66     model->insertRow(1, item);
67
68     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
69     item->setChild(0, childItem);
70
71     item = new QStandardItem(QLatin1String("Row 3 Item"));
72     item->setIcon(QIcon());
73     model->insertRow(2, item);
74 }
75
76
77 class tst_QDeclarative1PathView : public QObject
78 {
79     Q_OBJECT
80 public:
81     tst_QDeclarative1PathView();
82
83 private slots:
84     void initValues();
85     void items();
86     void dataModel();
87     void pathview2();
88     void pathview3();
89     void path();
90     void pathMoved();
91     void setCurrentIndex();
92     void resetModel();
93     void propertyChanges();
94     void pathChanges();
95     void componentChanges();
96     void modelChanges();
97     void pathUpdateOnStartChanged();
98     void package();
99     void emptyModel();
100     void closed();
101     void pathUpdate();
102     void visualDataModel();
103     void undefinedPath();
104     void mouseDrag();
105     void treeModel();
106     void changePreferredHighlight();
107
108 private:
109     QDeclarativeView *createView();
110     template<typename T>
111     T *findItem(QGraphicsObject *parent, const QString &objectName, int index=-1);
112     template<typename T>
113     QList<T*> findItems(QGraphicsObject *parent, const QString &objectName);
114 };
115
116 class TestObject : public QObject
117 {
118     Q_OBJECT
119
120     Q_PROPERTY(bool error READ error WRITE setError)
121     Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
122     Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
123
124 public:
125     TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
126
127     bool error() const { return mError; }
128     void setError(bool err) { mError = err; }
129
130     bool useModel() const { return mUseModel; }
131     void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
132
133     int pathItemCount() const { return mPathItemCount; }
134     void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
135
136 signals:
137     void useModelChanged();
138     void pathItemCountChanged();
139
140 private:
141     bool mError;
142     bool mUseModel;
143     int mPathItemCount;
144 };
145
146 class TestModel : public QAbstractListModel
147 {
148 public:
149     enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
150
151     TestModel(QObject *parent=0) : QAbstractListModel(parent) {
152         QHash<int, QByteArray> roles;
153         roles[Name] = "name";
154         roles[Number] = "number";
155         setRoleNames(roles);
156     }
157
158     int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
159     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
160         QVariant rv;
161         if (role == Name)
162             rv = list.at(index.row()).first;
163         else if (role == Number)
164             rv = list.at(index.row()).second;
165
166         return rv;
167     }
168
169     int count() const { return rowCount(); }
170     QString name(int index) const { return list.at(index).first; }
171     QString number(int index) const { return list.at(index).second; }
172
173     void addItem(const QString &name, const QString &number) {
174         beginInsertRows(QModelIndex(), list.count(), list.count());
175         list.append(QPair<QString,QString>(name, number));
176         endInsertRows();
177     }
178
179     void insertItem(int index, const QString &name, const QString &number) {
180         beginInsertRows(QModelIndex(), index, index);
181         list.insert(index, QPair<QString,QString>(name, number));
182         endInsertRows();
183     }
184
185     void removeItem(int index) {
186         beginRemoveRows(QModelIndex(), index, index);
187         list.removeAt(index);
188         endRemoveRows();
189     }
190
191     void moveItem(int from, int to) {
192         beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
193         list.move(from, to);
194         endMoveRows();
195     }
196
197     void modifyItem(int idx, const QString &name, const QString &number) {
198         list[idx] = QPair<QString,QString>(name, number);
199         emit dataChanged(index(idx,0), index(idx,0));
200     }
201
202 private:
203     QList<QPair<QString,QString> > list;
204 };
205
206
207 tst_QDeclarative1PathView::tst_QDeclarative1PathView()
208 {
209 }
210
211 void tst_QDeclarative1PathView::initValues()
212 {
213     QDeclarativeEngine engine;
214     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview1.qml"));
215     QDeclarative1PathView *obj = qobject_cast<QDeclarative1PathView*>(c.create());
216
217     QVERIFY(obj != 0);
218     QVERIFY(obj->path() == 0);
219     QVERIFY(obj->delegate() == 0);
220     QCOMPARE(obj->model(), QVariant());
221     QCOMPARE(obj->currentIndex(), 0);
222     QCOMPARE(obj->offset(), 0.);
223     QCOMPARE(obj->preferredHighlightBegin(), 0.);
224     QCOMPARE(obj->dragMargin(), 0.);
225     QCOMPARE(obj->count(), 0);
226     QCOMPARE(obj->pathItemCount(), -1);
227 }
228
229 void tst_QDeclarative1PathView::items()
230 {
231     QDeclarativeView *canvas = createView();
232
233     TestModel model;
234     model.addItem("Fred", "12345");
235     model.addItem("John", "2345");
236     model.addItem("Bob", "54321");
237     model.addItem("Bill", "4321");
238
239     QDeclarativeContext *ctxt = canvas->rootContext();
240     ctxt->setContextProperty("testModel", &model);
241
242     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
243     qApp->processEvents();
244
245     QDeclarative1PathView *pathview = findItem<QDeclarative1PathView>(canvas->rootObject(), "view");
246     QVERIFY(pathview != 0);
247
248     QCOMPARE(pathview->count(), model.count());
249     QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
250     QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
251
252     for (int i = 0; i < model.count(); ++i) {
253         QDeclarative1Text *name = findItem<QDeclarative1Text>(pathview, "textName", i);
254         QVERIFY(name != 0);
255         QCOMPARE(name->text(), model.name(i));
256         QDeclarative1Text *number = findItem<QDeclarative1Text>(pathview, "textNumber", i);
257         QVERIFY(number != 0);
258         QCOMPARE(number->text(), model.number(i));
259     }
260
261     QDeclarative1Path *path = qobject_cast<QDeclarative1Path*>(pathview->path());
262     QVERIFY(path);
263
264     QVERIFY(pathview->highlightItem());
265     QPointF start = path->pointAt(0.0);
266     QPointF offset;
267     offset.setX(pathview->highlightItem()->width()/2);
268     offset.setY(pathview->highlightItem()->height()/2);
269     QCOMPARE(pathview->highlightItem()->pos() + offset, start);
270
271     delete canvas;
272 }
273
274 void tst_QDeclarative1PathView::pathview2()
275 {
276     QDeclarativeEngine engine;
277     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview2.qml"));
278     QDeclarative1PathView *obj = qobject_cast<QDeclarative1PathView*>(c.create());
279
280     QVERIFY(obj != 0);
281     QVERIFY(obj->path() != 0);
282     QVERIFY(obj->delegate() != 0);
283     QVERIFY(obj->model() != QVariant());
284     QCOMPARE(obj->currentIndex(), 0);
285     QCOMPARE(obj->offset(), 0.);
286     QCOMPARE(obj->preferredHighlightBegin(), 0.);
287     QCOMPARE(obj->dragMargin(), 0.);
288     QCOMPARE(obj->count(), 8);
289     QCOMPARE(obj->pathItemCount(), 10);
290 }
291
292 void tst_QDeclarative1PathView::pathview3()
293 {
294     QDeclarativeEngine engine;
295     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathview3.qml"));
296     QDeclarative1PathView *obj = qobject_cast<QDeclarative1PathView*>(c.create());
297
298     QVERIFY(obj != 0);
299     QVERIFY(obj->path() != 0);
300     QVERIFY(obj->delegate() != 0);
301     QVERIFY(obj->model() != QVariant());
302     QCOMPARE(obj->currentIndex(), 0);
303     QCOMPARE(obj->offset(), 1.0);
304     QCOMPARE(obj->preferredHighlightBegin(), 0.5);
305     QCOMPARE(obj->dragMargin(), 24.);
306     QCOMPARE(obj->count(), 8);
307     QCOMPARE(obj->pathItemCount(), 4);
308 }
309
310 void tst_QDeclarative1PathView::path()
311 {
312     QDeclarativeEngine engine;
313     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/pathtest.qml"));
314     QDeclarative1Path *obj = qobject_cast<QDeclarative1Path*>(c.create());
315
316     QVERIFY(obj != 0);
317     QCOMPARE(obj->startX(), 120.);
318     QCOMPARE(obj->startY(), 100.);
319     QVERIFY(obj->path() != QPainterPath());
320
321     QDeclarativeListReference list(obj, "pathElements");
322     QCOMPARE(list.count(), 5);
323
324     QDeclarative1PathAttribute* attr = qobject_cast<QDeclarative1PathAttribute*>(list.at(0));
325     QVERIFY(attr != 0);
326     QCOMPARE(attr->name(), QString("scale"));
327     QCOMPARE(attr->value(), 1.0);
328
329     QDeclarative1PathQuad* quad = qobject_cast<QDeclarative1PathQuad*>(list.at(1));
330     QVERIFY(quad != 0);
331     QCOMPARE(quad->x(), 120.);
332     QCOMPARE(quad->y(), 25.);
333     QCOMPARE(quad->controlX(), 260.);
334     QCOMPARE(quad->controlY(), 75.);
335
336     QDeclarative1PathPercent* perc = qobject_cast<QDeclarative1PathPercent*>(list.at(2));
337     QVERIFY(perc != 0);
338     QCOMPARE(perc->value(), 0.3);
339
340     QDeclarative1PathLine* line = qobject_cast<QDeclarative1PathLine*>(list.at(3));
341     QVERIFY(line != 0);
342     QCOMPARE(line->x(), 120.);
343     QCOMPARE(line->y(), 100.);
344
345     QDeclarative1PathCubic* cubic = qobject_cast<QDeclarative1PathCubic*>(list.at(4));
346     QVERIFY(cubic != 0);
347     QCOMPARE(cubic->x(), 180.);
348     QCOMPARE(cubic->y(), 0.);
349     QCOMPARE(cubic->control1X(), -10.);
350     QCOMPARE(cubic->control1Y(), 90.);
351     QCOMPARE(cubic->control2X(), 210.);
352     QCOMPARE(cubic->control2Y(), 90.);
353 }
354
355 void tst_QDeclarative1PathView::dataModel()
356 {
357     QDeclarativeView *canvas = createView();
358
359     QDeclarativeContext *ctxt = canvas->rootContext();
360     TestObject *testObject = new TestObject;
361     ctxt->setContextProperty("testObject", testObject);
362
363     TestModel model;
364     model.addItem("red", "1");
365     model.addItem("green", "2");
366     model.addItem("blue", "3");
367     model.addItem("purple", "4");
368     model.addItem("gray", "5");
369     model.addItem("brown", "6");
370     model.addItem("yellow", "7");
371     model.addItem("thistle", "8");
372     model.addItem("cyan", "9");
373     model.addItem("peachpuff", "10");
374     model.addItem("powderblue", "11");
375     model.addItem("gold", "12");
376     model.addItem("sandybrown", "13");
377
378     ctxt->setContextProperty("testData", &model);
379
380     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/datamodel.qml"));
381     qApp->processEvents();
382
383     QDeclarative1PathView *pathview = qobject_cast<QDeclarative1PathView*>(canvas->rootObject());
384     QVERIFY(pathview != 0);
385
386     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
387     QVERIFY(testObject->error() == false);
388
389     QDeclarativeItem *item = findItem<QDeclarativeItem>(pathview, "wrapper", 0);
390     QVERIFY(item);
391     QCOMPARE(item->x(), 110.0);
392     QCOMPARE(item->y(), 10.0);
393
394     model.insertItem(4, "orange", "10");
395     QTest::qWait(100);
396
397     QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
398     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 14);
399
400     QVERIFY(pathview->currentIndex() == 0);
401
402     QDeclarative1Text *text = findItem<QDeclarative1Text>(pathview, "myText", 4);
403     QVERIFY(text);
404     QCOMPARE(text->text(), model.name(4));
405
406     model.removeItem(2);
407     QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
408     text = findItem<QDeclarative1Text>(pathview, "myText", 2);
409     QVERIFY(text);
410     QCOMPARE(text->text(), model.name(2));
411
412     testObject->setPathItemCount(5);
413     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
414     QVERIFY(testObject->error() == false);
415
416     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
417
418     QDeclarative1Rectangle *testItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 4);
419     QVERIFY(testItem != 0);
420     testItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 5);
421     QVERIFY(testItem == 0);
422
423     pathview->setCurrentIndex(1);
424
425     model.insertItem(2, "pink", "2");
426     QTest::qWait(100);
427
428     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
429     QVERIFY(pathview->currentIndex() == 1);
430
431     text = findItem<QDeclarative1Text>(pathview, "myText", 2);
432     QVERIFY(text);
433     QCOMPARE(text->text(), model.name(2));
434
435     model.removeItem(3);
436     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
437     text = findItem<QDeclarative1Text>(pathview, "myText", 3);
438     QVERIFY(text);
439     QCOMPARE(text->text(), model.name(3));
440
441     model.moveItem(3, 5);
442     QTRY_COMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
443     QList<QDeclarativeItem*> items = findItems<QDeclarativeItem>(pathview, "wrapper");
444     foreach (QDeclarativeItem *item, items) {
445         QVERIFY(item->property("onPath").toBool());
446     }
447
448     // QTBUG-14199
449     pathview->setOffset(7);
450     pathview->setOffset(0);
451     QCOMPARE(findItems<QDeclarativeItem>(pathview, "wrapper").count(), 5);
452
453     pathview->setCurrentIndex(model.count()-1);
454     model.removeItem(model.count()-1);
455     QCOMPARE(pathview->currentIndex(), model.count()-1);
456
457     // QTBUG-18825
458     // Confirm that the target offset is adjusted when removing items
459     pathview->setCurrentIndex(model.count()-1);
460     QTRY_COMPARE(pathview->offset(), 1.);
461     pathview->setCurrentIndex(model.count()-5);
462     model.removeItem(model.count()-1);
463     model.removeItem(model.count()-1);
464     model.removeItem(model.count()-1);
465     QTRY_COMPARE(pathview->offset(), 2.);
466
467     delete canvas;
468     delete testObject;
469 }
470
471 void tst_QDeclarative1PathView::pathMoved()
472 {
473     QDeclarativeView *canvas = createView();
474
475     TestModel model;
476     model.addItem("Ben", "12345");
477     model.addItem("Bohn", "2345");
478     model.addItem("Bob", "54321");
479     model.addItem("Bill", "4321");
480
481     QDeclarativeContext *ctxt = canvas->rootContext();
482     ctxt->setContextProperty("testModel", &model);
483
484     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
485     qApp->processEvents();
486
487     QDeclarative1PathView *pathview = findItem<QDeclarative1PathView>(canvas->rootObject(), "view");
488     QVERIFY(pathview != 0);
489
490     QDeclarative1Rectangle *firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 0);
491     QVERIFY(firstItem);
492     QDeclarative1Path *path = qobject_cast<QDeclarative1Path*>(pathview->path());
493     QVERIFY(path);
494     QPointF start = path->pointAt(0.0);
495     QPointF offset;//Center of item is at point, but pos is from corner
496     offset.setX(firstItem->width()/2);
497     offset.setY(firstItem->height()/2);
498     QCOMPARE(firstItem->pos() + offset, start);
499     pathview->setOffset(1.0);
500
501     for(int i=0; i<model.count(); i++){
502         QDeclarative1Rectangle *curItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", i);
503         QPointF itemPos(path->pointAt(0.25 + i*0.25));
504         QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
505     }
506
507     pathview->setOffset(0.0);
508     QCOMPARE(firstItem->pos() + offset, start);
509
510     // Change delegate size
511     pathview->setOffset(0.1);
512     pathview->setOffset(0.0);
513     canvas->rootObject()->setProperty("delegateWidth", 30);
514     QCOMPARE(firstItem->width(), 30.0);
515     offset.setX(firstItem->width()/2);
516     QTRY_COMPARE(firstItem->pos() + offset, start);
517
518     // Change delegate scale
519     pathview->setOffset(0.1);
520     pathview->setOffset(0.0);
521     canvas->rootObject()->setProperty("delegateScale", 1.2);
522     QTRY_COMPARE(firstItem->pos() + offset, start);
523
524     delete canvas;
525 }
526
527 void tst_QDeclarative1PathView::setCurrentIndex()
528 {
529     QDeclarativeView *canvas = createView();
530
531     TestModel model;
532     model.addItem("Ben", "12345");
533     model.addItem("Bohn", "2345");
534     model.addItem("Bob", "54321");
535     model.addItem("Bill", "4321");
536
537     QDeclarativeContext *ctxt = canvas->rootContext();
538     ctxt->setContextProperty("testModel", &model);
539
540     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview0.qml"));
541     qApp->processEvents();
542
543     QDeclarative1PathView *pathview = findItem<QDeclarative1PathView>(canvas->rootObject(), "view");
544     QVERIFY(pathview != 0);
545
546     QDeclarative1Rectangle *firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 0);
547     QVERIFY(firstItem);
548     QDeclarative1Path *path = qobject_cast<QDeclarative1Path*>(pathview->path());
549     QVERIFY(path);
550     QPointF start = path->pointAt(0.0);
551     QPointF offset;//Center of item is at point, but pos is from corner
552     offset.setX(firstItem->width()/2);
553     offset.setY(firstItem->height()/2);
554     QCOMPARE(firstItem->pos() + offset, start);
555     QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
556     QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
557
558     pathview->setCurrentIndex(2);
559
560     firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 2);
561     QTRY_COMPARE(firstItem->pos() + offset, start);
562     QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
563     QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
564
565     pathview->decrementCurrentIndex();
566     QTRY_COMPARE(pathview->currentIndex(), 1);
567     firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 1);
568     QVERIFY(firstItem);
569     QTRY_COMPARE(firstItem->pos() + offset, start);
570
571     pathview->decrementCurrentIndex();
572     QTRY_COMPARE(pathview->currentIndex(), 0);
573     firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 0);
574     QVERIFY(firstItem);
575     QTRY_COMPARE(firstItem->pos() + offset, start);
576
577     pathview->decrementCurrentIndex();
578     QTRY_COMPARE(pathview->currentIndex(), 3);
579     firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 3);
580     QVERIFY(firstItem);
581     QTRY_COMPARE(firstItem->pos() + offset, start);
582
583     pathview->incrementCurrentIndex();
584     QTRY_COMPARE(pathview->currentIndex(), 0);
585     firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 0);
586     QVERIFY(firstItem);
587     QTRY_COMPARE(firstItem->pos() + offset, start);
588
589     delete canvas;
590 }
591
592 void tst_QDeclarative1PathView::resetModel()
593 {
594     QDeclarativeView *canvas = createView();
595
596     QStringList strings;
597     strings << "one" << "two" << "three";
598     QStringListModel model(strings);
599
600     QDeclarativeContext *ctxt = canvas->rootContext();
601     ctxt->setContextProperty("testModel", &model);
602
603     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaypath.qml"));
604     qApp->processEvents();
605
606     QDeclarative1PathView *pathview = findItem<QDeclarative1PathView>(canvas->rootObject(), "view");
607     QVERIFY(pathview != 0);
608
609     QCOMPARE(pathview->count(), model.rowCount());
610
611     for (int i = 0; i < model.rowCount(); ++i) {
612         QDeclarative1Text *display = findItem<QDeclarative1Text>(pathview, "displayText", i);
613         QVERIFY(display != 0);
614         QCOMPARE(display->text(), strings.at(i));
615     }
616
617     strings.clear();
618     strings << "four" << "five" << "six" << "seven";
619     model.setStringList(strings);
620
621     QCOMPARE(pathview->count(), model.rowCount());
622
623     for (int i = 0; i < model.rowCount(); ++i) {
624         QDeclarative1Text *display = findItem<QDeclarative1Text>(pathview, "displayText", i);
625         QVERIFY(display != 0);
626         QCOMPARE(display->text(), strings.at(i));
627     }
628
629     delete canvas;
630 }
631
632 void tst_QDeclarative1PathView::propertyChanges()
633 {
634     QDeclarativeView *canvas = createView();
635     QVERIFY(canvas);
636     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
637
638     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("pathView");
639     QVERIFY(pathView);
640
641     QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
642     QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
643
644     QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
645     QCOMPARE(pathView->dragMargin(), 5.0);
646
647     pathView->setPreferredHighlightBegin(0.4);
648     pathView->setPreferredHighlightEnd(0.4);
649     pathView->setDragMargin(20.0);
650
651     QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
652     QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
653     QCOMPARE(pathView->dragMargin(), 20.0);
654
655     QCOMPARE(snapPositionSpy.count(), 1);
656     QCOMPARE(dragMarginSpy.count(), 1);
657
658     pathView->setPreferredHighlightBegin(0.4);
659     pathView->setPreferredHighlightEnd(0.4);
660     pathView->setDragMargin(20.0);
661
662     QCOMPARE(snapPositionSpy.count(), 1);
663     QCOMPARE(dragMarginSpy.count(), 1);
664     delete canvas;
665 }
666
667 void tst_QDeclarative1PathView::pathChanges()
668 {
669     QDeclarativeView *canvas = createView();
670     QVERIFY(canvas);
671     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
672
673     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("pathView");
674     QVERIFY(pathView);
675
676     QDeclarative1Path *path = canvas->rootObject()->findChild<QDeclarative1Path*>("path");
677     QVERIFY(path);
678
679     QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
680     QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
681
682     QCOMPARE(path->startX(), 220.0);
683     QCOMPARE(path->startY(), 200.0);
684
685     path->setStartX(240.0);
686     path->setStartY(220.0);
687
688     QCOMPARE(path->startX(), 240.0);
689     QCOMPARE(path->startY(), 220.0);
690
691     QCOMPARE(startXSpy.count(),1);
692     QCOMPARE(startYSpy.count(),1);
693
694     path->setStartX(240);
695     path->setStartY(220);
696
697     QCOMPARE(startXSpy.count(),1);
698     QCOMPARE(startYSpy.count(),1);
699
700     QDeclarative1Path *alternatePath = canvas->rootObject()->findChild<QDeclarative1Path*>("alternatePath");
701     QVERIFY(alternatePath);
702
703     QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
704
705     QCOMPARE(pathView->path(), path);
706
707     pathView->setPath(alternatePath);
708     QCOMPARE(pathView->path(), alternatePath);
709     QCOMPARE(pathSpy.count(),1);
710
711     pathView->setPath(alternatePath);
712     QCOMPARE(pathSpy.count(),1);
713
714     QDeclarative1PathAttribute *pathAttribute = canvas->rootObject()->findChild<QDeclarative1PathAttribute*>("pathAttribute");
715     QVERIFY(pathAttribute);
716
717     QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
718     QCOMPARE(pathAttribute->name(), QString("opacity"));
719
720     pathAttribute->setName("scale");
721     QCOMPARE(pathAttribute->name(), QString("scale"));
722     QCOMPARE(nameSpy.count(),1);
723
724     pathAttribute->setName("scale");
725     QCOMPARE(nameSpy.count(),1);
726     delete canvas;
727 }
728
729 void tst_QDeclarative1PathView::componentChanges()
730 {
731     QDeclarativeView *canvas = createView();
732     QVERIFY(canvas);
733     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
734
735     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("pathView");
736     QVERIFY(pathView);
737
738     QDeclarativeComponent delegateComponent(canvas->engine());
739     delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
740
741     QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
742
743     pathView->setDelegate(&delegateComponent);
744     QCOMPARE(pathView->delegate(), &delegateComponent);
745     QCOMPARE(delegateSpy.count(),1);
746
747     pathView->setDelegate(&delegateComponent);
748     QCOMPARE(delegateSpy.count(),1);
749     delete canvas;
750 }
751
752 void tst_QDeclarative1PathView::modelChanges()
753 {
754     QDeclarativeView *canvas = createView();
755     QVERIFY(canvas);
756     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychanges.qml"));
757
758     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("pathView");
759     QVERIFY(pathView);
760
761 //    QDeclarative1ListModel *alternateModel = canvas->rootObject()->findChild<QDeclarative1ListModel*>("alternateModel");
762     QObject *alternateModel = canvas->rootObject()->findChild<QObject*>("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_QDeclarative1PathView::pathUpdateOnStartChanged()
781 {
782     QDeclarativeView *canvas = createView();
783     QVERIFY(canvas);
784     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathUpdateOnStartChanged.qml"));
785
786     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("pathView");
787     QVERIFY(pathView);
788
789     QDeclarative1Path *path = canvas->rootObject()->findChild<QDeclarative1Path*>("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_QDeclarative1PathView::package()
803 {
804     QDeclarativeView *canvas = createView();
805     QVERIFY(canvas);
806     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathview_package.qml"));
807
808     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("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_QDeclarative1PathView::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     QDeclarative1PathView *pathview = qobject_cast<QDeclarative1PathView*>(canvas->rootObject());
832     QVERIFY(pathview != 0);
833
834     QCOMPARE(pathview->offset(), qreal(0.0));
835
836     delete canvas;
837 }
838
839 void tst_QDeclarative1PathView::closed()
840 {
841     QDeclarativeEngine engine;
842
843     {
844         QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/openPath.qml"));
845         QDeclarative1Path *obj = qobject_cast<QDeclarative1Path*>(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         QDeclarative1Path *obj = qobject_cast<QDeclarative1Path*>(c.create());
854         QVERIFY(obj);
855         QCOMPARE(obj->isClosed(), true);
856         delete obj;
857     }
858 }
859
860 // QTBUG-14239
861 void tst_QDeclarative1PathView::pathUpdate()
862 {
863     QDeclarativeView *canvas = createView();
864     QVERIFY(canvas);
865     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pathUpdate.qml"));
866
867     QDeclarative1PathView *pathView = canvas->rootObject()->findChild<QDeclarative1PathView*>("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_QDeclarative1PathView::visualDataModel()
878 {
879     QDeclarativeEngine engine;
880     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/vdm.qml"));
881
882     QDeclarative1PathView *obj = qobject_cast<QDeclarative1PathView*>(c.create());
883     QVERIFY(obj != 0);
884
885     QCOMPARE(obj->count(), 3);
886
887     delete obj;
888 }
889
890 void tst_QDeclarative1PathView::undefinedPath()
891 {
892     QDeclarativeEngine engine;
893     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/undefinedpath.qml"));
894
895     QDeclarative1PathView *obj = qobject_cast<QDeclarative1PathView*>(c.create());
896     QVERIFY(obj != 0);
897
898     QCOMPARE(obj->count(), 3);
899
900     delete obj;
901 }
902
903 void tst_QDeclarative1PathView::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     QDeclarative1PathView *pathview = qobject_cast<QDeclarative1PathView*>(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_QDeclarative1PathView::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     QDeclarative1PathView *pathview = qobject_cast<QDeclarative1PathView*>(canvas->rootObject());
946     QVERIFY(pathview != 0);
947     QCOMPARE(pathview->count(), 3);
948
949     QDeclarative1Text *item = findItem<QDeclarative1Text>(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<QDeclarative1Text>(pathview, "wrapper", 0));
957     QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
958
959     delete canvas;
960 }
961
962 void tst_QDeclarative1PathView::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     QDeclarative1PathView *pathview = qobject_cast<QDeclarative1PathView*>(canvas->rootObject());
973     QVERIFY(pathview != 0);
974
975     int current = pathview->currentIndex();
976     QCOMPARE(current, 0);
977
978     QDeclarative1Rectangle *firstItem = findItem<QDeclarative1Rectangle>(pathview, "wrapper", 0);
979     QVERIFY(firstItem);
980     QDeclarative1Path *path = qobject_cast<QDeclarative1Path*>(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_QDeclarative1PathView::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_QDeclarative1PathView::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_QDeclarative1PathView::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_QDeclarative1PathView)
1060
1061 #include "tst_qdeclarativepathview.moc"