146dca8a5b7da07468f6d367988fdbe60ab9ca2e
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick1 / qdeclarativerepeater / tst_qdeclarativerepeater.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 <QtTest/QSignalSpy>
44 #include <QtDeclarative/qdeclarativeengine.h>
45 #include <QtQuick1/qdeclarativeview.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeexpression.h>
48 #include <QtQuick1/private/qdeclarativerepeater_p.h>
49 #include <QtQuick1/private/qdeclarativetext_p.h>
50
51 inline QUrl TEST_FILE(const QString &filename)
52 {
53     return QUrl::fromLocalFile(QLatin1String(SRCDIR) + QLatin1String("/data/") + filename);
54 }
55
56 class tst_QDeclarative1Repeater : public QObject
57 {
58     Q_OBJECT
59 public:
60     tst_QDeclarative1Repeater();
61
62 private slots:
63     void numberModel();
64     void objectList();
65     void stringList();
66     void dataModel_adding();
67     void dataModel_removing();
68     void dataModel_changes();
69     void itemModel();
70     void resetModel();
71     void modelChanged();
72     void properties();
73     void testQtQuick11Attributes();
74     void testQtQuick11Attributes_data();
75
76 private:
77     QDeclarativeView *createView();
78     template<typename T>
79     T *findItem(QGraphicsObject *parent, const QString &objectName, int index);
80     template<typename T>
81     T *findItem(QGraphicsObject *parent, const QString &id);
82 };
83
84 class TestObject : public QObject
85 {
86     Q_OBJECT
87
88     Q_PROPERTY(bool error READ error WRITE setError)
89     Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
90
91 public:
92     TestObject() : QObject(), mError(true), mUseModel(false) {}
93
94     bool error() const { return mError; }
95     void setError(bool err) { mError = err; }
96
97     bool useModel() const { return mUseModel; }
98     void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
99
100 signals:
101     void useModelChanged();
102
103 private:
104     bool mError;
105     bool mUseModel;
106 };
107
108 class TestModel : public QAbstractListModel
109 {
110 public:
111     enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
112
113     TestModel(QObject *parent=0) : QAbstractListModel(parent) {
114         QHash<int, QByteArray> roles;
115         roles[Name] = "name";
116         roles[Number] = "number";
117         setRoleNames(roles);
118     }
119
120     int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
121     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
122         QVariant rv;
123         if (role == Name)
124             rv = list.at(index.row()).first;
125         else if (role == Number)
126             rv = list.at(index.row()).second;
127
128         return rv;
129     }
130
131     int count() const { return rowCount(); }
132     QString name(int index) const { return list.at(index).first; }
133     QString number(int index) const { return list.at(index).second; }
134
135     void addItem(const QString &name, const QString &number) {
136         emit beginInsertRows(QModelIndex(), list.count(), list.count());
137         list.append(QPair<QString,QString>(name, number));
138         emit endInsertRows();
139     }
140
141     void insertItem(int index, const QString &name, const QString &number) {
142         emit beginInsertRows(QModelIndex(), index, index);
143         list.insert(index, QPair<QString,QString>(name, number));
144         emit endInsertRows();
145     }
146
147     void removeItem(int index) {
148         emit beginRemoveRows(QModelIndex(), index, index);
149         list.removeAt(index);
150         emit endRemoveRows();
151     }
152
153     void moveItem(int from, int to) {
154         emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
155         list.move(from, to);
156         emit endMoveRows();
157     }
158
159     void modifyItem(int idx, const QString &name, const QString &number) {
160         list[idx] = QPair<QString,QString>(name, number);
161         emit dataChanged(index(idx,0), index(idx,0));
162     }
163
164 private:
165     QList<QPair<QString,QString> > list;
166 };
167
168
169 tst_QDeclarative1Repeater::tst_QDeclarative1Repeater()
170 {
171 }
172
173 void tst_QDeclarative1Repeater::numberModel()
174 {
175     QDeclarativeView *canvas = createView();
176
177     QDeclarativeContext *ctxt = canvas->rootContext();
178     ctxt->setContextProperty("testData", 5);
179     TestObject *testObject = new TestObject;
180     ctxt->setContextProperty("testObject", testObject);
181
182     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/intmodel.qml"));
183     qApp->processEvents();
184
185     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
186     QVERIFY(repeater != 0);
187     QCOMPARE(repeater->parentItem()->childItems().count(), 5+1);
188
189     QVERIFY(!repeater->itemAt(-1));
190     for (int i=0; i<repeater->count(); i++)
191         QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i));
192     QVERIFY(!repeater->itemAt(repeater->count()));
193
194     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
195     QVERIFY(testObject->error() == false);
196
197     delete testObject;
198     delete canvas;
199 }
200
201 class MyObject : public QObject
202 {
203     Q_OBJECT
204     Q_PROPERTY(int idx READ idx CONSTANT)
205 public:
206     MyObject(int i) : QObject(), m_idx(i) {}
207
208     int idx() const { return m_idx; }
209
210     int m_idx;
211 };
212
213 void tst_QDeclarative1Repeater::objectList()
214 {
215     QDeclarativeView *canvas = createView();
216     QObjectList data;
217     for(int i=0; i<100; i++)
218         data << new MyObject(i);
219
220     QDeclarativeContext *ctxt = canvas->rootContext();
221     ctxt->setContextProperty("testData", QVariant::fromValue(data));
222
223     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/objlist.qml"));
224     qApp->processEvents();
225
226     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
227     QVERIFY(repeater != 0);
228     QCOMPARE(repeater->property("errors").toInt(), 0);//If this fails either they are out of order or can't find the object's data
229     QCOMPARE(repeater->property("instantiated").toInt(), 100);
230
231     QVERIFY(!repeater->itemAt(-1));
232     for (int i=0; i<data.count(); i++)
233         QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i));
234     QVERIFY(!repeater->itemAt(data.count()));
235
236     QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QDeclarativeItem*)));
237     QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QDeclarativeItem*)));
238     ctxt->setContextProperty("testData", QVariant::fromValue(data));
239     QCOMPARE(addedSpy.count(), data.count());
240     QCOMPARE(removedSpy.count(), data.count());
241
242     qDeleteAll(data);
243     delete canvas;
244 }
245
246 /*
247 The Repeater element creates children at its own position in its parent's
248 stacking order.  In this test we insert a repeater between two other Text
249 elements to test this.
250 */
251 void tst_QDeclarative1Repeater::stringList()
252 {
253     QDeclarativeView *canvas = createView();
254
255     QStringList data;
256     data << "One";
257     data << "Two";
258     data << "Three";
259     data << "Four";
260
261     QDeclarativeContext *ctxt = canvas->rootContext();
262     ctxt->setContextProperty("testData", data);
263
264     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater1.qml"));
265     qApp->processEvents();
266
267     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
268     QVERIFY(repeater != 0);
269
270     QDeclarativeItem *container = findItem<QDeclarativeItem>(canvas->rootObject(), "container");
271     QVERIFY(container != 0);
272
273     QCOMPARE(container->childItems().count(), data.count() + 3);
274
275     bool saw_repeater = false;
276     for (int i = 0; i < container->childItems().count(); ++i) {
277
278         if (i == 0) {
279             QDeclarative1Text *name = qobject_cast<QDeclarative1Text*>(container->childItems().at(i));
280             QVERIFY(name != 0);
281             QCOMPARE(name->text(), QLatin1String("Zero"));
282         } else if (i == container->childItems().count() - 2) {
283             // The repeater itself
284             QDeclarative1Repeater *rep = qobject_cast<QDeclarative1Repeater*>(container->childItems().at(i));
285             QCOMPARE(rep, repeater);
286             saw_repeater = true;
287             continue;
288         } else if (i == container->childItems().count() - 1) {
289             QDeclarative1Text *name = qobject_cast<QDeclarative1Text*>(container->childItems().at(i));
290             QVERIFY(name != 0);
291             QCOMPARE(name->text(), QLatin1String("Last"));
292         } else {
293             QDeclarative1Text *name = qobject_cast<QDeclarative1Text*>(container->childItems().at(i));
294             QVERIFY(name != 0);
295             QCOMPARE(name->text(), data.at(i-1));
296         }
297     }
298     QVERIFY(saw_repeater);
299
300     delete canvas;
301 }
302
303 void tst_QDeclarative1Repeater::dataModel_adding()
304 {
305     QDeclarativeView *canvas = createView();
306     QDeclarativeContext *ctxt = canvas->rootContext();
307     TestObject *testObject = new TestObject;
308     ctxt->setContextProperty("testObject", testObject);
309
310     TestModel testModel;
311     ctxt->setContextProperty("testData", &testModel);
312     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater2.qml"));
313     qApp->processEvents();
314
315     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
316     QVERIFY(repeater != 0);
317     QDeclarativeItem *container = findItem<QDeclarativeItem>(canvas->rootObject(), "container");
318     QVERIFY(container != 0);
319
320     QVERIFY(!repeater->itemAt(0));
321
322     QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
323     QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QDeclarativeItem*)));
324
325     // add to empty model
326     testModel.addItem("two", "2");
327     QCOMPARE(repeater->itemAt(0), container->childItems().at(0));
328     QCOMPARE(countSpy.count(), 1); countSpy.clear();
329     QCOMPARE(addedSpy.count(), 1);
330     QCOMPARE(addedSpy.at(0).at(0).toInt(), 0);
331     QCOMPARE(addedSpy.at(0).at(1).value<QDeclarativeItem*>(), container->childItems().at(0));
332     addedSpy.clear();
333
334     // insert at start
335     testModel.insertItem(0, "one", "1");
336     QCOMPARE(repeater->itemAt(0), container->childItems().at(0));
337     QCOMPARE(countSpy.count(), 1); countSpy.clear();
338     QCOMPARE(addedSpy.count(), 1);
339     QCOMPARE(addedSpy.at(0).at(0).toInt(), 0);
340     QCOMPARE(addedSpy.at(0).at(1).value<QDeclarativeItem*>(), container->childItems().at(0));
341     addedSpy.clear();
342
343     // insert at end
344     testModel.insertItem(2, "four", "4");
345     QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
346     QCOMPARE(countSpy.count(), 1); countSpy.clear();
347     QCOMPARE(addedSpy.count(), 1);
348     QCOMPARE(addedSpy.at(0).at(0).toInt(), 2);
349     QCOMPARE(addedSpy.at(0).at(1).value<QDeclarativeItem*>(), container->childItems().at(2));
350     addedSpy.clear();
351
352     // insert in middle
353     testModel.insertItem(2, "three", "3");
354     QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
355     QCOMPARE(countSpy.count(), 1); countSpy.clear();
356     QCOMPARE(addedSpy.count(), 1);
357     QCOMPARE(addedSpy.at(0).at(0).toInt(), 2);
358     QCOMPARE(addedSpy.at(0).at(1).value<QDeclarativeItem*>(), container->childItems().at(2));
359     addedSpy.clear();
360
361     delete testObject;
362     delete canvas;
363 }
364
365 void tst_QDeclarative1Repeater::dataModel_removing()
366 {
367     QDeclarativeView *canvas = createView();
368     QDeclarativeContext *ctxt = canvas->rootContext();
369     TestObject *testObject = new TestObject;
370     ctxt->setContextProperty("testObject", testObject);
371
372     TestModel testModel;
373     testModel.addItem("one", "1");
374     testModel.addItem("two", "2");
375     testModel.addItem("three", "3");
376     testModel.addItem("four", "4");
377     testModel.addItem("five", "5");
378
379     ctxt->setContextProperty("testData", &testModel);
380     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater2.qml"));
381     qApp->processEvents();
382
383     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
384     QVERIFY(repeater != 0);
385     QDeclarativeItem *container = findItem<QDeclarativeItem>(canvas->rootObject(), "container");
386     QVERIFY(container != 0);
387     QCOMPARE(container->childItems().count(), repeater->count()+1);
388
389     QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
390     QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QDeclarativeItem*)));
391
392     // remove at start
393     QDeclarativeItem *item = repeater->itemAt(0);
394     QCOMPARE(item, container->childItems().at(0));
395
396     testModel.removeItem(0);
397     QVERIFY(repeater->itemAt(0) != item);
398     QCOMPARE(countSpy.count(), 1); countSpy.clear();
399     QCOMPARE(removedSpy.count(), 1);
400     QCOMPARE(removedSpy.at(0).at(0).toInt(), 0);
401     QCOMPARE(removedSpy.at(0).at(1).value<QDeclarativeItem*>(), item);
402     removedSpy.clear();
403
404     // remove at end
405     int lastIndex = testModel.count()-1;
406     item = repeater->itemAt(lastIndex);
407     QCOMPARE(item, container->childItems().at(lastIndex));
408
409     testModel.removeItem(lastIndex);
410     QVERIFY(repeater->itemAt(lastIndex) != item);
411     QCOMPARE(countSpy.count(), 1); countSpy.clear();
412     QCOMPARE(removedSpy.count(), 1);
413     QCOMPARE(removedSpy.at(0).at(0).toInt(), lastIndex);
414     QCOMPARE(removedSpy.at(0).at(1).value<QDeclarativeItem*>(), item);
415     removedSpy.clear();
416
417     // remove from middle
418     item = repeater->itemAt(1);
419     QCOMPARE(item, container->childItems().at(1));
420
421     testModel.removeItem(1);
422     QVERIFY(repeater->itemAt(lastIndex) != item);
423     QCOMPARE(countSpy.count(), 1); countSpy.clear();
424     QCOMPARE(removedSpy.count(), 1);
425     QCOMPARE(removedSpy.at(0).at(0).toInt(), 1);
426     QCOMPARE(removedSpy.at(0).at(1).value<QDeclarativeItem*>(), item);
427     removedSpy.clear();
428
429     delete testObject;
430     delete canvas;
431 }
432
433 void tst_QDeclarative1Repeater::dataModel_changes()
434 {
435     QDeclarativeView *canvas = createView();
436     QDeclarativeContext *ctxt = canvas->rootContext();
437     TestObject *testObject = new TestObject;
438     ctxt->setContextProperty("testObject", testObject);
439
440     TestModel testModel;
441     testModel.addItem("one", "1");
442     testModel.addItem("two", "2");
443     testModel.addItem("three", "3");
444
445     ctxt->setContextProperty("testData", &testModel);
446     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater2.qml"));
447     qApp->processEvents();
448
449     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
450     QVERIFY(repeater != 0);
451     QDeclarativeItem *container = findItem<QDeclarativeItem>(canvas->rootObject(), "container");
452     QVERIFY(container != 0);
453     QCOMPARE(container->childItems().count(), repeater->count()+1);
454
455     // Check that model changes are propagated
456     QDeclarative1Text *text = findItem<QDeclarative1Text>(canvas->rootObject(), "myName", 1);
457     QVERIFY(text);
458     QCOMPARE(text->text(), QString("two"));
459
460     testModel.modifyItem(1, "Item two", "_2");
461     text = findItem<QDeclarative1Text>(canvas->rootObject(), "myName", 1);
462     QVERIFY(text);
463     QCOMPARE(text->text(), QString("Item two"));
464
465     text = findItem<QDeclarative1Text>(canvas->rootObject(), "myNumber", 1);
466     QVERIFY(text);
467     QCOMPARE(text->text(), QString("_2"));
468
469     delete testObject;
470     delete canvas;
471 }
472
473 void tst_QDeclarative1Repeater::itemModel()
474 {
475     QDeclarativeView *canvas = createView();
476     QDeclarativeContext *ctxt = canvas->rootContext();
477     TestObject *testObject = new TestObject;
478     ctxt->setContextProperty("testObject", testObject);
479
480     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/itemlist.qml"));
481     qApp->processEvents();
482
483     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
484     QVERIFY(repeater != 0);
485
486     QDeclarativeItem *container = findItem<QDeclarativeItem>(canvas->rootObject(), "container");
487     QVERIFY(container != 0);
488
489     QCOMPARE(container->childItems().count(), 1);
490
491     testObject->setUseModel(true);
492     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
493     QVERIFY(testObject->error() == false);
494
495     QCOMPARE(container->childItems().count(), 4);
496     QVERIFY(qobject_cast<QObject*>(container->childItems().at(0))->objectName() == "item1");
497     QVERIFY(qobject_cast<QObject*>(container->childItems().at(1))->objectName() == "item2");
498     QVERIFY(qobject_cast<QObject*>(container->childItems().at(2))->objectName() == "item3");
499     QVERIFY(container->childItems().at(3) == repeater);
500
501     QMetaObject::invokeMethod(canvas->rootObject(), "switchModel");
502     QCOMPARE(container->childItems().count(), 3);
503     QVERIFY(qobject_cast<QObject*>(container->childItems().at(0))->objectName() == "item4");
504     QVERIFY(qobject_cast<QObject*>(container->childItems().at(1))->objectName() == "item5");
505     QVERIFY(container->childItems().at(2) == repeater);
506
507     testObject->setUseModel(false);
508     QCOMPARE(container->childItems().count(), 1);
509
510     delete testObject;
511     delete canvas;
512 }
513
514 void tst_QDeclarative1Repeater::resetModel()
515 {
516     QDeclarativeView *canvas = createView();
517
518     QStringList dataA;
519     for (int i=0; i<10; i++)
520         dataA << QString::number(i);
521
522     QDeclarativeContext *ctxt = canvas->rootContext();
523     ctxt->setContextProperty("testData", dataA);
524     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/repeater1.qml"));
525     qApp->processEvents();
526     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(canvas->rootObject(), "repeater");
527     QVERIFY(repeater != 0);
528     QDeclarativeItem *container = findItem<QDeclarativeItem>(canvas->rootObject(), "container");
529     QVERIFY(container != 0);
530
531     QCOMPARE(repeater->count(), dataA.count());
532     for (int i=0; i<repeater->count(); i++)
533         QCOMPARE(repeater->itemAt(i), container->childItems().at(i+1)); // +1 to skip first Text object
534
535     QSignalSpy modelChangedSpy(repeater, SIGNAL(modelChanged()));
536     QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
537     QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QDeclarativeItem*)));
538     QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QDeclarativeItem*)));
539
540     QStringList dataB;
541     for (int i=0; i<20; i++)
542         dataB << QString::number(i);
543
544     // reset context property
545     ctxt->setContextProperty("testData", dataB);
546     QCOMPARE(repeater->count(), dataB.count());
547
548     QCOMPARE(modelChangedSpy.count(), 1);
549     QCOMPARE(countSpy.count(), 1);
550     QCOMPARE(removedSpy.count(), dataA.count());
551     QCOMPARE(addedSpy.count(), dataB.count());
552     for (int i=0; i<dataB.count(); i++) {
553         QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
554         QCOMPARE(addedSpy.at(i).at(1).value<QDeclarativeItem*>(), repeater->itemAt(i));
555     }
556     modelChangedSpy.clear();
557     countSpy.clear();
558     removedSpy.clear();
559     addedSpy.clear();
560
561     // reset via setModel()
562     repeater->setModel(dataA);
563     QCOMPARE(repeater->count(), dataA.count());
564
565     QCOMPARE(modelChangedSpy.count(), 1);
566     QCOMPARE(countSpy.count(), 1);
567     QCOMPARE(removedSpy.count(), dataB.count());
568     QCOMPARE(addedSpy.count(), dataA.count());
569     for (int i=0; i<dataA.count(); i++) {
570         QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
571         QCOMPARE(addedSpy.at(i).at(1).value<QDeclarativeItem*>(), repeater->itemAt(i));
572     }
573
574     delete canvas;
575 }
576
577 // QTBUG-17156
578 void tst_QDeclarative1Repeater::modelChanged()
579 {
580     QDeclarativeEngine engine;
581     QDeclarativeComponent component(&engine, TEST_FILE("/modelChanged.qml"));
582
583     QDeclarativeItem *rootObject = qobject_cast<QDeclarativeItem*>(component.create());
584     QVERIFY(rootObject);
585     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(rootObject, "repeater");
586     QVERIFY(repeater);
587
588     repeater->setModel(4);
589     QCOMPARE(repeater->count(), 4);
590     QCOMPARE(repeater->property("itemsCount").toInt(), 4);
591     QCOMPARE(repeater->property("itemsFound").toList().count(), 4);
592
593     repeater->setModel(10);
594     QCOMPARE(repeater->count(), 10);
595     QCOMPARE(repeater->property("itemsCount").toInt(), 10);
596     QCOMPARE(repeater->property("itemsFound").toList().count(), 10);
597
598     delete rootObject;
599 }
600
601 void tst_QDeclarative1Repeater::properties()
602 {
603     QDeclarativeEngine engine;
604     QDeclarativeComponent component(&engine, TEST_FILE("/properties.qml"));
605
606     QDeclarativeItem *rootObject = qobject_cast<QDeclarativeItem*>(component.create());
607     QVERIFY(rootObject);
608
609     QDeclarative1Repeater *repeater = findItem<QDeclarative1Repeater>(rootObject, "repeater");
610     QVERIFY(repeater);
611
612     QSignalSpy modelSpy(repeater, SIGNAL(modelChanged()));
613     repeater->setModel(3);
614     QCOMPARE(modelSpy.count(),1);
615     repeater->setModel(3);
616     QCOMPARE(modelSpy.count(),1);
617
618     QSignalSpy delegateSpy(repeater, SIGNAL(delegateChanged()));
619
620     QDeclarativeComponent rectComponent(&engine);
621     rectComponent.setData("import QtQuick 1.0; Rectangle {}", QUrl::fromLocalFile(""));
622
623     repeater->setDelegate(&rectComponent);
624     QCOMPARE(delegateSpy.count(),1);
625     repeater->setDelegate(&rectComponent);
626     QCOMPARE(delegateSpy.count(),1);
627
628     delete rootObject;
629 }
630
631 void tst_QDeclarative1Repeater::testQtQuick11Attributes()
632 {
633     QFETCH(QString, code);
634     QFETCH(QString, warning);
635     QFETCH(QString, error);
636
637     QDeclarativeEngine engine;
638     QObject *obj;
639
640     QDeclarativeComponent invalid(&engine);
641     invalid.setData("import QtQuick 1.0; Repeater { " + code.toUtf8() + " }", QUrl(""));
642     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
643     obj = invalid.create();
644     QCOMPARE(invalid.errorString(), error);
645     delete obj;
646
647     QDeclarativeComponent valid(&engine);
648     valid.setData("import QtQuick 1.1; Repeater { " + code.toUtf8() + " }", QUrl(""));
649     obj = valid.create();
650     QVERIFY(obj);
651     QVERIFY(valid.errorString().isEmpty());
652     delete obj;
653 }
654
655 void tst_QDeclarative1Repeater::testQtQuick11Attributes_data()
656 {
657     QTest::addColumn<QString>("code");
658     QTest::addColumn<QString>("warning");
659     QTest::addColumn<QString>("error");
660
661     QTest::newRow("itemAdded") << "onItemAdded: count"
662             << "QDeclarativeComponent: Component is not ready"
663             << ":1 \"Repeater.onItemAdded\" is not available in QtQuick 1.0.\n";
664
665     QTest::newRow("itemRemoved") << "onItemRemoved: count"
666             << "QDeclarativeComponent: Component is not ready"
667             << ":1 \"Repeater.onItemRemoved\" is not available in QtQuick 1.0.\n";
668
669     QTest::newRow("itemAt") << "Component.onCompleted: itemAt(0)"
670             << "<Unknown File>:1: ReferenceError: Can't find variable: itemAt"
671             << "";
672 }
673
674
675 QDeclarativeView *tst_QDeclarative1Repeater::createView()
676 {
677     QDeclarativeView *canvas = new QDeclarativeView(0);
678     canvas->setFixedSize(240,320);
679
680     return canvas;
681 }
682
683 template<typename T>
684 T *tst_QDeclarative1Repeater::findItem(QGraphicsObject *parent, const QString &objectName, int index)
685 {
686     const QMetaObject &mo = T::staticMetaObject;
687     //qDebug() << parent->childItems().count() << "children";
688     for (int i = 0; i < parent->childItems().count(); ++i) {
689         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
690         if(!item)
691             continue;
692         //qDebug() << "try" << item;
693         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
694             if (index != -1) {
695                 QDeclarativeExpression e(qmlContext(item), item, "index");
696                 if (e.evaluate().toInt() == index)
697                     return static_cast<T*>(item);
698             } else {
699                 return static_cast<T*>(item);
700             }
701         }
702         item = findItem<T>(item, objectName, index);
703         if (item)
704             return static_cast<T*>(item);
705     }
706
707     return 0;
708 }
709
710 template<typename T>
711 T *tst_QDeclarative1Repeater::findItem(QGraphicsObject *parent, const QString &objectName)
712 {
713     const QMetaObject &mo = T::staticMetaObject;
714     if (mo.cast(parent) && (objectName.isEmpty() || parent->objectName() == objectName))
715         return static_cast<T*>(parent);
716     for (int i = 0; i < parent->childItems().count(); ++i) {
717         QDeclarativeItem *child = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
718         if (!child)
719             continue;
720         QDeclarativeItem *item = findItem<T>(child, objectName);
721         if (item)
722             return static_cast<T*>(item);
723     }
724
725     return 0;
726 }
727
728 QTEST_MAIN(tst_QDeclarative1Repeater)
729
730 #include "tst_qdeclarativerepeater.moc"