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