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