partial build fix of qtquick1 autotests
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick1 / qdeclarativelistview / tst_qdeclarativelistview.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 <QtWidgets/QStringListModel>
44 #include <QtQuick1/qdeclarativeview.h>
45 #include <QtDeclarative/qdeclarativeengine.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeexpression.h>
48 #include <QtQuick1/private/qdeclarativeitem_p.h>
49 #include <QtQuick1/private/qdeclarativelistview_p.h>
50 #include <QtQuick1/private/qdeclarativetext_p.h>
51 #include <QtQuick1/private/qdeclarativevisualitemmodel_p.h>
52 #include <QtDeclarative/private/qlistmodelinterface_p.h>
53 #include "../../../shared/util.h"
54 #include "incrementalmodel.h"
55
56 #ifdef Q_OS_SYMBIAN
57 // In Symbian OS test data is located in applications private dir
58 #define SRCDIR "."
59 #endif
60
61 class tst_QDeclarative1ListView : public QObject
62 {
63     Q_OBJECT
64 public:
65     tst_QDeclarative1ListView();
66
67 private slots:
68     // Test both QListModelInterface and QAbstractItemModel model types
69     void qListModelInterface_items();
70     void qAbstractItemModel_items();
71
72     void qListModelInterface_changed();
73     void qAbstractItemModel_changed();
74
75     void qListModelInterface_inserted();
76     void qAbstractItemModel_inserted();
77
78     void qListModelInterface_removed();
79     void qAbstractItemModel_removed();
80
81     void qListModelInterface_moved();
82     void qAbstractItemModel_moved();
83
84     void qListModelInterface_clear();
85     void qAbstractItemModel_clear();
86
87     void itemList();
88     void currentIndex();
89     void noCurrentIndex();
90     void enforceRange();
91     void spacing();
92     void sections();
93     void sectionsDelegate();
94     void cacheBuffer();
95     void positionViewAtIndex();
96     void resetModel();
97     void propertyChanges();
98     void componentChanges();
99     void modelChanges();
100     void QTBUG_9791();
101     void manualHighlight();
102     void QTBUG_11105();
103     void header();
104     void footer();
105     void headerFooter();
106     void resizeView();
107     void sizeLessThan1();
108     void QTBUG_14821();
109     void resizeDelegate();
110     void QTBUG_16037();
111     void indexAt();
112     void incrementalModel();
113     void onAdd();
114     void onAdd_data();
115     void onRemove();
116     void onRemove_data();
117     void testQtQuick11Attributes();
118     void testQtQuick11Attributes_data();
119     void rightToLeft();
120     void test_mirroring();
121     void orientationChange();
122     void contentPosJump();
123
124 private:
125     template <class T> void items();
126     template <class T> void changed();
127     template <class T> void inserted();
128     template <class T> void removed(bool animated);
129     template <class T> void moved();
130     template <class T> void clear();
131     QDeclarativeView *createView();
132     template<typename T>
133     T *findItem(QGraphicsObject *parent, const QString &id, int index=-1);
134     template<typename T>
135     QList<T*> findItems(QGraphicsObject *parent, const QString &objectName);
136     void dumpTree(QDeclarativeItem *parent, int depth = 0);
137 };
138
139 class TestObject : public QObject
140 {
141     Q_OBJECT
142
143     Q_PROPERTY(bool error READ error WRITE setError NOTIFY changedError)
144     Q_PROPERTY(bool animate READ animate NOTIFY changedAnim)
145     Q_PROPERTY(bool invalidHighlight READ invalidHighlight NOTIFY changedHl)
146     Q_PROPERTY(int cacheBuffer READ cacheBuffer NOTIFY changedCacheBuffer)
147
148 public:
149     TestObject(QObject *parent = 0)
150         : QObject(parent), mError(true), mAnimate(false), mInvalidHighlight(false)
151         , mCacheBuffer(0) {}
152
153     bool error() const { return mError; }
154     void setError(bool err) { mError = err; emit changedError(); }
155
156     bool animate() const { return mAnimate; }
157     void setAnimate(bool anim) { mAnimate = anim; emit changedAnim(); }
158
159     bool invalidHighlight() const { return mInvalidHighlight; }
160     void setInvalidHighlight(bool invalid) { mInvalidHighlight = invalid; emit changedHl(); }
161
162     int cacheBuffer() const { return mCacheBuffer; }
163     void setCacheBuffer(int buffer) { mCacheBuffer = buffer; emit changedCacheBuffer(); }
164
165 signals:
166     void changedError();
167     void changedAnim();
168     void changedHl();
169     void changedCacheBuffer();
170
171 public:
172     bool mError;
173     bool mAnimate;
174     bool mInvalidHighlight;
175     int mCacheBuffer;
176 };
177
178 class TestModel : public QListModelInterface
179 {
180     Q_OBJECT
181 public:
182     TestModel(QObject *parent = 0) : QListModelInterface(parent) {}
183     ~TestModel() {}
184
185     enum Roles { Name, Number };
186
187     QString name(int index) const { return list.at(index).first; }
188     QString number(int index) const { return list.at(index).second; }
189
190     int count() const { return list.count(); }
191
192     QList<int> roles() const { return QList<int>() << Name << Number; }
193     QString toString(int role) const {
194         switch(role) {
195         case Name:
196             return "name";
197         case Number:
198             return "number";
199         default:
200             return "";
201         }
202     }
203
204     QVariant data(int index, int role) const
205     {
206         if (role==0)
207             return list.at(index).first;
208         if (role==1)
209             return list.at(index).second;
210         return QVariant();
211     }
212     QHash<int, QVariant> data(int index, const QList<int> &roles) const {
213         QHash<int,QVariant> returnHash;
214
215         for (int i = 0; i < roles.size(); ++i) {
216             int role = roles.at(i);
217             QVariant info;
218             switch(role) {
219             case Name:
220                 info = list.at(index).first;
221                 break;
222             case Number:
223                 info = list.at(index).second;
224                 break;
225             default:
226                 break;
227             }
228             returnHash.insert(role, info);
229         }
230         return returnHash;
231     }
232
233     void addItem(const QString &name, const QString &number) {
234         list.append(QPair<QString,QString>(name, number));
235         emit itemsInserted(list.count()-1, 1);
236     }
237
238     void insertItem(int index, const QString &name, const QString &number) {
239         list.insert(index, QPair<QString,QString>(name, number));
240         emit itemsInserted(index, 1);
241     }
242
243     void removeItem(int index) {
244         list.removeAt(index);
245         emit itemsRemoved(index, 1);
246     }
247
248     void removeItems(int index, int count) {
249         int c = count;
250         while (c--)
251             list.removeAt(index);
252         emit itemsRemoved(index, count);
253     }
254
255     void moveItem(int from, int to) {
256         list.move(from, to);
257         emit itemsMoved(from, to, 1);
258     }
259
260     void modifyItem(int index, const QString &name, const QString &number) {
261         list[index] = QPair<QString,QString>(name, number);
262         emit itemsChanged(index, 1, roles());
263     }
264
265     void clear() {
266         int count = list.count();
267         list.clear();
268         emit itemsRemoved(0, count);
269     }
270
271 private:
272     QList<QPair<QString,QString> > list;
273 };
274
275
276 class TestModel2 : public QAbstractListModel
277 {
278 public:
279     enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
280
281     TestModel2(QObject *parent=0) : QAbstractListModel(parent) {
282         QHash<int, QByteArray> roles;
283         roles[Name] = "name";
284         roles[Number] = "number";
285         setRoleNames(roles);
286     }
287
288     int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
289     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
290         QVariant rv;
291         if (role == Name)
292             rv = list.at(index.row()).first;
293         else if (role == Number)
294             rv = list.at(index.row()).second;
295
296         return rv;
297     }
298
299     int count() const { return rowCount(); }
300     QString name(int index) const { return list.at(index).first; }
301     QString number(int index) const { return list.at(index).second; }
302
303     void addItem(const QString &name, const QString &number) {
304         emit beginInsertRows(QModelIndex(), list.count(), list.count());
305         list.append(QPair<QString,QString>(name, number));
306         emit endInsertRows();
307     }
308
309     void addItems(const QList<QPair<QString, QString> > &items) {
310         emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
311         for (int i=0; i<items.count(); i++)
312             list.append(QPair<QString,QString>(items[i].first, items[i].second));
313         emit endInsertRows();
314     }
315
316     void insertItem(int index, const QString &name, const QString &number) {
317         emit beginInsertRows(QModelIndex(), index, index);
318         list.insert(index, QPair<QString,QString>(name, number));
319         emit endInsertRows();
320     }
321
322     void removeItem(int index) {
323         emit beginRemoveRows(QModelIndex(), index, index);
324         list.removeAt(index);
325         emit endRemoveRows();
326     }
327
328     void removeItems(int index, int count) {
329         emit beginRemoveRows(QModelIndex(), index, index+count-1);
330         while (count--)
331             list.removeAt(index);
332         emit endRemoveRows();
333     }
334
335     void moveItem(int from, int to) {
336         emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
337         list.move(from, to);
338         emit endMoveRows();
339     }
340
341     void modifyItem(int idx, const QString &name, const QString &number) {
342         list[idx] = QPair<QString,QString>(name, number);
343         emit dataChanged(index(idx,0), index(idx,0));
344     }
345
346     void clear() {
347         int count = list.count();
348         emit beginRemoveRows(QModelIndex(), 0, count-1);
349         list.clear();
350         emit endRemoveRows();
351     }
352
353 private:
354     QList<QPair<QString,QString> > list;
355 };
356
357 tst_QDeclarative1ListView::tst_QDeclarative1ListView()
358 {
359 }
360
361 template <class T>
362 void tst_QDeclarative1ListView::items()
363 {
364     QDeclarativeView *canvas = createView();
365
366     T model;
367     model.addItem("Fred", "12345");
368     model.addItem("John", "2345");
369     model.addItem("Bob", "54321");
370
371     QDeclarativeContext *ctxt = canvas->rootContext();
372     ctxt->setContextProperty("testModel", &model);
373
374     TestObject *testObject = new TestObject;
375     ctxt->setContextProperty("testObject", testObject);
376
377     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
378     qApp->processEvents();
379
380     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
381     QTRY_VERIFY(listview != 0);
382
383     QDeclarativeItem *contentItem = listview->contentItem();
384     QTRY_VERIFY(contentItem != 0);
385
386     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
387     QTRY_VERIFY(testObject->error() == false);
388
389     QTRY_VERIFY(listview->highlightItem() != 0);
390     QTRY_COMPARE(listview->count(), model.count());
391     QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
392     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
393
394     // current item should be first item
395     QTRY_COMPARE(listview->currentItem(), findItem<QDeclarativeItem>(contentItem, "wrapper", 0));
396
397     for (int i = 0; i < model.count(); ++i) {
398         QDeclarative1Text *name = findItem<QDeclarative1Text>(contentItem, "textName", i);
399         QTRY_VERIFY(name != 0);
400         QTRY_COMPARE(name->text(), model.name(i));
401         QDeclarative1Text *number = findItem<QDeclarative1Text>(contentItem, "textNumber", i);
402         QTRY_VERIFY(number != 0);
403         QTRY_COMPARE(number->text(), model.number(i));
404     }
405
406     // switch to other delegate
407     testObject->setAnimate(true);
408     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
409     QTRY_VERIFY(testObject->error() == false);
410     QTRY_VERIFY(listview->currentItem());
411
412     // set invalid highlight
413     testObject->setInvalidHighlight(true);
414     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
415     QTRY_VERIFY(testObject->error() == false);
416     QTRY_VERIFY(listview->currentItem());
417     QTRY_VERIFY(listview->highlightItem() == 0);
418
419     // back to normal highlight
420     testObject->setInvalidHighlight(false);
421     QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
422     QTRY_VERIFY(testObject->error() == false);
423     QTRY_VERIFY(listview->currentItem());
424     QTRY_VERIFY(listview->highlightItem() != 0);
425
426     // set an empty model and confirm that items are destroyed
427     T model2;
428     ctxt->setContextProperty("testModel", &model2);
429
430     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
431     QTRY_VERIFY(itemCount == 0);
432
433     QTRY_COMPARE(listview->highlightResizeSpeed(), 1000.0);
434     QTRY_COMPARE(listview->highlightMoveSpeed(), 1000.0);
435
436     delete canvas;
437     delete testObject;
438 }
439
440
441 template <class T>
442 void tst_QDeclarative1ListView::changed()
443 {
444     QDeclarativeView *canvas = createView();
445
446     T model;
447     model.addItem("Fred", "12345");
448     model.addItem("John", "2345");
449     model.addItem("Bob", "54321");
450
451     QDeclarativeContext *ctxt = canvas->rootContext();
452     ctxt->setContextProperty("testModel", &model);
453
454     TestObject *testObject = new TestObject;
455     ctxt->setContextProperty("testObject", testObject);
456
457     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
458     qApp->processEvents();
459
460     QDeclarative1Flickable *listview = findItem<QDeclarative1Flickable>(canvas->rootObject(), "list");
461     QTRY_VERIFY(listview != 0);
462
463     QDeclarativeItem *contentItem = listview->contentItem();
464     QTRY_VERIFY(contentItem != 0);
465
466     model.modifyItem(1, "Will", "9876");
467     QDeclarative1Text *name = findItem<QDeclarative1Text>(contentItem, "textName", 1);
468     QTRY_VERIFY(name != 0);
469     QTRY_COMPARE(name->text(), model.name(1));
470     QDeclarative1Text *number = findItem<QDeclarative1Text>(contentItem, "textNumber", 1);
471     QTRY_VERIFY(number != 0);
472     QTRY_COMPARE(number->text(), model.number(1));
473
474     delete canvas;
475     delete testObject;
476 }
477
478 template <class T>
479 void tst_QDeclarative1ListView::inserted()
480 {
481     QDeclarativeView *canvas = createView();
482
483     T model;
484     model.addItem("Fred", "12345");
485     model.addItem("John", "2345");
486     model.addItem("Bob", "54321");
487
488     QDeclarativeContext *ctxt = canvas->rootContext();
489     ctxt->setContextProperty("testModel", &model);
490
491     TestObject *testObject = new TestObject;
492     ctxt->setContextProperty("testObject", testObject);
493
494     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
495     qApp->processEvents();
496
497     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
498     QTRY_VERIFY(listview != 0);
499
500     QDeclarativeItem *contentItem = listview->contentItem();
501     QTRY_VERIFY(contentItem != 0);
502
503     model.insertItem(1, "Will", "9876");
504
505     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
506
507     QDeclarative1Text *name = findItem<QDeclarative1Text>(contentItem, "textName", 1);
508     QTRY_VERIFY(name != 0);
509     QTRY_COMPARE(name->text(), model.name(1));
510     QDeclarative1Text *number = findItem<QDeclarative1Text>(contentItem, "textNumber", 1);
511     QTRY_VERIFY(number != 0);
512     QTRY_COMPARE(number->text(), model.number(1));
513
514     // Confirm items positioned correctly
515     for (int i = 0; i < model.count(); ++i) {
516         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
517         QTRY_COMPARE(item->y(), i*20.0);
518     }
519
520     model.insertItem(0, "Foo", "1111"); // zero index, and current item
521
522     QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
523     QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
524
525     name = findItem<QDeclarative1Text>(contentItem, "textName", 0);
526     QTRY_VERIFY(name != 0);
527     QTRY_COMPARE(name->text(), model.name(0));
528     number = findItem<QDeclarative1Text>(contentItem, "textNumber", 0);
529     QTRY_VERIFY(number != 0);
530     QTRY_COMPARE(number->text(), model.number(0));
531
532     QTRY_COMPARE(listview->currentIndex(), 1);
533
534     // Confirm items positioned correctly
535     for (int i = 0; i < model.count(); ++i) {
536         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
537         QTRY_COMPARE(item->y(), i*20.0);
538     }
539
540     for (int i = model.count(); i < 30; ++i)
541         model.insertItem(i, "Hello", QString::number(i));
542
543     listview->setContentY(80);
544
545     // Insert item outside visible area
546     model.insertItem(1, "Hello", "1324");
547
548     QTRY_VERIFY(listview->contentY() == 80);
549
550     // Confirm items positioned correctly
551     for (int i = 5; i < 5+15; ++i) {
552         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
553         if (!item) qWarning() << "Item" << i << "not found";
554         QTRY_VERIFY(item);
555         QTRY_COMPARE(item->y(), i*20.0 - 20.0);
556     }
557
558 //    QTRY_COMPARE(listview->contentItemHeight(), model.count() * 20.0);
559
560     // QTBUG-19675
561     model.clear();
562     model.insertItem(0, "Hello", "1234");
563     QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", 0);
564     QVERIFY(item);
565     QCOMPARE(item->y(), 0.);
566     QVERIFY(listview->contentY() == 0);
567
568     delete canvas;
569     delete testObject;
570 }
571
572 template <class T>
573 void tst_QDeclarative1ListView::removed(bool animated)
574 {
575     QDeclarativeView *canvas = createView();
576
577     T model;
578     for (int i = 0; i < 50; i++)
579         model.addItem("Item" + QString::number(i), "");
580
581     QDeclarativeContext *ctxt = canvas->rootContext();
582     ctxt->setContextProperty("testModel", &model);
583
584     TestObject *testObject = new TestObject;
585     testObject->setAnimate(animated);
586     ctxt->setContextProperty("testObject", testObject);
587
588     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
589     qApp->processEvents();
590
591     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
592     QTRY_VERIFY(listview != 0);
593
594     QDeclarativeItem *contentItem = listview->contentItem();
595     QTRY_VERIFY(contentItem != 0);
596
597     model.removeItem(1);
598     QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
599
600     QDeclarative1Text *name = findItem<QDeclarative1Text>(contentItem, "textName", 1);
601     QTRY_VERIFY(name != 0);
602     QTRY_COMPARE(name->text(), model.name(1));
603     QDeclarative1Text *number = findItem<QDeclarative1Text>(contentItem, "textNumber", 1);
604     QTRY_VERIFY(number != 0);
605     QTRY_COMPARE(number->text(), model.number(1));
606
607     // Confirm items positioned correctly
608     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
609     for (int i = 0; i < model.count() && i < itemCount; ++i) {
610         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
611         if (!item) qWarning() << "Item" << i << "not found";
612         QTRY_VERIFY(item);
613         QTRY_VERIFY(item->y() == i*20);
614     }
615
616     // Remove first item (which is the current item);
617     model.removeItem(0);  // post: top item starts at 20
618
619     QTest::qWait(300);
620
621     name = findItem<QDeclarative1Text>(contentItem, "textName", 0);
622     QTRY_VERIFY(name != 0);
623     QTRY_COMPARE(name->text(), model.name(0));
624     number = findItem<QDeclarative1Text>(contentItem, "textNumber", 0);
625     QTRY_VERIFY(number != 0);
626     QTRY_COMPARE(number->text(), model.number(0));
627
628     // Confirm items positioned correctly
629     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
630     for (int i = 0; i < model.count() && i < itemCount; ++i) {
631         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
632         if (!item) qWarning() << "Item" << i << "not found";
633         QTRY_VERIFY(item);
634         QTRY_COMPARE(item->y(),i*20.0 + 20.0);
635     }
636
637     // Remove items not visible
638     model.removeItem(18);
639     qApp->processEvents();
640
641     // Confirm items positioned correctly
642     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
643     for (int i = 0; i < model.count() && i < itemCount; ++i) {
644         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
645         if (!item) qWarning() << "Item" << i << "not found";
646         QTRY_VERIFY(item);
647         QTRY_COMPARE(item->y(),i*20.0+20.0);
648     }
649
650     // Remove items before visible
651     listview->setContentY(80);
652     listview->setCurrentIndex(10);
653
654     model.removeItem(1); // post: top item will be at 40
655     qApp->processEvents();
656
657     // Confirm items positioned correctly
658     for (int i = 2; i < 18; ++i) {
659         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
660         if (!item) qWarning() << "Item" << i << "not found";
661         QTRY_VERIFY(item);
662         QTRY_COMPARE(item->y(),40+i*20.0);
663     }
664
665     // Remove current index
666     QTRY_VERIFY(listview->currentIndex() == 9);
667     QDeclarativeItem *oldCurrent = listview->currentItem();
668     model.removeItem(9);
669
670     QTRY_COMPARE(listview->currentIndex(), 9);
671     QTRY_VERIFY(listview->currentItem() != oldCurrent);
672
673     listview->setContentY(40); // That's the top now
674     // let transitions settle.
675     QTest::qWait(300);
676
677     // Confirm items positioned correctly
678     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
679     for (int i = 0; i < model.count() && i < itemCount; ++i) {
680         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
681         if (!item) qWarning() << "Item" << i << "not found";
682         QTRY_VERIFY(item);
683         QTRY_COMPARE(item->y(),40+i*20.0);
684     }
685
686     // remove current item beyond visible items.
687     listview->setCurrentIndex(20);
688     listview->setContentY(40);
689     model.removeItem(20);
690
691     QTRY_COMPARE(listview->currentIndex(), 20);
692     QTRY_VERIFY(listview->currentItem() != 0);
693
694     // remove item before current, but visible
695     listview->setCurrentIndex(8);
696     oldCurrent = listview->currentItem();
697     model.removeItem(6);
698
699     QTRY_COMPARE(listview->currentIndex(), 7);
700     QTRY_VERIFY(listview->currentItem() == oldCurrent);
701
702     listview->setContentY(80);
703     QTest::qWait(300);
704
705     // remove all visible items
706     model.removeItems(1, 18);
707     QTest::qWait(300);
708
709     // Confirm items positioned correctly
710     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
711     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
712         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i+2);
713         if (!item) qWarning() << "Item" << i+2 << "not found";
714         QTRY_VERIFY(item);
715         QTRY_COMPARE(item->y(),80+i*20.0);
716     }
717
718     model.removeItems(1, 17);
719 //    QTest::qWait(300);
720
721     model.removeItems(2, 1);
722     model.addItem("New", "1");
723
724     QTRY_VERIFY(name = findItem<QDeclarative1Text>(contentItem, "textName", model.count()-1));
725     QCOMPARE(name->text(), QString("New"));
726
727     // Add some more items so that we don't run out
728     model.clear();
729     for (int i = 0; i < 50; i++)
730         model.addItem("Item" + QString::number(i), "");
731
732     // QTBUG-QTBUG-20575
733     listview->setCurrentIndex(0);
734     listview->setContentY(30);
735     model.removeItem(0);
736     QTRY_VERIFY(name = findItem<QDeclarative1Text>(contentItem, "textName", 0));
737
738     // QTBUG-19198 move to end and remove all visible items one at a time.
739     listview->positionViewAtEnd();
740     for (int i = 0; i < 18; ++i)
741         model.removeItems(model.count() - 1, 1);
742     QTRY_VERIFY(findItems<QDeclarativeItem>(contentItem, "wrapper").count() > 16);
743
744     delete canvas;
745     delete testObject;
746 }
747
748 template <class T>
749 void tst_QDeclarative1ListView::clear()
750 {
751     QDeclarativeView *canvas = createView();
752
753     T model;
754     for (int i = 0; i < 30; i++)
755         model.addItem("Item" + QString::number(i), "");
756
757     QDeclarativeContext *ctxt = canvas->rootContext();
758     ctxt->setContextProperty("testModel", &model);
759
760     TestObject *testObject = new TestObject;
761     ctxt->setContextProperty("testObject", testObject);
762
763     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
764     qApp->processEvents();
765
766     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
767     QTRY_VERIFY(listview != 0);
768
769     QDeclarativeItem *contentItem = listview->contentItem();
770     QTRY_VERIFY(contentItem != 0);
771
772     model.clear();
773
774     QTRY_VERIFY(listview->count() == 0);
775     QTRY_VERIFY(listview->currentItem() == 0);
776     QTRY_VERIFY(listview->contentY() == 0);
777     QVERIFY(listview->currentIndex() == -1);
778
779     // confirm sanity when adding an item to cleared list
780     model.addItem("New", "1");
781     QTRY_VERIFY(listview->count() == 1);
782     QVERIFY(listview->currentItem() != 0);
783     QVERIFY(listview->currentIndex() == 0);
784
785     delete canvas;
786     delete testObject;
787 }
788
789
790 template <class T>
791 void tst_QDeclarative1ListView::moved()
792 {
793     QDeclarativeView *canvas = createView();
794
795     T model;
796     for (int i = 0; i < 30; i++)
797         model.addItem("Item" + QString::number(i), "");
798
799     QDeclarativeContext *ctxt = canvas->rootContext();
800     ctxt->setContextProperty("testModel", &model);
801
802     TestObject *testObject = new TestObject;
803     ctxt->setContextProperty("testObject", testObject);
804
805     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
806     qApp->processEvents();
807
808     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
809     QTRY_VERIFY(listview != 0);
810
811     QDeclarativeItem *contentItem = listview->contentItem();
812     QTRY_VERIFY(contentItem != 0);
813
814     model.moveItem(1, 4);
815
816     QDeclarative1Text *name = findItem<QDeclarative1Text>(contentItem, "textName", 1);
817     QTRY_VERIFY(name != 0);
818     QTRY_COMPARE(name->text(), model.name(1));
819     QDeclarative1Text *number = findItem<QDeclarative1Text>(contentItem, "textNumber", 1);
820     QTRY_VERIFY(number != 0);
821     QTRY_COMPARE(number->text(), model.number(1));
822
823     name = findItem<QDeclarative1Text>(contentItem, "textName", 4);
824     QTRY_VERIFY(name != 0);
825     QTRY_COMPARE(name->text(), model.name(4));
826     number = findItem<QDeclarative1Text>(contentItem, "textNumber", 4);
827     QTRY_VERIFY(number != 0);
828     QTRY_COMPARE(number->text(), model.number(4));
829
830     // Confirm items positioned correctly
831     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
832     for (int i = 0; i < model.count() && i < itemCount; ++i) {
833         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
834         if (!item) qWarning() << "Item" << i << "not found";
835         QTRY_VERIFY(item);
836         QTRY_VERIFY(item->y() == i*20);
837     }
838
839     listview->setContentY(80);
840
841     // move outside visible area
842     model.moveItem(1, 18);
843
844     // Confirm items positioned correctly and indexes correct
845     for (int i = 3; i < model.count() && i < itemCount; ++i) {
846         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
847         if (!item) qWarning() << "Item" << i << "not found";
848         QTRY_VERIFY(item);
849         QTRY_COMPARE(item->y(), i*20.0 + 20);
850         name = findItem<QDeclarative1Text>(contentItem, "textName", i);
851         QTRY_VERIFY(name != 0);
852         QTRY_COMPARE(name->text(), model.name(i));
853         number = findItem<QDeclarative1Text>(contentItem, "textNumber", i);
854         QTRY_VERIFY(number != 0);
855         QTRY_COMPARE(number->text(), model.number(i));
856     }
857
858     // move from outside visible into visible
859     model.moveItem(20, 4);
860
861     // Confirm items positioned correctly and indexes correct
862     for (int i = 3; i < model.count() && i < itemCount; ++i) {
863         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
864         if (!item) qWarning() << "Item" << i << "not found";
865         QTRY_VERIFY(item);
866         QTRY_COMPARE(item->y(), i*20.0 + 20);
867         name = findItem<QDeclarative1Text>(contentItem, "textName", i);
868         QTRY_VERIFY(name != 0);
869         QTRY_COMPARE(name->text(), model.name(i));
870         number = findItem<QDeclarative1Text>(contentItem, "textNumber", i);
871         QTRY_VERIFY(number != 0);
872         QTRY_COMPARE(number->text(), model.number(i));
873     }
874
875     delete canvas;
876     delete testObject;
877 }
878
879 void tst_QDeclarative1ListView::enforceRange()
880 {
881     QDeclarativeView *canvas = createView();
882
883     TestModel model;
884     for (int i = 0; i < 30; i++)
885         model.addItem("Item" + QString::number(i), "");
886
887     QDeclarativeContext *ctxt = canvas->rootContext();
888     ctxt->setContextProperty("testModel", &model);
889
890     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listview-enforcerange.qml"));
891     qApp->processEvents();
892
893     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
894     QTRY_VERIFY(listview != 0);
895
896     QTRY_COMPARE(listview->preferredHighlightBegin(), 100.0);
897     QTRY_COMPARE(listview->preferredHighlightEnd(), 100.0);
898     QTRY_COMPARE(listview->highlightRangeMode(), QDeclarative1ListView::StrictlyEnforceRange);
899
900     QDeclarativeItem *contentItem = listview->contentItem();
901     QTRY_VERIFY(contentItem != 0);
902
903     // view should be positioned at the top of the range.
904     QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", 0);
905     QTRY_VERIFY(item);
906     QTRY_COMPARE(listview->contentY(), -100.0);
907
908     QDeclarative1Text *name = findItem<QDeclarative1Text>(contentItem, "textName", 0);
909     QTRY_VERIFY(name != 0);
910     QTRY_COMPARE(name->text(), model.name(0));
911     QDeclarative1Text *number = findItem<QDeclarative1Text>(contentItem, "textNumber", 0);
912     QTRY_VERIFY(number != 0);
913     QTRY_COMPARE(number->text(), model.number(0));
914
915     // Check currentIndex is updated when contentItem moves
916     listview->setContentY(20);
917
918     QTRY_COMPARE(listview->currentIndex(), 6);
919
920     // change model
921     TestModel model2;
922     for (int i = 0; i < 5; i++)
923         model2.addItem("Item" + QString::number(i), "");
924
925     ctxt->setContextProperty("testModel", &model2);
926     QCOMPARE(listview->count(), 5);
927
928     delete canvas;
929 }
930
931 void tst_QDeclarative1ListView::spacing()
932 {
933     QDeclarativeView *canvas = createView();
934
935     TestModel model;
936     for (int i = 0; i < 30; i++)
937         model.addItem("Item" + QString::number(i), "");
938
939     QDeclarativeContext *ctxt = canvas->rootContext();
940     ctxt->setContextProperty("testModel", &model);
941
942     TestObject *testObject = new TestObject;
943     ctxt->setContextProperty("testObject", testObject);
944
945     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
946     qApp->processEvents();
947
948     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
949     QTRY_VERIFY(listview != 0);
950
951     QDeclarativeItem *contentItem = listview->contentItem();
952     QTRY_VERIFY(contentItem != 0);
953
954     // Confirm items positioned correctly
955     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
956     for (int i = 0; i < model.count() && i < itemCount; ++i) {
957         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
958         if (!item) qWarning() << "Item" << i << "not found";
959         QTRY_VERIFY(item);
960         QTRY_VERIFY(item->y() == i*20);
961     }
962
963     listview->setSpacing(10);
964     QTRY_VERIFY(listview->spacing() == 10);
965
966     // Confirm items positioned correctly
967     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
968     for (int i = 0; i < model.count() && i < itemCount; ++i) {
969         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
970         if (!item) qWarning() << "Item" << i << "not found";
971         QTRY_VERIFY(item);
972         QTRY_VERIFY(item->y() == i*30);
973     }
974
975     listview->setSpacing(0);
976
977     // Confirm items positioned correctly
978     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
979     for (int i = 0; i < model.count() && i < itemCount; ++i) {
980         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
981         if (!item) qWarning() << "Item" << i << "not found";
982         QTRY_VERIFY(item);
983         QTRY_COMPARE(item->y(), i*20.0);
984     }
985
986     delete canvas;
987     delete testObject;
988 }
989
990 void tst_QDeclarative1ListView::sections()
991 {
992     QDeclarativeView *canvas = createView();
993
994     TestModel model;
995     for (int i = 0; i < 30; i++)
996         model.addItem("Item" + QString::number(i), QString::number(i/5));
997
998     QDeclarativeContext *ctxt = canvas->rootContext();
999     ctxt->setContextProperty("testModel", &model);
1000
1001     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listview-sections.qml"));
1002     qApp->processEvents();
1003
1004     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1005     QTRY_VERIFY(listview != 0);
1006
1007     QDeclarativeItem *contentItem = listview->contentItem();
1008     QTRY_VERIFY(contentItem != 0);
1009
1010     // Confirm items positioned correctly
1011     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1012     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1013         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1014         QTRY_VERIFY(item);
1015         QTRY_COMPARE(item->y(), qreal(i*20 + ((i+4)/5) * 20));
1016         QDeclarative1Text *next = findItem<QDeclarative1Text>(item, "nextSection");
1017         QCOMPARE(next->text().toInt(), (i+1)/5);
1018     }
1019
1020     QSignalSpy currentSectionChangedSpy(listview, SIGNAL(currentSectionChanged()));
1021
1022     // Remove section boundary
1023     model.removeItem(5);
1024
1025     // New section header created
1026     QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", 5);
1027     QTRY_VERIFY(item);
1028     QTRY_COMPARE(item->height(), 40.0);
1029
1030     model.insertItem(3, "New Item", "0");
1031
1032     // Section header moved
1033     item = findItem<QDeclarativeItem>(contentItem, "wrapper", 5);
1034     QTRY_VERIFY(item);
1035     QTRY_COMPARE(item->height(), 20.0);
1036
1037     item = findItem<QDeclarativeItem>(contentItem, "wrapper", 6);
1038     QTRY_VERIFY(item);
1039     QTRY_COMPARE(item->height(), 40.0);
1040
1041     // insert item which will become a section header
1042     model.insertItem(6, "Replace header", "1");
1043
1044     item = findItem<QDeclarativeItem>(contentItem, "wrapper", 6);
1045     QTRY_VERIFY(item);
1046     QTRY_COMPARE(item->height(), 40.0);
1047
1048     item = findItem<QDeclarativeItem>(contentItem, "wrapper", 7);
1049     QTRY_VERIFY(item);
1050     QTRY_COMPARE(item->height(), 20.0);
1051
1052     QTRY_COMPARE(listview->currentSection(), QString("0"));
1053
1054     listview->setContentY(140);
1055     QTRY_COMPARE(listview->currentSection(), QString("1"));
1056
1057     QTRY_COMPARE(currentSectionChangedSpy.count(), 1);
1058
1059     listview->setContentY(20);
1060     QTRY_COMPARE(listview->currentSection(), QString("0"));
1061
1062     QTRY_COMPARE(currentSectionChangedSpy.count(), 2);
1063
1064     item = findItem<QDeclarativeItem>(contentItem, "wrapper", 1);
1065     QTRY_VERIFY(item);
1066     QTRY_COMPARE(item->height(), 20.0);
1067
1068     // check that headers change when item changes
1069     listview->setContentY(0);
1070     model.modifyItem(0, "changed", "2");
1071
1072     item = findItem<QDeclarativeItem>(contentItem, "wrapper", 1);
1073     QTRY_VERIFY(item);
1074     QTRY_COMPARE(item->height(), 40.0);
1075
1076     delete canvas;
1077 }
1078
1079 void tst_QDeclarative1ListView::sectionsDelegate()
1080 {
1081     QDeclarativeView *canvas = createView();
1082
1083     TestModel model;
1084     for (int i = 0; i < 30; i++)
1085         model.addItem("Item" + QString::number(i), QString::number(i/5));
1086
1087     QDeclarativeContext *ctxt = canvas->rootContext();
1088     ctxt->setContextProperty("testModel", &model);
1089
1090     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listview-sections_delegate.qml"));
1091     qApp->processEvents();
1092
1093     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1094     QTRY_VERIFY(listview != 0);
1095
1096     QDeclarativeItem *contentItem = listview->contentItem();
1097     QTRY_VERIFY(contentItem != 0);
1098
1099     // Confirm items positioned correctly
1100     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1101     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1102         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1103         QTRY_VERIFY(item);
1104         QTRY_COMPARE(item->y(), qreal(i*20 + ((i+5)/5) * 20));
1105         QDeclarative1Text *next = findItem<QDeclarative1Text>(item, "nextSection");
1106         QCOMPARE(next->text().toInt(), (i+1)/5);
1107     }
1108
1109     for (int i = 0; i < 3; ++i) {
1110         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "sect_" + QString::number(i));
1111         QVERIFY(item);
1112         QTRY_COMPARE(item->y(), qreal(i*20*6));
1113     }
1114
1115     model.modifyItem(0, "One", "aaa");
1116     model.modifyItem(1, "Two", "aaa");
1117     model.modifyItem(2, "Three", "aaa");
1118     model.modifyItem(3, "Four", "aaa");
1119     model.modifyItem(4, "Five", "aaa");
1120
1121     for (int i = 0; i < 3; ++i) {
1122         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem,
1123                 "sect_" + (i == 0 ? QString("aaa") : QString::number(i)));
1124         QVERIFY(item);
1125         QTRY_COMPARE(item->y(), qreal(i*20*6));
1126     }
1127
1128     // remove section boundary
1129     model.removeItem(5);
1130     qApp->processEvents();
1131     for (int i = 0; i < 3; ++i) {
1132         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem,
1133                 "sect_" + (i == 0 ? QString("aaa") : QString::number(i)));
1134         QVERIFY(item);
1135     }
1136
1137     // QTBUG-17606
1138     QList<QDeclarativeItem*> items = findItems<QDeclarativeItem>(contentItem, "sect_1");
1139     QCOMPARE(items.count(), 1);
1140
1141     // QTBUG-17759
1142     model.modifyItem(0, "One", "aaa");
1143     model.modifyItem(1, "One", "aaa");
1144     model.modifyItem(2, "One", "aaa");
1145     model.modifyItem(3, "Four", "aaa");
1146     model.modifyItem(4, "Four", "aaa");
1147     model.modifyItem(5, "Four", "aaa");
1148     model.modifyItem(6, "Five", "aaa");
1149     model.modifyItem(7, "Five", "aaa");
1150     model.modifyItem(8, "Five", "aaa");
1151     model.modifyItem(9, "Two", "aaa");
1152     model.modifyItem(10, "Two", "aaa");
1153     model.modifyItem(11, "Two", "aaa");
1154     QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_aaa").count(), 1);
1155     canvas->rootObject()->setProperty("sectionProperty", "name");
1156     // ensure view has settled.
1157     QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_Four").count(), 1);
1158     for (int i = 0; i < 4; ++i) {
1159         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem,
1160                 "sect_" + model.name(i*3));
1161         QVERIFY(item);
1162         QTRY_COMPARE(item->y(), qreal(i*20*4));
1163     }
1164
1165     // QTBUG-17769
1166     model.removeItems(10, 20);
1167     // ensure view has settled.
1168     QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "wrapper").count(), 10);
1169     // Drag view up beyond bounds
1170     QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,20)));
1171     {
1172         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,0)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1173         QApplication::sendEvent(canvas->viewport(), &mv);
1174     }
1175     {
1176         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-50)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1177         QApplication::sendEvent(canvas->viewport(), &mv);
1178     }
1179     {
1180         QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-200)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
1181         QApplication::sendEvent(canvas->viewport(), &mv);
1182     }
1183     QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,-200)));
1184     // view should settle back at 0
1185     QTRY_COMPARE(listview->contentY(), 0.0);
1186
1187     delete canvas;
1188 }
1189
1190 void tst_QDeclarative1ListView::currentIndex()
1191 {
1192     TestModel model;
1193     for (int i = 0; i < 30; i++)
1194         model.addItem("Item" + QString::number(i), QString::number(i));
1195
1196     QDeclarativeView *canvas = new QDeclarativeView(0);
1197     canvas->setFixedSize(240,320);
1198
1199     QDeclarativeContext *ctxt = canvas->rootContext();
1200     ctxt->setContextProperty("testModel", &model);
1201     ctxt->setContextProperty("testWrap", QVariant(false));
1202
1203     QString filename(SRCDIR "/data/listview-initCurrent.qml");
1204     canvas->setSource(QUrl::fromLocalFile(filename));
1205
1206     qApp->processEvents();
1207
1208     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1209     QTRY_VERIFY(listview != 0);
1210
1211     QDeclarativeItem *contentItem = listview->contentItem();
1212     QTRY_VERIFY(contentItem != 0);
1213
1214     // current item should be 20th item at startup
1215     // and current item should be in view
1216     QCOMPARE(listview->currentIndex(), 20);
1217     QCOMPARE(listview->contentY(), 100.0);
1218     QCOMPARE(listview->currentItem(), findItem<QDeclarativeItem>(contentItem, "wrapper", 20));
1219     QCOMPARE(listview->highlightItem()->y(), listview->currentItem()->y());
1220
1221     // no wrap
1222     listview->setCurrentIndex(0);
1223     QCOMPARE(listview->currentIndex(), 0);
1224     // confirm that the velocity is updated
1225     QTRY_VERIFY(listview->verticalVelocity() != 0.0);
1226
1227     listview->incrementCurrentIndex();
1228     QCOMPARE(listview->currentIndex(), 1);
1229     listview->decrementCurrentIndex();
1230     QCOMPARE(listview->currentIndex(), 0);
1231
1232     listview->decrementCurrentIndex();
1233     QCOMPARE(listview->currentIndex(), 0);
1234
1235     // with wrap
1236     ctxt->setContextProperty("testWrap", QVariant(true));
1237     QVERIFY(listview->isWrapEnabled());
1238
1239     listview->decrementCurrentIndex();
1240     QCOMPARE(listview->currentIndex(), model.count()-1);
1241
1242     QTRY_COMPARE(listview->contentY(), 280.0);
1243
1244     listview->incrementCurrentIndex();
1245     QCOMPARE(listview->currentIndex(), 0);
1246
1247     QTRY_COMPARE(listview->contentY(), 0.0);
1248
1249     // Test keys
1250     canvas->show();
1251     qApp->setActiveWindow(canvas);
1252 #ifdef Q_WS_X11
1253     // to be safe and avoid failing setFocus with window managers
1254     qt_x11_wait_for_window_manager(canvas);
1255 #endif
1256     QTRY_VERIFY(canvas->hasFocus());
1257     QTRY_VERIFY(canvas->scene()->hasFocus());
1258     qApp->processEvents();
1259
1260     QTest::keyClick(canvas, Qt::Key_Down);
1261     QCOMPARE(listview->currentIndex(), 1);
1262
1263     QTest::keyClick(canvas, Qt::Key_Up);
1264     QCOMPARE(listview->currentIndex(), 0);
1265
1266     // turn off auto highlight
1267     listview->setHighlightFollowsCurrentItem(false);
1268     QVERIFY(listview->highlightFollowsCurrentItem() == false);
1269
1270     QVERIFY(listview->highlightItem());
1271     qreal hlPos = listview->highlightItem()->y();
1272
1273     listview->setCurrentIndex(4);
1274     QTRY_COMPARE(listview->highlightItem()->y(), hlPos);
1275
1276     // insert item before currentIndex
1277     listview->setCurrentIndex(28);
1278     model.insertItem(0, "Foo", "1111");
1279     QTRY_COMPARE(canvas->rootObject()->property("current").toInt(), 29);
1280
1281     // check removing highlight by setting currentIndex to -1;
1282     listview->setCurrentIndex(-1);
1283
1284     QCOMPARE(listview->currentIndex(), -1);
1285     QVERIFY(!listview->highlightItem());
1286     QVERIFY(!listview->currentItem());
1287
1288     delete canvas;
1289 }
1290
1291 void tst_QDeclarative1ListView::noCurrentIndex()
1292 {
1293     TestModel model;
1294     for (int i = 0; i < 30; i++)
1295         model.addItem("Item" + QString::number(i), QString::number(i));
1296
1297     QDeclarativeView *canvas = new QDeclarativeView(0);
1298     canvas->setFixedSize(240,320);
1299
1300     QDeclarativeContext *ctxt = canvas->rootContext();
1301     ctxt->setContextProperty("testModel", &model);
1302
1303     QString filename(SRCDIR "/data/listview-noCurrent.qml");
1304     canvas->setSource(QUrl::fromLocalFile(filename));
1305
1306     qApp->processEvents();
1307
1308     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1309     QTRY_VERIFY(listview != 0);
1310
1311     QDeclarativeItem *contentItem = listview->contentItem();
1312     QTRY_VERIFY(contentItem != 0);
1313
1314     // current index should be -1 at startup
1315     // and we should not have a currentItem or highlightItem
1316     QCOMPARE(listview->currentIndex(), -1);
1317     QCOMPARE(listview->contentY(), 0.0);
1318     QVERIFY(!listview->highlightItem());
1319     QVERIFY(!listview->currentItem());
1320
1321     listview->setCurrentIndex(2);
1322     QCOMPARE(listview->currentIndex(), 2);
1323     QVERIFY(listview->highlightItem());
1324     QVERIFY(listview->currentItem());
1325
1326     delete canvas;
1327 }
1328
1329 void tst_QDeclarative1ListView::itemList()
1330 {
1331     QDeclarativeView *canvas = createView();
1332
1333     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/itemlist.qml"));
1334     qApp->processEvents();
1335
1336     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "view");
1337     QTRY_VERIFY(listview != 0);
1338
1339     QDeclarativeItem *contentItem = listview->contentItem();
1340     QTRY_VERIFY(contentItem != 0);
1341
1342     QDeclarative1VisualItemModel *model = canvas->rootObject()->findChild<QDeclarative1VisualItemModel*>("itemModel");
1343     QTRY_VERIFY(model != 0);
1344
1345     QTRY_VERIFY(model->count() == 3);
1346     QTRY_COMPARE(listview->currentIndex(), 0);
1347
1348     QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "item1");
1349     QTRY_VERIFY(item);
1350     QTRY_COMPARE(item->x(), 0.0);
1351     QCOMPARE(item->height(), listview->height());
1352
1353     QDeclarative1Text *text = findItem<QDeclarative1Text>(contentItem, "text1");
1354     QTRY_VERIFY(text);
1355     QTRY_COMPARE(text->text(), QLatin1String("index: 0"));
1356
1357     listview->setCurrentIndex(2);
1358
1359     item = findItem<QDeclarativeItem>(contentItem, "item3");
1360     QTRY_VERIFY(item);
1361     QTRY_COMPARE(item->x(), 480.0);
1362
1363     text = findItem<QDeclarative1Text>(contentItem, "text3");
1364     QTRY_VERIFY(text);
1365     QTRY_COMPARE(text->text(), QLatin1String("index: 2"));
1366
1367     delete canvas;
1368 }
1369
1370 void tst_QDeclarative1ListView::cacheBuffer()
1371 {
1372     QDeclarativeView *canvas = createView();
1373
1374     TestModel model;
1375     for (int i = 0; i < 30; i++)
1376         model.addItem("Item" + QString::number(i), "");
1377
1378     QDeclarativeContext *ctxt = canvas->rootContext();
1379     ctxt->setContextProperty("testModel", &model);
1380
1381     TestObject *testObject = new TestObject;
1382     ctxt->setContextProperty("testObject", testObject);
1383
1384     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
1385     qApp->processEvents();
1386
1387     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1388     QTRY_VERIFY(listview != 0);
1389
1390     QDeclarativeItem *contentItem = listview->contentItem();
1391     QTRY_VERIFY(contentItem != 0);
1392     QTRY_VERIFY(listview->delegate() != 0);
1393     QTRY_VERIFY(listview->model() != 0);
1394     QTRY_VERIFY(listview->highlight() != 0);
1395
1396     // Confirm items positioned correctly
1397     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1398     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1399         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1400         if (!item) qWarning() << "Item" << i << "not found";
1401         QTRY_VERIFY(item);
1402         QTRY_VERIFY(item->y() == i*20);
1403     }
1404
1405     testObject->setCacheBuffer(400);
1406     QTRY_VERIFY(listview->cacheBuffer() == 400);
1407
1408     int newItemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1409     QTRY_VERIFY(newItemCount > itemCount);
1410
1411     // Confirm items positioned correctly
1412     for (int i = 0; i < model.count() && i < newItemCount; ++i) {
1413         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1414         if (!item) qWarning() << "Item" << i << "not found";
1415         QTRY_VERIFY(item);
1416         QTRY_VERIFY(item->y() == i*20);
1417     }
1418
1419     delete canvas;
1420     delete testObject;
1421 }
1422
1423 void tst_QDeclarative1ListView::positionViewAtIndex()
1424 {
1425     QDeclarativeView *canvas = createView();
1426
1427     TestModel model;
1428     for (int i = 0; i < 40; i++)
1429         model.addItem("Item" + QString::number(i), "");
1430
1431     QDeclarativeContext *ctxt = canvas->rootContext();
1432     ctxt->setContextProperty("testModel", &model);
1433
1434     TestObject *testObject = new TestObject;
1435     ctxt->setContextProperty("testObject", testObject);
1436
1437     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
1438     qApp->processEvents();
1439
1440     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1441     QTRY_VERIFY(listview != 0);
1442
1443     QDeclarativeItem *contentItem = listview->contentItem();
1444     QTRY_VERIFY(contentItem != 0);
1445
1446     // Confirm items positioned correctly
1447     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1448     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1449         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1450         if (!item) qWarning() << "Item" << i << "not found";
1451         QTRY_VERIFY(item);
1452         QTRY_COMPARE(item->y(), i*20.);
1453     }
1454
1455     // Position on a currently visible item
1456     listview->positionViewAtIndex(3, QDeclarative1ListView::Beginning);
1457     QTRY_COMPARE(listview->contentY(), 60.);
1458
1459     // Confirm items positioned correctly
1460     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1461     for (int i = 3; i < model.count() && i < itemCount-3-1; ++i) {
1462         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1463         if (!item) qWarning() << "Item" << i << "not found";
1464         QTRY_VERIFY(item);
1465         QTRY_COMPARE(item->y(), i*20.);
1466     }
1467
1468     // Position on an item beyond the visible items
1469     listview->positionViewAtIndex(22, QDeclarative1ListView::Beginning);
1470     QTRY_COMPARE(listview->contentY(), 440.);
1471
1472     // Confirm items positioned correctly
1473     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1474     for (int i = 22; i < model.count() && i < itemCount-22-1; ++i) {
1475         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1476         if (!item) qWarning() << "Item" << i << "not found";
1477         QTRY_VERIFY(item);
1478         QTRY_COMPARE(item->y(), i*20.);
1479     }
1480
1481     // Position on an item that would leave empty space if positioned at the top
1482     listview->positionViewAtIndex(28, QDeclarative1ListView::Beginning);
1483     QTRY_COMPARE(listview->contentY(), 480.);
1484
1485     // Confirm items positioned correctly
1486     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1487     for (int i = 24; i < model.count() && i < itemCount-24-1; ++i) {
1488         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1489         if (!item) qWarning() << "Item" << i << "not found";
1490         QTRY_VERIFY(item);
1491         QTRY_COMPARE(item->y(), i*20.);
1492     }
1493
1494     // Position at the beginning again
1495     listview->positionViewAtIndex(0, QDeclarative1ListView::Beginning);
1496     QTRY_COMPARE(listview->contentY(), 0.);
1497
1498     // Confirm items positioned correctly
1499     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1500     for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
1501         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1502         if (!item) qWarning() << "Item" << i << "not found";
1503         QTRY_VERIFY(item);
1504         QTRY_COMPARE(item->y(), i*20.);
1505     }
1506
1507     // Position at End using last index
1508     listview->positionViewAtIndex(model.count()-1, QDeclarative1ListView::End);
1509     QTRY_COMPARE(listview->contentY(), 480.);
1510
1511     // Confirm items positioned correctly
1512     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1513     for (int i = 24; i < model.count(); ++i) {
1514         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1515         if (!item) qWarning() << "Item" << i << "not found";
1516         QTRY_VERIFY(item);
1517         QTRY_COMPARE(item->y(), i*20.);
1518     }
1519
1520     // Position at End
1521     listview->positionViewAtIndex(20, QDeclarative1ListView::End);
1522     QTRY_COMPARE(listview->contentY(), 100.);
1523
1524     // Position in Center
1525     listview->positionViewAtIndex(15, QDeclarative1ListView::Center);
1526     QTRY_COMPARE(listview->contentY(), 150.);
1527
1528     // Ensure at least partially visible
1529     listview->positionViewAtIndex(15, QDeclarative1ListView::Visible);
1530     QTRY_COMPARE(listview->contentY(), 150.);
1531
1532     listview->setContentY(302);
1533     listview->positionViewAtIndex(15, QDeclarative1ListView::Visible);
1534     QTRY_COMPARE(listview->contentY(), 302.);
1535
1536     listview->setContentY(320);
1537     listview->positionViewAtIndex(15, QDeclarative1ListView::Visible);
1538     QTRY_COMPARE(listview->contentY(), 300.);
1539
1540     listview->setContentY(85);
1541     listview->positionViewAtIndex(20, QDeclarative1ListView::Visible);
1542     QTRY_COMPARE(listview->contentY(), 85.);
1543
1544     listview->setContentY(75);
1545     listview->positionViewAtIndex(20, QDeclarative1ListView::Visible);
1546     QTRY_COMPARE(listview->contentY(), 100.);
1547
1548     // Ensure completely visible
1549     listview->setContentY(120);
1550     listview->positionViewAtIndex(20, QDeclarative1ListView::Contain);
1551     QTRY_COMPARE(listview->contentY(), 120.);
1552
1553     listview->setContentY(302);
1554     listview->positionViewAtIndex(15, QDeclarative1ListView::Contain);
1555     QTRY_COMPARE(listview->contentY(), 300.);
1556
1557     listview->setContentY(85);
1558     listview->positionViewAtIndex(20, QDeclarative1ListView::Contain);
1559     QTRY_COMPARE(listview->contentY(), 100.);
1560
1561     // positionAtBeginnging
1562     listview->positionViewAtBeginning();
1563     QTRY_COMPARE(listview->contentY(), 0.);
1564
1565     listview->setContentY(80);
1566     canvas->rootObject()->setProperty("showHeader", true);
1567     listview->positionViewAtBeginning();
1568     QTRY_COMPARE(listview->contentY(), -30.);
1569
1570     // positionAtEnd
1571     listview->positionViewAtEnd();
1572     QTRY_COMPARE(listview->contentY(), 480.); // 40*20 - 320
1573
1574     listview->setContentY(80);
1575     canvas->rootObject()->setProperty("showFooter", true);
1576     listview->positionViewAtEnd();
1577     QTRY_COMPARE(listview->contentY(), 510.);
1578
1579     delete canvas;
1580     delete testObject;
1581 }
1582
1583 void tst_QDeclarative1ListView::resetModel()
1584 {
1585     QDeclarativeView *canvas = createView();
1586
1587     QStringList strings;
1588     strings << "one" << "two" << "three";
1589     QStringListModel model(strings);
1590
1591     QDeclarativeContext *ctxt = canvas->rootContext();
1592     ctxt->setContextProperty("testModel", &model);
1593
1594     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml"));
1595     qApp->processEvents();
1596
1597     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1598     QTRY_VERIFY(listview != 0);
1599
1600     QDeclarativeItem *contentItem = listview->contentItem();
1601     QTRY_VERIFY(contentItem != 0);
1602
1603     QTRY_COMPARE(listview->count(), model.rowCount());
1604
1605     for (int i = 0; i < model.rowCount(); ++i) {
1606         QDeclarative1Text *display = findItem<QDeclarative1Text>(contentItem, "displayText", i);
1607         QTRY_VERIFY(display != 0);
1608         QTRY_COMPARE(display->text(), strings.at(i));
1609     }
1610
1611     strings.clear();
1612     strings << "four" << "five" << "six" << "seven";
1613     model.setStringList(strings);
1614
1615     QTRY_COMPARE(listview->count(), model.rowCount());
1616
1617     for (int i = 0; i < model.rowCount(); ++i) {
1618         QDeclarative1Text *display = findItem<QDeclarative1Text>(contentItem, "displayText", i);
1619         QTRY_VERIFY(display != 0);
1620         QTRY_COMPARE(display->text(), strings.at(i));
1621     }
1622
1623     delete canvas;
1624 }
1625
1626 void tst_QDeclarative1ListView::propertyChanges()
1627 {
1628     QDeclarativeView *canvas = createView();
1629     QTRY_VERIFY(canvas);
1630     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1631
1632     QDeclarative1ListView *listView = canvas->rootObject()->findChild<QDeclarative1ListView*>("listView");
1633     QTRY_VERIFY(listView);
1634
1635     QSignalSpy highlightFollowsCurrentItemSpy(listView, SIGNAL(highlightFollowsCurrentItemChanged()));
1636     QSignalSpy preferredHighlightBeginSpy(listView, SIGNAL(preferredHighlightBeginChanged()));
1637     QSignalSpy preferredHighlightEndSpy(listView, SIGNAL(preferredHighlightEndChanged()));
1638     QSignalSpy highlightRangeModeSpy(listView, SIGNAL(highlightRangeModeChanged()));
1639     QSignalSpy keyNavigationWrapsSpy(listView, SIGNAL(keyNavigationWrapsChanged()));
1640     QSignalSpy cacheBufferSpy(listView, SIGNAL(cacheBufferChanged()));
1641     QSignalSpy snapModeSpy(listView, SIGNAL(snapModeChanged()));
1642
1643     QTRY_COMPARE(listView->highlightFollowsCurrentItem(), true);
1644     QTRY_COMPARE(listView->preferredHighlightBegin(), 0.0);
1645     QTRY_COMPARE(listView->preferredHighlightEnd(), 0.0);
1646     QTRY_COMPARE(listView->highlightRangeMode(), QDeclarative1ListView::ApplyRange);
1647     QTRY_COMPARE(listView->isWrapEnabled(), true);
1648     QTRY_COMPARE(listView->cacheBuffer(), 10);
1649     QTRY_COMPARE(listView->snapMode(), QDeclarative1ListView::SnapToItem);
1650
1651     listView->setHighlightFollowsCurrentItem(false);
1652     listView->setPreferredHighlightBegin(1.0);
1653     listView->setPreferredHighlightEnd(1.0);
1654     listView->setHighlightRangeMode(QDeclarative1ListView::StrictlyEnforceRange);
1655     listView->setWrapEnabled(false);
1656     listView->setCacheBuffer(3);
1657     listView->setSnapMode(QDeclarative1ListView::SnapOneItem);
1658
1659     QTRY_COMPARE(listView->highlightFollowsCurrentItem(), false);
1660     QTRY_COMPARE(listView->preferredHighlightBegin(), 1.0);
1661     QTRY_COMPARE(listView->preferredHighlightEnd(), 1.0);
1662     QTRY_COMPARE(listView->highlightRangeMode(), QDeclarative1ListView::StrictlyEnforceRange);
1663     QTRY_COMPARE(listView->isWrapEnabled(), false);
1664     QTRY_COMPARE(listView->cacheBuffer(), 3);
1665     QTRY_COMPARE(listView->snapMode(), QDeclarative1ListView::SnapOneItem);
1666
1667     QTRY_COMPARE(highlightFollowsCurrentItemSpy.count(),1);
1668     QTRY_COMPARE(preferredHighlightBeginSpy.count(),1);
1669     QTRY_COMPARE(preferredHighlightEndSpy.count(),1);
1670     QTRY_COMPARE(highlightRangeModeSpy.count(),1);
1671     QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1672     QTRY_COMPARE(cacheBufferSpy.count(),1);
1673     QTRY_COMPARE(snapModeSpy.count(),1);
1674
1675     listView->setHighlightFollowsCurrentItem(false);
1676     listView->setPreferredHighlightBegin(1.0);
1677     listView->setPreferredHighlightEnd(1.0);
1678     listView->setHighlightRangeMode(QDeclarative1ListView::StrictlyEnforceRange);
1679     listView->setWrapEnabled(false);
1680     listView->setCacheBuffer(3);
1681     listView->setSnapMode(QDeclarative1ListView::SnapOneItem);
1682
1683     QTRY_COMPARE(highlightFollowsCurrentItemSpy.count(),1);
1684     QTRY_COMPARE(preferredHighlightBeginSpy.count(),1);
1685     QTRY_COMPARE(preferredHighlightEndSpy.count(),1);
1686     QTRY_COMPARE(highlightRangeModeSpy.count(),1);
1687     QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
1688     QTRY_COMPARE(cacheBufferSpy.count(),1);
1689     QTRY_COMPARE(snapModeSpy.count(),1);
1690
1691     delete canvas;
1692 }
1693
1694 void tst_QDeclarative1ListView::componentChanges()
1695 {
1696     QDeclarativeView *canvas = createView();
1697     QTRY_VERIFY(canvas);
1698     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1699
1700     QDeclarative1ListView *listView = canvas->rootObject()->findChild<QDeclarative1ListView*>("listView");
1701     QTRY_VERIFY(listView);
1702
1703     QDeclarativeComponent component(canvas->engine());
1704     component.setData("import QtQuick 1.0; Rectangle { color: \"blue\"; }", QUrl::fromLocalFile(""));
1705
1706     QDeclarativeComponent delegateComponent(canvas->engine());
1707     delegateComponent.setData("import QtQuick 1.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
1708
1709     QSignalSpy highlightSpy(listView, SIGNAL(highlightChanged()));
1710     QSignalSpy delegateSpy(listView, SIGNAL(delegateChanged()));
1711     QSignalSpy headerSpy(listView, SIGNAL(headerChanged()));
1712     QSignalSpy footerSpy(listView, SIGNAL(footerChanged()));
1713
1714     listView->setHighlight(&component);
1715     listView->setHeader(&component);
1716     listView->setFooter(&component);
1717     listView->setDelegate(&delegateComponent);
1718
1719     QTRY_COMPARE(listView->highlight(), &component);
1720     QTRY_COMPARE(listView->header(), &component);
1721     QTRY_COMPARE(listView->footer(), &component);
1722     QTRY_COMPARE(listView->delegate(), &delegateComponent);
1723
1724     QTRY_COMPARE(highlightSpy.count(),1);
1725     QTRY_COMPARE(delegateSpy.count(),1);
1726     QTRY_COMPARE(headerSpy.count(),1);
1727     QTRY_COMPARE(footerSpy.count(),1);
1728
1729     listView->setHighlight(&component);
1730     listView->setHeader(&component);
1731     listView->setFooter(&component);
1732     listView->setDelegate(&delegateComponent);
1733
1734     QTRY_COMPARE(highlightSpy.count(),1);
1735     QTRY_COMPARE(delegateSpy.count(),1);
1736     QTRY_COMPARE(headerSpy.count(),1);
1737     QTRY_COMPARE(footerSpy.count(),1);
1738
1739     delete canvas;
1740 }
1741
1742 void tst_QDeclarative1ListView::modelChanges()
1743 {
1744     QDeclarativeView *canvas = createView();
1745     QTRY_VERIFY(canvas);
1746     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/propertychangestest.qml"));
1747
1748     QDeclarative1ListView *listView = canvas->rootObject()->findChild<QDeclarative1ListView*>("listView");
1749     QTRY_VERIFY(listView);
1750
1751     QObject *alternateModel = canvas->rootObject()->findChild<QObject*>("alternateModel");
1752     QTRY_VERIFY(alternateModel);
1753     QVariant modelVariant = QVariant::fromValue(alternateModel);
1754     QSignalSpy modelSpy(listView, SIGNAL(modelChanged()));
1755
1756     listView->setModel(modelVariant);
1757     QTRY_COMPARE(listView->model(), modelVariant);
1758     QTRY_COMPARE(modelSpy.count(),1);
1759
1760     listView->setModel(modelVariant);
1761     QTRY_COMPARE(modelSpy.count(),1);
1762
1763     listView->setModel(QVariant());
1764     QTRY_COMPARE(modelSpy.count(),2);
1765
1766     delete canvas;
1767 }
1768
1769 void tst_QDeclarative1ListView::QTBUG_9791()
1770 {
1771     QDeclarativeView *canvas = createView();
1772
1773     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/strictlyenforcerange.qml"));
1774     qApp->processEvents();
1775
1776     QDeclarative1ListView *listview = qobject_cast<QDeclarative1ListView*>(canvas->rootObject());
1777     QTRY_VERIFY(listview != 0);
1778
1779     QDeclarativeItem *contentItem = listview->contentItem();
1780     QTRY_VERIFY(contentItem != 0);
1781     QTRY_VERIFY(listview->delegate() != 0);
1782     QTRY_VERIFY(listview->model() != 0);
1783
1784     QMetaObject::invokeMethod(listview, "fillModel");
1785     qApp->processEvents();
1786
1787     // Confirm items positioned correctly
1788     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1789     QCOMPARE(itemCount, 3);
1790
1791     for (int i = 0; i < itemCount; ++i) {
1792         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1793         if (!item) qWarning() << "Item" << i << "not found";
1794         QTRY_VERIFY(item);
1795         QTRY_COMPARE(item->x(), i*300.0);
1796     }
1797
1798     // check that view is positioned correctly
1799     QTRY_COMPARE(listview->contentX(), 590.0);
1800
1801     delete canvas;
1802 }
1803
1804 void tst_QDeclarative1ListView::manualHighlight()
1805 {
1806     QDeclarativeView *canvas = new QDeclarativeView(0);
1807     canvas->setFixedSize(240,320);
1808
1809     QString filename(SRCDIR "/data/manual-highlight.qml");
1810     canvas->setSource(QUrl::fromLocalFile(filename));
1811
1812     qApp->processEvents();
1813
1814     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1815     QTRY_VERIFY(listview != 0);
1816
1817     QDeclarativeItem *contentItem = listview->contentItem();
1818     QTRY_VERIFY(contentItem != 0);
1819
1820     QTRY_COMPARE(listview->currentIndex(), 0);
1821     QTRY_COMPARE(listview->currentItem(), findItem<QDeclarativeItem>(contentItem, "wrapper", 0));
1822     QTRY_COMPARE(listview->highlightItem()->y() - 5, listview->currentItem()->y());
1823
1824     listview->setCurrentIndex(2);
1825
1826     QTRY_COMPARE(listview->currentIndex(), 2);
1827     QTRY_COMPARE(listview->currentItem(), findItem<QDeclarativeItem>(contentItem, "wrapper", 2));
1828     QTRY_COMPARE(listview->highlightItem()->y() - 5, listview->currentItem()->y());
1829
1830     // QTBUG-15972
1831     listview->positionViewAtIndex(3, QDeclarative1ListView::Contain);
1832
1833     QTRY_COMPARE(listview->currentIndex(), 2);
1834     QTRY_COMPARE(listview->currentItem(), findItem<QDeclarativeItem>(contentItem, "wrapper", 2));
1835     QTRY_COMPARE(listview->highlightItem()->y() - 5, listview->currentItem()->y());
1836
1837     delete canvas;
1838 }
1839
1840 void tst_QDeclarative1ListView::QTBUG_11105()
1841 {
1842     QDeclarativeView *canvas = createView();
1843
1844     TestModel model;
1845     for (int i = 0; i < 30; i++)
1846         model.addItem("Item" + QString::number(i), "");
1847
1848     QDeclarativeContext *ctxt = canvas->rootContext();
1849     ctxt->setContextProperty("testModel", &model);
1850
1851     TestObject *testObject = new TestObject;
1852     ctxt->setContextProperty("testObject", testObject);
1853
1854     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
1855     qApp->processEvents();
1856
1857     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1858     QTRY_VERIFY(listview != 0);
1859
1860     QDeclarativeItem *contentItem = listview->contentItem();
1861     QTRY_VERIFY(contentItem != 0);
1862
1863     // Confirm items positioned correctly
1864     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1865     for (int i = 0; i < model.count() && i < itemCount; ++i) {
1866         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
1867         if (!item) qWarning() << "Item" << i << "not found";
1868         QTRY_VERIFY(item);
1869         QTRY_VERIFY(item->y() == i*20);
1870     }
1871
1872     listview->positionViewAtIndex(20, QDeclarative1ListView::Beginning);
1873     QCOMPARE(listview->contentY(), 280.);
1874
1875     TestModel model2;
1876     for (int i = 0; i < 5; i++)
1877         model2.addItem("Item" + QString::number(i), "");
1878
1879     ctxt->setContextProperty("testModel", &model2);
1880
1881     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
1882     QCOMPARE(itemCount, 5);
1883
1884     delete canvas;
1885     delete testObject;
1886 }
1887
1888 void tst_QDeclarative1ListView::header()
1889 {
1890     {
1891         QDeclarativeView *canvas = createView();
1892
1893         TestModel model;
1894         for (int i = 0; i < 30; i++)
1895             model.addItem("Item" + QString::number(i), "");
1896
1897         QDeclarativeContext *ctxt = canvas->rootContext();
1898         ctxt->setContextProperty("testModel", &model);
1899
1900         canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
1901         qApp->processEvents();
1902
1903         QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1904         QTRY_VERIFY(listview != 0);
1905
1906         QDeclarativeItem *contentItem = listview->contentItem();
1907         QTRY_VERIFY(contentItem != 0);
1908
1909         QDeclarative1Text *header = findItem<QDeclarative1Text>(contentItem, "header");
1910         QVERIFY(header);
1911         QCOMPARE(header->y(), 0.0);
1912         QCOMPARE(header->height(), 20.0);
1913
1914         QCOMPARE(listview->contentY(), 0.0);
1915
1916         model.clear();
1917         QTRY_COMPARE(header->y(), 0.0);
1918
1919         for (int i = 0; i < 30; i++)
1920             model.addItem("Item" + QString::number(i), "");
1921
1922         QMetaObject::invokeMethod(canvas->rootObject(), "changeHeader");
1923
1924         header = findItem<QDeclarative1Text>(contentItem, "header");
1925         QVERIFY(!header);
1926         header = findItem<QDeclarative1Text>(contentItem, "header2");
1927         QVERIFY(header);
1928
1929         QCOMPARE(header->y(), 10.0);
1930         QCOMPARE(header->height(), 10.0);
1931         QCOMPARE(listview->contentY(), 10.0);
1932
1933         delete canvas;
1934     }
1935     {
1936         QDeclarativeView *canvas = createView();
1937
1938         TestModel model;
1939
1940         canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header1.qml"));
1941         qApp->processEvents();
1942
1943         QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1944         QTRY_VERIFY(listview != 0);
1945
1946         QDeclarativeItem *contentItem = listview->contentItem();
1947         QTRY_VERIFY(contentItem != 0);
1948
1949         QDeclarative1Text *header = findItem<QDeclarative1Text>(contentItem, "header");
1950         QVERIFY(header);
1951         QCOMPARE(header->y(), 0.0);
1952
1953         QCOMPARE(listview->contentY(), 0.0);
1954
1955         model.clear();
1956         QTRY_COMPARE(header->y(), 0.0);
1957
1958         delete canvas;
1959     }
1960     {
1961         // QTBUG-19844
1962         QDeclarativeView *canvas = createView();
1963
1964         TestModel model;
1965
1966         QDeclarativeContext *ctxt = canvas->rootContext();
1967         ctxt->setContextProperty("testModel", &model);
1968
1969         canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/header.qml"));
1970         qApp->processEvents();
1971
1972         QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
1973         QTRY_VERIFY(listview != 0);
1974
1975         QDeclarativeItem *contentItem = listview->contentItem();
1976         QTRY_VERIFY(contentItem != 0);
1977
1978         QDeclarative1Text *header = findItem<QDeclarative1Text>(contentItem, "header");
1979         QVERIFY(header);
1980
1981         header->setHeight(500);
1982
1983         model.addItem("Item 0", "");
1984
1985         header->setHeight(40);
1986         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", 0);
1987         QVERIFY(item);
1988         QTRY_VERIFY(header->y() + header->height() == item->y());
1989
1990         delete canvas;
1991     }
1992 }
1993
1994 void tst_QDeclarative1ListView::footer()
1995 {
1996     QDeclarativeView *canvas = createView();
1997
1998     TestModel model;
1999     for (int i = 0; i < 3; i++)
2000         model.addItem("Item" + QString::number(i), "");
2001
2002     QDeclarativeContext *ctxt = canvas->rootContext();
2003     ctxt->setContextProperty("testModel", &model);
2004
2005     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml"));
2006     qApp->processEvents();
2007
2008     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2009     QTRY_VERIFY(listview != 0);
2010
2011     QDeclarativeItem *contentItem = listview->contentItem();
2012     QTRY_VERIFY(contentItem != 0);
2013
2014     QDeclarative1Text *footer = findItem<QDeclarative1Text>(contentItem, "footer");
2015     QVERIFY(footer);
2016     QCOMPARE(footer->y(), 60.0);
2017     QCOMPARE(footer->height(), 30.0);
2018
2019     model.removeItem(1);
2020     QTRY_COMPARE(footer->y(), 40.0);
2021
2022     model.clear();
2023     QTRY_COMPARE(footer->y(), 0.0);
2024
2025     for (int i = 0; i < 30; i++)
2026         model.addItem("Item" + QString::number(i), "");
2027
2028     QMetaObject::invokeMethod(canvas->rootObject(), "changeFooter");
2029
2030     footer = findItem<QDeclarative1Text>(contentItem, "footer");
2031     QVERIFY(!footer);
2032     footer = findItem<QDeclarative1Text>(contentItem, "footer2");
2033     QVERIFY(footer);
2034
2035     QCOMPARE(footer->y(), 600.0);
2036     QCOMPARE(footer->height(), 20.0);
2037     QCOMPARE(listview->contentY(), 0.0);
2038
2039     delete canvas;
2040 }
2041
2042 class LVAccessor : public QDeclarative1ListView
2043 {
2044 public:
2045     qreal minY() const { return minYExtent(); }
2046     qreal maxY() const { return maxYExtent(); }
2047     qreal minX() const { return minXExtent(); }
2048     qreal maxX() const { return maxXExtent(); }
2049 };
2050
2051 void tst_QDeclarative1ListView::headerFooter()
2052 {
2053     {
2054         // Vertical
2055         QDeclarativeView *canvas = createView();
2056
2057         TestModel model;
2058         QDeclarativeContext *ctxt = canvas->rootContext();
2059         ctxt->setContextProperty("testModel", &model);
2060
2061         canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml"));
2062         qApp->processEvents();
2063
2064         QDeclarative1ListView *listview = qobject_cast<QDeclarative1ListView*>(canvas->rootObject());
2065         QTRY_VERIFY(listview != 0);
2066
2067         QDeclarativeItem *contentItem = listview->contentItem();
2068         QTRY_VERIFY(contentItem != 0);
2069
2070         QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header");
2071         QVERIFY(header);
2072         QCOMPARE(header->y(), 0.0);
2073
2074         QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer");
2075         QVERIFY(footer);
2076         QCOMPARE(footer->y(), 20.0);
2077
2078         QVERIFY(static_cast<LVAccessor*>(listview)->minY() == 0);
2079         QVERIFY(static_cast<LVAccessor*>(listview)->maxY() == 0);
2080
2081         delete canvas;
2082     }
2083     {
2084         // Horizontal
2085         QDeclarativeView *canvas = createView();
2086
2087         TestModel model;
2088         QDeclarativeContext *ctxt = canvas->rootContext();
2089         ctxt->setContextProperty("testModel", &model);
2090
2091         canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml"));
2092         canvas->rootObject()->setProperty("horizontal", true);
2093         qApp->processEvents();
2094
2095         QDeclarative1ListView *listview = qobject_cast<QDeclarative1ListView*>(canvas->rootObject());
2096         QTRY_VERIFY(listview != 0);
2097
2098         QDeclarativeItem *contentItem = listview->contentItem();
2099         QTRY_VERIFY(contentItem != 0);
2100
2101         QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header");
2102         QVERIFY(header);
2103         QCOMPARE(header->x(), 0.0);
2104
2105         QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer");
2106         QVERIFY(footer);
2107         QCOMPARE(footer->x(), 20.0);
2108
2109         QVERIFY(static_cast<LVAccessor*>(listview)->minX() == 0);
2110         QVERIFY(static_cast<LVAccessor*>(listview)->maxX() == 0);
2111
2112         delete canvas;
2113     }
2114     {
2115         // Horizontal RTL
2116         QDeclarativeView *canvas = createView();
2117
2118         TestModel model;
2119         QDeclarativeContext *ctxt = canvas->rootContext();
2120         ctxt->setContextProperty("testModel", &model);
2121
2122         canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/headerfooter.qml"));
2123         canvas->rootObject()->setProperty("horizontal", true);
2124         canvas->rootObject()->setProperty("rtl", true);
2125         qApp->processEvents();
2126
2127         QDeclarative1ListView *listview = qobject_cast<QDeclarative1ListView*>(canvas->rootObject());
2128         QTRY_VERIFY(listview != 0);
2129
2130         QDeclarativeItem *contentItem = listview->contentItem();
2131         QTRY_VERIFY(contentItem != 0);
2132
2133         QDeclarativeItem *header = findItem<QDeclarativeItem>(contentItem, "header");
2134         QVERIFY(header);
2135         QCOMPARE(header->x(), -20.0);
2136
2137         QDeclarativeItem *footer = findItem<QDeclarativeItem>(contentItem, "footer");
2138         QVERIFY(footer);
2139         QCOMPARE(footer->x(), -50.0);
2140
2141         QCOMPARE(static_cast<LVAccessor*>(listview)->minX(), 240.);
2142         QCOMPARE(static_cast<LVAccessor*>(listview)->maxX(), 240.);
2143
2144         delete canvas;
2145     }
2146 }
2147
2148 void tst_QDeclarative1ListView::resizeView()
2149 {
2150     QDeclarativeView *canvas = createView();
2151
2152     TestModel model;
2153     for (int i = 0; i < 40; i++)
2154         model.addItem("Item" + QString::number(i), "");
2155
2156     QDeclarativeContext *ctxt = canvas->rootContext();
2157     ctxt->setContextProperty("testModel", &model);
2158
2159     TestObject *testObject = new TestObject;
2160     ctxt->setContextProperty("testObject", testObject);
2161
2162     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
2163     qApp->processEvents();
2164
2165     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2166     QTRY_VERIFY(listview != 0);
2167
2168     QDeclarativeItem *contentItem = listview->contentItem();
2169     QTRY_VERIFY(contentItem != 0);
2170
2171     // Confirm items positioned correctly
2172     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
2173     for (int i = 0; i < model.count() && i < itemCount; ++i) {
2174         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2175         if (!item) qWarning() << "Item" << i << "not found";
2176         QTRY_VERIFY(item);
2177         QTRY_COMPARE(item->y(), i*20.);
2178     }
2179
2180     QVariant heightRatio;
2181     QMetaObject::invokeMethod(canvas->rootObject(), "heightRatio", Q_RETURN_ARG(QVariant, heightRatio));
2182     QCOMPARE(heightRatio.toReal(), 0.4);
2183
2184     listview->setHeight(200);
2185
2186     QMetaObject::invokeMethod(canvas->rootObject(), "heightRatio", Q_RETURN_ARG(QVariant, heightRatio));
2187     QCOMPARE(heightRatio.toReal(), 0.25);
2188
2189     delete canvas;
2190     delete testObject;
2191 }
2192
2193 void tst_QDeclarative1ListView::sizeLessThan1()
2194 {
2195     QDeclarativeView *canvas = createView();
2196
2197     TestModel model;
2198     for (int i = 0; i < 30; i++)
2199         model.addItem("Item" + QString::number(i), "");
2200
2201     QDeclarativeContext *ctxt = canvas->rootContext();
2202     ctxt->setContextProperty("testModel", &model);
2203
2204     TestObject *testObject = new TestObject;
2205     ctxt->setContextProperty("testObject", testObject);
2206
2207     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/sizelessthan1.qml"));
2208     qApp->processEvents();
2209
2210     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2211     QTRY_VERIFY(listview != 0);
2212
2213     QDeclarativeItem *contentItem = listview->contentItem();
2214     QTRY_VERIFY(contentItem != 0);
2215
2216     // Confirm items positioned correctly
2217     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
2218     for (int i = 0; i < model.count() && i < itemCount; ++i) {
2219         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2220         if (!item) qWarning() << "Item" << i << "not found";
2221         QTRY_VERIFY(item);
2222         QTRY_COMPARE(item->y(), i*0.5);
2223     }
2224
2225     delete canvas;
2226     delete testObject;
2227 }
2228
2229 void tst_QDeclarative1ListView::QTBUG_14821()
2230 {
2231     QDeclarativeView *canvas = createView();
2232
2233     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug14821.qml"));
2234     qApp->processEvents();
2235
2236     QDeclarative1ListView *listview = qobject_cast<QDeclarative1ListView*>(canvas->rootObject());
2237     QVERIFY(listview != 0);
2238
2239     QDeclarativeItem *contentItem = listview->contentItem();
2240     QVERIFY(contentItem != 0);
2241
2242     listview->decrementCurrentIndex();
2243     QCOMPARE(listview->currentIndex(), 99);
2244
2245     listview->incrementCurrentIndex();
2246     QCOMPARE(listview->currentIndex(), 0);
2247
2248     delete canvas;
2249 }
2250
2251 void tst_QDeclarative1ListView::resizeDelegate()
2252 {
2253     QDeclarativeView *canvas = createView();
2254
2255     QStringList strings;
2256     for (int i = 0; i < 30; ++i)
2257         strings << QString::number(i);
2258     QStringListModel model(strings);
2259
2260     QDeclarativeContext *ctxt = canvas->rootContext();
2261     ctxt->setContextProperty("testModel", &model);
2262
2263     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml"));
2264     qApp->processEvents();
2265
2266     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2267     QTRY_VERIFY(listview != 0);
2268
2269     QDeclarativeItem *contentItem = listview->contentItem();
2270     QTRY_VERIFY(contentItem != 0);
2271
2272     QTRY_COMPARE(listview->count(), model.rowCount());
2273
2274     listview->setCurrentIndex(25);
2275     listview->setContentY(0);
2276
2277     for (int i = 0; i < 16; ++i) {
2278         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2279         QVERIFY(item != 0);
2280         QCOMPARE(item->y(), i*20.0);
2281     }
2282
2283     QCOMPARE(listview->currentItem()->y(), 500.0);
2284     QTRY_COMPARE(listview->highlightItem()->y(), 500.0);
2285
2286     canvas->rootObject()->setProperty("delegateHeight", 30);
2287     qApp->processEvents();
2288
2289     for (int i = 0; i < 11; ++i) {
2290         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2291         QVERIFY(item != 0);
2292         QTRY_COMPARE(item->y(), i*30.0);
2293     }
2294
2295     QTRY_COMPARE(listview->currentItem()->y(), 750.0);
2296     QTRY_COMPARE(listview->highlightItem()->y(), 750.0);
2297
2298     listview->setCurrentIndex(1);
2299     listview->positionViewAtIndex(25, QDeclarative1ListView::Beginning);
2300     listview->positionViewAtIndex(5, QDeclarative1ListView::Beginning);
2301
2302     for (int i = 5; i < 16; ++i) {
2303         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2304         QVERIFY(item != 0);
2305         QCOMPARE(item->y(), i*30.0);
2306     }
2307
2308     QTRY_COMPARE(listview->currentItem()->y(), 30.0);
2309     QTRY_COMPARE(listview->highlightItem()->y(), 30.0);
2310
2311     canvas->rootObject()->setProperty("delegateHeight", 20);
2312     qApp->processEvents();
2313
2314     for (int i = 5; i < 11; ++i) {
2315         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2316         QVERIFY(item != 0);
2317         QTRY_COMPARE(item->y(), 150 + (i-5)*20.0);
2318     }
2319
2320     QTRY_COMPARE(listview->currentItem()->y(), 70.0);
2321     QTRY_COMPARE(listview->highlightItem()->y(), 70.0);
2322
2323     delete canvas;
2324 }
2325
2326 void tst_QDeclarative1ListView::QTBUG_16037()
2327 {
2328     QDeclarativeView *canvas = createView();
2329
2330     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug16037.qml"));
2331     qApp->processEvents();
2332
2333     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "listview");
2334     QTRY_VERIFY(listview != 0);
2335
2336     QVERIFY(listview->contentHeight() <= 0.0);
2337
2338     QMetaObject::invokeMethod(canvas->rootObject(), "setModel");
2339
2340     QTRY_COMPARE(listview->contentHeight(), 80.0);
2341
2342     delete canvas;
2343 }
2344
2345 void tst_QDeclarative1ListView::indexAt()
2346 {
2347     QDeclarativeView *canvas = createView();
2348
2349     TestModel model;
2350     for (int i = 0; i < 30; i++)
2351         model.addItem("Item" + QString::number(i), "");
2352
2353     QDeclarativeContext *ctxt = canvas->rootContext();
2354     ctxt->setContextProperty("testModel", &model);
2355
2356     TestObject *testObject = new TestObject;
2357     ctxt->setContextProperty("testObject", testObject);
2358
2359     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
2360     qApp->processEvents();
2361
2362     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2363     QTRY_VERIFY(listview != 0);
2364
2365     QDeclarativeItem *contentItem = listview->contentItem();
2366     QTRY_VERIFY(contentItem != 0);
2367
2368     QCOMPARE(listview->indexAt(0,0), 0);
2369     QCOMPARE(listview->indexAt(0,19), 0);
2370     QCOMPARE(listview->indexAt(239,19), 0);
2371     QCOMPARE(listview->indexAt(0,20), 1);
2372     QCOMPARE(listview->indexAt(240,20), -1);
2373
2374     delete canvas;
2375     delete testObject;
2376 }
2377
2378 void tst_QDeclarative1ListView::incrementalModel()
2379 {
2380     QDeclarativeView *canvas = createView();
2381
2382     IncrementalModel model;
2383     QDeclarativeContext *ctxt = canvas->rootContext();
2384     ctxt->setContextProperty("testModel", &model);
2385
2386     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml"));
2387     qApp->processEvents();
2388
2389     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2390     QTRY_VERIFY(listview != 0);
2391
2392     QDeclarativeItem *contentItem = listview->contentItem();
2393     QTRY_VERIFY(contentItem != 0);
2394
2395     QTRY_COMPARE(listview->count(), 20);
2396
2397     listview->positionViewAtIndex(10, QDeclarative1ListView::Beginning);
2398
2399     QTRY_COMPARE(listview->count(), 25);
2400
2401     delete canvas;
2402 }
2403
2404 void tst_QDeclarative1ListView::onAdd()
2405 {
2406     QFETCH(int, initialItemCount);
2407     QFETCH(int, itemsToAdd);
2408
2409     const int delegateHeight = 10;
2410     TestModel2 model;
2411
2412     // these initial items should not trigger ListView.onAdd
2413     for (int i=0; i<initialItemCount; i++)
2414         model.addItem("dummy value", "dummy value");
2415
2416     QDeclarativeView *canvas = createView();
2417     canvas->setFixedSize(200, delegateHeight * (initialItemCount + itemsToAdd));
2418     QDeclarativeContext *ctxt = canvas->rootContext();
2419     ctxt->setContextProperty("testModel", &model);
2420     ctxt->setContextProperty("delegateHeight", delegateHeight);
2421     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2422
2423     QObject *object = canvas->rootObject();
2424     object->setProperty("width", canvas->width());
2425     object->setProperty("height", canvas->height());
2426     qApp->processEvents();
2427
2428     QList<QPair<QString, QString> > items;
2429     for (int i=0; i<itemsToAdd; i++)
2430         items << qMakePair(QString("value %1").arg(i), QString::number(i));
2431     model.addItems(items);
2432
2433     qApp->processEvents();
2434
2435     QVariantList result = object->property("addedDelegates").toList();
2436     QCOMPARE(result.count(), items.count());
2437     for (int i=0; i<items.count(); i++)
2438         QCOMPARE(result[i].toString(), items[i].first);
2439
2440     delete canvas;
2441 }
2442
2443 void tst_QDeclarative1ListView::onAdd_data()
2444 {
2445     QTest::addColumn<int>("initialItemCount");
2446     QTest::addColumn<int>("itemsToAdd");
2447
2448     QTest::newRow("0, add 1") << 0 << 1;
2449     QTest::newRow("0, add 2") << 0 << 2;
2450     QTest::newRow("0, add 10") << 0 << 10;
2451
2452     QTest::newRow("1, add 1") << 1 << 1;
2453     QTest::newRow("1, add 2") << 1 << 2;
2454     QTest::newRow("1, add 10") << 1 << 10;
2455
2456     QTest::newRow("5, add 1") << 5 << 1;
2457     QTest::newRow("5, add 2") << 5 << 2;
2458     QTest::newRow("5, add 10") << 5 << 10;
2459 }
2460
2461 void tst_QDeclarative1ListView::onRemove()
2462 {
2463     QFETCH(int, initialItemCount);
2464     QFETCH(int, indexToRemove);
2465     QFETCH(int, removeCount);
2466
2467     const int delegateHeight = 10;
2468     TestModel2 model;
2469     for (int i=0; i<initialItemCount; i++)
2470         model.addItem(QString("value %1").arg(i), "dummy value");
2471
2472     QDeclarativeView *canvas = createView();
2473     QDeclarativeContext *ctxt = canvas->rootContext();
2474     ctxt->setContextProperty("testModel", &model);
2475     ctxt->setContextProperty("delegateHeight", delegateHeight);
2476     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
2477     QObject *object = canvas->rootObject();
2478
2479     qApp->processEvents();
2480
2481     model.removeItems(indexToRemove, removeCount);
2482     qApp->processEvents();
2483     QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
2484
2485     delete canvas;
2486 }
2487
2488 void tst_QDeclarative1ListView::onRemove_data()
2489 {
2490     QTest::addColumn<int>("initialItemCount");
2491     QTest::addColumn<int>("indexToRemove");
2492     QTest::addColumn<int>("removeCount");
2493
2494     QTest::newRow("remove first") << 1 << 0 << 1;
2495     QTest::newRow("two items, remove first") << 2 << 0 << 1;
2496     QTest::newRow("two items, remove last") << 2 << 1 << 1;
2497     QTest::newRow("two items, remove all") << 2 << 0 << 2;
2498
2499     QTest::newRow("four items, remove first") << 4 << 0 << 1;
2500     QTest::newRow("four items, remove 0-2") << 4 << 0 << 2;
2501     QTest::newRow("four items, remove 1-3") << 4 << 1 << 2;
2502     QTest::newRow("four items, remove 2-4") << 4 << 2 << 2;
2503     QTest::newRow("four items, remove last") << 4 << 3 << 1;
2504     QTest::newRow("four items, remove all") << 4 << 0 << 4;
2505
2506     QTest::newRow("ten items, remove 1-8") << 10 << 0 << 8;
2507     QTest::newRow("ten items, remove 2-7") << 10 << 2 << 5;
2508     QTest::newRow("ten items, remove 4-10") << 10 << 4 << 6;
2509 }
2510
2511 void tst_QDeclarative1ListView::testQtQuick11Attributes()
2512 {
2513     QFETCH(QString, code);
2514     QFETCH(QString, warning);
2515     QFETCH(QString, error);
2516
2517     QDeclarativeEngine engine;
2518     QObject *obj;
2519
2520     QDeclarativeComponent valid(&engine);
2521     valid.setData("import QtQuick 1.1; ListView { " + code.toUtf8() + " }", QUrl(""));
2522     obj = valid.create();
2523     QVERIFY(obj);
2524     QVERIFY(valid.errorString().isEmpty());
2525     delete obj;
2526
2527     QDeclarativeComponent invalid(&engine);
2528     invalid.setData("import QtQuick 1.0; ListView { " + code.toUtf8() + " }", QUrl(""));
2529     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
2530     obj = invalid.create();
2531     QCOMPARE(invalid.errorString(), error);
2532     delete obj;
2533 }
2534
2535 void tst_QDeclarative1ListView::testQtQuick11Attributes_data()
2536 {
2537     QTest::addColumn<QString>("code");
2538     QTest::addColumn<QString>("warning");
2539     QTest::addColumn<QString>("error");
2540
2541     QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
2542         << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
2543         << "";
2544
2545     QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
2546         << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
2547         << "";
2548 }
2549
2550 void tst_QDeclarative1ListView::rightToLeft()
2551 {
2552     QDeclarativeView *canvas = createView();
2553     canvas->setFixedSize(640,320);
2554     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml"));
2555     qApp->processEvents();
2556
2557     QVERIFY(canvas->rootObject() != 0);
2558     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "view");
2559     QTRY_VERIFY(listview != 0);
2560
2561     QDeclarativeItem *contentItem = listview->contentItem();
2562     QTRY_VERIFY(contentItem != 0);
2563
2564     QDeclarative1VisualItemModel *model = canvas->rootObject()->findChild<QDeclarative1VisualItemModel*>("itemModel");
2565     QTRY_VERIFY(model != 0);
2566
2567     QTRY_VERIFY(model->count() == 3);
2568     QTRY_COMPARE(listview->currentIndex(), 0);
2569
2570     // initial position at first item, right edge aligned
2571     QCOMPARE(listview->contentX(), -640.);
2572
2573     QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "item1");
2574     QTRY_VERIFY(item);
2575     QTRY_COMPARE(item->x(), -100.0);
2576     QCOMPARE(item->height(), listview->height());
2577
2578     QDeclarative1Text *text = findItem<QDeclarative1Text>(contentItem, "text1");
2579     QTRY_VERIFY(text);
2580     QTRY_COMPARE(text->text(), QLatin1String("index: 0"));
2581
2582     listview->setCurrentIndex(2);
2583
2584     item = findItem<QDeclarativeItem>(contentItem, "item3");
2585     QTRY_VERIFY(item);
2586     QTRY_COMPARE(item->x(), -540.0);
2587
2588     text = findItem<QDeclarative1Text>(contentItem, "text3");
2589     QTRY_VERIFY(text);
2590     QTRY_COMPARE(text->text(), QLatin1String("index: 2"));
2591
2592     QCOMPARE(listview->contentX(), -640.);
2593
2594     // Ensure resizing maintains position relative to right edge
2595     qobject_cast<QDeclarativeItem*>(canvas->rootObject())->setWidth(600);
2596     QTRY_COMPARE(listview->contentX(), -600.);
2597
2598     delete canvas;
2599 }
2600
2601 void tst_QDeclarative1ListView::test_mirroring()
2602 {
2603     QDeclarativeView *canvasA = createView();
2604     canvasA->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml"));
2605     QDeclarative1ListView *listviewA = findItem<QDeclarative1ListView>(canvasA->rootObject(), "view");
2606     QTRY_VERIFY(listviewA != 0);
2607
2608     QDeclarativeView *canvasB = createView();
2609     canvasB->setSource(QUrl::fromLocalFile(SRCDIR "/data/rightToLeft.qml"));
2610     QDeclarative1ListView *listviewB = findItem<QDeclarative1ListView>(canvasB->rootObject(), "view");
2611     QTRY_VERIFY(listviewA != 0);
2612     qApp->processEvents();
2613
2614     QList<QString> objectNames;
2615     objectNames << "item1" << "item2"; // << "item3"
2616
2617     listviewA->setProperty("layoutDirection", Qt::LeftToRight);
2618     listviewB->setProperty("layoutDirection", Qt::RightToLeft);
2619     QCOMPARE(listviewA->layoutDirection(), listviewA->effectiveLayoutDirection());
2620
2621     // LTR != RTL
2622     foreach(const QString objectName, objectNames)
2623         QVERIFY(findItem<QDeclarativeItem>(listviewA, objectName)->x() != findItem<QDeclarativeItem>(listviewB, objectName)->x());
2624
2625     listviewA->setProperty("layoutDirection", Qt::LeftToRight);
2626     listviewB->setProperty("layoutDirection", Qt::LeftToRight);
2627
2628     // LTR == LTR
2629     foreach(const QString objectName, objectNames)
2630         QCOMPARE(findItem<QDeclarativeItem>(listviewA, objectName)->x(), findItem<QDeclarativeItem>(listviewB, objectName)->x());
2631
2632     QVERIFY(listviewB->layoutDirection() == listviewB->effectiveLayoutDirection());
2633     QDeclarativeItemPrivate::get(listviewB)->setLayoutMirror(true);
2634     QVERIFY(listviewB->layoutDirection() != listviewB->effectiveLayoutDirection());
2635
2636     // LTR != LTR+mirror
2637     foreach(const QString objectName, objectNames)
2638         QVERIFY(findItem<QDeclarativeItem>(listviewA, objectName)->x() != findItem<QDeclarativeItem>(listviewB, objectName)->x());
2639
2640     listviewA->setProperty("layoutDirection", Qt::RightToLeft);
2641
2642     // RTL == LTR+mirror
2643     foreach(const QString objectName, objectNames)
2644         QCOMPARE(findItem<QDeclarativeItem>(listviewA, objectName)->x(), findItem<QDeclarativeItem>(listviewB, objectName)->x());
2645
2646     listviewB->setProperty("layoutDirection", Qt::RightToLeft);
2647
2648     // RTL != RTL+mirror
2649     foreach(const QString objectName, objectNames)
2650         QVERIFY(findItem<QDeclarativeItem>(listviewA, objectName)->x() != findItem<QDeclarativeItem>(listviewB, objectName)->x());
2651
2652     listviewA->setProperty("layoutDirection", Qt::LeftToRight);
2653
2654     // LTR == RTL+mirror
2655     foreach(const QString objectName, objectNames)
2656         QCOMPARE(findItem<QDeclarativeItem>(listviewA, objectName)->x(), findItem<QDeclarativeItem>(listviewB, objectName)->x());
2657
2658     delete canvasA;
2659     delete canvasB;
2660 }
2661
2662 void tst_QDeclarative1ListView::orientationChange()
2663 {
2664     QDeclarativeView *canvas = createView();
2665
2666     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/orientchange.qml"));
2667     qApp->processEvents();
2668
2669     QDeclarative1ListView *listview = qobject_cast<QDeclarative1ListView*>(canvas->rootObject());
2670     QVERIFY(listview != 0);
2671
2672     QDeclarativeItem *contentItem = listview->contentItem();
2673     QVERIFY(contentItem != 0);
2674
2675     listview->positionViewAtIndex(50, QDeclarative1ListView::Beginning);
2676
2677     // Confirm items positioned correctly
2678     for (int i = 50; i < 54; ++i) {
2679         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2680         QVERIFY(item);
2681         QCOMPARE(item->y(), i*80.0);
2682     }
2683
2684     listview->setOrientation(QDeclarative1ListView::Horizontal);
2685     QCOMPARE(listview->contentY(), 0.);
2686
2687     // Confirm items positioned correctly
2688     for (int i = 0; i < 3; ++i) {
2689         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2690         QVERIFY(item);
2691         QCOMPARE(item->x(), i*80.0);
2692     }
2693
2694     listview->positionViewAtIndex(50, QDeclarative1ListView::Beginning);
2695     listview->setOrientation(QDeclarative1ListView::Vertical);
2696     QCOMPARE(listview->contentX(), 0.);
2697     //
2698     // Confirm items positioned correctly
2699     for (int i = 0; i < 4; ++i) {
2700         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2701         QVERIFY(item);
2702         QCOMPARE(item->y(), i*80.0);
2703     }
2704
2705     delete canvas;
2706 }
2707
2708 void tst_QDeclarative1ListView::contentPosJump()
2709 {
2710     QDeclarativeView *canvas = createView();
2711
2712     TestModel model;
2713     for (int i = 0; i < 50; i++)
2714         model.addItem("Item" + QString::number(i), "");
2715
2716     QDeclarativeContext *ctxt = canvas->rootContext();
2717     ctxt->setContextProperty("testModel", &model);
2718
2719     TestObject *testObject = new TestObject;
2720     ctxt->setContextProperty("testObject", testObject);
2721
2722     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml"));
2723     qApp->processEvents();
2724
2725     QDeclarative1ListView *listview = findItem<QDeclarative1ListView>(canvas->rootObject(), "list");
2726     QTRY_VERIFY(listview != 0);
2727
2728     QDeclarativeItem *contentItem = listview->contentItem();
2729     QTRY_VERIFY(contentItem != 0);
2730
2731     // Confirm items positioned correctly
2732     int itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
2733     for (int i = 0; i < model.count() && i < itemCount; ++i) {
2734         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2735         if (!item) qWarning() << "Item" << i << "not found";
2736         QTRY_VERIFY(item);
2737         QTRY_VERIFY(item->y() == i*20);
2738     }
2739
2740     // Test jumping more than a page of items.
2741     listview->setContentY(500);
2742     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
2743     for (int i = 25; i < model.count() && i < itemCount; ++i) {
2744         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2745         if (!item) qWarning() << "Item" << i << "not found";
2746         QTRY_VERIFY(item);
2747         QTRY_VERIFY(item->y() == i*20);
2748     }
2749
2750     listview->setContentY(-100);
2751     itemCount = findItems<QDeclarativeItem>(contentItem, "wrapper").count();
2752     QVERIFY(itemCount < 20);
2753     for (int i = 0; i < model.count() && i < itemCount; ++i) {
2754         QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", i);
2755         if (!item) qWarning() << "Item" << i << "not found";
2756         QTRY_VERIFY(item);
2757         QTRY_VERIFY(item->y() == i*20);
2758     }
2759
2760     delete canvas;
2761 }
2762
2763 void tst_QDeclarative1ListView::qListModelInterface_items()
2764 {
2765     items<TestModel>();
2766 }
2767
2768 void tst_QDeclarative1ListView::qAbstractItemModel_items()
2769 {
2770     items<TestModel2>();
2771 }
2772
2773 void tst_QDeclarative1ListView::qListModelInterface_changed()
2774 {
2775     changed<TestModel>();
2776 }
2777
2778 void tst_QDeclarative1ListView::qAbstractItemModel_changed()
2779 {
2780     changed<TestModel2>();
2781 }
2782
2783 void tst_QDeclarative1ListView::qListModelInterface_inserted()
2784 {
2785     inserted<TestModel>();
2786 }
2787
2788 void tst_QDeclarative1ListView::qAbstractItemModel_inserted()
2789 {
2790     inserted<TestModel2>();
2791 }
2792
2793 void tst_QDeclarative1ListView::qListModelInterface_removed()
2794 {
2795     removed<TestModel>(false);
2796     removed<TestModel>(true);
2797 }
2798
2799 void tst_QDeclarative1ListView::qAbstractItemModel_removed()
2800 {
2801     removed<TestModel2>(false);
2802     removed<TestModel2>(true);
2803 }
2804
2805 void tst_QDeclarative1ListView::qListModelInterface_moved()
2806 {
2807     moved<TestModel>();
2808 }
2809
2810 void tst_QDeclarative1ListView::qAbstractItemModel_moved()
2811 {
2812     moved<TestModel2>();
2813 }
2814
2815 void tst_QDeclarative1ListView::qListModelInterface_clear()
2816 {
2817     clear<TestModel>();
2818 }
2819
2820 void tst_QDeclarative1ListView::qAbstractItemModel_clear()
2821 {
2822     clear<TestModel2>();
2823 }
2824
2825 QDeclarativeView *tst_QDeclarative1ListView::createView()
2826 {
2827     QDeclarativeView *canvas = new QDeclarativeView(0);
2828     canvas->setFixedSize(240,320);
2829
2830     return canvas;
2831 }
2832
2833 /*
2834    Find an item with the specified objectName.  If index is supplied then the
2835    item must also evaluate the {index} expression equal to index
2836 */
2837 template<typename T>
2838 T *tst_QDeclarative1ListView::findItem(QGraphicsObject *parent, const QString &objectName, int index)
2839 {
2840     const QMetaObject &mo = T::staticMetaObject;
2841     //qDebug() << parent->childItems().count() << "children";
2842     for (int i = 0; i < parent->childItems().count(); ++i) {
2843         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
2844         if(!item)
2845             continue;
2846         //qDebug() << "try" << item;
2847         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
2848             if (index != -1) {
2849                 QDeclarativeExpression e(qmlContext(item), item, "index");
2850                 if (e.evaluate().toInt() == index)
2851                     return static_cast<T*>(item);
2852             } else {
2853                 return static_cast<T*>(item);
2854             }
2855         }
2856         item = findItem<T>(item, objectName, index);
2857         if (item)
2858             return static_cast<T*>(item);
2859     }
2860
2861     return 0;
2862 }
2863
2864 template<typename T>
2865 QList<T*> tst_QDeclarative1ListView::findItems(QGraphicsObject *parent, const QString &objectName)
2866 {
2867     QList<T*> items;
2868     const QMetaObject &mo = T::staticMetaObject;
2869     //qDebug() << parent->childItems().count() << "children";
2870     for (int i = 0; i < parent->childItems().count(); ++i) {
2871         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
2872         if(!item || !item->isVisible())
2873             continue;
2874         //qDebug() << "try" << item;
2875         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
2876             items.append(static_cast<T*>(item));
2877         items += findItems<T>(item, objectName);
2878     }
2879
2880     return items;
2881 }
2882
2883 void tst_QDeclarative1ListView::dumpTree(QDeclarativeItem *parent, int depth)
2884 {
2885     static QString padding("                       ");
2886     for (int i = 0; i < parent->childItems().count(); ++i) {
2887         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
2888         if(!item)
2889             continue;
2890         qDebug() << padding.left(depth*2) << item;
2891         dumpTree(item, depth+1);
2892     }
2893 }
2894
2895
2896 QTEST_MAIN(tst_QDeclarative1ListView)
2897
2898 #include "tst_qdeclarativelistview.moc"