Remove usage of deprecated qWaitForWindowShown(QWidget *) method.
[profile/ivi/qtbase.git] / tests / auto / widgets / itemviews / qlistview / tst_qlistview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include <qabstractitemmodel.h>
46 #include <qapplication.h>
47 #include <qlistview.h>
48 #include <qlistwidget.h>
49 #include <qitemdelegate.h>
50 #include <qstandarditemmodel.h>
51 #include <qstringlistmodel.h>
52 #include <cmath>
53 #include <math.h>
54 #include <QtWidgets/QScrollBar>
55 #include <QtWidgets/QDialog>
56 #include <QtWidgets/QStyledItemDelegate>
57 #if defined(Q_OS_WIN) || defined(Q_OS_WINCE)
58 #  include <windows.h>
59 #  include <QtGui/QGuiApplication>
60 #include <qpa/qplatformnativeinterface.h>
61 #endif // Q_OS_WIN
62
63 #if defined(Q_OS_WIN) || defined(Q_OS_WINCE)
64 static inline HWND getHWNDForWidget(const QWidget *widget)
65 {
66     QWindow *window = widget->windowHandle();
67     return static_cast<HWND> (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
68 }
69 #endif // Q_OS_WIN
70
71 class tst_QListView : public QObject
72 {
73     Q_OBJECT
74
75 public:
76     tst_QListView();
77     virtual ~tst_QListView();
78
79
80 public slots:
81     void initTestCase();
82     void cleanupTestCase();
83     void init();
84     void cleanup();
85 private slots:
86     void getSetCheck();
87     void noDelegate();
88     void noModel();
89     void emptyModel();
90     void removeRows();
91     void cursorMove();
92     void hideRows();
93     void moveCursor();
94     void moveCursor2();
95     void moveCursor3();
96     void indexAt();
97     void clicked();
98     void singleSelectionRemoveRow();
99     void singleSelectionRemoveColumn();
100     void modelColumn();
101     void hideFirstRow();
102     void batchedMode();
103     void setCurrentIndex();
104     void selection_data();
105     void selection();
106     void scrollTo();
107     void scrollBarRanges();
108     void scrollBarAsNeeded_data();
109     void scrollBarAsNeeded();
110     void moveItems();
111     void wordWrap();
112     void setCurrentIndexAfterAppendRowCrash();
113     void emptyItemSize();
114     void task203585_selectAll();
115     void task228566_infiniteRelayout();
116     void task248430_crashWith0SizedItem();
117     void task250446_scrollChanged();
118     void task196118_visualRegionForSelection();
119     void task254449_draggingItemToNegativeCoordinates();
120     void keyboardSearch();
121     void shiftSelectionWithNonUniformItemSizes();
122     void clickOnViewportClearsSelection();
123     void task262152_setModelColumnNavigate();
124     void taskQTBUG_2233_scrollHiddenItems_data();
125     void taskQTBUG_2233_scrollHiddenItems();
126     void taskQTBUG_633_changeModelData();
127     void taskQTBUG_435_deselectOnViewportClick();
128     void taskQTBUG_2678_spacingAndWrappedText();
129     void taskQTBUG_5877_skippingItemInPageDownUp();
130     void taskQTBUG_9455_wrongScrollbarRanges();
131     void styleOptionViewItem();
132     void taskQTBUG_12308_artihmeticException();
133     void taskQTBUG_12308_wrongFlowLayout();
134     void taskQTBUG_21115_scrollToAndHiddenItems_data();
135     void taskQTBUG_21115_scrollToAndHiddenItems();
136 };
137
138 // Testing get/set functions
139 void tst_QListView::getSetCheck()
140 {
141     QListView obj1;
142     // Movement QListView::movement()
143     // void QListView::setMovement(Movement)
144     obj1.setMovement(QListView::Movement(QListView::Static));
145     QCOMPARE(QListView::Movement(QListView::Static), obj1.movement());
146     obj1.setMovement(QListView::Movement(QListView::Free));
147     QCOMPARE(QListView::Movement(QListView::Free), obj1.movement());
148     obj1.setMovement(QListView::Movement(QListView::Snap));
149     QCOMPARE(QListView::Movement(QListView::Snap), obj1.movement());
150
151     // Flow QListView::flow()
152     // void QListView::setFlow(Flow)
153     obj1.setFlow(QListView::Flow(QListView::LeftToRight));
154     QCOMPARE(QListView::Flow(QListView::LeftToRight), obj1.flow());
155     obj1.setFlow(QListView::Flow(QListView::TopToBottom));
156     QCOMPARE(QListView::Flow(QListView::TopToBottom), obj1.flow());
157
158     // ResizeMode QListView::resizeMode()
159     // void QListView::setResizeMode(ResizeMode)
160     obj1.setResizeMode(QListView::ResizeMode(QListView::Fixed));
161     QCOMPARE(QListView::ResizeMode(QListView::Fixed), obj1.resizeMode());
162     obj1.setResizeMode(QListView::ResizeMode(QListView::Adjust));
163     QCOMPARE(QListView::ResizeMode(QListView::Adjust), obj1.resizeMode());
164
165     // LayoutMode QListView::layoutMode()
166     // void QListView::setLayoutMode(LayoutMode)
167     obj1.setLayoutMode(QListView::LayoutMode(QListView::SinglePass));
168     QCOMPARE(QListView::LayoutMode(QListView::SinglePass), obj1.layoutMode());
169     obj1.setLayoutMode(QListView::LayoutMode(QListView::Batched));
170     QCOMPARE(QListView::LayoutMode(QListView::Batched), obj1.layoutMode());
171
172     // int QListView::spacing()
173     // void QListView::setSpacing(int)
174     obj1.setSpacing(0);
175     QCOMPARE(0, obj1.spacing());
176     obj1.setSpacing(INT_MIN);
177     QCOMPARE(INT_MIN, obj1.spacing());
178     obj1.setSpacing(INT_MAX);
179     QCOMPARE(INT_MAX, obj1.spacing());
180
181     // ViewMode QListView::viewMode()
182     // void QListView::setViewMode(ViewMode)
183     obj1.setViewMode(QListView::ViewMode(QListView::ListMode));
184     QCOMPARE(QListView::ViewMode(QListView::ListMode), obj1.viewMode());
185     obj1.setViewMode(QListView::ViewMode(QListView::IconMode));
186     QCOMPARE(QListView::ViewMode(QListView::IconMode), obj1.viewMode());
187
188     // int QListView::modelColumn()
189     // void QListView::setModelColumn(int)
190     obj1.setModelColumn(0);
191     QCOMPARE(0, obj1.modelColumn());
192     obj1.setModelColumn(INT_MIN);
193     QCOMPARE(0, obj1.modelColumn()); // Less than 0 => 0
194     obj1.setModelColumn(INT_MAX);
195     QCOMPARE(0, obj1.modelColumn()); // No model => 0
196
197     // bool QListView::uniformItemSizes()
198     // void QListView::setUniformItemSizes(bool)
199     obj1.setUniformItemSizes(false);
200     QCOMPARE(false, obj1.uniformItemSizes());
201     obj1.setUniformItemSizes(true);
202     QCOMPARE(true, obj1.uniformItemSizes());
203
204     // make sure setViewMode() doesn't reset resizeMode
205     obj1.clearPropertyFlags();
206     obj1.setResizeMode(QListView::Adjust);
207     obj1.setViewMode(QListView::IconMode);
208     QCOMPARE(obj1.resizeMode(), QListView::Adjust);
209
210     obj1.setWordWrap(false);
211     QCOMPARE(false, obj1.wordWrap());
212     obj1.setWordWrap(true);
213     QCOMPARE(true, obj1. wordWrap());
214 }
215
216 class QtTestModel: public QAbstractListModel
217 {
218 public:
219     QtTestModel(QObject *parent = 0): QAbstractListModel(parent),
220        colCount(0), rCount(0), wrongIndex(false) {}
221     int rowCount(const QModelIndex&) const { return rCount; }
222     int columnCount(const QModelIndex&) const { return colCount; }
223     bool isEditable(const QModelIndex &) const { return true; }
224
225     QVariant data(const QModelIndex &idx, int role) const
226     {
227
228         if (!m_icon.isNull() && role == Qt::DecorationRole) {
229             return m_icon;
230         }
231         if (role != Qt::DisplayRole)
232             return QVariant();
233
234         if (idx.row() < 0 || idx.column() < 0 || idx.column() >= colCount
235             || idx.row() >= rCount) {
236             wrongIndex = true;
237             qWarning("got invalid modelIndex %d/%d", idx.row(), idx.column());
238         }
239         return QString("%1/%2").arg(idx.row()).arg(idx.column());
240     }
241
242     void removeLastRow()
243     {
244         beginRemoveRows(QModelIndex(), rCount - 2, rCount - 1);
245         --rCount;
246         endRemoveRows();
247     }
248
249     void removeAllRows()
250     {
251         beginRemoveRows(QModelIndex(), 0, rCount - 1);
252         rCount = 0;
253         endRemoveRows();
254     }
255
256     void setDataIcon(const QIcon &icon)
257     {
258         m_icon = icon;
259     }
260
261     int colCount, rCount;
262     QIcon m_icon;
263     mutable bool wrongIndex;
264 };
265
266 tst_QListView::tst_QListView()
267 {
268 }
269
270 tst_QListView::~tst_QListView()
271 {
272 }
273
274 void tst_QListView::initTestCase()
275 {
276 }
277
278 void tst_QListView::cleanupTestCase()
279 {
280 }
281
282 void tst_QListView::init()
283 {
284 #ifdef Q_OS_WINCE //disable magic for WindowsCE
285     qApp->setAutoMaximizeThreshold(-1);
286 #endif
287 }
288
289 void tst_QListView::cleanup()
290 {
291 }
292
293
294 void tst_QListView::noDelegate()
295 {
296     QtTestModel model(0);
297     model.rCount = model.colCount = 10;
298     QListView view;
299     view.setModel(&model);
300     view.setItemDelegate(0);
301     view.show();
302 }
303
304 void tst_QListView::noModel()
305 {
306     QListView view;
307     view.show();
308     view.setRowHidden(0, true);
309 }
310
311 void tst_QListView::emptyModel()
312 {
313     QtTestModel model(0);
314     QListView view;
315     view.setModel(&model);
316     view.show();
317     QVERIFY(!model.wrongIndex);
318 }
319
320 void tst_QListView::removeRows()
321 {
322     QtTestModel model(0);
323     model.rCount = model.colCount = 10;
324
325     QListView view;
326     view.setModel(&model);
327     view.show();
328
329     model.removeLastRow();
330     QVERIFY(!model.wrongIndex);
331
332     model.removeAllRows();
333     QVERIFY(!model.wrongIndex);
334 }
335
336 void tst_QListView::cursorMove()
337 {
338     int rows = 6*6;
339     int columns = 6;
340
341     QStandardItemModel model(rows, columns);
342     QWidget topLevel;
343     QListView view(&topLevel);
344     view.setModel(&model);
345
346     for (int j = 0; j < columns; ++j) {
347         view.setModelColumn(j);
348         for (int i = 0; i < rows; ++i) {
349             QModelIndex index = model.index(i, j);
350             model.setData(index, QString("[%1,%2]").arg(i).arg(j));
351             view.setCurrentIndex(index);
352             QApplication::processEvents();
353             QCOMPARE(view.currentIndex(), index);
354         }
355     }
356
357     QSize cellsize(60, 25);
358     int gap = 1; // compensate for the scrollbars
359     int displayColumns = 6;
360
361     view.resize((displayColumns + gap) * cellsize.width(),
362                  int((ceil(double(rows) / displayColumns) + gap) * cellsize.height()));
363     view.setResizeMode(QListView::Adjust);
364     view.setGridSize(cellsize);
365     view.setViewMode(QListView::IconMode);
366     view.doItemsLayout();
367     topLevel.show();
368
369     QVector<Qt::Key> keymoves;
370     keymoves << Qt::Key_Up << Qt::Key_Up << Qt::Key_Right << Qt::Key_Right << Qt::Key_Up
371              << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up
372              << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up
373              << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down;
374
375     int displayRow    = rows / displayColumns - 1;
376     int displayColumn = displayColumns - (rows % displayColumns) - 1;
377
378     QApplication::instance()->processEvents();
379     for (int i = 0; i < keymoves.size(); ++i) {
380         Qt::Key key = keymoves.at(i);
381         QTest::keyClick(&view, key);
382         switch (key) {
383         case Qt::Key_Up:
384             displayRow = qMax(0, displayRow - 1);
385             break;
386         case Qt::Key_Down:
387             displayRow = qMin(rows / displayColumns - 1, displayRow + 1);
388             break;
389         case Qt::Key_Left:
390             displayColumn = qMax(0, displayColumn - 1);
391             break;
392         case Qt::Key_Right:
393             displayColumn = qMin(displayColumns-1, displayColumn + 1);
394             break;
395         default:
396             QVERIFY(false);
397         }
398
399         QApplication::instance()->processEvents();
400
401         int row = displayRow * displayColumns + displayColumn;
402         int column = columns - 1;
403         QModelIndex index = model.index(row, column);
404         QCOMPARE(view.currentIndex().row(), row);
405         QCOMPARE(view.currentIndex().column(), column);
406         QCOMPARE(view.currentIndex(), index);
407     }
408 }
409
410 void tst_QListView::hideRows()
411 {
412     QtTestModel model(0);
413     model.rCount = model.colCount = 10;
414
415     QListView view;
416     view.setModel(&model);
417     view.show();
418
419     // hide then show
420     QVERIFY(!view.isRowHidden(2));
421     view.setRowHidden(2, true);
422     QVERIFY(view.isRowHidden(2));
423     view.setRowHidden(2, false);
424     QVERIFY(!view.isRowHidden(2));
425
426     // re show same row
427     QVERIFY(!view.isRowHidden(2));
428     view.setRowHidden(2, false);
429     QVERIFY(!view.isRowHidden(2));
430
431     // double hidding
432     QVERIFY(!view.isRowHidden(2));
433     view.setRowHidden(2, true);
434     QVERIFY(view.isRowHidden(2));
435     view.setRowHidden(2, true);
436     QVERIFY(view.isRowHidden(2));
437     view.setRowHidden(2, false);
438     QVERIFY(!view.isRowHidden(2));
439
440     // show in per-item mode, then hide the first row
441     view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
442     QVERIFY(!view.isRowHidden(0));
443     view.setRowHidden(0, true);
444     QVERIFY(view.isRowHidden(0));
445     view.setRowHidden(0, false);
446     QVERIFY(!view.isRowHidden(0));
447
448     QStandardItemModel sim(0);
449     QStandardItem *root = new QStandardItem("Root row");
450     for (int i=0;i<5;i++)
451         root->appendRow(new QStandardItem(QString("Row %1").arg(i)));
452     sim.appendRow(root);
453     view.setModel(&sim);
454     view.setRootIndex(root->index());
455     QVERIFY(!view.isRowHidden(0));
456     view.setRowHidden(0, true);
457     QVERIFY(view.isRowHidden(0));
458     view.setRowHidden(0, false);
459     QVERIFY(!view.isRowHidden(0));
460 }
461
462
463 void tst_QListView::moveCursor()
464 {
465     QtTestModel model(0);
466     model.rCount = model.colCount = 10;
467
468     QListView view;
469     view.setModel(&model);
470
471     QTest::keyClick(&view, Qt::Key_Down);
472
473     view.setModel(0);
474     view.setModel(&model);
475     view.setRowHidden(0, true);
476
477     QTest::keyClick(&view, Qt::Key_Down);
478     QCOMPARE(view.selectionModel()->currentIndex(), model.index(1, 0));
479 }
480
481 class QMoveCursorListView : public QListView
482 {
483 public:
484     QMoveCursorListView() : QListView() {}
485
486     enum CursorAction { MoveUp, MoveDown, MoveLeft, MoveRight,
487         MoveHome, MoveEnd, MovePageUp, MovePageDown,
488         MoveNext, MovePrevious };
489
490     QModelIndex moveCursor(QMoveCursorListView::CursorAction action, Qt::KeyboardModifiers modifiers)
491     {
492         return QListView::moveCursor((QListView::CursorAction)action, modifiers);
493     }
494 };
495
496 void tst_QListView::moveCursor2()
497 {
498     QtTestModel model(0);
499     model.colCount = 1;
500     model.rCount = 100;
501     QPixmap pm(32, 32);
502     pm.fill(Qt::green);
503     model.setDataIcon(QIcon(pm));
504
505     QMoveCursorListView vu;
506     vu.setModel(&model);
507     vu.setIconSize(QSize(36,48));
508     vu.setGridSize(QSize(34,56));
509     //Standard framesize is 1. If Framesize > 2 increase size
510     int frameSize = qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
511     vu.resize(300 + frameSize * 2,300);
512     vu.setFlow(QListView::LeftToRight);
513     vu.setMovement(QListView::Static);
514     vu.setWrapping(true);
515     vu.setViewMode(QListView::IconMode);
516     vu.setLayoutMode(QListView::Batched);
517     vu.show();
518     vu.selectionModel()->setCurrentIndex(model.index(0,0), QItemSelectionModel::SelectCurrent);
519     QCoreApplication::processEvents();
520
521     QModelIndex idx = vu.moveCursor(QMoveCursorListView::MoveHome, Qt::NoModifier);
522     QCOMPARE(idx, model.index(0,0));
523     idx = vu.moveCursor(QMoveCursorListView::MoveDown, Qt::NoModifier);
524     QCOMPARE(idx, model.index(8,0));
525 }
526
527 void tst_QListView::moveCursor3()
528 {
529     //this tests is for task 159792
530     //it tests that navigation works even with non uniform item sizes
531     QListView view;
532     QStandardItemModel model(0, 1);
533     QStandardItem *i1 = new QStandardItem("First item, long name");
534     QStandardItem *i2 = new QStandardItem("2nd item");
535     QStandardItem *i3 = new QStandardItem("Third item, long name");
536     i1->setSizeHint(QSize(200,32));
537     model.appendRow(i1);
538     model.appendRow(i2);
539     model.appendRow(i3);
540     view.setModel(&model);
541
542     view.setCurrentIndex(model.index(0, 0));
543
544     QCOMPARE(view.selectionModel()->currentIndex(), model.index(0, 0));
545     QTest::keyClick(&view, Qt::Key_Down);
546     QCOMPARE(view.selectionModel()->currentIndex(), model.index(1, 0));
547     QTest::keyClick(&view, Qt::Key_Down);
548     QCOMPARE(view.selectionModel()->currentIndex(), model.index(2, 0));
549     QTest::keyClick(&view, Qt::Key_Up);
550     QCOMPARE(view.selectionModel()->currentIndex(), model.index(1, 0));
551     QTest::keyClick(&view, Qt::Key_Up);
552     QCOMPARE(view.selectionModel()->currentIndex(), model.index(0, 0));
553 }
554
555
556 class QListViewShowEventListener : public QListView
557 {
558 public:
559     QListViewShowEventListener() : QListView() { m_shown = false;}
560
561     virtual void showEvent(QShowEvent * /*e*/)
562     {
563         int columnwidth = sizeHintForColumn(0);
564         QSize sz = sizeHintForIndex(model()->index(0,0));
565
566         // This should retrieve a model index in the 2nd section
567         m_index = indexAt(QPoint(columnwidth +2, sz.height()/2));
568         m_shown = true;
569     }
570
571     QModelIndex m_index;
572     bool m_shown;
573
574 };
575
576 void tst_QListView::indexAt()
577 {
578     QtTestModel model(0);
579     model.rCount = 2;
580     model.colCount = 1;
581
582     QListView view;
583     view.setModel(&model);
584     view.setViewMode(QListView::ListMode);
585     view.setFlow(QListView::TopToBottom);
586
587     QSize sz = view.sizeHintForIndex(model.index(0,0));
588     QModelIndex index;
589     index = view.indexAt(QPoint(20,0));
590     QVERIFY(index.isValid());
591     QCOMPARE(index.row(), 0);
592
593     index = view.indexAt(QPoint(20,sz.height()));
594     QVERIFY(index.isValid());
595     QCOMPARE(index.row(), 1);
596
597     index = view.indexAt(QPoint(20,2 * sz.height()));
598     QVERIFY(!index.isValid());
599
600     // Check when peeking out of the viewport bounds
601     index = view.indexAt(QPoint(view.viewport()->rect().width(), 0));
602     QVERIFY(!index.isValid());
603     index = view.indexAt(QPoint(-1, 0));
604     QVERIFY(!index.isValid());
605     index = view.indexAt(QPoint(20, view.viewport()->rect().height()));
606     QVERIFY(!index.isValid());
607     index = view.indexAt(QPoint(20, -1));
608     QVERIFY(!index.isValid());
609
610     model.rCount = 30;
611     QListViewShowEventListener view2;
612     // Set the height to a small enough value so that it wraps to a new section.
613     view2.resize(300,100);
614     view2.setModel(&model);
615     view2.setFlow(QListView::TopToBottom);
616     view2.setViewMode(QListView::ListMode);
617     view2.setWrapping(true);
618     // We really want to make sure it is shown, because the layout won't be known until it is shown
619     view2.show();
620     QVERIFY(QTest::qWaitForWindowExposed(&view2));
621     QTRY_VERIFY(view2.m_shown);
622
623     QVERIFY(view2.m_index.isValid());
624     QVERIFY(view2.m_index.row() != 0);
625 }
626
627 void tst_QListView::clicked()
628 {
629     QtTestModel model;
630     model.rCount = 10;
631     model.colCount = 2;
632
633     qRegisterMetaType<QModelIndex>("QModelIndex");
634
635     QListView view;
636     view.setModel(&model);
637
638     view.show();
639     QApplication::processEvents();
640
641     QModelIndex firstIndex = model.index(0, 0, QModelIndex());
642     QVERIFY(firstIndex.isValid());
643     int itemHeight = view.visualRect(firstIndex).height();
644     view.resize(200, itemHeight * (model.rCount + 1));
645
646     for (int i = 0; i < model.rCount; ++i) {
647         QPoint p(5, 1 + itemHeight * i);
648         QModelIndex index = view.indexAt(p);
649         if (!index.isValid())
650             continue;
651         QSignalSpy spy(&view, SIGNAL(clicked(const QModelIndex&)));
652         QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
653         QCOMPARE(spy.count(), 1);
654     }
655 }
656
657 void tst_QListView::singleSelectionRemoveRow()
658 {
659     QStringList items;
660     items << "item1" << "item2" << "item3" << "item4";
661     QStringListModel model(items);
662
663     QListView view;
664     view.setModel(&model);
665     view.show();
666
667     QModelIndex index;
668     view.setCurrentIndex(model.index(1));
669     index = view.currentIndex();
670     QCOMPARE(view.model()->data(index).toString(), QString("item2"));
671
672     model.removeRow(1);
673     index = view.currentIndex();
674     QCOMPARE(view.model()->data(index).toString(), QString("item3"));
675
676     model.removeRow(0);
677     index = view.currentIndex();
678     QCOMPARE(view.model()->data(index).toString(), QString("item3"));
679 }
680
681 void tst_QListView::singleSelectionRemoveColumn()
682 {
683     int numCols = 3;
684     int numRows = 3;
685     QStandardItemModel model(numCols, numRows);
686     for (int r = 0; r < numRows; ++r)
687         for (int c = 0; c < numCols; ++c)
688             model.setData(model.index(r, c), QString("%1,%2").arg(r).arg(c));
689
690     QListView view;
691     view.setModel(&model);
692     view.show();
693
694     QModelIndex index;
695     view.setCurrentIndex(model.index(1, 1));
696     index = view.currentIndex();
697     QCOMPARE(view.model()->data(index).toString(), QString("1,1"));
698
699     model.removeColumn(1);
700     index = view.currentIndex();
701     QCOMPARE(view.model()->data(index).toString(), QString("1,0"));
702
703     model.removeColumn(0);
704     index = view.currentIndex();
705     QCOMPARE(view.model()->data(index).toString(), QString("1,2"));
706 }
707
708 void tst_QListView::modelColumn()
709 {
710     int numCols = 3;
711     int numRows = 3;
712     QStandardItemModel model(numCols, numRows);
713     for (int r = 0; r < numRows; ++r)
714         for (int c = 0; c < numCols; ++c)
715             model.setData(model.index(r, c), QString("%1,%2").arg(r).arg(c));
716
717
718     QListView view;
719     view.setModel(&model);
720
721
722     //
723     // Set and get with a valid model
724     //
725
726     // Default is column 0
727     QCOMPARE(view.modelColumn(), 0);
728
729     view.setModelColumn(0);
730     QCOMPARE(view.modelColumn(), 0);
731     view.setModelColumn(1);
732     QCOMPARE(view.modelColumn(), 1);
733     view.setModelColumn(2);
734     QCOMPARE(view.modelColumn(), 2);
735
736     // Out of bound cases should not modify the modelColumn
737     view.setModelColumn(-1);
738     QCOMPARE(view.modelColumn(), 2);
739     view.setModelColumn(INT_MAX);
740     QCOMPARE(view.modelColumn(), 2);
741
742
743     // See if it displays the right column using indexAt()...
744     view.resize(400,400);
745     view.show();
746
747     for (int c = 0; c < 3; ++c) {
748         view.setModelColumn(c);
749         int startrow = 0;
750         for (int y = 0; y < view.height(); ++y) {
751             QModelIndex idx = view.indexAt( QPoint(1, y) );
752             if (idx.row() == startrow + 1) ++startrow;
753             else if (idx.row() == -1) break;
754             QCOMPARE(idx.row(), startrow);
755             QCOMPARE(idx.column(), c);
756         }
757         QCOMPARE(startrow, 2);
758     }
759 }
760
761 void tst_QListView::hideFirstRow()
762 {
763     QStringList items;
764     for (int i=0; i <100; ++i)
765         items << "item";
766     QStringListModel model(items);
767
768     QListView view;
769     view.setModel(&model);
770     view.setUniformItemSizes(true);
771     view.setRowHidden(0,true);
772     view.show();
773     QVERIFY(QTest::qWaitForWindowExposed(&view));
774     QTest::qWait(10);
775 }
776
777 void tst_QListView::batchedMode()
778 {
779     QStringList items;
780     for (int i=0; i <3; ++i)
781         items << "item";
782     QStringListModel model(items);
783
784     QListView view;
785     view.setModel(&model);
786     view.setUniformItemSizes(true);
787     view.setViewMode(QListView::ListMode);
788     view.setLayoutMode(QListView::Batched);
789     view.setBatchSize(2);
790     view.resize(200,400);
791     view.show();
792     QVERIFY(QTest::qWaitForWindowExposed(&view));
793     QTest::qWait(100);
794
795 #if defined(Q_OS_WINCE)
796     QTest::qWait(2000);
797 #endif
798     QBitArray ba;
799     for (int y = 0; y < view.height(); ++y) {
800         QModelIndex idx = view.indexAt( QPoint(1, y) );
801         if (!idx.isValid())
802             break;
803         if (idx.row() >= ba.size())
804             ba.resize(idx.row() + 1);
805         ba.setBit(idx.row(), true);
806     }
807     QCOMPARE(ba.size(), 3);
808
809
810     // Test the dynamic listview too.
811     view.setViewMode(QListView::IconMode);
812     view.setLayoutMode(QListView::Batched);
813     view.setFlow(QListView::TopToBottom);
814     view.setBatchSize(2);
815
816 #if !defined(Q_OS_WINCE)
817     QTest::qWait(100);
818 #else
819     QTest::qWait(2000);
820 #endif
821
822     ba.clear();
823     for (int y = 0; y < view.height(); ++y) {
824         QModelIndex idx = view.indexAt( QPoint(1, y) );
825         if (!idx.isValid())
826             break;
827         if (idx.row() >= ba.size())
828             ba.resize(idx.row() + 1);
829         ba.setBit(idx.row(), true);
830     }
831     QCOMPARE(ba.size(), 3);
832 }
833
834 void tst_QListView::setCurrentIndex()
835 {
836     QStringList items;
837     int i;
838     for (i=0; i <20; ++i)
839         items << QString("item %1").arg(i);
840     QStringListModel model(items);
841
842     QListView view;
843     view.setModel(&model);
844
845     view.resize(220,182);
846     view.show();
847
848     for (int pass = 0; pass < 2; ++pass) {
849         view.setFlow(pass == 0 ? QListView::TopToBottom : QListView::LeftToRight);
850         QScrollBar *sb = pass == 0 ? view.verticalScrollBar() : view.horizontalScrollBar();
851         QList<QSize> gridsizes;
852         gridsizes << QSize() << QSize(200,38);
853         for (int ig = 0; ig < gridsizes.count(); ++ig) {
854             if (pass == 1 && !gridsizes.at(ig).isValid()) // the width of an item varies, so it might jump two times
855                 continue;
856             view.setGridSize(gridsizes.at(ig));
857
858             qApp->processEvents();
859             int offset = sb->value();
860
861             // first "scroll" down, verify that we scroll one step at a time
862             i = 0;
863             for (i = 0; i < 20; ++i) {
864                 QModelIndex idx = model.index(i,0);
865                 view.setCurrentIndex(idx);
866                 if (offset != sb->value()) {
867                     // If it has scrolled, it should have scrolled only by one.
868                     QCOMPARE(sb->value(), offset + 1);
869                     ++offset;
870                 }
871                 //QTest::qWait(50);
872             }
873
874             --i;    // item 20 does not exist
875             // and then "scroll" up, verify that we scroll one step at a time
876             for (; i >= 0; --i) {
877                 QModelIndex idx = model.index(i,0);
878                 view.setCurrentIndex(idx);
879                 if (offset != sb->value()) {
880                     // If it has scrolled, it should have scrolled only by one.
881                     QCOMPARE(sb->value(), offset - 1);
882                     --offset;
883                 }
884                 //QTest::qWait(50);
885             }
886         }
887     }
888 }
889
890 class PublicListView : public QListView
891 {
892     public:
893     PublicListView(QWidget *parent = 0) : QListView(parent)
894     {
895
896     }
897     void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) {
898         QListView::setSelection(rect, flags);
899     }
900     QSize contentsSize() const { return QListView::contentsSize(); }
901
902     void setPositionForIndex(const QPoint &pos, const QModelIndex &index) {
903         QListView::setPositionForIndex(pos, index);
904     }
905 };
906
907 class TestDelegate : public QItemDelegate
908 {
909 public:
910     TestDelegate(QObject *parent) : QItemDelegate(parent), m_sizeHint(50,50) {}
911     QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return m_sizeHint; }
912
913     QSize m_sizeHint;
914 };
915
916 typedef QList<int> IntList;
917 Q_DECLARE_METATYPE(IntList)
918
919 void tst_QListView::selection_data()
920 {
921     QTest::addColumn<int>("itemCount");
922     QTest::addColumn<int>("viewMode");
923     QTest::addColumn<int>("flow");
924     QTest::addColumn<bool>("wrapping");
925     QTest::addColumn<int>("spacing");
926     QTest::addColumn<QSize>("gridSize");
927     QTest::addColumn<IntList>("hiddenRows");
928     QTest::addColumn<QRect>("selectionRect");
929     QTest::addColumn<IntList>("expectedItems");
930
931     QTest::newRow("select all")
932         << 4                                    // itemCount
933         << int(QListView::ListMode)
934         << int(QListView::TopToBottom)
935         << false                                // wrapping
936         << 0                                    // spacing
937         << QSize()                              // gridSize
938         << IntList()                            // hiddenRows
939         << QRect(0, 0, 10, 200)                 // selection rectangle
940         << (IntList() << 0 << 1 << 2 << 3);     // expected items
941
942     QTest::newRow("select below, (on viewport)")
943         << 4                                    // itemCount
944         << int(QListView::ListMode)
945         << int(QListView::TopToBottom)
946         << false                                // wrapping
947         << 0                                    // spacing
948         << QSize()                              // gridSize
949         << IntList()                            // hiddenRows
950         << QRect(10, 250, 1, 1)                 // selection rectangle
951         << IntList();                           // expected items
952
953     QTest::newRow("select below 2, (on viewport)")
954         << 4                                    // itemCount
955         << int(QListView::ListMode)
956         << int(QListView::TopToBottom)
957         << true                                 // wrapping
958         << 0                                    // spacing
959         << QSize()                              // gridSize
960         << IntList()                            // hiddenRows
961         << QRect(10, 250, 1, 1)                 // selection rectangle
962         << IntList();                           // expected items
963
964     QTest::newRow("select to the right, (on viewport)")
965         << 40                                   // itemCount
966         << int(QListView::ListMode)
967         << int(QListView::TopToBottom)
968         << true                                 // wrapping
969         << 0                                    // spacing
970         << QSize()                              // gridSize
971         << IntList()                            // hiddenRows
972         << QRect(300, 10, 1, 1)                 // selection rectangle
973         << IntList();                           // expected items
974
975     QTest::newRow("select to the right 2, (on viewport)")
976         << 40                                   // itemCount
977         << int(QListView::ListMode)
978         << int(QListView::TopToBottom)
979         << true                                 // wrapping
980         << 0                                    // spacing
981         << QSize()                              // gridSize
982         << IntList()                            // hiddenRows
983         << QRect(300, 0, 1, 300)                // selection rectangle
984         << IntList();                           // expected items
985
986 #if defined(Q_OS_WINCE)
987     // depending on whether the display is double-pixeld, we need
988     // to click at a different position
989     bool doubledSize = false;
990     int dpi = GetDeviceCaps(GetDC(0), LOGPIXELSX);
991     if ((dpi < 1000) && (dpi > 0)) {
992         doubledSize = true;
993     }
994     QTest::newRow("select inside contents, (on viewport)")
995         << 35                                   // itemCount
996         << int(QListView::ListMode)
997         << int(QListView::TopToBottom)
998         << true                                 // wrapping
999         << 0                                    // spacing
1000         << QSize()                              // gridSize
1001         << IntList()                            // hiddenRows
1002         << QRect(doubledSize?350:175,doubledSize?550:275, 1, 1)// selection rectangle
1003         << IntList();                           // expected items
1004 #else
1005     QTest::newRow("select inside contents, (on viewport)")
1006         << 35                                   // itemCount
1007         << int(QListView::ListMode)
1008         << int(QListView::TopToBottom)
1009         << true                                 // wrapping
1010         << 0                                    // spacing
1011         << QSize()                              // gridSize
1012         << IntList()                            // hiddenRows
1013         << QRect(175, 275, 1, 1)                // selection rectangle
1014         << IntList();                           // expected items
1015 #endif
1016
1017     QTest::newRow("select a tall rect in LeftToRight flow, wrap items")
1018         << 70                                   // itemCount
1019         << int(QListView::ListMode)
1020         << int(QListView::LeftToRight)
1021         << true                                 // wrapping
1022         << 0                                    // spacing
1023         << QSize()                              // gridSize
1024         << IntList()                            // hiddenRows
1025         << QRect(90, 90, 1, 100)                // selection rectangle
1026         << (IntList()                           // expected items
1027                       << 11 << 12 << 13 << 14 << 15 << 16 << 17 << 18 << 19
1028                 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 << 28 << 29
1029                 << 30 << 31);
1030
1031     QTest::newRow("select a wide rect in LeftToRight, wrap items")
1032         << 70                                   // itemCount
1033         << int(QListView::ListMode)
1034         << int(QListView::LeftToRight)
1035         << true                                 // wrapping
1036         << 0                                    // spacing
1037         << QSize()                              // gridSize
1038         << IntList()                            // hiddenRows
1039         << QRect(90, 90, 200, 1)                // selection rectangle
1040         << (IntList()                           // expected items
1041                       << 11 << 12 << 13 << 14 << 15);
1042
1043     QTest::newRow("select a wide negative rect in LeftToRight flow, wrap items")
1044         << 70                                   // itemCount
1045         << int(QListView::ListMode)
1046         << int(QListView::LeftToRight)
1047         << true                                 // wrapping
1048         << 0                                    // spacing
1049         << QSize()                              // gridSize
1050         << IntList()                            // hiddenRows
1051         << QRect(290, 90, -200, 1)              // selection rectangle
1052         << (IntList()                           // expected items
1053                       << 11 << 12 << 13 << 14 << 15);
1054
1055     QTest::newRow("select a tall rect in TopToBottom flow, wrap items")
1056         << 70                                   // itemCount
1057         << int(QListView::ListMode)
1058         << int(QListView::TopToBottom)
1059         << true                                 // wrapping
1060         << 0                                    // spacing
1061         << QSize()                              // gridSize
1062         << IntList()                            // hiddenRows
1063         << QRect(90, 90, 1, 100)                // selection rectangle
1064         << (IntList()                           // expected items
1065                       << 11
1066                       << 12
1067                       << 13);
1068
1069     QTest::newRow("select a tall negative rect in TopToBottom flow, wrap items")
1070         << 70                                   // itemCount
1071         << int(QListView::ListMode)
1072         << int(QListView::TopToBottom)
1073         << true                                 // wrapping
1074         << 0                                    // spacing
1075         << QSize()                              // gridSize
1076         << IntList()                            // hiddenRows
1077         << QRect(90, 190, 1, -100)              // selection rectangle
1078         << (IntList()                           // expected items
1079                       << 11
1080                       << 12
1081                       << 13);
1082
1083     QTest::newRow("select a wide rect in TopToBottom, wrap items")
1084         << 70                                   // itemCount
1085         << int(QListView::ListMode)
1086         << int(QListView::TopToBottom)
1087         << true                                 // wrapping
1088         << 0                                    // spacing
1089         << QSize()                              // gridSize
1090         << IntList()                            // hiddenRows
1091         << QRect(90, 90, 100, 1)                // selection rectangle
1092         << (IntList()                           // expected items
1093                             << 20 << 30
1094                       << 11 << 21 << 31
1095                       << 12 << 22
1096                       << 13 << 23
1097                       << 14 << 24
1098                       << 15 << 25
1099                       << 16 << 26
1100                       << 17 << 27
1101                       << 18 << 28
1102                       << 19 << 29);
1103 }
1104
1105 void tst_QListView::selection()
1106 {
1107     QFETCH(int, itemCount);
1108     QFETCH(int, viewMode);
1109     QFETCH(int, flow);
1110     QFETCH(bool, wrapping);
1111     QFETCH(int, spacing);
1112     QFETCH(QSize, gridSize);
1113     QFETCH(IntList, hiddenRows);
1114     QFETCH(QRect, selectionRect);
1115     QFETCH(IntList, expectedItems);
1116
1117     QWidget topLevel;
1118     PublicListView v(&topLevel);
1119     QtTestModel model;
1120     model.colCount = 1;
1121     model.rCount = itemCount;
1122
1123     // avoid scrollbar size mismatches among different styles
1124     v.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1125     v.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1126
1127     v.setItemDelegate(new TestDelegate(&v));
1128     v.setModel(&model);
1129     v.setViewMode(QListView::ViewMode(viewMode));
1130     v.setFlow(QListView::Flow(flow));
1131     v.setWrapping(wrapping);
1132     v.setResizeMode(QListView::Adjust);
1133     v.setSpacing(spacing);
1134     if (gridSize.isValid())
1135         v.setGridSize(gridSize);
1136     for (int j = 0; j < hiddenRows.count(); ++j) {
1137         v.setRowHidden(hiddenRows.at(j), true);
1138     }
1139
1140 #if defined(Q_OS_WINCE)
1141     // If the device is double-pixeled then the scrollbars become
1142     // 10 pixels wider than normal (Windows Style: 16, Windows Mobile Style: 26).
1143     // So we have to make the window slightly bigger to have the same count of
1144     // items in each row of the list view like in the other styles.
1145     static const int dpi = ::GetDeviceCaps(GetDC(0), LOGPIXELSX);
1146     if ((dpi < 1000) && (dpi > 0))
1147         v.resize(535,535);
1148 #else
1149     v.resize(525,525);
1150 #endif
1151
1152     topLevel.show();
1153     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
1154
1155     v.setSelection(selectionRect, QItemSelectionModel::ClearAndSelect);
1156
1157     QModelIndexList selected = v.selectionModel()->selectedIndexes();
1158
1159     QCOMPARE(selected.count(), expectedItems.count());
1160     for (int i = 0; i < selected.count(); ++i) {
1161         QVERIFY(expectedItems.contains(selected.at(i).row()));
1162     }
1163 }
1164
1165 void tst_QListView::scrollTo()
1166 {
1167     QWidget topLevel;
1168     QListView lv(&topLevel);
1169     QStringListModel model(&lv);
1170     QStringList list;
1171     list << "Short item 1";
1172     list << "Short item 2";
1173     list << "Short item 3";
1174     list << "Short item 4";
1175     list << "Short item 5";
1176     list << "Short item 6";
1177     list << "Begin This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1178             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1179             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1180             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1181             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1182             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1183             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1184             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1185             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1186             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1187             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1188             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1189             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1190             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1191             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
1192             "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item End\n";
1193     list << "Short item";
1194     list << "Short item";
1195     list << "Short item";
1196     list << "Short item";
1197     list << "Short item";
1198     list << "Short item";
1199     list << "Short item";
1200     list << "Short item";
1201     model.setStringList(list);
1202     lv.setModel(&model);
1203     lv.setFixedSize(100, 200);
1204     topLevel.show();
1205     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
1206
1207     //by default, the list view scrolls per item and has no wrapping
1208     QModelIndex index = model.index(6,0);
1209
1210     //we save the size of the item for later comparisons
1211     const QSize itemsize = lv.visualRect(index).size();
1212     QVERIFY(itemsize.height() > lv.height());
1213     QVERIFY(itemsize.width() > lv.width());
1214
1215     //we click the item
1216     QPoint p = lv.visualRect(index).center();
1217     QTest::mouseClick(lv.viewport(), Qt::LeftButton, Qt::NoModifier, p);
1218     //let's wait because the scrolling is delayed
1219     QTest::qWait(QApplication::doubleClickInterval() + 150);
1220     QTRY_COMPARE(lv.visualRect(index).y(),0);
1221
1222     //we scroll down. As the item is to tall for the view, it will disappear
1223     QTest::keyClick(lv.viewport(), Qt::Key_Down, Qt::NoModifier);
1224     QCOMPARE(lv.visualRect(index).y(), -itemsize.height());
1225
1226     QTest::keyClick(lv.viewport(), Qt::Key_Up, Qt::NoModifier);
1227     QCOMPARE(lv.visualRect(index).y(), 0);
1228
1229     //Let's enable wrapping
1230
1231     lv.setWrapping(true);
1232     lv.horizontalScrollBar()->setValue(0); //let's scroll to the beginning
1233
1234     //we click the item
1235     p = lv.visualRect(index).center();
1236     QTest::mouseClick(lv.viewport(), Qt::LeftButton, Qt::NoModifier, p);
1237     //let's wait because the scrolling is delayed
1238     QTest::qWait(QApplication::doubleClickInterval() + 150);
1239     QTRY_COMPARE(lv.visualRect(index).x(),0);
1240
1241     //we scroll right. As the item is too wide for the view, it will disappear
1242     QTest::keyClick(lv.viewport(), Qt::Key_Right, Qt::NoModifier);
1243     QCOMPARE(lv.visualRect(index).x(), -itemsize.width());
1244
1245     QTest::keyClick(lv.viewport(), Qt::Key_Left, Qt::NoModifier);
1246     QCOMPARE(lv.visualRect(index).x(), 0);
1247
1248     lv.setWrapping(false);
1249     qApp->processEvents(); //let the layout happen
1250
1251     //Let's try with scrolling per pixel
1252     lv.setHorizontalScrollMode( QListView::ScrollPerPixel);
1253     lv.verticalScrollBar()->setValue(0); //scrolls back to the first item
1254
1255     //we click the item
1256     p = lv.visualRect(index).center();
1257     QTest::mouseClick(lv.viewport(), Qt::LeftButton, Qt::NoModifier, p);
1258     //let's wait because the scrolling is delayed
1259     QTest::qWait(QApplication::doubleClickInterval() + 150);
1260     QTRY_COMPARE(lv.visualRect(index).y(),0);
1261
1262     //we scroll down. As the item is too tall for the view, it will partially disappear
1263     QTest::keyClick(lv.viewport(), Qt::Key_Down, Qt::NoModifier);
1264     QVERIFY(lv.visualRect(index).y()<0);
1265
1266     QTest::keyClick(lv.viewport(), Qt::Key_Up, Qt::NoModifier);
1267     QCOMPARE(lv.visualRect(index).y(), 0);
1268 }
1269
1270
1271 void tst_QListView::scrollBarRanges()
1272 {
1273     const int rowCount = 10;
1274     const int rowHeight = 20;
1275
1276     QWidget topLevel;
1277     QListView lv(&topLevel);
1278     QStringListModel model(&lv);
1279     QStringList list;
1280     for (int i = 0; i < rowCount; ++i)
1281         list << QString::fromLatin1("Item %1").arg(i);
1282
1283     model.setStringList(list);
1284     lv.setModel(&model);
1285     lv.resize(250, 130);
1286     TestDelegate *delegate = new TestDelegate(&lv);
1287     delegate->m_sizeHint = QSize(100, rowHeight);
1288     lv.setItemDelegate(delegate);
1289     topLevel.show();
1290
1291     for (int h = 30; h <= 210; ++h) {
1292         lv.resize(250, h);
1293         QApplication::processEvents(); // wait for the layout to be done
1294         int visibleRowCount = lv.viewport()->size().height() / rowHeight;
1295         int invisibleRowCount = rowCount - visibleRowCount;
1296         QCOMPARE(lv.verticalScrollBar()->maximum(), invisibleRowCount);
1297     }
1298 }
1299
1300 void tst_QListView::scrollBarAsNeeded_data()
1301 {
1302     QTest::addColumn<QSize>("size");
1303     QTest::addColumn<int>("itemCount");
1304     QTest::addColumn<int>("flow");
1305     QTest::addColumn<bool>("horizontalScrollBarVisible");
1306     QTest::addColumn<bool>("verticalScrollBarVisible");
1307
1308
1309     QTest::newRow("TopToBottom, count:0")
1310             << QSize(200, 100)
1311             << 0
1312             << int(QListView::TopToBottom)
1313             << false
1314             << false;
1315
1316     QTest::newRow("TopToBottom, count:1")
1317             << QSize(200, 100)
1318             << 1
1319             << int(QListView::TopToBottom)
1320             << false
1321             << false;
1322
1323     QTest::newRow("TopToBottom, count:20")
1324             << QSize(200, 100)
1325             << 20
1326             << int(QListView::TopToBottom)
1327             << false
1328             << true;
1329
1330     QTest::newRow("LeftToRight, count:0")
1331             << QSize(200, 100)
1332             << 0
1333             << int(QListView::LeftToRight)
1334             << false
1335             << false;
1336
1337     QTest::newRow("LeftToRight, count:1")
1338             << QSize(200, 100)
1339             << 1
1340             << int(QListView::LeftToRight)
1341             << false
1342             << false;
1343
1344     QTest::newRow("LeftToRight, count:20")
1345             << QSize(200, 100)
1346             << 20
1347             << int(QListView::LeftToRight)
1348             << true
1349             << false;
1350
1351
1352 }
1353 void tst_QListView::scrollBarAsNeeded()
1354 {
1355
1356     QFETCH(QSize, size);
1357     QFETCH(int, itemCount);
1358     QFETCH(int, flow);
1359     QFETCH(bool, horizontalScrollBarVisible);
1360     QFETCH(bool, verticalScrollBarVisible);
1361
1362
1363     const int rowCounts[3] = {0, 1, 20};
1364
1365     QWidget topLevel;
1366     QListView lv(&topLevel);
1367     lv.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1368     lv.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1369     lv.setFlow((QListView::Flow)flow);
1370     QStringListModel model(&lv);
1371     lv.setModel(&model);
1372     lv.resize(size);
1373     topLevel.show();
1374
1375     for (uint r = 0; r < sizeof(rowCounts)/sizeof(int); ++r) {
1376         QStringList list;
1377         int i;
1378         for (i = 0; i < rowCounts[r]; ++i)
1379             list << QString::fromLatin1("Item %1").arg(i);
1380
1381         model.setStringList(list);
1382         QApplication::processEvents();
1383         QTest::qWait(50);
1384
1385         QStringList replacement;
1386         for (i = 0; i < itemCount; ++i) {
1387             replacement << QString::fromLatin1("Item %1").arg(i);
1388         }
1389         model.setStringList(replacement);
1390
1391         QApplication::processEvents();
1392
1393         QTRY_COMPARE(lv.horizontalScrollBar()->isVisible(), horizontalScrollBarVisible);
1394         QTRY_COMPARE(lv.verticalScrollBar()->isVisible(), verticalScrollBarVisible);
1395     }
1396 }
1397
1398 void tst_QListView::moveItems()
1399 {
1400     QStandardItemModel model;
1401     for (int r = 0; r < 4; ++r) {
1402         for (int c = 0; c < 4; ++c) {
1403             QStandardItem* item = new QStandardItem(QString("standard item (%1,%2)").arg(r).arg(c));
1404             model.setItem(r, c, item);
1405         }
1406     }
1407
1408     PublicListView view;
1409     view.setViewMode(QListView::IconMode);
1410     view.setResizeMode(QListView::Fixed);
1411     view.setWordWrap(true);
1412     view.setModel(&model);
1413     view.setItemDelegate(new TestDelegate(&view));
1414
1415     for (int r = 0; r < model.rowCount(); ++r) {
1416         for (int c = 0; c < model.columnCount(); ++c) {
1417             const QModelIndex& idx = model.index(r, c);
1418             view.setPositionForIndex(QPoint(r * 75, r * 75), idx);
1419         }
1420     }
1421
1422     QCOMPARE(view.contentsSize(), QSize(275, 275));
1423 }
1424
1425 void tst_QListView::wordWrap()
1426 {
1427     QListView lv;
1428     lv.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1429     lv.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1430     QStringListModel model(&lv);
1431     QStringList list;
1432     list << "Short item 1";
1433     list << "Short item 2";
1434     list << "Short item 3";
1435     list << "Begin\nThis item take severals Lines\nEnd";
1436     list << "And this is a very long item very long item this is a very vary vary long item"
1437             "very long very very long long long this is a long item a very long item a very very long item";
1438     list << "And this is a second even a little more long very long item very long item this is a very vary vary long item"
1439             "very long very very long long long this is a long item a very long item a very very long item";
1440     list << "Short item";
1441     list << "rzeofig zerig fslfgj smdlfkgj qmsdlfj amrzriougf qsla zrg fgsdf gsdfg sdfgs dfg sdfgcvb sdfg qsdjfh qsdfjklh qs";
1442     list << "Short item";
1443     model.setStringList(list);
1444     lv.setModel(&model);
1445     lv.setWordWrap(true);
1446     lv.setFixedSize(150, 150);
1447     lv.show();
1448     QApplication::processEvents();
1449
1450     QTRY_COMPARE(lv.horizontalScrollBar()->isVisible(), false);
1451     QTRY_COMPARE(lv.verticalScrollBar()->isVisible(), true);
1452 }
1453
1454 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1455 class SetCurrentIndexAfterAppendRowCrashDialog : public QDialog
1456 {
1457     Q_OBJECT
1458 public:
1459     SetCurrentIndexAfterAppendRowCrashDialog()
1460     {
1461 #if WINVER >= 0x0500
1462         listView = new QListView();
1463         listView->setViewMode(QListView::IconMode);
1464
1465         model = new QStandardItemModel(this);
1466         listView->setModel(model);
1467
1468         timer = new QTimer(this);
1469         connect(timer, SIGNAL(timeout()), this, SLOT(buttonClicked()));
1470         timer->start(1000);
1471
1472         DWORD lParam = 0xFFFFFFFC/*OBJID_CLIENT*/;
1473         DWORD wParam = 0;
1474         if (const HWND hwnd =getHWNDForWidget(this))
1475             SendMessage(hwnd, WM_GETOBJECT, wParam, lParam);
1476 #endif
1477     }
1478
1479 private slots:
1480     void buttonClicked()
1481     {
1482         timer->stop();
1483         QStandardItem *item = new QStandardItem("test");
1484         model->appendRow(item);
1485         listView->setCurrentIndex(model->indexFromItem(item));
1486         close();
1487     }
1488 private:
1489     QListView *listView;
1490     QStandardItemModel *model;
1491     QTimer *timer;
1492 };
1493 #endif
1494
1495 void tst_QListView::setCurrentIndexAfterAppendRowCrash()
1496 {
1497 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && WINVER >= 0x0500
1498     SetCurrentIndexAfterAppendRowCrashDialog w;
1499     w.exec();
1500 #else
1501     QSKIP("This test only makes sense on windows 2000 and higher.");
1502 #endif
1503 }
1504
1505 void tst_QListView::emptyItemSize()
1506 {
1507     QStandardItemModel model;
1508     for (int r = 0; r < 4; ++r) {
1509         QStandardItem* item = new QStandardItem(QString("standard item (%1)").arg(r));
1510         model.setItem(r, 0, item);
1511     }
1512     model.setItem(4, 0, new QStandardItem());
1513
1514     PublicListView view;
1515     view.setModel(&model);
1516
1517     for (int i = 0; i < 5; ++i)
1518         QVERIFY(!view.visualRect(model.index(i, 0)).isEmpty());
1519 }
1520
1521 void tst_QListView::task203585_selectAll()
1522 {
1523     //we make sure that "select all" doesn't select the hidden items
1524     QListView view;
1525     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
1526     view.setModel(new QStringListModel( QStringList() << "foo"));
1527     view.setRowHidden(0, true);
1528     view.selectAll();
1529     QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
1530     view.setRowHidden(0, false);
1531     view.selectAll();
1532     QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
1533 }
1534
1535 void tst_QListView::task228566_infiniteRelayout()
1536 {
1537     QListView view;
1538
1539     QStringList list;
1540     for (int i = 0; i < 10; ++i) {
1541         list << "small";
1542     }
1543
1544     list << "BIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIG";
1545     list << "BIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIG";
1546
1547     QStringListModel model(list);
1548     view.setModel(&model);
1549     view.setWrapping(true);
1550     view.setResizeMode(QListView::Adjust);
1551
1552     const int itemHeight = view.visualRect( model.index(0, 0)).height();
1553
1554     view.setFixedHeight(itemHeight * 12);
1555     view.show();
1556     QTest::qWait(100); //make sure the layout is done once
1557
1558     QSignalSpy spy(view.horizontalScrollBar(), SIGNAL(rangeChanged(int, int)));
1559
1560     QTest::qWait(200);
1561     //the layout should already have been done
1562     //so there should be no change made to the scrollbar
1563     QCOMPARE(spy.count(), 0);
1564 }
1565
1566 void tst_QListView::task248430_crashWith0SizedItem()
1567 {
1568     QListView view;
1569     view.setViewMode(QListView::IconMode);
1570     QStringListModel model(QStringList() << QLatin1String("item1") << QString());
1571     view.setModel(&model);
1572     view.show();
1573     QVERIFY(QTest::qWaitForWindowExposed(&view));
1574     QTest::qWait(20);
1575 }
1576
1577 void tst_QListView::task250446_scrollChanged()
1578 {
1579     QStandardItemModel model(200, 1);
1580     QListView view;
1581     view.setModel(&model);
1582     QModelIndex index = model.index(0, 0);
1583     QVERIFY(index.isValid());
1584     view.setCurrentIndex(index);
1585     view.show();
1586     QVERIFY(QTest::qWaitForWindowExposed(&view));
1587     const int scrollValue = view.verticalScrollBar()->maximum();
1588     view.verticalScrollBar()->setValue(scrollValue);
1589     QCOMPARE(view.verticalScrollBar()->value(), scrollValue);
1590     QCOMPARE(view.currentIndex(), index);
1591
1592     view.showMinimized();
1593     QTest::qWait(50);
1594     QTRY_COMPARE(view.verticalScrollBar()->value(), scrollValue);
1595     QTRY_COMPARE(view.currentIndex(), index);
1596
1597     view.showNormal();
1598     QTest::qWait(50);
1599     QTRY_COMPARE(view.verticalScrollBar()->value(), scrollValue);
1600     QTRY_COMPARE(view.currentIndex(), index);
1601 }
1602
1603 void tst_QListView::task196118_visualRegionForSelection()
1604 {
1605     class MyListView : public QListView
1606     {
1607     public:
1608         QRegion visualRegionForSelection() const
1609         { return QListView::visualRegionForSelection( selectionModel()->selection()); }
1610     } view;
1611
1612     QStandardItemModel model;
1613     QStandardItem top1("top1");
1614     QStandardItem sub1("sub1");
1615     top1.appendRow(QList<QStandardItem*>() << &sub1);
1616     model.appendColumn(QList<QStandardItem*>() << &top1);
1617     view.setModel(&model);
1618     view.setRootIndex(top1.index());
1619
1620     view.selectionModel()->select(top1.index(), QItemSelectionModel::Select);
1621
1622     QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
1623     QVERIFY(view.visualRegionForSelection().isEmpty());
1624 }
1625
1626 void tst_QListView::task254449_draggingItemToNegativeCoordinates()
1627 {
1628     //we'll check that the items are painted correctly
1629     class MyListView : public QListView
1630     {
1631     public:
1632         void setPositionForIndex(const QPoint &position, const QModelIndex &index)
1633         { QListView::setPositionForIndex(position, index); }
1634
1635     } list;
1636
1637     QStandardItemModel model(1,1);
1638     QModelIndex index = model.index(0,0);
1639     model.setData(index, QLatin1String("foo"));
1640     list.setModel(&model);
1641     list.setViewMode(QListView::IconMode);
1642     list.show();
1643     list.activateWindow();
1644     QVERIFY(QTest::qWaitForWindowActive(&list));
1645
1646
1647     class MyItemDelegate : public QStyledItemDelegate
1648     {
1649     public:
1650         MyItemDelegate() : numPaints(0) { }
1651         void paint(QPainter *painter,
1652                const QStyleOptionViewItem &option, const QModelIndex &index) const
1653         {
1654             numPaints++;
1655             QStyledItemDelegate::paint(painter, option, index);
1656         }
1657
1658         mutable int numPaints;
1659     } delegate;
1660     delegate.numPaints = 0;
1661     list.setItemDelegate(&delegate);
1662     QApplication::processEvents();
1663     QTRY_VERIFY(delegate.numPaints > 0);  //makes sure the layout is done
1664
1665     const QPoint topLeft(-6, 0);
1666     list.setPositionForIndex(topLeft, index);
1667
1668     //we'll make sure the item is repainted
1669     delegate.numPaints = 0;
1670     QApplication::processEvents();
1671     QTRY_COMPARE(delegate.numPaints, 1);
1672     QCOMPARE(list.visualRect(index).topLeft(), topLeft);
1673 }
1674
1675
1676 void tst_QListView::keyboardSearch()
1677 {
1678     QStringList items;
1679     items << "AB" << "AC" << "BA" << "BB" << "BD" << "KAFEINE" << "KONQUEROR" << "KOPETE" << "KOOKA" << "OKULAR";
1680     QStringListModel model(items);
1681
1682     QListView view;
1683     view.setModel(&model);
1684     view.show();
1685     qApp->setActiveWindow(&view);
1686     QVERIFY(QTest::qWaitForWindowActive(&view));
1687
1688 //    QCOMPARE(view.currentIndex() , model.index(0,0));
1689
1690     QTest::keyClick(&view, Qt::Key_K);
1691     QTest::qWait(10);
1692     QCOMPARE(view.currentIndex() , model.index(5,0)); //KAFEINE
1693
1694     QTest::keyClick(&view, Qt::Key_O);
1695     QTest::qWait(10);
1696     QCOMPARE(view.currentIndex() , model.index(6,0)); //KONQUEROR
1697
1698     QTest::keyClick(&view, Qt::Key_N);
1699     QTest::qWait(10);
1700     QCOMPARE(view.currentIndex() , model.index(6,0)); //KONQUEROR
1701 }
1702
1703 void tst_QListView::shiftSelectionWithNonUniformItemSizes()
1704 {
1705     // This checks that no items are selected unexpectedly by Shift-Arrow
1706     // when items with non-uniform sizes are laid out in a grid
1707     {   // First test: QListView::LeftToRight flow
1708         QStringList items;
1709         items << "Long\nText" << "Text" << "Text" << "Text";
1710         QStringListModel model(items);
1711
1712         QListView view;
1713         view.setFixedSize(250, 250);
1714         view.setFlow(QListView::LeftToRight);
1715         view.setGridSize(QSize(100, 100));
1716         view.setSelectionMode(QListView::ExtendedSelection);
1717         view.setViewMode(QListView::IconMode);
1718         view.setModel(&model);
1719         view.show();
1720         QVERIFY(QTest::qWaitForWindowExposed(&view));
1721
1722         // Verfify that item sizes are non-uniform
1723         QVERIFY(view.sizeHintForIndex(model.index(0, 0)).height() > view.sizeHintForIndex(model.index(1, 0)).height());
1724
1725         QModelIndex index = model.index(3, 0);
1726         view.setCurrentIndex(index);
1727         QCOMPARE(view.currentIndex(), index);
1728
1729         QTest::keyClick(&view, Qt::Key_Up, Qt::ShiftModifier);
1730         QTest::qWait(10);
1731         QCOMPARE(view.currentIndex(), model.index(1, 0));
1732
1733         QModelIndexList selected = view.selectionModel()->selectedIndexes();
1734         QCOMPARE(selected.count(), 3);
1735         QVERIFY(!selected.contains(model.index(0, 0)));
1736     }
1737     {   // Second test: QListView::TopToBottom flow
1738         QStringList items;
1739         items << "ab" << "a" << "a" << "a";
1740         QStringListModel model(items);
1741
1742         QListView view;
1743         view.setFixedSize(250, 250);
1744         view.setFlow(QListView::TopToBottom);
1745         view.setGridSize(QSize(100, 100));
1746         view.setSelectionMode(QListView::ExtendedSelection);
1747         view.setViewMode(QListView::IconMode);
1748         view.setModel(&model);
1749         view.show();
1750         QVERIFY(QTest::qWaitForWindowExposed(&view));
1751
1752         // Verfify that item sizes are non-uniform
1753         QVERIFY(view.sizeHintForIndex(model.index(0, 0)).width() > view.sizeHintForIndex(model.index(1, 0)).width());
1754
1755         QModelIndex index = model.index(3, 0);
1756         view.setCurrentIndex(index);
1757         QCOMPARE(view.currentIndex(), index);
1758
1759         QTest::keyClick(&view, Qt::Key_Left, Qt::ShiftModifier);
1760         QTest::qWait(10);
1761         QCOMPARE(view.currentIndex(), model.index(1, 0));
1762
1763         QModelIndexList selected = view.selectionModel()->selectedIndexes();
1764         QCOMPARE(selected.count(), 3);
1765         QVERIFY(!selected.contains(model.index(0, 0)));
1766     }
1767 }
1768
1769 void tst_QListView::clickOnViewportClearsSelection()
1770 {
1771     QStringList items;
1772     items << "Text1";
1773     QStringListModel model(items);
1774     QListView view;
1775     view.setModel(&model);
1776     view.setSelectionMode(QListView::ExtendedSelection);
1777
1778     view.selectAll();
1779     QModelIndex index = model.index(0);
1780     QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
1781     QVERIFY(view.selectionModel()->isSelected(index));
1782
1783     //we try to click outside of the index
1784     const QPoint point = view.visualRect(index).bottomRight() + QPoint(10,10);
1785
1786     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, point);
1787     //at this point, the selection shouldn't have changed
1788     QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
1789     QVERIFY(view.selectionModel()->isSelected(index));
1790
1791     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, point);
1792     //now the selection should be cleared
1793     QVERIFY(!view.selectionModel()->hasSelection());
1794 }
1795
1796 void tst_QListView::task262152_setModelColumnNavigate()
1797 {
1798     QListView view;
1799     QStandardItemModel model(3,2);
1800     model.setItem(0,1,new QStandardItem("[0,1]"));
1801     model.setItem(1,1,new QStandardItem("[1,1]"));
1802     model.setItem(2,1,new QStandardItem("[2,1]"));
1803
1804     view.setModel(&model);
1805     view.setModelColumn(1);
1806
1807     view.show();
1808     QApplication::setActiveWindow(&view);
1809     QVERIFY(QTest::qWaitForWindowActive(&view));
1810     QCOMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
1811     QTest::keyClick(&view, Qt::Key_Down);
1812     QTest::qWait(30);
1813     QTRY_COMPARE(view.currentIndex(), model.index(1,1));
1814     QTest::keyClick(&view, Qt::Key_Down);
1815     QTest::qWait(30);
1816     QTRY_COMPARE(view.currentIndex(), model.index(2,1));
1817 }
1818
1819 void tst_QListView::taskQTBUG_2233_scrollHiddenItems_data()
1820 {
1821     QTest::addColumn<int>("flow");
1822
1823     QTest::newRow("TopToBottom") << static_cast<int>(QListView::TopToBottom);
1824     QTest::newRow("LeftToRight") << static_cast<int>(QListView::LeftToRight);
1825 }
1826
1827 void tst_QListView::taskQTBUG_2233_scrollHiddenItems()
1828 {
1829     QFETCH(int, flow);
1830     const int rowCount = 200;
1831
1832     QWidget topLevel;
1833     QListView view(&topLevel);
1834     QStringListModel model(&view);
1835     QStringList list;
1836     for (int i = 0; i < rowCount; ++i)
1837         list << QString::number(i);
1838
1839     model.setStringList(list);
1840     view.setModel(&model);
1841     view.setUniformItemSizes(true);
1842     view.setViewMode(QListView::ListMode);
1843     for (int i = 0; i < rowCount / 2; ++i)
1844         view.setRowHidden(2 * i, true);
1845     view.setFlow(static_cast<QListView::Flow>(flow));
1846     view.resize(130, 130);
1847
1848     for (int i = 0; i < 10; ++i) {
1849         (view.flow() == QListView::TopToBottom
1850             ? view.verticalScrollBar()
1851             : view.horizontalScrollBar())->setValue(i);
1852         QModelIndex index = view.indexAt(QPoint(0,0));
1853         QVERIFY(index.isValid());
1854         QCOMPARE(index.row(), 2 * i + 1);
1855     }
1856
1857     //QTBUG-7929  should not crash
1858     topLevel.show();
1859     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
1860     QScrollBar *bar = view.flow() == QListView::TopToBottom
1861             ? view.verticalScrollBar() : view.horizontalScrollBar();
1862
1863     int nbVisibleItem = rowCount / 2 - bar->maximum();
1864
1865     bar->setValue(bar->maximum());
1866     QApplication::processEvents();
1867     for (int i = rowCount; i > rowCount / 2; i--) {
1868         view.setRowHidden(i, true);
1869     }
1870     QApplication::processEvents();
1871     QTest::qWait(50);
1872     QCOMPARE(bar->value(), bar->maximum());
1873     QCOMPARE(bar->maximum(), rowCount/4 - nbVisibleItem);
1874 }
1875
1876 void tst_QListView::taskQTBUG_633_changeModelData()
1877 {
1878     QListView view;
1879     view.setFlow(QListView::LeftToRight);
1880     QStandardItemModel model(5,1);
1881     for (int i = 0; i < model.rowCount(); ++i) {
1882         model.setData( model.index(i, 0), QString::number(i));
1883     }
1884
1885     view.setModel(&model);
1886     view.show();
1887     QVERIFY(QTest::qWaitForWindowExposed(&view));
1888     model.setData( model.index(1, 0), QLatin1String("long long text"));
1889     QTest::qWait(100); //leave time for relayouting the items
1890     QRect rectLongText = view.visualRect(model.index(1,0));
1891     QRect rect2 = view.visualRect(model.index(2,0));
1892     QVERIFY( ! rectLongText.intersects(rect2) );
1893 }
1894
1895 void tst_QListView::taskQTBUG_435_deselectOnViewportClick()
1896 {
1897     QListView view;
1898     QStringListModel model( QStringList() << "1" << "2" << "3" << "4");
1899     view.setModel(&model);
1900     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
1901     view.selectAll();
1902     QCOMPARE(view.selectionModel()->selectedIndexes().count(), model.rowCount());
1903
1904
1905     const QRect itemRect = view.visualRect(model.index(model.rowCount() - 1));
1906     QPoint p = view.visualRect(model.index(model.rowCount() - 1)).center() + QPoint(0, itemRect.height());
1907     //first the left button
1908     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
1909     QVERIFY(!view.selectionModel()->hasSelection());
1910
1911     view.selectAll();
1912     QCOMPARE(view.selectionModel()->selectedIndexes().count(), model.rowCount());
1913
1914     //and now the right button
1915     QTest::mouseClick(view.viewport(), Qt::RightButton, 0, p);
1916     QVERIFY(!view.selectionModel()->hasSelection());
1917 }
1918
1919 void tst_QListView::taskQTBUG_2678_spacingAndWrappedText()
1920 {
1921     static const QString lorem("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
1922     QStringListModel model(QStringList() << lorem << lorem << "foo" << lorem << "bar" << lorem << lorem);
1923     QListView w;
1924     w.setModel(&model);
1925     w.setViewMode(QListView::ListMode);
1926     w.setWordWrap(true);
1927     w.setSpacing(10);
1928     w.show();
1929     QVERIFY(QTest::qWaitForWindowExposed(&w));
1930     QCOMPARE(w.horizontalScrollBar()->minimum(), w.horizontalScrollBar()->maximum());
1931 }
1932
1933 void tst_QListView::taskQTBUG_5877_skippingItemInPageDownUp()
1934 {
1935     QList<int> currentItemIndexes;
1936     QtTestModel model(0);
1937     model.colCount = 1;
1938     model.rCount = 100;
1939
1940     currentItemIndexes << 0 << 6 << 16 << 25 << 34 << 42 << 57 << 68 << 77
1941                        << 83 << 91 << 94;
1942     QMoveCursorListView vu;
1943     vu.setModel(&model);
1944     vu.show();
1945
1946     QVERIFY(QTest::qWaitForWindowExposed(&vu));
1947
1948     int itemHeight = vu.visualRect(model.index(0, 0)).height();
1949     int visibleRowCount = vu.viewport()->height() / itemHeight;
1950     int scrolledRowCount = visibleRowCount - 1;
1951
1952     for (int i = 0; i < currentItemIndexes.size(); ++i) {
1953         vu.selectionModel()->setCurrentIndex(model.index(currentItemIndexes[i], 0),
1954                                              QItemSelectionModel::SelectCurrent);
1955
1956         QModelIndex idx = vu.moveCursor(QMoveCursorListView::MovePageDown, Qt::NoModifier);
1957         int newCurrent = qMin(currentItemIndexes[i] + scrolledRowCount, 99);
1958         QCOMPARE(idx, model.index(newCurrent, 0));
1959
1960         idx = vu.moveCursor(QMoveCursorListView::MovePageUp, Qt::NoModifier);
1961         newCurrent = qMax(currentItemIndexes[i] - scrolledRowCount, 0);
1962         QCOMPARE(idx, model.index(newCurrent, 0));
1963     }
1964 }
1965
1966 class ListView_9455 : public QListView
1967 {
1968 public:
1969     QSize contentsSize() const
1970     {
1971         return QListView::contentsSize();
1972     }
1973 };
1974
1975 void tst_QListView::taskQTBUG_9455_wrongScrollbarRanges()
1976 {
1977     QStringList list;
1978     const int nrItems = 8;
1979     for (int i = 0; i < nrItems; i++)
1980         list << QString().sprintf("item %d", i);
1981
1982     QStringListModel model(list);
1983     ListView_9455 w;
1984     w.setModel(&model);
1985     w.setViewMode(QListView::IconMode);
1986     w.resize(116, 132);
1987     w.setMovement(QListView::Static);
1988     const int spacing = 40;
1989     w.setSpacing(spacing);
1990     w.show();
1991     QVERIFY(QTest::qWaitForWindowExposed(&w));
1992     QCOMPARE(w.verticalScrollBar()->maximum(), w.contentsSize().height() - w.viewport()->geometry().height());
1993 }
1994
1995 void tst_QListView::styleOptionViewItem()
1996 {
1997     class MyDelegate : public QStyledItemDelegate
1998     {
1999         public:
2000             void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
2001             {
2002                 QVERIFY(qstyleoption_cast<const QStyleOptionViewItemV4 *>(&option));
2003                 QStyleOptionViewItemV4 opt(option);
2004                 initStyleOption(&opt, index);
2005
2006                 QCOMPARE(opt.index, index);
2007
2008                 QStyledItemDelegate::paint(painter, option, index);
2009             }
2010     };
2011
2012     QListView view;
2013     QStandardItemModel model;
2014     view.setModel(&model);
2015     MyDelegate delegate;
2016     view.setItemDelegate(&delegate);
2017     model.appendRow(QList<QStandardItem*>()
2018         << new QStandardItem("Beginning") <<  new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
2019
2020     // Run test
2021     view.showMaximized();
2022     QApplication::processEvents();
2023 }
2024
2025 void tst_QListView::taskQTBUG_12308_artihmeticException()
2026 {
2027     QListWidget lw;
2028     lw.setLayoutMode(QListView::Batched);
2029     lw.setViewMode(QListView::IconMode);
2030     for (int i = 0; i < lw.batchSize() + 1; i++) {
2031         QListWidgetItem *item = new QListWidgetItem();
2032         item->setText(QString("Item %L1").arg(i));
2033         lw.addItem(item);
2034         item->setHidden(true);
2035     }
2036     lw.show();
2037     QVERIFY(QTest::qWaitForWindowExposed(&lw));
2038     // No crash, it's all right.
2039 }
2040
2041 class Delegate12308 : public QStyledItemDelegate
2042 {
2043     Q_OBJECT
2044 public:
2045     Delegate12308(QObject *parent = 0) : QStyledItemDelegate(parent)
2046     { }
2047
2048     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
2049     {
2050         QVERIFY(option.rect.topLeft() != QPoint(-1, -1));
2051         QStyledItemDelegate::paint(painter, option, index);
2052     }
2053 };
2054
2055 void tst_QListView::taskQTBUG_12308_wrongFlowLayout()
2056 {
2057     QListWidget lw;
2058     Delegate12308 delegate;
2059     lw.setLayoutMode(QListView::Batched);
2060     lw.setViewMode(QListView::IconMode);
2061     lw.setItemDelegate(&delegate);
2062     for (int i = 0; i < lw.batchSize() + 1; i++) {
2063         QListWidgetItem *item = new QListWidgetItem();
2064         item->setText(QString("Item %L1").arg(i));
2065         lw.addItem(item);
2066         if (!item->text().contains(QString::fromLatin1("1")))
2067             item->setHidden(true);
2068     }
2069     lw.show();
2070     QVERIFY(QTest::qWaitForWindowExposed(&lw));
2071 }
2072
2073 void tst_QListView::taskQTBUG_21115_scrollToAndHiddenItems_data()
2074 {
2075     QTest::addColumn<int>("flow");
2076     QTest::newRow("flow TopToBottom") << static_cast<int>(QListView::TopToBottom);
2077     QTest::newRow("flow LeftToRight") << static_cast<int>(QListView::LeftToRight);
2078 }
2079
2080 void tst_QListView::taskQTBUG_21115_scrollToAndHiddenItems()
2081 {
2082     QFETCH(int, flow);
2083
2084     QListView lv;
2085     lv.setUniformItemSizes(true);
2086     lv.setFlow(static_cast<QListView::Flow>(flow));
2087
2088     QStringListModel model;
2089     QStringList list;
2090     for (int i = 0; i < 30; i++)
2091         list << QString::number(i);
2092     model.setStringList(list);
2093     lv.setModel(&model);
2094     lv.show();
2095     QVERIFY(QTest::qWaitForWindowExposed(&lv));
2096
2097     // Save first item rect for reference
2098     QRect firstItemRect = lv.visualRect(model.index(0, 0));
2099
2100     // Select an item and scroll to selection
2101     QModelIndex index = model.index(2, 0);
2102     lv.setCurrentIndex(index);
2103     lv.scrollTo(index, QAbstractItemView::PositionAtTop);
2104     QApplication::processEvents();
2105     QCOMPARE(lv.visualRect(index), firstItemRect);
2106
2107     // Hide some rows and scroll to selection
2108     for (int i = 0; i < 5; i++) {
2109         if (i == index.row())
2110             continue;
2111         lv.setRowHidden(i, true);
2112     }
2113     lv.scrollTo(index, QAbstractItemView::PositionAtTop);
2114     QApplication::processEvents();
2115     QCOMPARE(lv.visualRect(index), firstItemRect);
2116 }
2117
2118
2119 QTEST_MAIN(tst_QListView)
2120 #include "tst_qlistview.moc"