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