QTreeView: fix crash when starting a drag with hidden columns.
[qt:qt.git] / tests / auto / qtreeview / tst_qtreeview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43
44 #include <qabstractitemview.h>
45
46 #include <QtTest/QtTest>
47 #include <QtGui/QtGui>
48 #include <private/qabstractitemview_p.h>
49 #include "../../shared/util.h"
50
51 //TESTED_CLASS=
52 //TESTED_FILES=
53
54 Q_DECLARE_METATYPE(QModelIndex)
55 #ifndef QT_NO_DRAGANDDROP
56 Q_DECLARE_METATYPE(QAbstractItemView::DragDropMode)
57 #endif
58 Q_DECLARE_METATYPE(QAbstractItemView::EditTriggers)
59 Q_DECLARE_METATYPE(QAbstractItemView::EditTrigger)
60
61 static void initStandardTreeModel(QStandardItemModel *model)
62 {
63     QStandardItem *item;
64     item = new QStandardItem(QLatin1String("Row 1 Item"));
65     model->insertRow(0, item);
66
67     item = new QStandardItem(QLatin1String("Row 2 Item"));
68     item->setCheckable(true);
69     model->insertRow(1, item);
70
71     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
72     item->setChild(0, childItem);
73
74     item = new QStandardItem(QLatin1String("Row 3 Item"));
75     item->setIcon(QIcon());
76     model->insertRow(2, item);
77 }
78
79 struct PublicView : public QTreeView
80 {
81     inline void executeDelayedItemsLayout()
82     { QTreeView::executeDelayedItemsLayout(); }
83
84     enum PublicCursorAction {
85         MoveUp = QAbstractItemView::MoveUp,
86         MoveDown = QAbstractItemView::MoveDown,
87         MoveLeft = QAbstractItemView::MoveLeft,
88         MoveRight = QAbstractItemView::MoveRight,
89         MoveHome = QAbstractItemView::MoveHome,
90         MoveEnd = QAbstractItemView::MoveEnd,
91         MovePageUp = QAbstractItemView::MovePageUp,
92         MovePageDown = QAbstractItemView::MovePageDown,
93         MoveNext = QAbstractItemView::MoveNext,
94         MovePrevious = QAbstractItemView::MovePrevious
95     };
96
97     inline QModelIndex moveCursor(PublicCursorAction ca, Qt::KeyboardModifiers kbm)
98     { return QTreeView::moveCursor((CursorAction)ca, kbm); }
99
100     inline void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
101     {
102         QTreeView::setSelection(rect, command);
103     }
104     inline int state()
105     {
106         return QTreeView::state();
107     }
108
109     inline int rowHeight(QModelIndex idx) { return QTreeView::rowHeight(idx); }
110     inline int indexRowSizeHint(const QModelIndex &index) const { return QTreeView::indexRowSizeHint(index); }
111
112     inline QModelIndexList selectedIndexes() const { return QTreeView::selectedIndexes(); }
113
114     inline QStyleOptionViewItem viewOptions() const { return QTreeView::viewOptions(); }
115     inline int sizeHintForColumn(int column) const { return QTreeView::sizeHintForColumn(column); }
116     QAbstractItemViewPrivate* aiv_priv() { return static_cast<QAbstractItemViewPrivate*>(d_ptr.data()); }
117 };
118
119 class tst_QTreeView : public QObject
120 {
121     Q_OBJECT
122
123 public:
124     tst_QTreeView();
125     virtual ~tst_QTreeView();
126
127
128 public slots:
129     void initTestCase();
130     void cleanupTestCase();
131     void init();
132     void cleanup();
133
134     void selectionOrderTest();
135
136 private slots:
137     void getSetCheck();
138
139     // one test per QTreeView property
140     void construction();
141     void alternatingRowColors();
142     void currentIndex_data();
143     void currentIndex();
144 #ifndef QT_NO_DRAGANDDROP
145     void dragDropMode_data();
146     void dragDropMode();
147     void dragDropModeFromDragEnabledAndAcceptDrops_data();
148     void dragDropModeFromDragEnabledAndAcceptDrops();
149     void dragDropOverwriteMode();
150 #endif
151     void editTriggers_data();
152     void editTriggers();
153     void hasAutoScroll();
154     void horizontalScrollMode();
155     void iconSize();
156     void indexAt();
157     void indexWidget();
158     void itemDelegate();
159     void itemDelegateForColumnOrRow();
160     void keyboardSearch();
161     void setModel();
162     void openPersistentEditor();
163     void rootIndex();
164
165     // specialized tests below
166     void setHeader();
167     void columnHidden();
168     void rowHidden();
169     void noDelegate();
170     void noModel();
171     void emptyModel();
172     void removeRows();
173     void removeCols();
174     void expandAndCollapse_data();
175     void expandAndCollapse();
176     void expandAndCollapseAll();
177     void expandWithNoChildren();
178     void keyboardNavigation();
179     void headerSections();
180     void moveCursor_data();
181     void moveCursor();
182     void setSelection_data();
183     void setSelection();
184     void extendedSelection_data();
185     void extendedSelection();
186     void indexAbove();
187     void indexBelow();
188     void clicked();
189     void mouseDoubleClick();
190     void rowsAboutToBeRemoved();
191     void headerSections_unhideSection();
192     void columnAt();
193     void scrollTo();
194     void rowsAboutToBeRemoved_move();
195     void resizeColumnToContents();
196     void insertAfterSelect();
197     void removeAfterSelect();
198     void hiddenItems();
199     void spanningItems();
200     void rowSizeHint();
201     void setSortingEnabled();
202     void headerHidden();
203
204     void selection();
205     void removeAndInsertExpandedCol0();
206     void selectionWithHiddenItems();
207     void selectAll();
208
209     void disabledButCheckable();
210     void sortByColumn_data();
211     void sortByColumn();
212
213     void evilModel_data();
214     void evilModel();
215
216     void indexRowSizeHint();
217     void addRowsWhileSectionsAreHidden();
218     void filterProxyModelCrash();
219     void styleOptionViewItem();
220     void keyboardNavigationWithDisabled();
221
222     // task-specific tests:
223     void task174627_moveLeftToRoot();
224     void task171902_expandWith1stColHidden();
225     void task203696_hidingColumnsAndRowsn();
226     void task211293_removeRootIndex();
227     void task216717_updateChildren();
228     void task220298_selectColumns();
229     void task224091_appendColumns();
230     void task225539_deleteModel();
231     void task230123_setItemsExpandable();
232     void task202039_closePersistentEditor();
233     void task238873_avoidAutoReopening();
234     void task244304_clickOnDecoration();
235     void task246536_scrollbarsNotWorking();
236     void task250683_wrongSectionSize();
237     void task239271_addRowsWithFirstColumnHidden();
238     void task254234_proxySort();
239     void task248022_changeSelection();
240     void task245654_changeModelAndExpandAll();
241     void doubleClickedWithSpans();
242     void taskQTBUG_6450_selectAllWith1stColumnHidden();
243     void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint();
244     void taskQTBUG_11466_keyboardNavigationRegression();
245     void taskQTBUG_13567_removeLastItemRegression();
246 };
247
248 class QtTestModel: public QAbstractItemModel
249 {
250 public:
251     QtTestModel(QObject *parent = 0): QAbstractItemModel(parent),
252        fetched(false), rows(0), cols(0), levels(INT_MAX), wrongIndex(false) { init(); }
253
254     QtTestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
255        fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); }
256
257     void init() {
258         decorationsEnabled = false;
259     }
260
261     inline qint32 level(const QModelIndex &index) const {
262         return index.isValid() ? qint32(index.internalId()) : qint32(-1);
263     }
264
265     bool canFetchMore(const QModelIndex &) const {
266         return !fetched;
267     }
268
269     void fetchMore(const QModelIndex &) {
270         fetched = true;
271     }
272
273     bool hasChildren(const QModelIndex &parent = QModelIndex()) const {
274         bool hasFetched = fetched;
275         fetched = true;
276         bool r = QAbstractItemModel::hasChildren(parent);
277         fetched = hasFetched;
278         return r;
279     }
280
281     int rowCount(const QModelIndex& parent = QModelIndex()) const {
282         if (!fetched)
283             qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO);
284         if ((parent.column() > 0) || (level(parent) > levels))
285             return 0;
286         return rows;
287     }
288     int columnCount(const QModelIndex& parent = QModelIndex()) const {
289         if ((parent.column() > 0) || (level(parent) > levels))
290             return 0;
291         return cols;
292     }
293
294     bool isEditable(const QModelIndex &index) const {
295         if (index.isValid())
296             return true;
297         return false;
298     }
299
300     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
301     {
302         if (row < 0 || column < 0 || (level(parent) > levels) || column >= cols || row >= rows) {
303             return QModelIndex();
304         }
305         QModelIndex i = createIndex(row, column, level(parent) + 1);
306         parentHash[i] = parent;
307         return i;
308     }
309
310     QModelIndex parent(const QModelIndex &index) const
311     {
312         if (!parentHash.contains(index))
313             return QModelIndex();
314         return parentHash[index];
315     }
316
317     QVariant data(const QModelIndex &idx, int role) const
318     {
319         if (!idx.isValid())
320             return QVariant();
321
322         if (role == Qt::DisplayRole) {
323             if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
324                 wrongIndex = true;
325                 qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
326                          idx.internalPointer());
327             }
328             if (idx.row() & 1)
329                 return QString("[%1,%2,%3] - this item is extra wide").arg(idx.row()).arg(idx.column()).arg(level(idx));
330             return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column()).arg(level(idx));
331         }
332         if (decorationsEnabled && role == Qt::DecorationRole) {
333             QPixmap pm(16,16);
334             pm.fill(QColor::fromHsv((idx.column() % 16)*8 + 64, 254, (idx.row() % 16)*8 + 32));
335             return pm;
336         }
337         return QVariant();
338     }
339
340     void removeLastRow()
341     {
342         beginRemoveRows(QModelIndex(), rows - 1, rows - 1);
343         --rows;
344         endRemoveRows();
345     }
346
347     void removeAllRows()
348     {
349         beginRemoveRows(QModelIndex(), 0, rows - 1);
350         rows = 0;
351         endRemoveRows();
352     }
353
354     void removeLastColumn()
355     {
356         beginRemoveColumns(QModelIndex(), cols - 1, cols - 1);
357         --cols;
358         endRemoveColumns();
359     }
360
361     void removeAllColumns()
362     {
363         beginRemoveColumns(QModelIndex(), 0, cols - 1);
364         cols = 0;
365         endRemoveColumns();
366     }
367
368     void insertNewRow()
369     {
370         beginInsertRows(QModelIndex(), rows - 1, rows - 1);
371         ++rows;
372         endInsertRows();
373     }
374
375     void setDecorationsEnabled(bool enable)
376     {
377         decorationsEnabled = enable;
378     }
379
380     mutable bool fetched;
381     bool decorationsEnabled;
382     int rows, cols;
383     int levels;
384     mutable bool wrongIndex;
385     mutable QMap<QModelIndex,QModelIndex> parentHash;
386 };
387
388 tst_QTreeView::tst_QTreeView()
389 {
390 }
391
392 tst_QTreeView::~tst_QTreeView()
393 {
394 }
395
396 void tst_QTreeView::initTestCase()
397 {
398 #ifdef Q_OS_WINCE //disable magic for WindowsCE
399     qApp->setAutoMaximizeThreshold(-1);
400 #endif
401     qRegisterMetaType<QModelIndex>("QModelIndex");
402 }
403
404 void tst_QTreeView::cleanupTestCase()
405 {
406 }
407
408 void tst_QTreeView::init()
409 {
410 }
411
412 void tst_QTreeView::cleanup()
413 {
414 }
415
416 // Testing get/set functions
417 void tst_QTreeView::getSetCheck()
418 {
419     QTreeView obj1;
420
421     // int QTreeView::indentation()
422     // void QTreeView::setIndentation(int)
423     QCOMPARE(obj1.indentation(), 20);
424     obj1.setIndentation(0);
425     QCOMPARE(obj1.indentation(), 0);
426     obj1.setIndentation(INT_MIN);
427     QCOMPARE(obj1.indentation(), INT_MIN);
428     obj1.setIndentation(INT_MAX);
429     QCOMPARE(obj1.indentation(), INT_MAX);
430
431     // bool QTreeView::rootIsDecorated()
432     // void QTreeView::setRootIsDecorated(bool)
433     QCOMPARE(obj1.rootIsDecorated(), true);
434     obj1.setRootIsDecorated(false);
435     QCOMPARE(obj1.rootIsDecorated(), false);
436     obj1.setRootIsDecorated(true);
437     QCOMPARE(obj1.rootIsDecorated(), true);
438
439     // bool QTreeView::uniformRowHeights()
440     // void QTreeView::setUniformRowHeights(bool)
441     QCOMPARE(obj1.uniformRowHeights(), false);
442     obj1.setUniformRowHeights(false);
443     QCOMPARE(obj1.uniformRowHeights(), false);
444     obj1.setUniformRowHeights(true);
445     QCOMPARE(obj1.uniformRowHeights(), true);
446
447     // bool QTreeView::itemsExpandable()
448     // void QTreeView::setItemsExpandable(bool)
449     QCOMPARE(obj1.itemsExpandable(), true);
450     obj1.setItemsExpandable(false);
451     QCOMPARE(obj1.itemsExpandable(), false);
452     obj1.setItemsExpandable(true);
453     QCOMPARE(obj1.itemsExpandable(), true);
454
455     // bool QTreeView::allColumnsShowFocus
456     // void QTreeView::setAllColumnsShowFocus
457     QCOMPARE(obj1.allColumnsShowFocus(), false);
458     obj1.setAllColumnsShowFocus(false);
459     QCOMPARE(obj1.allColumnsShowFocus(), false);
460     obj1.setAllColumnsShowFocus(true);
461     QCOMPARE(obj1.allColumnsShowFocus(), true);
462
463     // bool QTreeView::isAnimated
464     // void QTreeView::setAnimated
465     QCOMPARE(obj1.isAnimated(), false);
466     obj1.setAnimated(false);
467     QCOMPARE(obj1.isAnimated(), false);
468     obj1.setAnimated(true);
469     QCOMPARE(obj1.isAnimated(), true);
470
471     // bool QTreeView::setSortingEnabled
472     // void QTreeView::isSortingEnabled
473     QCOMPARE(obj1.isSortingEnabled(), false);
474     obj1.setSortingEnabled(false);
475     QCOMPARE(obj1.isSortingEnabled(), false);
476     obj1.setSortingEnabled(true);
477     QCOMPARE(obj1.isSortingEnabled(), true);
478 }
479
480 void tst_QTreeView::construction()
481 {
482     QTreeView view;
483
484     // QAbstractItemView properties
485     QVERIFY(!view.alternatingRowColors());
486     QCOMPARE(view.currentIndex(), QModelIndex());
487 #ifndef QT_NO_DRAGANDDROP
488     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
489     QVERIFY(!view.dragDropOverwriteMode());
490     QVERIFY(!view.dragEnabled());
491 #endif
492     QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked);
493     QVERIFY(view.hasAutoScroll());
494     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
495     QCOMPARE(view.iconSize(), QSize());
496     QCOMPARE(view.indexAt(QPoint()), QModelIndex());
497     QVERIFY(!view.indexWidget(QModelIndex()));
498     QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate()));
499     QVERIFY(!view.itemDelegateForColumn(-1));
500     QVERIFY(!view.itemDelegateForColumn(0));
501     QVERIFY(!view.itemDelegateForColumn(1));
502     QVERIFY(!view.itemDelegateForRow(-1));
503     QVERIFY(!view.itemDelegateForRow(0));
504     QVERIFY(!view.itemDelegateForRow(1));
505     QVERIFY(!view.model());
506     QCOMPARE(view.rootIndex(), QModelIndex());
507     QCOMPARE(view.selectionBehavior(), QAbstractItemView::SelectRows);
508     QCOMPARE(view.selectionMode(), QAbstractItemView::SingleSelection);
509     QVERIFY(!view.selectionModel());
510 #ifndef QT_NO_DRAGANDDROP
511     QVERIFY(view.showDropIndicator());
512 #endif
513     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(-1), -1); // <- protected in QTreeView
514     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(0), -1); // <- protected in QTreeView
515     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(1), -1); // <- protected in QTreeView
516     QCOMPARE(view.sizeHintForIndex(QModelIndex()), QSize());
517     QCOMPARE(view.sizeHintForRow(-1), -1);
518     QCOMPARE(view.sizeHintForRow(0), -1);
519     QCOMPARE(view.sizeHintForRow(1), -1);
520     QVERIFY(!view.tabKeyNavigation());
521     QCOMPARE(view.textElideMode(), Qt::ElideRight);
522     QCOMPARE(view.verticalScrollMode(), QAbstractItemView::ScrollPerItem);
523     QCOMPARE(view.visualRect(QModelIndex()), QRect());
524
525     // QTreeView properties
526     QVERIFY(!view.allColumnsShowFocus());
527     QCOMPARE(view.autoExpandDelay(), -1);
528     QCOMPARE(view.columnAt(-1), -1);
529     QCOMPARE(view.columnAt(0), -1);
530     QCOMPARE(view.columnAt(1), -1);
531     QCOMPARE(view.columnViewportPosition(-1), -1);
532     QCOMPARE(view.columnViewportPosition(0), -1);
533     QCOMPARE(view.columnViewportPosition(1), -1);
534     QCOMPARE(view.columnWidth(-1), 0);
535     QCOMPARE(view.columnWidth(0), 0);
536     QCOMPARE(view.columnWidth(1), 0);
537     QVERIFY(view.header());
538     QCOMPARE(view.indentation(), 20);
539     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
540     QCOMPARE(view.indexBelow(QModelIndex()), QModelIndex());
541     QVERIFY(!view.isAnimated());
542     QVERIFY(!view.isColumnHidden(-1));
543     QVERIFY(!view.isColumnHidden(0));
544     QVERIFY(!view.isColumnHidden(1));
545     QVERIFY(!view.isExpanded(QModelIndex()));
546     QVERIFY(!view.isRowHidden(-1, QModelIndex()));
547     QVERIFY(!view.isRowHidden(0, QModelIndex()));
548     QVERIFY(!view.isRowHidden(1, QModelIndex()));
549     QVERIFY(!view.isFirstColumnSpanned(-1, QModelIndex()));
550     QVERIFY(!view.isFirstColumnSpanned(0, QModelIndex()));
551     QVERIFY(!view.isFirstColumnSpanned(1, QModelIndex()));
552     QVERIFY(!view.isSortingEnabled());
553     QVERIFY(view.itemsExpandable());
554     QVERIFY(view.rootIsDecorated());
555     QVERIFY(!view.uniformRowHeights());
556     QCOMPARE(view.visualRect(QModelIndex()), QRect());
557     QVERIFY(!view.wordWrap());
558 }
559
560 void tst_QTreeView::alternatingRowColors()
561 {
562     QTreeView view;
563     QVERIFY(!view.alternatingRowColors());
564     view.setAlternatingRowColors(true);
565     QVERIFY(view.alternatingRowColors());
566     view.setAlternatingRowColors(false);
567     QVERIFY(!view.alternatingRowColors());
568
569     // ### Test visual effect.
570 }
571
572 void tst_QTreeView::currentIndex_data()
573 {
574     QTest::addColumn<int>("row");
575     QTest::addColumn<int>("column");
576     QTest::addColumn<int>("indexRow");
577     QTest::addColumn<int>("indexColumn");
578     QTest::addColumn<int>("parentIndexRow");
579     QTest::addColumn<int>("parentIndexColumn");
580
581     QTest::newRow("-1, -1") << -1 << -1 << -1 << -1 << -1 << -1;
582     QTest::newRow("-1, 0") << -1 << 0 << -1 << -1 << -1 << -1;
583     QTest::newRow("0, -1") << 0 << -1 << -1 << -1 << -1 << -1;
584     QTest::newRow("0, 0") << 0 << 0 << 0 << 0 << -1 << -1;
585     QTest::newRow("0, 1") << 0 << 0 << 0 << 0 << -1 << -1;
586     QTest::newRow("1, 0") << 1 << 0 << 1 << 0 << -1 << -1;
587     QTest::newRow("1, 1") << 1 << 1 << -1 << -1 << -1 << -1;
588     QTest::newRow("2, 0") << 2 << 0 << 2 << 0 << -1 << -1;
589     QTest::newRow("2, 1") << 2 << 1 << -1 << -1 << -1 << -1;
590     QTest::newRow("3, -1") << 3 << -1 << -1 << -1 << -1 << -1;
591     QTest::newRow("3, 0") << 3 << 0 << -1 << -1 << -1 << -1;
592     QTest::newRow("3, 1") << 3 << 1 << -1 << -1 << -1 << -1;
593 }
594
595 void tst_QTreeView::currentIndex()
596 {
597     QFETCH(int, row);
598     QFETCH(int, column);
599     QFETCH(int, indexRow);
600     QFETCH(int, indexColumn);
601     QFETCH(int, parentIndexRow);
602     QFETCH(int, parentIndexColumn);
603
604     QTreeView view;
605     QStandardItemModel treeModel;
606     initStandardTreeModel(&treeModel);
607     view.setModel(&treeModel);
608
609     QCOMPARE(view.currentIndex(), QModelIndex());
610     view.setCurrentIndex(view.model()->index(row, column));
611     QCOMPARE(view.currentIndex().row(), indexRow);
612     QCOMPARE(view.currentIndex().column(), indexColumn);
613     QCOMPARE(view.currentIndex().parent().row(), parentIndexRow);
614     QCOMPARE(view.currentIndex().parent().column(), parentIndexColumn);
615
616     // ### Test child and grandChild indexes.
617 }
618
619 #ifndef QT_NO_DRAGANDDROP
620
621 void tst_QTreeView::dragDropMode_data()
622 {
623     QTest::addColumn<QAbstractItemView::DragDropMode>("dragDropMode");
624     QTest::addColumn<bool>("acceptDrops");
625     QTest::addColumn<bool>("dragEnabled");
626     QTest::newRow("NoDragDrop") << QAbstractItemView::NoDragDrop << false << false;
627     QTest::newRow("DragOnly") << QAbstractItemView::DragOnly << false << true;
628     QTest::newRow("DropOnly") << QAbstractItemView::DropOnly << true << false;
629     QTest::newRow("DragDrop") << QAbstractItemView::DragDrop << true << true;
630     QTest::newRow("InternalMove") << QAbstractItemView::InternalMove << true << true;
631 }
632
633 void tst_QTreeView::dragDropMode()
634 {
635     QFETCH(QAbstractItemView::DragDropMode, dragDropMode);
636     QFETCH(bool, acceptDrops);
637     QFETCH(bool, dragEnabled);
638
639     QTreeView view;
640     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
641     QVERIFY(!view.acceptDrops());
642     QVERIFY(!view.dragEnabled());
643
644     view.setDragDropMode(dragDropMode);
645     QCOMPARE(view.dragDropMode(), dragDropMode);
646     QCOMPARE(view.acceptDrops(), acceptDrops);
647     QCOMPARE(view.dragEnabled(), dragEnabled);
648
649     // ### Test effects of this mode
650 }
651
652 void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops_data()
653 {
654     QTest::addColumn<bool>("dragEnabled");
655     QTest::addColumn<bool>("acceptDrops");
656     QTest::addColumn<QAbstractItemView::DragDropMode>("dragDropMode");
657     QTest::addColumn<QAbstractItemView::DragDropMode>("setBehavior");
658
659     QTest::newRow("NoDragDrop -1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDropMode(-1);
660     QTest::newRow("NoDragDrop 0") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::NoDragDrop;
661     QTest::newRow("NoDragDrop 1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragOnly;
662     QTest::newRow("NoDragDrop 2") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DropOnly;
663     QTest::newRow("NoDragDrop 3") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDrop;
664     QTest::newRow("NoDragDrop 4") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::InternalMove;
665     QTest::newRow("DragOnly -1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDropMode(-1);
666     QTest::newRow("DragOnly 0") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::NoDragDrop;
667     QTest::newRow("DragOnly 1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragOnly;
668     QTest::newRow("DragOnly 2") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DropOnly;
669     QTest::newRow("DragOnly 3") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDrop;
670     QTest::newRow("DragOnly 4") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::InternalMove;
671     QTest::newRow("DropOnly -1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDropMode(-1);
672     QTest::newRow("DropOnly 0") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::NoDragDrop;
673     QTest::newRow("DropOnly 1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragOnly;
674     QTest::newRow("DropOnly 2") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DropOnly;
675     QTest::newRow("DropOnly 3") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDrop;
676     QTest::newRow("DropOnly 4") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::InternalMove;
677     QTest::newRow("DragDrop -1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1);
678     QTest::newRow("DragDrop 0") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1);
679     QTest::newRow("DragDrop 1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::NoDragDrop;
680     QTest::newRow("DragDrop 2") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragOnly;
681     QTest::newRow("DragDrop 3") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DropOnly;
682     QTest::newRow("DragDrop 4") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDrop;
683     QTest::newRow("DragDrop 5") << true << true << QAbstractItemView::InternalMove << QAbstractItemView::InternalMove;
684 }
685
686 void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops()
687 {
688     QFETCH(bool, acceptDrops);
689     QFETCH(bool, dragEnabled);
690     QFETCH(QAbstractItemView::DragDropMode, dragDropMode);
691     QFETCH(QAbstractItemView::DragDropMode, setBehavior);
692
693     QTreeView view;
694     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
695
696     if (setBehavior != QAbstractItemView::DragDropMode(-1))
697         view.setDragDropMode(setBehavior);
698
699     view.setAcceptDrops(acceptDrops);
700     view.setDragEnabled(dragEnabled);
701     QCOMPARE(view.dragDropMode(), dragDropMode);
702
703     // ### Test effects of this mode
704 }
705
706 void tst_QTreeView::dragDropOverwriteMode()
707 {
708     QTreeView view;
709     QVERIFY(!view.dragDropOverwriteMode());
710     view.setDragDropOverwriteMode(true);
711     QVERIFY(view.dragDropOverwriteMode());
712     view.setDragDropOverwriteMode(false);
713     QVERIFY(!view.dragDropOverwriteMode());
714
715     // ### This property changes the behavior of dropIndicatorPosition(),
716     // which is protected and called only from within QListWidget and
717     // QTableWidget, from their reimplementations of dropMimeData(). Hard to
718     // test.
719 }
720 #endif
721
722 void tst_QTreeView::editTriggers_data()
723 {
724     QTest::addColumn<QAbstractItemView::EditTriggers>("editTriggers");
725     QTest::addColumn<QAbstractItemView::EditTrigger>("triggeredTrigger");
726     QTest::addColumn<bool>("editorOpened");
727
728     // NoEditTriggers
729     QTest::newRow("NoEditTriggers 0") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
730                                       << QAbstractItemView::NoEditTriggers << false;
731     QTest::newRow("NoEditTriggers 1") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
732                                       << QAbstractItemView::CurrentChanged << false;
733     QTest::newRow("NoEditTriggers 2") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
734                                       << QAbstractItemView::DoubleClicked << false;
735     QTest::newRow("NoEditTriggers 3") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
736                                       << QAbstractItemView::SelectedClicked << false;
737     QTest::newRow("NoEditTriggers 4") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
738                                       << QAbstractItemView::EditKeyPressed << false;
739
740     // CurrentChanged
741     QTest::newRow("CurrentChanged 0") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
742                                       << QAbstractItemView::NoEditTriggers << false;
743     QTest::newRow("CurrentChanged 1") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
744                                       << QAbstractItemView::CurrentChanged << true;
745     QTest::newRow("CurrentChanged 2") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
746                                       << QAbstractItemView::DoubleClicked << false;
747     QTest::newRow("CurrentChanged 3") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
748                                       << QAbstractItemView::SelectedClicked << false;
749     QTest::newRow("CurrentChanged 4") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
750                                       << QAbstractItemView::EditKeyPressed << false;
751
752     // DoubleClicked
753     QTest::newRow("DoubleClicked 0") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
754                                      << QAbstractItemView::NoEditTriggers << false;
755     QTest::newRow("DoubleClicked 1") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
756                                      << QAbstractItemView::CurrentChanged << false;
757     QTest::newRow("DoubleClicked 2") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
758                                      << QAbstractItemView::DoubleClicked << true;
759     QTest::newRow("DoubleClicked 3") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
760                                      << QAbstractItemView::SelectedClicked << false;
761     QTest::newRow("DoubleClicked 4") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
762                                      << QAbstractItemView::EditKeyPressed << false;
763
764     // SelectedClicked
765     QTest::newRow("SelectedClicked 0") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
766                                        << QAbstractItemView::NoEditTriggers << false;
767     QTest::newRow("SelectedClicked 1") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
768                                        << QAbstractItemView::CurrentChanged << false;
769     QTest::newRow("SelectedClicked 2") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
770                                        << QAbstractItemView::DoubleClicked << false;
771     QTest::newRow("SelectedClicked 3") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
772                                        << QAbstractItemView::SelectedClicked << true;
773     QTest::newRow("SelectedClicked 4") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
774                                        << QAbstractItemView::EditKeyPressed << false;
775
776     // EditKeyPressed
777     QTest::newRow("EditKeyPressed 0") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
778                                       << QAbstractItemView::NoEditTriggers << false;
779     QTest::newRow("EditKeyPressed 1") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
780                                       << QAbstractItemView::CurrentChanged << false;
781     QTest::newRow("EditKeyPressed 2") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
782                                       << QAbstractItemView::DoubleClicked << false;
783     QTest::newRow("EditKeyPressed 3") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
784                                       << QAbstractItemView::SelectedClicked << false;
785     QTest::newRow("EditKeyPressed 4") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
786                                       << QAbstractItemView::EditKeyPressed << true;
787 }
788
789 void tst_QTreeView::editTriggers()
790 {
791     QFETCH(QAbstractItemView::EditTriggers, editTriggers);
792     QFETCH(QAbstractItemView::EditTrigger, triggeredTrigger);
793     QFETCH(bool, editorOpened);
794
795     QTreeView view;
796     QStandardItemModel treeModel;
797     initStandardTreeModel(&treeModel);
798     view.setModel(&treeModel);
799     view.show();
800
801     QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked);
802
803     // Initialize the first index
804     view.setCurrentIndex(view.model()->index(0, 0));
805
806     // Verify that we don't have any editor initially
807     QVERIFY(!qFindChild<QLineEdit *>(&view, QString()));
808
809     // Set the triggers
810     view.setEditTriggers(editTriggers);
811
812     // Interact with the view
813     switch (triggeredTrigger) {
814     case QAbstractItemView::NoEditTriggers:
815         // Do nothing, the editor shouldn't be there
816         break;
817     case QAbstractItemView::CurrentChanged:
818         // Change the index to open an editor
819         view.setCurrentIndex(view.model()->index(1, 0));
820         break;
821     case QAbstractItemView::DoubleClicked:
822         // Doubleclick the center of the current cell
823         QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
824                           view.visualRect(view.model()->index(0, 0)).center());
825         QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0,
826                            view.visualRect(view.model()->index(0, 0)).center());
827         break;
828     case QAbstractItemView::SelectedClicked:
829         // Click the center of the current cell
830         view.selectionModel()->select(view.model()->index(0, 0), QItemSelectionModel::Select);
831         QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
832                           view.visualRect(view.model()->index(0, 0)).center());
833         QTest::qWait(int(QApplication::doubleClickInterval() * 1.5));
834         break;
835     case QAbstractItemView::EditKeyPressed:
836         view.setFocus();
837 #ifdef Q_OS_MAC
838         // Mac OS X uses Enter for editing
839         QTest::keyPress(&view, Qt::Key_Enter);
840 #else
841         // All other platforms use F2
842         QTest::keyPress(&view, Qt::Key_F2);
843 #endif
844         break;
845     default:
846         break;
847     }
848
849     // Check if we got an editor
850     QTRY_COMPARE(qFindChild<QLineEdit *>(&view, QString()) != 0, editorOpened);
851 }
852
853 void tst_QTreeView::hasAutoScroll()
854 {
855     QTreeView view;
856     QVERIFY(view.hasAutoScroll());
857     view.setAutoScroll(false);
858     QVERIFY(!view.hasAutoScroll());
859     view.setAutoScroll(true);
860     QVERIFY(view.hasAutoScroll());
861 }
862
863 void tst_QTreeView::horizontalScrollMode()
864 {
865     QStandardItemModel model;
866     for (int i = 0; i < 100; ++i) {
867         model.appendRow(QList<QStandardItem *>()
868                         << new QStandardItem("An item that has very long text and should"
869                                              " cause the horizontal scroll bar to appear.")
870                         << new QStandardItem("An item that has very long text and should"
871                                              " cause the horizontal scroll bar to appear."));
872     }
873
874     QTreeView view;
875     view.setModel(&model);
876     view.setFixedSize(100, 100);
877     view.header()->resizeSection(0, 200);
878     view.show();
879
880     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
881     QCOMPARE(view.horizontalScrollBar()->minimum(), 0);
882     QVERIFY(view.horizontalScrollBar()->maximum() > 2);
883
884     view.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
885     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerItem);
886     QCOMPARE(view.horizontalScrollBar()->minimum(), 0);
887     QCOMPARE(view.horizontalScrollBar()->maximum(), 1);
888
889     view.setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
890     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
891     QCOMPARE(view.horizontalScrollBar()->minimum(), 0);
892     QVERIFY(view.horizontalScrollBar()->maximum() > 2);
893 }
894
895 class RepaintTreeView : public QTreeView
896 {
897 public:
898     RepaintTreeView() : repainted(false) { }
899     bool repainted;
900
901 protected:
902     void paintEvent(QPaintEvent *event)
903     { repainted = true; QTreeView::paintEvent(event); }
904 };
905
906 void tst_QTreeView::iconSize()
907 {
908     RepaintTreeView view;
909     QCOMPARE(view.iconSize(), QSize());
910
911     QStandardItemModel treeModel;
912     initStandardTreeModel(&treeModel);
913     view.setModel(&treeModel);
914     QCOMPARE(view.iconSize(), QSize());
915     QVERIFY(!view.repainted);
916
917     view.show();
918     view.update();
919     QTest::qWaitForWindowShown(&view);
920     QTRY_VERIFY(view.repainted);
921     QCOMPARE(view.iconSize(), QSize());
922
923     view.repainted = false;
924     view.setIconSize(QSize());
925     QTRY_VERIFY(!view.repainted);
926     QCOMPARE(view.iconSize(), QSize());
927
928     view.setIconSize(QSize(10, 10));
929     QTRY_VERIFY(view.repainted);
930     QCOMPARE(view.iconSize(), QSize(10, 10));
931
932     view.repainted = false;
933     view.setIconSize(QSize(10000, 10000));
934     QTRY_VERIFY(view.repainted);
935     QCOMPARE(view.iconSize(), QSize(10000, 10000));
936 }
937
938 void tst_QTreeView::indexAt()
939 {
940     QtTestModel model;
941     model.rows = model.cols = 5;
942
943     QTreeView view;
944     QCOMPARE(view.indexAt(QPoint()), QModelIndex());
945     view.setModel(&model);
946     QVERIFY(view.indexAt(QPoint()) != QModelIndex());
947
948     QSize itemSize = view.visualRect(model.index(0, 0)).size();
949     for (int i = 0; i < model.rowCount(); ++i) {
950         QPoint pos(itemSize.width() / 2, (i * itemSize.height()) + (itemSize.height() / 2));
951         QModelIndex index = view.indexAt(pos);
952         QCOMPARE(index, model.index(i, 0));
953     }
954
955     /*
956       // ### this is wrong; the widget _will_ affect the item size
957     for (int j = 0; j < model.rowCount(); ++j)
958         view.setIndexWidget(model.index(j, 0), new QPushButton);
959     */
960
961     for (int k = 0; k < model.rowCount(); ++k) {
962         QPoint pos(itemSize.width() / 2, (k * itemSize.height()) + (itemSize.height() / 2));
963         QModelIndex index = view.indexAt(pos);
964         QCOMPARE(index, model.index(k, 0));
965     }
966
967     view.show();
968     view.resize(600, 600);
969     view.header()->setStretchLastSection(false);
970     QCOMPARE(view.indexAt(QPoint(550, 20)), QModelIndex());
971 }
972
973 void tst_QTreeView::indexWidget()
974 {
975     QTreeView view;
976     QStandardItemModel treeModel;
977     initStandardTreeModel(&treeModel);
978     view.setModel(&treeModel);
979
980     QModelIndex index = view.model()->index(0, 0);
981
982     QVERIFY(!view.indexWidget(QModelIndex()));
983     QVERIFY(!view.indexWidget(index));
984
985     QString text = QLatin1String("TestLabel");
986
987     QWidget *label = new QLabel(text);
988     view.setIndexWidget(QModelIndex(), label);
989     QVERIFY(!view.indexWidget(QModelIndex()));
990     QVERIFY(!label->parent());
991     view.setIndexWidget(index, label);
992     QCOMPARE(view.indexWidget(index), label);
993     QCOMPARE(label->parentWidget(), view.viewport());
994
995
996     QTextEdit *widget = new QTextEdit(text);
997     widget->setFixedSize(200,100);
998     view.setIndexWidget(index, widget);
999     QCOMPARE(view.indexWidget(index), static_cast<QWidget *>(widget));
1000
1001     QCOMPARE(widget->parentWidget(), view.viewport());
1002     QCOMPARE(widget->geometry(), view.visualRect(index).intersected(widget->geometry()));
1003     QCOMPARE(widget->toPlainText(), text);
1004
1005     //now let's try to do that later when the widget is already shown
1006     view.show();
1007     index = view.model()->index(1, 0);
1008     QVERIFY(!view.indexWidget(index));
1009
1010     widget = new QTextEdit(text);
1011     widget->setFixedSize(200,100);
1012     view.setIndexWidget(index, widget);
1013     QCOMPARE(view.indexWidget(index), static_cast<QWidget *>(widget));
1014
1015     QCOMPARE(widget->parentWidget(), view.viewport());
1016     QCOMPARE(widget->geometry(), view.visualRect(index).intersect(widget->geometry()));
1017     QCOMPARE(widget->toPlainText(), text);
1018 }
1019
1020 void tst_QTreeView::itemDelegate()
1021 {
1022     QPointer<QAbstractItemDelegate> oldDelegate;
1023     QPointer<QItemDelegate> otherItemDelegate;
1024
1025     {
1026         QTreeView view;
1027         QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate()));
1028         QPointer<QAbstractItemDelegate> oldDelegate = view.itemDelegate();
1029
1030         otherItemDelegate = new QItemDelegate;
1031         view.setItemDelegate(otherItemDelegate);
1032         QVERIFY(!otherItemDelegate->parent());
1033         QVERIFY(oldDelegate);
1034
1035         QCOMPARE(view.itemDelegate(), (QAbstractItemDelegate *)otherItemDelegate);
1036
1037         view.setItemDelegate(0);
1038         QVERIFY(!view.itemDelegate()); // <- view does its own drawing?
1039         QVERIFY(otherItemDelegate);
1040     }
1041
1042     // This is strange. Why doesn't setItemDelegate() reparent the delegate?
1043     QVERIFY(!oldDelegate);
1044     QVERIFY(otherItemDelegate);
1045
1046     delete otherItemDelegate;
1047 }
1048
1049 void tst_QTreeView::itemDelegateForColumnOrRow()
1050 {
1051     QTreeView view;
1052     QAbstractItemDelegate *defaultDelegate = view.itemDelegate();
1053     QVERIFY(defaultDelegate);
1054
1055     QVERIFY(!view.itemDelegateForRow(0));
1056     QVERIFY(!view.itemDelegateForColumn(0));
1057     QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate);
1058
1059     QStandardItemModel model;
1060     for (int i = 0; i < 100; ++i) {
1061         model.appendRow(QList<QStandardItem *>()
1062                         << new QStandardItem("An item that has very long text and should"
1063                                              " cause the horizontal scroll bar to appear.")
1064                         << new QStandardItem("An item that has very long text and should"
1065                                              " cause the horizontal scroll bar to appear.")
1066                         << new QStandardItem("An item that has very long text and should"
1067                                              " cause the horizontal scroll bar to appear."));
1068     }
1069     view.setModel(&model);
1070
1071     QVERIFY(!view.itemDelegateForRow(0));
1072     QVERIFY(!view.itemDelegateForColumn(0));
1073     QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate);
1074     QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), defaultDelegate);
1075
1076     QPointer<QAbstractItemDelegate> rowDelegate = new QItemDelegate;
1077     view.setItemDelegateForRow(0, rowDelegate);
1078     QVERIFY(!rowDelegate->parent());
1079     QCOMPARE(view.itemDelegateForRow(0), (QAbstractItemDelegate *)rowDelegate);
1080     QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), (QAbstractItemDelegate *)rowDelegate);
1081     QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), (QAbstractItemDelegate *)rowDelegate);
1082     QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate);
1083     QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), defaultDelegate);
1084
1085     QPointer<QAbstractItemDelegate> columnDelegate = new QItemDelegate;
1086     view.setItemDelegateForColumn(1, columnDelegate);
1087     QVERIFY(!columnDelegate->parent());
1088     QCOMPARE(view.itemDelegateForColumn(1), (QAbstractItemDelegate *)columnDelegate);
1089     QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), (QAbstractItemDelegate *)rowDelegate);
1090     QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), (QAbstractItemDelegate *)rowDelegate); // row wins
1091     QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate);
1092     QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), (QAbstractItemDelegate *)columnDelegate);
1093
1094     view.setItemDelegateForRow(0, 0);
1095     QVERIFY(!view.itemDelegateForRow(0));
1096     QVERIFY(rowDelegate); // <- wasn't deleted
1097
1098     view.setItemDelegateForColumn(1, 0);
1099     QVERIFY(!view.itemDelegateForColumn(1));
1100     QVERIFY(columnDelegate); // <- wasn't deleted
1101
1102     delete rowDelegate;
1103     delete columnDelegate;
1104 }
1105
1106 void tst_QTreeView::keyboardSearch()
1107 {
1108     QTreeView view;
1109     QStandardItemModel model;
1110     model.appendRow(new QStandardItem("Andreas"));
1111     model.appendRow(new QStandardItem("Baldrian"));
1112     model.appendRow(new QStandardItem("Cecilie"));
1113     view.setModel(&model);
1114     view.show();
1115
1116     // Nothing is selected
1117     QVERIFY(!view.selectionModel()->hasSelection());
1118     QVERIFY(!view.selectionModel()->isSelected(model.index(0, 0)));
1119
1120     // First item is selected
1121     view.keyboardSearch(QLatin1String("A"));
1122     QTRY_VERIFY(view.selectionModel()->isSelected(model.index(0, 0)));
1123
1124     // First item is still selected
1125     view.keyboardSearch(QLatin1String("n"));
1126     QVERIFY(view.selectionModel()->isSelected(model.index(0, 0)));
1127
1128     // No "AnB" item - keep the same selection.
1129     view.keyboardSearch(QLatin1String("B"));
1130     QVERIFY(view.selectionModel()->isSelected(model.index(0, 0)));
1131
1132     // Wait a bit.
1133     QTest::qWait(QApplication::keyboardInputInterval() * 2);
1134
1135     // The item that starts with B is selected.
1136     view.keyboardSearch(QLatin1String("B"));
1137     QVERIFY(view.selectionModel()->isSelected(model.index(1, 0)));
1138 }
1139
1140 void tst_QTreeView::setModel()
1141 {
1142     QTreeView view;
1143     view.show();
1144     QCOMPARE(view.model(), (QAbstractItemModel*)0);
1145     QCOMPARE(view.selectionModel(), (QItemSelectionModel*)0);
1146     QCOMPARE(view.header()->model(), (QAbstractItemModel*)0);
1147     QCOMPARE(view.header()->selectionModel(), (QItemSelectionModel*)0);
1148
1149     for (int x = 0; x < 2; ++x) {
1150         QtTestModel *model = new QtTestModel(10, 8);
1151         QAbstractItemModel *oldModel = view.model();
1152         QSignalSpy modelDestroyedSpy(oldModel ? oldModel : model, SIGNAL(destroyed()));
1153         // set the same model twice
1154         for (int i = 0; i < 2; ++i) {
1155             QItemSelectionModel *oldSelectionModel = view.selectionModel();
1156             QItemSelectionModel *dummy = new QItemSelectionModel(model);
1157             QSignalSpy selectionModelDestroyedSpy(
1158                 oldSelectionModel ? oldSelectionModel : dummy, SIGNAL(destroyed()));
1159             view.setModel(model);
1160 //                QCOMPARE(selectionModelDestroyedSpy.count(), (x == 0 || i == 1) ? 0 : 1);
1161             QCOMPARE(view.model(), (QAbstractItemModel *)model);
1162             QCOMPARE(view.header()->model(), (QAbstractItemModel *)model);
1163             QCOMPARE(view.selectionModel() != oldSelectionModel, (i == 0));
1164         }
1165         QTRY_COMPARE(modelDestroyedSpy.count(), 0);
1166
1167         view.setModel(0);
1168         QCOMPARE(view.model(), (QAbstractItemModel*)0);
1169         // ### shouldn't selectionModel also be 0 now?
1170 //        QCOMPARE(view.selectionModel(), (QItemSelectionModel*)0);
1171         delete model;
1172     }
1173 }
1174
1175 void tst_QTreeView::openPersistentEditor()
1176 {
1177     QTreeView view;
1178     QStandardItemModel treeModel;
1179     initStandardTreeModel(&treeModel);
1180     view.setModel(&treeModel);
1181     view.show();
1182
1183     QVERIFY(!qFindChild<QLineEdit *>(view.viewport()));
1184     view.openPersistentEditor(view.model()->index(0, 0));
1185     QVERIFY(qFindChild<QLineEdit *>(view.viewport()));
1186
1187     view.closePersistentEditor(view.model()->index(0, 0));
1188     QVERIFY(!qFindChild<QLineEdit *>(view.viewport())->isVisible());
1189
1190     qApp->sendPostedEvents(0, QEvent::DeferredDelete);
1191     QVERIFY(!qFindChild<QLineEdit *>(view.viewport()));
1192 }
1193
1194 void tst_QTreeView::rootIndex()
1195 {
1196     QTreeView view;
1197     QCOMPARE(view.rootIndex(), QModelIndex());
1198     QStandardItemModel treeModel;
1199     initStandardTreeModel(&treeModel);
1200     view.setModel(&treeModel);
1201     QCOMPARE(view.rootIndex(), QModelIndex());
1202
1203     view.setRootIndex(view.model()->index(1, 0));
1204
1205     QCOMPARE(view.model()->data(view.model()->index(0, view.header()->visualIndex(0), view.rootIndex()), Qt::DisplayRole)
1206              .toString(), QString("Row 2 Child Item"));
1207 }
1208
1209 void tst_QTreeView::setHeader()
1210 {
1211     QTreeView view;
1212     QVERIFY(view.header() != 0);
1213     QCOMPARE(view.header()->orientation(), Qt::Horizontal);
1214     QCOMPARE(view.header()->parent(), (QObject *)&view);
1215     for (int x = 0; x < 2; ++x) {
1216         QSignalSpy destroyedSpy(view.header(), SIGNAL(destroyed()));
1217         Qt::Orientation orient = x ? Qt::Vertical : Qt::Horizontal;
1218         QHeaderView *head = new QHeaderView(orient);
1219         view.setHeader(head);
1220         QCOMPARE(destroyedSpy.count(), 1);
1221         QCOMPARE(head->parent(), (QObject *)&view);
1222         QCOMPARE(view.header(), head);
1223         view.setHeader(head);
1224         QCOMPARE(view.header(), head);
1225         // Itemviews in Qt < 4.2 have asserts for this. Qt >= 4.2 should handle this gracefully
1226         view.setHeader((QHeaderView *)0);
1227         QCOMPARE(view.header(), head);
1228     }
1229 }
1230
1231 void tst_QTreeView::columnHidden()
1232 {
1233     QTreeView view;
1234     QtTestModel model(10, 8);
1235     view.setModel(&model);
1236     view.show();
1237     for (int c = 0; c < model.columnCount(); ++c)
1238         QCOMPARE(view.isColumnHidden(c), false);
1239     // hide even columns
1240     for (int c = 0; c < model.columnCount(); c+=2)
1241         view.setColumnHidden(c, true);
1242     for (int c = 0; c < model.columnCount(); ++c)
1243         QCOMPARE(view.isColumnHidden(c), (c & 1) == 0);
1244     view.update();
1245     // hide odd columns too
1246     for (int c = 1; c < model.columnCount(); c+=2)
1247         view.setColumnHidden(c, true);
1248     for (int c = 0; c < model.columnCount(); ++c)
1249         QCOMPARE(view.isColumnHidden(c), true);
1250     view.update();
1251 }
1252
1253 void tst_QTreeView::rowHidden()
1254 {
1255     QtTestModel model(4, 6);
1256     model.levels = 3;
1257     QTreeView view;
1258     view.resize(500,500);
1259     view.setModel(&model);
1260     view.show();
1261
1262     QCOMPARE(view.isRowHidden(-1, QModelIndex()), false);
1263     QCOMPARE(view.isRowHidden(999999, QModelIndex()), false);
1264     view.setRowHidden(-1, QModelIndex(), true);
1265     view.setRowHidden(999999, QModelIndex(), true);
1266     QCOMPARE(view.isRowHidden(-1, QModelIndex()), false);
1267     QCOMPARE(view.isRowHidden(999999, QModelIndex()), false);
1268
1269     view.setRowHidden(0, QModelIndex(), true);
1270     QCOMPARE(view.isRowHidden(0, QModelIndex()), true);
1271     view.setRowHidden(0, QModelIndex(), false);
1272     QCOMPARE(view.isRowHidden(0, QModelIndex()), false);
1273
1274     QStack<QModelIndex> parents;
1275     parents.push(QModelIndex());
1276     while (!parents.isEmpty()) {
1277         QModelIndex p = parents.pop();
1278         if (model.canFetchMore(p))
1279             model.fetchMore(p);
1280         int rows = model.rowCount(p);
1281         // hide all
1282         for (int r = 0; r < rows; ++r) {
1283             view.setRowHidden(r, p, true);
1284             QCOMPARE(view.isRowHidden(r, p), true);
1285         }
1286         // hide none
1287         for (int r = 0; r < rows; ++r) {
1288             view.setRowHidden(r, p, false);
1289             QCOMPARE(view.isRowHidden(r, p), false);
1290         }
1291         // hide only even rows
1292         for (int r = 0; r < rows; ++r) {
1293             bool hide = (r & 1) == 0;
1294             view.setRowHidden(r, p, hide);
1295             QCOMPARE(view.isRowHidden(r, p), hide);
1296         }
1297         for (int r = 0; r < rows; ++r)
1298             parents.push(model.index(r, 0, p));
1299     }
1300
1301     parents.push(QModelIndex());
1302     while (!parents.isEmpty()) {
1303         QModelIndex p = parents.pop();
1304         // all even rows should still be hidden
1305         for (int r = 0; r < model.rowCount(p); ++r)
1306             QCOMPARE(view.isRowHidden(r, p), (r & 1) == 0);
1307         if (model.rowCount(p) > 0) {
1308             for (int r = 0; r < model.rowCount(p); ++r)
1309                 parents.push(model.index(r, 0, p));
1310         }
1311     }
1312 }
1313
1314 void tst_QTreeView::noDelegate()
1315 {
1316     QtTestModel model(10, 7);
1317     QTreeView view;
1318     view.setModel(&model);
1319     view.setItemDelegate(0);
1320     QCOMPARE(view.itemDelegate(), (QAbstractItemDelegate *)0);
1321 }
1322
1323 void tst_QTreeView::noModel()
1324 {
1325     QTreeView view;
1326     view.show();
1327     view.setRowHidden(0, QModelIndex(), true);
1328 }
1329
1330 void tst_QTreeView::emptyModel()
1331 {
1332     QtTestModel model;
1333     QTreeView view;
1334     view.setModel(&model);
1335     view.show();
1336     QVERIFY(!model.wrongIndex);
1337 }
1338
1339 void tst_QTreeView::removeRows()
1340 {
1341     QtTestModel model(7, 10);
1342
1343     QTreeView view;
1344
1345     view.setModel(&model);
1346     view.show();
1347
1348     model.removeLastRow();
1349     QVERIFY(!model.wrongIndex);
1350
1351     model.removeAllRows();
1352     QVERIFY(!model.wrongIndex);
1353 }
1354
1355 void tst_QTreeView::removeCols()
1356 {
1357     QtTestModel model(5, 8);
1358
1359     QTreeView view;
1360     view.setModel(&model);
1361     view.show();
1362     model.fetched = true;
1363     model.removeLastColumn();
1364     QVERIFY(!model.wrongIndex);
1365     QCOMPARE(view.header()->count(), model.cols);
1366
1367     model.removeAllColumns();
1368     QVERIFY(!model.wrongIndex);
1369     QCOMPARE(view.header()->count(), model.cols);
1370 }
1371
1372 void tst_QTreeView::expandAndCollapse_data()
1373 {
1374     QTest::addColumn<bool>("animationEnabled");
1375     QTest::newRow("normal") << false;
1376     QTest::newRow("animated") << true;
1377
1378 }
1379
1380 void tst_QTreeView::expandAndCollapse()
1381 {
1382     QFETCH(bool, animationEnabled);
1383
1384     QtTestModel model(10, 9);
1385
1386     QTreeView view;
1387     view.setUniformRowHeights(true);
1388     view.setModel(&model);
1389     view.setAnimated(animationEnabled);
1390     view.show();
1391
1392     QModelIndex a = model.index(0, 0, QModelIndex());
1393     QModelIndex b = model.index(0, 0, a);
1394
1395     QSignalSpy expandedSpy(&view, SIGNAL(expanded(const QModelIndex&)));
1396     QSignalSpy collapsedSpy(&view, SIGNAL(collapsed(const QModelIndex&)));
1397     QVariantList args;
1398
1399     for (int y = 0; y < 2; ++y) {
1400         view.setVisible(y == 0);
1401         for (int x = 0; x < 2; ++x) {
1402             view.setItemsExpandable(x == 0);
1403
1404             // Test bad args
1405             view.expand(QModelIndex());
1406             QCOMPARE(view.isExpanded(QModelIndex()), false);
1407             view.collapse(QModelIndex());
1408             QCOMPARE(expandedSpy.count(), 0);
1409             QCOMPARE(collapsedSpy.count(), 0);
1410
1411             // expand a first level item
1412             QVERIFY(!view.isExpanded(a));
1413             view.expand(a);
1414             QVERIFY(view.isExpanded(a));
1415             QCOMPARE(expandedSpy.count(), 1);
1416             QCOMPARE(collapsedSpy.count(), 0);
1417             args = expandedSpy.takeFirst();
1418             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
1419
1420             view.expand(a);
1421             QVERIFY(view.isExpanded(a));
1422             QCOMPARE(expandedSpy.count(), 0);
1423             QCOMPARE(collapsedSpy.count(), 0);
1424
1425             // expand a second level item
1426             QVERIFY(!view.isExpanded(b));
1427             view.expand(b);
1428             QVERIFY(view.isExpanded(a));
1429             QVERIFY(view.isExpanded(b));
1430             QCOMPARE(expandedSpy.count(), 1);
1431             QCOMPARE(collapsedSpy.count(), 0);
1432             args = expandedSpy.takeFirst();
1433             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
1434
1435             view.expand(b);
1436             QVERIFY(view.isExpanded(b));
1437             QCOMPARE(expandedSpy.count(), 0);
1438             QCOMPARE(collapsedSpy.count(), 0);
1439
1440             // collapse the first level item
1441             view.collapse(a);
1442             QVERIFY(!view.isExpanded(a));
1443             QVERIFY(view.isExpanded(b));
1444             QCOMPARE(expandedSpy.count(), 0);
1445             QCOMPARE(collapsedSpy.count(), 1);
1446             args = collapsedSpy.takeFirst();
1447             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
1448
1449             view.collapse(a);
1450             QVERIFY(!view.isExpanded(a));
1451             QCOMPARE(expandedSpy.count(), 0);
1452             QCOMPARE(collapsedSpy.count(), 0);
1453
1454             // expand the first level item again
1455             view.expand(a);
1456             QVERIFY(view.isExpanded(a));
1457             QVERIFY(view.isExpanded(b));
1458             QCOMPARE(expandedSpy.count(), 1);
1459             QCOMPARE(collapsedSpy.count(), 0);
1460             args = expandedSpy.takeFirst();
1461             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
1462
1463             // collapse the second level item
1464             view.collapse(b);
1465             QVERIFY(view.isExpanded(a));
1466             QVERIFY(!view.isExpanded(b));
1467             QCOMPARE(expandedSpy.count(), 0);
1468             QCOMPARE(collapsedSpy.count(), 1);
1469             args = collapsedSpy.takeFirst();
1470             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
1471
1472             // collapse the first level item
1473             view.collapse(a);
1474             QVERIFY(!view.isExpanded(a));
1475             QVERIFY(!view.isExpanded(b));
1476             QCOMPARE(expandedSpy.count(), 0);
1477             QCOMPARE(collapsedSpy.count(), 1);
1478             args = collapsedSpy.takeFirst();
1479             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
1480
1481             // expand and remove row
1482             QPersistentModelIndex c = model.index(9, 0, b);
1483             view.expand(a);
1484             view.expand(b);
1485             model.removeLastRow(); // remove c
1486             QVERIFY(view.isExpanded(a));
1487             QVERIFY(view.isExpanded(b));
1488             QVERIFY(!view.isExpanded(c));
1489             QCOMPARE(expandedSpy.count(), 2);
1490             QCOMPARE(collapsedSpy.count(), 0);
1491             args = expandedSpy.takeFirst();
1492             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
1493             args = expandedSpy.takeFirst();
1494             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
1495
1496             view.collapse(a);
1497             view.collapse(b);
1498             QVERIFY(!view.isExpanded(a));
1499             QVERIFY(!view.isExpanded(b));
1500             QVERIFY(!view.isExpanded(c));
1501             QCOMPARE(expandedSpy.count(), 0);
1502             QCOMPARE(collapsedSpy.count(), 2);
1503             args = collapsedSpy.takeFirst();
1504             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
1505             args = collapsedSpy.takeFirst();
1506             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
1507         }
1508     }
1509 }
1510
1511 void tst_QTreeView::expandAndCollapseAll()
1512 {
1513     QtTestModel model(3, 2);
1514     model.levels = 2;
1515     QTreeView view;
1516     view.setUniformRowHeights(true);
1517     view.setModel(&model);
1518
1519     QSignalSpy expandedSpy(&view, SIGNAL(expanded(const QModelIndex&)));
1520     QSignalSpy collapsedSpy(&view, SIGNAL(collapsed(const QModelIndex&)));
1521
1522     view.expandAll();
1523     view.show();
1524
1525     QCOMPARE(collapsedSpy.count(), 0);
1526
1527     QStack<QModelIndex> parents;
1528     parents.push(QModelIndex());
1529     int count = 0;
1530     while (!parents.isEmpty()) {
1531         QModelIndex p = parents.pop();
1532         int rows = model.rowCount(p);
1533         for (int r = 0; r < rows; ++r)
1534             QVERIFY(view.isExpanded(model.index(r, 0, p)));
1535         count += rows;
1536         for (int r = 0; r < rows; ++r)
1537             parents.push(model.index(r, 0, p));
1538     }
1539 // ### why is expanded() signal not emitted?
1540 //    QCOMPARE(expandedSpy.count(), count);
1541
1542     view.collapseAll();
1543
1544     QCOMPARE(expandedSpy.count(), 0);
1545
1546     parents.push(QModelIndex());
1547     count = 0;
1548     while (!parents.isEmpty()) {
1549         QModelIndex p = parents.pop();
1550         int rows = model.rowCount(p);
1551         for (int r = 0; r < rows; ++r)
1552             QVERIFY(!view.isExpanded(model.index(r, 0, p)));
1553         count += rows;
1554         for (int r = 0; r < rows; ++r)
1555             parents.push(model.index(r, 0, p));
1556     }
1557 // ### why is collapsed() signal not emitted?
1558 //    QCOMPARE(collapsedSpy.count(), count);
1559 }
1560
1561 void tst_QTreeView::expandWithNoChildren()
1562 {
1563     QTreeView tree;
1564     QStandardItemModel model(1,1);
1565     tree.setModel(&model);
1566     tree.setAnimated(true);
1567     tree.doItemsLayout();
1568     //this test should not output warnings
1569     tree.expand(model.index(0,0));
1570 }
1571
1572
1573
1574 void tst_QTreeView::keyboardNavigation()
1575 {
1576     const int rows = 10;
1577     const int columns = 7;
1578
1579     QtTestModel model(rows, columns);
1580
1581     QTreeView view;
1582     view.setModel(&model);
1583     view.show();
1584
1585     QVector<Qt::Key> keymoves;
1586     keymoves << Qt::Key_Down << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right
1587              << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down
1588              << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right
1589              << Qt::Key_Left << Qt::Key_Up << Qt::Key_Left << Qt::Key_Left
1590              << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up << Qt::Key_Up
1591              << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up
1592              << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down;
1593
1594     int row    = 0;
1595     int column = 0;
1596     QModelIndex index = model.index(row, column, QModelIndex());
1597     view.setCurrentIndex(index);
1598     QCOMPARE(view.currentIndex(), index);
1599
1600     for (int i = 0; i < keymoves.size(); ++i) {
1601         Qt::Key key = keymoves.at(i);
1602         QTest::keyClick(&view, key);
1603
1604         switch (key) {
1605         case Qt::Key_Up:
1606             if (row > 0) {
1607                 index = index.sibling(row - 1, column);
1608                 row -= 1;
1609             } else if (index.parent() != QModelIndex()) {
1610                 index = index.parent();
1611                 row = index.row();
1612             }
1613             break;
1614         case Qt::Key_Down:
1615             if (view.isExpanded(index)) {
1616                 row = 0;
1617                 index = index.child(row, column);
1618             } else {
1619                 row = qMin(rows - 1, row + 1);
1620                 index = index.sibling(row, column);
1621             }
1622             break;
1623         case Qt::Key_Left: {
1624             QScrollBar *b = view.horizontalScrollBar();
1625             if (b->value() == b->minimum())
1626                 QVERIFY(!view.isExpanded(index));
1627             // windows style right will walk to the parent
1628             if (view.currentIndex() != index) {
1629                 QCOMPARE(view.currentIndex(), index.parent());
1630                 index = view.currentIndex();
1631                 row = index.row();
1632                 column = index.column();
1633             }
1634             break;
1635         }
1636         case Qt::Key_Right:
1637             QVERIFY(view.isExpanded(index));
1638             // windows style right will walk to the first child
1639             if (view.currentIndex() != index) {
1640                 QCOMPARE(view.currentIndex().parent(), index);
1641                 row = view.currentIndex().row();
1642                 column = view.currentIndex().column();
1643                 index = view.currentIndex();
1644             }
1645             break;
1646         default:
1647             QVERIFY(false);
1648         }
1649
1650         QCOMPARE(view.currentIndex().row(), row);
1651         QCOMPARE(view.currentIndex().column(), column);
1652         QCOMPARE(view.currentIndex(), index);
1653     }
1654 }
1655
1656 class Dmodel : public QtTestModel
1657 {
1658 public:
1659     Dmodel() : QtTestModel(10, 10){}
1660
1661     int columnCount(const QModelIndex &parent) const
1662     {
1663         if (parent.row() == 5)
1664             return 1;
1665         return QtTestModel::columnCount(parent);
1666     }
1667 };
1668
1669 void tst_QTreeView::headerSections()
1670 {
1671     Dmodel model;
1672
1673     QTreeView view;
1674     QHeaderView *header = view.header();
1675
1676     view.setModel(&model);
1677     QModelIndex index = model.index(5, 0);
1678     view.setRootIndex(index);
1679     QCOMPARE(model.columnCount(QModelIndex()), 10);
1680     QCOMPARE(model.columnCount(index), 1);
1681     QCOMPARE(header->count(), model.columnCount(index));
1682 }
1683
1684 void tst_QTreeView::moveCursor_data()
1685 {
1686     QTest::addColumn<bool>("uniformRowHeights");
1687     QTest::addColumn<bool>("scrollPerPixel");
1688     QTest::newRow("uniformRowHeights = false, scrollPerPixel = false")
1689         << false << false;
1690     QTest::newRow("uniformRowHeights = true, scrollPerPixel = false")
1691         << true << false;
1692     QTest::newRow("uniformRowHeights = false, scrollPerPixel = true")
1693         << false << true;
1694     QTest::newRow("uniformRowHeights = true, scrollPerPixel = true")
1695         << true << true;
1696 }
1697
1698 void tst_QTreeView::moveCursor()
1699 {
1700     QFETCH(bool, uniformRowHeights);
1701     QFETCH(bool, scrollPerPixel);
1702     QtTestModel model(8, 6);
1703
1704     PublicView view;
1705     view.setUniformRowHeights(uniformRowHeights);
1706     view.setModel(&model);
1707     view.setRowHidden(0, QModelIndex(), true);
1708     view.setVerticalScrollMode(scrollPerPixel ?
1709             QAbstractItemView::ScrollPerPixel :
1710             QAbstractItemView::ScrollPerItem);
1711     QVERIFY(view.isRowHidden(0, QModelIndex()));
1712     view.setColumnHidden(0, true);
1713     QVERIFY(view.isColumnHidden(0));
1714     view.show();
1715     qApp->setActiveWindow(&view);
1716
1717     //here the first visible index should be selected
1718     //because the view got the focus
1719     QModelIndex expected = model.index(1, 1, QModelIndex());
1720     QCOMPARE(view.currentIndex(), expected);
1721
1722     //then pressing down should go to the next line
1723     QModelIndex actual = view.moveCursor(PublicView::MoveDown, Qt::NoModifier);
1724     expected = model.index(2, 1, QModelIndex());
1725     QCOMPARE(actual, expected);
1726
1727     view.setRowHidden(0, QModelIndex(), false);
1728     view.setColumnHidden(0, false);
1729
1730     // PageUp was broken with uniform row heights turned on
1731     view.setCurrentIndex(model.index(1, 0));
1732     actual = view.moveCursor(PublicView::MovePageUp, Qt::NoModifier);
1733     expected = model.index(0, 0, QModelIndex());
1734     QCOMPARE(actual, expected);
1735
1736     //let's try another column
1737     view.setCurrentIndex(model.index(1, 1));
1738     view.setSelectionBehavior(QAbstractItemView::SelectItems);
1739     QTest::keyClick(view.viewport(), Qt::Key_Up);
1740     expected = model.index(0, 1, QModelIndex());
1741     QCOMPARE(view.currentIndex(), expected);
1742     QTest::keyClick(view.viewport(), Qt::Key_Down);
1743     expected = model.index(1, 1, QModelIndex());
1744     QCOMPARE(view.currentIndex(), expected);
1745     QTest::keyClick(view.viewport(), Qt::Key_Up);
1746     expected = model.index(0, 1, QModelIndex());
1747     QCOMPARE(view.currentIndex(), expected);
1748     view.setColumnHidden(0, true);
1749     QTest::keyClick(view.viewport(), Qt::Key_Left);
1750     expected = model.index(0, 1, QModelIndex()); //it shouldn't have changed
1751     QCOMPARE(view.currentIndex(), expected);
1752     view.setColumnHidden(0, false);
1753     QTest::keyClick(view.viewport(), Qt::Key_Left);
1754     expected = model.index(0, 0, QModelIndex());
1755     QCOMPARE(view.currentIndex(), expected);
1756 }
1757
1758 class TestDelegate : public QItemDelegate
1759 {
1760 public:
1761     TestDelegate(QObject *parent) : QItemDelegate(parent) {}
1762     QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(200, 50); }
1763 };
1764
1765 typedef QList<QPoint> PointList;
1766 Q_DECLARE_METATYPE(PointList)
1767
1768 void tst_QTreeView::setSelection_data()
1769 {
1770     QTest::addColumn<QRect>("selectionRect");
1771     QTest::addColumn<int>("selectionMode");
1772     QTest::addColumn<int>("selectionCommand");
1773     QTest::addColumn<PointList>("expectedItems");
1774     QTest::addColumn<int>("verticalOffset");
1775
1776     QTest::newRow("(0,0,50,20),rows") << QRect(0,0,50,20)
1777                                  << int(QAbstractItemView::SingleSelection)
1778                                  << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
1779                                  << (PointList()
1780                                     << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
1781                                     )
1782                                  << 0;
1783
1784     QTest::newRow("(0,0,50,90),rows") << QRect(0,0,50,90)
1785                                  << int(QAbstractItemView::ExtendedSelection)
1786                                  << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
1787                                  << (PointList()
1788                                     << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
1789                                     << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
1790                                     )
1791                                  << 0;
1792
1793     QTest::newRow("(50,0,0,90),rows,invalid rect") << QRect(QPoint(50, 0), QPoint(0, 90))
1794                                  << int(QAbstractItemView::ExtendedSelection)
1795                                  << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
1796                                  << (PointList()
1797                                     << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
1798                                     << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
1799                                     )
1800                                  << 0;
1801
1802     QTest::newRow("(0,-20,20,50),rows") << QRect(0,-20,20,50)
1803                                  << int(QAbstractItemView::ExtendedSelection)
1804                                  << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
1805                                  << (PointList()
1806                                     << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
1807                                     << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
1808                                     )
1809                                  << 1;
1810     QTest::newRow("(0,-50,20,90),rows") << QRect(0,-50,20,90)
1811                                  << int(QAbstractItemView::ExtendedSelection)
1812                                  << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
1813                                  << (PointList()
1814                                     << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
1815                                     << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
1816                                     )
1817                                  << 1;
1818
1819 }
1820
1821 void tst_QTreeView::setSelection()
1822 {
1823     QFETCH(QRect, selectionRect);
1824     QFETCH(int, selectionMode);
1825     QFETCH(int, selectionCommand);
1826     QFETCH(PointList, expectedItems);
1827     QFETCH(int, verticalOffset);
1828
1829     QtTestModel model(10, 5);
1830     model.levels = 1;
1831     model.setDecorationsEnabled(true);
1832     PublicView view;
1833     view.resize(400, 300);
1834     view.show();
1835     view.setRootIsDecorated(false);
1836     view.setItemDelegate(new TestDelegate(&view));
1837     view.setSelectionMode(QAbstractItemView::SelectionMode(selectionMode));
1838     view.setModel(&model);
1839     view.setUniformRowHeights(true);
1840     view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
1841     view.scrollTo(model.index(verticalOffset, 0), QAbstractItemView::PositionAtTop);
1842     view.setSelection(selectionRect, QItemSelectionModel::SelectionFlags(selectionCommand));
1843     QItemSelectionModel *selectionModel = view.selectionModel();
1844     QVERIFY(selectionModel);
1845
1846     QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
1847     QCOMPARE(selectedIndexes.count(), expectedItems.count());
1848     for (int i = 0; i < selectedIndexes.count(); ++i) {
1849         QModelIndex idx = selectedIndexes.at(i);
1850         QVERIFY(expectedItems.contains(QPoint(idx.column(), idx.row())));
1851     }
1852 }
1853
1854 void tst_QTreeView::indexAbove()
1855 {
1856     QtTestModel model(6, 7);
1857     model.levels = 2;
1858     QTreeView view;
1859
1860     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
1861     view.setModel(&model);
1862     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
1863
1864     QStack<QModelIndex> parents;
1865     parents.push(QModelIndex());
1866     while (!parents.isEmpty()) {
1867         QModelIndex p = parents.pop();
1868         if (model.canFetchMore(p))
1869             model.fetchMore(p);
1870         int rows = model.rowCount(p);
1871         for (int r = rows - 1; r > 0; --r) {
1872             QModelIndex idx = model.index(r, 0, p);
1873             QModelIndex expected = model.index(r - 1, 0, p);
1874             QCOMPARE(view.indexAbove(idx), expected);
1875         }
1876         // hide even rows
1877         for (int r = 0; r < rows; r+=2)
1878             view.setRowHidden(r, p, true);
1879         for (int r = rows - 1; r > 0; r-=2) {
1880             QModelIndex idx = model.index(r, 0, p);
1881             QModelIndex expected = model.index(r - 2, 0, p);
1882             QCOMPARE(view.indexAbove(idx), expected);
1883         }
1884 //        for (int r = 0; r < rows; ++r)
1885 //            parents.push(model.index(r, 0, p));
1886     }
1887 }
1888
1889 void tst_QTreeView::indexBelow()
1890 {
1891     QtTestModel model(2, 1);
1892
1893     QTreeView view;
1894     view.setModel(&model);
1895     view.show();
1896
1897     QModelIndex i = model.index(0, 0, view.rootIndex());
1898     QVERIFY(i.isValid());
1899     QCOMPARE(i.row(), 0);
1900
1901     i = view.indexBelow(i);
1902     QVERIFY(i.isValid());
1903     QCOMPARE(i.row(), 1);
1904     i = view.indexBelow(i);
1905     QVERIFY(!i.isValid());
1906 }
1907
1908 void tst_QTreeView::clicked()
1909 {
1910     QtTestModel model(10, 2);
1911
1912     QTreeView view;
1913     view.setModel(&model);
1914     view.show();
1915
1916     QModelIndex firstIndex = model.index(0, 0, QModelIndex());
1917     QVERIFY(firstIndex.isValid());
1918     int itemHeight = view.visualRect(firstIndex).height();
1919     int itemOffset = view.visualRect(firstIndex).width() / 2;
1920     view.resize(200, itemHeight * (model.rows + 2));
1921
1922     for (int i = 0; i < model.rowCount(); ++i) {
1923         QPoint p(itemOffset, 1 + itemHeight * i);
1924         QModelIndex index = view.indexAt(p);
1925         if (!index.isValid())
1926             continue;
1927         QSignalSpy spy(&view, SIGNAL(clicked(const QModelIndex&)));
1928         QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
1929         QTRY_COMPARE(spy.count(), 1);
1930     }
1931 }
1932
1933 void tst_QTreeView::mouseDoubleClick()
1934 {
1935     // Test double clicks outside the viewport.
1936     // (Should be a no-op and should not expand any item.)
1937
1938     QStandardItemModel model(20, 2);
1939     for (int i = 0; i < model.rowCount(); i++) {
1940         QModelIndex index = model.index(i, 0, QModelIndex());
1941         model.insertRows(0, 20, index);
1942         model.insertColumns(0,2,index);
1943         for (int i1 = 0; i1 <  model.rowCount(index); i1++) {
1944             QModelIndex index2 = model.index(i1, 0, index);
1945         }
1946     }
1947
1948     QTreeView view;
1949     view.setModel(&model);
1950
1951     // make sure the viewport height is smaller than the contents height.
1952     view.resize(200,200);
1953     view.move(0,0);
1954     view.show();
1955     QModelIndex index = model.index(0, 0, QModelIndex());
1956     view.setCurrentIndex(index);
1957
1958     view.setExpanded(model.index(0,0, QModelIndex()), true);
1959     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
1960     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
1961
1962     // Make sure all items are collapsed
1963     for (int i = 0; i < model.rowCount(QModelIndex()); i++) {
1964         view.setExpanded(model.index(i,0, QModelIndex()), false);
1965     }
1966
1967     int maximum = view.verticalScrollBar()->maximum();
1968
1969     // Doubleclick in the bottom right corner, in the unused area between the vertical and horizontal scrollbar.
1970     int vsw = view.verticalScrollBar()->width();
1971     int hsh = view.horizontalScrollBar()->height();
1972     QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, QPoint(view.width() - vsw + 1, view.height() - hsh + 1));
1973     // Should not have expanded, thus maximum() should have the same value.
1974     QCOMPARE(maximum, view.verticalScrollBar()->maximum());
1975
1976     view.setExpandsOnDoubleClick(false);
1977     QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, view.visualRect(index).center());
1978     QVERIFY(!view.isExpanded(index));
1979 }
1980
1981 void tst_QTreeView::rowsAboutToBeRemoved()
1982 {
1983     QStandardItemModel model(3, 1);
1984     for (int i = 0; i < model.rowCount(); i++) {
1985         QModelIndex index = model.index(i, 0, QModelIndex());
1986         model.setData(index, QString("%1").arg(i));
1987         model.insertRows(0, 4, index);
1988         model.insertColumns(0,1,index);
1989         for (int i1 = 0; i1 <  model.rowCount(index); i1++) {
1990             QModelIndex index2 = model.index(i1, 0, index);
1991             model.setData(index2, QString("%1%2").arg(i).arg(i1));
1992         }
1993     }
1994
1995     PublicView view;
1996     view.setModel(&model);
1997     view.show();
1998     QModelIndex index = model.index(0,0, QModelIndex());
1999     view.setCurrentIndex(index);
2000     view.setExpanded(model.index(0,0, QModelIndex()), true);
2001
2002     for (int i = 0; i < model.rowCount(QModelIndex()); i++) {
2003         view.setExpanded(model.index(i,0, QModelIndex()), true);
2004     }
2005
2006     QSignalSpy spy1(&model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
2007
2008     model.removeRows(1,1);
2009     QCOMPARE(view.state(), 0);
2010     // Should not be 5 (or any other number for that sake :)
2011     QCOMPARE(spy1.count(), 1);
2012
2013 }
2014
2015 void tst_QTreeView::headerSections_unhideSection()
2016 {
2017     QtTestModel model(10, 7);
2018
2019     QTreeView view;
2020
2021     view.setModel(&model);
2022     view.show();
2023     int size = view.header()->sectionSize(0);
2024     view.setColumnHidden(0, true);
2025
2026     // should go back to old size
2027     view.setColumnHidden(0, false);
2028     QCOMPARE(size, view.header()->sectionSize(0));
2029 }
2030
2031 void tst_QTreeView::columnAt()
2032 {
2033     QtTestModel model;
2034     model.rows = model.cols = 10;
2035     QTreeView view;
2036     view.resize(500,500);
2037     view.setModel(&model);
2038
2039     QCOMPARE(view.columnAt(0), 0);
2040     // really this is testing the header... so not much more should be needed if the header is working...
2041 }
2042
2043 void tst_QTreeView::scrollTo()
2044 {
2045 #define CHECK_VISIBLE(ROW,COL) QVERIFY(QRect(QPoint(),view.viewport()->size()).contains(\
2046                     view.visualRect(model.index((ROW),(COL),QModelIndex()))))
2047
2048     QtTestModel model;
2049     model.rows = model.cols = 100;
2050     QTreeView view;
2051     view.setUniformRowHeights(true);
2052     view.scrollTo(QModelIndex(), QTreeView::PositionAtTop);
2053     view.setModel(&model);
2054
2055     // ### check the scrollbar values an make sure it actually scrolls to the item
2056     // ### check for bot item based and pixel based scrolling
2057     // ### create a data function for this test
2058
2059     view.scrollTo(QModelIndex());
2060     view.scrollTo(model.index(0,0,QModelIndex()));
2061     view.scrollTo(model.index(0,0,QModelIndex()), QTreeView::PositionAtTop);
2062     view.scrollTo(model.index(0,0,QModelIndex()), QTreeView::PositionAtBottom);
2063
2064     //
2065
2066     view.show();
2067     view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); //some styles change that in Polish
2068
2069     view.resize(300, 200);
2070     //view.verticalScrollBar()->setValue(0);
2071
2072     view.scrollTo(model.index(0,0,QModelIndex()));
2073     CHECK_VISIBLE(0,0);
2074     QCOMPARE(view.verticalScrollBar()->value(), 0);
2075
2076     view.header()->resizeSection(0, 5); // now we only see the branches
2077     view.scrollTo(model.index(5, 0, QModelIndex()), QTreeView::PositionAtTop);
2078     QCOMPARE(view.verticalScrollBar()->value(), 5);
2079
2080     view.scrollTo(model.index(60, 60, QModelIndex()));
2081
2082     CHECK_VISIBLE(60,60);
2083     view.scrollTo(model.index(60, 30, QModelIndex()));
2084     CHECK_VISIBLE(60,30);
2085     view.scrollTo(model.index(30, 30, QModelIndex()));
2086     CHECK_VISIBLE(30,30);
2087
2088     // TODO force it to move to the left and then the right
2089 }
2090
2091 void tst_QTreeView::rowsAboutToBeRemoved_move()
2092 {
2093     QStandardItemModel model(3,1);
2094     QTreeView view;
2095     view.setModel(&model);
2096     QModelIndex indexThatWantsToLiveButWillDieDieITellYou;
2097     QModelIndex parent = model.index(2, 0 );
2098     view.expand(parent);
2099     for (int i = 0; i < 6; ++i) {
2100         model.insertRows(0, 1, parent);
2101         model.insertColumns(0, 1, parent);
2102         QModelIndex index = model.index(0, 0, parent);
2103         view.expand(index);
2104         if ( i == 3 )
2105             indexThatWantsToLiveButWillDieDieITellYou = index;
2106         model.setData(index, i);
2107         parent = index;
2108     }
2109     view.resize(600,800);
2110     view.show();
2111     view.doItemsLayout();
2112     static_cast<PublicView *>(&view)->executeDelayedItemsLayout();
2113     parent = indexThatWantsToLiveButWillDieDieITellYou.parent();
2114     QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true);
2115     QCOMPARE(parent.isValid(), true);
2116     QCOMPARE(parent.parent().isValid(), true);
2117     view.expand(parent);
2118     QCOMPARE(view.isExpanded(parent), true);
2119     QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true);
2120     model.removeRow(0, indexThatWantsToLiveButWillDieDieITellYou);
2121     QCOMPARE(view.isExpanded(parent), true);
2122     QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true);
2123 }
2124
2125 void tst_QTreeView::resizeColumnToContents()
2126 {
2127     QStandardItemModel model(50,2);
2128     for (int r = 0; r < model.rowCount(); ++r) {
2129         for (int c = 0; c < model.columnCount(); ++c) {
2130             QModelIndex idx = model.index(r, c);
2131             model.setData(idx, QString::fromAscii("%1,%2").arg(r).arg(c) );
2132             model.insertColumns(0, 2, idx);
2133             model.insertRows(0, 6, idx);
2134             for (int i = 0; i < 6; ++i) {
2135                 for (int j = 0; j < 2 ; ++j) {
2136                     model.setData(model.index(i, j, idx), QString::fromAscii("child%1%2").arg(i).arg(j));
2137                 }
2138             }
2139         }
2140     }
2141     QTreeView view;
2142     view.setModel(&model);
2143     view.show();
2144     qApp->processEvents(); //must have this, or else it will not scroll
2145     view.scrollToBottom();
2146     view.resizeColumnToContents(0);
2147     int oldColumnSize = view.header()->sectionSize(0);
2148     view.setRootIndex(model.index(0, 0));
2149     view.resizeColumnToContents(0);        //Earlier, this gave an assert
2150     QVERIFY(view.header()->sectionSize(0) > oldColumnSize);
2151 }
2152
2153 void tst_QTreeView::insertAfterSelect()
2154 {
2155     QtTestModel model;
2156     model.rows = model.cols = 10;
2157     QTreeView view;
2158     view.setModel(&model);
2159     view.show();
2160     QModelIndex firstIndex = model.index(0, 0, QModelIndex());
2161     QVERIFY(firstIndex.isValid());
2162     int itemOffset = view.visualRect(firstIndex).width() / 2;
2163     QPoint p(itemOffset, 1);
2164     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
2165     QVERIFY(view.selectionModel()->isSelected(firstIndex));
2166     model.insertNewRow();
2167     QVERIFY(view.selectionModel()->isSelected(firstIndex)); // Should still be selected
2168 }
2169
2170 void tst_QTreeView::removeAfterSelect()
2171 {
2172     QtTestModel model;
2173     model.rows = model.cols = 10;
2174     QTreeView view;
2175     view.setModel(&model);
2176     view.show();
2177     QModelIndex firstIndex = model.index(0, 0, QModelIndex());
2178     QVERIFY(firstIndex.isValid());
2179     int itemOffset = view.visualRect(firstIndex).width() / 2;
2180     QPoint p(itemOffset, 1);
2181     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
2182     QVERIFY(view.selectionModel()->isSelected(firstIndex));
2183     model.removeLastRow();
2184     QVERIFY(view.selectionModel()->isSelected(firstIndex)); // Should still be selected
2185 }
2186
2187 void tst_QTreeView::hiddenItems()
2188 {
2189     QtTestModel model;
2190     model.rows = model.cols = 10;
2191     QTreeView view;
2192     view.setModel(&model);
2193     view.show();
2194
2195     QModelIndex firstIndex = model.index(1, 0, QModelIndex());
2196     QVERIFY(firstIndex.isValid());
2197     if (model.canFetchMore(firstIndex))
2198         model.fetchMore(firstIndex);
2199     for (int i=0; i < model.rowCount(firstIndex); i++)
2200         view.setRowHidden(i , firstIndex, true );
2201
2202     int itemOffset = view.visualRect(firstIndex).width() / 2;
2203     int itemHeight = view.visualRect(firstIndex).height();
2204     QPoint p(itemOffset, itemHeight + 1);
2205     view.setExpanded(firstIndex, false);
2206     QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
2207     QCOMPARE(view.isExpanded(firstIndex), false);
2208
2209     p.setX( 5 );
2210     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
2211     QCOMPARE(view.isExpanded(firstIndex), false);
2212 }
2213
2214 void tst_QTreeView::spanningItems()
2215 {
2216     QtTestModel model;
2217     model.rows = model.cols = 10;
2218     PublicView view;
2219     view.setModel(&model);
2220     view.show();
2221
2222     int itemWidth = view.header()->sectionSize(0);
2223     int itemHeight = view.visualRect(model.index(0, 0, QModelIndex())).height();
2224
2225     // every second row is spanning
2226     for (int i = 1; i < model.rowCount(QModelIndex()); i += 2)
2227         view.setFirstColumnSpanned(i , QModelIndex(), true);
2228
2229     // non-spanning item
2230     QPoint p(itemWidth / 2, itemHeight / 2); // column 0, row 0
2231     view.setCurrentIndex(QModelIndex());
2232     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
2233     QCOMPARE(view.currentIndex(), model.index(0, 0, QModelIndex()));
2234     QCOMPARE(view.header()->sectionSize(0) - view.indentation(),
2235              view.visualRect(model.index(0, 0, QModelIndex())).width());
2236
2237     // spanning item
2238     p.setX(itemWidth + (itemWidth / 2)); // column 1
2239     p.setY(itemHeight + (itemHeight / 2)); // row 1
2240     QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
2241     QCOMPARE(view.currentIndex(), model.index(1, 0, QModelIndex()));
2242     QCOMPARE(view.header()->length() - view.indentation(),
2243              view.visualRect(model.index(1, 0, QModelIndex())).width());
2244
2245     // size hint
2246     // every second row is un-spanned
2247     QStyleOptionViewItem option = view.viewOptions();
2248     int w = view.header()->sectionSizeHint(0);
2249     for (int i = 0; i < model.rowCount(QModelIndex()); ++i) {
2250         if (!view.isFirstColumnSpanned(i, QModelIndex())) {
2251             QModelIndex index = model.index(i, 0, QModelIndex());
2252             w = qMax(w, view.itemDelegate(index)->sizeHint(option, index).width() + view.indentation());
2253         }
2254     }
2255     QCOMPARE(view.sizeHintForColumn(0), w);
2256 }
2257
2258 void tst_QTreeView::selectionOrderTest()
2259 {
2260     QVERIFY(((QItemSelectionModel*)sender())->currentIndex().row() != -1);
2261 }
2262
2263 void tst_QTreeView::selection()
2264 {
2265     QTreeView treeView;
2266     QStandardItemModel m(10, 2);
2267     for (int i = 0;i < 10; ++i)
2268         m.setData(m.index(i, 0), i);
2269     treeView.setModel(&m);
2270
2271     treeView.setSelectionBehavior(QAbstractItemView::SelectRows);
2272     treeView.setSelectionMode(QAbstractItemView::ExtendedSelection);
2273
2274     connect(treeView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
2275             this, SLOT(selectionOrderTest()));
2276
2277     treeView.show();
2278
2279     QTest::mousePress(treeView.viewport(), Qt::LeftButton, 0, treeView.visualRect(m.index(1, 0)).center());
2280     QTest::keyPress(treeView.viewport(), Qt::Key_Down);
2281 }
2282
2283 //From task 151686 QTreeView ExtendedSelection selects hidden rows
2284 void tst_QTreeView::selectionWithHiddenItems()
2285 {
2286     QStandardItemModel model;
2287     for (int i = 0; i < model.rowCount(); ++i)
2288         model.setData(model.index(i,0), QString("row %1").arg(i));
2289
2290     QStandardItem item0("row 0");
2291     QStandardItem item1("row 1");
2292     QStandardItem item2("row 2");
2293     QStandardItem item3("row 3");
2294     model.appendColumn( QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3);
2295
2296     QStandardItem child("child");
2297     item1.appendRow( &child);
2298
2299     QTreeView view;
2300     view.setModel(&model);
2301     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
2302     view.show();
2303     qApp->processEvents();
2304
2305     //child should not be selected as it is hidden (its parent is not expanded)
2306     view.selectAll();
2307     QCOMPARE(view.selectionModel()->selection().count(), 1); //one range
2308     QCOMPARE(view.selectionModel()->selectedRows().count(), 4);
2309     view.expandAll();
2310     QVERIFY(view.isExpanded(item1.index()));
2311     QCOMPARE(view.selectionModel()->selection().count(), 1);
2312     QCOMPARE(view.selectionModel()->selectedRows().count(), 4);
2313     QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&child)));
2314     view.clearSelection();
2315     QVERIFY(view.isExpanded(item1.index()));
2316
2317     //child should be selected as it is visible (its parent is expanded)
2318     view.selectAll();
2319     QCOMPARE(view.selectionModel()->selection().count(), 2);
2320     QCOMPARE(view.selectionModel()->selectedRows().count(), 5); //everything is selected
2321     view.clearSelection();
2322
2323     //we hide the node with a child (there should then be 3 items selected in 2 ranges)
2324     view.setRowHidden(1, QModelIndex(), true);
2325     QVERIFY(view.isExpanded(item1.index()));
2326     qApp->processEvents();
2327     view.selectAll();
2328     QCOMPARE(view.selectionModel()->selection().count(), 2);
2329     QCOMPARE(view.selectionModel()->selectedRows().count(), 3);
2330     QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&item1)));
2331     QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&child)));
2332
2333     view.setRowHidden(1, QModelIndex(), false);
2334     QVERIFY(view.isExpanded(item1.index()));
2335     view.clearSelection();
2336
2337     //we hide a node without children (there should then be 4 items selected in 3 ranges)
2338     view.setRowHidden(2, QModelIndex(), true);
2339     qApp->processEvents();
2340     QVERIFY(view.isExpanded(item1.index()));
2341     view.selectAll();
2342     QVERIFY(view.isExpanded(item1.index()));
2343     QCOMPARE(view.selectionModel()->selection().count(), 3);
2344     QCOMPARE(view.selectionModel()->selectedRows().count(), 4);
2345     QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&item2)));
2346     view.setRowHidden(2, QModelIndex(), false);
2347     QVERIFY(view.isExpanded(item1.index()));
2348     view.clearSelection();
2349 }
2350
2351 void tst_QTreeView::selectAll()
2352 {
2353     QStandardItemModel model(4,4);
2354     PublicView view2;
2355     view2.setModel(&model);
2356     view2.setSelectionMode(QAbstractItemView::ExtendedSelection);
2357     view2.selectAll();  // Should work with an empty model
2358     //everything should be selected since we are in ExtendedSelection mode
2359     QCOMPARE(view2.selectedIndexes().count(), model.rowCount() * model.columnCount());
2360
2361     for (int i = 0; i < model.rowCount(); ++i)
2362         model.setData(model.index(i,0), QString("row %1").arg(i));
2363     PublicView view;
2364     view.setModel(&model);
2365     int selectedCount = view.selectedIndexes().count();
2366     view.selectAll();
2367     QCOMPARE(view.selectedIndexes().count(), selectedCount);
2368 }
2369
2370 void tst_QTreeView::extendedSelection_data()
2371 {
2372     QTest::addColumn<QPoint>("mousePressPos");
2373     QTest::addColumn<int>("selectedCount");
2374
2375     QTest::newRow("select") << QPoint(10, 10) << 2;
2376     QTest::newRow("unselect") << QPoint(10, 150) << 0;
2377 }
2378
2379 void tst_QTreeView::extendedSelection()
2380 {
2381     QFETCH(QPoint, mousePressPos);
2382     QFETCH(int, selectedCount);
2383
2384     QStandardItemModel model(5, 2);
2385     QWidget topLevel;
2386     QTreeView view(&topLevel);
2387     view.resize(qMax(mousePressPos.x() * 2, 200), qMax(mousePressPos.y() * 2, 200));
2388     view.setModel(&model);
2389
2390     //ensure that mousePressPos is below the last row if we want to unselect
2391     if (!selectedCount) {
2392         int minimumHeight = model.rowCount() * view.visualRect(model.index(0,0)).size().height();
2393         if (mousePressPos.y() < minimumHeight)
2394             mousePressPos.setY(minimumHeight + 10);
2395     }
2396
2397     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
2398     topLevel.show();
2399     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, mousePressPos);
2400     QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedCount);
2401 }
2402
2403 void tst_QTreeView::rowSizeHint()
2404 {
2405     //tests whether the correct visible columns are taken into account when
2406     //calculating the height of a line
2407     QStandardItemModel model(1,3);
2408     model.setData( model.index(0,0), QSize(20,40), Qt::SizeHintRole);
2409     model.setData( model.index(0,1), QSize(20,10), Qt::SizeHintRole);
2410     model.setData( model.index(0,2), QSize(20,10), Qt::SizeHintRole);
2411     QTreeView view;
2412     view.setModel(&model);
2413
2414     view.header()->moveSection(1, 0); //the 2nd column goes to the 1st place
2415
2416     view.show();
2417
2418     //it must be 40 since the tallest item that defines the height of a line
2419     QCOMPARE( view.visualRect(model.index(0,0)).height(), 40);
2420     QCOMPARE( view.visualRect(model.index(0,1)).height(), 40);
2421     QCOMPARE( view.visualRect(model.index(0,2)).height(), 40);
2422 }
2423
2424
2425 //From task 155449 (QTreeWidget has a large width for the first section when sorting
2426 //is turned on before items are added)
2427 void tst_QTreeView::setSortingEnabled()
2428 {
2429     //1st the treeview is a top-level
2430     {
2431         QTreeView view;
2432         QStandardItemModel model(1,1);
2433         view.setModel(&model);
2434         const int size = view.header()->sectionSize(0);
2435         view.setSortingEnabled(true);
2436         model.setColumnCount(3);
2437         //we test that changing the column count doesn't change the 1st column size
2438         QCOMPARE(view.header()->sectionSize(0), size);
2439     }
2440
2441     //then it is no more a top-level
2442     {
2443         QMainWindow win;
2444         QTreeView view;
2445         QStandardItemModel model(1,1);
2446         view.setModel(&model);
2447         win.setCentralWidget(&view);
2448         const int size = view.header()->sectionSize(0);
2449         view.setSortingEnabled(true);
2450         model.setColumnCount(3);
2451         //we test that changing the column count doesn't change the 1st column size
2452         QCOMPARE(view.header()->sectionSize(0), size);
2453     }
2454 }
2455
2456 void tst_QTreeView::headerHidden()
2457 {
2458     QTreeView view;
2459     QStandardItemModel model;
2460     view.setModel(&model);
2461     QCOMPARE(view.isHeaderHidden(), false);
2462     QCOMPARE(view.header()->isHidden(), false);
2463     view.setHeaderHidden(true);
2464     QCOMPARE(view.isHeaderHidden(), true);
2465     QCOMPARE(view.header()->isHidden(), true);
2466 }
2467
2468 // From Task 145199 (crash when column 0 having at least one expanded item is removed and then
2469 // inserted). The test passes simply if it doesn't crash, hence there are no calls
2470 // to QCOMPARE() or QVERIFY().
2471 void tst_QTreeView::removeAndInsertExpandedCol0()
2472 {
2473     QTreeView view;
2474     QStandardItemModel model;
2475     view.setModel(&model);
2476
2477     model.setColumnCount(1);
2478
2479     QStandardItem *item0 = new QStandardItem(QString("item 0"));
2480     model.invisibleRootItem()->appendRow(item0);
2481     view.expand(item0->index());
2482     QStandardItem *item1 = new QStandardItem(QString("item 1"));
2483     item0->appendRow(item1);
2484
2485     model.removeColumns(0, 1);
2486     model.insertColumns(0, 1);
2487
2488     view.show();
2489     qApp->processEvents();
2490 }
2491
2492 void tst_QTreeView::disabledButCheckable()
2493 {
2494     QTreeView view;
2495     QStandardItemModel model;
2496     QStandardItem *item;
2497     item = new QStandardItem(QLatin1String("Row 1 Item"));
2498     model.insertRow(0, item);
2499
2500     item = new QStandardItem(QLatin1String("Row 2 Item"));
2501     item->setCheckable(true);
2502     item->setEnabled(false);
2503     model.insertRow(1, item);
2504
2505     view.setModel(&model);
2506     view.setCurrentIndex(model.index(1,0));
2507     QCOMPARE(item->checkState(), Qt::Unchecked);
2508     view.show();
2509
2510     QTest::keyClick(&view, Qt::Key_Space);
2511     QCOMPARE(item->checkState(), Qt::Unchecked);
2512 }
2513
2514 void tst_QTreeView::sortByColumn_data()
2515 {
2516     QTest::addColumn<bool>("sortingEnabled");
2517     QTest::newRow("sorting enabled") << true;
2518     QTest::newRow("sorting disabled") << false;
2519 }
2520
2521 // Checks sorting and that sortByColumn also sets the sortIndicator
2522 void tst_QTreeView::sortByColumn()
2523 {
2524     QFETCH(bool, sortingEnabled);
2525     QTreeView view;
2526     QStandardItemModel model(4,2);
2527     model.setItem(0,0,new QStandardItem("b"));
2528     model.setItem(1,0,new QStandardItem("d"));
2529     model.setItem(2,0,new QStandardItem("c"));
2530     model.setItem(3,0,new QStandardItem("a"));
2531     model.setItem(0,1,new QStandardItem("e"));
2532     model.setItem(1,1,new QStandardItem("g"));
2533     model.setItem(2,1,new QStandardItem("h"));
2534     model.setItem(3,1,new QStandardItem("f"));
2535
2536     view.setSortingEnabled(sortingEnabled);
2537     view.setModel(&model);
2538     view.sortByColumn(1);
2539     QCOMPARE(view.header()->sortIndicatorSection(), 1);
2540     QCOMPARE(view.model()->data(view.model()->index(0,1)).toString(), QString::fromLatin1("h"));
2541     QCOMPARE(view.model()->data(view.model()->index(1,1)).toString(), QString::fromLatin1("g"));
2542     view.sortByColumn(0, Qt::AscendingOrder);
2543     QCOMPARE(view.header()->sortIndicatorSection(), 0);
2544     QCOMPARE(view.model()->data(view.model()->index(0,0)).toString(), QString::fromLatin1("a"));
2545     QCOMPARE(view.model()->data(view.model()->index(1,0)).toString(), QString::fromLatin1("b"));
2546 }
2547
2548 /*
2549     This is a model that every time kill() is called it will completely change
2550     all of its nodes for new nodes.  It then qFatal's if you later use a dead node.
2551  */
2552 class EvilModel: public QAbstractItemModel
2553 {
2554
2555 public:
2556     class Node {
2557     public:
2558         Node(Node *p = 0, int level = 0) : parent(p), isDead(false) {
2559             populate(level);
2560         }
2561         ~Node()
2562         {
2563             qDeleteAll(children.begin(), children.end());
2564             qDeleteAll(deadChildren.begin(), deadChildren.end());
2565         }
2566
2567         void populate(int level = 0) {
2568             if (level < 4)
2569                 for (int i = 0; i < 5; ++i)
2570                     children.append(new Node(this, level + 1));
2571         }
2572         void kill() {
2573             for (int i = children.count() -1; i >= 0; --i) {
2574                 children.at(i)->kill();
2575                 if (parent == 0) {
2576                     deadChildren.append(children.at(i));
2577                     children.removeAt(i);
2578                 }
2579             }
2580             if (parent == 0) {
2581                 if (!children.isEmpty())
2582                     qFatal("%s: children should be empty when parent is null", Q_FUNC_INFO);
2583                 populate();
2584             } else {
2585                 isDead = true;
2586             }
2587         }
2588
2589         QList<Node*> children;
2590         QList<Node*> deadChildren;
2591         Node *parent;
2592         bool isDead;
2593     };
2594
2595     Node *root;
2596
2597     EvilModel(QObject *parent = 0): QAbstractItemModel(parent), root(new Node)
2598     {
2599     }
2600     ~EvilModel()
2601     {
2602         delete root;
2603     }
2604
2605     void change()
2606     {
2607         emit layoutAboutToBeChanged();
2608         QModelIndexList oldList = persistentIndexList();
2609         QList<QStack<int> > oldListPath;
2610         for (int i = 0; i < oldList.count(); ++i) {
2611             QModelIndex idx = oldList.at(i);
2612             QStack<int> path;
2613             while (idx.isValid()) {
2614                 path.push(idx.row());
2615                 idx = idx.parent();
2616             }
2617             oldListPath.append(path);
2618         }
2619         root->kill();
2620
2621         QModelIndexList newList;
2622         for (int i = 0; i < oldListPath.count(); ++i) {
2623             QStack<int> path = oldListPath[i];
2624             QModelIndex idx;
2625             while(!path.isEmpty()) {
2626                 idx = index(path.pop(), 0, idx);
2627             }
2628             newList.append(idx);
2629         }
2630
2631         changePersistentIndexList(oldList, newList);
2632         emit layoutChanged();
2633     }
2634
2635     int rowCount(const QModelIndex& parent = QModelIndex()) const {
2636         Node *parentNode = root;
2637         if (parent.isValid()) {
2638             parentNode = static_cast<Node*>(parent.internalPointer());
2639             if (parentNode->isDead)
2640                 qFatal("%s: parentNode is dead!", Q_FUNC_INFO);
2641         }
2642         return parentNode->children.count();
2643     }
2644     int columnCount(const QModelIndex& parent = QModelIndex()) const {
2645         if (parent.column() > 0)
2646             return 0;
2647         return 1;
2648     }
2649
2650     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
2651     {
2652         Node *grandparentNode = static_cast<Node*>(parent.internalPointer());
2653         Node *parentNode = root;
2654         if (parent.isValid()) {
2655             if (grandparentNode->isDead)
2656                 qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
2657             parentNode = grandparentNode->children[parent.row()];
2658             if (parentNode->isDead)
2659                 qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
2660         }
2661         return createIndex(row, column, parentNode);
2662     }
2663
2664     QModelIndex parent(const QModelIndex &index) const
2665     {
2666         Node *parent = static_cast<Node*>(index.internalPointer());
2667         Node *grandparent = parent->parent;
2668         if (!grandparent)
2669             return QModelIndex();
2670         return createIndex(grandparent->children.indexOf(parent), 0, grandparent);
2671     }
2672
2673     QVariant data(const QModelIndex &idx, int role) const
2674     {
2675         if (idx.isValid() && role == Qt::DisplayRole) {
2676             Node *parentNode = root;
2677             if (idx.isValid()) {
2678                 parentNode = static_cast<Node*>(idx.internalPointer());
2679                 if (parentNode->isDead)
2680                     qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
2681             }
2682             return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column())
2683                 .arg(parentNode->isDead ? "dead" : "alive");
2684         }
2685         return QVariant();
2686     }
2687 };
2688
2689 void tst_QTreeView::evilModel_data()
2690 {
2691     QTest::addColumn<bool>("visible");
2692     QTest::newRow("visible") << false;
2693 }
2694
2695 void tst_QTreeView::evilModel()
2696 {
2697     QFETCH(bool, visible);
2698     // init
2699     PublicView view;
2700     EvilModel model;
2701     view.setModel(&model);
2702     view.setVisible(visible);
2703     QPersistentModelIndex firstLevel = model.index(0, 0);
2704     QPersistentModelIndex secondLevel = model.index(1, 0, firstLevel);
2705     QPersistentModelIndex thirdLevel = model.index(2, 0, secondLevel);
2706     view.setExpanded(firstLevel, true);
2707     view.setExpanded(secondLevel, true);
2708     view.setExpanded(thirdLevel, true);
2709     model.change();
2710
2711     // tests
2712     view.setRowHidden(0, firstLevel, true);
2713     model.change();
2714
2715     return;
2716     view.setFirstColumnSpanned(1, QModelIndex(), true);
2717     model.change();
2718
2719     view.expand(secondLevel);
2720     model.change();
2721
2722     view.collapse(secondLevel);
2723     model.change();
2724
2725     view.isExpanded(secondLevel);
2726     view.setCurrentIndex(firstLevel);
2727     model.change();
2728
2729     view.keyboardSearch("foo");
2730     model.change();
2731
2732     view.visualRect(secondLevel);
2733     model.change();
2734
2735     view.scrollTo(thirdLevel);
2736     model.change();
2737
2738     view.repaint();
2739     model.change();
2740
2741     QTest::mouseDClick(view.viewport(), Qt::LeftButton);
2742     model.change();
2743
2744     view.indexAt(QPoint(10, 10));
2745     model.change();
2746
2747     view.indexAbove(model.index(2, 0));
2748     model.change();
2749
2750     view.indexBelow(model.index(1, 0));
2751     model.change();
2752
2753     QRect rect(0, 0, 10, 10);
2754     view.setSelection(rect, QItemSelectionModel::Select);
2755     model.change();
2756
2757     view.moveCursor(PublicView::MoveDown, Qt::NoModifier);
2758     model.change();
2759
2760     view.resizeColumnToContents(1);
2761     model.change();
2762
2763     view.QAbstractItemView::sizeHintForColumn(1);
2764     model.change();
2765
2766     view.rowHeight(secondLevel);
2767     model.change();
2768
2769     view.setRootIsDecorated(true);
2770     model.change();
2771
2772     view.setItemsExpandable(false);
2773     model.change();
2774
2775     view.columnViewportPosition(0);
2776     model.change();
2777
2778     view.columnWidth(0);
2779     model.change();
2780
2781     view.setColumnWidth(0, 30);
2782     model.change();
2783
2784     view.columnAt(15);
2785     model.change();
2786
2787     view.isColumnHidden(1);
2788     model.change();
2789
2790     view.setColumnHidden(2, true);
2791     model.change();
2792
2793     view.isHeaderHidden();
2794     model.change();
2795
2796     view.setHeaderHidden(true);
2797     model.change();
2798
2799     view.isRowHidden(2, secondLevel);
2800     model.change();
2801
2802     view.setRowHidden(3, secondLevel, true);
2803     model.change();
2804
2805     view.isFirstColumnSpanned(3, thirdLevel);
2806     model.change();
2807
2808     view.setSortingEnabled(true);
2809     model.change();
2810
2811     view.isSortingEnabled();
2812     model.change();
2813
2814     view.setAnimated(true);
2815     model.change();
2816
2817     view.isAnimated();
2818     model.change();
2819
2820     view.setAllColumnsShowFocus(true);
2821     model.change();
2822
2823     view.allColumnsShowFocus();
2824     model.change();
2825
2826     view.doItemsLayout();
2827     model.change();
2828
2829     view.reset();
2830     model.change();
2831
2832     view.sortByColumn(1, Qt::AscendingOrder);
2833     model.change();
2834
2835     view.dataChanged(secondLevel, secondLevel);
2836     model.change();
2837
2838     view.hideColumn(1);
2839     model.change();
2840
2841     view.showColumn(1);
2842     model.change();
2843
2844     view.resizeColumnToContents(1);
2845     model.change();
2846
2847     view.sortByColumn(1);
2848     model.change();
2849
2850     view.selectAll();
2851     model.change();
2852
2853     view.expandAll();
2854     model.change();
2855
2856     view.collapseAll();
2857     model.change();
2858
2859     view.expandToDepth(3);
2860     model.change();
2861
2862     view.setRootIndex(secondLevel);
2863 }
2864
2865 void tst_QTreeView::indexRowSizeHint()
2866 {
2867     QStandardItemModel model(10, 1);
2868     PublicView view;
2869
2870     view.setModel(&model);
2871
2872     QModelIndex index = model.index(5, 0);
2873     QPushButton *w = new QPushButton("Test");
2874     view.setIndexWidget(index, w);
2875
2876     view.show();
2877
2878     QCOMPARE(view.indexRowSizeHint(index), w->sizeHint().height());
2879 }
2880
2881 void tst_QTreeView::filterProxyModelCrash()
2882 {
2883     QStandardItemModel model;
2884     QList<QStandardItem *> items;
2885     for (int i = 0; i < 100; i++)
2886         items << new QStandardItem(QString::fromLatin1("item %1").arg(i));
2887     model.appendColumn(items);
2888
2889     QSortFilterProxyModel proxy;
2890     proxy.setSourceModel(&model);
2891
2892     QTreeView view;
2893     view.setModel(&proxy);
2894     view.show();
2895     QTest::qWait(30);
2896     proxy.invalidate();
2897     view.verticalScrollBar()->setValue(15);
2898     QTest::qWait(20);
2899
2900     proxy.invalidate();
2901     view.repaint(); //used to crash
2902 }
2903
2904 void tst_QTreeView::styleOptionViewItem()
2905 {
2906     class MyDelegate : public QStyledItemDelegate
2907     {
2908         static QString posToString(QStyleOptionViewItemV4::ViewItemPosition pos) {
2909             static const char* s_pos[] = { "Invalid", "Beginning", "Middle", "End", "OnlyOne" };
2910             return s_pos[pos];
2911         }
2912         public:
2913             void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
2914             {
2915                 QVERIFY(qstyleoption_cast<const QStyleOptionViewItemV4 *>(&option));
2916                 QStyleOptionViewItemV4 opt(option);
2917                 initStyleOption(&opt, index);
2918
2919                 QVERIFY(!opt.text.isEmpty());
2920                 QCOMPARE(opt.index, index);
2921                 //qDebug() << index << opt.text;
2922
2923                 if (allCollapsed)
2924                     QCOMPARE(!(opt.features & QStyleOptionViewItemV2::Alternate), !(index.row() % 2));
2925                 QCOMPARE(!(opt.features & QStyleOptionViewItemV2::HasCheckIndicator), !opt.text.contains("Checkable"));
2926
2927                 if (opt.text.contains("Beginning"))
2928                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::Beginning));
2929
2930                 if (opt.text.contains("Middle"))
2931                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::Middle));
2932
2933                 if (opt.text.contains("End"))
2934                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::End));
2935
2936                 if (opt.text.contains("OnlyOne"))
2937                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::OnlyOne));
2938
2939                 if (opt.text.contains("Checked"))
2940                     QCOMPARE(opt.checkState, Qt::Checked);
2941                 else
2942                     QCOMPARE(opt.checkState, Qt::Unchecked);
2943
2944                 QCOMPARE(!(opt.state & QStyle::State_Children) , !opt.text.contains("HasChildren"));
2945                 QCOMPARE(!!(opt.state & QStyle::State_Sibling) , !opt.text.contains("Last"));
2946
2947                 QVERIFY(!opt.text.contains("Assert"));
2948
2949                 QStyledItemDelegate::paint(painter, option, index);
2950                 count++;
2951             }
2952             mutable int count;
2953             bool allCollapsed;
2954     };
2955
2956     PublicView view;
2957     QStandardItemModel model;
2958     view.setModel(&model);
2959     MyDelegate delegate;
2960     view.setItemDelegate(&delegate);
2961     model.appendRow(QList<QStandardItem*>()
2962         << new QStandardItem("Beginning") << new QStandardItem("Hidden") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
2963     QStandardItem *par1 = new QStandardItem("Beginning HasChildren");
2964     model.appendRow(QList<QStandardItem*>()
2965         << par1 << new QStandardItem("Hidden") << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") );
2966     model.appendRow(QList<QStandardItem*>()
2967         << new QStandardItem("OnlyOne") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Assert") );
2968     QStandardItem *checkable = new QStandardItem("Checkable");
2969     checkable->setCheckable(true);
2970     QStandardItem *checked = new QStandardItem("Checkable Checked");
2971     checked->setCheckable(true);
2972     checked->setCheckState(Qt::Checked);
2973     model.appendRow(QList<QStandardItem*>()
2974         << new QStandardItem("Beginning") << new QStandardItem("Hidden") << checkable << checked << new QStandardItem("End") );
2975     model.appendRow(QList<QStandardItem*>()
2976         << new QStandardItem("Beginning Last") << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
2977
2978     par1->appendRow(QList<QStandardItem*>()
2979         << new QStandardItem("Beginning") << new QStandardItem("Hidden") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
2980     QStandardItem *par2 = new QStandardItem("Beginning HasChildren");
2981     par1->appendRow(QList<QStandardItem*>()
2982         << par2 << new QStandardItem("Hidden") << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") );
2983     par2->appendRow(QList<QStandardItem*>()
2984         << new QStandardItem("Beginning Last") << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
2985
2986     QStandardItem *par3 = new QStandardItem("Beginning Last");
2987     par1->appendRow(QList<QStandardItem*>()
2988         << par3 << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
2989     par3->appendRow(QList<QStandardItem*>()
2990         << new QStandardItem("Assert") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") );
2991     view.setRowHidden(0, par3->index(), true);
2992     par1->appendRow(QList<QStandardItem*>()
2993         << new QStandardItem("Assert") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") );
2994     view.setRowHidden(3, par1->index(), true);
2995
2996     view.setColumnHidden(1, true);
2997     const int visibleColumns = 4;
2998     const int modelColumns = 5;
2999
3000     view.header()->swapSections(2, 3);
3001     view.setFirstColumnSpanned(2, QModelIndex(), true);
3002     view.setAlternatingRowColors(true);
3003
3004     delegate.count = 0;
3005     delegate.allCollapsed = true;
3006     view.showMaximized();
3007     QApplication::processEvents();
3008     QTRY_VERIFY(delegate.count >= 13);
3009     delegate.count = 0;
3010     delegate.allCollapsed = false;
3011     view.expandAll();
3012     QApplication::processEvents();
3013     QTRY_VERIFY(delegate.count >= 13);
3014     delegate.count = 0;
3015     view.collapse(par2->index());
3016     QApplication::processEvents();
3017     QTRY_VERIFY(delegate.count >= 4);
3018
3019     // test that the rendering of drag pixmap sets the correct options too (QTBUG-15834)
3020     delegate.count = 0;
3021     QItemSelection sel(model.index(0,0), model.index(0,modelColumns-1));
3022     QRect rect;
3023     view.aiv_priv()->renderToPixmap(sel.indexes(), &rect);
3024     QTRY_VERIFY(delegate.count == visibleColumns);
3025
3026     //test dynamic models
3027     {
3028         delegate.count = 0;
3029         QStandardItemModel model2;
3030         QStandardItem *item0 = new QStandardItem("OnlyOne Last");
3031         model2.appendRow(QList<QStandardItem*>() << item0);
3032         view.setModel(&model2);
3033         QApplication::processEvents();
3034         QTRY_VERIFY(delegate.count >= 1);
3035         QApplication::processEvents();
3036
3037         QStandardItem *item00 = new QStandardItem("OnlyOne Last");
3038         item0->appendRow(QList<QStandardItem*>() << item00);
3039         item0->setText("OnlyOne Last HasChildren");
3040         QApplication::processEvents();
3041         delegate.count = 0;
3042         view.expandAll();
3043         QApplication::processEvents();
3044         QTRY_VERIFY(delegate.count >= 2);
3045         QApplication::processEvents();
3046
3047         QStandardItem *item1 = new QStandardItem("OnlyOne Last");
3048         delegate.count = 0;
3049         item0->setText("OnlyOne HasChildren");
3050         model2.appendRow(QList<QStandardItem*>() << item1);
3051         QApplication::processEvents();
3052         QTRY_VERIFY(delegate.count >= 3);
3053         QApplication::processEvents();
3054
3055         QStandardItem *item01 = new QStandardItem("OnlyOne Last");
3056         delegate.count = 0;
3057         item00->setText("OnlyOne");
3058         item0->appendRow(QList<QStandardItem*>() << item01);
3059         QApplication::processEvents();
3060         QTRY_VERIFY(delegate.count >= 4);
3061         QApplication::processEvents();
3062
3063         QStandardItem *item000 = new QStandardItem("OnlyOne Last");
3064         delegate.count = 0;
3065         item00->setText("OnlyOne HasChildren");
3066         item00->appendRow(QList<QStandardItem*>() << item000);
3067         QApplication::processEvents();
3068         QTRY_VERIFY(delegate.count >= 5);
3069         QApplication::processEvents();
3070
3071         delegate.count = 0;
3072         item0->removeRow(0);
3073         QApplication::processEvents();
3074         QTRY_VERIFY(delegate.count >= 3);
3075         QApplication::processEvents();
3076
3077         item00 = new QStandardItem("OnlyOne");
3078         item0->insertRow(0, QList<QStandardItem*>() << item00);
3079         QApplication::processEvents();
3080         delegate.count = 0;
3081         view.expandAll();
3082         QApplication::processEvents();
3083         QTRY_VERIFY(delegate.count >= 4);
3084         QApplication::processEvents();
3085
3086         delegate.count = 0;
3087         item0->removeRow(1);
3088         item00->setText("OnlyOne Last");
3089         QApplication::processEvents();
3090         QTRY_VERIFY(delegate.count >= 3);
3091         QApplication::processEvents();
3092
3093         delegate.count = 0;
3094         item0->removeRow(0);
3095         item0->setText("OnlyOne");
3096         QApplication::processEvents();
3097         QTRY_VERIFY(delegate.count >= 2);
3098         QApplication::processEvents();
3099
3100         //with hidden items
3101         item0->setText("OnlyOne HasChildren");
3102         item00 = new QStandardItem("OnlyOne");
3103         item0->appendRow(QList<QStandardItem*>() << item00);
3104         item01 = new QStandardItem("Assert");
3105         item0->appendRow(QList<QStandardItem*>() << item01);
3106         view.setRowHidden(1, item0->index(), true);
3107         view.expandAll();
3108         QStandardItem *item02 = new QStandardItem("OnlyOne Last");
3109         item0->appendRow(QList<QStandardItem*>() << item02);
3110         delegate.count = 0;
3111         QApplication::processEvents();
3112         QTRY_VERIFY(delegate.count >= 4);
3113         QApplication::processEvents();
3114
3115         item0->removeRow(2);
3116         item00->setText("OnlyOne Last");
3117         delegate.count = 0;
3118         QApplication::processEvents();
3119         QTRY_VERIFY(delegate.count >= 3);
3120         QApplication::processEvents();
3121
3122         item00->setText("OnlyOne");
3123         item0->insertRow(2, new QStandardItem("OnlyOne Last"));
3124         view.collapse(item0->index());
3125         item0->removeRow(0);
3126         delegate.count = 0;
3127         QTRY_VERIFY(delegate.count >= 2);
3128         QApplication::processEvents();
3129
3130         item0->removeRow(1);
3131         item0->setText("OnlyOne");
3132         delegate.count = 0;
3133         QTRY_VERIFY(delegate.count >= 2);
3134         QApplication::processEvents();
3135     }
3136 }
3137
3138 class task174627_TreeView : public QTreeView
3139 {
3140     Q_OBJECT
3141 protected slots:
3142     void currentChanged(const QModelIndex &current, const QModelIndex &)
3143     { emit currentChanged(current); }
3144 signals:
3145     void currentChanged(const QModelIndex &);
3146 };
3147
3148 void tst_QTreeView::task174627_moveLeftToRoot()
3149 {
3150     QStandardItemModel model;
3151     QStandardItem *item1 = new QStandardItem(QString("item 1"));
3152     model.invisibleRootItem()->appendRow(item1);
3153     QStandardItem *item2 = new QStandardItem(QString("item 2"));
3154     item1->appendRow(item2);
3155
3156     task174627_TreeView view;
3157     view.setModel(&model);
3158     view.setRootIndex(item1->index());
3159     view.setCurrentIndex(item2->index());
3160
3161     QSignalSpy spy(&view, SIGNAL(currentChanged(QModelIndex)));
3162     QTest::keyClick(&view, Qt::Key_Left);
3163     QCOMPARE(spy.count(), 0);
3164 }
3165
3166 void tst_QTreeView::task171902_expandWith1stColHidden()
3167 {
3168     //the task was: if the first column of a treeview is hidden, the expanded state is not correctly restored
3169     QStandardItemModel model;
3170     QStandardItem root("root"), root2("root"),
3171         subitem("subitem"), subitem2("subitem"),
3172         subsubitem("subsubitem"), subsubitem2("subsubitem");
3173
3174     model.appendRow( QList<QStandardItem *>() << &root << &root2);
3175     root.appendRow( QList<QStandardItem *>() << &subitem << &subitem2);
3176     subitem.appendRow( QList<QStandardItem *>() << &subsubitem << &subsubitem2);
3177
3178     QTreeView view;
3179     view.setModel(&model);
3180
3181     view.setColumnHidden(0, true);
3182     view.expandAll();
3183     view.collapse(root.index());
3184     view.expand(root.index());
3185
3186     QCOMPARE(view.isExpanded(root.index()), true);
3187     QCOMPARE(view.isExpanded(subitem.index()), true);
3188
3189 }
3190
3191 void tst_QTreeView::task203696_hidingColumnsAndRowsn()
3192 {
3193     QTreeView view;
3194     QStandardItemModel *model = new QStandardItemModel(0, 3, &view);
3195     for (int i = 0; i < 3; ++i)
3196     {
3197         model->insertRow(model->rowCount());
3198         for (int j = 0; j < model->columnCount(); ++j)
3199             model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
3200     }
3201     view.setModel(model);
3202     view.show();
3203     view.setColumnHidden(0, true);
3204     view.setRowHidden(0, QModelIndex(), true);
3205     QCOMPARE(view.indexAt(QPoint(0, 0)), model->index(1, 1));
3206 }
3207
3208
3209 void tst_QTreeView::addRowsWhileSectionsAreHidden()
3210 {
3211     QTreeView view;
3212     for (int pass = 1; pass <= 2; ++pass) {
3213         QStandardItemModel *model = new QStandardItemModel(6, pass, &view);
3214         view.setModel(model);
3215         view.show();
3216
3217         int i;
3218         for (i = 0; i < 3; ++i)
3219         {
3220             model->insertRow(model->rowCount());
3221             for (int j = 0; j < model->columnCount(); ++j) {
3222                 model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
3223             }
3224         }
3225         int col;
3226         for (col = 0; col < pass; ++col)
3227             view.setColumnHidden(col, true);
3228         for (i = 3; i < 6; ++i)
3229         {
3230             model->insertRow(model->rowCount());
3231             for (int j = 0; j < model->columnCount(); ++j) {
3232                 model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
3233             }
3234         }
3235         for (col = 0; col < pass; ++col)
3236             view.setColumnHidden(col, false);
3237         QTest::qWait(250);
3238
3239         for (i = 0; i < 6; ++i) {
3240             QRect rect = view.visualRect(model->index(i, 0));
3241             QCOMPARE(rect.isValid(), true);
3242         }
3243
3244         delete model;
3245     }
3246 }
3247
3248 void tst_QTreeView::task216717_updateChildren()
3249 {
3250     class Tree : public QTreeWidget {
3251         protected:
3252             void paintEvent(QPaintEvent *e)
3253             {
3254                 QTreeWidget::paintEvent(e);
3255                 refreshed=true;
3256             }
3257         public:
3258             bool refreshed;
3259     } tree;
3260     tree.show();
3261     QTest::qWaitForWindowShown(&tree);
3262     tree.refreshed = false;
3263     QTreeWidgetItem *parent = new QTreeWidgetItem(QStringList() << "parent");
3264     tree.addTopLevelItem(parent);
3265     QTest::qWait(10);
3266     QTRY_VERIFY(tree.refreshed);
3267     tree.refreshed = false;
3268     parent->addChild(new QTreeWidgetItem(QStringList() << "child"));
3269     QTest::qWait(10);
3270     QTRY_VERIFY(tree.refreshed);
3271
3272 }
3273
3274 void tst_QTreeView::task220298_selectColumns()
3275 {
3276     //this is a very simple 3x3 model where the internalId of the index are different for each cell
3277     class Model : public QAbstractTableModel
3278     { public:
3279             virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const
3280             { return parent.isValid() ? 0 : 3; }
3281             virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const
3282             { return parent.isValid() ? 0 : 3; }
3283
3284             virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
3285             {
3286                 if(role == Qt::DisplayRole)
3287                     return QVariant(QString("%1-%2").arg(index.column()).arg(index.row()));
3288                 return QVariant();
3289             }
3290
3291             virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const
3292             {
3293                 return hasIndex(row, column, parent) ? createIndex(row, column, column*10+row) : QModelIndex();
3294             }
3295     };
3296
3297     class TreeView : public QTreeView { public: QModelIndexList selectedIndexes () const { return QTreeView::selectedIndexes(); } } view;
3298     Model model;
3299     view.setModel(&model);
3300     view.show();
3301     QTest::qWait(50);
3302     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
3303                       view.visualRect(view.model()->index(1, 1)).center());
3304     QTest::qWait(50);
3305     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 2)));
3306     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 1)));
3307     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 0)));
3308 }
3309
3310
3311 void tst_QTreeView::task224091_appendColumns()
3312 {
3313     QStandardItemModel *model = new QStandardItemModel();
3314     QWidget* topLevel= new QWidget;
3315     QTreeView *treeView = new QTreeView(topLevel);
3316     treeView->setModel(model);
3317     topLevel->show();
3318     treeView->resize(50,50);
3319
3320     QTest::qWaitForWindowShown(treeView);
3321     qApp->processEvents();
3322
3323     QList<QStandardItem *> projlist;
3324     for (int k = 0; k < 10; ++k)
3325         projlist.append(new QStandardItem(QString("Top Level %0").arg(k)));
3326     model->appendColumn(projlist);
3327     model->invisibleRootItem()->appendRow(new QStandardItem("end"));
3328
3329     QTest::qWait(50);
3330     qApp->processEvents();
3331
3332     QTRY_VERIFY(treeView->verticalScrollBar()->isVisible());
3333
3334     delete topLevel;
3335     delete model;
3336 }
3337
3338 void tst_QTreeView::task211293_removeRootIndex()
3339 {
3340     QTreeView view;
3341     QStandardItemModel model;
3342     QStandardItem *A1 = new QStandardItem("A1");
3343     QStandardItem *B11 = new QStandardItem("B1.1");
3344     QStandardItem *C111 = new QStandardItem("C1.1.1");
3345     QStandardItem *C112 = new QStandardItem("C1.1.2");
3346     QStandardItem *C113 = new QStandardItem("C1.1.3");
3347     QStandardItem *D1131 = new QStandardItem("D1.1.3.1");
3348     QStandardItem *E11311 = new QStandardItem("E1.1.3.1.1");
3349     QStandardItem *E11312 = new QStandardItem("E1.1.3.1.2");
3350     QStandardItem *E11313 = new QStandardItem("E1.1.3.1.3");
3351     QStandardItem *E11314 = new QStandardItem("E1.1.3.1.4");
3352     QStandardItem *D1132 = new QStandardItem("D1.1.3.2");
3353     QStandardItem *E11321 = new QStandardItem("E1.1.3.2.1");
3354     D1132->appendRow(E11321);
3355     D1131->appendRow(E11311);
3356     D1131->appendRow(E11312);
3357     D1131->appendRow(E11313);
3358     D1131->appendRow(E11314);
3359     C113->appendRow(D1131);
3360     C113->appendRow(D1132);
3361     B11->appendRow(C111);
3362     B11->appendRow(C112);
3363     B11->appendRow(C113);
3364     A1->appendRow(B11);
3365     model.appendRow(A1);
3366     view.setModel(&model);
3367     view.setRootIndex(model.indexFromItem(B11));
3368     view.setExpanded(model.indexFromItem(B11), true);
3369     view.setCurrentIndex(model.indexFromItem(E11314));
3370     view.setExpanded(model.indexFromItem(E11314), true);
3371     view.show();
3372     qApp->processEvents();
3373     model.removeRows(0, 1);
3374     qApp->processEvents();
3375 }
3376
3377 void tst_QTreeView::task225539_deleteModel()
3378 {
3379     QTreeView treeView;
3380     treeView.show();
3381     QStandardItemModel *model = new QStandardItemModel(&treeView);
3382
3383     QStandardItem* parentItem = model->invisibleRootItem();
3384     QStandardItem* item = new QStandardItem(QString("item"));
3385     parentItem->appendRow(item);
3386
3387     treeView.setModel(model);
3388
3389     QCOMPARE(item->index(), treeView.indexAt(QPoint()));
3390
3391     delete model;
3392
3393     QVERIFY(!treeView.indexAt(QPoint()).isValid());
3394 }
3395
3396 void tst_QTreeView::task230123_setItemsExpandable()
3397 {
3398     //let's check that we prevent the expansion inside a treeview
3399     //when the property is set.
3400     QTreeWidget tree;
3401
3402     QTreeWidgetItem root;
3403     QTreeWidgetItem child;
3404     root.addChild(&child);
3405     tree.addTopLevelItem(&root);
3406
3407     tree.setCurrentItem(&root);
3408
3409     tree.setItemsExpandable(false);
3410
3411     QTest::keyClick(&tree, Qt::Key_Plus);
3412     QVERIFY(!root.isExpanded());
3413
3414     QTest::keyClick(&tree, Qt::Key_Right);
3415     QVERIFY(!root.isExpanded());
3416
3417     tree.setItemsExpandable(true);
3418
3419     QTest::keyClick(&tree, Qt::Key_Plus);
3420     QVERIFY(root.isExpanded());
3421
3422     QTest::keyClick(&tree, Qt::Key_Minus);
3423     QVERIFY(!root.isExpanded());
3424
3425     QTest::keyClick(&tree, Qt::Key_Right);
3426     QVERIFY(root.isExpanded());
3427
3428     QTest::keyClick(&tree, Qt::Key_Left);
3429     QVERIFY(!root.isExpanded());
3430
3431     QTest::keyClick(&tree, Qt::Key_Right);
3432     QVERIFY(root.isExpanded());
3433
3434     const bool navToChild = tree.style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, &tree);
3435     QTest::keyClick(&tree, Qt::Key_Right);
3436     QCOMPARE(tree.currentItem(), navToChild ? &child : &root);
3437
3438     QTest::keyClick(&tree, Qt::Key_Right);
3439     //it should not be expanded: it has no leaf
3440     QCOMPARE(child.isExpanded(), false);
3441
3442     QTest::keyClick(&tree, Qt::Key_Left);
3443     QCOMPARE(tree.currentItem(), &root);
3444
3445     QTest::keyClick(&tree, Qt::Key_Left);
3446     QVERIFY(!root.isExpanded());
3447
3448
3449 }
3450
3451 void tst_QTreeView::task202039_closePersistentEditor()
3452 {
3453     QStandardItemModel model(1,1);
3454     QTreeView view;
3455     view.setModel(&model);
3456
3457     QModelIndex current = model.index(0,0);
3458     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3459     QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3460     QCOMPARE(view.currentIndex(), current);
3461     QVERIFY(view.indexWidget(current));
3462
3463     view.closePersistentEditor(current);
3464     QVERIFY(view.indexWidget(current) == 0);
3465
3466     //here was the bug: closing the persistent editor would not reset the state
3467     //and it was impossible to go into editinon again
3468     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3469     QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3470     QCOMPARE(view.currentIndex(), current);
3471     QVERIFY(view.indexWidget(current));
3472 }
3473
3474 void tst_QTreeView::task238873_avoidAutoReopening()
3475 {
3476     QStandardItemModel model;
3477
3478     QStandardItem item0("row 0");
3479     QStandardItem item1("row 1");
3480     QStandardItem item2("row 2");
3481     QStandardItem item3("row 3");
3482     model.appendColumn( QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3);
3483
3484     QStandardItem child("child");
3485     item1.appendRow( &child);
3486
3487     QTreeView view;
3488     view.setModel(&model);
3489     view.show();
3490     view.expandAll();
3491     QTest::qWait(100);
3492
3493     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(child.index()).center());
3494     QTest::qWait(20);
3495     QCOMPARE(view.currentIndex(), child.index());
3496
3497     view.setExpanded(item1.index(), false);
3498
3499     QTest::qWait(500); //enough to trigger the delayedAutoScroll timer
3500     QVERIFY(!view.isExpanded(item1.index()));