Remove usage of deprecated qWaitForWindowShown(QWidget *) method.
[profile/ivi/qtbase.git] / tests / auto / widgets / itemviews / qtreeview / tst_qtreeview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qabstractitemview.h>
43 #include <QtTest/QtTest>
44 #include <QtGui/QtGui>
45 #include <QtWidgets/QtWidgets>
46 #include <private/qabstractitemview_p.h>
47
48 Q_DECLARE_METATYPE(QModelIndex)
49 #ifndef QT_NO_DRAGANDDROP
50 Q_DECLARE_METATYPE(QAbstractItemView::DragDropMode)
51 #endif
52 Q_DECLARE_METATYPE(QAbstractItemView::EditTriggers)
53 Q_DECLARE_METATYPE(QAbstractItemView::EditTrigger)
54
55 static void initStandardTreeModel(QStandardItemModel *model)
56 {
57     QStandardItem *item;
58     item = new QStandardItem(QLatin1String("Row 1 Item"));
59     model->insertRow(0, item);
60
61     item = new QStandardItem(QLatin1String("Row 2 Item"));
62     item->setCheckable(true);
63     model->insertRow(1, item);
64
65     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
66     item->setChild(0, childItem);
67
68     item = new QStandardItem(QLatin1String("Row 3 Item"));
69     item->setIcon(QIcon());
70     model->insertRow(2, item);
71 }
72
73 struct PublicView : public QTreeView
74 {
75     inline void executeDelayedItemsLayout()
76     { QTreeView::executeDelayedItemsLayout(); }
77
78     enum PublicCursorAction {
79         MoveUp = QAbstractItemView::MoveUp,
80         MoveDown = QAbstractItemView::MoveDown,
81         MoveLeft = QAbstractItemView::MoveLeft,
82         MoveRight = QAbstractItemView::MoveRight,
83         MoveHome = QAbstractItemView::MoveHome,
84         MoveEnd = QAbstractItemView::MoveEnd,
85         MovePageUp = QAbstractItemView::MovePageUp,
86         MovePageDown = QAbstractItemView::MovePageDown,
87         MoveNext = QAbstractItemView::MoveNext,
88         MovePrevious = QAbstractItemView::MovePrevious
89     };
90
91     inline QModelIndex moveCursor(PublicCursorAction ca, Qt::KeyboardModifiers kbm)
92     { return QTreeView::moveCursor((CursorAction)ca, kbm); }
93
94     inline void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
95     {
96         QTreeView::setSelection(rect, command);
97     }
98     inline int state()
99     {
100         return QTreeView::state();
101     }
102
103     inline int rowHeight(QModelIndex idx) { return QTreeView::rowHeight(idx); }
104     inline int indexRowSizeHint(const QModelIndex &index) const { return QTreeView::indexRowSizeHint(index); }
105
106     inline QModelIndexList selectedIndexes() const { return QTreeView::selectedIndexes(); }
107
108     inline QStyleOptionViewItem viewOptions() const { return QTreeView::viewOptions(); }
109     inline int sizeHintForColumn(int column) const { return QTreeView::sizeHintForColumn(column); }
110     QAbstractItemViewPrivate* aiv_priv() { return static_cast<QAbstractItemViewPrivate*>(d_ptr.data()); }
111 };
112
113 class tst_QTreeView : public QObject
114 {
115     Q_OBJECT
116
117 public:
118     tst_QTreeView();
119     virtual ~tst_QTreeView();
120
121
122 public slots:
123     void initTestCase();
124     void cleanupTestCase();
125     void init();
126     void cleanup();
127
128     void selectionOrderTest();
129
130 private slots:
131     void getSetCheck();
132
133     // one test per QTreeView property
134     void construction();
135     void alternatingRowColors();
136     void currentIndex_data();
137     void currentIndex();
138 #ifndef QT_NO_DRAGANDDROP
139     void dragDropMode_data();
140     void dragDropMode();
141     void dragDropModeFromDragEnabledAndAcceptDrops_data();
142     void dragDropModeFromDragEnabledAndAcceptDrops();
143     void dragDropOverwriteMode();
144 #endif
145     void editTriggers_data();
146     void editTriggers();
147     void hasAutoScroll();
148     void horizontalScrollMode();
149     void iconSize();
150     void indexAt();
151     void indexWidget();
152     void itemDelegate();
153     void itemDelegateForColumnOrRow();
154     void keyboardSearch();
155     void setModel();
156     void openPersistentEditor();
157     void rootIndex();
158
159     // specialized tests below
160     void setHeader();
161     void columnHidden();
162     void rowHidden();
163     void noDelegate();
164     void noModel();
165     void emptyModel();
166     void removeRows();
167     void removeCols();
168     void expandAndCollapse_data();
169     void expandAndCollapse();
170     void expandAndCollapseAll();
171     void expandWithNoChildren();
172     void keyboardNavigation();
173     void headerSections();
174     void moveCursor_data();
175     void moveCursor();
176     void setSelection_data();
177     void setSelection();
178     void extendedSelection_data();
179     void extendedSelection();
180     void indexAbove();
181     void indexBelow();
182     void clicked();
183     void mouseDoubleClick();
184     void rowsAboutToBeRemoved();
185     void headerSections_unhideSection();
186     void columnAt();
187     void scrollTo();
188     void rowsAboutToBeRemoved_move();
189     void resizeColumnToContents();
190     void insertAfterSelect();
191     void removeAfterSelect();
192     void hiddenItems();
193     void spanningItems();
194     void rowSizeHint();
195     void setSortingEnabled();
196     void headerHidden();
197
198     void selection();
199     void removeAndInsertExpandedCol0();
200     void selectionWithHiddenItems();
201     void selectAll();
202
203     void disabledButCheckable();
204     void sortByColumn_data();
205     void sortByColumn();
206
207     void evilModel_data();
208     void evilModel();
209
210     void indexRowSizeHint();
211     void addRowsWhileSectionsAreHidden();
212     void filterProxyModelCrash();
213     void renderToPixmap_data();
214     void renderToPixmap();
215     void styleOptionViewItem();
216     void keyboardNavigationWithDisabled();
217
218     // task-specific tests:
219     void task174627_moveLeftToRoot();
220     void task171902_expandWith1stColHidden();
221     void task203696_hidingColumnsAndRowsn();
222     void task211293_removeRootIndex();
223     void task216717_updateChildren();
224     void task220298_selectColumns();
225     void task224091_appendColumns();
226     void task225539_deleteModel();
227     void task230123_setItemsExpandable();
228     void task202039_closePersistentEditor();
229     void task238873_avoidAutoReopening();
230     void task244304_clickOnDecoration();
231     void task246536_scrollbarsNotWorking();
232     void task250683_wrongSectionSize();
233     void task239271_addRowsWithFirstColumnHidden();
234     void task254234_proxySort();
235     void task248022_changeSelection();
236     void task245654_changeModelAndExpandAll();
237     void doubleClickedWithSpans();
238     void taskQTBUG_6450_selectAllWith1stColumnHidden();
239     void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint();
240     void taskQTBUG_11466_keyboardNavigationRegression();
241     void taskQTBUG_13567_removeLastItemRegression();
242     void taskQTBUG_25333_adjustViewOptionsForIndex();
243 };
244
245 class QtTestModel: public QAbstractItemModel
246 {
247 public:
248     QtTestModel(QObject *parent = 0): QAbstractItemModel(parent),
249        fetched(false), rows(0), cols(0), levels(INT_MAX), wrongIndex(false) { init(); }
250
251     QtTestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
252        fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); }
253
254     void init() {
255         decorationsEnabled = false;
256     }
257
258     inline qint32 level(const QModelIndex &index) const {
259         return index.isValid() ? qint32(index.internalId()) : qint32(-1);
260     }
261
262     bool canFetchMore(const QModelIndex &) const {
263         return !fetched;
264     }
265
266     void fetchMore(const QModelIndex &) {
267         fetched = true;
268     }
269
270     bool hasChildren(const QModelIndex &parent = QModelIndex()) const {
271         bool hasFetched = fetched;
272         fetched = true;
273         bool r = QAbstractItemModel::hasChildren(parent);
274         fetched = hasFetched;
275         return r;
276     }
277
278     int rowCount(const QModelIndex& parent = QModelIndex()) const {
279         if (!fetched)
280             qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO);
281         if ((parent.column() > 0) || (level(parent) > levels))
282             return 0;
283         return rows;
284     }
285     int columnCount(const QModelIndex& parent = QModelIndex()) const {
286         if ((parent.column() > 0) || (level(parent) > levels))
287             return 0;
288         return cols;
289     }
290
291     bool isEditable(const QModelIndex &index) const {
292         if (index.isValid())
293             return true;
294         return false;
295     }
296
297     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
298     {
299         if (row < 0 || column < 0 || (level(parent) > levels) || column >= cols || row >= rows) {
300             return QModelIndex();
301         }
302         QModelIndex i = createIndex(row, column, level(parent) + 1);
303         parentHash[i] = parent;
304         return i;
305     }
306
307     QModelIndex parent(const QModelIndex &index) const
308     {
309         if (!parentHash.contains(index))
310             return QModelIndex();
311         return parentHash[index];
312     }
313
314     QVariant data(const QModelIndex &idx, int role) const
315     {
316         if (!idx.isValid())
317             return QVariant();
318
319         if (role == Qt::DisplayRole) {
320             if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
321                 wrongIndex = true;
322                 qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
323                          idx.internalPointer());
324             }
325             if (idx.row() & 1)
326                 return QString("[%1,%2,%3] - this item is extra wide").arg(idx.row()).arg(idx.column()).arg(level(idx));
327             return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column()).arg(level(idx));
328         }
329         if (decorationsEnabled && role == Qt::DecorationRole) {
330             QPixmap pm(16,16);
331             pm.fill(QColor::fromHsv((idx.column() % 16)*8 + 64, 254, (idx.row() % 16)*8 + 32));
332             return pm;
333         }
334         return QVariant();
335     }
336
337     void removeLastRow()
338     {
339         beginRemoveRows(QModelIndex(), rows - 1, rows - 1);
340         --rows;
341         endRemoveRows();
342     }
343
344     void removeAllRows()
345     {
346         beginRemoveRows(QModelIndex(), 0, rows - 1);
347         rows = 0;
348         endRemoveRows();
349     }
350
351     void removeLastColumn()
352     {
353         beginRemoveColumns(QModelIndex(), cols - 1, cols - 1);
354         --cols;
355         endRemoveColumns();
356     }
357
358     void removeAllColumns()
359     {
360         beginRemoveColumns(QModelIndex(), 0, cols - 1);
361         cols = 0;
362         endRemoveColumns();
363     }
364
365     void insertNewRow()
366     {
367         beginInsertRows(QModelIndex(), rows - 1, rows - 1);
368         ++rows;
369         endInsertRows();
370     }
371
372     void setDecorationsEnabled(bool enable)
373     {
374         decorationsEnabled = enable;
375     }
376
377     mutable bool fetched;
378     bool decorationsEnabled;
379     int rows, cols;
380     int levels;
381     mutable bool wrongIndex;
382     mutable QMap<QModelIndex,QModelIndex> parentHash;
383 };
384
385 tst_QTreeView::tst_QTreeView()
386 {
387 }
388
389 tst_QTreeView::~tst_QTreeView()
390 {
391 }
392
393 void tst_QTreeView::initTestCase()
394 {
395 #ifdef Q_OS_WINCE //disable magic for WindowsCE
396     qApp->setAutoMaximizeThreshold(-1);
397 #endif
398     qRegisterMetaType<QModelIndex>("QModelIndex");
399 }
400
401 void tst_QTreeView::cleanupTestCase()
402 {
403 }
404
405 void tst_QTreeView::init()
406 {
407 }
408
409 void tst_QTreeView::cleanup()
410 {
411 }
412
413 // Testing get/set functions
414 void tst_QTreeView::getSetCheck()
415 {
416     QTreeView obj1;
417
418     // int QTreeView::indentation()
419     // void QTreeView::setIndentation(int)
420     QCOMPARE(obj1.indentation(), 20);
421     obj1.setIndentation(0);
422     QCOMPARE(obj1.indentation(), 0);
423     obj1.setIndentation(INT_MIN);
424     QCOMPARE(obj1.indentation(), INT_MIN);
425     obj1.setIndentation(INT_MAX);
426     QCOMPARE(obj1.indentation(), INT_MAX);
427
428     // bool QTreeView::rootIsDecorated()
429     // void QTreeView::setRootIsDecorated(bool)
430     QCOMPARE(obj1.rootIsDecorated(), true);
431     obj1.setRootIsDecorated(false);
432     QCOMPARE(obj1.rootIsDecorated(), false);
433     obj1.setRootIsDecorated(true);
434     QCOMPARE(obj1.rootIsDecorated(), true);
435
436     // bool QTreeView::uniformRowHeights()
437     // void QTreeView::setUniformRowHeights(bool)
438     QCOMPARE(obj1.uniformRowHeights(), false);
439     obj1.setUniformRowHeights(false);
440     QCOMPARE(obj1.uniformRowHeights(), false);
441     obj1.setUniformRowHeights(true);
442     QCOMPARE(obj1.uniformRowHeights(), true);
443
444     // bool QTreeView::itemsExpandable()
445     // void QTreeView::setItemsExpandable(bool)
446     QCOMPARE(obj1.itemsExpandable(), true);
447     obj1.setItemsExpandable(false);
448     QCOMPARE(obj1.itemsExpandable(), false);
449     obj1.setItemsExpandable(true);
450     QCOMPARE(obj1.itemsExpandable(), true);
451
452     // bool QTreeView::allColumnsShowFocus
453     // void QTreeView::setAllColumnsShowFocus
454     QCOMPARE(obj1.allColumnsShowFocus(), false);
455     obj1.setAllColumnsShowFocus(false);
456     QCOMPARE(obj1.allColumnsShowFocus(), false);
457     obj1.setAllColumnsShowFocus(true);
458     QCOMPARE(obj1.allColumnsShowFocus(), true);
459
460     // bool QTreeView::isAnimated
461     // void QTreeView::setAnimated
462     QCOMPARE(obj1.isAnimated(), false);
463     obj1.setAnimated(false);
464     QCOMPARE(obj1.isAnimated(), false);
465     obj1.setAnimated(true);
466     QCOMPARE(obj1.isAnimated(), true);
467
468     // bool QTreeView::setSortingEnabled
469     // void QTreeView::isSortingEnabled
470     QCOMPARE(obj1.isSortingEnabled(), false);
471     obj1.setSortingEnabled(false);
472     QCOMPARE(obj1.isSortingEnabled(), false);
473     obj1.setSortingEnabled(true);
474     QCOMPARE(obj1.isSortingEnabled(), true);
475 }
476
477 void tst_QTreeView::construction()
478 {
479     QTreeView view;
480
481     // QAbstractItemView properties
482     QVERIFY(!view.alternatingRowColors());
483     QCOMPARE(view.currentIndex(), QModelIndex());
484 #ifndef QT_NO_DRAGANDDROP
485     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
486     QVERIFY(!view.dragDropOverwriteMode());
487     QVERIFY(!view.dragEnabled());
488 #endif
489     QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked);
490     QVERIFY(view.hasAutoScroll());
491     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
492     QCOMPARE(view.iconSize(), QSize());
493     QCOMPARE(view.indexAt(QPoint()), QModelIndex());
494     QVERIFY(!view.indexWidget(QModelIndex()));
495     QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate()));
496     QVERIFY(!view.itemDelegateForColumn(-1));
497     QVERIFY(!view.itemDelegateForColumn(0));
498     QVERIFY(!view.itemDelegateForColumn(1));
499     QVERIFY(!view.itemDelegateForRow(-1));
500     QVERIFY(!view.itemDelegateForRow(0));
501     QVERIFY(!view.itemDelegateForRow(1));
502     QVERIFY(!view.model());
503     QCOMPARE(view.rootIndex(), QModelIndex());
504     QCOMPARE(view.selectionBehavior(), QAbstractItemView::SelectRows);
505     QCOMPARE(view.selectionMode(), QAbstractItemView::SingleSelection);
506     QVERIFY(!view.selectionModel());
507 #ifndef QT_NO_DRAGANDDROP
508     QVERIFY(view.showDropIndicator());
509 #endif
510     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(-1), -1); // <- protected in QTreeView
511     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(0), -1); // <- protected in QTreeView
512     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(1), -1); // <- protected in QTreeView
513     QCOMPARE(view.sizeHintForIndex(QModelIndex()), QSize());
514     QCOMPARE(view.sizeHintForRow(-1), -1);
515     QCOMPARE(view.sizeHintForRow(0), -1);
516     QCOMPARE(view.sizeHintForRow(1), -1);
517     QVERIFY(!view.tabKeyNavigation());
518     QCOMPARE(view.textElideMode(), Qt::ElideRight);
519     QCOMPARE(view.verticalScrollMode(), QAbstractItemView::ScrollPerItem);
520     QCOMPARE(view.visualRect(QModelIndex()), QRect());
521
522     // QTreeView properties
523     QVERIFY(!view.allColumnsShowFocus());
524     QCOMPARE(view.autoExpandDelay(), -1);
525     QCOMPARE(view.columnAt(-1), -1);
526     QCOMPARE(view.columnAt(0), -1);
527     QCOMPARE(view.columnAt(1), -1);
528     QCOMPARE(view.columnViewportPosition(-1), -1);
529     QCOMPARE(view.columnViewportPosition(0), -1);
530     QCOMPARE(view.columnViewportPosition(1), -1);
531     QCOMPARE(view.columnWidth(-1), 0);
532     QCOMPARE(view.columnWidth(0), 0);
533     QCOMPARE(view.columnWidth(1), 0);
534     QVERIFY(view.header());
535     QCOMPARE(view.indentation(), 20);
536     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
537     QCOMPARE(view.indexBelow(QModelIndex()), QModelIndex());
538     QVERIFY(!view.isAnimated());
539     QVERIFY(!view.isColumnHidden(-1));
540     QVERIFY(!view.isColumnHidden(0));
541     QVERIFY(!view.isColumnHidden(1));
542     QVERIFY(!view.isExpanded(QModelIndex()));
543     QVERIFY(!view.isRowHidden(-1, QModelIndex()));
544     QVERIFY(!view.isRowHidden(0, QModelIndex()));
545     QVERIFY(!view.isRowHidden(1, QModelIndex()));
546     QVERIFY(!view.isFirstColumnSpanned(-1, QModelIndex()));
547     QVERIFY(!view.isFirstColumnSpanned(0, QModelIndex()));
548     QVERIFY(!view.isFirstColumnSpanned(1, QModelIndex()));
549     QVERIFY(!view.isSortingEnabled());
550     QVERIFY(view.itemsExpandable());
551     QVERIFY(view.rootIsDecorated());
552     QVERIFY(!view.uniformRowHeights());
553     QCOMPARE(view.visualRect(QModelIndex()), QRect());
554     QVERIFY(!view.wordWrap());
555 }
556
557 void tst_QTreeView::alternatingRowColors()
558 {
559     QTreeView view;
560     QVERIFY(!view.alternatingRowColors());
561     view.setAlternatingRowColors(true);
562     QVERIFY(view.alternatingRowColors());
563     view.setAlternatingRowColors(false);
564     QVERIFY(!view.alternatingRowColors());
565
566     // ### Test visual effect.
567 }
568
569 void tst_QTreeView::currentIndex_data()
570 {
571     QTest::addColumn<int>("row");
572     QTest::addColumn<int>("column");
573     QTest::addColumn<int>("indexRow");
574     QTest::addColumn<int>("indexColumn");
575     QTest::addColumn<int>("parentIndexRow");
576     QTest::addColumn<int>("parentIndexColumn");
577
578     QTest::newRow("-1, -1") << -1 << -1 << -1 << -1 << -1 << -1;
579     QTest::newRow("-1, 0") << -1 << 0 << -1 << -1 << -1 << -1;
580     QTest::newRow("0, -1") << 0 << -1 << -1 << -1 << -1 << -1;
581     QTest::newRow("0, 0") << 0 << 0 << 0 << 0 << -1 << -1;
582     QTest::newRow("0, 1") << 0 << 0 << 0 << 0 << -1 << -1;
583     QTest::newRow("1, 0") << 1 << 0 << 1 << 0 << -1 << -1;
584     QTest::newRow("1, 1") << 1 << 1 << -1 << -1 << -1 << -1;
585     QTest::newRow("2, 0") << 2 << 0 << 2 << 0 << -1 << -1;
586     QTest::newRow("2, 1") << 2 << 1 << -1 << -1 << -1 << -1;
587     QTest::newRow("3, -1") << 3 << -1 << -1 << -1 << -1 << -1;
588     QTest::newRow("3, 0") << 3 << 0 << -1 << -1 << -1 << -1;
589     QTest::newRow("3, 1") << 3 << 1 << -1 << -1 << -1 << -1;
590 }
591
592 void tst_QTreeView::currentIndex()
593 {
594     QFETCH(int, row);
595     QFETCH(int, column);
596     QFETCH(int, indexRow);
597     QFETCH(int, indexColumn);
598     QFETCH(int, parentIndexRow);
599     QFETCH(int, parentIndexColumn);
600
601     QTreeView view;
602     QStandardItemModel treeModel;
603     initStandardTreeModel(&treeModel);
604     view.setModel(&treeModel);
605
606     QCOMPARE(view.currentIndex(), QModelIndex());
607     view.setCurrentIndex(view.model()->index(row, column));
608     QCOMPARE(view.currentIndex().row(), indexRow);
609     QCOMPARE(view.currentIndex().column(), indexColumn);
610     QCOMPARE(view.currentIndex().parent().row(), parentIndexRow);
611     QCOMPARE(view.currentIndex().parent().column(), parentIndexColumn);
612
613     // ### Test child and grandChild indexes.
614 }
615
616 #ifndef QT_NO_DRAGANDDROP
617
618 void tst_QTreeView::dragDropMode_data()
619 {
620     QTest::addColumn<QAbstractItemView::DragDropMode>("dragDropMode");
621     QTest::addColumn<bool>("acceptDrops");
622     QTest::addColumn<bool>("dragEnabled");
623     QTest::newRow("NoDragDrop") << QAbstractItemView::NoDragDrop << false << false;
624     QTest::newRow("DragOnly") << QAbstractItemView::DragOnly << false << true;
625     QTest::newRow("DropOnly") << QAbstractItemView::DropOnly << true << false;
626     QTest::newRow("DragDrop") << QAbstractItemView::DragDrop << true << true;
627     QTest::newRow("InternalMove") << QAbstractItemView::InternalMove << true << true;
628 }
629
630 void tst_QTreeView::dragDropMode()
631 {
632     QFETCH(QAbstractItemView::DragDropMode, dragDropMode);
633     QFETCH(bool, acceptDrops);
634     QFETCH(bool, dragEnabled);
635
636     QTreeView view;
637     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
638     QVERIFY(!view.acceptDrops());
639     QVERIFY(!view.dragEnabled());
640
641     view.setDragDropMode(dragDropMode);
642     QCOMPARE(view.dragDropMode(), dragDropMode);
643     QCOMPARE(view.acceptDrops(), acceptDrops);
644     QCOMPARE(view.dragEnabled(), dragEnabled);
645
646     // ### Test effects of this mode
647 }
648
649 void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops_data()
650 {
651     QTest::addColumn<bool>("dragEnabled");
652     QTest::addColumn<bool>("acceptDrops");
653     QTest::addColumn<QAbstractItemView::DragDropMode>("dragDropMode");
654     QTest::addColumn<QAbstractItemView::DragDropMode>("setBehavior");
655
656     QTest::newRow("NoDragDrop -1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDropMode(-1);
657     QTest::newRow("NoDragDrop 0") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::NoDragDrop;
658     QTest::newRow("NoDragDrop 1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragOnly;
659     QTest::newRow("NoDragDrop 2") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DropOnly;
660     QTest::newRow("NoDragDrop 3") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDrop;
661     QTest::newRow("NoDragDrop 4") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::InternalMove;
662     QTest::newRow("DragOnly -1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDropMode(-1);
663     QTest::newRow("DragOnly 0") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::NoDragDrop;
664     QTest::newRow("DragOnly 1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragOnly;
665     QTest::newRow("DragOnly 2") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DropOnly;
666     QTest::newRow("DragOnly 3") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDrop;
667     QTest::newRow("DragOnly 4") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::InternalMove;
668     QTest::newRow("DropOnly -1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDropMode(-1);
669     QTest::newRow("DropOnly 0") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::NoDragDrop;
670     QTest::newRow("DropOnly 1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragOnly;
671     QTest::newRow("DropOnly 2") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DropOnly;
672     QTest::newRow("DropOnly 3") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDrop;
673     QTest::newRow("DropOnly 4") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::InternalMove;
674     QTest::newRow("DragDrop -1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1);
675     QTest::newRow("DragDrop 0") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1);
676     QTest::newRow("DragDrop 1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::NoDragDrop;
677     QTest::newRow("DragDrop 2") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragOnly;
678     QTest::newRow("DragDrop 3") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DropOnly;
679     QTest::newRow("DragDrop 4") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDrop;
680     QTest::newRow("DragDrop 5") << true << true << QAbstractItemView::InternalMove << QAbstractItemView::InternalMove;
681 }
682
683 void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops()
684 {
685     QFETCH(bool, acceptDrops);
686     QFETCH(bool, dragEnabled);
687     QFETCH(QAbstractItemView::DragDropMode, dragDropMode);
688     QFETCH(QAbstractItemView::DragDropMode, setBehavior);
689
690     QTreeView view;
691     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
692
693     if (setBehavior != QAbstractItemView::DragDropMode(-1))
694         view.setDragDropMode(setBehavior);
695
696     view.setAcceptDrops(acceptDrops);
697     view.setDragEnabled(dragEnabled);
698     QCOMPARE(view.dragDropMode(), dragDropMode);
699
700     // ### Test effects of this mode
701 }
702
703 void tst_QTreeView::dragDropOverwriteMode()
704 {
705     QTreeView view;
706     QVERIFY(!view.dragDropOverwriteMode());
707     view.setDragDropOverwriteMode(true);
708     QVERIFY(view.dragDropOverwriteMode());
709     view.setDragDropOverwriteMode(false);
710     QVERIFY(!view.dragDropOverwriteMode());
711
712     // ### This property changes the behavior of dropIndicatorPosition(),
713     // which is protected and called only from within QListWidget and
714     // QTableWidget, from their reimplementations of dropMimeData(). Hard to
715     // test.
716 }
717 #endif
718
719 void tst_QTreeView::editTriggers_data()
720 {
721     QTest::addColumn<QAbstractItemView::EditTriggers>("editTriggers");
722     QTest::addColumn<QAbstractItemView::EditTrigger>("triggeredTrigger");
723     QTest::addColumn<bool>("editorOpened");
724
725     // NoEditTriggers
726     QTest::newRow("NoEditTriggers 0") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
727                                       << QAbstractItemView::NoEditTriggers << false;
728     QTest::newRow("NoEditTriggers 1") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
729                                       << QAbstractItemView::CurrentChanged << false;
730     QTest::newRow("NoEditTriggers 2") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
731                                       << QAbstractItemView::DoubleClicked << false;
732     QTest::newRow("NoEditTriggers 3") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
733                                       << QAbstractItemView::SelectedClicked << false;
734     QTest::newRow("NoEditTriggers 4") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
735                                       << QAbstractItemView::EditKeyPressed << false;
736
737     // CurrentChanged
738     QTest::newRow("CurrentChanged 0") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
739                                       << QAbstractItemView::NoEditTriggers << false;
740     QTest::newRow("CurrentChanged 1") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
741                                       << QAbstractItemView::CurrentChanged << true;
742     QTest::newRow("CurrentChanged 2") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
743                                       << QAbstractItemView::DoubleClicked << false;
744     QTest::newRow("CurrentChanged 3") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
745                                       << QAbstractItemView::SelectedClicked << false;
746     QTest::newRow("CurrentChanged 4") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
747                                       << QAbstractItemView::EditKeyPressed << false;
748
749     // DoubleClicked
750     QTest::newRow("DoubleClicked 0") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
751                                      << QAbstractItemView::NoEditTriggers << false;
752     QTest::newRow("DoubleClicked 1") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
753                                      << QAbstractItemView::CurrentChanged << false;
754     QTest::newRow("DoubleClicked 2") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
755                                      << QAbstractItemView::DoubleClicked << true;
756     QTest::newRow("DoubleClicked 3") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
757                                      << QAbstractItemView::SelectedClicked << false;
758     QTest::newRow("DoubleClicked 4") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
759                                      << QAbstractItemView::EditKeyPressed << false;
760
761     // SelectedClicked
762     QTest::newRow("SelectedClicked 0") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
763                                        << QAbstractItemView::NoEditTriggers << false;
764     QTest::newRow("SelectedClicked 1") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
765                                        << QAbstractItemView::CurrentChanged << false;
766     QTest::newRow("SelectedClicked 2") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
767                                        << QAbstractItemView::DoubleClicked << false;
768     QTest::newRow("SelectedClicked 3") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
769                                        << QAbstractItemView::SelectedClicked << true;
770     QTest::newRow("SelectedClicked 4") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
771                                        << QAbstractItemView::EditKeyPressed << false;
772
773     // EditKeyPressed
774     QTest::newRow("EditKeyPressed 0") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
775                                       << QAbstractItemView::NoEditTriggers << false;
776     QTest::newRow("EditKeyPressed 1") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
777                                       << QAbstractItemView::CurrentChanged << false;
778     QTest::newRow("EditKeyPressed 2") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
779                                       << QAbstractItemView::DoubleClicked << false;
780     QTest::newRow("EditKeyPressed 3") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
781                                       << QAbstractItemView::SelectedClicked << false;
782     QTest::newRow("EditKeyPressed 4") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
783                                       << QAbstractItemView::EditKeyPressed << true;
784 }
785
786 void tst_QTreeView::editTriggers()
787 {
788     QFETCH(QAbstractItemView::EditTriggers, editTriggers);
789     QFETCH(QAbstractItemView::EditTrigger, triggeredTrigger);
790     QFETCH(bool, editorOpened);
791
792     QTreeView view;
793     QStandardItemModel treeModel;
794     initStandardTreeModel(&treeModel);
795     view.setModel(&treeModel);
796     view.show();
797
798     QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked);
799
800     // Initialize the first index
801     view.setCurrentIndex(view.model()->index(0, 0));
802
803     // Verify that we don't have any editor initially
804     QVERIFY(!qFindChild<QLineEdit *>(&view, QString()));
805
806     // Set the triggers
807     view.setEditTriggers(editTriggers);
808
809     // Interact with the view
810     switch (triggeredTrigger) {
811     case QAbstractItemView::NoEditTriggers:
812         // Do nothing, the editor shouldn't be there
813         break;
814     case QAbstractItemView::CurrentChanged:
815         // Change the index to open an editor
816         view.setCurrentIndex(view.model()->index(1, 0));
817         break;
818     case QAbstractItemView::DoubleClicked:
819         // Doubleclick the center of the current cell
820         QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
821                           view.visualRect(view.model()->index(0, 0)).center());
822         QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0,
823                            view.visualRect(view.model()->index(0, 0)).center());
824         break;
825     case QAbstractItemView::SelectedClicked:
826         // Click the center of the current cell
827         view.selectionModel()->select(view.model()->index(0, 0), QItemSelectionModel::Select);
828         QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
829                           view.visualRect(view.model()->index(0, 0)).center());
830         QTest::qWait(int(QApplication::doubleClickInterval() * 1.5));
831         break;
832     case QAbstractItemView::EditKeyPressed:
833         view.setFocus();
834 #ifdef Q_OS_MAC
835         // Mac OS X uses Enter for editing
836         QTest::keyPress(&view, Qt::Key_Enter);
837 #else
838         // All other platforms use F2
839         QTest::keyPress(&view, Qt::Key_F2);
840 #endif
841         break;
842     default:
843         break;
844     }
845
846     // Check if we got an editor
847 #ifdef Q_OS_MAC
848     QEXPECT_FAIL("EditKeyPressed 4", "QTBUG-23696", Continue);
849 #endif
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     QVERIFY(QTest::qWaitForWindowExposed(&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::fromLatin1("%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::fromLatin1("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     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
2390     topLevel.show();
2391     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, mousePressPos);
2392     QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedCount);
2393 }
2394
2395 void tst_QTreeView::rowSizeHint()
2396 {
2397     //tests whether the correct visible columns are taken into account when
2398     //calculating the height of a line
2399     QStandardItemModel model(1,3);
2400     model.setData( model.index(0,0), QSize(20,40), Qt::SizeHintRole);
2401     model.setData( model.index(0,1), QSize(20,10), Qt::SizeHintRole);
2402     model.setData( model.index(0,2), QSize(20,10), Qt::SizeHintRole);
2403     QTreeView view;
2404     view.setModel(&model);
2405
2406     view.header()->moveSection(1, 0); //the 2nd column goes to the 1st place
2407
2408     view.show();
2409
2410     //it must be 40 since the tallest item that defines the height of a line
2411     QCOMPARE( view.visualRect(model.index(0,0)).height(), 40);
2412     QCOMPARE( view.visualRect(model.index(0,1)).height(), 40);
2413     QCOMPARE( view.visualRect(model.index(0,2)).height(), 40);
2414 }
2415
2416
2417 //From task 155449 (QTreeWidget has a large width for the first section when sorting
2418 //is turned on before items are added)
2419 void tst_QTreeView::setSortingEnabled()
2420 {
2421     //1st the treeview is a top-level
2422     {
2423         QTreeView view;
2424         QStandardItemModel model(1,1);
2425         view.setModel(&model);
2426         const int size = view.header()->sectionSize(0);
2427         view.setSortingEnabled(true);
2428         model.setColumnCount(3);
2429         //we test that changing the column count doesn't change the 1st column size
2430         QCOMPARE(view.header()->sectionSize(0), size);
2431     }
2432
2433     //then it is no more a top-level
2434     {
2435         QMainWindow win;
2436         QTreeView view;
2437         QStandardItemModel model(1,1);
2438         view.setModel(&model);
2439         win.setCentralWidget(&view);
2440         const int size = view.header()->sectionSize(0);
2441         view.setSortingEnabled(true);
2442         model.setColumnCount(3);
2443         //we test that changing the column count doesn't change the 1st column size
2444         QCOMPARE(view.header()->sectionSize(0), size);
2445     }
2446 }
2447
2448 void tst_QTreeView::headerHidden()
2449 {
2450     QTreeView view;
2451     QStandardItemModel model;
2452     view.setModel(&model);
2453     QCOMPARE(view.isHeaderHidden(), false);
2454     QCOMPARE(view.header()->isHidden(), false);
2455     view.setHeaderHidden(true);
2456     QCOMPARE(view.isHeaderHidden(), true);
2457     QCOMPARE(view.header()->isHidden(), true);
2458 }
2459
2460 // From Task 145199 (crash when column 0 having at least one expanded item is removed and then
2461 // inserted). The test passes simply if it doesn't crash, hence there are no calls
2462 // to QCOMPARE() or QVERIFY().
2463 void tst_QTreeView::removeAndInsertExpandedCol0()
2464 {
2465     QTreeView view;
2466     QStandardItemModel model;
2467     view.setModel(&model);
2468
2469     model.setColumnCount(1);
2470
2471     QStandardItem *item0 = new QStandardItem(QString("item 0"));
2472     model.invisibleRootItem()->appendRow(item0);
2473     view.expand(item0->index());
2474     QStandardItem *item1 = new QStandardItem(QString("item 1"));
2475     item0->appendRow(item1);
2476
2477     model.removeColumns(0, 1);
2478     model.insertColumns(0, 1);
2479
2480     view.show();
2481     qApp->processEvents();
2482 }
2483
2484 void tst_QTreeView::disabledButCheckable()
2485 {
2486     QTreeView view;
2487     QStandardItemModel model;
2488     QStandardItem *item;
2489     item = new QStandardItem(QLatin1String("Row 1 Item"));
2490     model.insertRow(0, item);
2491
2492     item = new QStandardItem(QLatin1String("Row 2 Item"));
2493     item->setCheckable(true);
2494     item->setEnabled(false);
2495     model.insertRow(1, item);
2496
2497     view.setModel(&model);
2498     view.setCurrentIndex(model.index(1,0));
2499     QCOMPARE(item->checkState(), Qt::Unchecked);
2500     view.show();
2501
2502     QTest::keyClick(&view, Qt::Key_Space);
2503     QCOMPARE(item->checkState(), Qt::Unchecked);
2504 }
2505
2506 void tst_QTreeView::sortByColumn_data()
2507 {
2508     QTest::addColumn<bool>("sortingEnabled");
2509     QTest::newRow("sorting enabled") << true;
2510     QTest::newRow("sorting disabled") << false;
2511 }
2512
2513 // Checks sorting and that sortByColumn also sets the sortIndicator
2514 void tst_QTreeView::sortByColumn()
2515 {
2516     QFETCH(bool, sortingEnabled);
2517     QTreeView view;
2518     QStandardItemModel model(4,2);
2519     model.setItem(0,0,new QStandardItem("b"));
2520     model.setItem(1,0,new QStandardItem("d"));
2521     model.setItem(2,0,new QStandardItem("c"));
2522     model.setItem(3,0,new QStandardItem("a"));
2523     model.setItem(0,1,new QStandardItem("e"));
2524     model.setItem(1,1,new QStandardItem("g"));
2525     model.setItem(2,1,new QStandardItem("h"));
2526     model.setItem(3,1,new QStandardItem("f"));
2527
2528     view.setSortingEnabled(sortingEnabled);
2529     view.setModel(&model);
2530     view.sortByColumn(1);
2531     QCOMPARE(view.header()->sortIndicatorSection(), 1);
2532     QCOMPARE(view.model()->data(view.model()->index(0,1)).toString(), QString::fromLatin1("h"));
2533     QCOMPARE(view.model()->data(view.model()->index(1,1)).toString(), QString::fromLatin1("g"));
2534     view.sortByColumn(0, Qt::AscendingOrder);
2535     QCOMPARE(view.header()->sortIndicatorSection(), 0);
2536     QCOMPARE(view.model()->data(view.model()->index(0,0)).toString(), QString::fromLatin1("a"));
2537     QCOMPARE(view.model()->data(view.model()->index(1,0)).toString(), QString::fromLatin1("b"));
2538 }
2539
2540 /*
2541     This is a model that every time kill() is called it will completely change
2542     all of its nodes for new nodes.  It then qFatal's if you later use a dead node.
2543  */
2544 class EvilModel: public QAbstractItemModel
2545 {
2546
2547 public:
2548     class Node {
2549     public:
2550         Node(Node *p = 0, int level = 0) : parent(p), isDead(false) {
2551             populate(level);
2552         }
2553         ~Node()
2554         {
2555             qDeleteAll(children.begin(), children.end());
2556             qDeleteAll(deadChildren.begin(), deadChildren.end());
2557         }
2558
2559         void populate(int level = 0) {
2560             if (level < 4)
2561                 for (int i = 0; i < 5; ++i)
2562                     children.append(new Node(this, level + 1));
2563         }
2564         void kill() {
2565             for (int i = children.count() -1; i >= 0; --i) {
2566                 children.at(i)->kill();
2567                 if (parent == 0) {
2568                     deadChildren.append(children.at(i));
2569                     children.removeAt(i);
2570                 }
2571             }
2572             if (parent == 0) {
2573                 if (!children.isEmpty())
2574                     qFatal("%s: children should be empty when parent is null", Q_FUNC_INFO);
2575                 populate();
2576             } else {
2577                 isDead = true;
2578             }
2579         }
2580
2581         QList<Node*> children;
2582         QList<Node*> deadChildren;
2583         Node *parent;
2584         bool isDead;
2585     };
2586
2587     Node *root;
2588
2589     EvilModel(QObject *parent = 0): QAbstractItemModel(parent), root(new Node)
2590     {
2591     }
2592     ~EvilModel()
2593     {
2594         delete root;
2595     }
2596
2597     void change()
2598     {
2599         emit layoutAboutToBeChanged();
2600         QModelIndexList oldList = persistentIndexList();
2601         QList<QStack<int> > oldListPath;
2602         for (int i = 0; i < oldList.count(); ++i) {
2603             QModelIndex idx = oldList.at(i);
2604             QStack<int> path;
2605             while (idx.isValid()) {
2606                 path.push(idx.row());
2607                 idx = idx.parent();
2608             }
2609             oldListPath.append(path);
2610         }
2611         root->kill();
2612
2613         QModelIndexList newList;
2614         for (int i = 0; i < oldListPath.count(); ++i) {
2615             QStack<int> path = oldListPath[i];
2616             QModelIndex idx;
2617             while(!path.isEmpty()) {
2618                 idx = index(path.pop(), 0, idx);
2619             }
2620             newList.append(idx);
2621         }
2622
2623         changePersistentIndexList(oldList, newList);
2624         emit layoutChanged();
2625     }
2626
2627     int rowCount(const QModelIndex& parent = QModelIndex()) const {
2628         Node *parentNode = root;
2629         if (parent.isValid()) {
2630             parentNode = static_cast<Node*>(parent.internalPointer());
2631             if (parentNode->isDead)
2632                 qFatal("%s: parentNode is dead!", Q_FUNC_INFO);
2633         }
2634         return parentNode->children.count();
2635     }
2636     int columnCount(const QModelIndex& parent = QModelIndex()) const {
2637         if (parent.column() > 0)
2638             return 0;
2639         return 1;
2640     }
2641
2642     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
2643     {
2644         Node *grandparentNode = static_cast<Node*>(parent.internalPointer());
2645         Node *parentNode = root;
2646         if (parent.isValid()) {
2647             if (grandparentNode->isDead)
2648                 qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
2649             parentNode = grandparentNode->children[parent.row()];
2650             if (parentNode->isDead)
2651                 qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
2652         }
2653         return createIndex(row, column, parentNode);
2654     }
2655
2656     QModelIndex parent(const QModelIndex &index) const
2657     {
2658         Node *parent = static_cast<Node*>(index.internalPointer());
2659         Node *grandparent = parent->parent;
2660         if (!grandparent)
2661             return QModelIndex();
2662         return createIndex(grandparent->children.indexOf(parent), 0, grandparent);
2663     }
2664
2665     QVariant data(const QModelIndex &idx, int role) const
2666     {
2667         if (idx.isValid() && role == Qt::DisplayRole) {
2668             Node *parentNode = root;
2669             if (idx.isValid()) {
2670                 parentNode = static_cast<Node*>(idx.internalPointer());
2671                 if (parentNode->isDead)
2672                     qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
2673             }
2674             return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column())
2675                 .arg(parentNode->isDead ? "dead" : "alive");
2676         }
2677         return QVariant();
2678     }
2679 };
2680
2681 void tst_QTreeView::evilModel_data()
2682 {
2683     QTest::addColumn<bool>("visible");
2684     QTest::newRow("visible") << false;
2685 }
2686
2687 void tst_QTreeView::evilModel()
2688 {
2689     QFETCH(bool, visible);
2690     // init
2691     PublicView view;
2692     EvilModel model;
2693     view.setModel(&model);
2694     view.setVisible(visible);
2695     QPersistentModelIndex firstLevel = model.index(0, 0);
2696     QPersistentModelIndex secondLevel = model.index(1, 0, firstLevel);
2697     QPersistentModelIndex thirdLevel = model.index(2, 0, secondLevel);
2698     view.setExpanded(firstLevel, true);
2699     view.setExpanded(secondLevel, true);
2700     view.setExpanded(thirdLevel, true);
2701     model.change();
2702
2703     // tests
2704     view.setRowHidden(0, firstLevel, true);
2705     model.change();
2706
2707     return;
2708     view.setFirstColumnSpanned(1, QModelIndex(), true);
2709     model.change();
2710
2711     view.expand(secondLevel);
2712     model.change();
2713
2714     view.collapse(secondLevel);
2715     model.change();
2716
2717     view.isExpanded(secondLevel);
2718     view.setCurrentIndex(firstLevel);
2719     model.change();
2720
2721     view.keyboardSearch("foo");
2722     model.change();
2723
2724     view.visualRect(secondLevel);
2725     model.change();
2726
2727     view.scrollTo(thirdLevel);
2728     model.change();
2729
2730     view.repaint();
2731     model.change();
2732
2733     QTest::mouseDClick(view.viewport(), Qt::LeftButton);
2734     model.change();
2735
2736     view.indexAt(QPoint(10, 10));
2737     model.change();
2738
2739     view.indexAbove(model.index(2, 0));
2740     model.change();
2741
2742     view.indexBelow(model.index(1, 0));
2743     model.change();
2744
2745     QRect rect(0, 0, 10, 10);
2746     view.setSelection(rect, QItemSelectionModel::Select);
2747     model.change();
2748
2749     view.moveCursor(PublicView::MoveDown, Qt::NoModifier);
2750     model.change();
2751
2752     view.resizeColumnToContents(1);
2753     model.change();
2754
2755     view.QAbstractItemView::sizeHintForColumn(1);
2756     model.change();
2757
2758     view.rowHeight(secondLevel);
2759     model.change();
2760
2761     view.setRootIsDecorated(true);
2762     model.change();
2763
2764     view.setItemsExpandable(false);
2765     model.change();
2766
2767     view.columnViewportPosition(0);
2768     model.change();
2769
2770     view.columnWidth(0);
2771     model.change();
2772
2773     view.setColumnWidth(0, 30);
2774     model.change();
2775
2776     view.columnAt(15);
2777     model.change();
2778
2779     view.isColumnHidden(1);
2780     model.change();
2781
2782     view.setColumnHidden(2, true);
2783     model.change();
2784
2785     view.isHeaderHidden();
2786     model.change();
2787
2788     view.setHeaderHidden(true);
2789     model.change();
2790
2791     view.isRowHidden(2, secondLevel);
2792     model.change();
2793
2794     view.setRowHidden(3, secondLevel, true);
2795     model.change();
2796
2797     view.isFirstColumnSpanned(3, thirdLevel);
2798     model.change();
2799
2800     view.setSortingEnabled(true);
2801     model.change();
2802
2803     view.isSortingEnabled();
2804     model.change();
2805
2806     view.setAnimated(true);
2807     model.change();
2808
2809     view.isAnimated();
2810     model.change();
2811
2812     view.setAllColumnsShowFocus(true);
2813     model.change();
2814
2815     view.allColumnsShowFocus();
2816     model.change();
2817
2818     view.doItemsLayout();
2819     model.change();
2820
2821     view.reset();
2822     model.change();
2823
2824     view.sortByColumn(1, Qt::AscendingOrder);
2825     model.change();
2826
2827     view.dataChanged(secondLevel, secondLevel);
2828     model.change();
2829
2830     view.hideColumn(1);
2831     model.change();
2832
2833     view.showColumn(1);
2834     model.change();
2835
2836     view.resizeColumnToContents(1);
2837     model.change();
2838
2839     view.sortByColumn(1);
2840     model.change();
2841
2842     view.selectAll();
2843     model.change();
2844
2845     view.expandAll();
2846     model.change();
2847
2848     view.collapseAll();
2849     model.change();
2850
2851     view.expandToDepth(3);
2852     model.change();
2853
2854     view.setRootIndex(secondLevel);
2855 }
2856
2857 void tst_QTreeView::indexRowSizeHint()
2858 {
2859     QStandardItemModel model(10, 1);
2860     PublicView view;
2861
2862     view.setModel(&model);
2863
2864     QModelIndex index = model.index(5, 0);
2865     QPushButton *w = new QPushButton("Test");
2866     view.setIndexWidget(index, w);
2867
2868     view.show();
2869
2870     QCOMPARE(view.indexRowSizeHint(index), w->sizeHint().height());
2871 }
2872
2873 void tst_QTreeView::filterProxyModelCrash()
2874 {
2875     QStandardItemModel model;
2876     QList<QStandardItem *> items;
2877     for (int i = 0; i < 100; i++)
2878         items << new QStandardItem(QString::fromLatin1("item %1").arg(i));
2879     model.appendColumn(items);
2880
2881     QSortFilterProxyModel proxy;
2882     proxy.setSourceModel(&model);
2883
2884     QTreeView view;
2885     view.setModel(&proxy);
2886     view.show();
2887     QTest::qWait(30);
2888     proxy.invalidate();
2889     view.verticalScrollBar()->setValue(15);
2890     QTest::qWait(20);
2891
2892     proxy.invalidate();
2893     view.repaint(); //used to crash
2894 }
2895
2896 void tst_QTreeView::renderToPixmap_data()
2897 {
2898     QTest::addColumn<int>("row");
2899     QTest::newRow("row-0") << 0;
2900     QTest::newRow("row-1") << 1;
2901 }
2902
2903 void tst_QTreeView::renderToPixmap()
2904 {
2905     QFETCH(int, row);
2906     PublicView view;
2907     QStandardItemModel model;
2908
2909     model.appendRow(new QStandardItem("Spanning"));
2910     model.appendRow(QList<QStandardItem*>() << new QStandardItem("Not") << new QStandardItem("Spanning"));
2911
2912     view.setModel(&model);
2913     view.setFirstColumnSpanned(0, QModelIndex(), true);
2914
2915 #ifdef QT_BUILD_INTERNAL
2916     {
2917         // We select the index at row=0 because it spans the
2918         // column (regression test for an assert)
2919         // We select the index at row=1 for coverage.
2920         QItemSelection sel(model.index(row,0), model.index(row,1));
2921         QRect rect;
2922         view.aiv_priv()->renderToPixmap(sel.indexes(), &rect);
2923     }
2924 #endif
2925 }
2926
2927 void tst_QTreeView::styleOptionViewItem()
2928 {
2929     class MyDelegate : public QStyledItemDelegate
2930     {
2931         static QString posToString(QStyleOptionViewItemV4::ViewItemPosition pos) {
2932             static const char* s_pos[] = { "Invalid", "Beginning", "Middle", "End", "OnlyOne" };
2933             return s_pos[pos];
2934         }
2935         public:
2936             void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
2937             {
2938                 QVERIFY(qstyleoption_cast<const QStyleOptionViewItemV4 *>(&option));
2939                 QStyleOptionViewItemV4 opt(option);
2940                 initStyleOption(&opt, index);
2941
2942                 QVERIFY(!opt.text.isEmpty());
2943                 QCOMPARE(opt.index, index);
2944                 //qDebug() << index << opt.text;
2945
2946                 if (allCollapsed)
2947                     QCOMPARE(!(opt.features & QStyleOptionViewItemV2::Alternate), !(index.row() % 2));
2948                 QCOMPARE(!(opt.features & QStyleOptionViewItemV2::HasCheckIndicator), !opt.text.contains("Checkable"));
2949
2950                 if (opt.text.contains("Beginning"))
2951                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::Beginning));
2952
2953                 if (opt.text.contains("Middle"))
2954                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::Middle));
2955
2956                 if (opt.text.contains("End"))
2957                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::End));
2958
2959                 if (opt.text.contains("OnlyOne"))
2960                     QCOMPARE(posToString(opt.viewItemPosition), posToString(QStyleOptionViewItemV4::OnlyOne));
2961
2962                 if (opt.text.contains("Checked"))
2963                     QCOMPARE(opt.checkState, Qt::Checked);
2964                 else
2965                     QCOMPARE(opt.checkState, Qt::Unchecked);
2966
2967                 QCOMPARE(!(opt.state & QStyle::State_Children) , !opt.text.contains("HasChildren"));
2968                 QCOMPARE(!!(opt.state & QStyle::State_Sibling) , !opt.text.contains("Last"));
2969
2970                 QVERIFY(!opt.text.contains("Assert"));
2971
2972                 QStyledItemDelegate::paint(painter, option, index);
2973                 count++;
2974             }
2975             mutable int count;
2976             bool allCollapsed;
2977     };
2978
2979     PublicView view;
2980     QStandardItemModel model;
2981     view.setModel(&model);
2982     MyDelegate delegate;
2983     view.setItemDelegate(&delegate);
2984     model.appendRow(QList<QStandardItem*>()
2985         << new QStandardItem("Beginning") << new QStandardItem("Hidden") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
2986     QStandardItem *par1 = new QStandardItem("Beginning HasChildren");
2987     model.appendRow(QList<QStandardItem*>()
2988         << par1 << new QStandardItem("Hidden") << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") );
2989     model.appendRow(QList<QStandardItem*>()
2990         << new QStandardItem("OnlyOne") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Assert") );
2991     QStandardItem *checkable = new QStandardItem("Checkable");
2992     checkable->setCheckable(true);
2993     QStandardItem *checked = new QStandardItem("Checkable Checked");
2994     checked->setCheckable(true);
2995     checked->setCheckState(Qt::Checked);
2996     model.appendRow(QList<QStandardItem*>()
2997         << new QStandardItem("Beginning") << new QStandardItem("Hidden") << checkable << checked << new QStandardItem("End") );
2998     model.appendRow(QList<QStandardItem*>()
2999         << new QStandardItem("Beginning Last") << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
3000
3001     par1->appendRow(QList<QStandardItem*>()
3002         << new QStandardItem("Beginning") << new QStandardItem("Hidden") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
3003     QStandardItem *par2 = new QStandardItem("Beginning HasChildren");
3004     par1->appendRow(QList<QStandardItem*>()
3005         << par2 << new QStandardItem("Hidden") << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") );
3006     par2->appendRow(QList<QStandardItem*>()
3007         << new QStandardItem("Beginning Last") << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
3008
3009     QStandardItem *par3 = new QStandardItem("Beginning Last");
3010     par1->appendRow(QList<QStandardItem*>()
3011         << par3 << new QStandardItem("Hidden") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
3012     par3->appendRow(QList<QStandardItem*>()
3013         << new QStandardItem("Assert") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") );
3014     view.setRowHidden(0, par3->index(), true);
3015     par1->appendRow(QList<QStandardItem*>()
3016         << new QStandardItem("Assert") << new QStandardItem("Hidden") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") );
3017     view.setRowHidden(3, par1->index(), true);
3018
3019     view.setColumnHidden(1, true);
3020     const int visibleColumns = 4;
3021     const int modelColumns = 5;
3022
3023     view.header()->swapSections(2, 3);
3024     view.setFirstColumnSpanned(2, QModelIndex(), true);
3025     view.setAlternatingRowColors(true);
3026
3027 #ifdef QT_BUILD_INTERNAL
3028     {
3029         // Test the rendering to pixmap before painting the widget.
3030         // The rendering to pixmap should not depend on having been
3031         // painted already yet.
3032         delegate.count = 0;
3033         QItemSelection sel(model.index(0,0), model.index(0,modelColumns-1));
3034         QRect rect;
3035         view.aiv_priv()->renderToPixmap(sel.indexes(), &rect);
3036         if (delegate.count != visibleColumns) {
3037             qDebug() << rect << view.rect() << view.isVisible();
3038         }
3039         QTRY_COMPARE(delegate.count, visibleColumns);
3040     }
3041 #endif
3042
3043     delegate.count = 0;
3044     delegate.allCollapsed = true;
3045     view.showMaximized();
3046     QApplication::processEvents();
3047     QTRY_VERIFY(delegate.count >= 13);
3048     delegate.count = 0;
3049     delegate.allCollapsed = false;
3050     view.expandAll();
3051     QApplication::processEvents();
3052     QTRY_VERIFY(delegate.count >= 13);
3053     delegate.count = 0;
3054     view.collapse(par2->index());
3055     QApplication::processEvents();
3056     QTRY_VERIFY(delegate.count >= 4);
3057
3058     // test that the rendering of drag pixmap sets the correct options too (QTBUG-15834)
3059 #ifdef QT_BUILD_INTERNAL
3060     delegate.count = 0;
3061     QItemSelection sel(model.index(0,0), model.index(0,modelColumns-1));
3062     QRect rect;
3063     view.aiv_priv()->renderToPixmap(sel.indexes(), &rect);
3064     if (delegate.count != visibleColumns) {
3065         qDebug() << rect << view.rect() << view.isVisible();
3066     }
3067     QTRY_COMPARE(delegate.count, visibleColumns);
3068 #endif
3069
3070     //test dynamic models
3071     {
3072         delegate.count = 0;
3073         QStandardItemModel model2;
3074         QStandardItem *item0 = new QStandardItem("OnlyOne Last");
3075         model2.appendRow(QList<QStandardItem*>() << item0);
3076         view.setModel(&model2);
3077         QApplication::processEvents();
3078         QTRY_VERIFY(delegate.count >= 1);
3079         QApplication::processEvents();
3080
3081         QStandardItem *item00 = new QStandardItem("OnlyOne Last");
3082         item0->appendRow(QList<QStandardItem*>() << item00);
3083         item0->setText("OnlyOne Last HasChildren");
3084         QApplication::processEvents();
3085         delegate.count = 0;
3086         view.expandAll();
3087         QApplication::processEvents();
3088         QTRY_VERIFY(delegate.count >= 2);
3089         QApplication::processEvents();
3090
3091         QStandardItem *item1 = new QStandardItem("OnlyOne Last");
3092         delegate.count = 0;
3093         item0->setText("OnlyOne HasChildren");
3094         model2.appendRow(QList<QStandardItem*>() << item1);
3095         QApplication::processEvents();
3096         QTRY_VERIFY(delegate.count >= 3);
3097         QApplication::processEvents();
3098
3099         QStandardItem *item01 = new QStandardItem("OnlyOne Last");
3100         delegate.count = 0;
3101         item00->setText("OnlyOne");
3102         item0->appendRow(QList<QStandardItem*>() << item01);
3103         QApplication::processEvents();
3104         QTRY_VERIFY(delegate.count >= 4);
3105         QApplication::processEvents();
3106
3107         QStandardItem *item000 = new QStandardItem("OnlyOne Last");
3108         delegate.count = 0;
3109         item00->setText("OnlyOne HasChildren");
3110         item00->appendRow(QList<QStandardItem*>() << item000);
3111         QApplication::processEvents();
3112         QTRY_VERIFY(delegate.count >= 5);
3113         QApplication::processEvents();
3114
3115         delegate.count = 0;
3116         item0->removeRow(0);
3117         QApplication::processEvents();
3118         QTRY_VERIFY(delegate.count >= 3);
3119         QApplication::processEvents();
3120
3121         item00 = new QStandardItem("OnlyOne");
3122         item0->insertRow(0, QList<QStandardItem*>() << item00);
3123         QApplication::processEvents();
3124         delegate.count = 0;
3125         view.expandAll();
3126         QApplication::processEvents();
3127         QTRY_VERIFY(delegate.count >= 4);
3128         QApplication::processEvents();
3129
3130         delegate.count = 0;
3131         item0->removeRow(1);
3132         item00->setText("OnlyOne Last");
3133         QApplication::processEvents();
3134         QTRY_VERIFY(delegate.count >= 3);
3135         QApplication::processEvents();
3136
3137         delegate.count = 0;
3138         item0->removeRow(0);
3139         item0->setText("OnlyOne");
3140         QApplication::processEvents();
3141         QTRY_VERIFY(delegate.count >= 2);
3142         QApplication::processEvents();
3143
3144         //with hidden items
3145         item0->setText("OnlyOne HasChildren");
3146         item00 = new QStandardItem("OnlyOne");
3147         item0->appendRow(QList<QStandardItem*>() << item00);
3148         item01 = new QStandardItem("Assert");
3149         item0->appendRow(QList<QStandardItem*>() << item01);
3150         view.setRowHidden(1, item0->index(), true);
3151         view.expandAll();
3152         QStandardItem *item02 = new QStandardItem("OnlyOne Last");
3153         item0->appendRow(QList<QStandardItem*>() << item02);
3154         delegate.count = 0;
3155         QApplication::processEvents();
3156         QTRY_VERIFY(delegate.count >= 4);
3157         QApplication::processEvents();
3158
3159         item0->removeRow(2);
3160         item00->setText("OnlyOne Last");
3161         delegate.count = 0;
3162         QApplication::processEvents();
3163         QTRY_VERIFY(delegate.count >= 3);
3164         QApplication::processEvents();
3165
3166         item00->setText("OnlyOne");
3167         item0->insertRow(2, new QStandardItem("OnlyOne Last"));
3168         view.collapse(item0->index());
3169         item0->removeRow(0);
3170         delegate.count = 0;
3171         QTRY_VERIFY(delegate.count >= 2);
3172         QApplication::processEvents();
3173
3174         item0->removeRow(1);
3175         item0->setText("OnlyOne");
3176         delegate.count = 0;
3177         QTRY_VERIFY(delegate.count >= 2);
3178         QApplication::processEvents();
3179     }
3180 }
3181
3182 class task174627_TreeView : public QTreeView
3183 {
3184     Q_OBJECT
3185 protected slots:
3186     void currentChanged(const QModelIndex &current, const QModelIndex &)
3187     { emit currentChanged(current); }
3188 signals:
3189     void currentChanged(const QModelIndex &);
3190 };
3191
3192 void tst_QTreeView::task174627_moveLeftToRoot()
3193 {
3194     QStandardItemModel model;
3195     QStandardItem *item1 = new QStandardItem(QString("item 1"));
3196     model.invisibleRootItem()->appendRow(item1);
3197     QStandardItem *item2 = new QStandardItem(QString("item 2"));
3198     item1->appendRow(item2);
3199
3200     task174627_TreeView view;
3201     view.setModel(&model);
3202     view.setRootIndex(item1->index());
3203     view.setCurrentIndex(item2->index());
3204
3205     QSignalSpy spy(&view, SIGNAL(currentChanged(QModelIndex)));
3206     QTest::keyClick(&view, Qt::Key_Left);
3207     QCOMPARE(spy.count(), 0);
3208 }
3209
3210 void tst_QTreeView::task171902_expandWith1stColHidden()
3211 {
3212     //the task was: if the first column of a treeview is hidden, the expanded state is not correctly restored
3213     QStandardItemModel model;
3214     QStandardItem root("root"), root2("root"),
3215         subitem("subitem"), subitem2("subitem"),
3216         subsubitem("subsubitem"), subsubitem2("subsubitem");
3217
3218     model.appendRow( QList<QStandardItem *>() << &root << &root2);
3219     root.appendRow( QList<QStandardItem *>() << &subitem << &subitem2);
3220     subitem.appendRow( QList<QStandardItem *>() << &subsubitem << &subsubitem2);
3221
3222     QTreeView view;
3223     view.setModel(&model);
3224
3225     view.setColumnHidden(0, true);
3226     view.expandAll();
3227     view.collapse(root.index());
3228     view.expand(root.index());
3229
3230     QCOMPARE(view.isExpanded(root.index()), true);
3231     QCOMPARE(view.isExpanded(subitem.index()), true);
3232
3233 }
3234
3235 void tst_QTreeView::task203696_hidingColumnsAndRowsn()
3236 {
3237     QTreeView view;
3238     QStandardItemModel *model = new QStandardItemModel(0, 3, &view);
3239     for (int i = 0; i < 3; ++i)
3240     {
3241         model->insertRow(model->rowCount());
3242         for (int j = 0; j < model->columnCount(); ++j)
3243             model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
3244     }
3245     view.setModel(model);
3246     view.show();
3247     view.setColumnHidden(0, true);
3248     view.setRowHidden(0, QModelIndex(), true);
3249     QCOMPARE(view.indexAt(QPoint(0, 0)), model->index(1, 1));
3250 }
3251
3252
3253 void tst_QTreeView::addRowsWhileSectionsAreHidden()
3254 {
3255     QTreeView view;
3256     for (int pass = 1; pass <= 2; ++pass) {
3257         QStandardItemModel *model = new QStandardItemModel(6, pass, &view);
3258         view.setModel(model);
3259         view.show();
3260
3261         int i;
3262         for (i = 0; i < 3; ++i)
3263         {
3264             model->insertRow(model->rowCount());
3265             for (int j = 0; j < model->columnCount(); ++j) {
3266                 model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
3267             }
3268         }
3269         int col;
3270         for (col = 0; col < pass; ++col)
3271             view.setColumnHidden(col, true);
3272         for (i = 3; i < 6; ++i)
3273         {
3274             model->insertRow(model->rowCount());
3275             for (int j = 0; j < model->columnCount(); ++j) {
3276                 model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
3277             }
3278         }
3279         for (col = 0; col < pass; ++col)
3280             view.setColumnHidden(col, false);
3281         QTest::qWait(250);
3282
3283         for (i = 0; i < 6; ++i) {
3284             QRect rect = view.visualRect(model->index(i, 0));
3285             QCOMPARE(rect.isValid(), true);
3286         }
3287
3288         delete model;
3289     }
3290 }
3291
3292 void tst_QTreeView::task216717_updateChildren()
3293 {
3294     class Tree : public QTreeWidget {
3295         protected:
3296             void paintEvent(QPaintEvent *e)
3297             {
3298                 QTreeWidget::paintEvent(e);
3299                 refreshed=true;
3300             }
3301         public:
3302             bool refreshed;
3303     } tree;
3304     tree.show();
3305     QVERIFY(QTest::qWaitForWindowExposed(&tree));
3306     tree.refreshed = false;
3307     QTreeWidgetItem *parent = new QTreeWidgetItem(QStringList() << "parent");
3308     tree.addTopLevelItem(parent);
3309     QTest::qWait(10);
3310     QTRY_VERIFY(tree.refreshed);
3311     tree.refreshed = false;
3312     parent->addChild(new QTreeWidgetItem(QStringList() << "child"));
3313     QTest::qWait(10);
3314     QTRY_VERIFY(tree.refreshed);
3315
3316 }
3317
3318 void tst_QTreeView::task220298_selectColumns()
3319 {
3320     //this is a very simple 3x3 model where the internalId of the index are different for each cell
3321     class Model : public QAbstractTableModel
3322     { public:
3323             virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const
3324             { return parent.isValid() ? 0 : 3; }
3325             virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const
3326             { return parent.isValid() ? 0 : 3; }
3327
3328             virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
3329             {
3330                 if(role == Qt::DisplayRole)
3331                     return QVariant(QString("%1-%2").arg(index.column()).arg(index.row()));
3332                 return QVariant();
3333             }
3334
3335             virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const
3336             {
3337                 return hasIndex(row, column, parent) ? createIndex(row, column, column*10+row) : QModelIndex();
3338             }
3339     };
3340
3341     class TreeView : public QTreeView { public: QModelIndexList selectedIndexes () const { return QTreeView::selectedIndexes(); } } view;
3342     Model model;
3343     view.setModel(&model);
3344     view.show();
3345     QTest::qWait(50);
3346     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
3347                       view.visualRect(view.model()->index(1, 1)).center());
3348     QTest::qWait(50);
3349     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 2)));
3350     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 1)));
3351     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 0)));
3352 }
3353
3354
3355 void tst_QTreeView::task224091_appendColumns()
3356 {
3357     QStandardItemModel *model = new QStandardItemModel();
3358     QWidget* topLevel= new QWidget;
3359     QTreeView *treeView = new QTreeView(topLevel);
3360     treeView->setModel(model);
3361     topLevel->show();
3362     treeView->resize(50,50);
3363     qApp->setActiveWindow(topLevel);
3364     QVERIFY(QTest::qWaitForWindowActive(topLevel));
3365
3366     QList<QStandardItem *> projlist;
3367     for (int k = 0; k < 10; ++k)
3368         projlist.append(new QStandardItem(QString("Top Level %0").arg(k)));
3369     model->appendColumn(projlist);
3370     model->invisibleRootItem()->appendRow(new QStandardItem("end"));
3371
3372     QTest::qWait(50);
3373     qApp->processEvents();
3374
3375     QTRY_VERIFY(treeView->verticalScrollBar()->isVisible());
3376
3377     delete topLevel;
3378     delete model;
3379 }
3380
3381 void tst_QTreeView::task211293_removeRootIndex()
3382 {
3383     QTreeView view;
3384     QStandardItemModel model;
3385     QStandardItem *A1 = new QStandardItem("A1");
3386     QStandardItem *B11 = new QStandardItem("B1.1");
3387     QStandardItem *C111 = new QStandardItem("C1.1.1");
3388     QStandardItem *C112 = new QStandardItem("C1.1.2");
3389     QStandardItem *C113 = new QStandardItem("C1.1.3");
3390     QStandardItem *D1131 = new QStandardItem("D1.1.3.1");
3391     QStandardItem *E11311 = new QStandardItem("E1.1.3.1.1");
3392     QStandardItem *E11312 = new QStandardItem("E1.1.3.1.2");
3393     QStandardItem *E11313 = new QStandardItem("E1.1.3.1.3");
3394     QStandardItem *E11314 = new QStandardItem("E1.1.3.1.4");
3395     QStandardItem *D1132 = new QStandardItem("D1.1.3.2");
3396     QStandardItem *E11321 = new QStandardItem("E1.1.3.2.1");
3397     D1132->appendRow(E11321);
3398     D1131->appendRow(E11311);
3399     D1131->appendRow(E11312);
3400     D1131->appendRow(E11313);
3401     D1131->appendRow(E11314);
3402     C113->appendRow(D1131);
3403     C113->appendRow(D1132);
3404     B11->appendRow(C111);
3405     B11->appendRow(C112);
3406     B11->appendRow(C113);
3407     A1->appendRow(B11);
3408     model.appendRow(A1);
3409     view.setModel(&model);
3410     view.setRootIndex(model.indexFromItem(B11));
3411     view.setExpanded(model.indexFromItem(B11), true);
3412     view.setCurrentIndex(model.indexFromItem(E11314));
3413     view.setExpanded(model.indexFromItem(E11314), true);
3414     view.show();
3415     qApp->processEvents();
3416     model.removeRows(0, 1);
3417     qApp->processEvents();
3418 }
3419
3420 void tst_QTreeView::task225539_deleteModel()
3421 {
3422     QTreeView treeView;
3423     treeView.show();
3424     QStandardItemModel *model = new QStandardItemModel(&treeView);
3425
3426     QStandardItem* parentItem = model->invisibleRootItem();
3427     QStandardItem* item = new QStandardItem(QString("item"));
3428     parentItem->appendRow(item);
3429
3430     treeView.setModel(model);
3431
3432     QCOMPARE(item->index(), treeView.indexAt(QPoint()));
3433
3434     delete model;
3435
3436     QVERIFY(!treeView.indexAt(QPoint()).isValid());
3437 }
3438
3439 void tst_QTreeView::task230123_setItemsExpandable()
3440 {
3441     //let's check that we prevent the expansion inside a treeview
3442     //when the property is set.
3443     QTreeWidget tree;
3444
3445     QTreeWidgetItem root;
3446     QTreeWidgetItem child;
3447     root.addChild(&child);
3448     tree.addTopLevelItem(&root);
3449
3450     tree.setCurrentItem(&root);
3451
3452     tree.setItemsExpandable(false);
3453
3454     QTest::keyClick(&tree, Qt::Key_Plus);
3455     QVERIFY(!root.isExpanded());
3456
3457     QTest::keyClick(&tree, Qt::Key_Right);
3458     QVERIFY(!root.isExpanded());
3459
3460     tree.setItemsExpandable(true);
3461
3462     QTest::keyClick(&tree, Qt::Key_Plus);
3463     QVERIFY(root.isExpanded());
3464
3465     QTest::keyClick(&tree, Qt::Key_Minus);
3466     QVERIFY(!root.isExpanded());
3467
3468     QTest::keyClick(&tree, Qt::Key_Right);
3469     QVERIFY(root.isExpanded());
3470
3471     QTest::keyClick(&tree, Qt::Key_Left);
3472     QVERIFY(!root.isExpanded());
3473
3474     QTest::keyClick(&tree, Qt::Key_Right);
3475     QVERIFY(root.isExpanded());
3476
3477     const bool navToChild = tree.style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, &tree);
3478     QTest::keyClick(&tree, Qt::Key_Right);
3479     QCOMPARE(tree.currentItem(), navToChild ? &child : &root);
3480
3481     QTest::keyClick(&tree, Qt::Key_Right);
3482     //it should not be expanded: it has no leaf
3483     QCOMPARE(child.isExpanded(), false);
3484
3485     QTest::keyClick(&tree, Qt::Key_Left);
3486     QCOMPARE(tree.currentItem(), &root);
3487
3488     QTest::keyClick(&tree, Qt::Key_Left);
3489     QVERIFY(!root.isExpanded());
3490
3491
3492 }
3493
3494 void tst_QTreeView::task202039_closePersistentEditor()
3495 {
3496     QStandardItemModel model(1,1);
3497     QTreeView view;
3498     view.setModel(&model);
3499
3500     QModelIndex current = model.index(0,0);
3501     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3502     QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3503     QCOMPARE(view.currentIndex(), current);
3504     QVERIFY(view.indexWidget(current));
3505
3506     view.closePersistentEditor(current);
3507     QVERIFY(view.indexWidget(current) == 0);
3508
3509     //here was the bug: closing the persistent editor would not reset the state
3510     //and it was impossible to go into editinon again
3511     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3512     QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
3513     QCOMPARE(view.currentIndex(), current);
3514     QVERIFY(view.indexWidget(current));
3515 }
3516
3517 void tst_QTreeView::task238873_avoidAutoReopening()
3518 {
3519     QStandardItemModel model;
3520
3521     QStandardItem item0("row 0");
3522     QStandardItem item1("row 1");
3523     QStandardItem item2("row 2");
3524     QStandardItem item3("row 3");
3525     model.appendColumn( QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3);
3526
3527     QStandardItem child("child");
3528     item1.appendRow( &child);
3529
3530     QTreeView view;
3531     view.setModel(&model);
3532     view.show();
3533     view.expandAll();
3534     QTest::qWait(100);
3535
3536     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(child.index()).center());
3537     QTest::qWait(20);
3538     QCOMPARE(view.currentIndex(), child.index());
3539
3540     view.setExpanded(item1.index(), false);
3541
3542     QTest::qWait(500); //enough to trigger the delayedAutoScroll timer
3543     QVERIFY(!view.isExpanded(item1.index()));
3544 }
3545
3546 void tst_QTreeView::task244304_clickOnDecoration()
3547 {
3548     QTreeView view;
3549     QStandardItemModel model;
3550     QStandardItem item0("row 0");
3551     QStandardItem item00("row 0");
3552     item0.appendRow(&item00);
3553     QStandardItem item1("row 1");
3554     model.appendColumn(QList<QStandardItem*>() << &item0 << &item1);
3555     view.setModel(&model);
3556
3557     QVERIFY(!view.currentIndex().isValid());
3558     QRect rect = view.visualRect(item0.index());
3559     //we click on the decoration
3560     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, rect.topLeft()+QPoint(-rect.left()/2,rect.height()/2));
3561     QVERIFY(!view.currentIndex().isValid());
3562     QVERIFY(view.isExpanded(item0.index()));
3563
3564     rect = view.visualRect(item1.index());
3565     //the item has no decoration, it should get selected
3566     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, rect.topLeft()+QPoint(-rect.left()/2,rect.height()/2));
3567     QCOMPARE(view.currentIndex(), item1.index());
3568 }
3569
3570 void tst_QTreeView::task246536_scrollbarsNotWorking()
3571 {
3572     struct MyObject : public QObject
3573     {
3574         MyObject() : count(0)
3575         {
3576         }
3577
3578         bool eventFilter(QObject*, QEvent *e)
3579         {
3580             if (e->type() == QEvent::Paint)
3581                 count++;
3582
3583             return false;
3584         }
3585
3586         int count;
3587     };
3588     QTreeView tree;
3589     MyObject o;
3590     tree.viewport()->installEventFilter(&o);
3591     QStandardItemModel model;
3592     tree.setModel(&model);
3593     tree.show();
3594     QVERIFY(QTest::qWaitForWindowExposed(&tree));
3595     QList<QStandardItem *> items;
3596     for(int i=0; i<100; ++i){
3597         items << new QStandardItem(QString::fromLatin1("item %1").arg(i));
3598     }
3599     model.invisibleRootItem()->appendColumn(items);
3600     QTest::qWait(100);
3601     o.count = 0;
3602     tree.verticalScrollBar()->setValue(50);
3603     QTest::qWait(100);
3604     QTRY_VERIFY(o.count > 0);
3605 }
3606
3607 void tst_QTreeView::task250683_wrongSectionSize()
3608 {
3609     QDirModel model;
3610     QTreeView treeView;
3611     treeView.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
3612     treeView.setModel(&model);
3613     treeView.setColumnHidden(2, true);
3614     treeView.setColumnHidden(3, true);
3615
3616     treeView.show();
3617     QTest::qWait(100);
3618
3619     QCOMPARE(treeView.header()->sectionSize(0) + treeView.header()->sectionSize(1), treeView.viewport()->width());
3620 }
3621
3622 void tst_QTreeView::task239271_addRowsWithFirstColumnHidden()
3623 {
3624     class MyDelegate : public QStyledItemDelegate
3625     {
3626     public:
3627         void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
3628         {
3629             paintedIndexes << index;
3630             QStyledItemDelegate::paint(painter, option, index);
3631         }
3632
3633         mutable QSet<QModelIndex> paintedIndexes;
3634     };
3635
3636     QTreeView view;
3637     QStandardItemModel model;
3638     view.setModel(&model);
3639     MyDelegate delegate;
3640     view.setItemDelegate(&delegate);
3641     QStandardItem root0("root0"), root1("root1");
3642     model.invisibleRootItem()->appendRow(QList<QStandardItem*>() << &root0 << &root1);
3643     QStandardItem sub0("sub0"), sub00("sub00");
3644     root0.appendRow(QList<QStandardItem*>() << &sub0 << &sub00);
3645     view.expand(root0.index());
3646
3647     view.hideColumn(0);
3648     view.show();
3649     QVERIFY(QTest::qWaitForWindowExposed(&view));
3650     delegate.paintedIndexes.clear();
3651     QStandardItem sub1("sub1"), sub11("sub11");
3652     root0.appendRow(QList<QStandardItem*>() << &sub1 << &sub11);
3653
3654     QTest::qWait(20);
3655     //items in the 2nd column should have been painted
3656     QTRY_VERIFY(!delegate.paintedIndexes.isEmpty());
3657     QVERIFY(delegate.paintedIndexes.contains(sub00.index()));
3658     QVERIFY(delegate.paintedIndexes.contains(sub11.index()));
3659 }
3660
3661 void tst_QTreeView::task254234_proxySort()
3662 {
3663     //based on tst_QTreeView::sortByColumn
3664     // it used not to work when setting the source of a proxy after enabling sorting
3665     QTreeView view;
3666     QStandardItemModel model(4,2);
3667     model.setItem(0,0,new QStandardItem("b"));
3668     model.setItem(1,0,new QStandardItem("d"));
3669     model.setItem(2,0,new QStandardItem("c"));
3670     model.setItem(3,0,new QStandardItem("a"));
3671     model.setItem(0,1,new QStandardItem("e"));
3672     model.setItem(1,1,new QStandardItem("g"));
3673     model.setItem(2,1,new QStandardItem("h"));
3674     model.setItem(3,1,new QStandardItem("f"));
3675
3676     view.sortByColumn(1);
3677     view.setSortingEnabled(true);
3678
3679     QSortFilterProxyModel proxy;
3680     proxy.setDynamicSortFilter(true);
3681     view.setModel(&proxy);
3682     proxy.setSourceModel(&model);
3683     QCOMPARE(view.header()->sortIndicatorSection(), 1);
3684     QCOMPARE(view.model()->data(view.model()->index(0,1)).toString(), QString::fromLatin1("h"));
3685     QCOMPARE(view.model()->data(view.model()->index(1,1)).toString(), QString::fromLatin1("g"));
3686 }
3687
3688 class TreeView : public QTreeView
3689 {
3690     Q_OBJECT
3691 public slots:
3692     void handleSelectionChanged()
3693     {
3694         //let's select the last item
3695         QModelIndex idx = model()->index(0, 0);
3696         selectionModel()->select(QItemSelection(idx, idx), QItemSelectionModel::Select);
3697         disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(handleSelectionChanged()));
3698     }
3699 };
3700
3701 void tst_QTreeView::task248022_changeSelection()
3702 {
3703     //we check that changing the selection between the mouse press and the mouse release
3704     //works correctly
3705     TreeView view;
3706     QStringList list = QStringList() << "1" << "2";
3707     QStringListModel model(list);
3708     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
3709     view.setModel(&model);
3710     view.connect(view.selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(handleSelectionChanged()));
3711     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(model.index(1)).center());
3712     QCOMPARE(view.selectionModel()->selectedIndexes().count(), list.count());
3713 }
3714
3715 void tst_QTreeView::task245654_changeModelAndExpandAll()
3716 {
3717     QTreeView view;
3718     QStandardItemModel *model = new QStandardItemModel;
3719     QStandardItem *top = new QStandardItem("top");
3720     QStandardItem *sub = new QStandardItem("sub");
3721     top->appendRow(sub);
3722     model->appendRow(top);
3723     view.setModel(model);
3724     view.expandAll();
3725     QApplication::processEvents();
3726     QVERIFY(view.isExpanded(top->index()));
3727
3728     //now let's try to delete the model
3729     //then repopulate and expand again
3730     delete model;
3731     model = new QStandardItemModel;
3732     top = new QStandardItem("top");
3733     sub = new QStandardItem("sub");
3734     top->appendRow(sub);
3735     model->appendRow(top);
3736     view.setModel(model);
3737     view.expandAll();
3738     QApplication::processEvents();
3739     QVERIFY(view.isExpanded(top->index()));
3740
3741 }
3742
3743 void tst_QTreeView::doubleClickedWithSpans()
3744 {
3745     QTreeView view;
3746     QStandardItemModel model(1, 2);
3747     view.setModel(&model);
3748     view.setFirstColumnSpanned(0, QModelIndex(), true);
3749     view.show();
3750     QApplication::setActiveWindow(&view);
3751     QVERIFY(QTest::qWaitForWindowActive(&view));
3752     QVERIFY(view.isActiveWindow());
3753
3754     QPoint p(10, 10);
3755     QCOMPARE(view.indexAt(p), model.index(0, 0));
3756     QSignalSpy spy(&view, SIGNAL(doubleClicked(QModelIndex)));
3757     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, p);
3758     QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, p);
3759     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, p);
3760     QCOMPARE(spy.count(), 1);
3761
3762     //let's click on the 2nd column
3763     p.setX(p.x() + view.header()->sectionSize(0));
3764     QCOMPARE(view.indexAt(p), model.index(0, 0));
3765
3766     //end the previous edition
3767     QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
3768     QTest::qWait(150);
3769     QTest::mousePress(view.viewport(), Qt::LeftButton, 0, p);
3770     QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, p);
3771     QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, p);
3772     QTRY_COMPARE(spy.count(), 2);
3773 }
3774
3775 void tst_QTreeView::taskQTBUG_6450_selectAllWith1stColumnHidden()
3776 {
3777     QTreeWidget tree;
3778     tree.setSelectionMode(QAbstractItemView::MultiSelection);
3779     tree.setColumnCount(2);
3780     QList<QTreeWidgetItem *> items;
3781     const int nrRows = 10;
3782     for (int i = 0; i < nrRows; ++i) {
3783         items.append(new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item: %1").arg(i))));
3784         items.last()->setText(1, QString("is an item"));
3785     }
3786     tree.insertTopLevelItems(0, items);
3787
3788     tree.hideColumn(0);
3789     tree.selectAll();
3790
3791     QVERIFY(tree.selectionModel()->hasSelection());
3792     for (int i = 0; i < nrRows; ++i)
3793         QVERIFY(tree.selectionModel()->isRowSelected(i, QModelIndex()));
3794 }
3795
3796 class TreeViewQTBUG_9216 : public QTreeView
3797 {
3798     Q_OBJECT
3799 public:
3800     void paintEvent(QPaintEvent *event)
3801     {
3802         if (doCompare)
3803             QCOMPARE(event->rect(), viewport()->rect());
3804         QTreeView::paintEvent(event);
3805         painted++;
3806     }
3807     int painted;
3808     bool doCompare;
3809 };
3810
3811 void tst_QTreeView::taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint()
3812 {
3813     QStandardItemModel model(10, 10, this);
3814     for (int row = 0; row < 10; row++)
3815         for (int col = 0; col < 10; col++)
3816             model.setItem(row, col, new QStandardItem(QString("row %0, col %1").arg(row).arg(col)));
3817     TreeViewQTBUG_9216 view;
3818     view.setUniformRowHeights(true);
3819     view.setModel(&model);
3820     view.painted = 0;
3821     view.doCompare = false;
3822     view.show();
3823     QVERIFY(QTest::qWaitForWindowExposed(&view));
3824     QTRY_VERIFY(view.painted > 0);
3825
3826     QTest::qWait(100);  // This one is needed to make the test fail before the patch.
3827     view.painted = 0;
3828     view.doCompare = true;
3829     model.setData(model.index(0, 0), QVariant(QSize(50, 50)), Qt::SizeHintRole);
3830     QTest::qWait(100);
3831     QTRY_VERIFY(view.painted > 0);
3832 }
3833
3834 void tst_QTreeView::keyboardNavigationWithDisabled()
3835 {
3836     QWidget topLevel;
3837     QTreeView view(&topLevel);
3838     QStandardItemModel model(90, 0);
3839     for (int i = 0; i < 90; i ++) {
3840         model.setItem(i, new QStandardItem(QString::number(i)));
3841         model.item(i)->setEnabled(i%6 == 0);
3842     }
3843     view.setModel(&model);
3844
3845     view.resize(200, view.visualRect(model.index(0,0)).height()*10);
3846     topLevel.show();
3847     QApplication::setActiveWindow(&topLevel);
3848     QVERIFY(QTest::qWaitForWindowActive(&topLevel));
3849     QVERIFY(topLevel.isActiveWindow());
3850
3851     view.setCurrentIndex(model.index(1, 0));
3852     QTest::keyClick(view.viewport(), Qt::Key_Up);
3853     QCOMPARE(view.currentIndex(), model.index(0, 0));
3854     QTest::keyClick(view.viewport(), Qt::Key_Down);
3855     QCOMPARE(view.currentIndex(), model.index(6, 0));
3856     QTest::keyClick(view.viewport(), Qt::Key_PageDown);
3857     QCOMPARE(view.currentIndex(), model.index(18, 0));
3858     QTest::keyClick(view.viewport(), Qt::Key_Down);
3859     QCOMPARE(view.currentIndex(), model.index(24, 0));
3860     QTest::keyClick(view.viewport(), Qt::Key_PageUp);
3861     QCOMPARE(view.currentIndex(), model.index(12, 0));
3862     QTest::keyClick(view.viewport(), Qt::Key_Up);
3863     QCOMPARE(view.currentIndex(), model.index(6, 0));
3864 }
3865
3866 class Model_11466 : public QAbstractItemModel
3867 {
3868     Q_OBJECT
3869 public:
3870     Model_11466(QObject * /* parent */) :
3871         m_block(false)
3872     {
3873         // set up the model to have two top level items and a few others
3874         m_selectionModel = new QItemSelectionModel(this, this); // owned by this
3875
3876         connect(m_selectionModel, SIGNAL(currentChanged(const QModelIndex &,const QModelIndex &)),
3877                 this, SLOT(slotCurrentChanged(const QModelIndex &,const QModelIndex &)));
3878     };
3879
3880     int rowCount(const QModelIndex &parent) const
3881     {
3882         if (parent.isValid())
3883             return (parent.internalId() == 0) ? 4 : 0;
3884         return 2; // two top level items
3885     }
3886
3887     int columnCount(const QModelIndex & /* parent */) const
3888     {
3889         return 2;
3890     }
3891
3892     QVariant data(const QModelIndex &index, int role) const
3893     {
3894         if (role == Qt::DisplayRole && index.isValid()) {
3895             qint64 parentRowPlusOne = index.internalId();
3896             QString str;
3897             QTextStream stream(&str);
3898             if (parentRowPlusOne > 0)
3899                 stream << parentRowPlusOne << " -> " << index.row() << " : " << index.column();
3900             else
3901                 stream << index.row() << " : " << index.column();
3902             return QVariant(str);
3903         }
3904         return QVariant();
3905     }
3906
3907     QModelIndex parent(const QModelIndex &index) const
3908     {
3909         if (index.isValid()) {
3910             qint64 parentRowPlusOne = index.internalId();
3911             if (parentRowPlusOne > 0) {
3912                 int row = static_cast<int>(parentRowPlusOne - 1);
3913                 return createIndex(row, 0, (quint32)0);
3914             }
3915         }
3916         return QModelIndex();
3917     }
3918
3919     void bindView(QTreeView *view)
3920     {
3921         // sets the view to this model with a shared selection model
3922         QItemSelectionModel *oldModel = view->selectionModel();
3923         if (oldModel != m_selectionModel)
3924             delete oldModel;
3925         view->setModel(this); // this creates a new selection model for the view, but we don't want it either ...
3926         oldModel = view->selectionModel();
3927         view->setSelectionModel(m_selectionModel);
3928         delete oldModel;
3929     }
3930
3931     QModelIndex index(int row, int column, const QModelIndex &parent) const
3932     {
3933         return createIndex(row, column, parent.isValid() ? (quint32)(parent.row() + 1) : (quint32)0);
3934     }
3935
3936 public slots:
3937     void slotCurrentChanged(const QModelIndex &current,const QModelIndex &)
3938     {
3939         if (m_block)
3940             return;
3941
3942         if (current.isValid()) {
3943             int selectedRow = current.row();
3944             quint32 parentRowPlusOne = static_cast<quint32>(current.internalId());
3945
3946             for (int i = 0; i < 2; ++i) {
3947                 // announce the removal of all non top level items
3948                 beginRemoveRows(createIndex(i, 0, 0), 0, 3);
3949                 // nothing to actually do for the removal
3950                 endRemoveRows();
3951
3952                 // put them back in again
3953                 beginInsertRows(createIndex(i, 0, 0), 0, 3);
3954                 // nothing to actually do for the insertion
3955                 endInsertRows();
3956             }
3957             // reselect the current item ...
3958             QModelIndex selectedIndex = createIndex(selectedRow, 0, parentRowPlusOne);
3959
3960             m_block = true; // recursion block
3961             m_selectionModel->select(selectedIndex, QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current|QItemSelectionModel::Rows);
3962             m_selectionModel->setCurrentIndex(selectedIndex, QItemSelectionModel::NoUpdate);
3963             m_block = false;
3964         } else {
3965             m_selectionModel->clear();
3966         }
3967     }
3968
3969 private:
3970     bool m_block;
3971     QItemSelectionModel *m_selectionModel;
3972 };
3973
3974 void tst_QTreeView::taskQTBUG_11466_keyboardNavigationRegression()
3975 {
3976     QTreeView treeView;
3977     treeView.setSelectionBehavior(QAbstractItemView::SelectRows);
3978     treeView.setSelectionMode(QAbstractItemView::SingleSelection);
3979     Model_11466 model(&treeView);
3980     model.bindView(&treeView);
3981     treeView.expandAll();
3982     treeView.show();
3983     QVERIFY(QTest::qWaitForWindowExposed(&treeView));
3984
3985     QTest::keyPress(treeView.viewport(), Qt::Key_Down);
3986     QTest::qWait(10);
3987     QTRY_COMPARE(treeView.currentIndex(), treeView.selectionModel()->selection().indexes().first());
3988 }
3989
3990 void tst_QTreeView::taskQTBUG_13567_removeLastItemRegression()
3991 {
3992     QtTestModel model(200, 1);
3993
3994     QTreeView view;
3995     view.setSelectionMode(QAbstractItemView::ExtendedSelection);
3996     view.setModel(&model);
3997     view.show();
3998     QVERIFY(QTest::qWaitForWindowExposed(&view));
3999
4000     view.scrollToBottom();
4001     QTest::qWait(10);
4002     CHECK_VISIBLE(199, 0);
4003
4004     view.setCurrentIndex(model.index(199, 0));
4005     model.removeLastRow();
4006     QTest::qWait(10);
4007     QCOMPARE(view.currentIndex(), model.index(198, 0));
4008     CHECK_VISIBLE(198, 0);
4009 }
4010
4011 // From QTBUG-25333 (QTreeWidget drag crashes when there was a hidden item in tree)
4012 // The test passes simply if it doesn't crash, hence there are no calls
4013 // to QCOMPARE() or QVERIFY().
4014 // Note: define QT_BUILD_INTERNAL to run this test
4015 void tst_QTreeView::taskQTBUG_25333_adjustViewOptionsForIndex()
4016 {
4017     PublicView view;
4018     QStandardItemModel model;
4019     QStandardItem *item1 = new QStandardItem("Item1");
4020     QStandardItem *item2 = new QStandardItem("Item2");
4021     QStandardItem *item3 = new QStandardItem("Item3");
4022     QStandardItem *data1 = new QStandardItem("Data1");
4023     QStandardItem *data2 = new QStandardItem("Data2");
4024     QStandardItem *data3 = new QStandardItem("Data3");
4025
4026     // Create a treeview
4027     model.appendRow(QList<QStandardItem*>() << item1 << data1 );
4028     model.appendRow(QList<QStandardItem*>() << item2 << data2 );
4029     model.appendRow(QList<QStandardItem*>() << item3 << data3 );
4030
4031     view.setModel(&model);
4032
4033     // Hide a row
4034     view.setRowHidden(1, QModelIndex(), true);
4035     view.expandAll();
4036
4037     view.show();
4038
4039 #ifdef QT_BUILD_INTERNAL
4040     {
4041         QStyleOptionViewItemV4 option;
4042
4043         view.aiv_priv()->adjustViewOptionsForIndex(&option, model.indexFromItem(item1));
4044
4045         view.aiv_priv()->adjustViewOptionsForIndex(&option, model.indexFromItem(item3));
4046     }
4047 #endif
4048
4049 }
4050
4051
4052 QTEST_MAIN(tst_QTreeView)
4053 #include "tst_qtreeview.moc"