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