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