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