summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/itemviews
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets/itemviews')
-rw-r--r--tests/auto/widgets/itemviews/itemviews.pro33
-rw-r--r--tests/auto/widgets/itemviews/qabstractitemview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qabstractitemview/qabstractitemview.pro3
-rw-r--r--tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp1504
-rw-r--r--tests/auto/widgets/itemviews/qabstractproxymodel/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qabstractproxymodel/qabstractproxymodel.pro3
-rw-r--r--tests/auto/widgets/itemviews/qabstractproxymodel/tst_qabstractproxymodel.cpp449
-rw-r--r--tests/auto/widgets/itemviews/qcolumnview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qcolumnview/qcolumnview.pro6
-rw-r--r--tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp1040
-rw-r--r--tests/auto/widgets/itemviews/qdatawidgetmapper/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qdatawidgetmapper/qdatawidgetmapper.pro5
-rw-r--r--tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp411
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/dummy1
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/test0
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro20
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/test/file01.tst0
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/test/file02.tst0
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/test/file03.tst0
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/test/file04.tst0
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp698
-rw-r--r--tests/auto/widgets/itemviews/qfileiconprovider/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qfileiconprovider/qfileiconprovider.pro5
-rw-r--r--tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp181
-rw-r--r--tests/auto/widgets/itemviews/qheaderview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qheaderview/qheaderview.pro8
-rw-r--r--tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp2135
-rw-r--r--tests/auto/widgets/itemviews/qidentityproxymodel/qidentityproxymodel.pro7
-rw-r--r--tests/auto/widgets/itemviews/qidentityproxymodel/tst_qidentityproxymodel.cpp333
-rw-r--r--tests/auto/widgets/itemviews/qitemdelegate/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro6
-rw-r--r--tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp1216
-rw-r--r--tests/auto/widgets/itemviews/qitemeditorfactory/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qitemeditorfactory/qitemeditorfactory.pro5
-rw-r--r--tests/auto/widgets/itemviews/qitemeditorfactory/tst_qitemeditorfactory.cpp105
-rw-r--r--tests/auto/widgets/itemviews/qitemselectionmodel/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qitemselectionmodel/qitemselectionmodel.pro5
-rw-r--r--tests/auto/widgets/itemviews/qitemselectionmodel/tst_qitemselectionmodel.cpp2714
-rw-r--r--tests/auto/widgets/itemviews/qitemview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qitemview/qitemview.pro5
-rw-r--r--tests/auto/widgets/itemviews/qitemview/tst_qitemview.cpp928
-rw-r--r--tests/auto/widgets/itemviews/qitemview/viewstotest.cpp165
-rw-r--r--tests/auto/widgets/itemviews/qlistview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qlistview/qlistview.pro6
-rw-r--r--tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp2073
-rw-r--r--tests/auto/widgets/itemviews/qlistwidget/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qlistwidget/qlistwidget.pro6
-rw-r--r--tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp1685
-rw-r--r--tests/auto/widgets/itemviews/qsortfilterproxymodel/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qsortfilterproxymodel/qsortfilterproxymodel.pro8
-rw-r--r--tests/auto/widgets/itemviews/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp3274
-rw-r--r--tests/auto/widgets/itemviews/qstandarditem/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qstandarditem/qstandarditem.pro5
-rw-r--r--tests/auto/widgets/itemviews/qstandarditem/tst_qstandarditem.cpp1110
-rw-r--r--tests/auto/widgets/itemviews/qstandarditemmodel/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qstandarditemmodel/qstandarditemmodel.pro8
-rw-r--r--tests/auto/widgets/itemviews/qstandarditemmodel/tst_qstandarditemmodel.cpp1666
-rw-r--r--tests/auto/widgets/itemviews/qstringlistmodel/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qstringlistmodel/qmodellistener.h75
-rw-r--r--tests/auto/widgets/itemviews/qstringlistmodel/qstringlistmodel.pro8
-rw-r--r--tests/auto/widgets/itemviews/qstringlistmodel/tst_qstringlistmodel.cpp286
-rw-r--r--tests/auto/widgets/itemviews/qtableview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qtableview/qtableview.pro7
-rw-r--r--tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp4075
-rw-r--r--tests/auto/widgets/itemviews/qtablewidget/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qtablewidget/qtablewidget.pro3
-rw-r--r--tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp1500
-rw-r--r--tests/auto/widgets/itemviews/qtreeview/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qtreeview/qtreeview.pro3
-rw-r--r--tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp3942
-rw-r--r--tests/auto/widgets/itemviews/qtreewidget/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qtreewidget/qtreewidget.pro3
-rw-r--r--tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp3349
-rw-r--r--tests/auto/widgets/itemviews/qtreewidgetitemiterator/.gitignore1
-rw-r--r--tests/auto/widgets/itemviews/qtreewidgetitemiterator/qtreewidgetitemiterator.pro5
-rw-r--r--tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp1243
77 files changed, 36353 insertions, 0 deletions
diff --git a/tests/auto/widgets/itemviews/itemviews.pro b/tests/auto/widgets/itemviews/itemviews.pro
new file mode 100644
index 0000000000..fc338fdb7b
--- /dev/null
+++ b/tests/auto/widgets/itemviews/itemviews.pro
@@ -0,0 +1,33 @@
+TEMPLATE=subdirs
+SUBDIRS=\
+ qabstractitemview \
+ qabstractproxymodel \
+ qcolumnview \
+ qdatawidgetmapper \
+ qdirmodel \
+ qfileiconprovider \
+ qheaderview \
+ qidentityproxymodel \
+ qitemdelegate \
+ qitemeditorfactory \
+ qitemselectionmodel \
+ qitemview \
+ qlistview \
+ qlistwidget \
+ qsortfilterproxymodel \
+ qstandarditem \
+ qstandarditemmodel \
+ qstringlistmodel \
+ qtableview \
+ qtablewidget \
+ qtreeview \
+ qtreewidget \
+ qtreewidgetitemiterator \
+
+!contains(QT_CONFIG, private_tests): SUBDIRS -= \
+ qcolumnview \
+ qlistwidget \
+
+# This test takes too long to run on IRIX, so skip it on that platform
+irix-*:SUBDIRS -= qitemview
+
diff --git a/tests/auto/widgets/itemviews/qabstractitemview/.gitignore b/tests/auto/widgets/itemviews/qabstractitemview/.gitignore
new file mode 100644
index 0000000000..2f9f90e27e
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qabstractitemview/.gitignore
@@ -0,0 +1 @@
+tst_qabstractitemview
diff --git a/tests/auto/widgets/itemviews/qabstractitemview/qabstractitemview.pro b/tests/auto/widgets/itemviews/qabstractitemview/qabstractitemview.pro
new file mode 100644
index 0000000000..7f6c2cb65c
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qabstractitemview/qabstractitemview.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qabstractitemview.cpp
diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp
new file mode 100644
index 0000000000..b9c652f1d3
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp
@@ -0,0 +1,1504 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qabstractitemview.h>
+#include <qstandarditemmodel.h>
+#include <qapplication.h>
+#include <qlistview.h>
+#include <qlistwidget.h>
+#include <qtableview.h>
+#include <qtablewidget.h>
+#include <qtreeview.h>
+#include <qtreewidget.h>
+#include <qheaderview.h>
+#include <qspinbox.h>
+#include <qitemdelegate.h>
+#include <qpushbutton.h>
+#include <qscrollbar.h>
+#include <qboxlayout.h>
+#include <qlineedit.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+// Will try to wait for the condition while allowing event processing
+// for a maximum of 5 seconds.
+#define TRY_COMPARE(expr, expected) \
+ do { \
+ const int step = 50; \
+ for (int q = 0; q < 5000 && ((expr) != (expected)); q+=step) { \
+ QTest::qWait(step); \
+ } \
+ QCOMPARE(expr, expected); \
+ } while(0)
+
+class TestView : public QAbstractItemView
+{
+ Q_OBJECT
+public:
+ inline void tst_dataChanged(const QModelIndex &tl, const QModelIndex &br)
+ { dataChanged(tl, br); }
+ inline void tst_setHorizontalStepsPerItem(int steps)
+ { setHorizontalStepsPerItem(steps); }
+ inline int tst_horizontalStepsPerItem() const
+ { return horizontalStepsPerItem(); }
+ inline void tst_setVerticalStepsPerItem(int steps)
+ { setVerticalStepsPerItem(steps); }
+ inline int tst_verticalStepsPerItem() const
+ { return verticalStepsPerItem(); }
+
+ inline void tst_rowsInserted(const QModelIndex &parent, int start, int end)
+ { rowsInserted(parent, start, end); }
+ inline void tst_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+ { rowsAboutToBeRemoved(parent, start, end); }
+ inline void tst_selectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected)
+ { selectionChanged(selected, deselected); }
+ inline void tst_currentChanged(const QModelIndex &current, const QModelIndex &previous)
+ { currentChanged(current, previous); }
+ inline void tst_updateEditorData()
+ { updateEditorData(); }
+ inline void tst_updateEditorGeometries()
+ { updateEditorGeometries(); }
+ inline void tst_updateGeometries()
+ { updateGeometries(); }
+ inline void tst_verticalScrollbarAction(int action)
+ { verticalScrollbarAction(action); }
+ inline void tst_horizontalScrollbarAction(int action)
+ { horizontalScrollbarAction(action); }
+ inline void tst_verticalScrollbarValueChanged(int value)
+ { verticalScrollbarValueChanged(value); }
+ inline void tst_horizontalScrollbarValueChanged(int value)
+ { horizontalScrollbarValueChanged(value); }
+ inline void tst_closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
+ { closeEditor(editor, hint); }
+ inline void tst_commitData(QWidget *editor)
+ { commitData(editor); }
+ inline void tst_editorDestroyed(QObject *editor)
+ { editorDestroyed(editor); }
+ enum tst_CursorAction {
+ MoveUp = QAbstractItemView::MoveUp,
+ MoveDown = QAbstractItemView::MoveDown,
+ MoveLeft = QAbstractItemView::MoveLeft,
+ MoveRight = QAbstractItemView::MoveRight,
+ MoveHome = QAbstractItemView::MoveHome,
+ MoveEnd = QAbstractItemView::MoveEnd,
+ MovePageUp = QAbstractItemView::MovePageUp,
+ MovePageDown = QAbstractItemView::MovePageDown,
+ MoveNext = QAbstractItemView::MoveNext,
+ MovePrevious = QAbstractItemView::MovePrevious
+ };
+ inline QModelIndex tst_moveCursor(tst_CursorAction cursorAction,
+ Qt::KeyboardModifiers modifiers)
+ { return moveCursor(QAbstractItemView::CursorAction(cursorAction), modifiers); }
+ inline int tst_horizontalOffset() const
+ { return horizontalOffset(); }
+ inline int tst_verticalOffset() const
+ { return verticalOffset(); }
+ inline bool tst_isIndexHidden(const QModelIndex &index) const
+ { return isIndexHidden(index); }
+ inline void tst_setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+ { setSelection(rect, command); }
+ inline QRegion tst_visualRegionForSelection(const QItemSelection &selection) const
+ { return visualRegionForSelection(selection); }
+ inline QModelIndexList tst_selectedIndexes() const
+ { return selectedIndexes(); }
+ inline bool tst_edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
+ { return edit(index, trigger, event); }
+ inline QItemSelectionModel::SelectionFlags tst_selectionCommand(const QModelIndex &index,
+ const QEvent *event = 0) const
+ { return selectionCommand(index, event); }
+#ifndef QT_NO_DRAGANDDROP
+ inline void tst_startDrag(Qt::DropActions supportedActions)
+ { startDrag(supportedActions); }
+#endif
+ inline QStyleOptionViewItem tst_viewOptions() const
+ { return viewOptions(); }
+ enum tst_State {
+ NoState = QAbstractItemView::NoState,
+ DraggingState = QAbstractItemView::DraggingState,
+ DragSelectingState = QAbstractItemView::DragSelectingState,
+ EditingState = QAbstractItemView::EditingState,
+ ExpandingState = QAbstractItemView::ExpandingState,
+ CollapsingState = QAbstractItemView::CollapsingState
+ };
+ inline tst_State tst_state() const
+ { return (tst_State)state(); }
+ inline void tst_setState(tst_State state)
+ { setState(QAbstractItemView::State(state)); }
+ inline void tst_startAutoScroll()
+ { startAutoScroll(); }
+ inline void tst_stopAutoScroll()
+ { stopAutoScroll(); }
+ inline void tst_doAutoScroll()
+ { doAutoScroll(); }
+};
+
+class tst_QAbstractItemView : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ tst_QAbstractItemView();
+ virtual ~tst_QAbstractItemView();
+ void basic_tests(TestView *view);
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+private slots:
+ void getSetCheck();
+ void emptyModels_data();
+ void emptyModels();
+ void setModel_data();
+ void setModel();
+ void noModel();
+ void dragSelect();
+ void rowDelegate();
+ void columnDelegate();
+ void selectAll();
+ void ctrlA();
+ void persistentEditorFocus();
+ void setItemDelegate();
+ void setItemDelegate_data();
+ // The dragAndDrop() test doesn't work, and is thus disabled on Mac and Windows
+ // for the following reasons:
+ // Mac: use of GetCurrentEventButtonState() in QDragManager::drag()
+ // Win: unknown reason
+#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
+#if 0
+ void dragAndDrop();
+ void dragAndDropOnChild();
+#endif
+#endif
+ void noFallbackToRoot();
+ void setCurrentIndex_data();
+ void setCurrentIndex();
+
+ void task221955_selectedEditor();
+ void task250754_fontChange();
+ void task200665_itemEntered();
+ void task257481_emptyEditor();
+ void shiftArrowSelectionAfterScrolling();
+ void shiftSelectionAfterRubberbandSelection();
+ void ctrlRubberbandSelection();
+ void QTBUG6407_extendedSelection();
+ void QTBUG6753_selectOnSelection();
+};
+
+class MyAbstractItemDelegate : public QAbstractItemDelegate
+{
+public:
+ MyAbstractItemDelegate() : QAbstractItemDelegate() {};
+ void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const {}
+ QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(); }
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
+ const QModelIndex &) const { return new QWidget(parent); }
+};
+
+// Testing get/set functions
+void tst_QAbstractItemView::getSetCheck()
+{
+ QListView view;
+ TestView *obj1 = reinterpret_cast<TestView*>(&view);
+ // QAbstractItemDelegate * QAbstractItemView::itemDelegate()
+ // void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *)
+ MyAbstractItemDelegate *var1 = new MyAbstractItemDelegate;
+ obj1->setItemDelegate(var1);
+ QCOMPARE((QAbstractItemDelegate*)var1, obj1->itemDelegate());
+ obj1->setItemDelegate((QAbstractItemDelegate *)0);
+ QCOMPARE((QAbstractItemDelegate *)0, obj1->itemDelegate());
+ delete var1;
+
+ // EditTriggers QAbstractItemView::editTriggers()
+ // void QAbstractItemView::setEditTriggers(EditTriggers)
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers), obj1->editTriggers());
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged), obj1->editTriggers());
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked), obj1->editTriggers());
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked), obj1->editTriggers());
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed), obj1->editTriggers());
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::AnyKeyPressed));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::AnyKeyPressed), obj1->editTriggers());
+ obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::AllEditTriggers));
+ QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::AllEditTriggers), obj1->editTriggers());
+
+ // bool QAbstractItemView::tabKeyNavigation()
+ // void QAbstractItemView::setTabKeyNavigation(bool)
+ obj1->setTabKeyNavigation(false);
+ QCOMPARE(false, obj1->tabKeyNavigation());
+ obj1->setTabKeyNavigation(true);
+ QCOMPARE(true, obj1->tabKeyNavigation());
+
+ // bool QAbstractItemView::dragEnabled()
+ // void QAbstractItemView::setDragEnabled(bool)
+#ifndef QT_NO_DRAGANDDROP
+ obj1->setDragEnabled(false);
+ QCOMPARE(false, obj1->dragEnabled());
+ obj1->setDragEnabled(true);
+ QCOMPARE(true, obj1->dragEnabled());
+#endif
+ // bool QAbstractItemView::alternatingRowColors()
+ // void QAbstractItemView::setAlternatingRowColors(bool)
+ obj1->setAlternatingRowColors(false);
+ QCOMPARE(false, obj1->alternatingRowColors());
+ obj1->setAlternatingRowColors(true);
+ QCOMPARE(true, obj1->alternatingRowColors());
+
+ // State QAbstractItemView::state()
+ // void QAbstractItemView::setState(State)
+ obj1->tst_setState(TestView::tst_State(TestView::NoState));
+ QCOMPARE(TestView::tst_State(TestView::NoState), obj1->tst_state());
+ obj1->tst_setState(TestView::tst_State(TestView::DraggingState));
+ QCOMPARE(TestView::tst_State(TestView::DraggingState), obj1->tst_state());
+ obj1->tst_setState(TestView::tst_State(TestView::DragSelectingState));
+ QCOMPARE(TestView::tst_State(TestView::DragSelectingState), obj1->tst_state());
+ obj1->tst_setState(TestView::tst_State(TestView::EditingState));
+ QCOMPARE(TestView::tst_State(TestView::EditingState), obj1->tst_state());
+ obj1->tst_setState(TestView::tst_State(TestView::ExpandingState));
+ QCOMPARE(TestView::tst_State(TestView::ExpandingState), obj1->tst_state());
+ obj1->tst_setState(TestView::tst_State(TestView::CollapsingState));
+ QCOMPARE(TestView::tst_State(TestView::CollapsingState), obj1->tst_state());
+
+ // QWidget QAbstractScrollArea::viewport()
+ // void setViewport(QWidget*)
+ QWidget *vp = new QWidget;
+ obj1->setViewport(vp);
+ QCOMPARE(vp, obj1->viewport());
+
+ QCOMPARE(16, obj1->autoScrollMargin());
+ obj1->setAutoScrollMargin(20);
+ QCOMPARE(20, obj1->autoScrollMargin());
+ obj1->setAutoScrollMargin(16);
+ QCOMPARE(16, obj1->autoScrollMargin());
+}
+
+tst_QAbstractItemView::tst_QAbstractItemView()
+{
+}
+
+tst_QAbstractItemView::~tst_QAbstractItemView()
+{
+}
+
+void tst_QAbstractItemView::initTestCase()
+{
+#ifdef Q_OS_WINCE_WM
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QAbstractItemView::cleanupTestCase()
+{
+}
+
+void tst_QAbstractItemView::emptyModels_data()
+{
+ QTest::addColumn<QString>("viewType");
+
+ QTest::newRow("QListView") << "QListView";
+ QTest::newRow("QTableView") << "QTableView";
+ QTest::newRow("QTreeView") << "QTreeView";
+ QTest::newRow("QHeaderView") << "QHeaderView";
+}
+
+void tst_QAbstractItemView::emptyModels()
+{
+ QFETCH(QString, viewType);
+
+ TestView *view = 0;
+ if (viewType == "QListView")
+ view = reinterpret_cast<TestView*>(new QListView());
+ else if (viewType == "QTableView")
+ view = reinterpret_cast<TestView*>(new QTableView());
+ else if (viewType == "QTreeView")
+ view = reinterpret_cast<TestView*>(new QTreeView());
+ else if (viewType == "QHeaderView")
+ view = reinterpret_cast<TestView*>(new QHeaderView(Qt::Vertical));
+ else
+ QVERIFY(0);
+ view->show();
+
+ QVERIFY(!view->model());
+ QVERIFY(!view->selectionModel());
+ //QVERIFY(view->itemDelegate() != 0);
+
+ basic_tests(view);
+ delete view;
+}
+
+void tst_QAbstractItemView::setModel_data()
+{
+ QTest::addColumn<QString>("viewType");
+
+ QTest::newRow("QListView") << "QListView";
+ QTest::newRow("QTableView") << "QTableView";
+ QTest::newRow("QTreeView") << "QTreeView";
+ QTest::newRow("QHeaderView") << "QHeaderView";
+}
+
+void tst_QAbstractItemView::setModel()
+{
+ QFETCH(QString, viewType);
+ TestView *view = 0;
+ if (viewType == "QListView")
+ view = reinterpret_cast<TestView*>(new QListView());
+ else if (viewType == "QTableView")
+ view = reinterpret_cast<TestView*>(new QTableView());
+ else if (viewType == "QTreeView")
+ view = reinterpret_cast<TestView*>(new QTreeView());
+ else if (viewType == "QHeaderView")
+ view = reinterpret_cast<TestView*>(new QHeaderView(Qt::Vertical));
+ else
+ QVERIFY(0);
+ view->show();
+
+ QStandardItemModel model(20,20);
+ view->setModel(0);
+ view->setModel(&model);
+ basic_tests(view);
+ delete view;
+}
+
+void tst_QAbstractItemView::basic_tests(TestView *view)
+{
+ // setSelectionModel
+ // Will assert as it should
+ //view->setSelectionModel(0);
+ // setItemDelegate
+ //view->setItemDelegate(0);
+ // Will asswert as it should
+
+ // setSelectionMode
+ view->setSelectionMode(QAbstractItemView::SingleSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::SingleSelection);
+ view->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::ContiguousSelection);
+ view->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::ExtendedSelection);
+ view->setSelectionMode(QAbstractItemView::MultiSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::MultiSelection);
+ view->setSelectionMode(QAbstractItemView::NoSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::NoSelection);
+
+ // setSelectionBehavior
+ view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectItems);
+ view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectRows);
+ view->setSelectionBehavior(QAbstractItemView::SelectColumns);
+ QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectColumns);
+
+ // setEditTriggers
+ view->setEditTriggers(QAbstractItemView::EditKeyPressed);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::EditKeyPressed);
+ view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::NoEditTriggers);
+ view->setEditTriggers(QAbstractItemView::CurrentChanged);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::CurrentChanged);
+ view->setEditTriggers(QAbstractItemView::DoubleClicked);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::DoubleClicked);
+ view->setEditTriggers(QAbstractItemView::SelectedClicked);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::SelectedClicked);
+ view->setEditTriggers(QAbstractItemView::AnyKeyPressed);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::AnyKeyPressed);
+ view->setEditTriggers(QAbstractItemView::AllEditTriggers);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::AllEditTriggers);
+
+ // setAutoScroll
+ view->setAutoScroll(false);
+ QCOMPARE(view->hasAutoScroll(), false);
+ view->setAutoScroll(true);
+ QCOMPARE(view->hasAutoScroll(), true);
+
+ // setTabKeyNavigation
+ view->setTabKeyNavigation(false);
+ QCOMPARE(view->tabKeyNavigation(), false);
+ view->setTabKeyNavigation(true);
+ QCOMPARE(view->tabKeyNavigation(), true);
+
+#ifndef QT_NO_DRAGANDDROP
+ // setDropIndicatorShown
+ view->setDropIndicatorShown(false);
+ QCOMPARE(view->showDropIndicator(), false);
+ view->setDropIndicatorShown(true);
+ QCOMPARE(view->showDropIndicator(), true);
+
+ // setDragEnabled
+ view->setDragEnabled(false);
+ QCOMPARE(view->dragEnabled(), false);
+ view->setDragEnabled(true);
+ QCOMPARE(view->dragEnabled(), true);
+#endif
+
+ // setAlternatingRowColors
+ view->setAlternatingRowColors(false);
+ QCOMPARE(view->alternatingRowColors(), false);
+ view->setAlternatingRowColors(true);
+ QCOMPARE(view->alternatingRowColors(), true);
+
+ // setIconSize
+ view->setIconSize(QSize(16, 16));
+ QCOMPARE(view->iconSize(), QSize(16, 16));
+ view->setIconSize(QSize(32, 32));
+ QCOMPARE(view->iconSize(), QSize(32, 32));
+ // Should this happen?
+ view->setIconSize(QSize(-1, -1));
+ QCOMPARE(view->iconSize(), QSize(-1, -1));
+
+ QCOMPARE(view->currentIndex(), QModelIndex());
+ QCOMPARE(view->rootIndex(), QModelIndex());
+
+ view->keyboardSearch("");
+ view->keyboardSearch("foo");
+ view->keyboardSearch("1");
+
+ QCOMPARE(view->visualRect(QModelIndex()), QRect());
+
+ view->scrollTo(QModelIndex());
+
+ QCOMPARE(view->sizeHintForIndex(QModelIndex()), QSize());
+ QCOMPARE(view->indexAt(QPoint(-1, -1)), QModelIndex());
+
+ if (!view->model()){
+ QCOMPARE(view->indexAt(QPoint(10, 10)), QModelIndex());
+ QCOMPARE(view->sizeHintForRow(0), -1);
+ QCOMPARE(view->sizeHintForColumn(0), -1);
+ }else if (view->itemDelegate()){
+ view->sizeHintForRow(0);
+ view->sizeHintForColumn(0);
+ }
+ view->openPersistentEditor(QModelIndex());
+ view->closePersistentEditor(QModelIndex());
+
+ view->reset();
+ view->setRootIndex(QModelIndex());
+ view->doItemsLayout();
+ view->selectAll();
+ view->edit(QModelIndex());
+ view->clearSelection();
+ view->setCurrentIndex(QModelIndex());
+
+ // protected methods
+ view->tst_dataChanged(QModelIndex(), QModelIndex());
+ view->tst_rowsInserted(QModelIndex(), -1, -1);
+ view->tst_rowsAboutToBeRemoved(QModelIndex(), -1, -1);
+ view->tst_selectionChanged(QItemSelection(), QItemSelection());
+ if (view->model()){
+ view->tst_currentChanged(QModelIndex(), QModelIndex());
+ view->tst_currentChanged(QModelIndex(), view->model()->index(0,0));
+ }
+ view->tst_updateEditorData();
+ view->tst_updateEditorGeometries();
+ view->tst_updateGeometries();
+ view->tst_verticalScrollbarAction(QAbstractSlider::SliderSingleStepAdd);
+ view->tst_horizontalScrollbarAction(QAbstractSlider::SliderSingleStepAdd);
+ view->tst_verticalScrollbarValueChanged(10);
+ view->tst_horizontalScrollbarValueChanged(10);
+ view->tst_closeEditor(0, QAbstractItemDelegate::NoHint);
+ view->tst_commitData(0);
+ view->tst_editorDestroyed(0);
+
+ view->tst_setHorizontalStepsPerItem(2);
+ view->tst_horizontalStepsPerItem();
+ view->tst_setVerticalStepsPerItem(2);
+ view->tst_verticalStepsPerItem();
+
+ // Will assert as it should
+ // view->setIndexWidget(QModelIndex(), 0);
+
+ view->tst_moveCursor(TestView::MoveUp, Qt::NoModifier);
+ view->tst_horizontalOffset();
+ view->tst_verticalOffset();
+
+// view->tst_isIndexHidden(QModelIndex()); // will (correctly) assert
+ if(view->model())
+ view->tst_isIndexHidden(view->model()->index(0,0));
+
+ view->tst_setSelection(QRect(0, 0, 10, 10), QItemSelectionModel::ClearAndSelect);
+ view->tst_setSelection(QRect(-1, -1, -1, -1), QItemSelectionModel::ClearAndSelect);
+ view->tst_visualRegionForSelection(QItemSelection());
+ view->tst_selectedIndexes();
+
+ view->tst_edit(QModelIndex(), QAbstractItemView::NoEditTriggers, 0);
+
+ view->tst_selectionCommand(QModelIndex(), 0);
+
+#ifndef QT_NO_DRAGANDDROP
+ if (!view->model())
+ view->tst_startDrag(Qt::CopyAction);
+
+ view->tst_viewOptions();
+
+ view->tst_setState(TestView::NoState);
+ QVERIFY(view->tst_state()==TestView::NoState);
+ view->tst_setState(TestView::DraggingState);
+ QVERIFY(view->tst_state()==TestView::DraggingState);
+ view->tst_setState(TestView::DragSelectingState);
+ QVERIFY(view->tst_state()==TestView::DragSelectingState);
+ view->tst_setState(TestView::EditingState);
+ QVERIFY(view->tst_state()==TestView::EditingState);
+ view->tst_setState(TestView::ExpandingState);
+ QVERIFY(view->tst_state()==TestView::ExpandingState);
+ view->tst_setState(TestView::CollapsingState);
+ QVERIFY(view->tst_state()==TestView::CollapsingState);
+#endif
+
+ view->tst_startAutoScroll();
+ view->tst_stopAutoScroll();
+ view->tst_doAutoScroll();
+
+ // testing mouseFoo and key functions
+// QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0,0));
+// mouseMove(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
+// QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
+// QTest::mouseClick(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
+// mouseDClick(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
+// QTest::keyClick(view, Qt::Key_A);
+}
+
+void tst_QAbstractItemView::noModel()
+{
+ // From task #85415
+
+ QStandardItemModel model(20,20);
+ QTreeView view;
+
+ view.setModel(&model);
+ // Make the viewport smaller than the contents, so that we can scroll
+ view.resize(100,100);
+ view.show();
+
+ // make sure that the scrollbars are not at value 0
+ view.scrollTo(view.model()->index(10,10));
+ QApplication::processEvents();
+
+ view.setModel(0);
+ // Due to the model is removed, this will generate a valueChanged signal on both scrollbars. (value to 0)
+ QApplication::processEvents();
+ QCOMPARE(view.model(), (QAbstractItemModel*)0);
+}
+
+void tst_QAbstractItemView::dragSelect()
+{
+ // From task #86108
+
+ QStandardItemModel model(64,64);
+
+ QTableView view;
+ view.setModel(&model);
+ view.setVisible(true);
+
+ const int delay = 2;
+ for (int i = 0; i < 2; ++i) {
+ bool tracking = (i == 1);
+ view.setMouseTracking(false);
+ QTest::mouseMove(&view, QPoint(0, 0), delay);
+ view.setMouseTracking(tracking);
+ QTest::mouseMove(&view, QPoint(50, 50), delay);
+ QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
+ }
+}
+
+void tst_QAbstractItemView::rowDelegate()
+{
+ QStandardItemModel model(4,4);
+ MyAbstractItemDelegate delegate;
+
+ QTableView view;
+ view.setModel(&model);
+ view.setItemDelegateForRow(3, &delegate);
+ view.show();
+
+ QModelIndex index = model.index(3, 0);
+ view.openPersistentEditor(index);
+ QWidget *w = view.indexWidget(index);
+ QVERIFY(w);
+ QCOMPARE(w->metaObject()->className(), "QWidget");
+}
+
+void tst_QAbstractItemView::columnDelegate()
+{
+ QStandardItemModel model(4,4);
+ MyAbstractItemDelegate delegate;
+
+ QTableView view;
+ view.setModel(&model);
+ view.setItemDelegateForColumn(3, &delegate);
+ view.show();
+
+ QModelIndex index = model.index(0, 3);
+ view.openPersistentEditor(index);
+ QWidget *w = view.indexWidget(index);
+ QVERIFY(w);
+ QCOMPARE(w->metaObject()->className(), "QWidget");
+}
+
+void tst_QAbstractItemView::selectAll()
+{
+ QStandardItemModel model(4,4);
+ QTableView view;
+ view.setModel(&model);
+
+ TestView *tst_view = (TestView*)&view;
+
+ QCOMPARE(tst_view->tst_selectedIndexes().count(), 0);
+ view.selectAll();
+ QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4);
+}
+
+void tst_QAbstractItemView::ctrlA()
+{
+ QStandardItemModel model(4,4);
+ QTableView view;
+ view.setModel(&model);
+
+ TestView *tst_view = (TestView*)&view;
+
+ QCOMPARE(tst_view->tst_selectedIndexes().count(), 0);
+ QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
+ QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4);
+}
+
+void tst_QAbstractItemView::persistentEditorFocus()
+{
+ // one row, three columns
+ QStandardItemModel model(1, 3);
+ for(int i = 0; i < model.columnCount(); ++i)
+ model.setData(model.index(0, i), i);
+ QTableView view;
+ view.setModel(&model);
+
+ view.openPersistentEditor(model.index(0, 1));
+ view.openPersistentEditor(model.index(0, 2));
+
+ //these are spinboxes because we put numbers inside
+ QList<QSpinBox*> list = qFindChildren<QSpinBox*>(view.viewport());
+ QCOMPARE(list.count(), 2); //these should be the 2 editors
+
+ view.setCurrentIndex(model.index(0, 0));
+ QCOMPARE(view.currentIndex(), model.index(0, 0));
+ view.show();
+ QTRY_VERIFY(view.isVisible());
+
+ for (int i = 0; i < list.count(); ++i) {
+ TRY_COMPARE(list.at(i)->isVisible(), true);
+ QPoint p = QPoint(5, 5);
+ QMouseEvent mouseEvent(QEvent::MouseButtonPress, p, Qt::LeftButton,
+ Qt::LeftButton, Qt::NoModifier);
+ qApp->sendEvent(list.at(i), &mouseEvent);
+ if (!qApp->focusWidget())
+ QSKIP("Some window managers don't handle focus that well", SkipAll);
+ QTRY_COMPARE(qApp->focusWidget(), static_cast<QWidget *>(list.at(i)));
+ }
+}
+
+
+#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
+
+#if 0
+
+static void sendMouseMove(QWidget *widget, QPoint pos = QPoint())
+{
+ if (pos.isNull())
+ pos = widget->rect().center();
+ QMouseEvent event(QEvent::MouseMove, pos, widget->mapToGlobal(pos), Qt::NoButton, 0, 0);
+ QCursor::setPos(widget->mapToGlobal(pos));
+ qApp->processEvents();
+#if defined(Q_WS_X11)
+ qt_x11_wait_for_window_manager(widget);
+#endif
+ QApplication::sendEvent(widget, &event);
+}
+
+static void sendMousePress(
+ QWidget *widget, QPoint pos = QPoint(), Qt::MouseButton button = Qt::LeftButton)
+{
+ if (pos.isNull())
+ pos = widget->rect().center();
+ QMouseEvent event(QEvent::MouseButtonPress, pos, widget->mapToGlobal(pos), button, 0, 0);
+ QApplication::sendEvent(widget, &event);
+}
+
+static void sendMouseRelease(
+ QWidget *widget, QPoint pos = QPoint(), Qt::MouseButton button = Qt::LeftButton)
+{
+ if (pos.isNull())
+ pos = widget->rect().center();
+ QMouseEvent event(QEvent::MouseButtonRelease, pos, widget->mapToGlobal(pos), button, 0, 0);
+ QApplication::sendEvent(widget, &event);
+}
+
+class DnDTestModel : public QStandardItemModel
+{
+ Q_OBJECT
+ bool dropMimeData(const QMimeData *md, Qt::DropAction action, int r, int c, const QModelIndex &p)
+ {
+ dropAction_result = action;
+ QStandardItemModel::dropMimeData(md, action, r, c, p);
+ return true;
+ }
+ Qt::DropActions supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; }
+
+ Qt::DropAction dropAction_result;
+public:
+ DnDTestModel() : QStandardItemModel(20, 20), dropAction_result(Qt::IgnoreAction) {
+ for (int i = 0; i < rowCount(); ++i)
+ setData(index(i, 0), QString("%1").arg(i));
+ }
+ Qt::DropAction dropAction() const { return dropAction_result; }
+};
+
+class DnDTestView : public QTreeView
+{
+ Q_OBJECT
+
+ QPoint dropPoint;
+ Qt::DropAction dropAction;
+
+ void dragEnterEvent(QDragEnterEvent *event)
+ {
+ QAbstractItemView::dragEnterEvent(event);
+ }
+
+ void dropEvent(QDropEvent *event)
+ {
+ event->setDropAction(dropAction);
+ QTreeView::dropEvent(event);
+ }
+
+ void timerEvent(QTimerEvent *event)
+ {
+ killTimer(event->timerId());
+ sendMouseMove(this, dropPoint);
+ sendMouseRelease(this);
+ }
+
+ void mousePressEvent(QMouseEvent *e)
+ {
+ QTreeView::mousePressEvent(e);
+
+ startTimer(0);
+ setState(DraggingState);
+ startDrag(dropAction);
+ }
+
+public:
+ DnDTestView(Qt::DropAction dropAction, QAbstractItemModel *model)
+ : dropAction(dropAction)
+ {
+ header()->hide();
+ setModel(model);
+ setDragDropMode(QAbstractItemView::DragDrop);
+ setAcceptDrops(true);
+ setDragEnabled(true);
+ }
+
+ void dragAndDrop(QPoint drag, QPoint drop)
+ {
+ dropPoint = drop;
+ setCurrentIndex(indexAt(drag));
+ sendMousePress(viewport(), drag);
+ }
+};
+
+class DnDTestWidget : public QWidget
+{
+ Q_OBJECT
+
+ Qt::DropAction dropAction_request;
+ Qt::DropAction dropAction_result;
+ QWidget *dropTarget;
+
+ void timerEvent(QTimerEvent *event)
+ {
+ killTimer(event->timerId());
+ sendMouseMove(dropTarget);
+ sendMouseRelease(dropTarget);
+ }
+
+ void mousePressEvent(QMouseEvent *)
+ {
+ QDrag *drag = new QDrag(this);
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setData("application/x-qabstractitemmodeldatalist", QByteArray(""));
+ drag->setMimeData(mimeData);
+ startTimer(0);
+ dropAction_result = drag->start(dropAction_request);
+ }
+
+public:
+ Qt::DropAction dropAction() const { return dropAction_result; }
+
+ void dragAndDrop(QWidget *dropTarget, Qt::DropAction dropAction)
+ {
+ this->dropTarget = dropTarget;
+ dropAction_request = dropAction;
+ sendMousePress(this);
+ }
+};
+
+void tst_QAbstractItemView::dragAndDrop()
+{
+ // From Task 137729
+
+#ifdef Q_WS_QWS
+ QSKIP("Embedded drag-and-drop not good enough yet...", SkipAll);
+#endif
+
+ const int attempts = 10;
+ int successes = 0;
+ for (int i = 0; i < attempts; ++i) {
+ Qt::DropAction dropAction = Qt::MoveAction;
+
+ DnDTestModel model;
+ DnDTestView view(dropAction, &model);
+ DnDTestWidget widget;
+
+ const int size = 200;
+ widget.setFixedSize(size, size);
+ view.setFixedSize(size, size);
+
+ widget.move(0, 0);
+ view.move(int(size * 1.5), int(size * 1.5));
+
+ widget.show();
+ view.show();
+#if defined(Q_WS_X11)
+ qt_x11_wait_for_window_manager(&widget);
+ qt_x11_wait_for_window_manager(&view);
+#endif
+
+ widget.dragAndDrop(&view, dropAction);
+ if (model.dropAction() == dropAction
+ && widget.dropAction() == dropAction)
+ ++successes;
+ }
+
+ if (successes < attempts) {
+ QString msg = QString("# successes (%1) < # attempts (%2)").arg(successes).arg(attempts);
+ QWARN(msg.toLatin1());
+ }
+ QVERIFY(successes > 0); // allow for some "event unstability" (i.e. unless
+ // successes == 0, QAbstractItemView is probably ok!)
+}
+
+void tst_QAbstractItemView::dragAndDropOnChild()
+{
+#ifdef Q_WS_QWS
+ QSKIP("Embedded drag-and-drop not good enough yet...", SkipAll);
+#endif
+
+ const int attempts = 10;
+ int successes = 0;
+ for (int i = 0; i < attempts; ++i) {
+ Qt::DropAction dropAction = Qt::MoveAction;
+
+ DnDTestModel model;
+ QModelIndex parent = model.index(0, 0);
+ model.insertRow(0, parent);
+ model.insertColumn(0, parent);
+ QModelIndex child = model.index(0, 0, parent);
+ model.setData(child, "child");
+ QCOMPARE(model.rowCount(parent), 1);
+ DnDTestView view(dropAction, &model);
+ view.setExpanded(parent, true);
+ view.setDragDropMode(QAbstractItemView::InternalMove);
+
+ const int size = 200;
+ view.setFixedSize(size, size);
+ view.move(int(size * 1.5), int(size * 1.5));
+ view.show();
+#if defined(Q_WS_X11)
+ qt_x11_wait_for_window_manager(&view);
+#endif
+
+ view.dragAndDrop(view.visualRect(parent).center(),
+ view.visualRect(child).center());
+ if (model.dropAction() == dropAction)
+ ++successes;
+ }
+
+ QVERIFY(successes == 0);
+}
+
+#endif // 0
+#endif // !Q_OS_MAC && !Q_OS_WIN
+
+class TestModel : public QStandardItemModel
+{
+public:
+ TestModel(int rows, int columns) : QStandardItemModel(rows, columns)
+ {
+ setData_count = 0;
+ }
+
+ virtual bool setData(const QModelIndex &/*index*/, const QVariant &/*value*/, int /*role = Qt::EditRole*/)
+ {
+ ++setData_count;
+ return true;
+ }
+
+ int setData_count;
+};
+
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
+
+void tst_QAbstractItemView::setItemDelegate_data()
+{
+ // default is rows, a -1 will switch to columns
+ QTest::addColumn<IntList>("rowsOrColumnsWithDelegate");
+ QTest::addColumn<QPoint>("cellToEdit");
+ QTest::newRow("4 columndelegates")
+ << (IntList() << -1 << 0 << 1 << 2 << 3)
+ << QPoint(0, 0);
+ QTest::newRow("2 identical rowdelegates on the same row")
+ << (IntList() << 0 << 0)
+ << QPoint(0, 0);
+ QTest::newRow("2 identical columndelegates on the same column")
+ << (IntList() << -1 << 2 << 2)
+ << QPoint(2, 0);
+ QTest::newRow("2 duplicate delegates, 1 row and 1 column")
+ << (IntList() << 0 << -1 << 2)
+ << QPoint(2, 0);
+ QTest::newRow("4 duplicate delegates, 2 row and 2 column")
+ << (IntList() << 0 << 0 << -1 << 2 << 2)
+ << QPoint(2, 0);
+
+}
+
+void tst_QAbstractItemView::setItemDelegate()
+{
+ QFETCH(IntList, rowsOrColumnsWithDelegate);
+ QFETCH(QPoint, cellToEdit);
+ QTableView v;
+ QItemDelegate *delegate = new QItemDelegate(&v);
+ TestModel model(5, 5);
+ v.setModel(&model);
+
+ bool row = true;
+ foreach (int rc, rowsOrColumnsWithDelegate) {
+ if (rc == -1) {
+ row = !row;
+ } else {
+ if (row) {
+ v.setItemDelegateForRow(rc, delegate);
+ } else {
+ v.setItemDelegateForColumn(rc, delegate);
+ }
+ }
+ }
+ v.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&v);
+ QCursor::setPos(v.geometry().center());
+ QApplication::syncX();
+#endif
+ QTest::qWait(20);
+ QApplication::setActiveWindow(&v);
+
+ QModelIndex index = model.index(cellToEdit.y(), cellToEdit.x());
+ v.edit(index);
+
+ // This will close the editor
+ TRY_COMPARE(QApplication::focusWidget() == 0, false);
+ QWidget *editor = QApplication::focusWidget();
+ QVERIFY(editor);
+ editor->hide();
+ delete editor;
+ QCOMPARE(model.setData_count, 1);
+ delete delegate;
+}
+
+void tst_QAbstractItemView::noFallbackToRoot()
+{
+ QStandardItemModel model(0, 1);
+ for (int i = 0; i < 5; ++i)
+ model.appendRow(new QStandardItem("top" + QString::number(i)));
+ QStandardItem *par1 = model.item(1);
+ for (int j = 0; j < 15; ++j)
+ par1->appendRow(new QStandardItem("sub" + QString::number(j)));
+ QStandardItem *par2 = par1->child(2);
+ for (int k = 0; k < 10; ++k)
+ par2->appendRow(new QStandardItem("bot" + QString::number(k)));
+ QStandardItem *it1 = par2->child(5);
+
+ QModelIndex parent1 = model.indexFromItem(par1);
+ QModelIndex parent2 = model.indexFromItem(par2);
+ QModelIndex item1 = model.indexFromItem(it1);
+
+ QTreeView v;
+ v.setModel(&model);
+ v.setRootIndex(parent1);
+ v.setCurrentIndex(item1);
+ QCOMPARE(v.currentIndex(), item1);
+ QVERIFY(model.removeRows(0, 10, parent2));
+ QCOMPARE(v.currentIndex(), parent2);
+ QVERIFY(model.removeRows(0, 15, parent1));
+ QCOMPARE(v.currentIndex(), QModelIndex());
+}
+
+void tst_QAbstractItemView::setCurrentIndex_data()
+{
+ QTest::addColumn<QString>("viewType");
+ QTest::addColumn<int>("itemFlags");
+ QTest::addColumn<bool>("result");
+
+ QStringList widgets;
+ widgets << "QListView" << "QTreeView" << "QHeaderView" << "QTableView";
+
+ foreach(QString widget, widgets) {
+ QTest::newRow((widget+QLatin1String(": no flags")).toLocal8Bit().constData())
+ << widget << (int)0 << false;
+ QTest::newRow((widget+QLatin1String(": checkable")).toLocal8Bit().constData())
+ << widget << (int)Qt::ItemIsUserCheckable << false;
+ QTest::newRow((widget+QLatin1String(": selectable")).toLocal8Bit().constData())
+ << widget << (int)Qt::ItemIsSelectable << false;
+ QTest::newRow((widget+QLatin1String(": enabled")).toLocal8Bit().constData())
+ << widget << (int)Qt::ItemIsEnabled << true;
+ QTest::newRow((widget+QLatin1String(": enabled|selectable")).toLocal8Bit().constData())
+ << widget << (int)(Qt::ItemIsSelectable|Qt::ItemIsEnabled) << true;
+ }
+}
+
+void tst_QAbstractItemView::setCurrentIndex()
+{
+ QFETCH(QString, viewType);
+ QFETCH(int, itemFlags);
+ QFETCH(bool, result);
+
+ TestView *view = 0;
+ if (viewType == "QListView")
+ view = reinterpret_cast<TestView*>(new QListView());
+ else if (viewType == "QTableView")
+ view = reinterpret_cast<TestView*>(new QTableView());
+ else if (viewType == "QTreeView")
+ view = reinterpret_cast<TestView*>(new QTreeView());
+ else if (viewType == "QHeaderView")
+ view = reinterpret_cast<TestView*>(new QHeaderView(Qt::Vertical));
+ else
+ QVERIFY(0);
+ view->show();
+
+ QStandardItemModel *model = new QStandardItemModel(view);
+ QStandardItem *item = new QStandardItem("first item");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ model->appendRow(item);
+
+ item = new QStandardItem("test item");
+ item->setFlags(Qt::ItemFlags(itemFlags));
+ model->appendRow(item);
+
+ view->setModel(model);
+
+ view->setCurrentIndex(model->index(0,0));
+ QVERIFY(view->currentIndex() == model->index(0,0));
+ view->setCurrentIndex(model->index(1,0));
+ QVERIFY(view->currentIndex() == model->index(result ? 1 : 0,0));
+
+ delete view;
+}
+
+void tst_QAbstractItemView::task221955_selectedEditor()
+{
+ QPushButton *button;
+
+ QTreeWidget tree;
+ tree.setColumnCount(2);
+
+ tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Foo" <<"1"));
+ tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Bar" <<"2"));
+ tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Baz" <<"3"));
+
+ QTreeWidgetItem *dummy = new QTreeWidgetItem();
+ tree.addTopLevelItem(dummy);
+ tree.setItemWidget(dummy, 0, button = new QPushButton("More..."));
+ button->setAutoFillBackground(true); // as recommended in doc
+
+ tree.show();
+ tree.setFocus();
+ tree.setCurrentIndex(tree.model()->index(1,0));
+ QTest::qWait(100);
+ QApplication::setActiveWindow(&tree);
+
+ QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
+
+ //We set the focus to the button, the index need to be selected
+ button->setFocus();
+ QTest::qWait(100);
+ QVERIFY(tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
+
+ tree.setCurrentIndex(tree.model()->index(1,0));
+ QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
+
+ //Same thing but with the flag NoSelection, nothing can be selected.
+ tree.setFocus();
+ tree.setSelectionMode(QAbstractItemView::NoSelection);
+ tree.clearSelection();
+ QVERIFY(tree.selectionModel()->selectedIndexes().isEmpty());
+ QTest::qWait(10);
+ button->setFocus();
+ QTest::qWait(50);
+ QVERIFY(tree.selectionModel()->selectedIndexes().isEmpty());
+}
+
+void tst_QAbstractItemView::task250754_fontChange()
+{
+ QString app_css = qApp->styleSheet();
+ qApp->setStyleSheet("/* */");
+
+ QWidget w;
+ QTreeView tree(&w);
+ QVBoxLayout *vLayout = new QVBoxLayout(&w);
+ vLayout->addWidget(&tree);
+
+ QStandardItemModel *m = new QStandardItemModel(this);
+ for (int i=0; i<5; ++i) {
+ QStandardItem *item = new QStandardItem(QString("Item number %1").arg(i));
+ for (int j=0; j<5; ++j) {
+ QStandardItem *child = new QStandardItem(QString("Child Item number %1").arg(j));
+ item->setChild(j, 0, child);
+ }
+ m->setItem(i, 0, item);
+ }
+ tree.setModel(m);
+
+ w.show();
+ w.resize(150,240);
+ QTest::qWait(30);
+ QFont font = tree.font();
+ font.setPixelSize(10);
+ tree.setFont(font);
+ QTRY_VERIFY(!tree.verticalScrollBar()->isVisible());
+
+ font.setPixelSize(60);
+ tree.setFont(font);
+ //now with the huge items, the scrollbar must be visible
+ QTRY_VERIFY(tree.verticalScrollBar()->isVisible());
+
+ qApp->setStyleSheet(app_css);
+}
+
+void tst_QAbstractItemView::task200665_itemEntered()
+{
+#ifdef Q_OS_WINCE_WM
+ QSKIP("On Windows Mobile the mouse tracking is unavailable at the moment", SkipAll);
+#endif
+ //we test that view will emit entered
+ //when the scrollbar move but not the mouse itself
+ QStandardItemModel model(1000,1);
+ QListView view;
+ view.setModel(&model);
+ view.show();
+ QTest::qWait(200);
+ QRect rect = view.visualRect(model.index(0,0));
+ QCursor::setPos( view.viewport()->mapToGlobal(rect.center()) );
+ QSignalSpy spy(&view, SIGNAL(entered(QModelIndex)));
+ view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum());
+
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QAbstractItemView::task257481_emptyEditor()
+{
+ QIcon icon = qApp->style()->standardIcon(QStyle::SP_ComputerIcon);
+
+ QStandardItemModel model;
+
+ model.appendRow( new QStandardItem(icon, QString()) );
+ model.appendRow( new QStandardItem(icon, "Editor works") );
+ model.appendRow( new QStandardItem( QString() ) );
+
+ QTreeView treeView;
+ treeView.setRootIsDecorated(false);
+ treeView.setModel(&model);
+ treeView.show();
+
+ treeView.edit(model.index(0,0));
+ QList<QLineEdit *> lineEditors = qFindChildren<QLineEdit *>(treeView.viewport());
+ QCOMPARE(lineEditors.count(), 1);
+ QVERIFY(!lineEditors.first()->size().isEmpty());
+
+ QTest::qWait(30);
+
+ treeView.edit(model.index(1,0));
+ lineEditors = qFindChildren<QLineEdit *>(treeView.viewport());
+ QCOMPARE(lineEditors.count(), 1);
+ QVERIFY(!lineEditors.first()->size().isEmpty());
+
+ QTest::qWait(30);
+
+ treeView.edit(model.index(2,0));
+ lineEditors = qFindChildren<QLineEdit *>(treeView.viewport());
+ QCOMPARE(lineEditors.count(), 1);
+ QVERIFY(!lineEditors.first()->size().isEmpty());
+}
+
+void tst_QAbstractItemView::shiftArrowSelectionAfterScrolling()
+{
+ QStandardItemModel model;
+ for (int i=0; i<10; ++i) {
+ QStandardItem *item = new QStandardItem(QString("%1").arg(i));
+ model.setItem(i, 0, item);
+ }
+
+ QListView view;
+ view.setFixedSize(150, 250);
+ view.setFlow(QListView::LeftToRight);
+ view.setGridSize(QSize(100, 100));
+ view.setSelectionMode(QListView::ExtendedSelection);
+ view.setViewMode(QListView::IconMode);
+ view.setModel(&model);
+ view.show();
+ QTest::qWait(30);
+
+ QModelIndex index0 = model.index(0, 0);
+ QModelIndex index1 = model.index(1, 0);
+ QModelIndex index9 = model.index(9, 0);
+
+ view.selectionModel()->setCurrentIndex(index0, QItemSelectionModel::NoUpdate);
+ QCOMPARE(view.currentIndex(), index0);
+
+ view.scrollTo(index9);
+ QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier);
+
+ QCOMPARE(view.currentIndex(), index1);
+ QModelIndexList selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 2);
+ QVERIFY(selected.contains(index0));
+ QVERIFY(selected.contains(index1));
+}
+
+void tst_QAbstractItemView::shiftSelectionAfterRubberbandSelection()
+{
+ QStandardItemModel model;
+ for (int i=0; i<3; ++i) {
+ QStandardItem *item = new QStandardItem(QString("%1").arg(i));
+ model.setItem(i, 0, item);
+ }
+
+ QListView view;
+ view.setFixedSize(150, 450);
+ view.setFlow(QListView::LeftToRight);
+ view.setGridSize(QSize(100, 100));
+ view.setSelectionMode(QListView::ExtendedSelection);
+ view.setViewMode(QListView::IconMode);
+ view.setModel(&model);
+ view.show();
+ QTest::qWait(30);
+
+ QModelIndex index0 = model.index(0, 0);
+ QModelIndex index1 = model.index(1, 0);
+ QModelIndex index2 = model.index(2, 0);
+
+ view.setCurrentIndex(index0);
+ QCOMPARE(view.currentIndex(), index0);
+
+ // Determine the points where the rubberband selection starts and ends
+ QPoint pressPos = view.visualRect(index1).bottomRight() + QPoint(1, 1);
+ QPoint releasePos = view.visualRect(index1).center();
+ QVERIFY(!view.indexAt(pressPos).isValid());
+ QCOMPARE(view.indexAt(releasePos), index1);
+
+ // Select item 1 using a rubberband selection
+ // The mouse move event has to be created manually because the QTest framework does not
+ // contain a function for mouse moves with buttons pressed
+ QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos);
+ QMouseEvent moveEvent(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
+ bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent);
+ QVERIFY(moveEventReceived);
+ QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos);
+ QCOMPARE(view.currentIndex(), index1);
+
+ // Shift-click item 2
+ QPoint item2Pos = view.visualRect(index2).center();
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, item2Pos);
+ QCOMPARE(view.currentIndex(), index2);
+
+ // Verify that the selection worked OK
+ QModelIndexList selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 2);
+ QVERIFY(selected.contains(index1));
+ QVERIFY(selected.contains(index2));
+
+ // Select item 0 to revert the selection
+ view.setCurrentIndex(index0);
+ QCOMPARE(view.currentIndex(), index0);
+
+ // Repeat the same steps as above, but with a Shift-Arrow selection
+ QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos);
+ QMouseEvent moveEvent2(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
+ moveEventReceived = qApp->notify(view.viewport(), &moveEvent2);
+ QVERIFY(moveEventReceived);
+ QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos);
+ QCOMPARE(view.currentIndex(), index1);
+
+ // Press Shift-Down
+ QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier);
+ QCOMPARE(view.currentIndex(), index2);
+
+ // Verify that the selection worked OK
+ selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 2);
+ QVERIFY(selected.contains(index1));
+ QVERIFY(selected.contains(index2));
+}
+
+void tst_QAbstractItemView::ctrlRubberbandSelection()
+{
+ QStandardItemModel model;
+ for (int i=0; i<3; ++i) {
+ QStandardItem *item = new QStandardItem(QString("%1").arg(i));
+ model.setItem(i, 0, item);
+ }
+
+ QListView view;
+ view.setFixedSize(150, 450);
+ view.setFlow(QListView::LeftToRight);
+ view.setGridSize(QSize(100, 100));
+ view.setSelectionMode(QListView::ExtendedSelection);
+ view.setViewMode(QListView::IconMode);
+ view.setModel(&model);
+ view.show();
+ QTest::qWait(30);
+
+ QModelIndex index1 = model.index(1, 0);
+ QModelIndex index2 = model.index(2, 0);
+
+ // Select item 1
+ view.setCurrentIndex(index1);
+ QModelIndexList selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 1);
+ QVERIFY(selected.contains(index1));
+
+ // Now press control and draw a rubberband around items 1 and 2.
+ // The mouse move event has to be created manually because the QTest framework does not
+ // contain a function for mouse moves with buttons pressed.
+ QPoint pressPos = view.visualRect(index1).topLeft() - QPoint(1, 1);
+ QPoint releasePos = view.visualRect(index2).bottomRight() + QPoint(1, 1);
+ QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, pressPos);
+ QMouseEvent moveEvent(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
+ bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent);
+ QVERIFY(moveEventReceived);
+ QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, releasePos);
+
+ // Verify that item 2 is selected now
+ selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 1);
+ QVERIFY(selected.contains(index2));
+}
+
+void tst_QAbstractItemView::QTBUG6407_extendedSelection()
+{
+ QListWidget view;
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ for(int i = 0; i < 50; ++i)
+ view.addItem(QString::number(i));
+
+ QFont font = view.font();
+ font.setPixelSize(10);
+ view.setFont(font);
+ view.resize(200,240);
+
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
+
+ view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum());
+ QTest::qWait(20);
+
+ QModelIndex index49 = view.model()->index(49,0);
+ QPoint p = view.visualRect(index49).center();
+ QVERIFY(view.viewport()->rect().contains(p));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
+ QCOMPARE(view.currentIndex(), index49);
+ QCOMPARE(view.selectedItems().count(), 1);
+
+ QModelIndex index47 = view.model()->index(47,0);
+ p = view.visualRect(index47).center();
+ QVERIFY(view.viewport()->rect().contains(p));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, p);
+ QCOMPARE(view.currentIndex(), index47);
+ QCOMPARE(view.selectedItems().count(), 3); //49, 48, 47;
+
+ QModelIndex index44 = view.model()->index(44,0);
+ p = view.visualRect(index44).center();
+ QVERIFY(view.viewport()->rect().contains(p));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, p);
+ QCOMPARE(view.currentIndex(), index44);
+ QCOMPARE(view.selectedItems().count(), 6); //49 .. 44;
+
+}
+
+void tst_QAbstractItemView::QTBUG6753_selectOnSelection()
+{
+ QTableWidget table(5, 5);
+ for (int i = 0; i < table.rowCount(); ++i)
+ for (int j = 0; j < table.columnCount(); ++j)
+ table.setItem(i, j, new QTableWidgetItem("choo-be-doo-wah"));
+
+ table.show();
+ table.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ table.selectAll();
+ QTest::qWaitForWindowShown(&table);
+ QModelIndex item = table.model()->index(1,1);
+ QRect itemRect = table.visualRect(item);
+ QTest::mouseMove(table.viewport(), itemRect.center());
+ QTest::mouseClick(table.viewport(), Qt::LeftButton, Qt::NoModifier, itemRect.center());
+ QTest::qWait(20);
+
+ QCOMPARE(table.selectedItems().count(), 1);
+ QCOMPARE(table.selectedItems().first(), table.item(item.row(), item.column()));
+}
+
+QTEST_MAIN(tst_QAbstractItemView)
+#include "tst_qabstractitemview.moc"
diff --git a/tests/auto/widgets/itemviews/qabstractproxymodel/.gitignore b/tests/auto/widgets/itemviews/qabstractproxymodel/.gitignore
new file mode 100644
index 0000000000..bffc04d632
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qabstractproxymodel/.gitignore
@@ -0,0 +1 @@
+tst_qabstractproxymodel
diff --git a/tests/auto/widgets/itemviews/qabstractproxymodel/qabstractproxymodel.pro b/tests/auto/widgets/itemviews/qabstractproxymodel/qabstractproxymodel.pro
new file mode 100644
index 0000000000..7a6a841796
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qabstractproxymodel/qabstractproxymodel.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qabstractproxymodel.cpp
diff --git a/tests/auto/widgets/itemviews/qabstractproxymodel/tst_qabstractproxymodel.cpp b/tests/auto/widgets/itemviews/qabstractproxymodel/tst_qabstractproxymodel.cpp
new file mode 100644
index 0000000000..b6557c45ec
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qabstractproxymodel/tst_qabstractproxymodel.cpp
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qabstractproxymodel.h>
+#include <QItemSelection>
+#include <qstandarditemmodel.h>
+
+class tst_QAbstractProxyModel : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void qabstractproxymodel_data();
+ void qabstractproxymodel();
+ void data_data();
+ void data();
+ void flags_data();
+ void flags();
+ void headerData_data();
+ void headerData();
+ void itemData_data();
+ void itemData();
+ void mapFromSource_data();
+ void mapFromSource();
+ void mapSelectionFromSource_data();
+ void mapSelectionFromSource();
+ void mapSelectionToSource_data();
+ void mapSelectionToSource();
+ void mapToSource_data();
+ void mapToSource();
+ void revert_data();
+ void revert();
+ void setSourceModel_data();
+ void setSourceModel();
+ void submit_data();
+ void submit();
+ void testRoleNames();
+};
+
+// Subclass that exposes the protected functions.
+class SubQAbstractProxyModel : public QAbstractProxyModel
+{
+public:
+ // QAbstractProxyModel::mapFromSource is a pure virtual function.
+ QModelIndex mapFromSource(QModelIndex const& sourceIndex) const
+ { Q_UNUSED(sourceIndex); return QModelIndex(); }
+
+ // QAbstractProxyModel::mapToSource is a pure virtual function.
+ QModelIndex mapToSource(QModelIndex const& proxyIndex) const
+ { Q_UNUSED(proxyIndex); return QModelIndex(); }
+
+ QModelIndex index(int, int, const QModelIndex&) const
+ {
+ return QModelIndex();
+ }
+
+ QModelIndex parent(const QModelIndex&) const
+ {
+ return QModelIndex();
+ }
+
+ int rowCount(const QModelIndex&) const
+ {
+ return 0;
+ }
+
+ int columnCount(const QModelIndex&) const
+ {
+ return 0;
+ }
+};
+
+// This will be called before the first test function is executed.
+// It is only called once.
+void tst_QAbstractProxyModel::initTestCase()
+{
+}
+
+// This will be called after the last test function is executed.
+// It is only called once.
+void tst_QAbstractProxyModel::cleanupTestCase()
+{
+}
+
+// This will be called before each test function is executed.
+void tst_QAbstractProxyModel::init()
+{
+}
+
+// This will be called after every test function.
+void tst_QAbstractProxyModel::cleanup()
+{
+}
+
+void tst_QAbstractProxyModel::qabstractproxymodel_data()
+{
+}
+
+void tst_QAbstractProxyModel::qabstractproxymodel()
+{
+ SubQAbstractProxyModel model;
+ model.data(QModelIndex());
+ model.flags(QModelIndex());
+ model.headerData(0, Qt::Vertical, 0);
+ model.itemData(QModelIndex());
+ model.mapFromSource(QModelIndex());
+ model.mapSelectionFromSource(QItemSelection());
+ model.mapSelectionToSource(QItemSelection());
+ model.mapToSource(QModelIndex());
+ model.revert();
+ model.setSourceModel(0);
+ QCOMPARE(model.sourceModel(), (QAbstractItemModel*)0);
+ model.submit();
+}
+
+Q_DECLARE_METATYPE(QVariant)
+Q_DECLARE_METATYPE(QModelIndex)
+void tst_QAbstractProxyModel::data_data()
+{
+ QTest::addColumn<QModelIndex>("proxyIndex");
+ QTest::addColumn<int>("role");
+ QTest::addColumn<QVariant>("data");
+ QTest::newRow("null") << QModelIndex() << 0 << QVariant();
+}
+
+// public QVariant data(QModelIndex const& proxyIndex, int role = Qt::DisplayRole) const
+void tst_QAbstractProxyModel::data()
+{
+ QFETCH(QModelIndex, proxyIndex);
+ QFETCH(int, role);
+ QFETCH(QVariant, data);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.data(proxyIndex, role), data);
+}
+
+Q_DECLARE_METATYPE(Qt::ItemFlags)
+void tst_QAbstractProxyModel::flags_data()
+{
+ QTest::addColumn<QModelIndex>("index");
+ QTest::addColumn<Qt::ItemFlags>("flags");
+ QTest::newRow("null") << QModelIndex() << (Qt::ItemFlags)0;
+}
+
+// public Qt::ItemFlags flags(QModelIndex const& index) const
+void tst_QAbstractProxyModel::flags()
+{
+ QFETCH(QModelIndex, index);
+ QFETCH(Qt::ItemFlags, flags);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.flags(index), flags);
+}
+
+Q_DECLARE_METATYPE(Qt::Orientation)
+Q_DECLARE_METATYPE(Qt::ItemDataRole)
+void tst_QAbstractProxyModel::headerData_data()
+{
+ QTest::addColumn<int>("section");
+ QTest::addColumn<Qt::Orientation>("orientation");
+ QTest::addColumn<Qt::ItemDataRole>("role");
+ QTest::addColumn<QVariant>("headerData");
+ QTest::newRow("null") << 0 << Qt::Vertical << Qt::UserRole << QVariant();
+}
+
+// public QVariant headerData(int section, Qt::Orientation orientation, int role) const
+void tst_QAbstractProxyModel::headerData()
+{
+ QFETCH(int, section);
+ QFETCH(Qt::Orientation, orientation);
+ QFETCH(Qt::ItemDataRole, role);
+ QFETCH(QVariant, headerData);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.headerData(section, orientation, role), headerData);
+}
+
+void tst_QAbstractProxyModel::itemData_data()
+{
+ QTest::addColumn<QModelIndex>("index");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("null") << QModelIndex() << 0;
+}
+
+// public QMap<int,QVariant> itemData(QModelIndex const& index) const
+void tst_QAbstractProxyModel::itemData()
+{
+ QFETCH(QModelIndex, index);
+ QFETCH(int, count);
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.itemData(index).count(), count);
+}
+
+void tst_QAbstractProxyModel::mapFromSource_data()
+{
+ QTest::addColumn<QModelIndex>("sourceIndex");
+ QTest::addColumn<QModelIndex>("mapFromSource");
+ QTest::newRow("null") << QModelIndex() << QModelIndex();
+}
+
+// public QModelIndex mapFromSource(QModelIndex const& sourceIndex) const
+void tst_QAbstractProxyModel::mapFromSource()
+{
+ QFETCH(QModelIndex, sourceIndex);
+ QFETCH(QModelIndex, mapFromSource);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.mapFromSource(sourceIndex), mapFromSource);
+}
+
+Q_DECLARE_METATYPE(QItemSelection)
+void tst_QAbstractProxyModel::mapSelectionFromSource_data()
+{
+ QTest::addColumn<QItemSelection>("selection");
+ QTest::addColumn<QItemSelection>("mapSelectionFromSource");
+ QTest::newRow("null") << QItemSelection() << QItemSelection();
+ QTest::newRow("empty") << QItemSelection(QModelIndex(), QModelIndex()) << QItemSelection(QModelIndex(), QModelIndex());
+}
+
+// public QItemSelection mapSelectionFromSource(QItemSelection const& selection) const
+void tst_QAbstractProxyModel::mapSelectionFromSource()
+{
+ QFETCH(QItemSelection, selection);
+ QFETCH(QItemSelection, mapSelectionFromSource);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.mapSelectionFromSource(selection), mapSelectionFromSource);
+}
+
+void tst_QAbstractProxyModel::mapSelectionToSource_data()
+{
+ QTest::addColumn<QItemSelection>("selection");
+ QTest::addColumn<QItemSelection>("mapSelectionToSource");
+ QTest::newRow("null") << QItemSelection() << QItemSelection();
+ QTest::newRow("empty") << QItemSelection(QModelIndex(), QModelIndex()) << QItemSelection(QModelIndex(), QModelIndex());
+}
+
+// public QItemSelection mapSelectionToSource(QItemSelection const& selection) const
+void tst_QAbstractProxyModel::mapSelectionToSource()
+{
+ QFETCH(QItemSelection, selection);
+ QFETCH(QItemSelection, mapSelectionToSource);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.mapSelectionToSource(selection), mapSelectionToSource);
+}
+
+void tst_QAbstractProxyModel::mapToSource_data()
+{
+ QTest::addColumn<QModelIndex>("proxyIndex");
+ QTest::addColumn<QModelIndex>("mapToSource");
+ QTest::newRow("null") << QModelIndex() << QModelIndex();
+}
+
+// public QModelIndex mapToSource(QModelIndex const& proxyIndex) const
+void tst_QAbstractProxyModel::mapToSource()
+{
+ QFETCH(QModelIndex, proxyIndex);
+ QFETCH(QModelIndex, mapToSource);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.mapToSource(proxyIndex), mapToSource);
+}
+
+void tst_QAbstractProxyModel::revert_data()
+{
+ //QTest::addColumn<int>("foo");
+ //QTest::newRow("null") << 0;
+}
+
+// public void revert()
+void tst_QAbstractProxyModel::revert()
+{
+ //QFETCH(int, foo);
+
+ SubQAbstractProxyModel model;
+ model.revert();
+}
+
+void tst_QAbstractProxyModel::setSourceModel_data()
+{
+ //QTest::addColumn<int>("sourceModelCount");
+ //QTest::newRow("null") << 0;
+}
+
+// public void setSourceModel(QAbstractItemModel* sourceModel)
+void tst_QAbstractProxyModel::setSourceModel()
+{
+ //QFETCH(int, sourceModelCount);
+
+ SubQAbstractProxyModel model;
+ QStandardItemModel *sourceModel = new QStandardItemModel(&model);
+ model.setSourceModel(sourceModel);
+ QCOMPARE(model.sourceModel(), static_cast<QAbstractItemModel*>(sourceModel));
+
+ QStandardItemModel *sourceModel2 = new QStandardItemModel(&model);
+ model.setSourceModel(sourceModel2);
+ QCOMPARE(model.sourceModel(), static_cast<QAbstractItemModel*>(sourceModel2));
+
+ delete sourceModel2;
+ QCOMPARE(model.sourceModel(), static_cast<QAbstractItemModel*>(0));
+}
+
+void tst_QAbstractProxyModel::submit_data()
+{
+ QTest::addColumn<bool>("submit");
+ QTest::newRow("null") << true;
+}
+
+// public bool submit()
+void tst_QAbstractProxyModel::submit()
+{
+ QFETCH(bool, submit);
+
+ SubQAbstractProxyModel model;
+ QCOMPARE(model.submit(), submit);
+}
+
+class StandardItemModelWithCustomRoleNames : public QStandardItemModel
+{
+public:
+ enum CustomRole {
+ CustomRole1 = Qt::UserRole,
+ CustomRole2
+ };
+
+ StandardItemModelWithCustomRoleNames() {
+ QHash<int, QByteArray> _roleNames = roleNames();
+ _roleNames.insert(CustomRole1, "custom1");
+ _roleNames.insert(CustomRole2, "custom2");
+ setRoleNames(_roleNames);
+ }
+};
+
+class AnotherStandardItemModelWithCustomRoleNames : public QStandardItemModel
+{
+ public:
+ enum CustomRole {
+ AnotherCustomRole1 = Qt::UserRole + 10, // Different to StandardItemModelWithCustomRoleNames::CustomRole1
+ AnotherCustomRole2
+ };
+
+ AnotherStandardItemModelWithCustomRoleNames() {
+ QHash<int, QByteArray> _roleNames = roleNames();
+ _roleNames.insert(AnotherCustomRole1, "another_custom1");
+ _roleNames.insert(AnotherCustomRole2, "another_custom2");
+ setRoleNames(_roleNames);
+ }
+};
+
+/**
+ Verifies that @p subSet is a subset of @p superSet. That is, all keys in @p subSet exist in @p superSet and have the same values.
+*/
+static void verifySubSetOf(const QHash<int, QByteArray> &superSet, const QHash<int, QByteArray> &subSet)
+{
+ QHash<int, QByteArray>::const_iterator it = subSet.constBegin();
+ const QHash<int, QByteArray>::const_iterator end = subSet.constEnd();
+ for ( ; it != end; ++it ) {
+ QVERIFY(superSet.contains(it.key()));
+ QVERIFY(it.value() == superSet.value(it.key()));
+ }
+}
+
+void tst_QAbstractProxyModel::testRoleNames()
+{
+ QStandardItemModel defaultModel;
+ StandardItemModelWithCustomRoleNames model;
+ QHash<int, QByteArray> rootModelRoleNames = model.roleNames();
+ QHash<int, QByteArray> defaultModelRoleNames = defaultModel.roleNames();
+
+ verifySubSetOf( rootModelRoleNames, defaultModelRoleNames);
+ QVERIFY( rootModelRoleNames.size() == defaultModelRoleNames.size() + 2 );
+ QVERIFY( rootModelRoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole1));
+ QVERIFY( rootModelRoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole2));
+ QVERIFY( rootModelRoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole1) == "custom1" );
+ QVERIFY( rootModelRoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole2) == "custom2" );
+
+ SubQAbstractProxyModel proxy1;
+ proxy1.setSourceModel(&model);
+ QHash<int, QByteArray> proxy1RoleNames = proxy1.roleNames();
+ verifySubSetOf( proxy1RoleNames, defaultModelRoleNames );
+ QVERIFY( proxy1RoleNames.size() == defaultModelRoleNames.size() + 2 );
+ QVERIFY( proxy1RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole1));
+ QVERIFY( proxy1RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole2));
+ QVERIFY( proxy1RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole1) == "custom1" );
+ QVERIFY( proxy1RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole2) == "custom2" );
+
+ SubQAbstractProxyModel proxy2;
+ proxy2.setSourceModel(&proxy1);
+ QHash<int, QByteArray> proxy2RoleNames = proxy2.roleNames();
+ verifySubSetOf( proxy2RoleNames, defaultModelRoleNames );
+ QVERIFY( proxy2RoleNames.size() == defaultModelRoleNames.size() + 2 );
+ QVERIFY( proxy2RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole1));
+ QVERIFY( proxy2RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole2));
+ QVERIFY( proxy2RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole1) == "custom1" );
+ QVERIFY( proxy2RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole2) == "custom2" );
+
+}
+
+QTEST_MAIN(tst_QAbstractProxyModel)
+#include "tst_qabstractproxymodel.moc"
+
diff --git a/tests/auto/widgets/itemviews/qcolumnview/.gitignore b/tests/auto/widgets/itemviews/qcolumnview/.gitignore
new file mode 100644
index 0000000000..580ca0edad
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qcolumnview/.gitignore
@@ -0,0 +1 @@
+tst_qcolumnview
diff --git a/tests/auto/widgets/itemviews/qcolumnview/qcolumnview.pro b/tests/auto/widgets/itemviews/qcolumnview/qcolumnview.pro
new file mode 100644
index 0000000000..bca9e75ba5
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qcolumnview/qcolumnview.pro
@@ -0,0 +1,6 @@
+CONFIG += qttest_p4
+QT += widgets widgets-private
+QT += gui-private core-private
+
+SOURCES += tst_qcolumnview.cpp
+TARGET = tst_qcolumnview
diff --git a/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp b/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp
new file mode 100644
index 0000000000..364f917511
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp
@@ -0,0 +1,1040 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qstandarditemmodel.h>
+#include <qitemdelegate.h>
+#include <qcolumnview.h>
+#include "../../../src/widgets/itemviews/qcolumnviewgrip_p.h"
+#include "../../../src/widgets/dialogs/qfilesystemmodel_p.h"
+#include <qdirmodel.h>
+#include <qstringlistmodel.h>
+#include <qdebug.h>
+#include <qitemdelegate.h>
+#include <qscrollbar.h>
+#include <private/qcolumnview_p.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+#define ANIMATION_DELAY 300
+
+class tst_QColumnView : public QObject {
+ Q_OBJECT
+
+public:
+ tst_QColumnView();
+ virtual ~tst_QColumnView();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ void rootIndex();
+ void grips();
+ void isIndexHidden();
+ void indexAt();
+ void scrollContentsBy_data();
+ void scrollContentsBy();
+ void scrollTo_data();
+ void scrollTo();
+ void moveCursor_data();
+ void moveCursor();
+ void selectAll();
+ void clicked();
+ void selectedColumns();
+ void setSelection();
+ void setSelectionModel();
+ void visualRegionForSelection();
+
+ void dynamicModelChanges();
+
+ // grip
+ void moveGrip_basic();
+ void moveGrip_data();
+ void moveGrip();
+ void doubleClick();
+ void gripMoved();
+
+ void preview();
+ void swapPreview();
+ void sizes();
+ void rowDelegate();
+ void resize();
+ void changeSameColumn();
+ void parentCurrentIndex_data();
+ void parentCurrentIndex();
+ void pullRug_data();
+ void pullRug();
+
+protected slots:
+ void setPreviewWidget();
+};
+
+class TreeModel : public QStandardItemModel
+{
+public:
+ TreeModel()
+ {
+ for (int j = 0; j < 10; ++j) {
+ QStandardItem *parentItem = invisibleRootItem();
+ for (int i = 0; i < 10; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item);
+ QStandardItem *item2 = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item2);
+ item2->appendRow(new QStandardItem(QString("item %0").arg(i)));
+ parentItem->appendRow(new QStandardItem(QString("file %0").arg(i)));
+ parentItem = item;
+ }
+ }
+ }
+
+ inline QModelIndex firstLevel() { return index(0, 0, QModelIndex()); }
+ inline QModelIndex secondLevel() { return index(0, 0, firstLevel()); }
+ inline QModelIndex thirdLevel() { return index(0, 0, secondLevel()); }
+};
+
+class ColumnView : public QColumnView {
+
+public:
+ ColumnView(QWidget *parent = 0) : QColumnView(parent){}
+
+ QList<QPointer<QAbstractItemView> > createdColumns;
+ void ScrollContentsBy(int x, int y) {scrollContentsBy(x,y); }
+ int HorizontalOffset() const { return horizontalOffset(); }
+ void emitClicked() { emit clicked(QModelIndex()); }
+
+ enum PublicCursorAction {
+ MoveUp = QAbstractItemView::MoveUp,
+ MoveDown = QAbstractItemView::MoveDown,
+ MoveLeft = QAbstractItemView::MoveLeft,
+ MoveRight = QAbstractItemView::MoveRight,
+ MoveHome = QAbstractItemView::MoveHome,
+ MoveEnd = QAbstractItemView::MoveEnd,
+ MovePageUp = QAbstractItemView::MovePageUp,
+ MovePageDown = QAbstractItemView::MovePageDown,
+ MoveNext = QAbstractItemView::MoveNext,
+ MovePrevious = QAbstractItemView::MovePrevious
+ };
+
+ inline QModelIndex MoveCursor(PublicCursorAction ca, Qt::KeyboardModifiers kbm)
+ { return QColumnView::moveCursor((CursorAction)ca, kbm); }
+ bool IsIndexHidden(const QModelIndex&index) const
+ { return isIndexHidden(index); }
+
+ void setSelection(const QRect & rect, QItemSelectionModel::SelectionFlags command )
+ {
+ QColumnView::setSelection(rect, command);
+ }
+
+ QRegion visualRegionForSelection(QItemSelection selection){
+ return QColumnView::visualRegionForSelection(selection);
+ }
+protected:
+ QAbstractItemView *createColumn(const QModelIndex &index) {
+ QAbstractItemView *view = QColumnView::createColumn(index);
+ QPointer<QAbstractItemView> savedView = view;
+ createdColumns.append(savedView);
+ return view;
+ }
+
+};
+
+tst_QColumnView::tst_QColumnView()
+{
+}
+
+tst_QColumnView::~tst_QColumnView()
+{
+}
+
+void tst_QColumnView::init()
+{
+ qApp->setLayoutDirection(Qt::LeftToRight);
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QColumnView::cleanup()
+{
+}
+
+void tst_QColumnView::rootIndex()
+{
+ ColumnView view;
+ // no model
+ view.setRootIndex(QModelIndex());
+
+ TreeModel model;
+ view.setModel(&model);
+
+ // A top level index
+ QModelIndex drive = model.firstLevel();
+ QVERIFY(view.visualRect(drive).isValid());
+ view.setRootIndex(QModelIndex());
+ QCOMPARE(view.HorizontalOffset(), 0);
+ QCOMPARE(view.rootIndex(), QModelIndex());
+ QVERIFY(view.visualRect(drive).isValid());
+
+ // A item under the rootIndex exists
+ QModelIndex home = model.thirdLevel();
+ QModelIndex homeFile = model.index(0, 0, home);
+ int i = 0;
+ while (i < model.rowCount(home) - 1 && !model.hasChildren(homeFile))
+ homeFile = model.index(++i, 0, home);
+ view.setRootIndex(home);
+ QCOMPARE(view.HorizontalOffset(), 0);
+ QCOMPARE(view.rootIndex(), home);
+ QVERIFY(!view.visualRect(drive).isValid());
+ QVERIFY(!view.visualRect(home).isValid());
+ if (homeFile.isValid())
+ QVERIFY(view.visualRect(homeFile).isValid());
+
+ // set root when there already is one and everything should still be ok
+ view.setRootIndex(home);
+ view.setCurrentIndex(homeFile);
+ view.scrollTo(model.index(0,0, homeFile));
+ QCOMPARE(view.HorizontalOffset(), 0);
+ QCOMPARE(view.rootIndex(), home);
+ QVERIFY(!view.visualRect(drive).isValid());
+ QVERIFY(!view.visualRect(home).isValid());
+ if (homeFile.isValid())
+ QVERIFY(view.visualRect(homeFile).isValid());
+
+ //
+ homeFile = model.thirdLevel();
+ home = homeFile.parent();
+ view.setRootIndex(home);
+ view.setCurrentIndex(homeFile);
+ view.show();
+ i = 0;
+ QModelIndex two = model.index(0, 0, homeFile);
+ while (i < model.rowCount(homeFile) - 1 && !model.hasChildren(two))
+ two = model.index(++i, 0, homeFile);
+ qApp->processEvents();
+ QTest::qWait(ANIMATION_DELAY);
+ view.setCurrentIndex(two);
+ view.scrollTo(two);
+ QTest::qWait(ANIMATION_DELAY);
+ qApp->processEvents();
+ QVERIFY(two.isValid());
+ QVERIFY(view.HorizontalOffset() != 0);
+
+ view.setRootIndex(homeFile);
+ QCOMPARE(view.HorizontalOffset(), 0);
+}
+
+void tst_QColumnView::grips()
+{
+ QColumnView view;
+ QDirModel model;
+ view.setModel(&model);
+ QCOMPARE(view.resizeGripsVisible(), true);
+
+ view.setResizeGripsVisible(true);
+ QCOMPARE(view.resizeGripsVisible(), true);
+
+ {
+ const QObjectList list = view.viewport()->children();
+ for (int i = 0 ; i < list.count(); ++i) {
+ if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(list.at(i)))
+ QVERIFY(view->cornerWidget() != 0);
+ }
+ }
+ view.setResizeGripsVisible(false);
+ QCOMPARE(view.resizeGripsVisible(), false);
+
+ {
+ const QObjectList list = view.viewport()->children();
+ for (int i = 0 ; i < list.count(); ++i) {
+ if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(list.at(i))) {
+ if (view->isVisible())
+ QVERIFY(view->cornerWidget() == 0);
+ }
+ }
+ }
+
+ view.setResizeGripsVisible(true);
+ QCOMPARE(view.resizeGripsVisible(), true);
+}
+
+void tst_QColumnView::isIndexHidden()
+{
+ ColumnView view;
+ QModelIndex idx;
+ QCOMPARE(view.IsIndexHidden(idx), false);
+ QDirModel model;
+ view.setModel(&model);
+ QCOMPARE(view.IsIndexHidden(idx), false);
+}
+
+void tst_QColumnView::indexAt()
+{
+ QColumnView view;
+ QCOMPARE(view.indexAt(QPoint(0,0)), QModelIndex());
+ QDirModel model;
+ view.setModel(&model);
+
+ QModelIndex home = model.index(QDir::homePath());
+ QModelIndex homeFile = model.index(0, 0, home);
+ if (!homeFile.isValid())
+ return;
+ view.setRootIndex(home);
+ QRect rect = view.visualRect(QModelIndex());
+ QVERIFY(!rect.isValid());
+ rect = view.visualRect(homeFile);
+ QVERIFY(rect.isValid());
+
+ QModelIndex child;
+ for (int i = 0; i < model.rowCount(home); ++i) {
+ child = model.index(i, 0, home);
+ rect = view.visualRect(child);
+ QVERIFY(rect.isValid());
+ if (i > 0)
+ QVERIFY(rect.top() > 0);
+ QCOMPARE(view.indexAt(rect.center()), child);
+
+ view.selectionModel()->select(child, QItemSelectionModel::SelectCurrent);
+ view.setCurrentIndex(child);
+ qApp->processEvents();
+ QTest::qWait(200);
+
+ // test that the second row doesn't start at 0
+ if (model.rowCount(child) > 0) {
+ child = model.index(0, 0, child);
+ QVERIFY(child.isValid());
+ rect = view.visualRect(child);
+ QVERIFY(rect.isValid());
+ QVERIFY(rect.left() > 0);
+ QCOMPARE(view.indexAt(rect.center()), child);
+ break;
+ }
+ }
+}
+
+void tst_QColumnView::scrollContentsBy_data()
+{
+ QTest::addColumn<bool>("reverse");
+ QTest::newRow("normal") << false;
+ QTest::newRow("reverse") << true;
+}
+
+void tst_QColumnView::scrollContentsBy()
+{
+ QFETCH(bool, reverse);
+ if (reverse)
+ qApp->setLayoutDirection(Qt::RightToLeft);
+ ColumnView view;
+ view.ScrollContentsBy(-1, -1);
+ view.ScrollContentsBy(0, 0);
+
+ TreeModel model;
+ view.setModel(&model);
+ view.ScrollContentsBy(0, 0);
+
+ QModelIndex home = model.thirdLevel();
+ view.setCurrentIndex(home);
+ QTest::qWait(ANIMATION_DELAY);
+ view.ScrollContentsBy(0, 0);
+}
+
+void tst_QColumnView::scrollTo_data()
+{
+ QTest::addColumn<bool>("reverse");
+ QTest::addColumn<bool>("giveFocus");
+ /// ### add test later for giveFocus == true
+ QTest::newRow("normal") << false << false;
+ QTest::newRow("reverse") << true << false;
+}
+
+void tst_QColumnView::scrollTo()
+{
+ QFETCH(bool, reverse);
+ QFETCH(bool, giveFocus);
+ if (reverse)
+ qApp->setLayoutDirection(Qt::RightToLeft);
+ QWidget topLevel;
+ ColumnView view(&topLevel);
+ view.resize(200, 200);
+ topLevel.show();
+ view.scrollTo(QModelIndex(), QAbstractItemView::EnsureVisible);
+ QCOMPARE(view.HorizontalOffset(), 0);
+
+ TreeModel model;
+ view.setModel(&model);
+ view.scrollTo(QModelIndex(), QAbstractItemView::EnsureVisible);
+
+ QModelIndex home;
+ home = model.index(0, 0, home);
+ home = model.index(0, 0, home);
+ home = model.index(0, 0, home);
+ view.scrollTo(home, QAbstractItemView::EnsureVisible);
+ QModelIndex homeFile = model.index(0, 0, home);
+ view.setRootIndex(home);
+
+ QModelIndex index = model.index(0, 0, home);
+ view.scrollTo(index, QAbstractItemView::EnsureVisible);
+ QCOMPARE(view.HorizontalOffset(), 0);
+
+ // Embedded requires that at least one widget have focus
+ QWidget w;
+ w.show();
+
+ if (giveFocus)
+ view.setFocus(Qt::OtherFocusReason);
+ else
+ view.clearFocus();
+
+ qApp->processEvents();
+ QTRY_COMPARE(view.hasFocus(), giveFocus);
+ // scroll to the right
+ int level = 0;
+ int last = view.HorizontalOffset();
+ while(model.hasChildren(index) && level < 5) {
+ view.setCurrentIndex(index);
+ QTest::qWait(ANIMATION_DELAY);
+ view.scrollTo(index, QAbstractItemView::EnsureVisible);
+ QTest::qWait(ANIMATION_DELAY);
+ qApp->processEvents();
+ index = model.index(0, 0, index);
+ level++;
+ if (level >= 2) {
+ if (!reverse) {
+ QTRY_VERIFY(view.HorizontalOffset() < 0);
+ QTRY_VERIFY(last > view.HorizontalOffset());
+ } else {
+ QTRY_VERIFY(view.HorizontalOffset() > 0);
+ QTRY_VERIFY(last < view.HorizontalOffset());
+ }
+ }
+ last = view.HorizontalOffset();
+ }
+
+ // scroll to the left
+ int start = level;
+ while(index.parent().isValid() && index != view.rootIndex()) {
+ view.setCurrentIndex(index);
+ QTest::qWait(ANIMATION_DELAY);
+ view.scrollTo(index, QAbstractItemView::EnsureVisible);
+ index = index.parent();
+ if (start != level) {
+ if (!reverse)
+ QTRY_VERIFY(last < view.HorizontalOffset());
+ else
+ QTRY_VERIFY(last > view.HorizontalOffset());
+ }
+ level--;
+ last = view.HorizontalOffset();
+ }
+ // It shouldn't automatically steal focus if it doesn't have it
+ QTRY_COMPARE(view.hasFocus(), giveFocus);
+
+ // Try scrolling to something that is above the root index
+ home = model.index(0, 0, QModelIndex());
+ QModelIndex temp = model.index(1, 0, home);
+ home = model.index(0, 0, home);
+ home = model.index(0, 0, home);
+ view.setRootIndex(home);
+ view.scrollTo(model.index(0, 0, home));
+ QTest::qWait(ANIMATION_DELAY);
+ view.scrollTo(temp);
+}
+
+void tst_QColumnView::moveCursor_data()
+{
+ QTest::addColumn<bool>("reverse");
+ QTest::newRow("normal") << false;
+ QTest::newRow("reverse") << true;
+}
+
+void tst_QColumnView::moveCursor()
+{
+ QFETCH(bool, reverse);
+ if (reverse)
+ qApp->setLayoutDirection(Qt::RightToLeft);
+ ColumnView view;
+
+ // don't crash
+ view.MoveCursor(ColumnView::MoveUp, Qt::NoModifier);
+
+ // don't do anything
+ QCOMPARE(view.MoveCursor(ColumnView::MoveEnd, Qt::NoModifier), QModelIndex());
+
+ QDirModel model;
+ view.setModel(&model);
+ QModelIndex home = model.index(QDir::homePath());
+ QModelIndex ci = view.currentIndex();
+ QCOMPARE(view.MoveCursor(ColumnView::MoveUp, Qt::NoModifier), QModelIndex());
+ QCOMPARE(view.MoveCursor(ColumnView::MoveDown, Qt::NoModifier), QModelIndex());
+
+ // left at root
+ view.setCurrentIndex(model.index(0,0));
+ ColumnView::PublicCursorAction action = reverse ? ColumnView::MoveRight : ColumnView::MoveLeft;
+ QCOMPARE(view.MoveCursor(action, Qt::NoModifier), model.index(0,0));
+
+ // left shouldn't move up
+ int i = 0;
+ ci = model.index(0, 0);
+ while (i < model.rowCount() - 1 && !model.hasChildren(ci))
+ ci = model.index(++i, 0);
+ QVERIFY(model.hasChildren(ci));
+ view.setCurrentIndex(ci);
+ action = reverse ? ColumnView::MoveRight : ColumnView::MoveLeft;
+ QCOMPARE(view.MoveCursor(action, Qt::NoModifier), ci);
+
+ // now move to the left (i.e. move over one column)
+ view.setCurrentIndex(home);
+ QCOMPARE(view.MoveCursor(action, Qt::NoModifier), home.parent());
+
+ // right
+ action = reverse ? ColumnView::MoveLeft : ColumnView::MoveRight;
+ view.setCurrentIndex(ci);
+ QModelIndex mc = view.MoveCursor(action, Qt::NoModifier);
+ QCOMPARE(mc, model.index(0,0, ci));
+
+ // next one should move down
+ QModelIndex idx = model.index(0, 0, ci);
+ while (model.hasChildren(idx) && model.rowCount(ci) > idx.row() + 1)
+ idx = idx.sibling(idx.row() + 1, idx.column());
+ view.setCurrentIndex(idx);
+ mc = view.MoveCursor(action, Qt::NoModifier);
+ QCOMPARE(mc, idx.sibling(idx.row() + 1, idx.column()));
+}
+
+void tst_QColumnView::selectAll()
+{
+ ColumnView view;
+ view.selectAll();
+
+ QDirModel model;
+ view.setModel(&model);
+ view.selectAll();
+ QVERIFY(view.selectionModel()->selectedIndexes().count() >= 0);
+
+ QModelIndex home = model.index(QDir::homePath());
+ view.setCurrentIndex(home);
+ view.selectAll();
+ QVERIFY(view.selectionModel()->selectedIndexes().count() > 0);
+
+ QModelIndex file;
+ for (int i = 0; i < model.rowCount(home); ++i)
+ if (!model.hasChildren(model.index(i, 0, home))) {
+ file = model.index(i, 0, home);
+ break;
+ }
+ view.setCurrentIndex(file);
+ view.selectAll();
+ QVERIFY(view.selectionModel()->selectedIndexes().count() > 0);
+
+ view.setCurrentIndex(QModelIndex());
+ QVERIFY(view.selectionModel()->selectedIndexes().count() == 0);
+}
+
+void tst_QColumnView::clicked()
+{
+ ColumnView view;
+
+ QDirModel model;
+ view.setModel(&model);
+ view.resize(800,300);
+ view.show();
+
+ QModelIndex home = model.index(QDir::homePath());
+ QVERIFY(home.isValid());
+ view.setCurrentIndex(home);
+ QTest::qWait(ANIMATION_DELAY);
+
+ QModelIndex parent = home.parent();
+ QVERIFY(parent.isValid());
+
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+ QSignalSpy clickedSpy(&view, SIGNAL(clicked(const QModelIndex &)));
+
+ QPoint localPoint = view.visualRect(home).center();
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, localPoint);
+ QCOMPARE(clickedSpy.count(), 1);
+ qApp->processEvents();
+
+ if (sizeof(qreal) != sizeof(double)) {
+ QSKIP("Skipped due to rounding errors", SkipAll);
+ }
+
+ for (int i = 0; i < view.createdColumns.count(); ++i) {
+ QAbstractItemView *column = view.createdColumns.at(i);
+ if (column && column->selectionModel() && (column->rootIndex() == home))
+ QVERIFY(column->selectionModel()->selectedIndexes().isEmpty());
+ }
+}
+
+void tst_QColumnView::selectedColumns()
+{
+ ColumnView view;
+ QDirModel model;
+ view.setModel(&model);
+ view.resize(800,300);
+ view.show();
+
+ QModelIndex home = model.index(QDir::homePath());
+ view.setCurrentIndex(home);
+
+ QTest::qWait(ANIMATION_DELAY);
+
+ for (int i = 0; i < view.createdColumns.count(); ++i) {
+ QAbstractItemView *column = view.createdColumns.at(i);
+ if (!column)
+ continue;
+ if (!column->rootIndex().isValid() || column->rootIndex() == home)
+ continue;
+ QTRY_VERIFY(column->currentIndex().isValid());
+ }
+}
+
+void tst_QColumnView::setSelection()
+{
+ ColumnView view;
+ // shouldn't do anything, it falls to the columns to handle this
+ QRect r;
+ view.setSelection(r, QItemSelectionModel::NoUpdate);
+}
+
+void tst_QColumnView::setSelectionModel()
+{
+ ColumnView view;
+ QDirModel model;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex home = model.index(QDir::homePath());
+ view.setCurrentIndex(home);
+ QTest::qWait(ANIMATION_DELAY);
+
+ QItemSelectionModel *selectionModel = new QItemSelectionModel(&model);
+ view.setSelectionModel(selectionModel);
+
+ bool found = false;
+ for (int i = 0; i < view.createdColumns.count(); ++i) {
+ if (view.createdColumns.at(i)->selectionModel() == selectionModel) {
+ found = true;
+ break;
+ }
+ }
+ QVERIFY(found);
+}
+
+void tst_QColumnView::visualRegionForSelection()
+{
+ ColumnView view;
+ QItemSelection emptyItemSelection;
+ QCOMPARE(QRegion(), view.visualRegionForSelection(emptyItemSelection));
+
+ // a region that isn't empty
+ QDirModel model;
+ view.setModel(&model);
+
+ // On Windows CE the home directory might actually be empty.
+#ifndef Q_OS_WINCE
+ QString location = QDir::homePath();
+#else
+ QString location = QLatin1String("/Windows");
+#endif
+
+ QModelIndex home = model.index(location);
+ QVERIFY(model.rowCount(home) > 1);
+ QItemSelection itemSelection(model.index(0, 0, home), model.index(model.rowCount(home) - 1, 0, home));
+ QVERIFY(QRegion() != view.visualRegionForSelection(itemSelection));
+}
+
+void tst_QColumnView::moveGrip_basic()
+{
+ QColumnView view;
+ QColumnViewGrip *grip = new QColumnViewGrip(&view);
+ QSignalSpy spy(grip, SIGNAL(gripMoved(int)));
+ view.setCornerWidget(grip);
+ int oldX = view.width();
+ grip->moveGrip(10);
+ QCOMPARE(oldX + 10, view.width());
+ grip->moveGrip(-10);
+ QCOMPARE(oldX, view.width());
+ grip->moveGrip(-800);
+ QVERIFY(view.width() == 0 || view.width() == 1);
+ grip->moveGrip(800);
+ view.setMinimumWidth(200);
+ grip->moveGrip(-800);
+ QCOMPARE(view.width(), 200);
+ QCOMPARE(spy.count(), 5);
+}
+
+void tst_QColumnView::moveGrip_data()
+{
+ QTest::addColumn<bool>("reverse");
+ QTest::newRow("normal") << false;
+ QTest::newRow("reverse") << true;
+}
+
+void tst_QColumnView::moveGrip()
+{
+ QFETCH(bool, reverse);
+ if (reverse)
+ qApp->setLayoutDirection(Qt::RightToLeft);
+ QWidget topLevel;
+ ColumnView view(&topLevel);
+ TreeModel model;
+ view.setModel(&model);
+ QModelIndex home = model.thirdLevel();
+ view.setCurrentIndex(home);
+ view.resize(640, 200);
+ topLevel.show();
+ QTest::qWait(ANIMATION_DELAY);
+
+ int columnNum = view.createdColumns.count() - 2;
+ QVERIFY(columnNum >= 0);
+ QObjectList list = view.createdColumns[columnNum]->children();
+ QColumnViewGrip *grip = 0;
+ for (int i = 0; i < list.count(); ++i) {
+ if ((grip = qobject_cast<QColumnViewGrip *>(list[i]))) {
+ break;
+ }
+ }
+ if (!grip)
+ return;
+
+ QAbstractItemView *column = qobject_cast<QAbstractItemView *>(grip->parent());
+ int oldX = column->width();
+ QCOMPARE(view.columnWidths().value(columnNum), oldX);
+ grip->moveGrip(10);
+ QCOMPARE(view.columnWidths().value(columnNum), (oldX + (reverse ? -10 : 10)));
+}
+
+void tst_QColumnView::doubleClick()
+{
+ QColumnView view;
+ QColumnViewGrip *grip = new QColumnViewGrip(&view);
+ QSignalSpy spy(grip, SIGNAL(gripMoved(int)));
+ view.setCornerWidget(grip);
+ view.resize(200, 200);
+ QCOMPARE(view.width(), 200);
+ QTest::mouseDClick(grip, Qt::LeftButton);
+ QCOMPARE(view.width(), view.sizeHint().width());
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QColumnView::gripMoved()
+{
+ QColumnView view;
+ QColumnViewGrip *grip = new QColumnViewGrip(&view);
+ QSignalSpy spy(grip, SIGNAL(gripMoved(int)));
+ view.setCornerWidget(grip);
+ view.move(300, 300);
+ view.resize(200, 200);
+ qApp->processEvents();
+
+ int oldWidth = view.width();
+
+ QTest::mousePress(grip, Qt::LeftButton, 0, QPoint(1,1));
+ //QTest::mouseMove(grip, QPoint(grip->globalX()+50, y));
+
+ QPoint posNew = QPoint(grip->mapToGlobal(QPoint(1,1)).x() + 65, 0);
+ QMouseEvent *event = new QMouseEvent(QEvent::MouseMove, posNew, posNew, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QCoreApplication::postEvent(grip, event);
+ QCoreApplication::processEvents();
+ QTest::mouseRelease(grip, Qt::LeftButton);
+
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(view.width(), oldWidth + 65);
+}
+
+void tst_QColumnView::preview()
+{
+ QColumnView view;
+ QCOMPARE(view.previewWidget(), (QWidget*)0);
+ TreeModel model;
+ view.setModel(&model);
+ QCOMPARE(view.previewWidget(), (QWidget*)0);
+ QModelIndex home = model.index(0, 0);
+ QVERIFY(home.isValid());
+ QVERIFY(model.hasChildren(home));
+ view.setCurrentIndex(home);
+ QCOMPARE(view.previewWidget(), (QWidget*)0);
+
+ QModelIndex file;
+ QVERIFY(model.rowCount(home) > 0);
+ for (int i = 0; i < model.rowCount(home); ++i) {
+ if (!model.hasChildren(model.index(i, 0, home))) {
+ file = model.index(i, 0, home);
+ break;
+ }
+ }
+ QVERIFY(file.isValid());
+ view.setCurrentIndex(file);
+ QVERIFY(view.previewWidget() != (QWidget*)0);
+
+ QWidget *previewWidget = new QWidget(&view);
+ view.setPreviewWidget(previewWidget);
+ QCOMPARE(view.previewWidget(), previewWidget);
+ QVERIFY(previewWidget->parent() != ((QWidget*)&view));
+ view.setCurrentIndex(home);
+
+ // previewWidget should be marked for deletion
+ QWidget *previewWidget2 = new QWidget(&view);
+ view.setPreviewWidget(previewWidget2);
+ QCOMPARE(view.previewWidget(), previewWidget2);
+}
+
+void tst_QColumnView::swapPreview()
+{
+ // swap the preview widget in updatePreviewWidget
+ QColumnView view;
+ QStringList sl;
+ sl << QLatin1String("test");
+ QStringListModel model(sl);
+ view.setModel(&model);
+ view.setCurrentIndex(view.indexAt(QPoint(1, 1)));
+ connect(&view, SIGNAL(updatePreviewWidget(const QModelIndex &)),
+ this, SLOT(setPreviewWidget()));
+ view.setCurrentIndex(view.indexAt(QPoint(1, 1)));
+ QTest::qWait(ANIMATION_DELAY);
+ qApp->processEvents();
+}
+
+void tst_QColumnView::setPreviewWidget()
+{
+ ((QColumnView*)sender())->setPreviewWidget(new QWidget);
+}
+
+void tst_QColumnView::sizes()
+{
+ QColumnView view;
+ QCOMPARE(view.columnWidths().count(), 0);
+
+ QList<int> newSizes;
+ newSizes << 10 << 4 << 50 << 6;
+
+ QList<int> visibleSizes;
+ view.setColumnWidths(newSizes);
+ QCOMPARE(view.columnWidths(), visibleSizes);
+
+ QDirModel model;
+ view.setModel(&model);
+ QModelIndex home = model.index(QDir::homePath());
+ view.setCurrentIndex(home);
+
+ QList<int> postSizes = view.columnWidths().mid(0, newSizes.count());
+ QCOMPARE(postSizes, newSizes.mid(0, postSizes.count()));
+
+ QVERIFY(view.columnWidths().count() > 1);
+ QList<int> smallerSizes;
+ smallerSizes << 6;
+ view.setColumnWidths(smallerSizes);
+ QList<int> expectedSizes = newSizes;
+ expectedSizes[0] = 6;
+ postSizes = view.columnWidths().mid(0, newSizes.count());
+ QCOMPARE(postSizes, expectedSizes.mid(0, postSizes.count()));
+}
+
+void tst_QColumnView::rowDelegate()
+{
+ ColumnView view;
+ QItemDelegate *d = new QItemDelegate;
+ view.setItemDelegateForRow(3, d);
+
+ QDirModel model;
+ view.setModel(&model);
+ for (int i = 0; i < view.createdColumns.count(); ++i) {
+ QAbstractItemView *column = view.createdColumns.at(i);
+ QCOMPARE(column->itemDelegateForRow(3), (QAbstractItemDelegate*)d);
+ }
+ delete d;
+}
+
+void tst_QColumnView::resize()
+{
+ QWidget topLevel;
+ ColumnView view(&topLevel);
+ QDirModel model;
+ view.setModel(&model);
+ view.resize(200, 200);
+
+ topLevel.show();
+ QModelIndex home = model.index(QDir::homePath()).parent();
+ view.setCurrentIndex(home);
+ QTest::qWait(ANIMATION_DELAY);
+ view.resize(200, 300);
+ QTest::qWait(ANIMATION_DELAY);
+
+ QVERIFY(view.horizontalScrollBar()->maximum() != 0);
+ view.resize(view.horizontalScrollBar()->maximum() * 10, 300);
+ QTest::qWait(ANIMATION_DELAY);
+ QVERIFY(view.horizontalScrollBar()->maximum() <= 0);
+}
+
+void tst_QColumnView::changeSameColumn()
+{
+ ColumnView view;
+ TreeModel model;
+ view.setModel(&model);
+ QModelIndex second;
+
+ QModelIndex home = model.secondLevel();
+ //index(QDir::homePath());
+ view.setCurrentIndex(home);
+ for (int i = 0; i < model.rowCount(home.parent()); ++i) {
+ QModelIndex idx = model.index(i, 0, home.parent());
+ if (model.hasChildren(idx) && idx != home) {
+ second = idx;
+ break;
+ }
+ }
+ QVERIFY(second.isValid());
+
+ QList<QPointer<QAbstractItemView> > old = view.createdColumns;
+ view.setCurrentIndex(second);
+
+ QCOMPARE(old, view.createdColumns);
+}
+
+void tst_QColumnView::parentCurrentIndex_data()
+{
+ QTest::addColumn<int>("firstRow");
+ QTest::addColumn<int>("secondRow");
+ QTest::newRow("down") << 0 << 1;
+ QTest::newRow("up") << 1 << 0;
+}
+
+void tst_QColumnView::parentCurrentIndex()
+{
+ QFETCH(int, firstRow);
+ QFETCH(int, secondRow);
+
+ ColumnView view;
+ TreeModel model;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex first;
+ QModelIndex second;
+ QModelIndex third;
+ first = model.index(0, 0, QModelIndex());
+ second = model.index(firstRow, 0, first);
+ third = model.index(0, 0, second);
+ QVERIFY(first.isValid());
+ QVERIFY(second.isValid());
+ QVERIFY(third.isValid());
+ view.setCurrentIndex(third);
+ QTest::qWait(ANIMATION_DELAY);
+ QTRY_COMPARE(view.createdColumns[0]->currentIndex(), first);
+ QTRY_COMPARE(view.createdColumns[1]->currentIndex(), second);
+ QTRY_COMPARE(view.createdColumns[2]->currentIndex(), third);
+
+ first = model.index(0, 0, QModelIndex());
+ second = model.index(secondRow, 0, first);
+ third = model.index(0, 0, second);
+ QVERIFY(first.isValid());
+ QVERIFY(second.isValid());
+ QVERIFY(third.isValid());
+ view.setCurrentIndex(third);
+ QTest::qWait(ANIMATION_DELAY);
+ QTRY_COMPARE(view.createdColumns[0]->currentIndex(), first);
+ QTRY_COMPARE(view.createdColumns[1]->currentIndex(), second);
+ QTRY_COMPARE(view.createdColumns[2]->currentIndex(), third);
+}
+
+void tst_QColumnView::pullRug_data()
+{
+ QTest::addColumn<bool>("removeModel");
+ QTest::newRow("model") << true;
+ QTest::newRow("index") << false;
+}
+
+void tst_QColumnView::pullRug()
+{
+ QFETCH(bool, removeModel);
+ ColumnView view;
+ TreeModel model;
+ view.setModel(&model);
+ QModelIndex home = model.thirdLevel();
+ view.setCurrentIndex(home);
+ if (removeModel)
+ view.setModel(0);
+ else
+ view.setCurrentIndex(QModelIndex());
+ QTest::qWait(ANIMATION_DELAY);
+ // don't crash
+}
+
+void tst_QColumnView::dynamicModelChanges()
+{
+ struct MyItemDelegate : public QItemDelegate
+ {
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+ {
+ paintedIndexes += index;
+ QItemDelegate::paint(painter, option, index);
+ }
+
+ mutable QSet<QModelIndex> paintedIndexes;
+
+ } delegate;;
+ QStandardItemModel model;
+ ColumnView view;
+ view.setModel(&model);
+ view.setItemDelegate(&delegate);
+ view.show();
+
+ QStandardItem *item = new QStandardItem(QLatin1String("item"));
+ model.appendRow(item);
+
+ QTest::qWait(200); //let the time for painting to occur
+ QCOMPARE(delegate.paintedIndexes.count(), 1);
+ QCOMPARE(*delegate.paintedIndexes.begin(), model.index(0,0));
+
+
+}
+
+
+QTEST_MAIN(tst_QColumnView)
+#include "tst_qcolumnview.moc"
+
diff --git a/tests/auto/widgets/itemviews/qdatawidgetmapper/.gitignore b/tests/auto/widgets/itemviews/qdatawidgetmapper/.gitignore
new file mode 100644
index 0000000000..9b0a1e6399
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdatawidgetmapper/.gitignore
@@ -0,0 +1 @@
+tst_qdatawidgetmapper
diff --git a/tests/auto/widgets/itemviews/qdatawidgetmapper/qdatawidgetmapper.pro b/tests/auto/widgets/itemviews/qdatawidgetmapper/qdatawidgetmapper.pro
new file mode 100644
index 0000000000..64e3b57291
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdatawidgetmapper/qdatawidgetmapper.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qdatawidgetmapper.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp b/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp
new file mode 100644
index 0000000000..7488195497
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdatawidgetmapper/tst_qdatawidgetmapper.cpp
@@ -0,0 +1,411 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+#include <QtTest/QtTest>
+
+class tst_QDataWidgetMapper: public QObject
+{
+ Q_OBJECT
+private slots:
+ void setModel();
+ void navigate();
+ void addMapping();
+ void currentIndexChanged();
+ void changingValues();
+ void setData();
+ void mappedWidgetAt();
+
+ void comboBox();
+};
+
+static QStandardItemModel *testModel(QObject *parent = 0)
+{
+ QStandardItemModel *model = new QStandardItemModel(10, 10, parent);
+
+ for (int row = 0; row < 10; ++row) {
+ for (int col = 0; col < 10; ++col)
+ model->setData(model->index(row, col), QString("item %1 %2").arg(row).arg(col));
+ }
+
+ return model;
+}
+
+void tst_QDataWidgetMapper::setModel()
+{
+ QDataWidgetMapper mapper;
+
+ QCOMPARE(mapper.model(), (QAbstractItemModel *)0);
+
+ { // let the model go out of scope firstma
+ QStandardItemModel model;
+ mapper.setModel(&model);
+ QCOMPARE(mapper.model(), static_cast<QAbstractItemModel *>(&model));
+ }
+
+ QCOMPARE(mapper.model(), (QAbstractItemModel *)0);
+
+ { // let the mapper go out of scope first
+ QStandardItemModel model2;
+ QDataWidgetMapper mapper2;
+ mapper2.setModel(&model2);
+ }
+}
+
+void tst_QDataWidgetMapper::navigate()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+
+ QLineEdit edit1;
+ QLineEdit edit2;
+ QLineEdit edit3;
+
+ mapper.addMapping(&edit1, 0);
+ mapper.toFirst();
+ mapper.addMapping(&edit2, 1);
+ mapper.addMapping(&edit3, 2);
+
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QVERIFY(edit2.text().isEmpty());
+ QVERIFY(edit3.text().isEmpty());
+ QVERIFY(mapper.submit());
+ edit2.setText(QString("item 0 1"));
+ edit3.setText(QString("item 0 2"));
+ QVERIFY(mapper.submit());
+
+ mapper.toFirst(); //this will repopulate
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QCOMPARE(edit2.text(), QString("item 0 1"));
+ QCOMPARE(edit3.text(), QString("item 0 2"));
+
+
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QCOMPARE(edit2.text(), QString("item 0 1"));
+ QCOMPARE(edit3.text(), QString("item 0 2"));
+
+ mapper.toPrevious(); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QCOMPARE(edit2.text(), QString("item 0 1"));
+ QCOMPARE(edit3.text(), QString("item 0 2"));
+
+ mapper.toNext();
+ QCOMPARE(edit1.text(), QString("item 1 0"));
+ QCOMPARE(edit2.text(), QString("item 1 1"));
+ QCOMPARE(edit3.text(), QString("item 1 2"));
+
+ mapper.toLast();
+ QCOMPARE(edit1.text(), QString("item 9 0"));
+ QCOMPARE(edit2.text(), QString("item 9 1"));
+ QCOMPARE(edit3.text(), QString("item 9 2"));
+
+ mapper.toNext(); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 9 0"));
+ QCOMPARE(edit2.text(), QString("item 9 1"));
+ QCOMPARE(edit3.text(), QString("item 9 2"));
+
+ mapper.setCurrentIndex(4);
+ QCOMPARE(edit1.text(), QString("item 4 0"));
+ QCOMPARE(edit2.text(), QString("item 4 1"));
+ QCOMPARE(edit3.text(), QString("item 4 2"));
+
+ mapper.setCurrentIndex(-1); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 4 0"));
+ QCOMPARE(edit2.text(), QString("item 4 1"));
+ QCOMPARE(edit3.text(), QString("item 4 2"));
+
+ mapper.setCurrentIndex(10); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 4 0"));
+ QCOMPARE(edit2.text(), QString("item 4 1"));
+ QCOMPARE(edit3.text(), QString("item 4 2"));
+
+ mapper.setCurrentModelIndex(QModelIndex()); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 4 0"));
+ QCOMPARE(edit2.text(), QString("item 4 1"));
+ QCOMPARE(edit3.text(), QString("item 4 2"));
+
+ mapper.setCurrentModelIndex(model->index(6, 0));
+ QCOMPARE(edit1.text(), QString("item 6 0"));
+ QCOMPARE(edit2.text(), QString("item 6 1"));
+ QCOMPARE(edit3.text(), QString("item 6 2"));
+
+ /* now try vertical navigation */
+
+ mapper.setOrientation(Qt::Vertical);
+
+ mapper.addMapping(&edit1, 0);
+ mapper.addMapping(&edit2, 1);
+ mapper.addMapping(&edit3, 2);
+
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QCOMPARE(edit2.text(), QString("item 1 0"));
+ QCOMPARE(edit3.text(), QString("item 2 0"));
+
+ mapper.toPrevious(); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QCOMPARE(edit2.text(), QString("item 1 0"));
+ QCOMPARE(edit3.text(), QString("item 2 0"));
+
+ mapper.toNext();
+ QCOMPARE(edit1.text(), QString("item 0 1"));
+ QCOMPARE(edit2.text(), QString("item 1 1"));
+ QCOMPARE(edit3.text(), QString("item 2 1"));
+
+ mapper.toLast();
+ QCOMPARE(edit1.text(), QString("item 0 9"));
+ QCOMPARE(edit2.text(), QString("item 1 9"));
+ QCOMPARE(edit3.text(), QString("item 2 9"));
+
+ mapper.toNext(); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 0 9"));
+ QCOMPARE(edit2.text(), QString("item 1 9"));
+ QCOMPARE(edit3.text(), QString("item 2 9"));
+
+ mapper.setCurrentIndex(4);
+ QCOMPARE(edit1.text(), QString("item 0 4"));
+ QCOMPARE(edit2.text(), QString("item 1 4"));
+ QCOMPARE(edit3.text(), QString("item 2 4"));
+
+ mapper.setCurrentIndex(-1); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 0 4"));
+ QCOMPARE(edit2.text(), QString("item 1 4"));
+ QCOMPARE(edit3.text(), QString("item 2 4"));
+
+ mapper.setCurrentIndex(10); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 0 4"));
+ QCOMPARE(edit2.text(), QString("item 1 4"));
+ QCOMPARE(edit3.text(), QString("item 2 4"));
+
+ mapper.setCurrentModelIndex(QModelIndex()); // should do nothing
+ QCOMPARE(edit1.text(), QString("item 0 4"));
+ QCOMPARE(edit2.text(), QString("item 1 4"));
+ QCOMPARE(edit3.text(), QString("item 2 4"));
+
+ mapper.setCurrentModelIndex(model->index(0, 6));
+ QCOMPARE(edit1.text(), QString("item 0 6"));
+ QCOMPARE(edit2.text(), QString("item 1 6"));
+ QCOMPARE(edit3.text(), QString("item 2 6"));
+}
+
+void tst_QDataWidgetMapper::addMapping()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+
+ QLineEdit edit1;
+ mapper.addMapping(&edit1, 0);
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+
+ mapper.addMapping(&edit1, 1);
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString("item 0 1"));
+
+ QCOMPARE(mapper.mappedSection(&edit1), 1);
+
+ edit1.clear();
+ mapper.removeMapping(&edit1);
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString());
+
+ {
+ QLineEdit edit2;
+ mapper.addMapping(&edit2, 2);
+ mapper.toFirst();
+ QCOMPARE(edit2.text(), QString("item 0 2"));
+ } // let the edit go out of scope
+
+ QCOMPARE(mapper.mappedWidgetAt(2), (QWidget *)0);
+ mapper.toLast();
+}
+
+void tst_QDataWidgetMapper::currentIndexChanged()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+
+ QSignalSpy spy(&mapper, SIGNAL(currentIndexChanged(int)));
+
+ mapper.toFirst();
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.takeFirst().at(0).toInt(), 0);
+
+ mapper.toNext();
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.takeFirst().at(0).toInt(), 1);
+
+ mapper.setCurrentIndex(7);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.takeFirst().at(0).toInt(), 7);
+
+ mapper.setCurrentIndex(-1);
+ QCOMPARE(spy.count(), 0);
+
+ mapper.setCurrentIndex(42);
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QDataWidgetMapper::changingValues()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+
+ QLineEdit edit1;
+ mapper.addMapping(&edit1, 0);
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+
+ QLineEdit edit2;
+ mapper.addMapping(&edit2, 0, "text");
+ mapper.toFirst();
+ QCOMPARE(edit2.text(), QString("item 0 0"));
+
+ model->setData(model->index(0, 0), QString("changed"));
+ QCOMPARE(edit1.text(), QString("changed"));
+ QCOMPARE(edit2.text(), QString("changed"));
+}
+
+void tst_QDataWidgetMapper::setData()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+
+ QLineEdit edit1;
+ QLineEdit edit2;
+ QLineEdit edit3;
+
+ mapper.addMapping(&edit1, 0);
+ mapper.addMapping(&edit2, 1);
+ mapper.addMapping(&edit3, 0, "text");
+ mapper.toFirst();
+ QCOMPARE(edit1.text(), QString("item 0 0"));
+ QCOMPARE(edit2.text(), QString("item 0 1"));
+ QCOMPARE(edit3.text(), QString("item 0 0"));
+
+ edit1.setText("new text");
+
+ mapper.submit();
+ QCOMPARE(model->data(model->index(0, 0)).toString(), QString("new text"));
+
+ edit3.setText("more text");
+
+ mapper.submit();
+ QCOMPARE(model->data(model->index(0, 0)).toString(), QString("more text"));
+}
+
+void tst_QDataWidgetMapper::comboBox()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+ mapper.setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
+
+ QComboBox readOnlyBox;
+ readOnlyBox.setEditable(false);
+ readOnlyBox.addItem("read only item 0");
+ readOnlyBox.addItem("read only item 1");
+ readOnlyBox.addItem("read only item 2");
+
+ QComboBox readWriteBox;
+ readWriteBox.setEditable(true);
+ readWriteBox.addItem("read write item 0");
+ readWriteBox.addItem("read write item 1");
+ readWriteBox.addItem("read write item 2");
+
+ // populat the combo boxes with data
+ mapper.addMapping(&readOnlyBox, 0, "currentIndex");
+ mapper.addMapping(&readWriteBox, 1, "currentText");
+ mapper.toFirst();
+
+ QCOMPARE(readOnlyBox.currentText(), QString("read only item 0"));
+ QCOMPARE(readWriteBox.currentText(), QString("read write item 0"));
+
+ // set some new values on the boxes
+ readOnlyBox.setCurrentIndex(1);
+ readWriteBox.setEditText("read write item y");
+
+ mapper.submit();
+
+ // make sure the new values are in the model
+ QCOMPARE(model->data(model->index(0, 0)).toInt(), 1);
+ QCOMPARE(model->data(model->index(0, 1)).toString(), QString("read write item y"));
+
+ // now test updating of the widgets
+ model->setData(model->index(0, 0), 2, Qt::EditRole);
+ model->setData(model->index(0, 1), QString("read write item z"), Qt::EditRole);
+
+ QCOMPARE(readOnlyBox.currentIndex(), 2);
+ QEXPECT_FAIL("", "See task 125493 and QTBUG-428", Abort);
+ QCOMPARE(readWriteBox.currentText(), QString("read write item z"));
+}
+
+void tst_QDataWidgetMapper::mappedWidgetAt()
+{
+ QDataWidgetMapper mapper;
+ QAbstractItemModel *model = testModel(&mapper);
+ mapper.setModel(model);
+
+ QLineEdit lineEdit1;
+ QLineEdit lineEdit2;
+
+ QCOMPARE(mapper.mappedWidgetAt(432312), (QWidget*)0);
+
+ mapper.addMapping(&lineEdit1, 1);
+ mapper.addMapping(&lineEdit2, 2);
+
+ QCOMPARE(mapper.mappedWidgetAt(1), static_cast<QWidget *>(&lineEdit1));
+ QCOMPARE(mapper.mappedWidgetAt(2), static_cast<QWidget *>(&lineEdit2));
+
+ mapper.addMapping(&lineEdit2, 4242);
+
+ QCOMPARE(mapper.mappedWidgetAt(2), (QWidget*)0);
+ QCOMPARE(mapper.mappedWidgetAt(4242), static_cast<QWidget *>(&lineEdit2));
+}
+
+QTEST_MAIN(tst_QDataWidgetMapper)
+#include "tst_qdatawidgetmapper.moc"
diff --git a/tests/auto/widgets/itemviews/qdirmodel/.gitignore b/tests/auto/widgets/itemviews/qdirmodel/.gitignore
new file mode 100644
index 0000000000..641c99880f
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/.gitignore
@@ -0,0 +1 @@
+tst_qdirmodel
diff --git a/tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/dummy b/tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/dummy
new file mode 100644
index 0000000000..4d6a3b44f4
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/dummy
@@ -0,0 +1 @@
+ECHO is on.
diff --git a/tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/test b/tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/dirtest/test1/test
diff --git a/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro b/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro
new file mode 100644
index 0000000000..bc4e98d6ff
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro
@@ -0,0 +1,20 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qdirmodel.cpp
+
+wince* {
+ addit.files = dirtest\\test1\\*
+ addit.path = dirtest\\test1
+ tests.files = test\\*
+ tests.path = test
+ sourceFile.files = tst_qdirmodel.cpp
+ sourceFile.path = .
+ DEPLOYMENT += addit tests sourceFile
+}
+
+wince*: {
+ DEFINES += SRCDIR=\\\"./\\\"
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD/\\\"
+}
+
diff --git a/tests/auto/widgets/itemviews/qdirmodel/test/file01.tst b/tests/auto/widgets/itemviews/qdirmodel/test/file01.tst
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/test/file01.tst
diff --git a/tests/auto/widgets/itemviews/qdirmodel/test/file02.tst b/tests/auto/widgets/itemviews/qdirmodel/test/file02.tst
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/test/file02.tst
diff --git a/tests/auto/widgets/itemviews/qdirmodel/test/file03.tst b/tests/auto/widgets/itemviews/qdirmodel/test/file03.tst
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/test/file03.tst
diff --git a/tests/auto/widgets/itemviews/qdirmodel/test/file04.tst b/tests/auto/widgets/itemviews/qdirmodel/test/file04.tst
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/test/file04.tst
diff --git a/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp b/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp
new file mode 100644
index 0000000000..70eb17b5e6
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp
@@ -0,0 +1,698 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qdirmodel.h>
+#include <qapplication.h>
+#include <qtreeview.h>
+#include <qdir.h>
+#include <qdebug.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QDirModel : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ tst_QDirModel();
+ virtual ~tst_QDirModel();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+ void getSetCheck();
+ /*
+ void construct();
+ void rowCount();
+ void columnCount();
+ void t_data();
+ void setData();
+ void hasChildren();
+ void isEditable();
+ void isDragEnabled();
+ void isDropEnabled();
+ void sort();
+ */
+ bool rowsAboutToBeRemoved_init(const QString &test_path, const QStringList &initial_files);
+ bool rowsAboutToBeRemoved_cleanup(const QString &test_path);
+ void rowsAboutToBeRemoved_data();
+ void rowsAboutToBeRemoved();
+
+ void mkdir_data();
+ void mkdir();
+
+ void rmdir_data();
+ void rmdir();
+
+ void filePath();
+
+#ifdef Q_OS_UNIX
+ void hidden();
+#endif
+
+ void fileName();
+ void fileName_data();
+ void task196768_sorting();
+ void filter();
+
+ void task244669_remove();
+
+ void roleNames_data();
+ void roleNames();
+};
+
+// Testing get/set functions
+void tst_QDirModel::getSetCheck()
+{
+ QDirModel obj1;
+ // QFileIconProvider * QDirModel::iconProvider()
+ // void QDirModel::setIconProvider(QFileIconProvider *)
+ QFileIconProvider *var1 = new QFileIconProvider;
+ obj1.setIconProvider(var1);
+ QCOMPARE(var1, obj1.iconProvider());
+ obj1.setIconProvider((QFileIconProvider *)0);
+ QCOMPARE((QFileIconProvider *)0, obj1.iconProvider());
+ delete var1;
+
+ // bool QDirModel::resolveSymlinks()
+ // void QDirModel::setResolveSymlinks(bool)
+ obj1.setResolveSymlinks(false);
+ QCOMPARE(false, obj1.resolveSymlinks());
+ obj1.setResolveSymlinks(true);
+ QCOMPARE(true, obj1.resolveSymlinks());
+
+ // bool QDirModel::lazyChildCount()
+ // void QDirModel::setLazyChildCount(bool)
+ obj1.setLazyChildCount(false);
+ QCOMPARE(false, obj1.lazyChildCount());
+ obj1.setLazyChildCount(true);
+ QCOMPARE(true, obj1.lazyChildCount());
+}
+
+
+Q_DECLARE_METATYPE(QModelIndex)
+Q_DECLARE_METATYPE(QModelIndexList)
+
+tst_QDirModel::tst_QDirModel()
+
+{
+}
+
+tst_QDirModel::~tst_QDirModel()
+{
+}
+
+void tst_QDirModel::initTestCase()
+{
+}
+
+void tst_QDirModel::cleanupTestCase()
+{
+ QDir current;
+ current.rmdir(".qtest_hidden");
+}
+
+void tst_QDirModel::init()
+{
+}
+
+void tst_QDirModel::cleanup()
+{
+}
+
+/*
+ tests
+*/
+/*
+void tst_QDirModel::construct()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ index = model.index(2, 0, index);
+ QVERIFY(index.isValid());
+ QFileInfo info(QDir::currentPath() + "/test/file03.tst");
+ QCOMPARE(model.filePath(index), info.absoluteFilePath());
+}
+
+void tst_QDirModel::rowCount()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+ QCOMPARE(model.rowCount(index), 4);
+}
+
+void tst_QDirModel::columnCount()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+ QCOMPARE(model.columnCount(index), 4);
+}
+
+void tst_QDirModel::t_data()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+ QCOMPARE(model.rowCount(index), 4);
+
+ index = model.index(2, 0, index);
+ QVERIFY(index.isValid());
+ QCOMPARE(model.data(index).toString(), QString::fromLatin1("file03.tst"));
+ QCOMPARE(model.rowCount(index), 0);
+}
+
+void tst_QDirModel::setData()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+
+ index = model.index(2, 0, index);
+ QVERIFY(index.isValid());
+ QVERIFY(!model.setData(index, "file0X.tst", Qt::EditRole));
+}
+
+void tst_QDirModel::hasChildren()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+
+ index = model.index(2, 0, index);
+ QVERIFY(index.isValid());
+ QVERIFY(!model.hasChildren(index));
+}
+
+void tst_QDirModel::isEditable()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+
+ index = model.index(2, 0, index);
+ QVERIFY(index.isValid());
+ QVERIFY(!(model.flags(index) & Qt::ItemIsEditable));
+}
+
+void tst_QDirModel::isDragEnabled()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+
+ index = model.index(2, 0, index);
+ QVERIFY(index.isValid());
+ QVERIFY(model.flags(index) & Qt::ItemIsDragEnabled);
+}
+
+void tst_QDirModel::isDropEnabled()
+{
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/test");
+ QVERIFY(index.isValid());
+
+ index = model.index(2, 0, index);
+ QVERIFY(!(model.flags(index) & Qt::ItemIsDropEnabled));
+}
+
+void tst_QDirModel::sort()
+{
+ QDirModel model;
+ QModelIndex parent = model.index(QDir::currentPath() + "/test");
+ QVERIFY(parent.isValid());
+
+ QModelIndex index = model.index(0, 0, parent);
+ QCOMPARE(model.data(index).toString(), QString::fromLatin1("file01.tst"));
+
+ index = model.index(3, 0, parent);
+ QCOMPARE(model.data(index).toString(), QString::fromLatin1("file04.tst"));
+
+ model.sort(0, Qt::DescendingOrder);
+ parent = model.index(QDir::currentPath() + "/test");
+
+ index = model.index(0, 0, parent);
+ QCOMPARE(model.data(index).toString(), QString::fromLatin1("file04.tst"));
+
+ index = model.index(3, 0, parent);
+ QCOMPARE(model.data(index).toString(), QString::fromLatin1("file01.tst"));
+}
+*/
+
+void tst_QDirModel::mkdir_data()
+{
+ QTest::addColumn<QString>("dirName"); // the directory to be made under <currentpath>/dirtest
+ QTest::addColumn<bool>("mkdirSuccess");
+ QTest::addColumn<int>("rowCount");
+
+ QTest::newRow("okDirName") << QString("test2") << true << 2;
+ QTest::newRow("existingDirName") << QString("test1") << false << 1;
+ QTest::newRow("nameWithSpace") << QString("ab cd") << true << 2;
+ QTest::newRow("emptyDirName") << QString("") << false << 1;
+ QTest::newRow("nullDirName") << QString() << false << 1;
+
+/*
+ QTest::newRow("recursiveDirName") << QString("test2/test3") << false << false;
+ QTest::newRow("singleDotDirName") << QString("./test3") << true << true;
+ QTest::newRow("outOfTreeDirName") << QString("../test4") << false << false;
+ QTest::newRow("insideTreeDirName") << QString("../dirtest/test4") << true << true;
+ QTest::newRow("insideTreeDirName2") << QString("./././././../dirtest/./../dirtest/test4") << true << true;
+ QTest::newRow("absoluteDirName") << QString(QDir::currentPath() + "/dirtest/test5") << true << true;
+ QTest::newRow("outOfTreeDirName") << QString(QDir::currentPath() + "/test5") << false << false;
+
+ // Directory names only illegal on Windows
+#ifdef Q_WS_WIN
+ QTest::newRow("illegalDirName") << QString("*") << false << false;
+ QTest::newRow("illegalDirName2") << QString("|") << false << false;
+ QTest::newRow("onlySpace") << QString(" ") << false << false;
+#endif
+ */
+}
+
+void tst_QDirModel::mkdir()
+{
+ QFETCH(QString, dirName);
+ QFETCH(bool, mkdirSuccess);
+ QFETCH(int, rowCount);
+
+ QDirModel model;
+ model.setReadOnly(false);
+
+ QModelIndex parent = model.index(SRCDIR "dirtest");
+ QVERIFY(parent.isValid());
+ QCOMPARE(model.rowCount(parent), 1); // start out with only 'test1' - in's in the depot
+
+ QModelIndex index = model.mkdir(parent, dirName);
+ bool success = index.isValid();
+ int rows = model.rowCount(parent);
+
+ if (success && !model.rmdir(index))
+ QVERIFY(QDir(SRCDIR "dirtests").rmdir(dirName));
+
+ QCOMPARE(rows, rowCount);
+ QCOMPARE(success, mkdirSuccess);
+}
+
+void tst_QDirModel::rmdir_data()
+{
+ QTest::addColumn<QString>("dirName"); // <currentpath>/dirtest/dirname
+ QTest::addColumn<bool>("rmdirSuccess");
+ QTest::addColumn<int>("rowCount");
+
+ QTest::newRow("okDirName") << QString("test2") << true << 2;
+ QTest::newRow("existingDirName") << QString("test1") << false << 1;
+ QTest::newRow("nameWithSpace") << QString("ab cd") << true << 2;
+ QTest::newRow("emptyDirName") << QString("") << false << 1;
+ QTest::newRow("nullDirName") << QString() << false << 1;
+}
+
+void tst_QDirModel::rmdir()
+{
+ QFETCH(QString, dirName);
+ QFETCH(bool, rmdirSuccess);
+ QFETCH(int, rowCount);
+
+ QDirModel model;
+ model.setReadOnly(false);
+
+ QModelIndex parent = model.index(SRCDIR "/dirtest");
+ QVERIFY(parent.isValid());
+ QCOMPARE(model.rowCount(parent), 1); // start out with only 'test1' - in's in the depot
+
+ QModelIndex index;
+ if (rmdirSuccess) {
+ index = model.mkdir(parent, dirName);
+ QVERIFY(index.isValid());
+ }
+
+ int rows = model.rowCount(parent);
+ bool success = model.rmdir(index);
+
+ if (!success) { // cleanup
+ QDir dirtests(SRCDIR "/dirtests/");
+ dirtests.rmdir(dirName);
+ }
+
+ QCOMPARE(rows, rowCount);
+ QCOMPARE(success, rmdirSuccess);
+}
+
+void tst_QDirModel::rowsAboutToBeRemoved_data()
+{
+ QTest::addColumn<QString>("test_path");
+ QTest::addColumn<QStringList>("initial_files");
+ QTest::addColumn<int>("remove_row");
+ QTest::addColumn<QStringList>("remove_files");
+ QTest::addColumn<QStringList>("expected_files");
+
+ QString test_path = "test2";
+ QStringList initial_files = (QStringList()
+ << "file1.tst"
+ << "file2.tst"
+ << "file3.tst"
+ << "file4.tst");
+
+ QTest::newRow("removeFirstRow")
+ << test_path
+ << initial_files
+ << 0
+ << (QStringList() << "file1.tst")
+ << (QStringList() << "file2.tst" << "file3.tst" << "file4.tst");
+
+ QTest::newRow("removeMiddle")
+ << test_path
+ << initial_files
+ << 1
+ << (QStringList() << "file2.tst")
+ << (QStringList() << "file1.tst" << "file3.tst" << "file4.tst");
+
+ QTest::newRow("removeLastRow")
+ << test_path
+ << initial_files
+ << 3
+ << (QStringList() << "file4.tst")
+ << (QStringList() << "file1.tst" << "file2.tst" << "file3.tst");
+
+}
+
+bool tst_QDirModel::rowsAboutToBeRemoved_init(const QString &test_path, const QStringList &initial_files)
+{
+ QString path = QDir::currentPath() + "/" + test_path;
+ if (!QDir::current().mkdir(test_path) && false) { // FIXME
+ qDebug() << "failed to create dir" << path;
+ return false;
+ }
+
+ for (int i = 0; i < initial_files.count(); ++i) {
+ QFile file(path + "/" + initial_files.at(i));
+ if (!file.open(QIODevice::WriteOnly)) {
+ qDebug() << "failed to open file" << initial_files.at(i);
+ return false;
+ }
+ if (!file.resize(1024)) {
+ qDebug() << "failed to resize file" << initial_files.at(i);
+ return false;
+ }
+ if (!file.flush()) {
+ qDebug() << "failed to flush file" << initial_files.at(i);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool tst_QDirModel::rowsAboutToBeRemoved_cleanup(const QString &test_path)
+{
+ QString path = QDir::currentPath() + "/" + test_path;
+ QDir dir(path, "*", QDir::SortFlags(QDir::Name|QDir::IgnoreCase), QDir::Files);
+ QStringList files = dir.entryList();
+
+ for (int i = 0; i < files.count(); ++i) {
+ if (!dir.remove(files.at(i))) {
+ qDebug() << "failed to remove file" << files.at(i);
+ return false;
+ }
+ }
+
+ if (!QDir::current().rmdir(test_path) && false) { // FIXME
+ qDebug() << "failed to remove dir" << test_path;
+ return false;
+ }
+
+ return true;
+}
+
+void tst_QDirModel::rowsAboutToBeRemoved()
+{
+ QFETCH(QString, test_path);
+ QFETCH(QStringList, initial_files);
+ QFETCH(int, remove_row);
+ QFETCH(QStringList, remove_files);
+ QFETCH(QStringList, expected_files);
+
+ rowsAboutToBeRemoved_cleanup(test_path); // clean up first
+ QVERIFY(rowsAboutToBeRemoved_init(test_path, initial_files));
+
+ QDirModel model;
+ model.setReadOnly(false);
+
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+
+ // NOTE: QDirModel will call refresh() when a file is removed. refresh() will reread the entire directory,
+ // and emit layoutAboutToBeChanged and layoutChange. So, instead of checking for
+ // rowsAboutToBeRemoved/rowsRemoved we check for layoutAboutToBeChanged/layoutChanged
+ QSignalSpy spy(&model, SIGNAL(layoutAboutToBeChanged()));
+
+ QModelIndex parent = model.index(test_path);
+ QVERIFY(parent.isValid());
+
+ // remove the file
+ {
+ QModelIndex index = model.index(remove_row, 0, parent);
+ QVERIFY(index.isValid());
+ QVERIFY(model.remove(index));
+ }
+
+ QCOMPARE(spy.count(), 1);
+
+ // Compare the result
+ for (int row = 0; row < expected_files.count(); ++row) {
+ QModelIndex index = model.index(row, 0, parent);
+ QString str = index.data().toString();
+ QCOMPARE(str, expected_files.at(row));
+ }
+
+ QVERIFY(rowsAboutToBeRemoved_cleanup(test_path));
+}
+
+#ifdef Q_OS_UNIX
+void tst_QDirModel::hidden()
+{
+ QDir current;
+ current.mkdir(".qtest_hidden");
+
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/.qtest_hidden");
+ //QVERIFY(!index.isValid()); // hidden items are not listed, but if you specify a valid path, it will give a valid index
+
+ current.mkdir(".qtest_hidden/qtest_visible");
+ QModelIndex index2 = model.index(QDir::currentPath() + "/.qtest_hidden/qtest_visible");
+ QVERIFY(index2.isValid());
+
+ QDirModel model2;
+ model2.setFilter(model2.filter() | QDir::Hidden);
+ index = model2.index(QDir::currentPath() + "/.qtest_hidden");
+ QVERIFY(index.isValid());
+}
+#endif
+
+void tst_QDirModel::fileName_data()
+{
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("result");
+
+ QTest::newRow("invalid") << "" << "";
+ //QTest::newRow("root") << "/" << "/";
+ //QTest::newRow("home") << "/home" << "home";
+ // TODO add symlink test too
+}
+
+void tst_QDirModel::fileName()
+{
+ QDirModel model;
+
+ QFETCH(QString, path);
+ QFETCH(QString, result);
+ QCOMPARE(model.fileName(model.index(path)), result);
+}
+
+#if 0
+#ifdef Q_OS_UNIX
+void tst_QDirModel::unreadable()
+{
+ //QFile current("qtest_unreadable");
+ //QVERIFY(current.setPermissions(QFile::WriteOwner));
+
+ QDirModel model;
+ QModelIndex index = model.index(QDir::currentPath() + "/qtest_unreadable");
+ QVERIFY(!index.isValid());
+
+ QDirModel model2;
+ model2.setFilter(model2.filter() | QDir::Hidden);
+ index = model2.index(QDir::currentPath() + "/qtest_unreadable");
+ QVERIFY(index.isValid());
+}
+#endif
+#endif
+
+void tst_QDirModel::filePath()
+{
+ QFile::remove(SRCDIR "test.lnk");
+ QVERIFY(QFile(SRCDIR "tst_qdirmodel.cpp").link(SRCDIR "test.lnk"));
+ QDirModel model;
+ model.setResolveSymlinks(false);
+ QModelIndex index = model.index(SRCDIR "test.lnk");
+ QVERIFY(index.isValid());
+#ifndef Q_OS_WINCE
+ QString path = SRCDIR;
+#else
+ QString path = QFileInfo(SRCDIR).absoluteFilePath() + "/";
+#endif
+ QCOMPARE(model.filePath(index), path + QString( "test.lnk"));
+ model.setResolveSymlinks(true);
+ QCOMPARE(model.filePath(index), path + QString( "tst_qdirmodel.cpp"));
+ QFile::remove(SRCDIR "test.lnk");
+}
+
+void tst_QDirModel::task196768_sorting()
+{
+ //this task showed that the persistent model indexes got corrupted when sorting
+ QString path = SRCDIR;
+
+ QDirModel model;
+
+ /* QDirModel has a bug if we show the content of the subdirectory inside a hidden directory
+ and we don't add QDir::Hidden. But as QDirModel is deprecated, we decided not to fix it. */
+ model.setFilter(QDir::AllEntries | QDir::Hidden | QDir::AllDirs);
+
+ QTreeView view;
+ QPersistentModelIndex index = model.index(path);
+ view.setModel(&model);
+ QModelIndex index2 = model.index(path);
+ QCOMPARE(index.data(), index2.data());
+ view.setRootIndex(index);
+ index2 = model.index(path);
+ QCOMPARE(index.data(), index2.data());
+ view.setCurrentIndex(index);
+ index2 = model.index(path);
+ QCOMPARE(index.data(), index2.data());
+ view.setSortingEnabled(true);
+ index2 = model.index(path);
+
+ QCOMPARE(index.data(), index2.data());
+}
+
+void tst_QDirModel::filter()
+{
+ QDirModel model;
+ model.setNameFilters(QStringList() << "*.nada");
+ QModelIndex index = model.index(SRCDIR "test");
+ QCOMPARE(model.rowCount(index), 0);
+ QModelIndex index2 = model.index(SRCDIR "test/file01.tst");
+ QVERIFY(!index2.isValid());
+ QCOMPARE(model.rowCount(index), 0);
+}
+
+void tst_QDirModel::task244669_remove()
+{
+ QFile f1(SRCDIR "dirtest/f1.txt");
+ QVERIFY(f1.open(QIODevice::WriteOnly));
+ f1.close();
+ QFile f2(SRCDIR "dirtest/f2.txt");
+ QVERIFY(f2.open(QIODevice::WriteOnly));
+ f2.close();
+
+ QDirModel model;
+ model.setReadOnly(false);
+ QPersistentModelIndex parent = model.index(SRCDIR "dirtest");
+ QPersistentModelIndex index2 = model.index(SRCDIR "dirtest/f2.txt");
+ QPersistentModelIndex index1 = model.index(SRCDIR "dirtest/f1.txt");
+
+ QVERIFY(parent.isValid());
+ QVERIFY(index1.isValid());
+ QVERIFY(index2.isValid());
+ QCOMPARE(parent.data() , model.index(SRCDIR "dirtest").data());
+ QCOMPARE(index1.data() , model.index(SRCDIR "dirtest/f1.txt").data());
+ QCOMPARE(index2.data() , model.index(SRCDIR "dirtest/f2.txt").data());
+
+ QVERIFY(model.remove(index1));
+
+ QVERIFY(parent.isValid());
+ QVERIFY(!index1.isValid());
+ QVERIFY(index2.isValid());
+ QCOMPARE(parent.data() , model.index(SRCDIR "dirtest").data());
+ QCOMPARE(index2.data() , model.index(SRCDIR "dirtest/f2.txt").data());
+
+ QVERIFY(model.remove(index2));
+
+ QVERIFY(parent.isValid());
+ QVERIFY(!index2.isValid());
+ QVERIFY(!index1.isValid());
+ QCOMPARE(parent.data() , model.index(SRCDIR "dirtest").data());
+}
+
+void tst_QDirModel::roleNames_data()
+{
+ QTest::addColumn<int>("role");
+ QTest::addColumn<QByteArray>("roleName");
+ QTest::newRow("decoration") << int(Qt::DecorationRole) << QByteArray("decoration");
+ QTest::newRow("display") << int(Qt::DisplayRole) << QByteArray("display");
+ QTest::newRow("fileIcon") << int(QDirModel::FileIconRole) << QByteArray("fileIcon");
+ QTest::newRow("filePath") << int(QDirModel::FilePathRole) << QByteArray("filePath");
+ QTest::newRow("fileName") << int(QDirModel::FileNameRole) << QByteArray("fileName");
+}
+
+void tst_QDirModel::roleNames()
+{
+ QDirModel model;
+ QHash<int, QByteArray> roles = model.roleNames();
+
+ QFETCH(int, role);
+ QVERIFY(roles.contains(role));
+
+ QFETCH(QByteArray, roleName);
+ QList<QByteArray> values = roles.values(role);
+ QVERIFY(values.contains(roleName));
+}
+
+
+QTEST_MAIN(tst_QDirModel)
+#include "tst_qdirmodel.moc"
diff --git a/tests/auto/widgets/itemviews/qfileiconprovider/.gitignore b/tests/auto/widgets/itemviews/qfileiconprovider/.gitignore
new file mode 100644
index 0000000000..1b673b8fd4
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qfileiconprovider/.gitignore
@@ -0,0 +1 @@
+tst_qfileiconprovider
diff --git a/tests/auto/widgets/itemviews/qfileiconprovider/qfileiconprovider.pro b/tests/auto/widgets/itemviews/qfileiconprovider/qfileiconprovider.pro
new file mode 100644
index 0000000000..1e3d26de00
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qfileiconprovider/qfileiconprovider.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qfileiconprovider.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp b/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp
new file mode 100644
index 0000000000..cf53019ff1
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qfileiconprovider.h>
+#include <qfileinfo.h>
+
+class tst_QFileIconProvider : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void qfileiconprovider_data();
+ void qfileiconprovider();
+
+ void iconType_data();
+ void iconType();
+
+ void iconInfo_data();
+ void iconInfo();
+
+ void type_data();
+ void type();
+};
+
+// Subclass that exposes the protected functions.
+class SubQFileIconProvider : public QFileIconProvider
+{
+public:
+
+};
+
+// This will be called before the first test function is executed.
+// It is only called once.
+void tst_QFileIconProvider::initTestCase()
+{
+}
+
+// This will be called after the last test function is executed.
+// It is only called once.
+void tst_QFileIconProvider::cleanupTestCase()
+{
+}
+
+// This will be called before each test function is executed.
+void tst_QFileIconProvider::init()
+{
+}
+
+// This will be called after every test function.
+void tst_QFileIconProvider::cleanup()
+{
+}
+
+
+void tst_QFileIconProvider::qfileiconprovider_data()
+{
+}
+
+void tst_QFileIconProvider::qfileiconprovider()
+{
+ // don't crash
+ SubQFileIconProvider provider;
+}
+
+Q_DECLARE_METATYPE(QFileIconProvider::IconType)
+void tst_QFileIconProvider::iconType_data()
+{
+ QTest::addColumn<QFileIconProvider::IconType>("type");
+
+ QTest::newRow("computer") << QFileIconProvider::Computer;
+ QTest::newRow("desktop") << QFileIconProvider::Desktop;
+ QTest::newRow("trashcan") << QFileIconProvider::Trashcan;
+ QTest::newRow("network") << QFileIconProvider::Network;
+ QTest::newRow("drive") << QFileIconProvider::Drive;
+ QTest::newRow("folder") << QFileIconProvider::Folder;
+ QTest::newRow("file") << QFileIconProvider::File;
+}
+
+// public QIcon icon(QFileIconProvider::IconType const& type) const
+void tst_QFileIconProvider::iconType()
+{
+ QFETCH(QFileIconProvider::IconType, type);
+ SubQFileIconProvider provider;
+ QVERIFY(!provider.icon(type).isNull());
+}
+
+Q_DECLARE_METATYPE(QFileInfo)
+void tst_QFileIconProvider::iconInfo_data()
+{
+ QTest::addColumn<QFileInfo>("info");
+ QTest::addColumn<bool>("setPath");
+
+ QTest::newRow("null") << QFileInfo() << false;
+ QTest::newRow("drive") << QFileInfo(QDir::rootPath()) << true;
+ QTest::newRow("home") << QFileInfo(QDir::homePath()) << true;
+ QTest::newRow("current") << QFileInfo(QDir::currentPath()) << true;
+}
+
+// public QIcon icon(QFileInfo const& info) const
+void tst_QFileIconProvider::iconInfo()
+{
+ QFETCH(QFileInfo, info);
+ QFETCH(bool, setPath);
+
+ if (setPath)
+ QVERIFY(info.exists());
+ SubQFileIconProvider provider;
+ // we should always get an icon
+ QVERIFY(!provider.icon(info).isNull());
+}
+
+void tst_QFileIconProvider::type_data()
+{
+ QTest::addColumn<QFileInfo>("info");
+ // Return value is _very_ system dependent, hard to test
+ // QTest::addColumn<QString>("type");
+
+ QTest::newRow("null") << QFileInfo();
+ QTest::newRow("drive") << QFileInfo(QDir::rootPath());
+ QTest::newRow("home") << QFileInfo(QDir::homePath());
+ QTest::newRow("current") << QFileInfo(QDir::currentPath());
+ QTest::newRow("exe") << QFileInfo(QCoreApplication::applicationFilePath());
+}
+
+// public QString type(QFileInfo const& info) const
+void tst_QFileIconProvider::type()
+{
+ QFETCH(QFileInfo, info);
+ SubQFileIconProvider provider;
+ QVERIFY(!provider.type(info).isEmpty());
+}
+
+QTEST_MAIN(tst_QFileIconProvider)
+#include "tst_qfileiconprovider.moc"
+
diff --git a/tests/auto/widgets/itemviews/qheaderview/.gitignore b/tests/auto/widgets/itemviews/qheaderview/.gitignore
new file mode 100644
index 0000000000..dafdb3d2fb
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qheaderview/.gitignore
@@ -0,0 +1 @@
+tst_qheaderview
diff --git a/tests/auto/widgets/itemviews/qheaderview/qheaderview.pro b/tests/auto/widgets/itemviews/qheaderview/qheaderview.pro
new file mode 100644
index 0000000000..3b3afa7e49
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qheaderview/qheaderview.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+
+QT += widgets widgets-private
+QT += core-private gui-private
+
+SOURCES += tst_qheaderview.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
new file mode 100644
index 0000000000..dd087b0e95
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
@@ -0,0 +1,2135 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QStandardItemModel>
+#include <QStringListModel>
+#include <QSortFilterProxyModel>
+#include <QTableView>
+
+#include <qabstractitemmodel.h>
+#include <qapplication.h>
+#include <qheaderview.h>
+#include <private/qheaderview_p.h>
+#include <qitemdelegate.h>
+#include <qtreewidget.h>
+#include <qdebug.h>
+
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
+
+typedef QList<bool> BoolList;
+Q_DECLARE_METATYPE(BoolList)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+// Will try to wait for the condition while allowing event processing
+// for a maximum of 2 seconds.
+#define WAIT_FOR_CONDITION(expr, expected) \
+ do { \
+ const int step = 100; \
+ for (int i = 0; i < 2000 && expr != expected; i+=step) { \
+ QTest::qWait(step); \
+ } \
+ } while(0)
+
+class protected_QHeaderView : public QHeaderView
+{
+ Q_OBJECT
+public:
+ protected_QHeaderView(Qt::Orientation orientation) : QHeaderView(orientation) {
+ resizeSections();
+ };
+
+ void testEvent();
+ void testhorizontalOffset();
+ void testverticalOffset();
+ friend class tst_QHeaderView;
+};
+
+class tst_QHeaderView : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QHeaderView();
+ virtual ~tst_QHeaderView();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void getSetCheck();
+ void visualIndex();
+
+ void visualIndexAt_data();
+ void visualIndexAt();
+
+ void noModel();
+ void emptyModel();
+ void removeRows();
+ void removeCols();
+
+ void clickable();
+ void movable();
+ void hidden();
+ void stretch();
+
+ void sectionSize_data();
+ void sectionSize();
+
+ void length();
+ void offset();
+ void sectionSizeHint();
+ void logicalIndex();
+ void logicalIndexAt();
+ void swapSections();
+
+ void moveSection_data();
+ void moveSection();
+
+ void resizeMode();
+
+ void resizeSection_data();
+ void resizeSection();
+
+ void resizeAndMoveSection_data();
+ void resizeAndMoveSection();
+ void resizeHiddenSection_data();
+ void resizeHiddenSection();
+ void resizeAndInsertSection_data();
+ void resizeAndInsertSection();
+ void resizeWithResizeModes_data();
+ void resizeWithResizeModes();
+ void moveAndInsertSection_data();
+ void moveAndInsertSection();
+ void highlightSections();
+ void showSortIndicator();
+ void sortIndicatorTracking();
+ void removeAndInsertRow();
+ void unhideSection();
+ void event();
+ void headerDataChanged();
+ void currentChanged();
+ void horizontalOffset();
+ void verticalOffset();
+ void stretchSectionCount();
+ void hiddenSectionCount();
+ void focusPolicy();
+ void moveSectionAndReset();
+ void moveSectionAndRemove();
+ void saveRestore();
+
+ void defaultAlignment_data();
+ void defaultAlignment();
+
+ void globalResizeMode_data();
+ void globalResizeMode();
+
+ void sectionPressedSignal_data();
+ void sectionPressedSignal();
+ void sectionClickedSignal_data() { sectionPressedSignal_data(); }
+ void sectionClickedSignal();
+
+ void defaultSectionSize_data();
+ void defaultSectionSize();
+
+ void oneSectionSize();
+
+ void hideAndInsert_data();
+ void hideAndInsert();
+
+ void removeSection();
+ void preserveHiddenSectionWidth();
+ void invisibleStretchLastSection();
+
+ void emptySectionSpan();
+ void task236450_hidden_data();
+ void task236450_hidden();
+ void task248050_hideRow();
+ void QTBUG6058_reset();
+ void QTBUG7833_sectionClicked();
+ void QTBUG8650_crashOnInsertSections();
+ void QTBUG12268_hiddenMovedSectionSorting();
+
+ void initialSortOrderRole();
+
+protected:
+ QWidget *topLevel;
+ QHeaderView *view;
+ QStandardItemModel *model;
+};
+
+class QtTestModel: public QAbstractTableModel
+{
+
+Q_OBJECT
+
+public:
+ QtTestModel(QObject *parent = 0): QAbstractTableModel(parent),
+ cols(0), rows(0), wrongIndex(false) {}
+ int rowCount(const QModelIndex&) const { return rows; }
+ int columnCount(const QModelIndex&) const { return cols; }
+ bool isEditable(const QModelIndex &) const { return true; }
+
+ QVariant data(const QModelIndex &idx, int) const
+ {
+ if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
+ wrongIndex = true;
+ qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(), idx.internalPointer());
+ }
+ return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column()).arg(0);//idx.data());
+ }
+
+ void insertOneColumn(int col)
+ {
+ beginInsertColumns(QModelIndex(), col, col);
+ --cols;
+ endInsertColumns();
+ }
+
+ void removeLastRow()
+ {
+ beginRemoveRows(QModelIndex(), rows - 1, rows - 1);
+ --rows;
+ endRemoveRows();
+ }
+
+ void removeAllRows()
+ {
+ beginRemoveRows(QModelIndex(), 0, rows - 1);
+ rows = 0;
+ endRemoveRows();
+ }
+
+ void removeOneColumn(int col)
+ {
+ beginRemoveColumns(QModelIndex(), col, col);
+ --cols;
+ endRemoveColumns();
+ }
+
+ void removeLastColumn()
+ {
+ beginRemoveColumns(QModelIndex(), cols - 1, cols - 1);
+ --cols;
+ endRemoveColumns();
+ }
+
+ void removeAllColumns()
+ {
+ beginRemoveColumns(QModelIndex(), 0, cols - 1);
+ cols = 0;
+ endRemoveColumns();
+ }
+
+ void cleanup()
+ {
+ cols = 3;
+ rows = 3;
+ emit layoutChanged();
+ }
+
+ int cols, rows;
+ mutable bool wrongIndex;
+};
+
+// Testing get/set functions
+void tst_QHeaderView::getSetCheck()
+{
+ protected_QHeaderView obj1(Qt::Horizontal);
+ // bool QHeaderView::highlightSections()
+ // void QHeaderView::setHighlightSections(bool)
+ obj1.setHighlightSections(false);
+ QCOMPARE(false, obj1.highlightSections());
+ obj1.setHighlightSections(true);
+ QCOMPARE(true, obj1.highlightSections());
+
+ // bool QHeaderView::stretchLastSection()
+ // void QHeaderView::setStretchLastSection(bool)
+ obj1.setStretchLastSection(false);
+ QCOMPARE(false, obj1.stretchLastSection());
+ obj1.setStretchLastSection(true);
+ QCOMPARE(true, obj1.stretchLastSection());
+
+ // int QHeaderView::defaultSectionSize()
+ // void QHeaderView::setDefaultSectionSize(int)
+ obj1.setDefaultSectionSize(0);
+ QCOMPARE(0, obj1.defaultSectionSize());
+ obj1.setDefaultSectionSize(INT_MIN);
+ QCOMPARE(INT_MIN, obj1.defaultSectionSize());
+ obj1.setDefaultSectionSize(INT_MAX);
+ QCOMPARE(INT_MAX, obj1.defaultSectionSize());
+ // ### the test above does not make sense for values below 0
+
+ // int QHeaderView::minimumSectionSize()
+ // void QHeaderView::setMinimumSectionSize(int)
+ obj1.setMinimumSectionSize(0);
+ QCOMPARE(0, obj1.minimumSectionSize());
+ obj1.setMinimumSectionSize(INT_MIN);
+ QCOMPARE(INT_MIN, obj1.minimumSectionSize());
+ obj1.setMinimumSectionSize(INT_MAX);
+ QCOMPARE(INT_MAX, obj1.minimumSectionSize());
+ // ### the test above does not make sense for values below 0
+
+ // int QHeaderView::offset()
+ // void QHeaderView::setOffset(int)
+ obj1.setOffset(0);
+ QCOMPARE(0, obj1.offset());
+ obj1.setOffset(INT_MIN);
+ QCOMPARE(INT_MIN, obj1.offset());
+ obj1.setOffset(INT_MAX);
+ QCOMPARE(INT_MAX, obj1.offset());
+
+}
+
+tst_QHeaderView::tst_QHeaderView()
+{
+ qRegisterMetaType<int>("Qt::SortOrder");
+}
+
+tst_QHeaderView::~tst_QHeaderView()
+{
+}
+
+void tst_QHeaderView::initTestCase()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QHeaderView::cleanupTestCase()
+{
+}
+
+void tst_QHeaderView::init()
+{
+ topLevel = new QWidget();
+ view = new QHeaderView(Qt::Vertical,topLevel);
+ // Some initial value tests before a model is added
+ QCOMPARE(view->length(), 0);
+ QVERIFY(view->sizeHint() == QSize(0,0));
+ QCOMPARE(view->sectionSizeHint(0), -1);
+
+ /*
+ model = new QStandardItemModel(1, 1);
+ view->setModel(model);
+ //qDebug() << view->count();
+ view->sizeHint();
+ */
+
+ int rows = 4;
+ int columns = 4;
+ model = new QStandardItemModel(rows, columns);
+ /*
+ for (int row = 0; row < rows; ++row) {
+ for (int column = 0; column < columns; ++column) {
+ QModelIndex index = model->index(row, column, QModelIndex());
+ model->setData(index, QVariant((row+1) * (column+1)));
+ }
+ }
+ */
+
+ QSignalSpy spy(view, SIGNAL(sectionCountChanged(int, int)));
+ view->setModel(model);
+ QCOMPARE(spy.count(), 1);
+ view->resize(200,200);
+ topLevel->show();
+}
+
+void tst_QHeaderView::cleanup()
+{
+ delete view;
+ view = 0;
+ delete model;
+ model = 0;
+}
+
+void tst_QHeaderView::noModel()
+{
+ QHeaderView emptyView(Qt::Vertical);
+ QCOMPARE(emptyView.count(), 0);
+}
+
+void tst_QHeaderView::emptyModel()
+{
+ QtTestModel testmodel;
+ view->setModel(&testmodel);
+ QVERIFY(!testmodel.wrongIndex);
+ QCOMPARE(view->count(), testmodel.rows);
+ view->setModel(model);
+}
+
+void tst_QHeaderView::removeRows()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+
+ QHeaderView vertical(Qt::Vertical);
+ QHeaderView horizontal(Qt::Horizontal);
+
+ vertical.setModel(&model);
+ horizontal.setModel(&model);
+ vertical.show();
+ horizontal.show();
+ QCOMPARE(vertical.count(), model.rows);
+ QCOMPARE(horizontal.count(), model.cols);
+
+ model.removeLastRow();
+ QVERIFY(!model.wrongIndex);
+ QCOMPARE(vertical.count(), model.rows);
+ QCOMPARE(horizontal.count(), model.cols);
+
+ model.removeAllRows();
+ QVERIFY(!model.wrongIndex);
+ QCOMPARE(vertical.count(), model.rows);
+ QCOMPARE(horizontal.count(), model.cols);
+}
+
+
+void tst_QHeaderView::removeCols()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+
+ QHeaderView vertical(Qt::Vertical);
+ QHeaderView horizontal(Qt::Horizontal);
+ vertical.setModel(&model);
+ horizontal.setModel(&model);
+ vertical.show();
+ horizontal.show();
+ QCOMPARE(vertical.count(), model.rows);
+ QCOMPARE(horizontal.count(), model.cols);
+
+ model.removeLastColumn();
+ QVERIFY(!model.wrongIndex);
+ QCOMPARE(vertical.count(), model.rows);
+ QCOMPARE(horizontal.count(), model.cols);
+
+ model.removeAllColumns();
+ QVERIFY(!model.wrongIndex);
+ QCOMPARE(vertical.count(), model.rows);
+ QCOMPARE(horizontal.count(), model.cols);
+}
+
+void tst_QHeaderView::movable()
+{
+ QCOMPARE(view->isMovable(), false);
+ view->setMovable(false);
+ QCOMPARE(view->isMovable(), false);
+ view->setMovable(true);
+ QCOMPARE(view->isMovable(), true);
+}
+
+void tst_QHeaderView::clickable()
+{
+ QCOMPARE(view->isClickable(), false);
+ view->setClickable(false);
+ QCOMPARE(view->isClickable(), false);
+ view->setClickable(true);
+ QCOMPARE(view->isClickable(), true);
+}
+
+void tst_QHeaderView::hidden()
+{
+ //hideSection() & showSection call setSectionHidden
+ // Test bad arguments
+ QCOMPARE(view->isSectionHidden(-1), false);
+ QCOMPARE(view->isSectionHidden(view->count()), false);
+ QCOMPARE(view->isSectionHidden(999999), false);
+
+ view->setSectionHidden(-1, true);
+ view->setSectionHidden(view->count(), true);
+ view->setSectionHidden(999999, true);
+ view->setSectionHidden(-1, false);
+ view->setSectionHidden(view->count(), false);
+ view->setSectionHidden(999999, false);
+
+ // Hidden sections shouldn't have visual properties (except position)
+ int pos = view->defaultSectionSize();
+ view->setSectionHidden(1, true);
+ QCOMPARE(view->sectionSize(1), 0);
+ QCOMPARE(view->sectionPosition(1), pos);
+ view->resizeSection(1, 100);
+ QCOMPARE(view->sectionViewportPosition(1), pos);
+ QCOMPARE(view->sectionSize(1), 0);
+ view->setSectionHidden(1, false);
+ QCOMPARE(view->isSectionHidden(0), false);
+ QCOMPARE(view->sectionSize(0), view->defaultSectionSize());
+}
+
+void tst_QHeaderView::stretch()
+{
+ // Show before resize and setStrechLastSection
+#if defined(Q_OS_WINCE)
+ QSize viewSize(200,300);
+#else
+ QSize viewSize(500, 500);
+#endif
+ view->resize(viewSize);
+ view->setStretchLastSection(true);
+ QCOMPARE(view->stretchLastSection(), true);
+ topLevel->show();
+ QCOMPARE(view->width(), viewSize.width());
+ QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 3);
+
+ view->setSectionHidden(3, true);
+ QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 2);
+
+ view->setStretchLastSection(false);
+ QCOMPARE(view->stretchLastSection(), false);
+}
+
+void tst_QHeaderView::oneSectionSize()
+{
+ //this ensures that if there is only one section, it gets a correct width (more than 0)
+ QHeaderView view (Qt::Vertical);
+ QtTestModel model;
+ model.cols = 1;
+ model.rows = 1;
+
+ view.setResizeMode(QHeaderView::Interactive);
+ view.setModel(&model);
+
+ view.show();
+
+ QVERIFY(view.sectionSize(0) > 0);
+}
+
+
+void tst_QHeaderView::sectionSize_data()
+{
+ QTest::addColumn<QList<int> >("boundsCheck");
+ QTest::addColumn<QList<int> >("defaultSizes");
+ QTest::addColumn<int>("initialDefaultSize");
+ QTest::addColumn<int>("lastVisibleSectionSize");
+ QTest::addColumn<int>("persistentSectionSize");
+
+ QTest::newRow("data set one")
+ << (QList<int>() << -1 << 0 << 4 << 9999)
+ << (QList<int>() << 10 << 30 << 30)
+ << 30
+ << 300
+ << 20;
+}
+
+void tst_QHeaderView::sectionSize()
+{
+ QFETCH(QList<int>, boundsCheck);
+ QFETCH(QList<int>, defaultSizes);
+ QFETCH(int, initialDefaultSize);
+ QFETCH(int, lastVisibleSectionSize);
+ QFETCH(int, persistentSectionSize);
+
+#ifdef Q_OS_WINCE
+ // We test on a device with doubled pixels. Therefore we need to specify
+ // different boundaries.
+ initialDefaultSize = qMax(view->minimumSectionSize(), 30);
+#endif
+
+ // bounds check
+ foreach (int val, boundsCheck)
+ view->sectionSize(val);
+
+ // default size
+ QCOMPARE(view->defaultSectionSize(), initialDefaultSize);
+ foreach (int def, defaultSizes) {
+ view->setDefaultSectionSize(def);
+ QCOMPARE(view->defaultSectionSize(), def);
+ }
+
+ view->setDefaultSectionSize(initialDefaultSize);
+ for (int s = 0; s < view->count(); ++s)
+ QCOMPARE(view->sectionSize(s), initialDefaultSize);
+ view->doItemsLayout();
+
+ // stretch last section
+ view->setStretchLastSection(true);
+ int lastSection = view->count() - 1;
+
+ //test that when hiding the last column,
+ //resizing the new last visible columns still works
+ view->hideSection(lastSection);
+ view->resizeSection(lastSection - 1, lastVisibleSectionSize);
+ QCOMPARE(view->sectionSize(lastSection - 1), lastVisibleSectionSize);
+ view->showSection(lastSection);
+
+ // turn off stretching
+ view->setStretchLastSection(false);
+ QCOMPARE(view->sectionSize(lastSection), initialDefaultSize);
+
+ // test persistence
+ int sectionCount = view->count();
+ for (int i = 0; i < sectionCount; ++i)
+ view->resizeSection(i, persistentSectionSize);
+ QtTestModel model;
+ model.cols = sectionCount * 2;
+ model.rows = sectionCount * 2;
+ view->setModel(&model);
+ for (int j = 0; j < sectionCount; ++j)
+ QCOMPARE(view->sectionSize(j), persistentSectionSize);
+ for (int k = sectionCount; k < view->count(); ++k)
+ QCOMPARE(view->sectionSize(k), initialDefaultSize);
+}
+
+void tst_QHeaderView::visualIndex()
+{
+ // Test bad arguments
+ QCOMPARE(view->visualIndex(999999), -1);
+ QCOMPARE(view->visualIndex(-1), -1);
+ QCOMPARE(view->visualIndex(1), 1);
+ view->setSectionHidden(1, true);
+ QCOMPARE(view->visualIndex(1), 1);
+ QCOMPARE(view->visualIndex(2), 2);
+
+ view->setSectionHidden(1, false);
+ QCOMPARE(view->visualIndex(1), 1);
+ QCOMPARE(view->visualIndex(2), 2);
+}
+
+void tst_QHeaderView::visualIndexAt_data()
+{
+ QTest::addColumn<QList<int> >("hidden");
+ QTest::addColumn<QList<int> >("from");
+ QTest::addColumn<QList<int> >("to");
+ QTest::addColumn<QList<int> >("coordinate");
+ QTest::addColumn<QList<int> >("visual");
+
+ QList<int> coordinateList;
+#ifndef Q_OS_WINCE
+ coordinateList << -1 << 0 << 31 << 91 << 99999;
+#else
+ // We test on a device with doubled pixels. Therefore we need to specify
+ // different boundaries.
+ coordinateList << -1 << 0 << 33 << 97 << 99999;
+#endif
+
+ QTest::newRow("no hidden, no moved sections")
+ << QList<int>()
+ << QList<int>()
+ << QList<int>()
+ << coordinateList
+ << (QList<int>() << -1 << 0 << 1 << 3 << -1);
+
+ QTest::newRow("no hidden, moved sections")
+ << QList<int>()
+ << (QList<int>() << 0)
+ << (QList<int>() << 1)
+ << coordinateList
+ << (QList<int>() << -1 << 0 << 1 << 3 << -1);
+
+ QTest::newRow("hidden, no moved sections")
+ << (QList<int>() << 0)
+ << QList<int>()
+ << QList<int>()
+ << coordinateList
+ << (QList<int>() << -1 << 1 << 2 << 3 << -1);
+}
+
+void tst_QHeaderView::visualIndexAt()
+{
+ QFETCH(QList<int>, hidden);
+ QFETCH(QList<int>, from);
+ QFETCH(QList<int>, to);
+ QFETCH(QList<int>, coordinate);
+ QFETCH(QList<int>, visual);
+
+ view->setStretchLastSection(true);
+ topLevel->show();
+
+ for (int i = 0; i < hidden.count(); ++i)
+ view->setSectionHidden(hidden.at(i), true);
+
+ for (int j = 0; j < from.count(); ++j)
+ view->moveSection(from.at(j), to.at(j));
+
+ QTest::qWait(100);
+
+ for (int k = 0; k < coordinate.count(); ++k)
+ QCOMPARE(view->visualIndexAt(coordinate.at(k)), visual.at(k));
+}
+
+void tst_QHeaderView::length()
+{
+#if defined(Q_OS_WINCE)
+ QFont font(QLatin1String("Tahoma"), 7);
+ view->setFont(font);
+#endif
+ view->setStretchLastSection(true);
+ topLevel->show();
+
+ //minimumSectionSize should be the size of the last section of the widget is not tall enough
+ int length = view->minimumSectionSize();
+ for (int i=0; i < view->count()-1; i++) {
+ length += view->sectionSize(i);
+ }
+
+ length = qMax(length, view->viewport()->height());
+ QCOMPARE(length, view->length());
+
+ view->setStretchLastSection(false);
+ topLevel->show();
+
+ QVERIFY(length != view->length());
+
+ // layoutChanged might mean rows have been removed
+ QtTestModel model;
+ model.cols = 10;
+ model.rows = 10;
+ view->setModel(&model);
+ int oldLength = view->length();
+ model.cleanup();
+ QCOMPARE(model.rows, view->count());
+ QVERIFY(oldLength != view->length());
+}
+
+void tst_QHeaderView::offset()
+{
+ QCOMPARE(view->offset(), 0);
+ view->setOffset(10);
+ QCOMPARE(view->offset(), 10);
+ view->setOffset(0);
+ QCOMPARE(view->offset(), 0);
+
+ // Test odd arguments
+ view->setOffset(-1);
+}
+
+void tst_QHeaderView::sectionSizeHint()
+{
+ // Test bad arguments
+ view->sectionSizeHint(-1);
+ view->sectionSizeHint(99999);
+
+ // TODO how to test the return value?
+}
+
+void tst_QHeaderView::logicalIndex()
+{
+ // Test bad arguments
+ QCOMPARE(view->logicalIndex(-1), -1);
+ QCOMPARE(view->logicalIndex(99999), -1);
+}
+
+void tst_QHeaderView::logicalIndexAt()
+{
+ // Test bad arguments
+ view->logicalIndexAt(-1);
+ view->logicalIndexAt(99999);
+ QCOMPARE(view->logicalIndexAt(0), 0);
+ QCOMPARE(view->logicalIndexAt(1), 0);
+
+ topLevel->show();
+ view->setStretchLastSection(true);
+ // First item
+ QCOMPARE(view->logicalIndexAt(0), 0);
+ QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 0);
+ QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 1);
+ // Last item
+ int last = view->length() - 1;//view->viewport()->height() - 10;
+ QCOMPARE(view->logicalIndexAt(last), 3);
+ // Not in widget
+ int outofbounds = view->length() + 1;//view->viewport()->height() + 1;
+ QCOMPARE(view->logicalIndexAt(outofbounds), -1);
+
+ view->moveSection(0,1);
+ // First item
+ QCOMPARE(view->logicalIndexAt(0), 1);
+ QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 1);
+ QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 0);
+ // Last item
+ QCOMPARE(view->logicalIndexAt(last), 3);
+ view->moveSection(1,0);
+
+}
+
+void tst_QHeaderView::swapSections()
+{
+ view->swapSections(-1, 1);
+ view->swapSections(99999, 1);
+ view->swapSections(1, -1);
+ view->swapSections(1, 99999);
+
+ QVector<int> logical = (QVector<int>() << 0 << 1 << 2 << 3);
+
+ QSignalSpy spy1(view, SIGNAL(sectionMoved(int, int, int)));
+
+ QCOMPARE(view->sectionsMoved(), false);
+ view->swapSections(1, 1);
+ QCOMPARE(view->sectionsMoved(), false);
+ view->swapSections(1, 2);
+ QCOMPARE(view->sectionsMoved(), true);
+ view->swapSections(2, 1);
+ QCOMPARE(view->sectionsMoved(), true);
+ for (int i = 0; i < view->count(); ++i)
+ QCOMPARE(view->logicalIndex(i), logical.at(i));
+ QCOMPARE(spy1.count(), 4);
+
+ logical = (QVector<int>() << 3 << 1 << 2 << 0);
+ view->swapSections(3, 0);
+ QCOMPARE(view->sectionsMoved(), true);
+ for (int j = 0; j < view->count(); ++j)
+ QCOMPARE(view->logicalIndex(j), logical.at(j));
+ QCOMPARE(spy1.count(), 6);
+}
+
+void tst_QHeaderView::moveSection_data()
+{
+ QTest::addColumn<QList<int> >("hidden");
+ QTest::addColumn<QList<int> >("from");
+ QTest::addColumn<QList<int> >("to");
+ QTest::addColumn<QList<bool> >("moved");
+ QTest::addColumn<QList<int> >("logical");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("bad args, no hidden")
+ << QList<int>()
+ << (QList<int>() << -1 << 1 << 99999 << 1)
+ << (QList<int>() << 1 << -1 << 1 << 99999)
+ << (QList<bool>() << false << false << false << false)
+ << (QList<int>() << 0 << 1 << 2 << 3)
+ << 0;
+
+ QTest::newRow("good args, no hidden")
+ << QList<int>()
+ << (QList<int>() << 1 << 1 << 2 << 1)
+ << (QList<int>() << 1 << 2 << 1 << 2)
+ << (QList<bool>() << false << true << true << true)
+ << (QList<int>() << 0 << 2 << 1 << 3)
+ << 3;
+
+ QTest::newRow("hidden sections")
+ << (QList<int>() << 0 << 3)
+ << (QList<int>() << 1 << 1 << 2 << 1)
+ << (QList<int>() << 1 << 2 << 1 << 2)
+ << (QList<bool>() << false << true << true << true)
+ << (QList<int>() << 0 << 2 << 1 << 3)
+ << 3;
+}
+
+void tst_QHeaderView::moveSection()
+{
+ QFETCH(QList<int>, hidden);
+ QFETCH(QList<int>, from);
+ QFETCH(QList<int>, to);
+ QFETCH(QList<bool>, moved);
+ QFETCH(QList<int>, logical);
+ QFETCH(int, count);
+
+ QVERIFY(from.count() == to.count());
+ QVERIFY(from.count() == moved.count());
+ QVERIFY(view->count() == logical.count());
+
+ QSignalSpy spy1(view, SIGNAL(sectionMoved(int, int, int)));
+ QCOMPARE(view->sectionsMoved(), false);
+
+ for (int h = 0; h < hidden.count(); ++h)
+ view->setSectionHidden(hidden.at(h), true);
+
+ for (int i = 0; i < from.count(); ++i) {
+ view->moveSection(from.at(i), to.at(i));
+ QCOMPARE(view->sectionsMoved(), moved.at(i));
+ }
+
+ for (int j = 0; j < view->count(); ++j)
+ QCOMPARE(view->logicalIndex(j), logical.at(j));
+
+ QCOMPARE(spy1.count(), count);
+}
+
+void tst_QHeaderView::resizeAndMoveSection_data()
+{
+ QTest::addColumn<IntList>("logicalIndexes");
+ QTest::addColumn<IntList>("sizes");
+ QTest::addColumn<int>("logicalFrom");
+ QTest::addColumn<int>("logicalTo");
+
+ QTest::newRow("resizeAndMove-1")
+ << (IntList() << 0 << 1)
+ << (IntList() << 20 << 40)
+ << 0 << 1;
+
+ QTest::newRow("resizeAndMove-2")
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 20 << 60 << 10 << 80)
+ << 0 << 2;
+
+ QTest::newRow("resizeAndMove-3")
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 100 << 60 << 40 << 10)
+ << 0 << 3;
+
+ QTest::newRow("resizeAndMove-4")
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 10 << 40 << 80 << 30)
+ << 1 << 2;
+
+ QTest::newRow("resizeAndMove-5")
+ << (IntList() << 2 << 3)
+ << (IntList() << 100 << 200)
+ << 3 << 2;
+}
+
+void tst_QHeaderView::resizeAndMoveSection()
+{
+ QFETCH(IntList, logicalIndexes);
+ QFETCH(IntList, sizes);
+ QFETCH(int, logicalFrom);
+ QFETCH(int, logicalTo);
+
+ // Save old visual indexes and sizes
+ IntList oldVisualIndexes;
+ IntList oldSizes;
+ foreach (int logical, logicalIndexes) {
+ oldVisualIndexes.append(view->visualIndex(logical));
+ oldSizes.append(view->sectionSize(logical));
+ }
+
+ // Resize sections
+ for (int i = 0; i < logicalIndexes.size(); ++i) {
+ int logical = logicalIndexes.at(i);
+ view->resizeSection(logical, sizes.at(i));
+ }
+
+ // Move sections
+ int visualFrom = view->visualIndex(logicalFrom);
+ int visualTo = view->visualIndex(logicalTo);
+ view->moveSection(visualFrom, visualTo);
+ QCOMPARE(view->visualIndex(logicalFrom), visualTo);
+
+ // Check that sizes are still correct
+ for (int i = 0; i < logicalIndexes.size(); ++i) {
+ int logical = logicalIndexes.at(i);
+ QCOMPARE(view->sectionSize(logical), sizes.at(i));
+ }
+
+ // Move sections back
+ view->moveSection(visualTo, visualFrom);
+
+ // Check that sizes are still correct
+ for (int i = 0; i < logicalIndexes.size(); ++i) {
+ int logical = logicalIndexes.at(i);
+ QCOMPARE(view->sectionSize(logical), sizes.at(i));
+ }
+
+ // Put everything back as it was
+ for (int i = 0; i < logicalIndexes.size(); ++i) {
+ int logical = logicalIndexes.at(i);
+ view->resizeSection(logical, oldSizes.at(i));
+ QCOMPARE(view->visualIndex(logical), oldVisualIndexes.at(i));
+ }
+}
+
+void tst_QHeaderView::resizeHiddenSection_data()
+{
+ QTest::addColumn<int>("section");
+ QTest::addColumn<int>("initialSize");
+ QTest::addColumn<int>("finalSize");
+
+ QTest::newRow("section 0 resize 50 to 20")
+ << 0 << 50 << 20;
+
+ QTest::newRow("section 1 resize 50 to 20")
+ << 1 << 50 << 20;
+
+ QTest::newRow("section 2 resize 50 to 20")
+ << 2 << 50 << 20;
+
+ QTest::newRow("section 3 resize 50 to 20")
+ << 3 << 50 << 20;
+}
+
+void tst_QHeaderView::resizeHiddenSection()
+{
+ QFETCH(int, section);
+ QFETCH(int, initialSize);
+ QFETCH(int, finalSize);
+
+ view->resizeSection(section, initialSize);
+ view->setSectionHidden(section, true);
+ QCOMPARE(view->sectionSize(section), 0);
+
+ view->resizeSection(section, finalSize);
+ QCOMPARE(view->sectionSize(section), 0);
+
+ view->setSectionHidden(section, false);
+ QCOMPARE(view->sectionSize(section), finalSize);
+}
+
+void tst_QHeaderView::resizeAndInsertSection_data()
+{
+ QTest::addColumn<int>("section");
+ QTest::addColumn<int>("size");
+ QTest::addColumn<int>("insert");
+ QTest::addColumn<int>("compare");
+ QTest::addColumn<int>("expected");
+
+ QTest::newRow("section 0 size 50 insert 0")
+ << 0 << 50 << 0 << 1 << 50;
+
+ QTest::newRow("section 1 size 50 insert 1")
+ << 0 << 50 << 1 << 0 << 50;
+
+ QTest::newRow("section 1 size 50 insert 0")
+ << 1 << 50 << 0 << 2 << 50;
+
+}
+
+void tst_QHeaderView::resizeAndInsertSection()
+{
+ QFETCH(int, section);
+ QFETCH(int, size);
+ QFETCH(int, insert);
+ QFETCH(int, compare);
+ QFETCH(int, expected);
+
+ view->setStretchLastSection(false);
+
+ view->resizeSection(section, size);
+ QCOMPARE(view->sectionSize(section), size);
+
+ model->insertRow(insert);
+
+ QCOMPARE(view->sectionSize(compare), expected);
+}
+
+void tst_QHeaderView::resizeWithResizeModes_data()
+{
+ QTest::addColumn<int>("size");
+ QTest::addColumn<QList<int> >("sections");
+ QTest::addColumn<QList<int> >("modes");
+ QTest::addColumn<QList<int> >("expected");
+
+ QTest::newRow("stretch first section")
+ << 600
+ << (QList<int>() << 100 << 100 << 100 << 100)
+ << (QList<int>() << ((int)QHeaderView::Stretch)
+ << ((int)QHeaderView::Interactive)
+ << ((int)QHeaderView::Interactive)
+ << ((int)QHeaderView::Interactive))
+ << (QList<int>() << 300 << 100 << 100 << 100);
+}
+
+void tst_QHeaderView::resizeWithResizeModes()
+{
+ QFETCH(int, size);
+ QFETCH(QList<int>, sections);
+ QFETCH(QList<int>, modes);
+ QFETCH(QList<int>, expected);
+
+ view->setStretchLastSection(false);
+ for (int i = 0; i < sections.count(); ++i) {
+ view->resizeSection(i, sections.at(i));
+ view->setResizeMode(i, (QHeaderView::ResizeMode)modes.at(i));
+ }
+ topLevel->show();
+ view->resize(size, size);
+ for (int j = 0; j < expected.count(); ++j)
+ QCOMPARE(view->sectionSize(j), expected.at(j));
+}
+
+void tst_QHeaderView::moveAndInsertSection_data()
+{
+ QTest::addColumn<int>("from");
+ QTest::addColumn<int>("to");
+ QTest::addColumn<int>("insert");
+ QTest::addColumn<QList<int> >("mapping");
+
+ QTest::newRow("move from 1 to 3, insert 0")
+ << 1 << 3 << 0 <<(QList<int>() << 0 << 1 << 3 << 4 << 2);
+
+}
+
+void tst_QHeaderView::moveAndInsertSection()
+{
+ QFETCH(int, from);
+ QFETCH(int, to);
+ QFETCH(int, insert);
+ QFETCH(QList<int>, mapping);
+
+ view->setStretchLastSection(false);
+
+ view->moveSection(from, to);
+
+ model->insertRow(insert);
+
+ for (int i = 0; i < mapping.count(); ++i)
+ QCOMPARE(view->logicalIndex(i), mapping.at(i));
+}
+
+void tst_QHeaderView::resizeMode()
+{
+ // resizeMode must not be called with an invalid index
+ int last = view->count() - 1;
+ view->setResizeMode(QHeaderView::Interactive);
+ QCOMPARE(view->resizeMode(last), QHeaderView::Interactive);
+ QCOMPARE(view->resizeMode(1), QHeaderView::Interactive);
+ view->setResizeMode(QHeaderView::Stretch);
+ QCOMPARE(view->resizeMode(last), QHeaderView::Stretch);
+ QCOMPARE(view->resizeMode(1), QHeaderView::Stretch);
+ view->setResizeMode(QHeaderView::Custom);
+ QCOMPARE(view->resizeMode(last), QHeaderView::Custom);
+ QCOMPARE(view->resizeMode(1), QHeaderView::Custom);
+
+ // test when sections have been moved
+ view->setStretchLastSection(false);
+ for (int i=0; i < (view->count() - 1); ++i)
+ view->setResizeMode(i, QHeaderView::Interactive);
+ int logicalIndex = view->count() / 2;
+ view->setResizeMode(logicalIndex, QHeaderView::Stretch);
+ view->moveSection(view->visualIndex(logicalIndex), 0);
+ for (int i=0; i < (view->count() - 1); ++i) {
+ if (i == logicalIndex)
+ QCOMPARE(view->resizeMode(i), QHeaderView::Stretch);
+ else
+ QCOMPARE(view->resizeMode(i), QHeaderView::Interactive);
+ }
+}
+
+void tst_QHeaderView::resizeSection_data()
+{
+ QTest::addColumn<int>("initial");
+ QTest::addColumn<QList<int> >("logical");
+ QTest::addColumn<QList<int> >("size");
+ QTest::addColumn<QList<int> >("mode");
+ QTest::addColumn<int>("resized");
+ QTest::addColumn<QList<int> >("expected");
+
+ QTest::newRow("bad args")
+ << 100
+ << (QList<int>() << -1 << -1 << 99999 << 99999 << 4)
+ << (QList<int>() << -1 << 0 << 99999 << -1 << -1)
+ << (QList<int>()
+ << int(QHeaderView::Interactive)
+ << int(QHeaderView::Interactive)
+ << int(QHeaderView::Interactive)
+ << int(QHeaderView::Interactive))
+ << 0
+ << (QList<int>() << 0 << 0 << 0 << 0 << 0);
+}
+
+void tst_QHeaderView::resizeSection()
+{
+
+ QFETCH(int, initial);
+ QFETCH(QList<int>, logical);
+ QFETCH(QList<int>, size);
+ QFETCH(QList<int>, mode);
+ QFETCH(int, resized);
+ QFETCH(QList<int>, expected);
+
+ view->resize(400, 400);
+
+ topLevel->show();
+ view->setMovable(true);
+ view->setStretchLastSection(false);
+
+ for (int i = 0; i < logical.count(); ++i)
+ if (logical.at(i) > -1 && logical.at(i) < view->count()) // for now
+ view->setResizeMode(logical.at(i), (QHeaderView::ResizeMode)mode.at(i));
+
+ for (int j = 0; j < logical.count(); ++j)
+ view->resizeSection(logical.at(j), initial);
+
+ QSignalSpy spy(view, SIGNAL(sectionResized(int, int, int)));
+
+ for (int k = 0; k < logical.count(); ++k)
+ view->resizeSection(logical.at(k), size.at(k));
+
+ QCOMPARE(spy.count(), resized);
+
+ for (int l = 0; l < logical.count(); ++l)
+ QCOMPARE(view->sectionSize(logical.at(l)), expected.at(l));
+}
+
+void tst_QHeaderView::highlightSections()
+{
+ view->setHighlightSections(true);
+ QCOMPARE(view->highlightSections(), true);
+ view->setHighlightSections(false);
+ QCOMPARE(view->highlightSections(), false);
+}
+
+void tst_QHeaderView::showSortIndicator()
+{
+ view->setSortIndicatorShown(true);
+ QCOMPARE(view->isSortIndicatorShown(), true);
+ QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder);
+ view->setSortIndicator(1, Qt::AscendingOrder);
+ QCOMPARE(view->sortIndicatorOrder(), Qt::AscendingOrder);
+ view->setSortIndicator(1, Qt::DescendingOrder);
+ QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder);
+ view->setSortIndicatorShown(false);
+ QCOMPARE(view->isSortIndicatorShown(), false);
+
+ view->setSortIndicator(999999, Qt::DescendingOrder);
+ // Don't segfault baby :)
+ view->setSortIndicatorShown(true);
+
+ view->setSortIndicator(0, Qt::DescendingOrder);
+ // Don't assert baby :)
+}
+
+void tst_QHeaderView::sortIndicatorTracking()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+
+ QHeaderView hv(Qt::Horizontal);
+
+ hv.setModel(&model);
+ hv.show();
+ hv.setSortIndicatorShown(true);
+ hv.setSortIndicator(1, Qt::DescendingOrder);
+
+ model.removeOneColumn(8);
+ QCOMPARE(hv.sortIndicatorSection(), 1);
+
+ model.removeOneColumn(2);
+ QCOMPARE(hv.sortIndicatorSection(), 1);
+
+ model.insertOneColumn(2);
+ QCOMPARE(hv.sortIndicatorSection(), 1);
+
+ model.insertOneColumn(1);
+ QCOMPARE(hv.sortIndicatorSection(), 2);
+
+ model.removeOneColumn(0);
+ QCOMPARE(hv.sortIndicatorSection(), 1);
+
+ model.removeOneColumn(1);
+ QCOMPARE(hv.sortIndicatorSection(), -1);
+}
+
+void tst_QHeaderView::removeAndInsertRow()
+{
+ // Check if logicalIndex returns the correct value after we have removed a row
+ // we might as well te
+ for (int i = 0; i < model->rowCount(); ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+
+ while (model->removeRow(0)) {
+ for (int i = 0; i < model->rowCount(); ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+ }
+
+ int pass = 0;
+ for (pass = 0; pass < 5; pass++) {
+ for (int i = 0; i < model->rowCount(); ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+ model->insertRow(0);
+ }
+
+ while (model->removeRows(0, 2)) {
+ for (int i = 0; i < model->rowCount(); ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+ }
+
+ for (pass = 0; pass < 3; pass++) {
+ model->insertRows(0, 2);
+ for (int i = 0; i < model->rowCount(); ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+ }
+
+ for (pass = 0; pass < 3; pass++) {
+ model->insertRows(3, 2);
+ for (int i = 0; i < model->rowCount(); ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+ }
+
+ // Insert at end
+ for (pass = 0; pass < 3; pass++) {
+ int rowCount = model->rowCount();
+ model->insertRows(rowCount, 1);
+ for (int i = 0; i < rowCount; ++i) {
+ QCOMPARE(i, view->logicalIndex(i));
+ }
+ }
+
+}
+void tst_QHeaderView::unhideSection()
+{
+ // You should not necessarily expect the same size back again, so the best test we can do is to test if it is larger than 0 after a unhide.
+ QCOMPARE(view->sectionsHidden(), false);
+ view->setSectionHidden(0, true);
+ QCOMPARE(view->sectionsHidden(), true);
+ QVERIFY(view->sectionSize(0) == 0);
+ view->setResizeMode(QHeaderView::Interactive);
+ view->setSectionHidden(0, false);
+ QVERIFY(view->sectionSize(0) > 0);
+
+ view->setSectionHidden(0, true);
+ QVERIFY(view->sectionSize(0) == 0);
+ view->setSectionHidden(0, true);
+ QVERIFY(view->sectionSize(0) == 0);
+ view->setResizeMode(QHeaderView::Stretch);
+ view->setSectionHidden(0, false);
+ QVERIFY(view->sectionSize(0) > 0);
+
+}
+
+void tst_QHeaderView::event()
+{
+ protected_QHeaderView x(Qt::Vertical);
+ x.testEvent();
+ protected_QHeaderView y(Qt::Horizontal);
+ y.testEvent();
+}
+
+
+void protected_QHeaderView::testEvent()
+{
+ // No crashy please
+ QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(), QPoint());
+ event(&enterEvent);
+ QHoverEvent eventLeave(QEvent::HoverLeave, QPoint(), QPoint());
+ event(&eventLeave);
+ QHoverEvent eventMove(QEvent::HoverMove, QPoint(), QPoint());
+ event(&eventMove);
+}
+
+void tst_QHeaderView::headerDataChanged()
+{
+ // This shouldn't asserver because view is Vertical
+ view->headerDataChanged(Qt::Horizontal, -1, -1);
+#if 0
+ // This will assert
+ view->headerDataChanged(Qt::Vertical, -1, -1);
+#endif
+
+ // No crashing please
+ view->headerDataChanged(Qt::Horizontal, 0, 1);
+ view->headerDataChanged(Qt::Vertical, 0, 1);
+}
+
+void tst_QHeaderView::currentChanged()
+{
+ view->setCurrentIndex(QModelIndex());
+}
+
+void tst_QHeaderView::horizontalOffset()
+{
+ protected_QHeaderView x(Qt::Vertical);
+ x.testhorizontalOffset();
+ protected_QHeaderView y(Qt::Horizontal);
+ y.testhorizontalOffset();
+}
+
+void tst_QHeaderView::verticalOffset()
+{
+ protected_QHeaderView x(Qt::Vertical);
+ x.testverticalOffset();
+ protected_QHeaderView y(Qt::Horizontal);
+ y.testverticalOffset();
+}
+
+void protected_QHeaderView::testhorizontalOffset()
+{
+ if(orientation() == Qt::Horizontal){
+ QCOMPARE(horizontalOffset(), 0);
+ setOffset(10);
+ QCOMPARE(horizontalOffset(), 10);
+ }
+ else
+ QCOMPARE(horizontalOffset(), 0);
+
+}
+
+void protected_QHeaderView::testverticalOffset()
+{
+ if(orientation() == Qt::Vertical){
+ QCOMPARE(verticalOffset(), 0);
+ setOffset(10);
+ QCOMPARE(verticalOffset(), 10);
+ }
+ else
+ QCOMPARE(verticalOffset(), 0);
+}
+
+void tst_QHeaderView::stretchSectionCount()
+{
+ view->setStretchLastSection(false);
+ QCOMPARE(view->stretchSectionCount(), 0);
+ view->setStretchLastSection(true);
+ QCOMPARE(view->stretchSectionCount(), 0);
+
+ view->setResizeMode(0, QHeaderView::Stretch);
+ QCOMPARE(view->stretchSectionCount(), 1);
+}
+
+void tst_QHeaderView::hiddenSectionCount()
+{
+ model->clear();
+ model->insertRows(0, 10);
+ // Hide every other one
+ for (int i=0; i<10; i++)
+ view->setSectionHidden(i, (i & 1) == 0);
+
+ QCOMPARE(view->hiddenSectionCount(), 5);
+
+ view->setResizeMode(QHeaderView::Stretch);
+ QCOMPARE(view->hiddenSectionCount(), 5);
+
+ // Remove some rows and make sure they are now still counted
+ model->removeRow(9);
+ model->removeRow(8);
+ model->removeRow(7);
+ model->removeRow(6);
+ QCOMPARE(view->count(), 6);
+ QCOMPARE(view->hiddenSectionCount(), 3);
+ model->removeRows(0,5);
+ QCOMPARE(view->count(), 1);
+ QCOMPARE(view->hiddenSectionCount(), 0);
+ QVERIFY(view->count() >= view->hiddenSectionCount());
+}
+
+void tst_QHeaderView::focusPolicy()
+{
+ QHeaderView view(Qt::Horizontal);
+ QCOMPARE(view.focusPolicy(), Qt::NoFocus);
+
+ QTreeWidget widget;
+ QCOMPARE(widget.header()->focusPolicy(), Qt::NoFocus);
+ QVERIFY(!widget.focusProxy());
+ QVERIFY(!widget.hasFocus());
+ QVERIFY(!widget.header()->focusProxy());
+ QVERIFY(!widget.header()->hasFocus());
+
+ widget.show();
+ widget.setFocus(Qt::OtherFocusReason);
+ QApplication::setActiveWindow(&widget);
+ QTest::qWaitForWindowShown(&widget);
+ widget.activateWindow();
+ QTest::qWait(100);
+
+ qApp->processEvents();
+
+ WAIT_FOR_CONDITION(widget.hasFocus(), true);
+
+ QVERIFY(widget.hasFocus());
+ QVERIFY(!widget.header()->hasFocus());
+
+ widget.setFocusPolicy(Qt::NoFocus);
+ widget.clearFocus();
+
+ qApp->processEvents();
+ qApp->processEvents();
+
+ WAIT_FOR_CONDITION(widget.hasFocus(), false);
+ QVERIFY(!widget.hasFocus());
+ QVERIFY(!widget.header()->hasFocus());
+
+ QTest::keyPress(&widget, Qt::Key_Tab);
+
+ qApp->processEvents();
+ qApp->processEvents();
+
+ QVERIFY(!widget.hasFocus());
+ QVERIFY(!widget.header()->hasFocus());
+}
+
+class SimpleModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+
+ SimpleModel( QObject* parent=0)
+ : QAbstractItemModel(parent),
+ m_col_count(3) {}
+
+ QModelIndex parent(const QModelIndex &/*child*/) const
+ {
+ return QModelIndex();
+ }
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
+ {
+ return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex();
+ }
+ int rowCount(const QModelIndex & /* parent */) const
+ {
+ return 8;
+ }
+ int columnCount(const QModelIndex &/*parent= QModelIndex()*/) const
+ {
+ return m_col_count;
+ }
+
+ QVariant data(const QModelIndex &index, int role) const
+ {
+ if (!index.isValid())
+ {
+ return QVariant();
+ }
+ if (role == Qt::DisplayRole) {
+ return QString::fromAscii("%1,%2").arg(index.row()).arg(index.column());
+ }
+ return QVariant();
+ }
+
+ void setColumnCount( int c )
+ {
+ m_col_count = c;
+ }
+
+private:
+ int m_col_count;
+};
+
+void tst_QHeaderView::moveSectionAndReset()
+{
+ SimpleModel m;
+ QHeaderView v(Qt::Horizontal);
+ v.setModel(&m);
+ int cc = 2;
+ for (cc = 2; cc < 4; ++cc) {
+ m.setColumnCount(cc);
+ int movefrom = 0;
+ int moveto;
+ for (moveto = 1; moveto < cc; ++moveto) {
+ v.moveSection(movefrom, moveto);
+ m.setColumnCount(cc - 1);
+ v.reset();
+ for (int i = 0; i < cc - 1; ++i) {
+ QCOMPARE(v.logicalIndex(v.visualIndex(i)), i);
+ }
+ }
+ }
+}
+
+void tst_QHeaderView::moveSectionAndRemove()
+{
+ QStandardItemModel m;
+ QHeaderView v(Qt::Horizontal);
+
+ v.setModel(&m);
+ v.model()->insertColumns(0, 3);
+ v.moveSection(0, 1);
+
+ QCOMPARE(v.count(), 3);
+ v.model()->removeColumns(0, v.model()->columnCount());
+ QCOMPARE(v.count(), 0);
+}
+
+void tst_QHeaderView::saveRestore()
+{
+ SimpleModel m;
+ QHeaderView h1(Qt::Horizontal);
+ h1.setModel(&m);
+ h1.swapSections(0, 2);
+ h1.resizeSection(1, 10);
+ h1.setSortIndicatorShown(true);
+ h1.setSortIndicator(1,Qt::DescendingOrder);
+ QByteArray s1 = h1.saveState();
+
+ QHeaderView h2(Qt::Vertical);
+ QSignalSpy spy(&h2, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)));
+
+ h2.setModel(&m);
+ h2.restoreState(s1);
+
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.at(0).at(0).toInt(), 1);
+
+ QCOMPARE(h2.logicalIndex(0), 2);
+ QCOMPARE(h2.logicalIndex(2), 0);
+ QCOMPARE(h2.sectionSize(1), 10);
+ QCOMPARE(h2.sortIndicatorSection(), 1);
+ QCOMPARE(h2.sortIndicatorOrder(), Qt::DescendingOrder);
+ QCOMPARE(h2.isSortIndicatorShown(), true);
+
+ QByteArray s2 = h2.saveState();
+
+ QVERIFY(s1 == s2);
+}
+
+void tst_QHeaderView::defaultAlignment_data()
+{
+ QTest::addColumn<int>("direction");
+ QTest::addColumn<int>("initial");
+ QTest::addColumn<int>("alignment");
+
+ QTest::newRow("horizontal right aligned")
+ << int(Qt::Horizontal)
+ << int(Qt::AlignCenter)
+ << int(Qt::AlignRight);
+
+ QTest::newRow("horizontal left aligned")
+ << int(Qt::Horizontal)
+ << int(Qt::AlignCenter)
+ << int(Qt::AlignLeft);
+
+ QTest::newRow("vertical right aligned")
+ << int(Qt::Vertical)
+ << int(Qt::AlignLeft|Qt::AlignVCenter)
+ << int(Qt::AlignRight);
+
+ QTest::newRow("vertical left aligned")
+ << int(Qt::Vertical)
+ << int(Qt::AlignLeft|Qt::AlignVCenter)
+ << int(Qt::AlignLeft);
+}
+
+void tst_QHeaderView::defaultAlignment()
+{
+ QFETCH(int, direction);
+ QFETCH(int, initial);
+ QFETCH(int, alignment);
+
+ SimpleModel m;
+
+ QHeaderView header((Qt::Orientation)direction);
+ header.setModel(&m);
+
+ QCOMPARE(header.defaultAlignment(), (Qt::Alignment)initial);
+ header.setDefaultAlignment((Qt::Alignment)alignment);
+ QCOMPARE(header.defaultAlignment(), (Qt::Alignment)alignment);
+}
+
+void tst_QHeaderView::globalResizeMode_data()
+{
+ QTest::addColumn<int>("direction");
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("insert");
+
+ QTest::newRow("horizontal ResizeToContents 0")
+ << int(Qt::Horizontal)
+ << int(QHeaderView::ResizeToContents)
+ << 0;
+}
+
+void tst_QHeaderView::globalResizeMode()
+{
+ QFETCH(int, direction);
+ QFETCH(int, mode);
+ QFETCH(int, insert);
+
+ QStandardItemModel m(4, 4);
+ QHeaderView h((Qt::Orientation)direction);
+ h.setModel(&m);
+
+ h.setResizeMode((QHeaderView::ResizeMode)mode);
+ m.insertRow(insert);
+ for (int i = 0; i < h.count(); ++i)
+ QCOMPARE(h.resizeMode(i), (QHeaderView::ResizeMode)mode);
+}
+
+
+void tst_QHeaderView::sectionPressedSignal_data()
+{
+ QTest::addColumn<int>("direction");
+ QTest::addColumn<bool>("clickable");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("horizontal unclickable 0")
+ << int(Qt::Horizontal)
+ << false
+ << 0;
+
+ QTest::newRow("horizontal clickable 1")
+ << int(Qt::Horizontal)
+ << true
+ << 1;
+}
+
+void tst_QHeaderView::sectionPressedSignal()
+{
+ QFETCH(int, direction);
+ QFETCH(bool, clickable);
+ QFETCH(int, count);
+
+ QStandardItemModel m(4, 4);
+ QHeaderView h((Qt::Orientation)direction);
+
+ h.setModel(&m);
+ h.show();
+ h.setClickable(clickable);
+
+ QSignalSpy spy(&h, SIGNAL(sectionPressed(int)));
+
+ QCOMPARE(spy.count(), 0);
+ QTest::mousePress(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
+ QCOMPARE(spy.count(), count);
+}
+
+void tst_QHeaderView::sectionClickedSignal()
+{
+ QFETCH(int, direction);
+ QFETCH(bool, clickable);
+ QFETCH(int, count);
+
+ QStandardItemModel m(4, 4);
+ QHeaderView h((Qt::Orientation)direction);
+
+ h.setModel(&m);
+ h.show();
+ h.setClickable(clickable);
+ h.setSortIndicatorShown(true);
+
+ QSignalSpy spy(&h, SIGNAL(sectionClicked(int)));
+ QSignalSpy spy2(&h, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)));
+
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy2.count(), 0);
+ QTest::mouseClick(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
+ QCOMPARE(spy.count(), count);
+ QCOMPARE(spy2.count(), count);
+
+ //now let's try with the sort indicator hidden (the result should be the same
+ spy.clear();
+ spy2.clear();
+ h.setSortIndicatorShown(false);
+ QTest::mouseClick(h.viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(5, 5));
+ QCOMPARE(spy.count(), count);
+ QCOMPARE(spy2.count(), count);
+}
+
+void tst_QHeaderView::defaultSectionSize_data()
+{
+ QTest::addColumn<int>("direction");
+ QTest::addColumn<int>("oldDefaultSize");
+ QTest::addColumn<int>("newDefaultSize");
+
+ //QTest::newRow("horizontal,-5") << int(Qt::Horizontal) << 100 << -5;
+ QTest::newRow("horizontal, 0") << int(Qt::Horizontal) << 100 << 0;
+ QTest::newRow("horizontal, 5") << int(Qt::Horizontal) << 100 << 5;
+ QTest::newRow("horizontal,25") << int(Qt::Horizontal) << 100 << 5;
+}
+
+void tst_QHeaderView::defaultSectionSize()
+{
+ QFETCH(int, direction);
+ QFETCH(int, oldDefaultSize);
+ QFETCH(int, newDefaultSize);
+
+ QStandardItemModel m(4, 4);
+ QHeaderView h((Qt::Orientation)direction);
+
+ h.setModel(&m);
+
+ QCOMPARE(h.defaultSectionSize(), oldDefaultSize);
+ h.setDefaultSectionSize(newDefaultSize);
+ QCOMPARE(h.defaultSectionSize(), newDefaultSize);
+ h.reset();
+ for (int i = 0; i < h.count(); ++i)
+ QCOMPARE(h.sectionSize(i), newDefaultSize);
+}
+
+void tst_QHeaderView::hideAndInsert_data()
+{
+ QTest::addColumn<int>("direction");
+ QTest::addColumn<int>("hide");
+ QTest::addColumn<int>("insert");
+ QTest::addColumn<int>("hidden");
+
+ QTest::newRow("horizontal, 0, 0") << int(Qt::Horizontal) << 0 << 0 << 1;
+}
+
+void tst_QHeaderView::hideAndInsert()
+{
+ QFETCH(int, direction);
+ QFETCH(int, hide);
+ QFETCH(int, insert);
+ QFETCH(int, hidden);
+
+ QStandardItemModel m(4, 4);
+ QHeaderView h((Qt::Orientation)direction);
+
+ h.setModel(&m);
+
+ h.setSectionHidden(hide, true);
+
+ if (direction == Qt::Vertical)
+ m.insertRow(insert);
+ else
+ m.insertColumn(insert);
+
+ for (int i = 0; i < h.count(); ++i)
+ if (i != hidden)
+ QCOMPARE(h.isSectionHidden(i), false);
+ else
+ QCOMPARE(h.isSectionHidden(i), true);
+}
+
+void tst_QHeaderView::removeSection()
+{
+//test that removing a hidden section gives the expected result: the next row should be hidden
+//(see task
+ const int hidden = 3; //section that will be hidden
+ const QStringList list = QStringList() << "0" << "1" << "2" << "3" << "4" << "5" << "6";
+
+ QStringListModel model( list );
+ QHeaderView view(Qt::Vertical);
+ view.setModel(&model);
+ view.hideSection(hidden);
+ view.hideSection(1);
+ model.removeRow(1);
+ view.show();
+
+ for(int i = 0; i < view.count(); i++) {
+ if (i == (hidden-1)) { //-1 because we removed a row in the meantime
+ QCOMPARE(view.sectionSize(i), 0);
+ QVERIFY(view.isSectionHidden(i));
+ } else {
+ QCOMPARE(view.sectionSize(i), view.defaultSectionSize() );
+ QVERIFY(!view.isSectionHidden(i));
+ }
+ }
+}
+
+void tst_QHeaderView::preserveHiddenSectionWidth()
+{
+ const QStringList list = QStringList() << "0" << "1" << "2" << "3";
+
+ QStringListModel model( list );
+ QHeaderView view(Qt::Vertical);
+ view.setModel(&model);
+ view.resizeSection(0, 100);
+ view.resizeSection(1, 10);
+ view.resizeSection(2, 50);
+ view.setResizeMode(3, QHeaderView::Stretch);
+ view.show();
+
+ view.hideSection(2);
+ model.removeRow(1);
+ view.showSection(1);
+ QCOMPARE(view.sectionSize(0), 100);
+ QCOMPARE(view.sectionSize(1), 50);
+
+ view.hideSection(1);
+ model.insertRow(1);
+ view.showSection(2);
+ QCOMPARE(view.sectionSize(0), 100);
+ QCOMPARE(view.sectionSize(1), view.defaultSectionSize());
+ QCOMPARE(view.sectionSize(2), 50);
+}
+
+void tst_QHeaderView::invisibleStretchLastSection()
+{
+ int count = 6;
+ QStandardItemModel model(1, count);
+ QHeaderView view(Qt::Horizontal);
+ view.setModel(&model);
+ int height = view.height();
+
+ view.resize(view.defaultSectionSize() * (count / 2), height); // don't show all sections
+ view.show();
+ view.setStretchLastSection(true);
+ // stretch section is not visible; it should not be stretched
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(view.sectionSize(i), view.defaultSectionSize());
+
+ view.resize(view.defaultSectionSize() * (count + 1), height); // give room to stretch
+
+ // stretch section is visible; it should be stretched
+ for (int i = 0; i < count - 1; ++i)
+ QCOMPARE(view.sectionSize(i), view.defaultSectionSize());
+ QCOMPARE(view.sectionSize(count - 1), view.defaultSectionSize() * 2);
+}
+
+void tst_QHeaderView::emptySectionSpan()
+{
+ QHeaderViewPrivate::SectionSpan span;
+ QCOMPARE(span.sectionSize(), 0);
+}
+
+void tst_QHeaderView::task236450_hidden_data()
+{
+ QTest::addColumn<QList<int> >("hide1");
+ QTest::addColumn<QList<int> >("hide2");
+
+ QTest::newRow("set 1") << (QList<int>() << 1 << 3)
+ << (QList<int>() << 1 << 5);
+
+ QTest::newRow("set 2") << (QList<int>() << 2 << 3)
+ << (QList<int>() << 1 << 5);
+
+ QTest::newRow("set 3") << (QList<int>() << 0 << 2 << 4)
+ << (QList<int>() << 2 << 3 << 5);
+
+}
+
+void tst_QHeaderView::task236450_hidden()
+{
+ QFETCH(QList<int>, hide1);
+ QFETCH(QList<int>, hide2);
+ const QStringList list = QStringList() << "0" << "1" << "2" << "3" << "4" << "5";
+
+ QStringListModel model( list );
+ protected_QHeaderView view(Qt::Vertical);
+ view.setModel(&model);
+ view.show();
+
+ foreach (int i, hide1)
+ view.hideSection(i);
+
+ QCOMPARE(view.hiddenSectionCount(), hide1.count());
+ for (int i = 0; i < 6; i++) {
+ QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i));
+ }
+
+ view.setDefaultSectionSize(2);
+ view.scheduleDelayedItemsLayout();
+ view.executeDelayedItemsLayout(); //force to do a relayout
+
+ QCOMPARE(view.hiddenSectionCount(), hide1.count());
+ for (int i = 0; i < 6; i++) {
+ QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i));
+ view.setSectionHidden(i, hide2.contains(i));
+ }
+
+ QCOMPARE(view.hiddenSectionCount(), hide2.count());
+ for (int i = 0; i < 6; i++) {
+ QCOMPARE(!view.isSectionHidden(i), !hide2.contains(i));
+ }
+
+}
+
+void tst_QHeaderView::task248050_hideRow()
+{
+ //this is the sequence of events that make the task fail
+ protected_QHeaderView header(Qt::Vertical);
+ QStandardItemModel model(0, 1);
+ header.setStretchLastSection(false);
+ header.setDefaultSectionSize(17);
+ header.setModel(&model);
+ header.doItemsLayout();
+
+ model.setRowCount(3);
+
+ QCOMPARE(header.sectionPosition(2), 17*2);
+
+ header.hideSection(1);
+ QCOMPARE(header.sectionPosition(2), 17);
+
+ QTest::qWait(100);
+ //the size of the section shouldn't have changed
+ QCOMPARE(header.sectionPosition(2), 17);
+}
+
+
+//returns 0 if everything is fine.
+static int checkHeaderViewOrder(QHeaderView *view, const QVector<int> &expected)
+{
+ if (view->count() != expected.count())
+ return 1;
+
+ for (int i = 0; i < expected.count(); i++) {
+ if (view->logicalIndex(i) != expected.at(i))
+ return i + 10;
+ if (view->visualIndex(expected.at(i)) != i)
+ return i + 100;
+ }
+ return 0;
+}
+
+
+void tst_QHeaderView::QTBUG6058_reset()
+{
+ QStringListModel model1( QStringList() << "0" << "1" << "2" << "3" << "4" << "5" );
+ QStringListModel model2( QStringList() << "a" << "b" << "c" );
+ QSortFilterProxyModel proxy;
+
+ QHeaderView view(Qt::Vertical);
+ view.setModel(&proxy);
+ view.show();
+ QTest::qWait(20);
+
+ proxy.setSourceModel(&model1);
+ QApplication::processEvents();
+ view.swapSections(0,2);
+ view.swapSections(1,4);
+ QApplication::processEvents();
+ QCOMPARE(checkHeaderViewOrder(&view, QVector<int>() << 2 << 4 << 0 << 3 << 1 << 5) , 0);
+
+ proxy.setSourceModel(&model2);
+ QApplication::processEvents();
+ QCOMPARE(checkHeaderViewOrder(&view, QVector<int>() << 2 << 0 << 1 ) , 0);
+
+ proxy.setSourceModel(&model1);
+ QApplication::processEvents();
+ QCOMPARE(checkHeaderViewOrder(&view, QVector<int>() << 2 << 0 << 1 << 3 << 4 << 5 ) , 0);
+}
+
+void tst_QHeaderView::QTBUG7833_sectionClicked()
+{
+
+
+
+
+ QTableView tv;
+ QStandardItemModel *sim = new QStandardItemModel(&tv);
+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv);
+ proxyModel->setSourceModel(sim);
+ proxyModel->setDynamicSortFilter(true);
+ proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+
+ QList<QStandardItem *> row;
+ for (int i = 0; i < 12; i++)
+ row.append(new QStandardItem(QString(QLatin1Char('A' + i))));
+ sim->appendRow(row);
+ row.clear();
+ for (int i = 12; i > 0; i--)
+ row.append(new QStandardItem(QString(QLatin1Char('A' + i))));
+ sim->appendRow(row);
+
+ tv.setSortingEnabled(true);
+ tv.horizontalHeader()->setSortIndicatorShown(true);
+ tv.horizontalHeader()->setClickable(true);
+ tv.horizontalHeader()->setStretchLastSection(true);
+ tv.horizontalHeader()->setResizeMode(QHeaderView::Interactive);
+
+ tv.setModel(proxyModel);
+ tv.setColumnHidden(5, true);
+ tv.setColumnHidden(6, true);
+ tv.horizontalHeader()->swapSections(8, 10);
+ tv.sortByColumn(1, Qt::AscendingOrder);
+
+ QSignalSpy clickedSpy(tv.horizontalHeader(), SIGNAL(sectionClicked(int)));
+ QSignalSpy pressedSpy(tv.horizontalHeader(), SIGNAL(sectionPressed(int)));
+
+
+ QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier,
+ QPoint(tv.horizontalHeader()->sectionViewportPosition(11) + tv.horizontalHeader()->sectionSize(11)/2, 5));
+ QCOMPARE(clickedSpy.count(), 1);
+ QCOMPARE(pressedSpy.count(), 1);
+ QCOMPARE(clickedSpy.at(0).at(0).toInt(), 11);
+ QCOMPARE(pressedSpy.at(0).at(0).toInt(), 11);
+
+ QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier,
+ QPoint(tv.horizontalHeader()->sectionViewportPosition(8) + tv.horizontalHeader()->sectionSize(0)/2, 5));
+
+ QCOMPARE(clickedSpy.count(), 2);
+ QCOMPARE(pressedSpy.count(), 2);
+ QCOMPARE(clickedSpy.at(1).at(0).toInt(), 8);
+ QCOMPARE(pressedSpy.at(1).at(0).toInt(), 8);
+
+ QTest::mouseClick(tv.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier,
+ QPoint(tv.horizontalHeader()->sectionViewportPosition(0) + tv.horizontalHeader()->sectionSize(0)/2, 5));
+
+ QCOMPARE(clickedSpy.count(), 3);
+ QCOMPARE(pressedSpy.count(), 3);
+ QCOMPARE(clickedSpy.at(2).at(0).toInt(), 0);
+ QCOMPARE(pressedSpy.at(2).at(0).toInt(), 0);
+}
+
+void tst_QHeaderView::QTBUG8650_crashOnInsertSections()
+{
+ QStringList headerLabels;
+ QHeaderView view(Qt::Horizontal);
+ QStandardItemModel model(2,2);
+ view.setModel(&model);
+ view.moveSection(1, 0);
+ view.hideSection(0);
+
+ QList<QStandardItem *> items;
+ items << new QStandardItem("c");
+ model.insertColumn(0, items);
+}
+
+void tst_QHeaderView::QTBUG12268_hiddenMovedSectionSorting()
+{
+ QTableView view;
+ QStandardItemModel *model = new QStandardItemModel(4,3, &view);
+ for (int i = 0; i< model->rowCount(); ++i)
+ for (int j = 0; j< model->columnCount(); ++j)
+ model->setData(model->index(i,j), QString("item [%1,%2]").arg(i).arg(j));
+ view.setModel(model);
+ view.horizontalHeader()->setMovable(true);
+ view.setSortingEnabled(true);
+ view.sortByColumn(1, Qt::AscendingOrder);
+ view.horizontalHeader()->moveSection(0,2);
+ view.setColumnHidden(1, true);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1);
+ QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton);
+ QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1);
+}
+
+void tst_QHeaderView::initialSortOrderRole()
+{
+ QTableView view;
+ QStandardItemModel *model = new QStandardItemModel(4, 3, &view);
+ for (int i = 0; i< model->rowCount(); ++i)
+ for (int j = 0; j< model->columnCount(); ++j)
+ model->setData(model->index(i,j), QString("item [%1,%2]").arg(i).arg(j));
+ QStandardItem *ascendingItem = new QStandardItem();
+ QStandardItem *descendingItem = new QStandardItem();
+ ascendingItem->setData(Qt::AscendingOrder, Qt::InitialSortOrderRole);
+ descendingItem->setData(Qt::DescendingOrder, Qt::InitialSortOrderRole);
+ model->setHorizontalHeaderItem(1, ascendingItem);
+ model->setHorizontalHeaderItem(2, descendingItem);
+ view.setModel(model);
+ view.setSortingEnabled(true);
+ view.sortByColumn(0, Qt::AscendingOrder);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ const int column1Pos = view.horizontalHeader()->sectionViewportPosition(1) + 5; // +5 not to be on the handle
+ QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column1Pos, 0));
+ QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 1);
+ QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder);
+
+ const int column2Pos = view.horizontalHeader()->sectionViewportPosition(2) + 5; // +5 not to be on the handle
+ QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column2Pos, 0));
+ QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 2);
+ QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::DescendingOrder);
+
+ const int column0Pos = view.horizontalHeader()->sectionViewportPosition(0) + 5; // +5 not to be on the handle
+ QTest::mouseClick(view.horizontalHeader()->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(column0Pos, 0));
+ QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 0);
+ QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder);
+}
+
+QTEST_MAIN(tst_QHeaderView)
+#include "tst_qheaderview.moc"
diff --git a/tests/auto/widgets/itemviews/qidentityproxymodel/qidentityproxymodel.pro b/tests/auto/widgets/itemviews/qidentityproxymodel/qidentityproxymodel.pro
new file mode 100644
index 0000000000..141e72a8c0
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qidentityproxymodel/qidentityproxymodel.pro
@@ -0,0 +1,7 @@
+load(qttest_p4)
+
+mtdir = ../../../integrationtests/modeltest
+INCLUDEPATH += $$PWD/$${mtdir}
+QT += widgets
+SOURCES += tst_qidentityproxymodel.cpp $${mtdir}/dynamictreemodel.cpp $${mtdir}/modeltest.cpp
+HEADERS += $${mtdir}/dynamictreemodel.h $${mtdir}/modeltest.h
diff --git a/tests/auto/widgets/itemviews/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/widgets/itemviews/qidentityproxymodel/tst_qidentityproxymodel.cpp
new file mode 100644
index 0000000000..6d73cbe2e1
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qidentityproxymodel/tst_qidentityproxymodel.cpp
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtCore>
+#include <QtGui>
+#include <QtWidgets>
+
+#include "dynamictreemodel.h"
+#include "qidentityproxymodel.h"
+
+//TESTED CLASS=
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QModelIndex)
+
+class tst_QIdentityProxyModel : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ tst_QIdentityProxyModel();
+ virtual ~tst_QIdentityProxyModel();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void insertRows();
+ void removeRows();
+ void moveRows();
+ void reset();
+
+protected:
+ void verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex());
+
+private:
+ QStandardItemModel *m_model;
+ QIdentityProxyModel *m_proxy;
+};
+
+tst_QIdentityProxyModel::tst_QIdentityProxyModel()
+ : m_model(0), m_proxy(0)
+{
+
+}
+
+tst_QIdentityProxyModel::~tst_QIdentityProxyModel()
+{
+
+}
+
+void tst_QIdentityProxyModel::initTestCase()
+{
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+
+ m_model = new QStandardItemModel(0, 1);
+ m_proxy = new QIdentityProxyModel();
+}
+
+void tst_QIdentityProxyModel::cleanupTestCase()
+{
+ delete m_proxy;
+ delete m_model;
+}
+
+void tst_QIdentityProxyModel::init()
+{
+}
+
+void tst_QIdentityProxyModel::cleanup()
+{
+ m_model->clear();
+ m_model->insertColumns(0, 1);
+}
+
+void tst_QIdentityProxyModel::verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent)
+{
+ const int rows = model->rowCount(parent);
+ const int columns = model->columnCount(parent);
+ const QModelIndex proxyParent = m_proxy->mapFromSource(parent);
+
+ QVERIFY(m_proxy->mapToSource(proxyParent) == parent);
+ QVERIFY(rows == m_proxy->rowCount(proxyParent));
+ QVERIFY(columns == m_proxy->columnCount(proxyParent));
+
+ for (int row = 0; row < rows; ++row) {
+ for (int column = 0; column < columns; ++column) {
+ const QModelIndex idx = model->index(row, column, parent);
+ const QModelIndex proxyIdx = m_proxy->mapFromSource(idx);
+ QVERIFY(proxyIdx.model() == m_proxy);
+ QVERIFY(m_proxy->mapToSource(proxyIdx) == idx);
+ QVERIFY(proxyIdx.isValid());
+ QVERIFY(proxyIdx.row() == row);
+ QVERIFY(proxyIdx.column() == column);
+ QVERIFY(proxyIdx.parent() == proxyParent);
+ QVERIFY(proxyIdx.data() == idx.data());
+ QVERIFY(proxyIdx.flags() == idx.flags());
+ const int childCount = m_proxy->rowCount(proxyIdx);
+ const bool hasChildren = m_proxy->hasChildren(proxyIdx);
+ QVERIFY(model->hasChildren(idx) == hasChildren);
+ QVERIFY((childCount > 0) == hasChildren);
+
+ if (hasChildren)
+ verifyIdentity(model, idx);
+ }
+ }
+}
+
+/*
+ tests
+*/
+
+void tst_QIdentityProxyModel::insertRows()
+{
+ QStandardItem *parentItem = m_model->invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+
+ m_proxy->setSourceModel(m_model);
+
+ verifyIdentity(m_model);
+
+ QSignalSpy modelBeforeSpy(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
+ QSignalSpy modelAfterSpy(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)));
+ QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
+ QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsInserted(QModelIndex,int,int)));
+
+ QStandardItem *item = new QStandardItem(QString("new item"));
+ parentItem->appendRow(item);
+
+ QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size());
+ QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size());
+
+ QVERIFY(modelBeforeSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value<QModelIndex>()));
+ QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1));
+ QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2));
+
+ QVERIFY(modelAfterSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().first().value<QModelIndex>()));
+ QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1));
+ QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2));
+
+ verifyIdentity(m_model);
+
+}
+
+void tst_QIdentityProxyModel::removeRows()
+{
+ QStandardItem *parentItem = m_model->invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+
+ m_proxy->setSourceModel(m_model);
+
+ verifyIdentity(m_model);
+
+ QSignalSpy modelBeforeSpy(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
+ QSignalSpy modelAfterSpy(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)));
+ QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
+ QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsRemoved(QModelIndex,int,int)));
+
+ const QModelIndex topLevel = m_model->index(0, 0, QModelIndex());
+ const QModelIndex secondLevel = m_model->index(0, 0, topLevel);
+ const QModelIndex thirdLevel = m_model->index(0, 0, secondLevel);
+
+ QVERIFY(thirdLevel.isValid());
+
+ m_model->removeRow(0, secondLevel);
+
+ QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size());
+ QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size());
+
+ QVERIFY(modelBeforeSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value<QModelIndex>()));
+ QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1));
+ QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2));
+
+ QVERIFY(modelAfterSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().first().value<QModelIndex>()));
+ QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1));
+ QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2));
+
+ verifyIdentity(m_model);
+}
+
+void tst_QIdentityProxyModel::moveRows()
+{
+ DynamicTreeModel model;
+
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setAncestorRowNumbers(QList<int>() << 5);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+
+ m_proxy->setSourceModel(&model);
+
+ verifyIdentity(&model);
+
+ QSignalSpy modelBeforeSpy(&model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy modelAfterSpy(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+
+ {
+ ModelMoveCommand moveCommand(&model, 0);
+ moveCommand.setAncestorRowNumbers(QList<int>() << 5);
+ moveCommand.setStartRow(3);
+ moveCommand.setEndRow(4);
+ moveCommand.setDestRow(1);
+ moveCommand.doCommand();
+ }
+
+ QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size());
+ QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size());
+
+ QVERIFY(modelBeforeSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value<QModelIndex>()));
+ QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1));
+ QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2));
+ QVERIFY(modelBeforeSpy.first().at(3).value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().at(3).value<QModelIndex>()));
+ QVERIFY(modelBeforeSpy.first().at(4) == proxyBeforeSpy.first().at(4));
+
+ QVERIFY(modelAfterSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().first().value<QModelIndex>()));
+ QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1));
+ QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2));
+ QVERIFY(modelAfterSpy.first().at(3).value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().at(3).value<QModelIndex>()));
+ QVERIFY(modelAfterSpy.first().at(4) == proxyAfterSpy.first().at(4));
+
+ verifyIdentity(&model);
+
+ m_proxy->setSourceModel(0);
+}
+
+void tst_QIdentityProxyModel::reset()
+{
+ DynamicTreeModel model;
+
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setAncestorRowNumbers(QList<int>() << 5);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+
+ m_proxy->setSourceModel(&model);
+
+ verifyIdentity(&model);
+
+ QSignalSpy modelBeforeSpy(&model, SIGNAL(modelAboutToBeReset()));
+ QSignalSpy modelAfterSpy(&model, SIGNAL(modelReset()));
+ QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(modelAboutToBeReset()));
+ QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(modelReset()));
+
+ {
+ ModelResetCommandFixed resetCommand(&model, 0);
+ resetCommand.setAncestorRowNumbers(QList<int>() << 5);
+ resetCommand.setStartRow(3);
+ resetCommand.setEndRow(4);
+ resetCommand.setDestRow(1);
+ resetCommand.doCommand();
+ }
+
+ QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size());
+ QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size());
+
+ verifyIdentity(&model);
+ m_proxy->setSourceModel(0);
+}
+
+QTEST_MAIN(tst_QIdentityProxyModel)
+#include "tst_qidentityproxymodel.moc"
diff --git a/tests/auto/widgets/itemviews/qitemdelegate/.gitignore b/tests/auto/widgets/itemviews/qitemdelegate/.gitignore
new file mode 100644
index 0000000000..5faa678712
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemdelegate/.gitignore
@@ -0,0 +1 @@
+tst_qitemdelegate
diff --git a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro
new file mode 100644
index 0000000000..9a1a3b5e94
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qitemdelegate.cpp
+
+win32:!wince*: LIBS += -lUser32
+
diff --git a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
new file mode 100644
index 0000000000..e419a7f097
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
@@ -0,0 +1,1216 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qabstractitemview.h>
+#include <qstandarditemmodel.h>
+#include <qapplication.h>
+#include <qdatetimeedit.h>
+#include <qspinbox.h>
+#include <qlistview.h>
+#include <qtableview.h>
+#include <qtreeview.h>
+#include <qheaderview.h>
+#include <qitemeditorfactory.h>
+#include <qlineedit.h>
+#include <qvalidator.h>
+#include <qtablewidget.h>
+#include <qtreewidget.h>
+
+#include <QItemDelegate>
+#include <QAbstractItemDelegate>
+#include <QTextEdit>
+#include <QPlainTextEdit>
+#include <QDialog>
+
+Q_DECLARE_METATYPE(QAbstractItemDelegate::EndEditHint)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+#if defined (Q_OS_WIN) && !defined(Q_OS_WINCE)
+#include <windows.h>
+#define Q_CHECK_PAINTEVENTS \
+ if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \
+ QSKIP("The widgets don't get the paint events", SkipSingle);
+#else
+#define Q_CHECK_PAINTEVENTS
+#endif
+
+//Begin of class definitions
+
+class TestItemDelegate : public QItemDelegate
+{
+public:
+ TestItemDelegate(QObject *parent = 0) : QItemDelegate(parent) {}
+ ~TestItemDelegate() {}
+
+ void drawDisplay(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QRect &rect, const QString &text) const
+ {
+ displayText = text;
+ displayFont = option.font;
+ QItemDelegate::drawDisplay(painter, option, rect, text);
+ }
+
+ void drawDecoration(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QRect &rect, const QPixmap &pixmap) const
+ {
+ decorationPixmap = pixmap;
+ decorationRect = rect;
+ QItemDelegate::drawDecoration(painter, option, rect, pixmap);
+ }
+
+
+ inline QRect textRectangle(QPainter * painter, const QRect &rect,
+ const QFont &font, const QString &text) const
+ {
+ return QItemDelegate::textRectangle(painter, rect, font, text);
+ }
+
+ inline void doLayout(const QStyleOptionViewItem &option,
+ QRect *checkRect, QRect *pixmapRect,
+ QRect *textRect, bool hint) const
+ {
+ QItemDelegate::doLayout(option, checkRect, pixmapRect, textRect, hint);
+ }
+
+ inline QRect rect(const QStyleOptionViewItem &option,
+ const QModelIndex &index, int role) const
+ {
+ return QItemDelegate::rect(option, index, role);
+ }
+
+ inline bool eventFilter(QObject *object, QEvent *event)
+ {
+ return QItemDelegate::eventFilter(object, event);
+ }
+
+ inline bool editorEvent(QEvent *event,
+ QAbstractItemModel *model,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index)
+ {
+ return QItemDelegate::editorEvent(event, model, option, index);
+ }
+
+ // stored values for testing
+ mutable QString displayText;
+ mutable QFont displayFont;
+ mutable QPixmap decorationPixmap;
+ mutable QRect decorationRect;
+};
+
+class TestItemModel : public QAbstractTableModel
+{
+public:
+
+ enum Roles {
+ PixmapTestRole,
+ ImageTestRole,
+ IconTestRole,
+ ColorTestRole,
+ DoubleTestRole
+ };
+
+ TestItemModel(const QSize &size) : size(size) {}
+
+ ~TestItemModel() {}
+
+ int rowCount(const QModelIndex &parent) const
+ {
+ Q_UNUSED(parent);
+ return 1;
+ }
+
+ int columnCount(const QModelIndex &parent) const
+ {
+ Q_UNUSED(parent);
+ return 1;
+ }
+
+ QVariant data(const QModelIndex& index, int role) const
+ {
+ Q_UNUSED(index);
+ static QPixmap pixmap(size);
+ static QImage image(size, QImage::Format_Mono);
+ static QIcon icon(pixmap);
+ static QColor color(Qt::green);
+
+ switch (role) {
+ case PixmapTestRole: return pixmap;
+ case ImageTestRole: return image;
+ case IconTestRole: return icon;
+ case ColorTestRole: return color;
+ case DoubleTestRole: return 10.00000001;
+ default: break;
+ }
+
+ return QVariant();
+ }
+
+private:
+ QSize size;
+};
+
+class tst_QItemDelegate : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QItemDelegate();
+ virtual ~tst_QItemDelegate();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+ void getSetCheck();
+ void textRectangle_data();
+ void textRectangle();
+ void sizeHint_data();
+ void sizeHint();
+ void editorKeyPress_data();
+ void editorKeyPress();
+ void doubleEditorNegativeInput();
+ void font_data();
+ void font();
+ void doLayout_data();
+ void doLayout();
+ void rect_data();
+ void rect();
+ void eventFilter();
+ void dateTimeEditor_data();
+ void dateTimeEditor();
+ void decoration_data();
+ void decoration();
+ void editorEvent_data();
+ void editorEvent();
+ void enterKey_data();
+ void enterKey();
+
+ void task257859_finalizeEdit();
+ void QTBUG4435_keepSelectionOnCheck();
+};
+
+
+//End of class definitions
+
+// Testing get/set functions
+void tst_QItemDelegate::getSetCheck()
+{
+ QItemDelegate obj1;
+
+ // QItemEditorFactory * QItemDelegate::itemEditorFactory()
+ // void QItemDelegate::setItemEditorFactory(QItemEditorFactory *)
+ QItemEditorFactory *var1 = new QItemEditorFactory;
+ obj1.setItemEditorFactory(var1);
+ QCOMPARE(var1, obj1.itemEditorFactory());
+ obj1.setItemEditorFactory((QItemEditorFactory *)0);
+ QCOMPARE((QItemEditorFactory *)0, obj1.itemEditorFactory());
+ delete var1;
+
+ QCOMPARE(obj1.hasClipping(), true);
+ obj1.setClipping(false);
+ QCOMPARE(obj1.hasClipping(), false);
+ obj1.setClipping(true);
+ QCOMPARE(obj1.hasClipping(), true);
+}
+
+tst_QItemDelegate::tst_QItemDelegate()
+{
+}
+
+tst_QItemDelegate::~tst_QItemDelegate()
+{
+}
+
+void tst_QItemDelegate::initTestCase()
+{
+}
+
+void tst_QItemDelegate::cleanupTestCase()
+{
+}
+
+void tst_QItemDelegate::init()
+{
+}
+
+void tst_QItemDelegate::cleanup()
+{
+}
+
+void tst_QItemDelegate::textRectangle_data()
+{
+ QFont font;
+ QFontMetrics fontMetrics(font);
+ int pm = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
+ int margins = 2 * (pm + 1); // margin on each side of the text
+ int height = fontMetrics.height();
+
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QRect>("rect");
+ QTest::addColumn<QRect>("expected");
+
+ QTest::newRow("empty") << QString()
+ << QRect()
+ << QRect(0, 0, margins, height);
+}
+
+void tst_QItemDelegate::textRectangle()
+{
+ QFETCH(QString, text);
+ QFETCH(QRect, rect);
+ QFETCH(QRect, expected);
+
+ QFont font;
+ TestItemDelegate delegate;
+ QRect result = delegate.textRectangle(0, rect, font, text);
+
+ QCOMPARE(result, expected);
+}
+
+void tst_QItemDelegate::sizeHint_data()
+{
+ QTest::addColumn<QSize>("expected");
+
+ QFont font;
+ QFontMetrics fontMetrics(font);
+ //int m = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
+ QTest::newRow("empty")
+ << QSize(0, fontMetrics.height());
+
+}
+
+void tst_QItemDelegate::sizeHint()
+{
+ QFETCH(QSize, expected);
+
+ QModelIndex index;
+ QStyleOptionViewItem option;
+
+ TestItemDelegate delegate;
+ QSize result = delegate.sizeHint(option, index);
+ QCOMPARE(result, expected);
+}
+
+void tst_QItemDelegate::editorKeyPress_data()
+{
+ QTest::addColumn<QString>("initial");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("foo bar")
+ << QString("foo")
+ << QString("bar");
+}
+
+void tst_QItemDelegate::editorKeyPress()
+{
+ QFETCH(QString, initial);
+ QFETCH(QString, expected);
+
+ QStandardItemModel model;
+ model.appendRow(new QStandardItem(initial));
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex index = model.index(0, 0);
+ view.setCurrentIndex(index); // the editor will only selectAll on the current index
+ view.edit(index);
+
+ QList<QLineEdit*> lineEditors = qFindChildren<QLineEdit *>(view.viewport());
+ QCOMPARE(lineEditors.count(), 1);
+
+ QLineEdit *editor = lineEditors.at(0);
+ QCOMPARE(editor->selectedText(), initial);
+
+ QTest::keyClicks(editor, expected);
+ QTest::keyClick(editor, Qt::Key_Enter);
+ QApplication::processEvents();
+
+ QCOMPARE(index.data().toString(), expected);
+}
+
+void tst_QItemDelegate::doubleEditorNegativeInput()
+{
+ QStandardItemModel model;
+
+ QStandardItem *item = new QStandardItem;
+ item->setData(10.0, Qt::DisplayRole);
+ model.appendRow(item);
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex index = model.index(0, 0);
+ view.setCurrentIndex(index); // the editor will only selectAll on the current index
+ view.edit(index);
+
+ QList<QDoubleSpinBox*> editors = qFindChildren<QDoubleSpinBox *>(view.viewport());
+ QCOMPARE(editors.count(), 1);
+
+ QDoubleSpinBox *editor = editors.at(0);
+ QCOMPARE(editor->value(), double(10));
+
+ QTest::keyClick(editor, Qt::Key_Minus);
+ QTest::keyClick(editor, Qt::Key_1);
+ QTest::keyClick(editor, Qt::Key_0);
+ QTest::keyClick(editor, Qt::Key_Comma); //support both , and . locales
+ QTest::keyClick(editor, Qt::Key_Period);
+ QTest::keyClick(editor, Qt::Key_0);
+ QTest::keyClick(editor, Qt::Key_Enter);
+ QApplication::processEvents();
+
+ QCOMPARE(index.data().toString(), QString("-10"));
+}
+
+void tst_QItemDelegate::font_data()
+{
+ QTest::addColumn<QString>("itemText");
+ QTest::addColumn<QString>("properties");
+ QTest::addColumn<QFont>("itemFont");
+ QTest::addColumn<QFont>("viewFont");
+
+ QFont itemFont;
+ itemFont.setItalic(true);
+ QFont viewFont;
+
+ QTest::newRow("foo italic")
+ << QString("foo")
+ << QString("italic")
+ << itemFont
+ << viewFont;
+
+ itemFont.setItalic(true);
+
+ QTest::newRow("foo bold")
+ << QString("foo")
+ << QString("bold")
+ << itemFont
+ << viewFont;
+
+ itemFont.setFamily(itemFont.defaultFamily());
+
+ QTest::newRow("foo family")
+ << QString("foo")
+ << QString("family")
+ << itemFont
+ << viewFont;
+ }
+
+void tst_QItemDelegate::font()
+{
+ Q_CHECK_PAINTEVENTS
+
+ QFETCH(QString, itemText);
+ QFETCH(QString, properties);
+ QFETCH(QFont, itemFont);
+ QFETCH(QFont, viewFont);
+
+ QTableWidget table(1, 1);
+ table.setFont(viewFont);
+
+ TestItemDelegate *delegate = new TestItemDelegate(&table);
+ table.setItemDelegate(delegate);
+ table.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&table);
+#endif
+
+ QTableWidgetItem *item = new QTableWidgetItem;
+ item->setText(itemText);
+ item->setFont(itemFont);
+ table.setItem(0, 0, item);
+
+ QApplication::processEvents();
+#ifdef Q_WS_QWS
+ QApplication::sendPostedEvents(); //glib workaround
+#endif
+
+ QTRY_COMPARE(delegate->displayText, item->text());
+ if (properties.contains("italic")) {
+ QCOMPARE(delegate->displayFont.italic(), item->font().italic());
+ }
+ if (properties.contains("bold")){
+ QCOMPARE(delegate->displayFont.bold(), item->font().bold());
+ }
+ if (properties.contains("family")){
+ QCOMPARE(delegate->displayFont.family(), item->font().family());
+ }
+}
+
+//Testing the different QRect created by the doLayout function.
+//Tests are made with different values for the QStyleOptionViewItem properties:
+//decorationPosition and position.
+
+void tst_QItemDelegate::doLayout_data()
+{
+ QTest::addColumn<int>("position");
+ QTest::addColumn<int>("direction");
+ QTest::addColumn<bool>("hint");
+ QTest::addColumn<QRect>("itemRect");
+ QTest::addColumn<QRect>("checkRect");
+ QTest::addColumn<QRect>("pixmapRect");
+ QTest::addColumn<QRect>("textRect");
+ QTest::addColumn<QRect>("expectedCheckRect");
+ QTest::addColumn<QRect>("expectedPixmapRect");
+ QTest::addColumn<QRect>("expectedTextRect");
+
+ int m = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
+ //int item = 400;
+ //int check = 50;
+ //int pixmap = 1000;
+ //int text = 400;
+
+ QTest::newRow("top, left to right, hint")
+ << (int)QStyleOptionViewItem::Top
+ << (int)Qt::LeftToRight
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(m, 0, 50 + 2*m, 1000)
+ << QRect(50 + 2*m, 0, 1000 + 2*m, 1000 + m)
+ << QRect(50 + 2*m, 1000 + m, 1000 + 2*m, 400);
+ /*
+ QTest::newRow("top, left to right, limited")
+ << (int)QStyleOptionViewItem::Top
+ << (int)Qt::LeftToRight
+ << false
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(m, (400/2) - (50/2), 50, 50)
+ << QRect(50 + 2*m, 0, 1000, 1000)
+ << QRect(50 + 2*m, 1000 + m, 400 - (50 + 2*m), 400 - 1000 - m);
+ */
+ QTest::newRow("top, right to left, hint")
+ << (int)QStyleOptionViewItem::Top
+ << (int)Qt::RightToLeft
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(1000 + 2 * m, 0, 50 + 2 * m, 1000)
+ << QRect(0, 0, 1000 + 2 * m, 1000 + m)
+ << QRect(0, 1000 + m, 1000 + 2 * m, 400);
+
+ QTest::newRow("bottom, left to right, hint")
+ << (int)QStyleOptionViewItem::Bottom
+ << (int)Qt::LeftToRight
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(m, 0, 50 + 2 * m, 1000)
+ << QRect(50 + 2 * m, 400 + m, 1000 + 2 * m, 1000)
+ << QRect(50 + 2 * m, 0, 1000 + 2 * m, 400 + m);
+
+ QTest::newRow("bottom, right to left, hint")
+ << (int)QStyleOptionViewItem::Bottom
+ << (int)Qt::RightToLeft
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(1000 + 2 * m, 0, 50 + 2 * m, 1000)
+ << QRect(0, 400 + m, 1000 + 2 * m, 1000)
+ << QRect(0, 0, 1000 + 2 * m, 400 + m);
+
+ QTest::newRow("left, left to right, hint")
+ << (int)QStyleOptionViewItem::Left
+ << (int)Qt::LeftToRight
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(m, 0, 50 + 2 * m, 1000)
+ << QRect(50 + 2 * m, 0, 1000 + 2 * m, 1000)
+ << QRect(1050 + 4 * m, 0, 400 + 2 * m, 1000);
+
+ QTest::newRow("left, right to left, hint")
+ << (int)QStyleOptionViewItem::Left
+ << (int)Qt::RightToLeft
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(1400 + 4 * m, 0, 50 + 2 * m, 1000)
+ << QRect(400 + 2 * m, 0, 1000 + 2 * m, 1000)
+ << QRect(0, 0, 400 + 2 * m, 1000);
+
+ QTest::newRow("right, left to right, hint")
+ << (int)QStyleOptionViewItem::Right
+ << (int)Qt::LeftToRight
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(m, 0, 50 + 2 * m, 1000)
+ << QRect(450 + 4 * m, 0, 1000 + 2 * m, 1000)
+ << QRect(50 + 2 * m, 0, 400 + 2 * m, 1000);
+
+ QTest::newRow("right, right to left, hint")
+ << (int)QStyleOptionViewItem::Right
+ << (int)Qt::RightToLeft
+ << true
+ << QRect(0, 0, 400, 400)
+ << QRect(0, 0, 50, 50)
+ << QRect(0, 0, 1000, 1000)
+ << QRect(0, 0, 400, 400)
+ << QRect(1400 + 4 * m, 0, 50 + 2 * m, 1000)
+ << QRect(0, 0, 1000 + 2 * m, 1000)
+ << QRect(1000 + 2 * m, 0, 400 + 2 * m, 1000);
+}
+
+void tst_QItemDelegate::doLayout()
+{
+ QFETCH(int, position);
+ QFETCH(int, direction);
+ QFETCH(bool, hint);
+ QFETCH(QRect, itemRect);
+ QFETCH(QRect, checkRect);
+ QFETCH(QRect, pixmapRect);
+ QFETCH(QRect, textRect);
+ QFETCH(QRect, expectedCheckRect);
+ QFETCH(QRect, expectedPixmapRect);
+ QFETCH(QRect, expectedTextRect);
+
+ TestItemDelegate delegate;
+ QStyleOptionViewItem option;
+
+ option.rect = itemRect;
+ option.decorationPosition = (QStyleOptionViewItem::Position)position;
+ option.direction = (Qt::LayoutDirection)direction;
+
+ delegate.doLayout(option, &checkRect, &pixmapRect, &textRect, hint);
+
+ QCOMPARE(checkRect, expectedCheckRect);
+ QCOMPARE(pixmapRect, expectedPixmapRect);
+ QCOMPARE(textRect, expectedTextRect);
+}
+
+void tst_QItemDelegate::rect_data()
+{
+ QTest::addColumn<int>("role");
+ QTest::addColumn<QSize>("size");
+ QTest::addColumn<QRect>("expected");
+
+ QTest::newRow("pixmap")
+ << (int)TestItemModel::PixmapTestRole
+ << QSize(200, 300)
+ << QRect(0, 0, 200, 300);
+
+ QTest::newRow("image")
+ << (int)TestItemModel::ImageTestRole
+ << QSize(200, 300)
+ << QRect(0, 0, 200, 300);
+
+ QTest::newRow("icon")
+ << (int)TestItemModel::IconTestRole
+ << QSize(200, 300)
+ << QRect(0, 0, 200, 300);
+
+ QTest::newRow("color")
+ << (int)TestItemModel::ColorTestRole
+ << QSize(200, 300)
+ << QRect(0, 0, 200, 300);
+
+ QTest::newRow("double")
+ << (int)TestItemModel::DoubleTestRole
+ << QSize()
+ << QRect();
+}
+
+void tst_QItemDelegate::rect()
+{
+ QFETCH(int, role);
+ QFETCH(QSize, size);
+ QFETCH(QRect, expected);
+
+ TestItemModel model(size);
+ QStyleOptionViewItem option;
+ TestItemDelegate delegate;
+ option.decorationSize = size;
+
+ if (role == TestItemModel::DoubleTestRole)
+ expected = delegate.textRectangle(0, QRect(), QFont(), QLatin1String("10.00000001"));
+
+ QModelIndex index = model.index(0, 0);
+ QVERIFY(index.isValid());
+ QRect result = delegate.rect(option, index, role);
+ QCOMPARE(result, expected);
+}
+
+//TODO : Add a test for the keyPress event
+//with Qt::Key_Enter and Qt::Key_Return
+void tst_QItemDelegate::eventFilter()
+{
+ TestItemDelegate delegate;
+ QWidget widget;
+ QEvent *event;
+
+ qRegisterMetaType<QAbstractItemDelegate::EndEditHint>("QAbstractItemDelegate::EndEditHint");
+
+ QSignalSpy commitDataSpy(&delegate, SIGNAL(commitData(QWidget *)));
+ QSignalSpy closeEditorSpy(&delegate,
+ SIGNAL(closeEditor(QWidget *,
+ QAbstractItemDelegate::EndEditHint)));
+
+ //Subtest KeyPress
+ //For each test we send a key event and check if signals were emitted.
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier);
+ QVERIFY(delegate.eventFilter(&widget, event));
+ QCOMPARE(closeEditorSpy.count(), 1);
+ QCOMPARE(commitDataSpy.count(), 1);
+ delete event;
+
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier);
+ QVERIFY(delegate.eventFilter(&widget, event));
+ QCOMPARE(closeEditorSpy.count(), 2);
+ QCOMPARE(commitDataSpy.count(), 2);
+ delete event;
+
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
+ QVERIFY(delegate.eventFilter(&widget, event));
+ QCOMPARE(closeEditorSpy.count(), 3);
+ QCOMPARE(commitDataSpy.count(), 2);
+ delete event;
+
+ event = new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
+ QVERIFY(!delegate.eventFilter(&widget, event));
+ QCOMPARE(closeEditorSpy.count(), 3);
+ QCOMPARE(commitDataSpy.count(), 2);
+ delete event;
+
+ //Subtest focusEvent
+ event = new QFocusEvent(QEvent::FocusOut);
+ QVERIFY(!delegate.eventFilter(&widget, event));
+ QCOMPARE(closeEditorSpy.count(), 4);
+ QCOMPARE(commitDataSpy.count(), 3);
+ delete event;
+}
+
+void tst_QItemDelegate::dateTimeEditor_data()
+{
+ QTest::addColumn<QTime>("time");
+ QTest::addColumn<QDate>("date");
+
+ QTest::newRow("data")
+ << QTime(7, 16, 34)
+ << QDate(2006, 10, 31);
+}
+
+void tst_QItemDelegate::dateTimeEditor()
+{
+ QFETCH(QTime, time);
+ QFETCH(QDate, date);
+
+ QTableWidgetItem *item1 = new QTableWidgetItem;
+ item1->setData(Qt::DisplayRole, time);
+
+ QTableWidgetItem *item2 = new QTableWidgetItem;
+ item2->setData(Qt::DisplayRole, date);
+
+ QTableWidgetItem *item3 = new QTableWidgetItem;
+ item3->setData(Qt::DisplayRole, QDateTime(date, time));
+
+ QTableWidget widget(1, 3);
+ widget.setItem(0, 0, item1);
+ widget.setItem(0, 1, item2);
+ widget.setItem(0, 2, item3);
+ widget.show();
+
+ widget.editItem(item1);
+
+ QTestEventLoop::instance().enterLoop(1);
+
+ QTimeEdit *timeEditor = qFindChild<QTimeEdit *>(widget.viewport());
+ QVERIFY(timeEditor);
+ QCOMPARE(timeEditor->time(), time);
+
+ widget.clearFocus();
+ qApp->setActiveWindow(&widget);
+ widget.setFocus();
+ widget.editItem(item2);
+
+ QTestEventLoop::instance().enterLoop(1);
+
+ QDateEdit *dateEditor = qFindChild<QDateEdit *>(widget.viewport());
+ QVERIFY(dateEditor);
+ QCOMPARE(dateEditor->date(), date);
+
+ widget.clearFocus();
+ widget.setFocus();
+ widget.editItem(item3);
+
+ QTestEventLoop::instance().enterLoop(1);
+
+ QList<QDateTimeEdit *> dateTimeEditors = widget.findChildren<QDateTimeEdit *>();
+ QDateTimeEdit *dateTimeEditor = 0;
+ foreach(dateTimeEditor, dateTimeEditors)
+ if (dateTimeEditor->metaObject()->className() == QLatin1String("QDateTimeEdit"))
+ break;
+ QVERIFY(dateTimeEditor);
+ QCOMPARE(dateTimeEditor->date(), date);
+ QCOMPARE(dateTimeEditor->time(), time);
+}
+
+void tst_QItemDelegate::decoration_data()
+{
+ QTest::addColumn<int>("type");
+ QTest::addColumn<QSize>("size");
+ QTest::addColumn<QSize>("expected");
+
+ int pm = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
+
+ QTest::newRow("pixmap 30x30")
+ << (int)QVariant::Pixmap
+ << QSize(30, 30)
+ << QSize(30, 30);
+
+ QTest::newRow("image 30x30")
+ << (int)QVariant::Image
+ << QSize(30, 30)
+ << QSize(30, 30);
+
+//The default engine scales pixmaps down if required, but never up. For WinCE we need bigger IconSize than 30
+ QTest::newRow("icon 30x30")
+ << (int)QVariant::Icon
+ << QSize(60, 60)
+ << QSize(pm, pm);
+
+ QTest::newRow("color 30x30")
+ << (int)QVariant::Color
+ << QSize(30, 30)
+ << QSize(pm, pm);
+
+ // This demands too much memory and potentially hangs. Feel free to uncomment
+ // for your own testing.
+// QTest::newRow("pixmap 30x30 big")
+// << (int)QVariant::Pixmap
+// << QSize(1024, 1024) // Over 1M
+// << QSize(1024, 1024);
+}
+
+void tst_QItemDelegate::decoration()
+{
+ Q_CHECK_PAINTEVENTS
+
+ QFETCH(int, type);
+ QFETCH(QSize, size);
+ QFETCH(QSize, expected);
+
+ QTableWidget table(1, 1);
+ TestItemDelegate delegate;
+ table.setItemDelegate(&delegate);
+ table.show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&table);
+#endif
+ QApplication::setActiveWindow(&table);
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&table));
+
+ QVariant value;
+ switch ((QVariant::Type)type) {
+ case QVariant::Pixmap: {
+ QPixmap pm(size);
+ pm.fill(Qt::black);
+ value = pm;
+ break;
+ }
+ case QVariant::Image: {
+ QImage img(size, QImage::Format_Mono);
+ qMemSet(img.bits(), 0, img.byteCount());
+ value = img;
+ break;
+ }
+ case QVariant::Icon: {
+ QPixmap pm(size);
+ pm.fill(Qt::black);
+ value = QIcon(pm);
+ break;
+ }
+ case QVariant::Color:
+ value = QColor(Qt::green);
+ break;
+ default:
+ break;
+ }
+
+ QTableWidgetItem *item = new QTableWidgetItem;
+ item->setData(Qt::DecorationRole, value);
+ table.setItem(0, 0, item);
+ item->setSelected(true);
+
+ QApplication::processEvents();
+
+ QTRY_COMPARE(delegate.decorationRect.size(), expected);
+}
+
+void tst_QItemDelegate::editorEvent_data()
+{
+ QTest::addColumn<QRect>("rect");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<int>("checkState");
+ QTest::addColumn<int>("flags");
+ QTest::addColumn<bool>("inCheck");
+ QTest::addColumn<int>("type");
+ QTest::addColumn<int>("button");
+ QTest::addColumn<bool>("edited");
+ QTest::addColumn<int>("expectedCheckState");
+
+ QTest::newRow("unchecked, checkable, release")
+ << QRect(0, 0, 20, 20)
+ << QString("foo")
+ << (int)(Qt::Unchecked)
+ << (int)(Qt::ItemIsEditable
+ |Qt::ItemIsSelectable
+ |Qt::ItemIsUserCheckable
+ |Qt::ItemIsEnabled
+ |Qt::ItemIsDragEnabled
+ |Qt::ItemIsDropEnabled)
+ << true
+ << (int)(QEvent::MouseButtonRelease)
+ << (int)(Qt::LeftButton)
+ << true
+ << (int)(Qt::Checked);
+
+ QTest::newRow("checked, checkable, release")
+ << QRect(0, 0, 20, 20)
+ << QString("foo")
+ << (int)(Qt::Checked)
+ << (int)(Qt::ItemIsEditable
+ |Qt::ItemIsSelectable
+ |Qt::ItemIsUserCheckable
+ |Qt::ItemIsEnabled
+ |Qt::ItemIsDragEnabled
+ |Qt::ItemIsDropEnabled)
+ << true
+ << (int)(QEvent::MouseButtonRelease)
+ << (int)(Qt::LeftButton)
+ << true
+ << (int)(Qt::Unchecked);
+
+ QTest::newRow("unchecked, checkable, release")
+ << QRect(0, 0, 20, 20)
+ << QString("foo")
+ << (int)(Qt::Unchecked)
+ << (int)(Qt::ItemIsEditable
+ |Qt::ItemIsSelectable
+ |Qt::ItemIsUserCheckable
+ |Qt::ItemIsEnabled
+ |Qt::ItemIsDragEnabled
+ |Qt::ItemIsDropEnabled)
+ << true
+ << (int)(QEvent::MouseButtonRelease)
+ << (int)(Qt::LeftButton)
+ << true
+ << (int)(Qt::Checked);
+
+ QTest::newRow("unchecked, checkable, release, right button")
+ << QRect(0, 0, 20, 20)
+ << QString("foo")
+ << (int)(Qt::Unchecked)
+ << (int)(Qt::ItemIsEditable
+ |Qt::ItemIsSelectable
+ |Qt::ItemIsUserCheckable
+ |Qt::ItemIsEnabled
+ |Qt::ItemIsDragEnabled
+ |Qt::ItemIsDropEnabled)
+ << true
+ << (int)(QEvent::MouseButtonRelease)
+ << (int)(Qt::RightButton)
+ << false
+ << (int)(Qt::Unchecked);
+
+ QTest::newRow("unchecked, checkable, release outside")
+ << QRect(0, 0, 20, 20)
+ << QString("foo")
+ << (int)(Qt::Unchecked)
+ << (int)(Qt::ItemIsEditable
+ |Qt::ItemIsSelectable
+ |Qt::ItemIsUserCheckable
+ |Qt::ItemIsEnabled
+ |Qt::ItemIsDragEnabled
+ |Qt::ItemIsDropEnabled)
+ << false
+ << (int)(QEvent::MouseButtonRelease)
+ << (int)(Qt::LeftButton)
+ << false
+ << (int)(Qt::Unchecked);
+
+ QTest::newRow("unchecked, checkable, dblclick")
+ << QRect(0, 0, 20, 20)
+ << QString("foo")
+ << (int)(Qt::Unchecked)
+ << (int)(Qt::ItemIsEditable
+ |Qt::ItemIsSelectable
+ |Qt::ItemIsUserCheckable
+ |Qt::ItemIsEnabled
+ |Qt::ItemIsDragEnabled
+ |Qt::ItemIsDropEnabled)
+ << true
+ << (int)(QEvent::MouseButtonDblClick)
+ << (int)(Qt::LeftButton)
+ << true
+ << (int)(Qt::Unchecked);
+}
+
+void tst_QItemDelegate::editorEvent()
+{
+ QFETCH(QRect, rect);
+ QFETCH(QString, text);
+ QFETCH(int, checkState);
+ QFETCH(int, flags);
+ QFETCH(bool, inCheck);
+ QFETCH(int, type);
+ QFETCH(int, button);
+ QFETCH(bool, edited);
+ QFETCH(int, expectedCheckState);
+
+ QStandardItemModel model(1, 1);
+ QModelIndex index = model.index(0, 0);
+ QVERIFY(index.isValid());
+
+ QStandardItem *item = model.itemFromIndex(index);
+ item->setText(text);
+ item->setCheckState((Qt::CheckState)checkState);
+ item->setFlags((Qt::ItemFlags)flags);
+
+ QStyleOptionViewItem option;
+ option.rect = rect;
+ option.state |= QStyle::State_Enabled;
+
+ const int checkMargin = qApp->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, 0) + 1;
+ QPoint pos = inCheck ? qApp->style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &option, 0).center() + QPoint(checkMargin, 0) : QPoint(200,200);
+
+ QEvent *event = new QMouseEvent((QEvent::Type)type,
+ pos,
+ (Qt::MouseButton)button,
+ (Qt::MouseButton)button,
+ Qt::NoModifier);
+ TestItemDelegate delegate;
+ bool wasEdited = delegate.editorEvent(event, &model, option, index);
+ delete event;
+
+ QApplication::processEvents();
+
+ QCOMPARE(wasEdited, edited);
+ QCOMPARE(index.data(Qt::CheckStateRole).toInt(), expectedCheckState);
+}
+
+enum WidgetType
+{
+ LineEdit,
+ TextEdit,
+ PlainTextEdit
+};
+Q_DECLARE_METATYPE(WidgetType);
+
+void tst_QItemDelegate::enterKey_data()
+{
+ QTest::addColumn<WidgetType>("widget");
+ QTest::addColumn<int>("key");
+ QTest::addColumn<bool>("expectedFocus");
+
+ QTest::newRow("lineedit enter") << LineEdit << int(Qt::Key_Enter) << false;
+ QTest::newRow("textedit enter") << TextEdit << int(Qt::Key_Enter) << true;
+ QTest::newRow("plaintextedit enter") << PlainTextEdit << int(Qt::Key_Enter) << true;
+ QTest::newRow("plaintextedit return") << PlainTextEdit << int(Qt::Key_Return) << true;
+ QTest::newRow("plaintextedit tab") << PlainTextEdit << int(Qt::Key_Tab) << false;
+ QTest::newRow("lineedit tab") << LineEdit << int(Qt::Key_Tab) << false;
+}
+
+void tst_QItemDelegate::enterKey()
+{
+ QFETCH(WidgetType, widget);
+ QFETCH(int, key);
+ QFETCH(bool, expectedFocus);
+
+ QStandardItemModel model;
+ model.appendRow(new QStandardItem());
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ view.setFocus();
+ QTest::qWait(30);
+
+ struct TestDelegate : public QItemDelegate
+ {
+ WidgetType widgetType;
+ virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const
+ {
+ QWidget *editor = 0;
+ switch(widgetType) {
+ case LineEdit:
+ editor = new QLineEdit(parent);
+ break;
+ case TextEdit:
+ editor = new QTextEdit(parent);
+ break;
+ case PlainTextEdit:
+ editor = new QPlainTextEdit(parent);
+ break;
+ }
+ editor->setObjectName(QString::fromLatin1("TheEditor"));
+ return editor;
+ }
+ } delegate;
+
+ delegate.widgetType = widget;
+
+ view.setItemDelegate(&delegate);
+ QModelIndex index = model.index(0, 0);
+ view.setCurrentIndex(index); // the editor will only selectAll on the current index
+ view.edit(index);
+ QTest::qWait(30);
+
+ QList<QWidget*> lineEditors = qFindChildren<QWidget *>(view.viewport(), QString::fromLatin1("TheEditor"));
+ QCOMPARE(lineEditors.count(), 1);
+
+ QPointer<QWidget> editor = lineEditors.at(0);
+ QCOMPARE(editor->hasFocus(), true);
+
+ QTest::keyClick(editor, Qt::Key(key));
+ QApplication::processEvents();
+
+ // The line edit has already been destroyed, so avoid that case.
+ if (widget == TextEdit || widget == PlainTextEdit) {
+ QVERIFY(!editor.isNull());
+ QCOMPARE(editor && editor->hasFocus(), expectedFocus);
+ }
+}
+
+void tst_QItemDelegate::task257859_finalizeEdit()
+{
+ QStandardItemModel model;
+ model.appendRow(new QStandardItem());
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ view.setFocus();
+ QTest::qWait(30);
+
+ QModelIndex index = model.index(0, 0);
+ view.edit(index);
+ QTest::qWait(30);
+
+ QList<QLineEdit *> lineEditors = qFindChildren<QLineEdit *>(view.viewport());
+ QCOMPARE(lineEditors.count(), 1);
+
+ QPointer<QWidget> editor = lineEditors.at(0);
+ QCOMPARE(editor->hasFocus(), true);
+
+ QDialog dialog;
+ QTimer::singleShot(500, &dialog, SLOT(close()));
+ dialog.exec();
+ QTRY_VERIFY(!editor);
+}
+
+void tst_QItemDelegate::QTBUG4435_keepSelectionOnCheck()
+{
+ QStandardItemModel model(3, 1);
+ for (int i = 0; i < 3; ++i) {
+ QStandardItem *item = new QStandardItem(QLatin1String("Item ") + QString::number(i));
+ item->setCheckable(true);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ model.setItem(i, item);
+ }
+ QTableView view;
+ view.setModel(&model);
+ view.setItemDelegate(new TestItemDelegate);
+ view.show();
+ view.selectAll();
+ QTest::qWaitForWindowShown(&view);
+ QStyleOptionViewItem option;
+ option.rect = view.visualRect(model.index(0, 0));
+ const int checkMargin = qApp->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, 0) + 1;
+ QPoint pos = qApp->style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &option, 0).center()
+ + QPoint(checkMargin, 0);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, pos);
+ QTRY_VERIFY(view.selectionModel()->isColumnSelected(0, QModelIndex()));
+ QCOMPARE(model.item(0)->checkState(), Qt::Checked);
+}
+
+
+// ### _not_ covered:
+
+// editing with a custom editor factory
+
+// painting when editing
+// painting elided text
+// painting wrapped text
+// painting focus
+// painting icon
+// painting color
+// painting check
+// painting selected
+
+// rect for invalid
+// rect for pixmap
+// rect for image
+// rect for icon
+// rect for check
+
+QTEST_MAIN(tst_QItemDelegate)
+#include "tst_qitemdelegate.moc"
diff --git a/tests/auto/widgets/itemviews/qitemeditorfactory/.gitignore b/tests/auto/widgets/itemviews/qitemeditorfactory/.gitignore
new file mode 100644
index 0000000000..33a458e65d
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemeditorfactory/.gitignore
@@ -0,0 +1 @@
+tst_qitemeditorfactory
diff --git a/tests/auto/widgets/itemviews/qitemeditorfactory/qitemeditorfactory.pro b/tests/auto/widgets/itemviews/qitemeditorfactory/qitemeditorfactory.pro
new file mode 100644
index 0000000000..89bc944c51
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemeditorfactory/qitemeditorfactory.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qitemeditorfactory.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qitemeditorfactory/tst_qitemeditorfactory.cpp b/tests/auto/widgets/itemviews/qitemeditorfactory/tst_qitemeditorfactory.cpp
new file mode 100644
index 0000000000..53c00dab0e
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemeditorfactory/tst_qitemeditorfactory.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+#include <QtTest/QtTest>
+
+class tst_QItemEditorFactory: public QObject
+{
+ Q_OBJECT
+private slots:
+ void createEditor();
+ void createCustomEditor();
+};
+
+void tst_QItemEditorFactory::createEditor()
+{
+ const QItemEditorFactory *factory = QItemEditorFactory::defaultFactory();
+
+ QWidget parent;
+
+ QWidget *w = factory->createEditor(QVariant::String, &parent);
+ QCOMPARE(w->metaObject()->className(), "QExpandingLineEdit");
+}
+
+//we make it inherit from QObject so that we can use QPointer
+class MyEditor : public QObject, public QStandardItemEditorCreator<QDoubleSpinBox>
+{
+};
+
+void tst_QItemEditorFactory::createCustomEditor()
+{
+ QPointer<MyEditor> creator = new MyEditor;
+ QPointer<MyEditor> creator2 = new MyEditor;
+
+ {
+ QItemEditorFactory editorFactory;
+
+ editorFactory.registerEditor(QVariant::Rect, creator);
+ editorFactory.registerEditor(QVariant::RectF, creator);
+
+ //creator should not be deleted as a result of calling the next line
+ editorFactory.registerEditor(QVariant::Rect, creator2);
+ QVERIFY(creator);
+
+ //this should erase creator2
+ editorFactory.registerEditor(QVariant::Rect, creator);
+ QVERIFY(creator2.isNull());
+
+
+ QWidget parent;
+
+ QWidget *w = editorFactory.createEditor(QVariant::Rect, &parent);
+ QCOMPARE(w->metaObject()->className(), "QDoubleSpinBox");
+ QCOMPARE(w->metaObject()->userProperty().type(), QVariant::Double);
+ }
+
+ //editorFactory has been deleted, so should be creator
+ //because editorFActory has the ownership
+ QVERIFY(creator.isNull());
+ QVERIFY(creator2.isNull());
+
+ delete creator;
+}
+
+QTEST_MAIN(tst_QItemEditorFactory)
+#include "tst_qitemeditorfactory.moc"
+
diff --git a/tests/auto/widgets/itemviews/qitemselectionmodel/.gitignore b/tests/auto/widgets/itemviews/qitemselectionmodel/.gitignore
new file mode 100644
index 0000000000..aa543a200a
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemselectionmodel/.gitignore
@@ -0,0 +1 @@
+tst_qitemselectionmodel
diff --git a/tests/auto/widgets/itemviews/qitemselectionmodel/qitemselectionmodel.pro b/tests/auto/widgets/itemviews/qitemselectionmodel/qitemselectionmodel.pro
new file mode 100644
index 0000000000..c675a6eb9d
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemselectionmodel/qitemselectionmodel.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qitemselectionmodel.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/widgets/itemviews/qitemselectionmodel/tst_qitemselectionmodel.cpp
new file mode 100644
index 0000000000..f7ce339854
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemselectionmodel/tst_qitemselectionmodel.cpp
@@ -0,0 +1,2714 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QItemSelectionModel : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QItemSelectionModel();
+ virtual ~tst_QItemSelectionModel();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+private slots:
+ void clear_data();
+ void clear();
+ void clearAndSelect();
+ void toggleSelection();
+ void select_data();
+ void select();
+ void persistentselections_data();
+ void persistentselections();
+ void resetModel();
+ void removeRows_data();
+ void removeRows();
+ void removeColumns_data();
+ void removeColumns();
+ void modelLayoutChanged_data();
+ void modelLayoutChanged();
+ void selectedRows_data();
+ void selectedRows();
+ void selectedColumns_data();
+ void selectedColumns();
+ void setCurrentIndex();
+ void splitOnInsert();
+ void task196285_rowIntersectsSelection();
+ void unselectable();
+ void task220420_selectedIndexes();
+ void task240734_layoutChanged();
+ void merge_data();
+ void merge();
+ void task119433_isRowSelected();
+ void task252069_rowIntersectsSelection();
+ void task232634_childrenDeselectionSignal();
+ void task260134_layoutChangedWithAllSelected();
+ void QTBUG5671_layoutChangedWithAllSelected();
+ void QTBUG2804_layoutChangedTreeSelection();
+ void deselectRemovedMiddleRange();
+ void rangeOperatorLessThan_data();
+ void rangeOperatorLessThan();
+
+ void testDifferentModels();
+
+ void testValidRangesInSelectionsAfterReset();
+ void testChainedSelectionClear();
+
+private:
+ QAbstractItemModel *model;
+ QItemSelectionModel *selection;
+};
+
+QDataStream &operator<<(QDataStream &, const QModelIndex &);
+QDataStream &operator>>(QDataStream &, QModelIndex &);
+QDataStream &operator<<(QDataStream &, const QModelIndexList &);
+QDataStream &operator>>(QDataStream &, QModelIndexList &);
+
+typedef QList<int> IntList;
+typedef QPair<int, int> IntPair;
+typedef QList<IntPair> PairList;
+
+
+Q_DECLARE_METATYPE(PairList)
+Q_DECLARE_METATYPE(QModelIndex)
+Q_DECLARE_METATYPE(QModelIndexList)
+Q_DECLARE_METATYPE(IntList)
+Q_DECLARE_METATYPE(QItemSelection)
+
+class QStreamHelper: public QAbstractItemModel
+{
+public:
+ QStreamHelper() {}
+ static QModelIndex create(int row = -1, int column = -1, void *data = 0)
+ {
+ QStreamHelper helper;
+ return helper.QAbstractItemModel::createIndex(row, column, data);
+ }
+
+ QModelIndex index(int, int, const QModelIndex&) const
+ { return QModelIndex(); }
+ QModelIndex parent(const QModelIndex&) const
+ { return QModelIndex(); }
+ int rowCount(const QModelIndex & = QModelIndex()) const
+ { return 0; }
+ int columnCount(const QModelIndex & = QModelIndex()) const
+ { return 0; }
+ QVariant data(const QModelIndex &, int = Qt::DisplayRole) const
+ { return QVariant(); }
+ bool hasChildren(const QModelIndex &) const
+ { return false; }
+};
+
+QDataStream &operator<<(QDataStream &s, const QModelIndex &input)
+{
+ s << input.row()
+ << input.column()
+ << reinterpret_cast<qlonglong>(input.internalPointer());
+ return s;
+}
+
+QDataStream &operator>>(QDataStream &s, QModelIndex &output)
+{
+ int r, c;
+ qlonglong ptr;
+ s >> r;
+ s >> c;
+ s >> ptr;
+ output = QStreamHelper::create(r, c, reinterpret_cast<void *>(ptr));
+ return s;
+}
+
+QDataStream &operator<<(QDataStream &s, const QModelIndexList &input)
+{
+ s << input.count();
+ for (int i=0; i<input.count(); ++i)
+ s << input.at(i);
+ return s;
+}
+
+QDataStream &operator>>(QDataStream &s, QModelIndexList &output)
+{
+ QModelIndex tmpIndex;
+ int count;
+ s >> count;
+ for (int i=0; i<count; ++i) {
+ s >> tmpIndex;
+ output << tmpIndex;
+ }
+ return s;
+}
+
+tst_QItemSelectionModel::tst_QItemSelectionModel() : model(0), selection(0)
+{
+}
+
+tst_QItemSelectionModel::~tst_QItemSelectionModel()
+{
+}
+
+/*
+ This test usually uses a model with a 5x5 table
+ -------------------------------------------
+ | 0,0 | 0,1 | 0,2 | 0,3 | 0,4 |
+ -------------------------------------------
+ | 1,0 | 1,1 | 1,2 | 1,3 | 1,4 |
+ -------------------------------------------
+ | 2,0 | 2,1 | 2,2 | 2,3 | 2,4 |
+ -------------------------------------------
+ | 3,0 | 3,1 | 3,2 | 3,3 | 3,4 |
+ -------------------------------------------
+ | 4,0 | 4,1 | 4,2 | 4,3 | 4,4 |
+ -------------------------------------------
+
+ ...that for each row has a children in a new 5x5 table ad infinitum.
+
+*/
+void tst_QItemSelectionModel::initTestCase()
+{
+ qRegisterMetaType<QItemSelection>("QItemSelection");
+
+ model = new QStandardItemModel(5, 5);
+ QModelIndex parent = model->index(0, 0, QModelIndex());
+ model->insertRows(0, 5, parent);
+ model->insertColumns(0, 5, parent);
+ selection = new QItemSelectionModel(model);
+}
+
+void tst_QItemSelectionModel::cleanupTestCase()
+{
+ delete selection;
+ delete model;
+}
+
+void tst_QItemSelectionModel::init()
+{
+ selection->clear();
+ while (model->rowCount(QModelIndex()) > 5)
+ model->removeRow(0, QModelIndex());
+ while (model->rowCount(QModelIndex()) < 5)
+ model->insertRow(0, QModelIndex());
+}
+
+void tst_QItemSelectionModel::clear_data()
+{
+ QTest::addColumn<QModelIndexList>("indexList");
+ QTest::addColumn<IntList>("commandList");
+ {
+ QModelIndexList index;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ index << model->index(1, 0, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ QTest::newRow("(0, 0) and (1, 0): Select|Rows")
+ << index
+ << command;
+ }
+ {
+ QModelIndexList index;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ index << model->index(0, 1, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ QTest::newRow("(0, 0) and (1, 0): Select|Columns")
+ << index
+ << command;
+ }
+ {
+ QModelIndexList index;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(1, 1, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::SelectCurrent;
+ QTest::newRow("(0, 0), (1, 1) and (2, 2): Select, Select, SelectCurrent")
+ << index
+ << command;
+ }
+ {
+ QModelIndexList index;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(1, 1, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(1, 1, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+ QTest::newRow("(0, 0), (1, 1) and (1, 1): Select, Select, Toggle")
+ << index
+ << command;
+ }
+ {
+ QModelIndexList index;
+ IntList command;
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ QTest::newRow("child (0, 0) of (0, 0): Select|Rows")
+ << index
+ << command;
+ }
+}
+
+void tst_QItemSelectionModel::clear()
+{
+ QFETCH(QModelIndexList, indexList);
+ QFETCH(IntList, commandList);
+
+ // do selections
+ for (int i=0; i<indexList.count(); ++i) {
+ selection->select(indexList.at(i), (QItemSelectionModel::SelectionFlags)commandList.at(i));
+ }
+ // test that we have selected items
+ QVERIFY(!selection->selectedIndexes().isEmpty());
+ selection->clear();
+ // test that they were all cleared
+ QVERIFY(selection->selectedIndexes().isEmpty());
+}
+
+void tst_QItemSelectionModel::clearAndSelect()
+{
+ // populate selectionmodel
+ selection->select(model->index(1, 1, QModelIndex()), QItemSelectionModel::Select);
+ QCOMPARE(selection->selectedIndexes().count(), 1);
+ QVERIFY(selection->hasSelection());
+
+ // ClearAndSelect with empty selection
+ QItemSelection emptySelection;
+ selection->select(emptySelection, QItemSelectionModel::ClearAndSelect);
+
+ // verify the selectionmodel is empty
+ QVERIFY(selection->selectedIndexes().isEmpty());
+ QVERIFY(selection->hasSelection()==false);
+}
+
+void tst_QItemSelectionModel::toggleSelection()
+{
+ //test the toggle selection and checks whether selectedIndex
+ //and hasSelection returns the correct value
+
+ selection->clearSelection();
+ QCOMPARE(selection->selectedIndexes().count(), 0);
+ QVERIFY(selection->hasSelection()==false);
+
+ QModelIndex index=model->index(1, 1, QModelIndex());
+ // populate selectionmodel
+ selection->select(index, QItemSelectionModel::Toggle);
+ QCOMPARE(selection->selectedIndexes().count(), 1);
+ QVERIFY(selection->hasSelection()==true);
+
+ selection->select(index, QItemSelectionModel::Toggle);
+ QCOMPARE(selection->selectedIndexes().count(), 0);
+ QVERIFY(selection->hasSelection()==false);
+
+ // populate selectionmodel with rows
+ selection->select(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
+ QCOMPARE(selection->selectedIndexes().count(), model->columnCount());
+ QVERIFY(selection->hasSelection()==true);
+
+ selection->select(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
+ QCOMPARE(selection->selectedIndexes().count(), 0);
+ QVERIFY(selection->hasSelection()==false);
+
+}
+
+
+void tst_QItemSelectionModel::select_data()
+{
+ QTest::addColumn<QModelIndexList>("indexList");
+ QTest::addColumn<bool>("useRanges");
+ QTest::addColumn<IntList>("commandList");
+ QTest::addColumn<QModelIndexList>("expectedList");
+
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ expected << model->index(0, 0, QModelIndex());
+ QTest::newRow("(0, 0): Select")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ command << QItemSelectionModel::Select;
+ expected << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ QTest::newRow("child (0, 0) of (0, 0): Select")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Deselect;
+ QTest::newRow("(0, 0): Deselect")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+ expected << model->index(0, 0, QModelIndex());
+ QTest::newRow("(0, 0): Toggle")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+ QTest::newRow("(0, 0) and (0, 0): Select and Toggle")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Deselect;
+ QTest::newRow("(0, 0) and (0, 0): Select and Deselect")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ command << QItemSelectionModel::ClearAndSelect;
+ expected << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ QTest::newRow("(0, 0) and child (0, 0) of (0, 0): Select and ClearAndSelect")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(0, 1, QModelIndex());
+ index << model->index(4, 1, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 1, QModelIndex());
+ command << QItemSelectionModel::Deselect;
+ QTest::newRow("(0, 0 to 4, 0) and (0, 1 to 4, 1) and (0, 0 to 4, 1): Select and Select and Deselect")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(4, 4, QModelIndex());
+ command << QItemSelectionModel::Select;
+ expected << model->index(0, 0, QModelIndex()) << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0) and (4, 4): Select")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(4, 4, QModelIndex());
+ command << QItemSelectionModel::ClearAndSelect;
+ expected << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0) and (4, 4): Select and ClearAndSelect")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ index << model->index(4, 4, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(4, 1, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(4, 3, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0) and (4, 4): Select|Rows")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ index << model->index(4, 4, model->index(0, 0, QModelIndex()));
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ QModelIndex parent = model->index(0, 0, QModelIndex());
+ expected << model->index(0, 0, parent)
+ << model->index(0, 1, parent)
+ << model->index(0, 2, parent)
+ << model->index(0, 3, parent)
+ << model->index(0, 4, parent)
+ << model->index(4, 0, parent)
+ << model->index(4, 1, parent)
+ << model->index(4, 2, parent)
+ << model->index(4, 3, parent)
+ << model->index(4, 4, parent);
+ QTest::newRow("child (0, 0) and (4, 4) of (0, 0): Select|Rows")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ index << model->index(4, 4, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ << model->index(3, 4, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0) and (4, 4): Select|Columns")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ index << model->index(4, 4, model->index(0, 0, QModelIndex()));
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ expected << model->index(0, 0, model->index(0, 0, QModelIndex()))
+ << model->index(1, 0, model->index(0, 0, QModelIndex()))
+ << model->index(2, 0, model->index(0, 0, QModelIndex()))
+ << model->index(3, 0, model->index(0, 0, QModelIndex()))
+ << model->index(4, 0, model->index(0, 0, QModelIndex()))
+ << model->index(0, 4, model->index(0, 0, QModelIndex()))
+ << model->index(1, 4, model->index(0, 0, QModelIndex()))
+ << model->index(2, 4, model->index(0, 0, QModelIndex()))
+ << model->index(3, 4, model->index(0, 0, QModelIndex()))
+ << model->index(4, 4, model->index(0, 0, QModelIndex()));
+ QTest::newRow("child (0, 0) and (4, 4) of (0, 0): Select|Columns")
+ << index
+ << false
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 0, QModelIndex());
+ command << QItemSelectionModel::Select;
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(4, 0, QModelIndex());
+ QTest::newRow("(0, 0 to 4, 0): Select")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ /* ### FAILS
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ command << QItemSelectionModel::Select;
+ QTest::newRow("(0, 0 to child 0, 0): Select")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ */
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, model->index(0, 0, QModelIndex()));
+ index << model->index(0, 0, model->index(1, 0, QModelIndex()));
+ command << QItemSelectionModel::Select;
+ QTest::newRow("child (0, 0) of (0, 0) to child (0, 0) of (1, 0): Select")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 4, QModelIndex());
+ command << QItemSelectionModel::Select;
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(1, 3, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(3, 1, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(3, 3, QModelIndex())
+ << model->index(3, 4, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(4, 1, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(4, 3, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0 to 4, 4): Select")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 0, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(1, 3, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(3, 1, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(3, 3, QModelIndex())
+ << model->index(3, 4, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(4, 1, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(4, 3, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0 to 4, 0): Select|Rows")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(0, 4, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(1, 3, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(3, 1, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(3, 3, QModelIndex())
+ << model->index(3, 4, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(4, 1, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(4, 3, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0 to 0, 4): Select|Columns")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 4, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(1, 3, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(3, 1, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(3, 3, QModelIndex())
+ << model->index(3, 4, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(4, 1, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(4, 3, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0 to 4, 4): Select|Rows")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(4, 4, QModelIndex());
+ command << (QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(1, 3, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ << model->index(3, 0, QModelIndex())
+ << model->index(3, 1, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(3, 3, QModelIndex())
+ << model->index(3, 4, QModelIndex())
+ << model->index(4, 0, QModelIndex())
+ << model->index(4, 1, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(4, 3, QModelIndex())
+ << model->index(4, 4, QModelIndex());
+ QTest::newRow("(0, 0 to 4, 4): Select|Columns")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 2, QModelIndex());
+ index << model->index(4, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(2, 0, QModelIndex());
+ index << model->index(2, 4, QModelIndex());
+ command << QItemSelectionModel::Select;
+ expected << model->index(0, 2, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex());
+ QTest::newRow("(0, 2 to 4, 2) and (2, 0 to 2, 4): Select")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 2, QModelIndex());
+ index << model->index(4, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(2, 0, QModelIndex());
+ index << model->index(2, 4, QModelIndex());
+ command << QItemSelectionModel::SelectCurrent;
+ expected << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex());
+ QTest::newRow("(0, 2 to 4, 2) and (2, 0 to 2, 4): Select and SelectCurrent")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 2, QModelIndex());
+ index << model->index(4, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(2, 0, QModelIndex());
+ index << model->index(2, 4, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+ expected << model->index(0, 2, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(4, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex());
+ QTest::newRow("(0, 2 to 4, 2) and (2, 0 to 2, 4): Select and Toggle")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 2, QModelIndex());
+ index << model->index(4, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+ index << model->index(2, 0, QModelIndex());
+ index << model->index(2, 4, QModelIndex());
+ command << QItemSelectionModel::Deselect;
+ expected << model->index(0, 2, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(4, 2, QModelIndex());
+ QTest::newRow("(0, 2 to 4, 2) and (2, 0 to 2, 4): Select and Deselect")
+ << index
+ << true
+ << command
+ << expected;
+ }
+
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(0, 0, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (0, 0 to 0, 0): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(0, 1, QModelIndex());
+ index << model->index(0, 1, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (0, 1 to 0, 1): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(0, 2, QModelIndex());
+ index << model->index(0, 2, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (0, 2 to 0, 2): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(1, 0, QModelIndex());
+ index << model->index(1, 0, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (1, 0 to 1, 0): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(1, 1, QModelIndex());
+ index << model->index(1, 1, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (1, 1 to 1, 1): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(1, 2, QModelIndex());
+ index << model->index(1, 2, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (1, 2 to 1, 2): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(2, 0, QModelIndex());
+ index << model->index(2, 0, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (2, 0 to 2, 0): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(2, 1, QModelIndex());
+ index << model->index(2, 1, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 2, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (2, 1 to 2, 1): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList index;
+ QModelIndexList expected;
+ IntList command;
+
+ index << model->index(0, 0, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Select;
+
+ index << model->index(2, 2, QModelIndex());
+ index << model->index(2, 2, QModelIndex());
+ command << QItemSelectionModel::Toggle;
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex());
+
+ QTest::newRow("(0, 0 to 2, 2) and (2, 2 to 2, 2): Select and Toggle at selection boundary")
+ << index
+ << true
+ << command
+ << expected;
+ }
+ {
+ QModelIndexList indexes;
+ IntList commands;
+ QModelIndexList expected;
+
+ indexes << model->index(0, 0, QModelIndex()) << model->index(0, 0, QModelIndex()) // press 0
+ << model->index(0, 0, QModelIndex()) << model->index(0, 0, QModelIndex()) // release 0
+ << model->index(1, 0, QModelIndex()) << model->index(1, 0, QModelIndex()) // press 1
+ << model->index(1, 0, QModelIndex()) << model->index(1, 0, QModelIndex()) // release 1
+ << model->index(2, 0, QModelIndex()) << model->index(2, 0, QModelIndex()) // press 2
+ << model->index(2, 0, QModelIndex()) << model->index(2, 0, QModelIndex()) // release 2
+ << model->index(3, 0, QModelIndex()) << model->index(3, 0, QModelIndex()) // press 3
+ << model->index(3, 0, QModelIndex()) << model->index(3, 0, QModelIndex()) // release 3
+ << model->index(2, 0, QModelIndex()) << model->index(2, 0, QModelIndex()) // press 2 again
+ << model->index(2, 0, QModelIndex()) << model->index(2, 0, QModelIndex());// move 2
+
+ commands << (QItemSelectionModel::NoUpdate) // press 0
+ << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 0
+ << (QItemSelectionModel::NoUpdate) // press 1
+ << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 1
+ << (QItemSelectionModel::NoUpdate) // press 2
+ << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 2
+ << (QItemSelectionModel::NoUpdate) // press 3
+ << (QItemSelectionModel::Toggle|QItemSelectionModel::Rows) // release 3
+ << (QItemSelectionModel::NoUpdate) // press 2 again
+ << (QItemSelectionModel::Toggle/*Current*/|QItemSelectionModel::Rows);// move 2
+
+ expected << model->index(0, 0, QModelIndex())
+ << model->index(0, 1, QModelIndex())
+ << model->index(0, 2, QModelIndex())
+ << model->index(0, 3, QModelIndex())
+ << model->index(0, 4, QModelIndex())
+
+ << model->index(1, 0, QModelIndex())
+ << model->index(1, 1, QModelIndex())
+ << model->index(1, 2, QModelIndex())
+ << model->index(1, 3, QModelIndex())
+ << model->index(1, 4, QModelIndex())
+ /*
+ << model->index(2, 0, QModelIndex())
+ << model->index(2, 1, QModelIndex())
+ << model->index(2, 2, QModelIndex())
+ << model->index(2, 3, QModelIndex())
+ << model->index(2, 4, QModelIndex())
+ */
+ << model->index(3, 0, QModelIndex())
+ << model->index(3, 1, QModelIndex())
+ << model->index(3, 2, QModelIndex())
+ << model->index(3, 3, QModelIndex())
+ << model->index(3, 4, QModelIndex());
+
+ QTest::newRow("simulated treeview multiselection behavior")
+ << indexes
+ << true
+ << commands
+ << expected;
+ }
+}
+
+void tst_QItemSelectionModel::select()
+{
+ QFETCH(QModelIndexList, indexList);
+ QFETCH(bool, useRanges);
+ QFETCH(IntList, commandList);
+ QFETCH(QModelIndexList, expectedList);
+
+ int lastCommand = 0;
+ // do selections
+ for (int i = 0; i<commandList.count(); ++i) {
+ if (useRanges) {
+ selection->select(QItemSelection(indexList.at(2*i), indexList.at(2*i+1)),
+ (QItemSelectionModel::SelectionFlags)commandList.at(i));
+ } else {
+ selection->select(indexList.at(i),
+ (QItemSelectionModel::SelectionFlags)commandList.at(i));
+ }
+ lastCommand = commandList.at(i);
+ }
+
+
+ QModelIndexList selectedList = selection->selectedIndexes();
+
+ QVERIFY(selection->hasSelection()!=selectedList.isEmpty());
+
+ // debug output
+// for (int i=0; i<selectedList.count(); ++i)
+// qDebug(QString("selected (%1, %2)")
+// .arg(selectedList.at(i).row())
+// .arg(selectedList.at(i).column()));
+
+ // test that the number of indices are as expected
+ QVERIFY2(selectedList.count() == expectedList.count(),
+ QString("expected indices: %1 actual indices: %2")
+ .arg(expectedList.count())
+ .arg(selectedList.count()).toLatin1());
+
+ // test existence of each index
+ for (int i=0; i<expectedList.count(); ++i) {
+ QVERIFY2(selectedList.contains(expectedList.at(i)),
+ QString("expected index(%1, %2) not found in selectedIndexes()")
+ .arg(expectedList.at(i).row())
+ .arg(expectedList.at(i).column()).toLatin1());
+ }
+
+ // test that isSelected agrees
+ for (int i=0; i<indexList.count(); ++i) {
+ QModelIndex idx = indexList.at(i);
+ QVERIFY2(selection->isSelected(idx) == selectedList.contains(idx),
+ QString("isSelected(index: %1, %2) does not match selectedIndexes()")
+ .arg(idx.row())
+ .arg(idx.column()).toLatin1());
+ }
+
+ //for now we assume Rows/Columns flag is the same for all commands, therefore we just check lastCommand
+ // test that isRowSelected agrees
+ if (lastCommand & QItemSelectionModel::Rows) {
+ for (int i=0; i<selectedList.count(); ++i)
+ QVERIFY2(selection->isRowSelected(selectedList.at(i).row(),
+ model->parent(selectedList.at(i))),
+ QString("isRowSelected(row: %1) does not match selectedIndexes()")
+ .arg(selectedList.at(i).row()).toLatin1());
+ }
+
+ // test that isColumnSelected agrees
+ if (lastCommand & QItemSelectionModel::Columns) {
+ for (int i=0; i<selectedList.count(); ++i)
+ QVERIFY2(selection->isColumnSelected(selectedList.at(i).column(),
+ model->parent(selectedList.at(i))),
+ QString("isColumnSelected(column: %1) does not match selectedIndexes()")
+ .arg(selectedList.at(i).column()).toLatin1());
+ }
+}
+
+void tst_QItemSelectionModel::persistentselections_data()
+{
+ QTest::addColumn<PairList>("indexList");
+ QTest::addColumn<IntList>("commandList");
+ QTest::addColumn<IntList>("insertRows"); // start, count
+ QTest::addColumn<IntList>("insertColumns"); // start, count
+ QTest::addColumn<IntList>("deleteRows"); // start, count
+ QTest::addColumn<IntList>("deleteColumns"); // start, count
+ QTest::addColumn<PairList>("expectedList");
+
+ PairList index, expected;
+ IntList command, insertRows, insertColumns, deleteRows, deleteColumns;
+
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ deleteRows << 4 << 1;
+ expected << IntPair(0, 0);
+ QTest::newRow("ClearAndSelect (0, 0). Delete last row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ deleteRows << 0 << 1;
+ QTest::newRow("ClearAndSelect (0, 0). Delete first row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(1, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ deleteRows << 0 << 1;
+ expected << IntPair(0, 0);
+ QTest::newRow("ClearAndSelect (1, 0). Delete first row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ insertRows << 5 << 1;
+ expected << IntPair(0, 0);
+ QTest::newRow("ClearAndSelect (0, 0). Append row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ insertRows << 0 << 1;
+ expected << IntPair(1, 0);
+ QTest::newRow("ClearAndSelect (0, 0). Insert before first row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0)
+ << IntPair(4, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ insertRows << 5 << 1;
+ expected << IntPair(0, 0)
+ << IntPair(1, 0)
+ << IntPair(2, 0)
+ << IntPair(3, 0)
+ << IntPair(4, 0);
+ QTest::newRow("ClearAndSelect (0, 0) to (4, 0). Append row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0)
+ << IntPair(4, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ insertRows << 0 << 1;
+ expected << IntPair(1, 0)
+ << IntPair(2, 0)
+ << IntPair(3, 0)
+ << IntPair(4, 0)
+ << IntPair(5, 0);
+ QTest::newRow("ClearAndSelect (0, 0) to (4, 0). Insert before first row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0)
+ << IntPair(4, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ deleteRows << 0 << 1;
+ expected << IntPair(0, 0)
+ << IntPair(1, 0)
+ << IntPair(2, 0)
+ << IntPair(3, 0);
+ QTest::newRow("ClearAndSelect (0, 0) to (4, 0). Delete first row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0)
+ << IntPair(4, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ deleteRows << 4 << 1;
+ expected << IntPair(0, 0)
+ << IntPair(1, 0)
+ << IntPair(2, 0)
+ << IntPair(3, 0);
+ QTest::newRow("ClearAndSelect (0, 0) to (4, 0). Delete last row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0)
+ << IntPair(4, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ deleteRows << 1 << 3;
+ expected << IntPair(0, 0)
+ << IntPair(1, 0);
+ QTest::newRow("ClearAndSelect (0, 0) to (4, 0). Deleting all but first and last row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+
+ index.clear(); expected.clear(); command.clear();
+ insertRows.clear(); insertColumns.clear(); deleteRows.clear(); deleteColumns.clear();
+ index << IntPair(0, 0)
+ << IntPair(4, 0);
+ command << QItemSelectionModel::ClearAndSelect;
+ insertRows << 1 << 1;
+ expected << IntPair(0, 0)
+ // the inserted row should not be selected
+ << IntPair(2, 0)
+ << IntPair(3, 0)
+ << IntPair(4, 0)
+ << IntPair(5, 0);
+ QTest::newRow("ClearAndSelect (0, 0) to (4, 0). Insert after first row.")
+ << index << command
+ << insertRows << insertColumns << deleteRows << deleteColumns
+ << expected;
+}
+
+void tst_QItemSelectionModel::persistentselections()
+{
+ QFETCH(PairList, indexList);
+ QFETCH(IntList, commandList);
+ QFETCH(IntList, insertRows);
+ QFETCH(IntList, insertColumns);
+ QFETCH(IntList, deleteRows);
+ QFETCH(IntList, deleteColumns);
+ QFETCH(PairList, expectedList);
+
+ // make sure the model is sane (5x5)
+ QCOMPARE(model->rowCount(QModelIndex()), 5);
+ QCOMPARE(model->columnCount(QModelIndex()), 5);
+
+ // do selections
+ for (int i=0; i<commandList.count(); ++i) {
+ if (indexList.count() == commandList.count()) {
+ QModelIndex index = model->index(indexList.at(i).first,
+ indexList.at(i).second,
+ QModelIndex());
+ selection->select(index, (QItemSelectionModel::SelectionFlags)commandList.at(i));
+ } else {
+ QModelIndex tl = model->index(indexList.at(2*i).first,
+ indexList.at(2*i).second,
+ QModelIndex());
+ QModelIndex br = model->index(indexList.at(2*i+1).first,
+ indexList.at(2*i+1).second,
+ QModelIndex());
+ selection->select(QItemSelection(tl, br),
+ (QItemSelectionModel::SelectionFlags)commandList.at(i));
+ }
+ }
+ // test that we have selected items
+ QVERIFY(!selection->selectedIndexes().isEmpty());
+ QVERIFY(selection->hasSelection());
+
+ // insert/delete row and/or columns
+ if (insertRows.count() > 1)
+ model->insertRows(insertRows.at(0), insertRows.at(1), QModelIndex());
+ if (insertColumns.count() > 1)
+ model->insertColumns(insertColumns.at(0), insertColumns.at(1), QModelIndex());
+ if (deleteRows.count() > 1)
+ model->removeRows(deleteRows.at(0), deleteRows.at(1), QModelIndex());
+ if (deleteColumns.count() > 1)
+ model->removeColumns(deleteColumns.at(0), deleteColumns.at(1), QModelIndex());
+
+ // check that the selected items are the correct number and indexes
+ QModelIndexList selectedList = selection->selectedIndexes();
+ QCOMPARE(selectedList.count(), expectedList.count());
+ foreach(IntPair pair, expectedList) {
+ QModelIndex index = model->index(pair.first, pair.second, QModelIndex());
+ QVERIFY(selectedList.contains(index));
+ }
+}
+
+// "make reset public"-model
+class MyStandardItemModel: public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ inline MyStandardItemModel(int i1, int i2): QStandardItemModel(i1, i2) {}
+ inline void reset() { QStandardItemModel::reset(); }
+};
+
+void tst_QItemSelectionModel::resetModel()
+{
+ MyStandardItemModel model(20, 20);
+ QTreeView view;
+ view.setModel(&model);
+
+ QSignalSpy spy(view.selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)));
+
+ view.selectionModel()->select(QItemSelection(model.index(0, 0), model.index(5, 5)), QItemSelectionModel::Select);
+
+ QCOMPARE(spy.count(), 1);
+
+ model.reset();
+
+ QVERIFY(view.selectionModel()->selection().isEmpty());
+ QVERIFY(view.selectionModel()->hasSelection() == false);
+
+ view.selectionModel()->select(QItemSelection(model.index(0, 0), model.index(5, 5)), QItemSelectionModel::Select);
+
+ QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.at(1).count(), 2);
+ // make sure we don't get an "old selection"
+ QCOMPARE(spy.at(1).at(1).userType(), qMetaTypeId<QItemSelection>());
+ QVERIFY(qvariant_cast<QItemSelection>(spy.at(1).at(1)).isEmpty());
+}
+
+void tst_QItemSelectionModel::removeRows_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+
+ QTest::addColumn<int>("selectTop");
+ QTest::addColumn<int>("selectLeft");
+ QTest::addColumn<int>("selectBottom");
+ QTest::addColumn<int>("selectRight");
+
+ QTest::addColumn<int>("removeTop");
+ QTest::addColumn<int>("removeBottom");
+
+ QTest::addColumn<int>("expectedTop");
+ QTest::addColumn<int>("expectedLeft");
+ QTest::addColumn<int>("expectedBottom");
+ QTest::addColumn<int>("expectedRight");
+
+ QTest::newRow("4x4 <0,1><1,1>")
+ << 4 << 4
+ << 0 << 1 << 1 << 1
+ << 0 << 0
+ << 0 << 1 << 0 << 1;
+}
+
+void tst_QItemSelectionModel::removeRows()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, selectTop);
+ QFETCH(int, selectLeft);
+ QFETCH(int, selectBottom);
+ QFETCH(int, selectRight);
+ QFETCH(int, removeTop);
+ QFETCH(int, removeBottom);
+ QFETCH(int, expectedTop);
+ QFETCH(int, expectedLeft);
+ QFETCH(int, expectedBottom);
+ QFETCH(int, expectedRight);
+
+ MyStandardItemModel model(rowCount, columnCount);
+ QItemSelectionModel selections(&model);
+ QSignalSpy spy(&selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)));
+
+ QModelIndex tl = model.index(selectTop, selectLeft);
+ QModelIndex br = model.index(selectBottom, selectRight);
+ selections.select(QItemSelection(tl, br), QItemSelectionModel::ClearAndSelect);
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(selections.isSelected(tl));
+ QVERIFY(selections.isSelected(br));
+ QVERIFY(selections.hasSelection());
+
+ model.removeRows(removeTop, removeBottom - removeTop + 1);
+
+ QCOMPARE(spy.count(), 2);
+ tl = model.index(expectedTop, expectedLeft);
+ br = model.index(expectedBottom, expectedRight);
+ QVERIFY(selections.isSelected(tl));
+ QVERIFY(selections.isSelected(br));
+}
+
+void tst_QItemSelectionModel::removeColumns_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+
+ QTest::addColumn<int>("selectTop");
+ QTest::addColumn<int>("selectLeft");
+ QTest::addColumn<int>("selectBottom");
+ QTest::addColumn<int>("selectRight");
+
+ QTest::addColumn<int>("removeLeft");
+ QTest::addColumn<int>("removeRight");
+
+ QTest::addColumn<int>("expectedTop");
+ QTest::addColumn<int>("expectedLeft");
+ QTest::addColumn<int>("expectedBottom");
+ QTest::addColumn<int>("expectedRight");
+
+ QTest::newRow("4x4 <0,1><1,1>")
+ << 4 << 4
+ << 1 << 0 << 1 << 1
+ << 0 << 0
+ << 1 << 0 << 1 << 0;
+}
+
+void tst_QItemSelectionModel::removeColumns()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, selectTop);
+ QFETCH(int, selectLeft);
+ QFETCH(int, selectBottom);
+ QFETCH(int, selectRight);
+ QFETCH(int, removeLeft);
+ QFETCH(int, removeRight);
+ QFETCH(int, expectedTop);
+ QFETCH(int, expectedLeft);
+ QFETCH(int, expectedBottom);
+ QFETCH(int, expectedRight);
+
+ MyStandardItemModel model(rowCount, columnCount);
+ QItemSelectionModel selections(&model);
+ QSignalSpy spy(&selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)));
+
+ QModelIndex tl = model.index(selectTop, selectLeft);
+ QModelIndex br = model.index(selectBottom, selectRight);
+ selections.select(QItemSelection(tl, br), QItemSelectionModel::ClearAndSelect);
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(selections.isSelected(tl));
+ QVERIFY(selections.isSelected(br));
+ QVERIFY(selections.hasSelection());
+
+ model.removeColumns(removeLeft, removeRight - removeLeft + 1);
+
+ QCOMPARE(spy.count(), 2);
+ tl = model.index(expectedTop, expectedLeft);
+ br = model.index(expectedBottom, expectedRight);
+ QVERIFY(selections.isSelected(tl));
+ QVERIFY(selections.isSelected(br));
+}
+
+typedef QList<IntList> IntListList;
+typedef QPair<IntPair, IntPair> IntPairPair;
+typedef QList<IntPairPair> IntPairPairList;
+Q_DECLARE_METATYPE(IntListList)
+Q_DECLARE_METATYPE(IntPairPair)
+Q_DECLARE_METATYPE(IntPairPairList)
+
+void tst_QItemSelectionModel::modelLayoutChanged_data()
+{
+ QTest::addColumn<IntListList>("items");
+ QTest::addColumn<IntPairPairList>("initialSelectedRanges");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<int>("sortColumn");
+ QTest::addColumn<IntPairPairList>("expectedSelectedRanges");
+
+ QTest::newRow("everything selected, then row order reversed")
+ << (IntListList()
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 3 << 2 << 1 << 0))
+ << (IntPairPairList()
+ << IntPairPair(IntPair(0, 0), IntPair(3, 1)))
+ << int(Qt::DescendingOrder)
+ << 0
+ << (IntPairPairList()
+ << IntPairPair(IntPair(0, 0), IntPair(3, 1)));
+ QTest::newRow("first two rows selected, then row order reversed")
+ << (IntListList()
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 3 << 2 << 1 << 0))
+ << (IntPairPairList()
+ << IntPairPair(IntPair(0, 0), IntPair(1, 1)))
+ << int(Qt::DescendingOrder)
+ << 0
+ << (IntPairPairList()
+ << IntPairPair(IntPair(2, 0), IntPair(3, 1)));
+ QTest::newRow("middle two rows selected, then row order reversed")
+ << (IntListList()
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 3 << 2 << 1 << 0))
+ << (IntPairPairList()
+ << IntPairPair(IntPair(1, 0), IntPair(2, 1)))
+ << int(Qt::DescendingOrder)
+ << 0
+ << (IntPairPairList()
+ << IntPairPair(IntPair(1, 0), IntPair(2, 1)));
+ QTest::newRow("two ranges")
+ << (IntListList()
+ << (IntList() << 2 << 0 << 3 << 1)
+ << (IntList() << 2 << 0 << 3 << 1))
+ << (IntPairPairList()
+ << IntPairPair(IntPair(1, 0), IntPair(1, 1))
+ << IntPairPair(IntPair(3, 0), IntPair(3, 1)))
+ << int(Qt::AscendingOrder)
+ << 0
+ << (IntPairPairList()
+ << IntPairPair(IntPair(0, 0), IntPair(0, 1))
+ << IntPairPair(IntPair(1, 0), IntPair(1, 1)));
+}
+
+void tst_QItemSelectionModel::modelLayoutChanged()
+{
+ QFETCH(IntListList, items);
+ QFETCH(IntPairPairList, initialSelectedRanges);
+ QFETCH(int, sortOrder);
+ QFETCH(int, sortColumn);
+ QFETCH(IntPairPairList, expectedSelectedRanges);
+
+ MyStandardItemModel model(items.at(0).count(), items.count());
+ // initialize model data
+ for (int i = 0; i < model.rowCount(); ++i) {
+ for (int j = 0; j < model.columnCount(); ++j) {
+ QModelIndex index = model.index(i, j);
+ model.setData(index, items.at(j).at(i), Qt::DisplayRole);
+ }
+ }
+
+ // select initial ranges
+ QItemSelectionModel selectionModel(&model);
+ foreach (IntPairPair range, initialSelectedRanges) {
+ IntPair tl = range.first;
+ IntPair br = range.second;
+ QItemSelection selection(
+ model.index(tl.first, tl.second),
+ model.index(br.first, br.second));
+ selectionModel.select(selection, QItemSelectionModel::Select);
+ }
+
+ // sort the model
+ model.sort(sortColumn, Qt::SortOrder(sortOrder));
+
+ // verify that selection is as expected
+ QItemSelection selection = selectionModel.selection();
+ QCOMPARE(selection.count(), expectedSelectedRanges.count());
+ QVERIFY(selectionModel.hasSelection() == !expectedSelectedRanges.isEmpty());
+
+ for (int i = 0; i < expectedSelectedRanges.count(); ++i) {
+ IntPairPair expectedRange = expectedSelectedRanges.at(i);
+ IntPair expectedTl = expectedRange.first;
+ IntPair expectedBr = expectedRange.second;
+ QItemSelectionRange actualRange = selection.at(i);
+ QModelIndex actualTl = actualRange.topLeft();
+ QModelIndex actualBr = actualRange.bottomRight();
+ QCOMPARE(actualTl.row(), expectedTl.first);
+ QCOMPARE(actualTl.column(), expectedTl.second);
+ QCOMPARE(actualBr.row(), expectedBr.first);
+ QCOMPARE(actualBr.column(), expectedBr.second);
+ }
+}
+
+void tst_QItemSelectionModel::selectedRows_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<IntList>("selectRows");
+ QTest::addColumn<IntList>("expectedRows");
+ QTest::addColumn<IntList>("unexpectedRows");
+
+ QTest::newRow("10x10, first row")
+ << 10 << 10 << 0
+ << (IntList() << 0)
+ << (IntList() << 0)
+ << (IntList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9);
+
+ QTest::newRow("10x10, first 4 rows")
+ << 10 << 10 << 0
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 4 << 5 << 6 << 7 << 8 << 9);
+
+ QTest::newRow("10x10, last 4 rows")
+ << 10 << 10 << 0
+ << (IntList() << 6 << 7 << 8 << 9)
+ << (IntList() << 6 << 7 << 8 << 9)
+ << (IntList() << 0 << 1 << 2 << 3 << 4 << 6);
+}
+
+void tst_QItemSelectionModel::selectedRows()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, column);
+ QFETCH(IntList, selectRows);
+ QFETCH(IntList, expectedRows);
+ QFETCH(IntList, unexpectedRows);
+
+ MyStandardItemModel model(rowCount, columnCount);
+ QItemSelectionModel selectionModel(&model);
+
+ for (int i = 0; i < selectRows.count(); ++i)
+ selectionModel.select(model.index(selectRows.at(i), 0),
+ QItemSelectionModel::Select
+ |QItemSelectionModel::Rows);
+
+ for (int j = 0; j < selectRows.count(); ++j)
+ QVERIFY(selectionModel.isRowSelected(expectedRows.at(j), QModelIndex()));
+
+ for (int k = 0; k < selectRows.count(); ++k)
+ QVERIFY(!selectionModel.isRowSelected(unexpectedRows.at(k), QModelIndex()));
+
+ QModelIndexList selectedRowIndexes = selectionModel.selectedRows(column);
+ QCOMPARE(selectedRowIndexes.count(), expectedRows.count());
+ qSort(selectedRowIndexes);
+ for (int l = 0; l < selectedRowIndexes.count(); ++l) {
+ QCOMPARE(selectedRowIndexes.at(l).row(), expectedRows.at(l));
+ QCOMPARE(selectedRowIndexes.at(l).column(), column);
+ }
+}
+
+void tst_QItemSelectionModel::selectedColumns_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<IntList>("selectColumns");
+ QTest::addColumn<IntList>("expectedColumns");
+ QTest::addColumn<IntList>("unexpectedColumns");
+
+ QTest::newRow("10x10, first columns")
+ << 10 << 10 << 0
+ << (IntList() << 0)
+ << (IntList() << 0)
+ << (IntList() << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9);
+
+ QTest::newRow("10x10, first 4 columns")
+ << 10 << 10 << 0
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 0 << 1 << 2 << 3)
+ << (IntList() << 4 << 5 << 6 << 7 << 8 << 9);
+
+ QTest::newRow("10x10, last 4 columns")
+ << 10 << 10 << 0
+ << (IntList() << 6 << 7 << 8 << 9)
+ << (IntList() << 6 << 7 << 8 << 9)
+ << (IntList() << 0 << 1 << 2 << 3 << 4 << 6);
+}
+
+void tst_QItemSelectionModel::selectedColumns()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(IntList, selectColumns);
+ QFETCH(IntList, expectedColumns);
+ QFETCH(IntList, unexpectedColumns);
+
+ MyStandardItemModel model(rowCount, columnCount);
+ QItemSelectionModel selectionModel(&model);
+
+ for (int i = 0; i < selectColumns.count(); ++i)
+ selectionModel.select(model.index(0, selectColumns.at(i)),
+ QItemSelectionModel::Select
+ |QItemSelectionModel::Columns);
+
+ for (int j = 0; j < selectColumns.count(); ++j)
+ QVERIFY(selectionModel.isColumnSelected(expectedColumns.at(j), QModelIndex()));
+
+ for (int k = 0; k < selectColumns.count(); ++k)
+ QVERIFY(!selectionModel.isColumnSelected(unexpectedColumns.at(k), QModelIndex()));
+
+ QModelIndexList selectedColumnIndexes = selectionModel.selectedColumns(row);
+ QCOMPARE(selectedColumnIndexes.count(), expectedColumns.count());
+ qSort(selectedColumnIndexes);
+ for (int l = 0; l < selectedColumnIndexes.count(); ++l) {
+ QCOMPARE(selectedColumnIndexes.at(l).column(), expectedColumns.at(l));
+ QCOMPARE(selectedColumnIndexes.at(l).row(), row);
+ }
+}
+
+void tst_QItemSelectionModel::setCurrentIndex()
+{
+ // Build up a simple tree
+ QStandardItemModel *treemodel = new QStandardItemModel(0, 1);
+ treemodel->insertRow(0, new QStandardItem(1));
+ treemodel->insertRow(1, new QStandardItem(2));
+
+ QTreeView treeView;
+ treeView.setModel(treemodel);
+ QItemSelectionModel *selectionModel = treeView.selectionModel();
+ selectionModel->setCurrentIndex(
+ treemodel->index(0, 0, treemodel->index(0, 0)),
+ QItemSelectionModel::SelectCurrent);
+
+ QSignalSpy currentSpy(selectionModel,
+ SIGNAL(currentChanged(QModelIndex,QModelIndex)));
+ QSignalSpy rowSpy(selectionModel,
+ SIGNAL(currentRowChanged(QModelIndex,QModelIndex)));
+ QSignalSpy columnSpy(selectionModel,
+ SIGNAL(currentColumnChanged(QModelIndex,QModelIndex)));
+
+ // Select the same row and column indexes, but with a different parent
+ selectionModel->setCurrentIndex(
+ treemodel->index(0, 0, treemodel->index(1, 0)),
+ QItemSelectionModel::SelectCurrent);
+
+ QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(rowSpy.count(), 1);
+ QCOMPARE(columnSpy.count(), 1);
+
+ // Select another row in the same parent
+ selectionModel->setCurrentIndex(
+ treemodel->index(1, 0, treemodel->index(1, 0)),
+ QItemSelectionModel::SelectCurrent);
+
+ QCOMPARE(currentSpy.count(), 2);
+ QCOMPARE(rowSpy.count(), 2);
+ QCOMPARE(columnSpy.count(), 1);
+
+ delete treemodel;
+}
+
+void tst_QItemSelectionModel::splitOnInsert()
+{
+ QStandardItemModel model(4, 1);
+ QItemSelectionModel selectionModel(&model);
+ selectionModel.select(model.index(2, 0), QItemSelectionModel::Select);
+ model.insertRow(2);
+ model.removeRow(3);
+ QVERIFY(!selectionModel.isSelected(model.index(1, 0)));
+}
+
+void tst_QItemSelectionModel::task196285_rowIntersectsSelection()
+{
+ QTableWidget table;
+ table.setColumnCount(1);
+ table.setRowCount(1);
+ table.setItem(0, 0, new QTableWidgetItem("foo"));
+ QAbstractItemModel *model = table.model();
+ QItemSelectionModel *selectionModel = table.selectionModel();
+ QModelIndex index = model->index(0, 0, QModelIndex());
+
+ selectionModel->select(index, QItemSelectionModel::Select);
+ QVERIFY(selectionModel->rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY(selectionModel->columnIntersectsSelection(0, QModelIndex()));
+
+ selectionModel->select(index, QItemSelectionModel::Deselect);
+ QVERIFY(!selectionModel->rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY(!selectionModel->columnIntersectsSelection(0, QModelIndex()));
+
+ selectionModel->select(index, QItemSelectionModel::Toggle);
+ QVERIFY(selectionModel->rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY(selectionModel->columnIntersectsSelection(0, QModelIndex()));
+
+ selectionModel->select(index, QItemSelectionModel::Toggle);
+ QVERIFY(!selectionModel->rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY(!selectionModel->columnIntersectsSelection(0, QModelIndex()));
+}
+
+void tst_QItemSelectionModel::unselectable()
+{
+ QTreeWidget w;
+ for (int i = 0; i < 10; ++i)
+ w.setItemSelected(new QTreeWidgetItem(&w), true);
+ QCOMPARE(w.topLevelItemCount(), 10);
+ QCOMPARE(w.selectionModel()->selectedIndexes().count(), 10);
+ QCOMPARE(w.selectionModel()->selectedRows().count(), 10);
+ for (int j = 0; j < 10; ++j)
+ w.topLevelItem(j)->setFlags(0);
+ QCOMPARE(w.selectionModel()->selectedIndexes().count(), 0);
+ QCOMPARE(w.selectionModel()->selectedRows().count(), 0);
+}
+
+void tst_QItemSelectionModel::task220420_selectedIndexes()
+{
+ QStandardItemModel model(2, 2);
+ QItemSelectionModel selectionModel(&model);
+ QItemSelection selection;
+ selection.append(QItemSelectionRange(model.index(0,0)));
+ selection.append(QItemSelectionRange(model.index(0,1)));
+
+ //we select the 1st row
+ selectionModel.select(selection, QItemSelectionModel::Rows | QItemSelectionModel::Select);
+
+ QCOMPARE(selectionModel.selectedRows().count(), 1);
+ QCOMPARE(selectionModel.selectedIndexes().count(), model.columnCount());
+}
+
+
+class QtTestTableModel: public QAbstractTableModel
+{
+ Q_OBJECT
+
+ public:
+ QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = 0)
+ : QAbstractTableModel(parent),
+ row_count(rows),
+ column_count(columns) {}
+
+ int rowCount(const QModelIndex& = QModelIndex()) const { return row_count; }
+ int columnCount(const QModelIndex& = QModelIndex()) const { return column_count; }
+ bool isEditable(const QModelIndex &) const { return true; }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (role == Qt::DisplayRole || role == Qt::EditRole)
+ return QString("[%1,%2]").arg(idx.row()).arg(idx.column());
+ return QVariant();
+ }
+
+ int row_count;
+ int column_count;
+ friend class tst_QItemSelectionModel;
+};
+
+
+void tst_QItemSelectionModel::task240734_layoutChanged()
+{
+ QtTestTableModel model(1,1);
+ QItemSelectionModel selectionModel(&model);
+ selectionModel.select(model.index(0,0), QItemSelectionModel::Select);
+ QCOMPARE(selectionModel.selectedIndexes().count() , 1);
+
+ emit model.layoutAboutToBeChanged();
+ model.row_count = 5;
+ emit model.layoutChanged();
+
+ //The selection should not change.
+ QCOMPARE(selectionModel.selectedIndexes().count() , 1);
+ QCOMPARE(selectionModel.selectedIndexes().first() , model.index(0,0));
+}
+
+void tst_QItemSelectionModel::merge_data()
+{
+ QTest::addColumn<QItemSelection>("init");
+ QTest::addColumn<QItemSelection>("other");
+ QTest::addColumn<int>("command");
+ QTest::addColumn<QItemSelection>("result");
+
+ QTest::newRow("Simple select")
+ << QItemSelection()
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << int(QItemSelectionModel::Select)
+ << QItemSelection(model->index(2, 1) , model->index(3, 4));
+
+ QTest::newRow("Simple deselect")
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << int(QItemSelectionModel::Deselect)
+ << QItemSelection();
+
+ QTest::newRow("Simple Toggle deselect")
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << int(QItemSelectionModel::Toggle)
+ << QItemSelection();
+
+ QTest::newRow("Simple Toggle select")
+ << QItemSelection()
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << int(QItemSelectionModel::Toggle)
+ << QItemSelection(model->index(2, 1) , model->index(3, 4));
+
+ QTest::newRow("Add select")
+ << QItemSelection(model->index(2, 1) , model->index(3, 3))
+ << QItemSelection(model->index(2, 2) , model->index(3, 4))
+ << int(QItemSelectionModel::Select)
+ << QItemSelection(model->index(2, 1) , model->index(3, 4));
+
+ QTest::newRow("Deselect")
+ << QItemSelection(model->index(2, 1) , model->index(3, 4))
+ << QItemSelection(model->index(2, 2) , model->index(3, 4))
+ << int(QItemSelectionModel::Deselect)
+ << QItemSelection(model->index(2, 1) , model->index(3, 1));
+
+ QItemSelection r1(model->index(2, 1) , model->index(3, 1));
+ r1.select(model->index(2, 4) , model->index(3, 4));
+ QTest::newRow("Toggle")
+ << QItemSelection(model->index(2, 1) , model->index(3, 3))
+ << QItemSelection(model->index(2, 2) , model->index(3, 4))
+ << int(QItemSelectionModel::Toggle)
+ << r1;
+}
+
+
+void tst_QItemSelectionModel::merge()
+{
+ QFETCH(QItemSelection, init);
+ QFETCH(QItemSelection, other);
+ QFETCH(int, command);
+ QFETCH(QItemSelection, result);
+
+ init.merge(other, QItemSelectionModel::SelectionFlags(command));
+
+ foreach(const QModelIndex &idx, init.indexes())
+ QVERIFY(result.contains(idx));
+ foreach(const QModelIndex &idx, result.indexes())
+ QVERIFY(init.contains(idx));
+}
+
+void tst_QItemSelectionModel::task119433_isRowSelected()
+{
+ QStandardItemModel model(2,2);
+ model.setData(model.index(0,0), 0, Qt::UserRole - 1);
+ QItemSelectionModel sel(&model);
+ sel.select( QItemSelection(model.index(0,0), model.index(0, 1)), QItemSelectionModel::Select);
+ QCOMPARE(sel.selectedIndexes().count(), 1);
+ QVERIFY(sel.isRowSelected(0, QModelIndex()));
+}
+
+void tst_QItemSelectionModel::task252069_rowIntersectsSelection()
+{
+ QStandardItemModel m;
+ for (int i=0; i<8; ++i) {
+ for (int j=0; j<8; ++j) {
+ QStandardItem *item = new QStandardItem(QString("Item number %1").arg(i));
+ if ((i % 2 == 0 && j == 0) ||
+ (j % 2 == 0 && i == 0) ||
+ j == 5 || i == 5 ) {
+ item->setEnabled(false);
+ //item->setSelectable(false);
+ }
+ m.setItem(i, j, item);
+ }
+ }
+
+ QItemSelectionModel selected(&m);
+ //nothing is selected
+ QVERIFY(!selected.rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(2, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(3, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(5, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(0, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(2, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(3, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex()));
+ selected.select(m.index(2, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ QVERIFY(!selected.rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY( selected.rowIntersectsSelection(2, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(3, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(5, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(0, QModelIndex()));
+ QVERIFY( selected.columnIntersectsSelection(2, QModelIndex()));
+ QVERIFY( selected.columnIntersectsSelection(3, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex()));
+ selected.select(m.index(0, 5), QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ QVERIFY(!selected.rowIntersectsSelection(0, QModelIndex()));
+ QVERIFY( selected.rowIntersectsSelection(2, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(3, QModelIndex()));
+ QVERIFY(!selected.rowIntersectsSelection(5, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(0, QModelIndex()));
+ QVERIFY( selected.columnIntersectsSelection(2, QModelIndex()));
+ QVERIFY( selected.columnIntersectsSelection(3, QModelIndex()));
+ QVERIFY(!selected.columnIntersectsSelection(5, QModelIndex()));
+}
+
+void tst_QItemSelectionModel::task232634_childrenDeselectionSignal()
+{
+ QStandardItemModel model;
+
+ QStandardItem *parentItem = model.invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+
+ QModelIndex root = model.index(0,0);
+ QModelIndex par = root.child(0,0);
+ QModelIndex sel = par.child(0,0);
+
+ QItemSelectionModel selectionModel(&model);
+ selectionModel.select(sel, QItemSelectionModel::SelectCurrent);
+
+ QSignalSpy deselectSpy(&selectionModel, SIGNAL(selectionChanged(const QItemSelection& , const QItemSelection&)));
+ model.removeRows(0, 1, root);
+ QVERIFY(deselectSpy.count() == 1);
+
+ // More testing stress for the patch.
+ model.clear();
+ selectionModel.clear();
+
+ parentItem = model.invisibleRootItem();
+ for (int i = 0; i < 2; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item);
+ }
+ for (int i = 0; i < 2; ++i) {
+ parentItem = model.invisibleRootItem()->child(i, 0);
+ for (int j = 0; j < 2; ++j) {
+ QStandardItem *item = new QStandardItem(QString("item %0.%1").arg(i).arg(j));
+ parentItem->appendRow(item);
+ }
+ }
+
+ sel = model.index(0, 0).child(0, 0);
+ selectionModel.select(sel, QItemSelectionModel::Select);
+ QModelIndex sel2 = model.index(1, 0).child(0, 0);
+ selectionModel.select(sel2, QItemSelectionModel::Select);
+
+ QVERIFY(selectionModel.selection().contains(sel));
+ QVERIFY(selectionModel.selection().contains(sel2));
+ deselectSpy.clear();
+ model.removeRow(0, model.index(0, 0));
+ QVERIFY(deselectSpy.count() == 1);
+ QVERIFY(!selectionModel.selection().contains(sel));
+ QVERIFY(selectionModel.selection().contains(sel2));
+}
+
+void tst_QItemSelectionModel::task260134_layoutChangedWithAllSelected()
+{
+ QStringListModel model( QStringList() << "foo" << "bar" << "foo2");
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QItemSelectionModel selection(&proxy);
+
+
+ QCOMPARE(model.rowCount(), 3);
+ QCOMPARE(proxy.rowCount(), 3);
+ proxy.setFilterRegExp( QRegExp("f"));
+ QCOMPARE(proxy.rowCount(), 2);
+
+ QList<QPersistentModelIndex> indexList;
+ indexList << proxy.index(0,0) << proxy.index(1,0);
+ selection.select( QItemSelection(indexList.first(), indexList.last()), QItemSelectionModel::Select);
+
+ //let's check the selection hasn't changed
+ QCOMPARE(selection.selectedIndexes().count(), indexList.count());
+ foreach(QPersistentModelIndex index, indexList)
+ QVERIFY(selection.isSelected(index));
+
+ proxy.setFilterRegExp(QRegExp());
+ QCOMPARE(proxy.rowCount(), 3);
+
+ //let's check the selection hasn't changed
+ QCOMPARE(selection.selectedIndexes().count(), indexList.count());
+ foreach(QPersistentModelIndex index, indexList)
+ QVERIFY(selection.isSelected(index));
+}
+
+
+void tst_QItemSelectionModel::QTBUG5671_layoutChangedWithAllSelected()
+{
+ struct MyFilterModel : public QSortFilterProxyModel
+ { // Override sort filter proxy to remove even numbered rows.
+ bool filtering;
+ virtual bool filterAcceptsRow( int source_row, const QModelIndex& /* source_parent */) const
+ {
+ return !filtering || !( source_row & 1 );
+ }
+ };
+
+ //same as task260134_layoutChangedWithAllSelected but with a sightly bigger model
+
+ enum { cNumRows=30, cNumCols=20 };
+
+ QStandardItemModel model(cNumRows, cNumCols);
+ MyFilterModel proxy;
+ proxy.filtering = true;
+ proxy.setSourceModel(&model);
+ QItemSelectionModel selection(&proxy);
+
+ // Populate the tree view.
+ for (unsigned int i = 0; i < cNumCols; i++)
+ model.setHeaderData( i, Qt::Horizontal, QString::fromLatin1("Column %1").arg(i));
+
+ for (unsigned int r = 0; r < cNumRows; r++) {
+ for (unsigned int c = 0; c < cNumCols; c++) {
+ model.setData(model.index(r, c, QModelIndex()),
+ QString::fromLatin1("r:%1/c:%2").arg(r, c));
+ }
+ }
+
+
+ QCOMPARE(model.rowCount(), int(cNumRows));
+ QCOMPARE(proxy.rowCount(), int(cNumRows/2));
+
+ selection.select( QItemSelection(proxy.index(0,0), proxy.index(proxy.rowCount() - 1, proxy.columnCount() - 1)), QItemSelectionModel::Select);
+
+ QList<QPersistentModelIndex> indexList;
+ foreach(const QModelIndex &id, selection.selectedIndexes())
+ indexList << id;
+
+ proxy.filtering = false;
+ proxy.invalidate();
+ QCOMPARE(proxy.rowCount(), int(cNumRows));
+
+ //let's check the selection hasn't changed
+ QCOMPARE(selection.selectedIndexes().count(), indexList.count());
+ foreach(QPersistentModelIndex index, indexList)
+ QVERIFY(selection.isSelected(index));
+}
+
+void tst_QItemSelectionModel::QTBUG2804_layoutChangedTreeSelection()
+{
+ QStandardItemModel model;
+ QStandardItem top1("Child1"), top2("Child2"), top3("Child3");
+ QStandardItem sub11("Alpha"), sub12("Beta"), sub13("Gamma"), sub14("Delta"),
+ sub21("Alpha"), sub22("Beta"), sub23("Gamma"), sub24("Delta");
+ top1.appendColumn(QList<QStandardItem*>() << &sub11 << &sub12 << &sub13 << &sub14);
+ top2.appendColumn(QList<QStandardItem*>() << &sub21 << &sub22 << &sub23 << &sub24);
+ model.appendColumn(QList<QStandardItem*>() << &top1 << &top2 << &top3);
+
+ QItemSelectionModel selModel(&model);
+
+ selModel.select(sub11.index(), QItemSelectionModel::Select);
+ selModel.select(sub12.index(), QItemSelectionModel::Select);
+ selModel.select(sub21.index(), QItemSelectionModel::Select);
+ selModel.select(sub23.index(), QItemSelectionModel::Select);
+
+ QModelIndexList list = selModel.selectedIndexes();
+ QCOMPARE(list.count(), 4);
+
+ model.sort(0); //this will provoke a relayout
+
+ QCOMPARE(selModel.selectedIndexes().count(), 4);
+}
+
+class RemovalObserver : public QObject
+{
+ Q_OBJECT
+ QItemSelectionModel *m_itemSelectionModel;
+public:
+ RemovalObserver(QItemSelectionModel *selectionModel)
+ : m_itemSelectionModel(selectionModel)
+ {
+ connect(m_itemSelectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(selectionChanged(QItemSelection, QItemSelection)));
+ }
+
+public slots:
+ void selectionChanged(const QItemSelection & /* selected */, const QItemSelection &deselected)
+ {
+ foreach(const QModelIndex &index, deselected.indexes()) {
+ QVERIFY(!m_itemSelectionModel->selection().contains(index));
+ }
+ QVERIFY(m_itemSelectionModel->selection().size() == 2);
+ }
+
+};
+
+void tst_QItemSelectionModel::deselectRemovedMiddleRange()
+{
+ QStandardItemModel model(8, 0);
+
+ for (int row = 0; row < 8; ++row) {
+ static const int column = 0;
+ QStandardItem *item = new QStandardItem(QString::number(row));
+ model.setItem(row, column, item);
+ }
+
+ QItemSelectionModel selModel(&model);
+
+ selModel.select(QItemSelection(model.index(3, 0), model.index(6, 0)), QItemSelectionModel::Select);
+
+ QVERIFY(selModel.selection().size() == 1);
+
+ RemovalObserver ro(&selModel);
+
+ QSignalSpy spy(&selModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)));
+ bool ok = model.removeRows(4, 2);
+
+ QVERIFY(ok);
+ QVERIFY(spy.size() == 1);
+}
+
+static QStandardItemModel* getModel(QObject *parent)
+{
+ QStandardItemModel *model = new QStandardItemModel(parent);
+
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *parentItem = model->invisibleRootItem();
+ QList<QStandardItem*> list;
+ for (int j = 0; j < 4; ++j) {
+ list.append(new QStandardItem(QString("item %1, %2").arg(i).arg(j)));
+ }
+ parentItem->appendRow(list);
+ parentItem = list.first();
+ for (int j = 0; j < 4; ++j) {
+ QList<QStandardItem*> list;
+ for (int k = 0; k < 4; ++k) {
+ list.append(new QStandardItem(QString("item %1, %2").arg(i).arg(j)));
+ }
+ parentItem->appendRow(list);
+ }
+ }
+ return model;
+}
+
+enum Result {
+ LessThan,
+ NotLessThan,
+ NotEqual
+};
+
+Q_DECLARE_METATYPE(Result);
+
+void tst_QItemSelectionModel::rangeOperatorLessThan_data()
+{
+ QTest::addColumn<int>("parent1");
+ QTest::addColumn<int>("top1");
+ QTest::addColumn<int>("left1");
+ QTest::addColumn<int>("bottom1");
+ QTest::addColumn<int>("right1");
+ QTest::addColumn<int>("parent2");
+ QTest::addColumn<int>("top2");
+ QTest::addColumn<int>("left2");
+ QTest::addColumn<int>("bottom2");
+ QTest::addColumn<int>("right2");
+ QTest::addColumn<Result>("result");
+
+ QTest::newRow("lt01") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 3 << 3 << NotLessThan;
+
+ QTest::newRow("lt02") << -1 << 0 << 0 << 2 << 3
+ << -1 << 0 << 0 << 3 << 3 << LessThan;
+ QTest::newRow("lt03") << -1 << 0 << 0 << 3 << 2
+ << -1 << 0 << 0 << 3 << 3 << LessThan;
+ QTest::newRow("lt04") << -1 << 0 << 0 << 2 << 2
+ << -1 << 0 << 0 << 3 << 3 << LessThan;
+
+ QTest::newRow("lt05") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 2 << 3 << NotLessThan;
+ QTest::newRow("lt06") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 3 << 2 << NotLessThan;
+ QTest::newRow("lt07") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 2 << 2 << NotLessThan;
+
+ QTest::newRow("lt08") << -1 << 0 << 0 << 3 << 3
+ << 0 << 0 << 0 << 3 << 3 << NotEqual;
+ QTest::newRow("lt09") << 1 << 0 << 0 << 3 << 3
+ << 0 << 0 << 0 << 3 << 3 << NotEqual;
+ QTest::newRow("lt10") << 1 << 0 << 0 << 1 << 1
+ << 0 << 2 << 2 << 3 << 3 << NotEqual;
+ QTest::newRow("lt11") << 1 << 2 << 2 << 3 << 3
+ << 0 << 0 << 0 << 1 << 1 << NotEqual;
+
+ QTest::newRow("lt12") << -1 << 0 << 0 << 1 << 1
+ << -1 << 2 << 2 << 3 << 3 << LessThan;
+ QTest::newRow("lt13") << -1 << 2 << 2 << 3 << 3
+ << -1 << 0 << 0 << 1 << 1 << NotLessThan;
+ QTest::newRow("lt14") << 1 << 0 << 0 << 1 << 1
+ << 1 << 2 << 2 << 3 << 3 << LessThan;
+ QTest::newRow("lt15") << 1 << 2 << 2 << 3 << 3
+ << 1 << 0 << 0 << 1 << 1 << NotLessThan;
+
+ QTest::newRow("lt16") << -1 << 0 << 0 << 2 << 2
+ << -1 << 1 << 1 << 3 << 3 << LessThan;
+ QTest::newRow("lt17") << -1 << 1 << 1 << 3 << 3
+ << -1 << 0 << 0 << 2 << 2 << NotLessThan;
+ QTest::newRow("lt18") << 1 << 0 << 0 << 2 << 2
+ << 1 << 1 << 1 << 3 << 3 << LessThan;
+ QTest::newRow("lt19") << 1 << 1 << 1 << 3 << 3
+ << 1 << 0 << 0 << 2 << 2 << NotLessThan;
+}
+
+void tst_QItemSelectionModel::rangeOperatorLessThan()
+{
+ QStandardItemModel *model1 = getModel(this);
+ QStandardItemModel *model2 = getModel(this);
+
+ QFETCH(int, parent1);
+ QFETCH(int, top1);
+ QFETCH(int, left1);
+ QFETCH(int, bottom1);
+ QFETCH(int, right1);
+ QFETCH(int, parent2);
+ QFETCH(int, top2);
+ QFETCH(int, left2);
+ QFETCH(int, bottom2);
+ QFETCH(int, right2);
+ QFETCH(Result, result);
+
+ QModelIndex p1 = model1->index(parent1, 0);
+
+ QModelIndex tl1 = model1->index(top1, left1, p1);
+ QModelIndex br1 = model1->index(bottom1, right1, p1);
+
+ QItemSelectionRange r1(tl1, br1);
+
+ QModelIndex p2 = model1->index(parent2, 0);
+
+ QModelIndex tl2 = model1->index(top2, left2, p2);
+ QModelIndex br2 = model1->index(bottom2, right2, p2);
+
+ QItemSelectionRange r2(tl2, br2);
+
+ if (result == LessThan)
+ QVERIFY(r1 < r2);
+ else if (result == NotLessThan)
+ QVERIFY(!(r1 < r2));
+ else if (result == NotEqual)
+ if (!(r1 < r2))
+ QVERIFY(r2 < r1);
+
+ // Ranges in different models are always non-equal
+
+ QModelIndex p3 = model2->index(parent1, 0);
+
+ QModelIndex tl3 = model2->index(top1, left1, p3);
+ QModelIndex br3 = model2->index(bottom1, right1, p3);
+
+ QItemSelectionRange r3(tl3, br3);
+
+ if (!(r1 < r3))
+ QVERIFY(r3 < r1);
+
+ if (!(r2 < r3))
+ QVERIFY(r3 < r2);
+
+ QModelIndex p4 = model2->index(parent2, 0);
+
+ QModelIndex tl4 = model2->index(top2, left2, p4);
+ QModelIndex br4 = model2->index(bottom2, right2, p4);
+
+ QItemSelectionRange r4(tl4, br4);
+
+ if (!(r1 < r4))
+ QVERIFY(r4 < r1);
+
+ if (!(r2 < r4))
+ QVERIFY(r4 < r2);
+}
+
+void tst_QItemSelectionModel::testDifferentModels()
+{
+ QStandardItemModel model1;
+ QStandardItemModel model2;
+ QStandardItem top11("Child1"), top12("Child2"), top13("Child3");
+ QStandardItem top21("Child1"), top22("Child2"), top23("Child3");
+
+ model1.appendColumn(QList<QStandardItem*>() << &top11 << &top12 << &top13);
+ model2.appendColumn(QList<QStandardItem*>() << &top21 << &top22 << &top23);
+
+
+ QModelIndex topIndex1 = model1.index(0, 0);
+ QModelIndex bottomIndex1 = model1.index(2, 0);
+ QModelIndex topIndex2 = model2.index(0, 0);
+
+ QItemSelectionRange range(topIndex1, bottomIndex1);
+
+ QVERIFY(range.intersects(QItemSelectionRange(topIndex1, topIndex1)));
+ QVERIFY(!range.intersects(QItemSelectionRange(topIndex2, topIndex2)));
+
+ QItemSelection newSelection;
+ QItemSelection::split(range, QItemSelectionRange(topIndex2, topIndex2), &newSelection);
+
+ QVERIFY(newSelection.isEmpty());
+}
+
+class SelectionObserver : public QObject
+{
+ Q_OBJECT
+public:
+ SelectionObserver(QAbstractItemModel *model, QObject *parent = 0)
+ : QObject(parent), m_model(model), m_selectionModel(0)
+ {
+ connect(model, SIGNAL(modelReset()), SLOT(modelReset()));
+ }
+
+ void setSelectionModel(QItemSelectionModel *selectionModel)
+ {
+ m_selectionModel = selectionModel;
+ connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(selectionChanged(QItemSelection,QItemSelection)));
+ }
+
+ private slots:
+ void modelReset()
+ {
+ const QModelIndex idx = m_model->index(2, 0);
+ QVERIFY(idx.isValid());
+ m_selectionModel->select(QItemSelection(idx, idx), QItemSelectionModel::Clear);
+ }
+
+ void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
+ {
+ foreach(const QItemSelectionRange &range, selected)
+ QVERIFY(range.isValid());
+ foreach(const QItemSelectionRange &range, deselected)
+ QVERIFY(range.isValid());
+ }
+
+private:
+ QAbstractItemModel *m_model;
+ QItemSelectionModel *m_selectionModel;
+};
+
+void tst_QItemSelectionModel::testValidRangesInSelectionsAfterReset()
+{
+ QStringListModel model;
+
+ QStringList strings;
+ strings << "one"
+ << "two"
+ << "three"
+ << "four"
+ << "five";
+
+ model.setStringList(strings);
+
+ SelectionObserver observer(&model);
+
+ QItemSelectionModel selectionModel(&model);
+
+ selectionModel.select(QItemSelection(model.index(1, 0), model.index(3, 0)), QItemSelectionModel::Select);
+
+ // Cause d->ranges to contain something.
+ model.insertRows(2, 1);
+
+ observer.setSelectionModel(&selectionModel);
+
+ model.setStringList(strings);
+}
+
+class DuplicateItemSelectionModel : public QItemSelectionModel
+{
+ Q_OBJECT
+public:
+ DuplicateItemSelectionModel(QItemSelectionModel *target, QAbstractItemModel *model, QObject *parent = 0)
+ : QItemSelectionModel(model, parent), m_target(target)
+ {
+
+ }
+
+ void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
+ {
+ QItemSelectionModel::select(selection, command);
+ m_target->select(selection, command);
+ }
+
+ using QItemSelectionModel::select;
+
+private:
+ QItemSelectionModel *m_target;
+
+};
+
+void tst_QItemSelectionModel::testChainedSelectionClear()
+{
+ QStringListModel model(QStringList() << "Apples" << "Pears");
+
+ QItemSelectionModel selectionModel(&model, 0);
+ DuplicateItemSelectionModel duplicate(&selectionModel, &model, 0);
+
+ duplicate.select(model.index(0, 0), QItemSelectionModel::Select);
+
+ {
+ QModelIndexList selectedIndexes = selectionModel.selection().indexes();
+ QModelIndexList duplicatedIndexes = duplicate.selection().indexes();
+
+ QVERIFY(selectedIndexes.size() == duplicatedIndexes.size());
+ QVERIFY(selectedIndexes.size() == 1);
+ QVERIFY(selectedIndexes.first() == model.index(0, 0));
+ }
+
+ duplicate.clearSelection();
+
+ {
+ QModelIndexList selectedIndexes = selectionModel.selection().indexes();
+ QModelIndexList duplicatedIndexes = duplicate.selection().indexes();
+
+ QVERIFY(selectedIndexes.size() == duplicatedIndexes.size());
+ QVERIFY(selectedIndexes.size() == 0);
+ }
+
+}
+
+QTEST_MAIN(tst_QItemSelectionModel)
+#include "tst_qitemselectionmodel.moc"
diff --git a/tests/auto/widgets/itemviews/qitemview/.gitignore b/tests/auto/widgets/itemviews/qitemview/.gitignore
new file mode 100644
index 0000000000..c129cad63c
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemview/.gitignore
@@ -0,0 +1 @@
+tst_qitemview
diff --git a/tests/auto/widgets/itemviews/qitemview/qitemview.pro b/tests/auto/widgets/itemviews/qitemview/qitemview.pro
new file mode 100644
index 0000000000..dbdd4612d5
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemview/qitemview.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qitemview.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qitemview/tst_qitemview.cpp b/tests/auto/widgets/itemviews/qitemview/tst_qitemview.cpp
new file mode 100644
index 0000000000..4c64d4c52a
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemview/tst_qitemview.cpp
@@ -0,0 +1,928 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtCore/QtCore>
+#include "viewstotest.cpp"
+#include <stdlib.h>
+
+#if defined(Q_OS_UNIX)
+#include <time.h>
+#endif
+#if defined(Q_OS_WIN)
+#include <time.h>
+#if defined(Q_OS_WINCE)
+#include <aygshell.h>
+#endif
+#define random rand
+#define srandom srand
+
+#if defined(Q_OS_WINCE)
+bool qt_wince_is_platform(const QString &platformString) {
+ wchar_t tszPlatform[64];
+ if (SystemParametersInfo(SPI_GETPLATFORMTYPE,
+ sizeof(tszPlatform)/sizeof(*tszPlatform),tszPlatform,0))
+ if (0 == _tcsicmp(reinterpret_cast<const wchar_t *> (platformString.utf16()), tszPlatform))
+ return true;
+ return false;
+}
+
+bool qt_wince_is_pocket_pc() {
+ return qt_wince_is_platform(QString::fromLatin1("PocketPC"));
+}
+
+bool qt_wince_is_smartphone() {
+ return qt_wince_is_platform(QString::fromLatin1("Smartphone"));
+}
+bool qt_wince_is_mobile() {
+ return (qt_wince_is_smartphone() || qt_wince_is_pocket_pc());
+}
+#endif
+#endif
+
+//TESTED_CLASS=
+//TESTED_FILES=gui/itemviews/qtreeview.h gui/itemviews/qtreeview.cpp
+
+/*!
+ See viewstotest.cpp for instructions on how to have your view tested with these tests.
+
+ Each test such as visualRect have a _data() function which populate the QTest data with
+ tests specified by viewstotest.cpp and any extra data needed for that particular test.
+
+ setupWithNoTestData() fills QTest data with only the tests it is used by most tests.
+
+ There are some basic qDebug statements sprikled about that might be helpfull for
+ fixing your issues.
+ */
+class tst_QItemView : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QItemView() {};
+ virtual ~tst_QItemView() {};
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void nonDestructiveBasicTest_data();
+ void nonDestructiveBasicTest();
+
+ void spider_data();
+ void spider();
+
+ void resize_data();
+ void resize();
+
+ void visualRect_data();
+ void visualRect();
+
+ void indexAt_data();
+ void indexAt();
+
+ void scrollTo_data();
+ void scrollTo();
+
+ void moveCursor_data();
+ void moveCursor();
+
+private:
+ void setupWithNoTestData();
+ void populate();
+ void walkScreen(QAbstractItemView *view);
+
+ QAbstractItemView *view;
+ QAbstractItemModel *treeModel;
+ ViewsToTest *testViews;
+};
+
+/*!
+ * Views should not make invalid requests, sense a model might not check all the bad cases.
+ */
+class CheckerModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ CheckerModel() : QStandardItemModel() {};
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole ) const {
+ if (!index.isValid()) {
+ qWarning("%s: index is not valid", Q_FUNC_INFO);
+ return QVariant();
+ }
+ return QStandardItemModel::data(index, role);
+ };
+
+ Qt::ItemFlags flags(const QModelIndex & index) const {
+ if (!index.isValid()) {
+ qWarning("%s: index is not valid", Q_FUNC_INFO);
+ return Qt::ItemFlags();
+ }
+ if (index.row() == 2 || index.row() == rowCount() - 3
+ || index.column() == 2 || index.column() == columnCount() - 3) {
+ Qt::ItemFlags f = QStandardItemModel::flags(index);
+ f &= ~Qt::ItemIsEnabled;
+ return f;
+ }
+ return QStandardItemModel::flags(index);
+ };
+
+ QModelIndex parent ( const QModelIndex & child ) const {
+ if (!child.isValid()) {
+ qWarning("%s: child index is not valid", Q_FUNC_INFO);
+ return QModelIndex();
+ }
+ return QStandardItemModel::parent(child);
+ };
+
+ QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const {
+ if (orientation == Qt::Horizontal
+ && (section < 0 || section > columnCount())) {
+ qWarning("%s: invalid section %d, must be in range 0..%d",
+ Q_FUNC_INFO, section, columnCount());
+ return QVariant();
+ }
+ if (orientation == Qt::Vertical
+ && (section < 0 || section > rowCount())) {
+ qWarning("%s: invalid section %d, must be in range 0..%d",
+ Q_FUNC_INFO, section, rowCount());
+ return QVariant();
+ }
+ return QStandardItemModel::headerData(section, orientation, role);
+ }
+
+ QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const {
+ return QStandardItemModel::index(row, column, parent);
+ };
+
+ bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) {
+ if (!index.isValid()) {
+ qWarning("%s: index is not valid", Q_FUNC_INFO);
+ return false;
+ }
+ return QStandardItemModel::setData(index, value, role);
+ }
+
+ void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) {
+ if (column < 0 || column > columnCount())
+ qWarning("%s: invalid column %d, must be in range 0..%d",
+ Q_FUNC_INFO, column, columnCount());
+ else
+ QStandardItemModel::sort(column, order);
+ };
+
+ QModelIndexList match ( const QModelIndex & start, int role, const QVariant & value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap ) ) const {
+ if (hits <= 0) {
+ qWarning("%s: hits must be greater than zero", Q_FUNC_INFO);
+ return QModelIndexList();
+ }
+ if (!value.isValid()) {
+ qWarning("%s: value is not valid", Q_FUNC_INFO);
+ return QModelIndexList();
+ }
+ return QAbstractItemModel::match(start, role, value, hits, flags);
+ };
+
+ bool setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role = Qt::EditRole ) {
+ if (orientation == Qt::Horizontal
+ && (section < 0 || section > columnCount())) {
+ qWarning("%s: invalid section %d, must be in range 0..%d",
+ Q_FUNC_INFO, section, columnCount());
+ return false;
+ }
+ if (orientation == Qt::Vertical
+ && (section < 0 || section > rowCount())) {
+ qWarning("%s: invalid section %d, must be in range 0..%d",
+ Q_FUNC_INFO, section, rowCount());
+ return false;
+ }
+ return QAbstractItemModel::setHeaderData(section, orientation, value, role);
+ };
+};
+
+void tst_QItemView::init()
+{
+ testViews = new ViewsToTest();
+ populate();
+}
+
+void tst_QItemView::cleanup()
+{
+ delete testViews;
+ delete view;
+ delete treeModel;
+ view = 0;
+ testViews = 0;
+ treeModel = 0;
+}
+
+void tst_QItemView::setupWithNoTestData()
+{
+ ViewsToTest testViews;
+ QTest::addColumn<QString>("viewType");
+ QTest::addColumn<bool>("displays");
+ QTest::addColumn<int>("vscroll");
+ QTest::addColumn<int>("hscroll");
+ for (int i = 0; i < testViews.tests.size(); ++i) {
+ QString view = testViews.tests.at(i).viewType;
+ QString test = view + " ScrollPerPixel";
+ bool displayIndexes = (testViews.tests.at(i).display == ViewsToTest::DisplayRoot);
+ QTest::newRow(test.toLatin1().data()) << view << displayIndexes
+ << (int)QAbstractItemView::ScrollPerPixel
+ << (int)QAbstractItemView::ScrollPerPixel
+ ;
+ }
+ for (int i = 0; i < testViews.tests.size(); ++i) {
+ QString view = testViews.tests.at(i).viewType;
+ QString test = view + " ScrollPerItem";
+ bool displayIndexes = (testViews.tests.at(i).display == ViewsToTest::DisplayRoot);
+ QTest::newRow(test.toLatin1().data()) << view << displayIndexes
+ << (int)QAbstractItemView::ScrollPerItem
+ << (int)QAbstractItemView::ScrollPerItem
+ ;
+ }
+}
+
+void tst_QItemView::populate()
+{
+ treeModel = new CheckerModel;
+ QModelIndex parent;
+#if defined(QT_ARCH_ARM)
+ const int baseInsert = 4;
+#else
+ const int baseInsert = 26;
+#endif
+ for (int i = 0; i < 40; ++i) {
+ parent = treeModel->index(0, 0, parent);
+ treeModel->insertRows(0, baseInsert + i, parent);
+ treeModel->insertColumns(0, baseInsert + i, parent);
+ // Fill in some values to make it easier to debug
+ for (int x = 0; x < treeModel->rowCount(); ++x) {
+ for (int y = 0; y < treeModel->columnCount(); ++y) {
+ QModelIndex index = treeModel->index(x, y, parent);
+ treeModel->setData(index, QString("%1_%2_%3").arg(x).arg(y).arg(i));
+ treeModel->setData(index, QVariant(QColor(Qt::blue)), Qt::TextColorRole);
+ }
+ }
+ }
+}
+
+void tst_QItemView::nonDestructiveBasicTest_data()
+{
+ setupWithNoTestData();
+}
+
+/*!
+ nonDestructiveBasicTest tries to call a number of the basic functions (not all)
+ to make sure the view doesn't segfault, testing the functions that makes sense.
+ */
+void tst_QItemView::nonDestructiveBasicTest()
+{
+#ifdef Q_OS_WINCE
+ QTest::qWait(400);
+#endif
+
+ QFETCH(QString, viewType);
+ QFETCH(int, vscroll);
+ QFETCH(int, hscroll);
+
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ view->setVerticalScrollMode((QAbstractItemView::ScrollMode)vscroll);
+ view->setHorizontalScrollMode((QAbstractItemView::ScrollMode)hscroll);
+
+ // setSelectionModel() will assert
+ //view->setSelectionModel(0);
+ // setItemDelegate() will assert
+ //view->setItemDelegate(0);
+
+ // setSelectionMode
+ view->setSelectionMode(QAbstractItemView::SingleSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::SingleSelection);
+ view->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::ContiguousSelection);
+ view->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::ExtendedSelection);
+ view->setSelectionMode(QAbstractItemView::MultiSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::MultiSelection);
+ view->setSelectionMode(QAbstractItemView::NoSelection);
+ QCOMPARE(view->selectionMode(), QAbstractItemView::NoSelection);
+
+ // setSelectionBehavior
+ view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectItems);
+ view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectRows);
+ view->setSelectionBehavior(QAbstractItemView::SelectColumns);
+ QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectColumns);
+
+ // setEditTriggers
+ view->setEditTriggers(QAbstractItemView::EditKeyPressed);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::EditKeyPressed);
+ view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::NoEditTriggers);
+ view->setEditTriggers(QAbstractItemView::CurrentChanged);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::CurrentChanged);
+ view->setEditTriggers(QAbstractItemView::DoubleClicked);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::DoubleClicked);
+ view->setEditTriggers(QAbstractItemView::SelectedClicked);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::SelectedClicked);
+ view->setEditTriggers(QAbstractItemView::AnyKeyPressed);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::AnyKeyPressed);
+ view->setEditTriggers(QAbstractItemView::AllEditTriggers);
+ QCOMPARE(view->editTriggers(), QAbstractItemView::AllEditTriggers);
+
+ // setAutoScroll
+ view->setAutoScroll(false);
+ QCOMPARE(view->hasAutoScroll(), false);
+ view->setAutoScroll(true);
+ QCOMPARE(view->hasAutoScroll(), true);
+
+ // setTabKeyNavigation
+ view->setTabKeyNavigation(false);
+ QCOMPARE(view->tabKeyNavigation(), false);
+ view->setTabKeyNavigation(true);
+ QCOMPARE(view->tabKeyNavigation(), true);
+#ifndef QT_NO_DRAGANDDROP
+ // setDropIndicatorShown
+ view->setDropIndicatorShown(false);
+ QCOMPARE(view->showDropIndicator(), false);
+ view->setDropIndicatorShown(true);
+ QCOMPARE(view->showDropIndicator(), true);
+
+ // setDragEnabled
+ view->setDragEnabled(false);
+ QCOMPARE(view->dragEnabled(), false);
+ view->setDragEnabled(true);
+ QCOMPARE(view->dragEnabled(), true);
+#endif
+
+ // setAlternatingRowColors
+ view->setAlternatingRowColors(false);
+ QCOMPARE(view->alternatingRowColors(), false);
+ view->setAlternatingRowColors(true);
+ QCOMPARE(view->alternatingRowColors(), true);
+
+ // setIconSize
+ view->setIconSize(QSize(16, 16));
+ QCOMPARE(view->iconSize(), QSize(16, 16));
+ view->setIconSize(QSize(32, 32));
+ QCOMPARE(view->iconSize(), QSize(32, 32));
+ // Should this happen?
+ view->setIconSize(QSize(-1, -1));
+ QCOMPARE(view->iconSize(), QSize(-1, -1));
+
+ QCOMPARE(view->currentIndex(), QModelIndex());
+ QCOMPARE(view->rootIndex(), QModelIndex());
+
+ view->keyboardSearch("");
+ view->keyboardSearch("foo");
+ view->keyboardSearch("1");
+
+ QCOMPARE(view->visualRect(QModelIndex()), QRect());
+
+ view->scrollTo(QModelIndex());
+
+ QCOMPARE(view->sizeHintForIndex(QModelIndex()), QSize());
+ QCOMPARE(view->indexAt(QPoint(-1, -1)), QModelIndex());
+
+ if (!view->model()){
+ QCOMPARE(view->indexAt(QPoint(10, 10)), QModelIndex());
+ QCOMPARE(view->sizeHintForRow(0), -1);
+ QCOMPARE(view->sizeHintForColumn(0), -1);
+ } else if (view->itemDelegate()){
+ view->sizeHintForRow(0);
+ view->sizeHintForColumn(0);
+ }
+ view->openPersistentEditor(QModelIndex());
+ view->closePersistentEditor(QModelIndex());
+
+ view->reset();
+ view->setRootIndex(QModelIndex());
+ view->doItemsLayout();
+ view->selectAll();
+ // edit() causes warning by default
+ //view->edit(QModelIndex());
+ view->clearSelection();
+ view->setCurrentIndex(QModelIndex());
+}
+
+void tst_QItemView::spider_data()
+{
+ setupWithNoTestData();
+}
+
+void touch(QWidget *widget, Qt::KeyboardModifier modifier, Qt::Key keyPress){
+ int width = widget->width();
+ int height = widget->height();
+ for (int i = 0; i < 5; ++i) {
+ QTest::mouseClick(widget, Qt::LeftButton, modifier, QPoint(random() % width, random() % height));
+ QTest::mouseDClick(widget, Qt::LeftButton, modifier, QPoint(random() % width, random() % height));
+ QPoint press(random() % width, random() % height);
+ QPoint releasePoint(random() % width, random() % height);
+ QTest::mousePress(widget, Qt::LeftButton, modifier, press);
+ QTest::mouseMove(widget, releasePoint);
+ if (random() % 1 == 0)
+ QTest::mouseRelease(widget, Qt::LeftButton, 0, releasePoint);
+ else
+ QTest::mouseRelease(widget, Qt::LeftButton, modifier, releasePoint);
+ QTest::keyClick(widget, keyPress);
+ }
+}
+
+/*!
+ This is a basic stress testing application that tries a few basics such as clicking around
+ the screen, and key presses.
+
+ The main goal is to catch any easy segfaults, not to test every case.
+ */
+void tst_QItemView::spider()
+{
+ QFETCH(QString, viewType);
+ QFETCH(int, vscroll);
+ QFETCH(int, hscroll);
+
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ view->setVerticalScrollMode((QAbstractItemView::ScrollMode)vscroll);
+ view->setHorizontalScrollMode((QAbstractItemView::ScrollMode)hscroll);
+ view->setModel(treeModel);
+ view->show();
+#if defined(Q_OS_WINCE)
+ srandom(0);
+#else
+ srandom(time(0));
+#endif
+ touch(view->viewport(), Qt::NoModifier, Qt::Key_Left);
+ touch(view->viewport(), Qt::ShiftModifier, Qt::Key_Enter);
+ touch(view->viewport(), Qt::ControlModifier, Qt::Key_Backspace);
+ touch(view->viewport(), Qt::AltModifier, Qt::Key_Up);
+}
+
+void tst_QItemView::resize_data()
+{
+ setupWithNoTestData();
+}
+
+/*!
+ The main goal is to catch any infinite loops from layouting
+ */
+void tst_QItemView::resize()
+{
+ QSKIP("This test needs to be re-thought out, it takes too long and doesn't really catch the problem.", SkipAll);
+
+ QFETCH(QString, viewType);
+ QFETCH(int, vscroll);
+ QFETCH(int, hscroll);
+
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ view->setVerticalScrollMode((QAbstractItemView::ScrollMode)vscroll);
+ view->setHorizontalScrollMode((QAbstractItemView::ScrollMode)hscroll);
+ view->setModel(treeModel);
+ view->show();
+
+ for (int w = 100; w < 400; w+=10) {
+ for (int h = 100; h < 400; h+=10) {
+ view->resize(w, h);
+ QTest::qWait(1);
+ qApp->processEvents();
+ }
+ }
+}
+
+void tst_QItemView::visualRect_data()
+{
+ setupWithNoTestData();
+}
+
+void tst_QItemView::visualRect()
+{
+ QFETCH(QString, viewType);
+ QFETCH(int, vscroll);
+ QFETCH(int, hscroll);
+
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ view->setVerticalScrollMode((QAbstractItemView::ScrollMode)vscroll);
+ view->setHorizontalScrollMode((QAbstractItemView::ScrollMode)hscroll);
+ QCOMPARE(view->visualRect(QModelIndex()), QRect());
+
+ // Add model
+ view->setModel(treeModel);
+ QCOMPARE(view->visualRect(QModelIndex()), QRect());
+
+ QModelIndex topIndex = treeModel->index(0,0);
+
+ QFETCH(bool, displays);
+ if (!displays){
+ QVERIFY(view->visualRect(topIndex) == QRect());
+ return;
+ }
+
+ QVERIFY(view->visualRect(topIndex) != QRect());
+ view->show();
+ QVERIFY(view->visualRect(topIndex) != QRect());
+
+ QVERIFY(topIndex == view->indexAt(view->visualRect(topIndex).center()));
+ QVERIFY(topIndex == view->indexAt(view->visualRect(topIndex).bottomLeft()));
+ QVERIFY(topIndex == view->indexAt(view->visualRect(topIndex).bottomRight()));
+ QVERIFY(topIndex == view->indexAt(view->visualRect(topIndex).topLeft()));
+ QVERIFY(topIndex == view->indexAt(view->visualRect(topIndex).topRight()));
+
+ testViews->hideIndexes(view);
+ QModelIndex hiddenIndex = treeModel->index(1, 0);
+ QVERIFY(view->visualRect(hiddenIndex) == QRect());
+}
+
+void tst_QItemView::walkScreen(QAbstractItemView *view)
+{
+ QModelIndex hiddenIndex = view->model() ? view->model()->index(1, 0) : QModelIndex();
+ int width = view->width();
+ int height = view->height();
+ for (int w = 0; w < width; ++w)
+ {
+ for (int h = 0; h < height; ++h)
+ {
+ QPoint point(w, h);
+ QModelIndex index = view->indexAt(point);
+
+ // If we have no model then we should *never* get a valid index
+ if (!view->model() || !view->isVisible())
+ QVERIFY(!index.isValid());
+ // index should not be the hidden one
+ if (hiddenIndex.isValid())
+ QVERIFY(hiddenIndex != index);
+ // If we are valid then check the visualRect for that index
+ if (index.isValid()){
+ QRect visualRect = view->visualRect(index);
+ if (!visualRect.contains(point))
+ qDebug() << point << visualRect;
+ QVERIFY(visualRect.contains(point));
+ }
+ }
+ }
+}
+
+void walkIndex(QModelIndex index, QAbstractItemView *view)
+{
+ QRect visualRect = view->visualRect(index);
+ //if (index.column() == 0)
+ //qDebug() << index << visualRect;
+ int width = visualRect.width();
+ int height = visualRect.height();
+
+ for (int w = 0; w < width; ++w)
+ {
+ for (int h = 0; h < height; ++h)
+ {
+ QPoint point(visualRect.x()+w, visualRect.y()+h);
+ if (view->indexAt(point) != index) {
+ qDebug() << "index" << index << "visualRect" << visualRect << point << view->indexAt(point);
+ }
+ QVERIFY(view->indexAt(point) == index);
+ }
+ }
+
+}
+
+/*!
+ A model that returns an index of parent X should also return X when asking
+ for the parent of the index.
+
+ This recursive function does pretty extensive testing on the whole model in an
+ effort to catch edge cases.
+
+ This function assumes that rowCount(), columnCount() and index() work. If they have
+ a bug it will point it out, but the above tests should have already found the basic bugs
+ because it is easier to figure out the problem in those tests then this one.
+ */
+void checkChildren(QAbstractItemView *currentView, const QModelIndex &parent = QModelIndex(), int currentDepth=0)
+{
+ QAbstractItemModel *currentModel = currentView->model();
+
+ int rows = currentModel->rowCount(parent);
+ int columns = currentModel->columnCount(parent);
+
+ for (int r = 0; r < rows; ++r) {
+ for (int c = 0; c < columns; ++c) {
+ QModelIndex index = currentModel->index(r, c, parent);
+ walkIndex(index, currentView);
+ if (QTest::currentTestFailed())
+ return;
+
+ // recursivly go down
+ if (currentModel->hasChildren(index) && currentDepth < 2) {
+ checkChildren(currentView, index, ++currentDepth);
+ // Because this is recursive we will return at the first failure rather then
+ // reporting it over and over
+ if (QTest::currentTestFailed())
+ return;
+ }
+ }
+ }
+}
+
+
+void tst_QItemView::indexAt_data()
+{
+ setupWithNoTestData();
+}
+
+void tst_QItemView::indexAt()
+{
+ QFETCH(QString, viewType);
+ QFETCH(int, vscroll);
+ QFETCH(int, hscroll);
+
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ view->setVerticalScrollMode((QAbstractItemView::ScrollMode)vscroll);
+ view->setHorizontalScrollMode((QAbstractItemView::ScrollMode)hscroll);
+ view->show();
+ view->setModel(treeModel);
+#if 0
+ checkChildren(view);
+
+ QModelIndex index = view->model()->index(0, 0);
+ while (view->model()->hasChildren(index))
+ index = view->model()->index(0, 0, index);
+ QCOMPARE(view->model()->hasChildren(index), false);
+ QVERIFY(index.isValid());
+ view->setRootIndex(index);
+ //qDebug() << view->indexAt(QPoint(view->width()/2, view->height()/2)) << view->rootIndex();
+ QPoint p(1, view->height()/2);
+ QModelIndex idx = view->indexAt(p);
+ QCOMPARE(idx, QModelIndex());
+#endif
+}
+
+void tst_QItemView::scrollTo_data()
+{
+ setupWithNoTestData();
+}
+
+void tst_QItemView::scrollTo()
+{
+ QFETCH(QString, viewType);
+ QFETCH(int, vscroll);
+ QFETCH(int, hscroll);
+
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ view->setVerticalScrollMode((QAbstractItemView::ScrollMode)vscroll);
+ view->setHorizontalScrollMode((QAbstractItemView::ScrollMode)hscroll);
+ view->setModel(treeModel);
+ view->show();
+
+ QModelIndex parent;
+ for (int row = 0; row < treeModel->rowCount(parent); ++row) {
+ for (int column = 0; column < treeModel->columnCount(parent); ++column) {
+ QModelIndex idx = treeModel->index(row, column, parent);
+ view->scrollTo(idx);
+ QRect rect = view->visualRect(idx);
+ view->scrollTo(idx);
+ QCOMPARE(rect, view->visualRect(idx));
+ }
+ }
+
+ QModelIndex idx = treeModel->index(0, 0, parent);
+ view->scrollTo(idx);
+ QRect rect = view->visualRect(idx);
+ view->scrollToBottom();
+ view->scrollTo(idx);
+ QCOMPARE(rect, view->visualRect(idx));
+}
+
+void tst_QItemView::moveCursor_data()
+{
+ setupWithNoTestData();
+}
+
+class Event {
+public:
+ Event(){}
+ Event(Qt::Key k, QModelIndex s, QModelIndex e, QString n) : key(k), start(s), end(e), name(n){}
+ Qt::Key key;
+ QModelIndex start;
+ QModelIndex end;
+ QString name;
+};
+
+
+void tst_QItemView::moveCursor()
+{
+ QFETCH(QString, viewType);
+ view = testViews->createView(viewType);
+ QVERIFY(view);
+ if (view->objectName() == "QHeaderView")
+ return;
+
+ view->setModel(treeModel);
+ testViews->hideIndexes(view);
+ view->resize(100, 100);
+
+ QModelIndex invalidIndex = QModelIndex();
+ QModelIndex firstRow = treeModel->index(0, 0);
+ QModelIndex hiddenRowT = treeModel->index(1, 0);
+ QModelIndex disabledRowT = treeModel->index(2, 0);
+ QModelIndex secondRow = treeModel->index(3, 0);
+
+ QModelIndex secondToLastRow = treeModel->index(treeModel->rowCount() - 4, 0);
+ QModelIndex disabledRowB = treeModel->index(treeModel->rowCount() - 3, 0);
+ QModelIndex hiddenRowB = treeModel->index(treeModel->rowCount() - 2, 0);
+ QModelIndex lastRow = treeModel->index(treeModel->rowCount() - 1, 0);
+
+ QStack<Event> events;
+
+ events.push(Event(Qt::Key_Up, invalidIndex, firstRow, "inv, first"));
+ events.push(Event(Qt::Key_Up, hiddenRowT, firstRow, "hid, first"));
+ events.push(Event(Qt::Key_Up, disabledRowT, firstRow, "dis, first"));
+ events.push(Event(Qt::Key_Up, firstRow, firstRow, "first, first"));
+ events.push(Event(Qt::Key_Up, secondRow, firstRow, "sec, first"));
+ events.push(Event(Qt::Key_Up, hiddenRowB, firstRow, "hidB, first"));
+ events.push(Event(Qt::Key_Up, disabledRowB, secondToLastRow, "disB, secLast"));
+ events.push(Event(Qt::Key_Up, lastRow, secondToLastRow, "last, secLast"));
+
+ events.push(Event(Qt::Key_Down, invalidIndex, firstRow, "inv, first"));
+ events.push(Event(Qt::Key_Down, hiddenRowT, firstRow, "hid, first"));
+ events.push(Event(Qt::Key_Down, disabledRowT, secondRow, "dis, sec"));
+ events.push(Event(Qt::Key_Down, firstRow, secondRow, "first, sec"));
+ events.push(Event(Qt::Key_Down, secondToLastRow, lastRow, "secLast, last" ));
+ events.push(Event(Qt::Key_Down, disabledRowB, lastRow, "disB, last"));
+ events.push(Event(Qt::Key_Down, hiddenRowB, firstRow, "hidB, first"));
+ events.push(Event(Qt::Key_Down, lastRow, lastRow, "last, last"));
+
+ events.push(Event(Qt::Key_Home, invalidIndex, firstRow, "inv, first"));
+ events.push(Event(Qt::Key_End, invalidIndex, firstRow, "inv, first"));
+
+ if (view->objectName() == "QTableView") {
+ // In a table we move to the first/last column
+ events.push(Event(Qt::Key_Home, hiddenRowT, firstRow, "hid, first"));
+ events.push(Event(Qt::Key_Home, disabledRowT, disabledRowT, "dis, dis"));
+ events.push(Event(Qt::Key_Home, firstRow, firstRow, "first, first"));
+ events.push(Event(Qt::Key_Home, secondRow, secondRow, "sec, sec"));
+ events.push(Event(Qt::Key_Home, disabledRowB, disabledRowB, "disB, disB"));
+ events.push(Event(Qt::Key_Home, hiddenRowB, firstRow, "hidB, first"));
+ events.push(Event(Qt::Key_Home, secondToLastRow, secondToLastRow, "secLast, secLast"));
+ events.push(Event(Qt::Key_Home, lastRow, lastRow, "last, last"));
+
+ int col = treeModel->columnCount() - 1;
+ events.push(Event(Qt::Key_End, hiddenRowT, firstRow, "hidT, hidT"));
+ events.push(Event(Qt::Key_End, disabledRowT, disabledRowT, "disT, disT"));
+ events.push(Event(Qt::Key_End, firstRow, firstRow.sibling(firstRow.row(), col), "first, first_C"));
+ events.push(Event(Qt::Key_End, secondRow, secondRow.sibling(secondRow.row(), col), "sec, sec_C"));
+ events.push(Event(Qt::Key_End, disabledRowB, disabledRowB, "disB, disB"));
+ events.push(Event(Qt::Key_End, hiddenRowB, firstRow, "hidB, hidB"));
+ events.push(Event(Qt::Key_End, secondToLastRow, secondToLastRow.sibling(secondToLastRow.row(), col), "secLast, secLast_C"));
+ events.push(Event(Qt::Key_End, lastRow, lastRow.sibling(lastRow.row(), col), "last, last_C"));
+ } else {
+ events.push(Event(Qt::Key_Home, hiddenRowT, firstRow, "hid, first"));
+ events.push(Event(Qt::Key_Home, disabledRowT, firstRow, "dis, first"));
+ events.push(Event(Qt::Key_Home, firstRow, firstRow, "first, first"));
+ events.push(Event(Qt::Key_Home, secondRow, firstRow, "sec, first"));
+ events.push(Event(Qt::Key_Home, disabledRowB, firstRow, "disB, first"));
+ events.push(Event(Qt::Key_Home, hiddenRowB, firstRow, "hidB, first"));
+ events.push(Event(Qt::Key_Home, secondToLastRow, firstRow, "sec, first"));
+ events.push(Event(Qt::Key_Home, lastRow, firstRow, "last, first"));
+
+ events.push(Event(Qt::Key_End, hiddenRowT, firstRow, "hid, last"));
+ events.push(Event(Qt::Key_End, disabledRowT, lastRow, "dis, last"));
+ events.push(Event(Qt::Key_End, firstRow, lastRow, "first, last"));
+ events.push(Event(Qt::Key_End, secondRow, lastRow, "sec, last"));
+ events.push(Event(Qt::Key_End, disabledRowB, lastRow, "disB, last"));
+ events.push(Event(Qt::Key_End, hiddenRowB, firstRow, "hidB, last"));
+ events.push(Event(Qt::Key_End, secondToLastRow, lastRow, "sec, last"));
+ events.push(Event(Qt::Key_End, lastRow, lastRow, "last, last"));
+ }
+
+ events.push(Event(Qt::Key_PageDown, invalidIndex, firstRow, "inv, first"));
+ events.push(Event(Qt::Key_PageDown, firstRow, QModelIndex(), "first, x"));
+ events.push(Event(Qt::Key_PageDown, secondRow, QModelIndex(), "sec, x"));
+ events.push(Event(Qt::Key_PageDown, hiddenRowT, QModelIndex(), "hid, x"));
+ events.push(Event(Qt::Key_PageDown, disabledRowT, QModelIndex(), "dis, x"));
+ events.push(Event(Qt::Key_PageDown, disabledRowB, lastRow, "disB, last"));
+ events.push(Event(Qt::Key_PageDown, hiddenRowB, lastRow, "hidB, last"));
+ events.push(Event(Qt::Key_PageDown, secondToLastRow, lastRow, "secLast, last"));
+ events.push(Event(Qt::Key_PageDown, lastRow, lastRow, "last, last"));
+
+ events.push(Event(Qt::Key_PageUp, invalidIndex, firstRow, "inv, first"));
+ events.push(Event(Qt::Key_PageUp, firstRow, firstRow, "first, first"));
+ events.push(Event(Qt::Key_PageUp, secondRow, firstRow, "sec, first"));
+ events.push(Event(Qt::Key_PageUp, secondToLastRow, QModelIndex(), "secLast, x"));
+ events.push(Event(Qt::Key_PageUp, lastRow, QModelIndex(), "last, x"));
+
+ if (view->objectName() == "QTableView") {
+ events.push(Event(Qt::Key_Left, firstRow, firstRow, "first_0, first"));
+ events.push(Event(Qt::Key_Left, firstRow.sibling(0, 1), firstRow, "first_1, first"));
+ events.push(Event(Qt::Key_Left, firstRow.sibling(0, 2), firstRow, "first_2, first"));
+ events.push(Event(Qt::Key_Left, firstRow.sibling(0, 3), firstRow, "first_3, first"));
+ events.push(Event(Qt::Key_Left, secondRow, secondRow, "sec, sec"));
+
+ events.push(Event(Qt::Key_Right, firstRow, firstRow.sibling(0, 3), "first, first_3"));
+ events.push(Event(Qt::Key_Right, firstRow.sibling(0, 1), firstRow, "first_1, first"));
+ events.push(Event(Qt::Key_Right, firstRow.sibling(0, 2), firstRow.sibling(0, 3), "first_2, first_3"));
+ events.push(Event(Qt::Key_Right, firstRow.sibling(0, treeModel->columnCount()-1), firstRow.sibling(0, treeModel->columnCount()-1), "first_3, sec"));
+ }
+
+#if 0 // ### disable this part for now
+
+ // ### hide the first/last row,column and re-run all of these tests
+ // ### Not 100% sure, but I think the next to are tableview specific only and everyone else just does up/down
+ // QAbstractItemView::MoveNext, AbstractItemView::MovePrevious
+
+ while (!events.isEmpty()) {
+ Event event = events.pop();
+ view->setCurrentIndex(event.start);
+ QCOMPARE(view->currentIndex(), event.start);
+
+ if (event.key == Qt::Key_PageUp && event.end == QModelIndex()) {
+ QModelIndex x = view->indexAt(QPoint(1,1));
+ if (x.row() == 0)
+ event.end = x;
+ else
+ event.end = x.sibling(x.row() - 1, x.column());
+ }
+ if (event.key == Qt::Key_PageDown && event.end == QModelIndex()) {
+ QModelIndex x = view->indexAt(QPoint(1, view->viewport()->height() - 10));
+ if (x.row() == view->model()->rowCount() - 1)
+ event.end = x;
+ else
+ event.end = x.sibling(x.row() + 1, x.column());
+ }
+
+ QTest::keyPress(view, event.key);
+ QTest::keyRelease(view, event.key);
+ QModelIndex current = view->currentIndex();
+ if (event.key == Qt::Key_PageUp) {
+ int diff = event.end.row() - current.row();
+ QVERIFY(diff <= 2);
+ continue;
+ }
+ if (event.key == Qt::Key_PageDown) {
+ int diff = current.row() - event.end.row();
+ QVERIFY(diff <= 2);
+ continue;
+ }
+
+ if (current != event.end) {
+ QString k;
+ if (event.key == Qt::Key_Up) k = "up";
+ if (event.key == Qt::Key_Right) k = "right";
+ if (event.key == Qt::Key_Left) k = "left";
+ if (event.key == Qt::Key_PageUp) k = "page up";
+ if (event.key == Qt::Key_PageDown) k = "page down";
+ if (event.key == Qt::Key_Down) k = "down";
+ if (event.key == Qt::Key_Home) k = "home";
+ if (event.key == Qt::Key_End) k = "end";
+ qDebug() << k << event.name << event.start << event.end << current;
+ }
+ QCOMPARE(current, event.end);
+ }
+#endif
+}
+
+QTEST_MAIN(tst_QItemView)
+#include "tst_qitemview.moc"
diff --git a/tests/auto/widgets/itemviews/qitemview/viewstotest.cpp b/tests/auto/widgets/itemviews/qitemview/viewstotest.cpp
new file mode 100644
index 0000000000..b61ecd5c2a
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qitemview/viewstotest.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtCore/QtCore>
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+
+/*
+ To add a view to be tested add the header file to the includes
+ and impliment what is needed in the functions below.
+
+ You can add more then one view, several Qt views are included as examples.
+
+ In tst_qitemview.cpp a new ViewsToTest object is created for each test.
+
+ When you have errors fix the first ones first. Later tests depend upon them working
+*/
+
+class ViewsToTest
+{
+public:
+ ViewsToTest();
+
+ QAbstractItemView *createView(const QString &viewType);
+ void hideIndexes(QAbstractItemView *view);
+
+ enum Display { DisplayNone, DisplayRoot };
+
+ struct test {
+ test(QString m, Display d) : viewType(m), display(d){};
+ QString viewType;
+ Display display;
+ };
+
+ QList<test> tests;
+};
+
+
+/*!
+ Add new tests, they can be the same view, but in a different state.
+ */
+ViewsToTest::ViewsToTest()
+{
+ tests.append(test("QTreeView_ScrollPerItem", DisplayRoot));
+ tests.append(test("QTreeView_ScrollPerPixel", DisplayRoot));
+ tests.append(test("QListView_ScrollPerItem", DisplayRoot));
+ tests.append(test("QListView_ScrollPerPixel", DisplayRoot));
+ tests.append(test("QHeaderViewHorizontal", DisplayNone));
+ tests.append(test("QHeaderViewVertical", DisplayNone));
+ tests.append(test("QTableView_ScrollPerItem", DisplayRoot));
+ tests.append(test("QTableView_ScrollPerPixel", DisplayRoot));
+ tests.append(test("QTableViewNoGrid", DisplayRoot));
+}
+
+/*!
+ Return a new viewType.
+ */
+QAbstractItemView *ViewsToTest::createView(const QString &viewType)
+{
+ QAbstractItemView *view = 0;
+ if (viewType == "QListView_ScrollPerItem") {
+ view = new QListView();
+ view->setObjectName("QListView");
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+ } else if (viewType == "QListView_ScrollPerPixel") {
+ view = new QListView();
+ view->setObjectName("QListView");
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ } else if (viewType == "QHeaderViewHorizontal") {
+ view = new QHeaderView(Qt::Horizontal);
+ view->setObjectName("QHeaderView");
+ } else if (viewType == "QHeaderViewVertical") {
+ view = new QHeaderView(Qt::Vertical);
+ view->setObjectName("QHeaderView");
+ } else if (viewType == "QTableView_ScrollPerItem") {
+ view = new QTableView();
+ view->setObjectName("QTableView");
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+ } else if (viewType == "QTableView_ScrollPerPixel") {
+ view = new QTableView();
+ view->setObjectName("QTableView");
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ } else if (viewType == "QTableViewNoGrid") {
+ QTableView *table = new QTableView();
+ table->setObjectName("QTableView");
+ table->setShowGrid(false);
+ view = table;
+ } else if (viewType == "QTreeView_ScrollPerItem") {
+ view = new QTreeView();
+ view->setObjectName("QTreeView");
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+ view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ } else if (viewType == "QTreeView_ScrollPerPixel") {
+ view = new QTreeView();
+ view->setObjectName("QTreeView");
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ }
+ return view;
+}
+
+void ViewsToTest::hideIndexes(QAbstractItemView *view)
+{
+ if (QTableView *tableView = qobject_cast<QTableView *>(view)) {
+ tableView->setColumnHidden(1, true);
+ tableView->setRowHidden(1, true);
+ tableView->setRowHidden(tableView->model()->rowCount()-2, true);
+ }
+ if (QTreeView *treeView = qobject_cast<QTreeView *>(view)) {
+ treeView->setColumnHidden(1, true);
+ treeView->setRowHidden(1, QModelIndex(), true);
+ treeView->setRowHidden(treeView->model()->rowCount()-2, QModelIndex(), true);
+ }
+ if (QListView *listView = qobject_cast<QListView *>(view)) {
+ listView->setRowHidden(1, true);
+ listView->setRowHidden(listView->model()->rowCount()-2, true);
+ }
+}
+
diff --git a/tests/auto/widgets/itemviews/qlistview/.gitignore b/tests/auto/widgets/itemviews/qlistview/.gitignore
new file mode 100644
index 0000000000..a0e31d03d4
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qlistview/.gitignore
@@ -0,0 +1 @@
+tst_qlistview
diff --git a/tests/auto/widgets/itemviews/qlistview/qlistview.pro b/tests/auto/widgets/itemviews/qlistview/qlistview.pro
new file mode 100644
index 0000000000..07fabbce35
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qlistview/qlistview.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+QT += widgets gui-private
+SOURCES += tst_qlistview.cpp
+win32:!wince*: LIBS += -luser32
+
+qpa:contains(QT_CONFIG,xcb):CONFIG+=insignificant_test
diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
new file mode 100644
index 0000000000..b58a306f94
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
@@ -0,0 +1,2073 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qabstractitemmodel.h>
+#include <qapplication.h>
+#include <qlistview.h>
+#include <qlistwidget.h>
+#include <qitemdelegate.h>
+#include <qstandarditemmodel.h>
+#include <qstringlistmodel.h>
+#include <cmath>
+#include <math.h>
+#include <QtWidgets/QScrollBar>
+#include <QtWidgets/QDialog>
+#include <QtWidgets/QStyledItemDelegate>
+#if defined(Q_OS_WIN) || defined(Q_OS_WINCE)
+# include <windows.h>
+# include <QtGui/QGuiApplication>
+# include <QtGui/QPlatformNativeInterface>
+#endif // Q_OS_WIN
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+#if defined(Q_OS_WIN) || defined(Q_OS_WINCE)
+static inline HWND getHWNDForWidget(const QWidget *widget)
+{
+ QWindow *window = widget->windowHandle();
+ return static_cast<HWND> (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
+}
+#endif // Q_OS_WIN
+
+class tst_QListView : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QListView();
+ virtual ~tst_QListView();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+ void getSetCheck();
+ void noDelegate();
+ void noModel();
+ void emptyModel();
+ void removeRows();
+ void cursorMove();
+ void hideRows();
+ void moveCursor();
+ void moveCursor2();
+ void moveCursor3();
+ void indexAt();
+ void clicked();
+ void singleSelectionRemoveRow();
+ void singleSelectionRemoveColumn();
+ void modelColumn();
+ void hideFirstRow();
+ void batchedMode();
+ void setCurrentIndex();
+ void selection_data();
+ void selection();
+ void scrollTo();
+ void scrollBarRanges();
+ void scrollBarAsNeeded_data();
+ void scrollBarAsNeeded();
+ void moveItems();
+ void wordWrap();
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && WINVER >= 0x0500
+ void setCurrentIndexAfterAppendRowCrash();
+#endif
+ void emptyItemSize();
+ void task203585_selectAll();
+ void task228566_infiniteRelayout();
+ void task248430_crashWith0SizedItem();
+ void task250446_scrollChanged();
+ void task196118_visualRegionForSelection();
+ void task254449_draggingItemToNegativeCoordinates();
+ void keyboardSearch();
+ void shiftSelectionWithNonUniformItemSizes();
+ void clickOnViewportClearsSelection();
+ void task262152_setModelColumnNavigate();
+ void taskQTBUG_2233_scrollHiddenItems_data();
+ void taskQTBUG_2233_scrollHiddenItems();
+ void taskQTBUG_633_changeModelData();
+ void taskQTBUG_435_deselectOnViewportClick();
+ void taskQTBUG_2678_spacingAndWrappedText();
+ void taskQTBUG_5877_skippingItemInPageDownUp();
+ void taskQTBUG_9455_wrongScrollbarRanges();
+ void styleOptionViewItem();
+ void taskQTBUG_12308_artihmeticException();
+ void taskQTBUG_12308_wrongFlowLayout();
+};
+
+// Testing get/set functions
+void tst_QListView::getSetCheck()
+{
+ QListView obj1;
+ // Movement QListView::movement()
+ // void QListView::setMovement(Movement)
+ obj1.setMovement(QListView::Movement(QListView::Static));
+ QCOMPARE(QListView::Movement(QListView::Static), obj1.movement());
+ obj1.setMovement(QListView::Movement(QListView::Free));
+ QCOMPARE(QListView::Movement(QListView::Free), obj1.movement());
+ obj1.setMovement(QListView::Movement(QListView::Snap));
+ QCOMPARE(QListView::Movement(QListView::Snap), obj1.movement());
+
+ // Flow QListView::flow()
+ // void QListView::setFlow(Flow)
+ obj1.setFlow(QListView::Flow(QListView::LeftToRight));
+ QCOMPARE(QListView::Flow(QListView::LeftToRight), obj1.flow());
+ obj1.setFlow(QListView::Flow(QListView::TopToBottom));
+ QCOMPARE(QListView::Flow(QListView::TopToBottom), obj1.flow());
+
+ // ResizeMode QListView::resizeMode()
+ // void QListView::setResizeMode(ResizeMode)
+ obj1.setResizeMode(QListView::ResizeMode(QListView::Fixed));
+ QCOMPARE(QListView::ResizeMode(QListView::Fixed), obj1.resizeMode());
+ obj1.setResizeMode(QListView::ResizeMode(QListView::Adjust));
+ QCOMPARE(QListView::ResizeMode(QListView::Adjust), obj1.resizeMode());
+
+ // LayoutMode QListView::layoutMode()
+ // void QListView::setLayoutMode(LayoutMode)
+ obj1.setLayoutMode(QListView::LayoutMode(QListView::SinglePass));
+ QCOMPARE(QListView::LayoutMode(QListView::SinglePass), obj1.layoutMode());
+ obj1.setLayoutMode(QListView::LayoutMode(QListView::Batched));
+ QCOMPARE(QListView::LayoutMode(QListView::Batched), obj1.layoutMode());
+
+ // int QListView::spacing()
+ // void QListView::setSpacing(int)
+ obj1.setSpacing(0);
+ QCOMPARE(0, obj1.spacing());
+ obj1.setSpacing(INT_MIN);
+ QCOMPARE(INT_MIN, obj1.spacing());
+ obj1.setSpacing(INT_MAX);
+ QCOMPARE(INT_MAX, obj1.spacing());
+
+ // ViewMode QListView::viewMode()
+ // void QListView::setViewMode(ViewMode)
+ obj1.setViewMode(QListView::ViewMode(QListView::ListMode));
+ QCOMPARE(QListView::ViewMode(QListView::ListMode), obj1.viewMode());
+ obj1.setViewMode(QListView::ViewMode(QListView::IconMode));
+ QCOMPARE(QListView::ViewMode(QListView::IconMode), obj1.viewMode());
+
+ // int QListView::modelColumn()
+ // void QListView::setModelColumn(int)
+ obj1.setModelColumn(0);
+ QCOMPARE(0, obj1.modelColumn());
+ obj1.setModelColumn(INT_MIN);
+ QCOMPARE(0, obj1.modelColumn()); // Less than 0 => 0
+ obj1.setModelColumn(INT_MAX);
+ QCOMPARE(0, obj1.modelColumn()); // No model => 0
+
+ // bool QListView::uniformItemSizes()
+ // void QListView::setUniformItemSizes(bool)
+ obj1.setUniformItemSizes(false);
+ QCOMPARE(false, obj1.uniformItemSizes());
+ obj1.setUniformItemSizes(true);
+ QCOMPARE(true, obj1.uniformItemSizes());
+
+ // make sure setViewMode() doesn't reset resizeMode
+ obj1.clearPropertyFlags();
+ obj1.setResizeMode(QListView::Adjust);
+ obj1.setViewMode(QListView::IconMode);
+ QCOMPARE(obj1.resizeMode(), QListView::Adjust);
+
+ obj1.setWordWrap(false);
+ QCOMPARE(false, obj1.wordWrap());
+ obj1.setWordWrap(true);
+ QCOMPARE(true, obj1. wordWrap());
+}
+
+class QtTestModel: public QAbstractListModel
+{
+public:
+ QtTestModel(QObject *parent = 0): QAbstractListModel(parent),
+ colCount(0), rCount(0), wrongIndex(false) {}
+ int rowCount(const QModelIndex&) const { return rCount; }
+ int columnCount(const QModelIndex&) const { return colCount; }
+ bool isEditable(const QModelIndex &) const { return true; }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+
+ if (!m_icon.isNull() && role == Qt::DecorationRole) {
+ return m_icon;
+ }
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (idx.row() < 0 || idx.column() < 0 || idx.column() >= colCount
+ || idx.row() >= rCount) {
+ wrongIndex = true;
+ qWarning("got invalid modelIndex %d/%d", idx.row(), idx.column());
+ }
+ return QString("%1/%2").arg(idx.row()).arg(idx.column());
+ }
+
+ void removeLastRow()
+ {
+ beginRemoveRows(QModelIndex(), rCount - 2, rCount - 1);
+ --rCount;
+ endRemoveRows();
+ }
+
+ void removeAllRows()
+ {
+ beginRemoveRows(QModelIndex(), 0, rCount - 1);
+ rCount = 0;
+ endRemoveRows();
+ }
+
+ void setDataIcon(const QIcon &icon)
+ {
+ m_icon = icon;
+ }
+
+ int colCount, rCount;
+ QIcon m_icon;
+ mutable bool wrongIndex;
+};
+
+tst_QListView::tst_QListView()
+{
+}
+
+tst_QListView::~tst_QListView()
+{
+}
+
+void tst_QListView::initTestCase()
+{
+}
+
+void tst_QListView::cleanupTestCase()
+{
+}
+
+void tst_QListView::init()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QListView::cleanup()
+{
+}
+
+
+void tst_QListView::noDelegate()
+{
+ QtTestModel model(0);
+ model.rCount = model.colCount = 10;
+ QListView view;
+ view.setModel(&model);
+ view.setItemDelegate(0);
+ view.show();
+}
+
+void tst_QListView::noModel()
+{
+ QListView view;
+ view.show();
+ view.setRowHidden(0, true);
+}
+
+void tst_QListView::emptyModel()
+{
+ QtTestModel model(0);
+ QListView view;
+ view.setModel(&model);
+ view.show();
+ QVERIFY(!model.wrongIndex);
+}
+
+void tst_QListView::removeRows()
+{
+ QtTestModel model(0);
+ model.rCount = model.colCount = 10;
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+
+ model.removeLastRow();
+ QVERIFY(!model.wrongIndex);
+
+ model.removeAllRows();
+ QVERIFY(!model.wrongIndex);
+}
+
+void tst_QListView::cursorMove()
+{
+ int rows = 6*6;
+ int columns = 6;
+
+ QStandardItemModel model(rows, columns);
+ QWidget topLevel;
+ QListView view(&topLevel);
+ view.setModel(&model);
+
+ for (int j = 0; j < columns; ++j) {
+ view.setModelColumn(j);
+ for (int i = 0; i < rows; ++i) {
+ QModelIndex index = model.index(i, j);
+ model.setData(index, QString("[%1,%2]").arg(i).arg(j));
+ view.setCurrentIndex(index);
+ QApplication::processEvents();
+ QCOMPARE(view.currentIndex(), index);
+ }
+ }
+
+ QSize cellsize(60, 25);
+ int gap = 1; // compensate for the scrollbars
+ int displayColumns = 6;
+
+ view.resize((displayColumns + gap) * cellsize.width(),
+ int((ceil(double(rows) / displayColumns) + gap) * cellsize.height()));
+ view.setResizeMode(QListView::Adjust);
+ view.setGridSize(cellsize);
+ view.setViewMode(QListView::IconMode);
+ view.doItemsLayout();
+ topLevel.show();
+
+ QVector<Qt::Key> keymoves;
+ keymoves << Qt::Key_Up << Qt::Key_Up << Qt::Key_Right << Qt::Key_Right << Qt::Key_Up
+ << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up
+ << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up
+ << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down;
+
+ int displayRow = rows / displayColumns - 1;
+ int displayColumn = displayColumns - (rows % displayColumns) - 1;
+
+ QApplication::instance()->processEvents();
+ for (int i = 0; i < keymoves.size(); ++i) {
+ Qt::Key key = keymoves.at(i);
+ QTest::keyClick(&view, key);
+ switch (key) {
+ case Qt::Key_Up:
+ displayRow = qMax(0, displayRow - 1);
+ break;
+ case Qt::Key_Down:
+ displayRow = qMin(rows / displayColumns - 1, displayRow + 1);
+ break;
+ case Qt::Key_Left:
+ displayColumn = qMax(0, displayColumn - 1);
+ break;
+ case Qt::Key_Right:
+ displayColumn = qMin(displayColumns-1, displayColumn + 1);
+ break;
+ default:
+ QVERIFY(false);
+ }
+
+ QApplication::instance()->processEvents();
+
+ int row = displayRow * displayColumns + displayColumn;
+ int column = columns - 1;
+ QModelIndex index = model.index(row, column);
+ QCOMPARE(view.currentIndex().row(), row);
+ QCOMPARE(view.currentIndex().column(), column);
+ QCOMPARE(view.currentIndex(), index);
+ }
+}
+
+void tst_QListView::hideRows()
+{
+ QtTestModel model(0);
+ model.rCount = model.colCount = 10;
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+
+ // hide then show
+ QVERIFY(!view.isRowHidden(2));
+ view.setRowHidden(2, true);
+ QVERIFY(view.isRowHidden(2));
+ view.setRowHidden(2, false);
+ QVERIFY(!view.isRowHidden(2));
+
+ // re show same row
+ QVERIFY(!view.isRowHidden(2));
+ view.setRowHidden(2, false);
+ QVERIFY(!view.isRowHidden(2));
+
+ // double hidding
+ QVERIFY(!view.isRowHidden(2));
+ view.setRowHidden(2, true);
+ QVERIFY(view.isRowHidden(2));
+ view.setRowHidden(2, true);
+ QVERIFY(view.isRowHidden(2));
+ view.setRowHidden(2, false);
+ QVERIFY(!view.isRowHidden(2));
+
+ // show in per-item mode, then hide the first row
+ view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+ QVERIFY(!view.isRowHidden(0));
+ view.setRowHidden(0, true);
+ QVERIFY(view.isRowHidden(0));
+ view.setRowHidden(0, false);
+ QVERIFY(!view.isRowHidden(0));
+
+ QStandardItemModel sim(0);
+ QStandardItem *root = new QStandardItem("Root row");
+ for (int i=0;i<5;i++)
+ root->appendRow(new QStandardItem(QString("Row %1").arg(i)));
+ sim.appendRow(root);
+ view.setModel(&sim);
+ view.setRootIndex(root->index());
+ QVERIFY(!view.isRowHidden(0));
+ view.setRowHidden(0, true);
+ QVERIFY(view.isRowHidden(0));
+ view.setRowHidden(0, false);
+ QVERIFY(!view.isRowHidden(0));
+}
+
+
+void tst_QListView::moveCursor()
+{
+ QtTestModel model(0);
+ model.rCount = model.colCount = 10;
+
+ QListView view;
+ view.setModel(&model);
+
+ QTest::keyClick(&view, Qt::Key_Down);
+
+ view.setModel(0);
+ view.setModel(&model);
+ view.setRowHidden(0, true);
+
+ QTest::keyClick(&view, Qt::Key_Down);
+ QCOMPARE(view.selectionModel()->currentIndex(), model.index(1, 0));
+}
+
+class QMoveCursorListView : public QListView
+{
+public:
+ QMoveCursorListView() : QListView() {}
+
+ enum CursorAction { MoveUp, MoveDown, MoveLeft, MoveRight,
+ MoveHome, MoveEnd, MovePageUp, MovePageDown,
+ MoveNext, MovePrevious };
+
+ QModelIndex moveCursor(QMoveCursorListView::CursorAction action, Qt::KeyboardModifiers modifiers)
+ {
+ return QListView::moveCursor((QListView::CursorAction)action, modifiers);
+ }
+};
+
+void tst_QListView::moveCursor2()
+{
+ QtTestModel model(0);
+ model.colCount = 1;
+ model.rCount = 100;
+ QPixmap pm(32, 32);
+ pm.fill(Qt::green);
+ model.setDataIcon(QIcon(pm));
+
+ QMoveCursorListView vu;
+ vu.setModel(&model);
+ vu.setIconSize(QSize(36,48));
+ vu.setGridSize(QSize(34,56));
+ //Standard framesize is 1. If Framesize > 2 increase size
+ int frameSize = qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ vu.resize(300 + frameSize * 2,300);
+ vu.setFlow(QListView::LeftToRight);
+ vu.setMovement(QListView::Static);
+ vu.setWrapping(true);
+ vu.setViewMode(QListView::IconMode);
+ vu.setLayoutMode(QListView::Batched);
+ vu.show();
+ vu.selectionModel()->setCurrentIndex(model.index(0,0), QItemSelectionModel::SelectCurrent);
+ QCoreApplication::processEvents();
+
+ QModelIndex idx = vu.moveCursor(QMoveCursorListView::MoveHome, Qt::NoModifier);
+ QCOMPARE(idx, model.index(0,0));
+ idx = vu.moveCursor(QMoveCursorListView::MoveDown, Qt::NoModifier);
+ QCOMPARE(idx, model.index(8,0));
+}
+
+void tst_QListView::moveCursor3()
+{
+ //this tests is for task 159792
+ //it tests that navigation works even with non uniform item sizes
+ QListView view;
+ QStandardItemModel model(0, 1);
+ QStandardItem *i1 = new QStandardItem("First item, long name");
+ QStandardItem *i2 = new QStandardItem("2nd item");
+ QStandardItem *i3 = new QStandardItem("Third item, long name");
+ i1->setSizeHint(QSize(200,32));
+ model.appendRow(i1);
+ model.appendRow(i2);
+ model.appendRow(i3);
+ view.setModel(&model);
+
+ view.setCurrentIndex(model.index(0, 0));
+
+ QCOMPARE(view.selectionModel()->currentIndex(), model.index(0, 0));
+ QTest::keyClick(&view, Qt::Key_Down);
+ QCOMPARE(view.selectionModel()->currentIndex(), model.index(1, 0));
+ QTest::keyClick(&view, Qt::Key_Down);
+ QCOMPARE(view.selectionModel()->currentIndex(), model.index(2, 0));
+ QTest::keyClick(&view, Qt::Key_Up);
+ QCOMPARE(view.selectionModel()->currentIndex(), model.index(1, 0));
+ QTest::keyClick(&view, Qt::Key_Up);
+ QCOMPARE(view.selectionModel()->currentIndex(), model.index(0, 0));
+}
+
+
+class QListViewShowEventListener : public QListView
+{
+public:
+ QListViewShowEventListener() : QListView() { m_shown = false;}
+
+ virtual void showEvent(QShowEvent * /*e*/)
+ {
+ int columnwidth = sizeHintForColumn(0);
+ QSize sz = sizeHintForIndex(model()->index(0,0));
+
+ // This should retrieve a model index in the 2nd section
+ m_index = indexAt(QPoint(columnwidth +2, sz.height()/2));
+ m_shown = true;
+ }
+
+ QModelIndex m_index;
+ bool m_shown;
+
+};
+
+void tst_QListView::indexAt()
+{
+ QtTestModel model(0);
+ model.rCount = 2;
+ model.colCount = 1;
+
+ QListView view;
+ view.setModel(&model);
+ view.setViewMode(QListView::ListMode);
+ view.setFlow(QListView::TopToBottom);
+
+ QSize sz = view.sizeHintForIndex(model.index(0,0));
+ QModelIndex index;
+ index = view.indexAt(QPoint(20,0));
+ QVERIFY(index.isValid());
+ QCOMPARE(index.row(), 0);
+
+ index = view.indexAt(QPoint(20,sz.height()));
+ QVERIFY(index.isValid());
+ QCOMPARE(index.row(), 1);
+
+ index = view.indexAt(QPoint(20,2 * sz.height()));
+ QVERIFY(!index.isValid());
+
+ // Check when peeking out of the viewport bounds
+ index = view.indexAt(QPoint(view.viewport()->rect().width(), 0));
+ QVERIFY(!index.isValid());
+ index = view.indexAt(QPoint(-1, 0));
+ QVERIFY(!index.isValid());
+ index = view.indexAt(QPoint(20, view.viewport()->rect().height()));
+ QVERIFY(!index.isValid());
+ index = view.indexAt(QPoint(20, -1));
+ QVERIFY(!index.isValid());
+
+ model.rCount = 30;
+ QListViewShowEventListener view2;
+ // Set the height to a small enough value so that it wraps to a new section.
+ view2.resize(300,100);
+ view2.setModel(&model);
+ view2.setFlow(QListView::TopToBottom);
+ view2.setViewMode(QListView::ListMode);
+ view2.setWrapping(true);
+ // We really want to make sure it is shown, because the layout won't be known until it is shown
+ view2.show();
+ QTest::qWaitForWindowShown(&view2);
+ QTRY_VERIFY(view2.m_shown);
+
+ QVERIFY(view2.m_index.isValid());
+ QVERIFY(view2.m_index.row() != 0);
+}
+
+void tst_QListView::clicked()
+{
+ QtTestModel model;
+ model.rCount = 10;
+ model.colCount = 2;
+
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+
+ QListView view;
+ view.setModel(&model);
+
+ view.show();
+ QApplication::processEvents();
+
+ QModelIndex firstIndex = model.index(0, 0, QModelIndex());
+ QVERIFY(firstIndex.isValid());
+ int itemHeight = view.visualRect(firstIndex).height();
+ view.resize(200, itemHeight * (model.rCount + 1));
+
+ for (int i = 0; i < model.rCount; ++i) {
+ QPoint p(5, 1 + itemHeight * i);
+ QModelIndex index = view.indexAt(p);
+ if (!index.isValid())
+ continue;
+ QSignalSpy spy(&view, SIGNAL(clicked(const QModelIndex&)));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QCOMPARE(spy.count(), 1);
+ }
+}
+
+void tst_QListView::singleSelectionRemoveRow()
+{
+ QStringList items;
+ items << "item1" << "item2" << "item3" << "item4";
+ QStringListModel model(items);
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex index;
+ view.setCurrentIndex(model.index(1));
+ index = view.currentIndex();
+ QCOMPARE(view.model()->data(index).toString(), QString("item2"));
+
+ model.removeRow(1);
+ index = view.currentIndex();
+ QCOMPARE(view.model()->data(index).toString(), QString("item3"));
+
+ model.removeRow(0);
+ index = view.currentIndex();
+ QCOMPARE(view.model()->data(index).toString(), QString("item3"));
+}
+
+void tst_QListView::singleSelectionRemoveColumn()
+{
+ int numCols = 3;
+ int numRows = 3;
+ QStandardItemModel model(numCols, numRows);
+ for (int r = 0; r < numRows; ++r)
+ for (int c = 0; c < numCols; ++c)
+ model.setData(model.index(r, c), QString("%1,%2").arg(r).arg(c));
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex index;
+ view.setCurrentIndex(model.index(1, 1));
+ index = view.currentIndex();
+ QCOMPARE(view.model()->data(index).toString(), QString("1,1"));
+
+ model.removeColumn(1);
+ index = view.currentIndex();
+ QCOMPARE(view.model()->data(index).toString(), QString("1,0"));
+
+ model.removeColumn(0);
+ index = view.currentIndex();
+ QCOMPARE(view.model()->data(index).toString(), QString("1,2"));
+}
+
+void tst_QListView::modelColumn()
+{
+ int numCols = 3;
+ int numRows = 3;
+ QStandardItemModel model(numCols, numRows);
+ for (int r = 0; r < numRows; ++r)
+ for (int c = 0; c < numCols; ++c)
+ model.setData(model.index(r, c), QString("%1,%2").arg(r).arg(c));
+
+
+ QListView view;
+ view.setModel(&model);
+
+
+ //
+ // Set and get with a valid model
+ //
+
+ // Default is column 0
+ QCOMPARE(view.modelColumn(), 0);
+
+ view.setModelColumn(0);
+ QCOMPARE(view.modelColumn(), 0);
+ view.setModelColumn(1);
+ QCOMPARE(view.modelColumn(), 1);
+ view.setModelColumn(2);
+ QCOMPARE(view.modelColumn(), 2);
+
+ // Out of bound cases should not modify the modelColumn
+ view.setModelColumn(-1);
+ QCOMPARE(view.modelColumn(), 2);
+ view.setModelColumn(INT_MAX);
+ QCOMPARE(view.modelColumn(), 2);
+
+
+ // See if it displays the right column using indexAt()...
+ view.resize(400,400);
+ view.show();
+
+ for (int c = 0; c < 3; ++c) {
+ view.setModelColumn(c);
+ int startrow = 0;
+ for (int y = 0; y < view.height(); ++y) {
+ QModelIndex idx = view.indexAt( QPoint(1, y) );
+ if (idx.row() == startrow + 1) ++startrow;
+ else if (idx.row() == -1) break;
+ QCOMPARE(idx.row(), startrow);
+ QCOMPARE(idx.column(), c);
+ }
+ QCOMPARE(startrow, 2);
+ }
+}
+
+void tst_QListView::hideFirstRow()
+{
+ QStringList items;
+ for (int i=0; i <100; ++i)
+ items << "item";
+ QStringListModel model(items);
+
+ QListView view;
+ view.setModel(&model);
+ view.setUniformItemSizes(true);
+ view.setRowHidden(0,true);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTest::qWait(10);
+}
+
+void tst_QListView::batchedMode()
+{
+ QStringList items;
+ for (int i=0; i <3; ++i)
+ items << "item";
+ QStringListModel model(items);
+
+ QListView view;
+ view.setModel(&model);
+ view.setUniformItemSizes(true);
+ view.setViewMode(QListView::ListMode);
+ view.setLayoutMode(QListView::Batched);
+ view.setBatchSize(2);
+ view.resize(200,400);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTest::qWait(100);
+
+#if defined(Q_OS_WINCE)
+ QTest::qWait(2000);
+#endif
+ QBitArray ba;
+ for (int y = 0; y < view.height(); ++y) {
+ QModelIndex idx = view.indexAt( QPoint(1, y) );
+ if (!idx.isValid())
+ break;
+ if (idx.row() >= ba.size())
+ ba.resize(idx.row() + 1);
+ ba.setBit(idx.row(), true);
+ }
+ QCOMPARE(ba.size(), 3);
+
+
+ // Test the dynamic listview too.
+ view.setViewMode(QListView::IconMode);
+ view.setLayoutMode(QListView::Batched);
+ view.setFlow(QListView::TopToBottom);
+ view.setBatchSize(2);
+
+#if !defined(Q_OS_WINCE)
+ QTest::qWait(100);
+#else
+ QTest::qWait(2000);
+#endif
+
+ ba.clear();
+ for (int y = 0; y < view.height(); ++y) {
+ QModelIndex idx = view.indexAt( QPoint(1, y) );
+ if (!idx.isValid())
+ break;
+ if (idx.row() >= ba.size())
+ ba.resize(idx.row() + 1);
+ ba.setBit(idx.row(), true);
+ }
+ QCOMPARE(ba.size(), 3);
+}
+
+void tst_QListView::setCurrentIndex()
+{
+ QStringList items;
+ int i;
+ for (i=0; i <20; ++i)
+ items << QString("item %1").arg(i);
+ QStringListModel model(items);
+
+ QListView view;
+ view.setModel(&model);
+
+ view.resize(220,182);
+ view.show();
+
+ for (int pass = 0; pass < 2; ++pass) {
+ view.setFlow(pass == 0 ? QListView::TopToBottom : QListView::LeftToRight);
+ QScrollBar *sb = pass == 0 ? view.verticalScrollBar() : view.horizontalScrollBar();
+ QList<QSize> gridsizes;
+ gridsizes << QSize() << QSize(200,38);
+ for (int ig = 0; ig < gridsizes.count(); ++ig) {
+ if (pass == 1 && !gridsizes.at(ig).isValid()) // the width of an item varies, so it might jump two times
+ continue;
+ view.setGridSize(gridsizes.at(ig));
+
+ qApp->processEvents();
+ int offset = sb->value();
+
+ // first "scroll" down, verify that we scroll one step at a time
+ i = 0;
+ for (i = 0; i < 20; ++i) {
+ QModelIndex idx = model.index(i,0);
+ view.setCurrentIndex(idx);
+ if (offset != sb->value()) {
+ // If it has scrolled, it should have scrolled only by one.
+ QCOMPARE(sb->value(), offset + 1);
+ ++offset;
+ }
+ //QTest::qWait(50);
+ }
+
+ --i; // item 20 does not exist
+ // and then "scroll" up, verify that we scroll one step at a time
+ for (; i >= 0; --i) {
+ QModelIndex idx = model.index(i,0);
+ view.setCurrentIndex(idx);
+ if (offset != sb->value()) {
+ // If it has scrolled, it should have scrolled only by one.
+ QCOMPARE(sb->value(), offset - 1);
+ --offset;
+ }
+ //QTest::qWait(50);
+ }
+ }
+ }
+}
+
+class PublicListView : public QListView
+{
+ public:
+ PublicListView(QWidget *parent = 0) : QListView(parent)
+ {
+
+ }
+ void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) {
+ QListView::setSelection(rect, flags);
+ }
+ QSize contentsSize() const { return QListView::contentsSize(); }
+
+ void setPositionForIndex(const QPoint &pos, const QModelIndex &index) {
+ QListView::setPositionForIndex(pos, index);
+ }
+};
+
+class TestDelegate : public QItemDelegate
+{
+public:
+ TestDelegate(QObject *parent) : QItemDelegate(parent), m_sizeHint(50,50) {}
+ QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return m_sizeHint; }
+
+ QSize m_sizeHint;
+};
+
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
+
+void tst_QListView::selection_data()
+{
+ QTest::addColumn<int>("itemCount");
+ QTest::addColumn<int>("viewMode");
+ QTest::addColumn<int>("flow");
+ QTest::addColumn<bool>("wrapping");
+ QTest::addColumn<int>("spacing");
+ QTest::addColumn<QSize>("gridSize");
+ QTest::addColumn<IntList>("hiddenRows");
+ QTest::addColumn<QRect>("selectionRect");
+ QTest::addColumn<IntList>("expectedItems");
+
+ QTest::newRow("select all")
+ << 4 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << false // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(0, 0, 10, 200) // selection rectangle
+ << (IntList() << 0 << 1 << 2 << 3); // expected items
+
+ QTest::newRow("select below, (on viewport)")
+ << 4 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << false // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(10, 250, 1, 1) // selection rectangle
+ << IntList(); // expected items
+
+ QTest::newRow("select below 2, (on viewport)")
+ << 4 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(10, 250, 1, 1) // selection rectangle
+ << IntList(); // expected items
+
+ QTest::newRow("select to the right, (on viewport)")
+ << 40 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(300, 10, 1, 1) // selection rectangle
+ << IntList(); // expected items
+
+ QTest::newRow("select to the right, (on viewport)")
+ << 40 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(300, 0, 1, 300) // selection rectangle
+ << IntList(); // expected items
+
+#if defined(Q_OS_WINCE)
+ // depending on whether the display is double-pixeld, we need
+ // to click at a different position
+ bool doubledSize = false;
+ int dpi = GetDeviceCaps(GetDC(0), LOGPIXELSX);
+ if ((dpi < 1000) && (dpi > 0)) {
+ doubledSize = true;
+ }
+ QTest::newRow("select inside contents, (on viewport)")
+ << 35 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(doubledSize?350:175,doubledSize?550:275, 1, 1)// selection rectangle
+ << IntList(); // expected items
+#else
+ QTest::newRow("select inside contents, (on viewport)")
+ << 35 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(175, 275, 1, 1) // selection rectangle
+ << IntList(); // expected items
+#endif
+
+ QTest::newRow("select a tall rect in LeftToRight flow, wrap items")
+ << 70 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::LeftToRight)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(90, 90, 1, 100) // selection rectangle
+ << (IntList() // expected items
+ << 11 << 12 << 13 << 14 << 15 << 16 << 17 << 18 << 19
+ << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 << 28 << 29
+ << 30 << 31);
+
+ QTest::newRow("select a wide rect in LeftToRight, wrap items")
+ << 70 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::LeftToRight)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(90, 90, 200, 1) // selection rectangle
+ << (IntList() // expected items
+ << 11 << 12 << 13 << 14 << 15);
+
+ QTest::newRow("select a wide negative rect in LeftToRight flow, wrap items")
+ << 70 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::LeftToRight)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(290, 90, -200, 1) // selection rectangle
+ << (IntList() // expected items
+ << 11 << 12 << 13 << 14 << 15);
+
+ QTest::newRow("select a tall rect in TopToBottom flow, wrap items")
+ << 70 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(90, 90, 1, 100) // selection rectangle
+ << (IntList() // expected items
+ << 11
+ << 12
+ << 13);
+
+ QTest::newRow("select a tall negative rect in TopToBottom flow, wrap items")
+ << 70 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(90, 190, 1, -100) // selection rectangle
+ << (IntList() // expected items
+ << 11
+ << 12
+ << 13);
+
+ QTest::newRow("select a wide rect in TopToBottom, wrap items")
+ << 70 // itemCount
+ << int(QListView::ListMode)
+ << int(QListView::TopToBottom)
+ << true // wrapping
+ << 0 // spacing
+ << QSize() // gridSize
+ << IntList() // hiddenRows
+ << QRect(90, 90, 100, 1) // selection rectangle
+ << (IntList() // expected items
+ << 20 << 30
+ << 11 << 21 << 31
+ << 12 << 22
+ << 13 << 23
+ << 14 << 24
+ << 15 << 25
+ << 16 << 26
+ << 17 << 27
+ << 18 << 28
+ << 19 << 29);
+}
+
+void tst_QListView::selection()
+{
+ QFETCH(int, itemCount);
+ QFETCH(int, viewMode);
+ QFETCH(int, flow);
+ QFETCH(bool, wrapping);
+ QFETCH(int, spacing);
+ QFETCH(QSize, gridSize);
+ QFETCH(IntList, hiddenRows);
+ QFETCH(QRect, selectionRect);
+ QFETCH(IntList, expectedItems);
+
+ QWidget topLevel;
+ PublicListView v(&topLevel);
+ QtTestModel model;
+ model.colCount = 1;
+ model.rCount = itemCount;
+
+ // avoid scrollbar size mismatches among different styles
+ v.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ v.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ v.setItemDelegate(new TestDelegate(&v));
+ v.setModel(&model);
+ v.setViewMode(QListView::ViewMode(viewMode));
+ v.setFlow(QListView::Flow(flow));
+ v.setWrapping(wrapping);
+ v.setResizeMode(QListView::Adjust);
+ v.setSpacing(spacing);
+ if (gridSize.isValid())
+ v.setGridSize(gridSize);
+ for (int j = 0; j < hiddenRows.count(); ++j) {
+ v.setRowHidden(hiddenRows.at(j), true);
+ }
+
+#if defined(Q_OS_WINCE)
+ // If the device is double-pixeled then the scrollbars become
+ // 10 pixels wider than normal (Windows Style: 16, Windows Mobile Style: 26).
+ // So we have to make the window slightly bigger to have the same count of
+ // items in each row of the list view like in the other styles.
+ static const int dpi = ::GetDeviceCaps(GetDC(0), LOGPIXELSX);
+ if ((dpi < 1000) && (dpi > 0))
+ v.resize(535,535);
+#else
+ v.resize(525,525);
+#endif
+
+ topLevel.show();
+ QTest::qWaitForWindowShown(&v);
+ QApplication::processEvents();
+
+ v.setSelection(selectionRect, QItemSelectionModel::ClearAndSelect);
+
+ QModelIndexList selected = v.selectionModel()->selectedIndexes();
+
+ QCOMPARE(selected.count(), expectedItems.count());
+ for (int i = 0; i < selected.count(); ++i) {
+ QVERIFY(expectedItems.contains(selected.at(i).row()));
+ }
+}
+
+void tst_QListView::scrollTo()
+{
+ QWidget topLevel;
+ QListView lv(&topLevel);
+ QStringListModel model(&lv);
+ QStringList list;
+ list << "Short item 1";
+ list << "Short item 2";
+ list << "Short item 3";
+ list << "Short item 4";
+ list << "Short item 5";
+ list << "Short item 6";
+ list << "Begin This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\n"
+ "This is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item\nThis is a very long item End\n";
+ list << "Short item";
+ list << "Short item";
+ list << "Short item";
+ list << "Short item";
+ list << "Short item";
+ list << "Short item";
+ list << "Short item";
+ list << "Short item";
+ model.setStringList(list);
+ lv.setModel(&model);
+ lv.setFixedSize(100, 200);
+ topLevel.show();
+ QTest::qWaitForWindowShown(&topLevel);
+
+ //by default, the list view scrolls per item and has no wrapping
+ QModelIndex index = model.index(6,0);
+
+ //we save the size of the item for later comparisons
+ const QSize itemsize = lv.visualRect(index).size();
+ QVERIFY(itemsize.height() > lv.height());
+ QVERIFY(itemsize.width() > lv.width());
+
+ //we click the item
+ QPoint p = lv.visualRect(index).center();
+ QTest::mouseClick(lv.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ //let's wait because the scrolling is delayed
+ QTest::qWait(QApplication::doubleClickInterval() + 150);
+ QTRY_COMPARE(lv.visualRect(index).y(),0);
+
+ //we scroll down. As the item is to tall for the view, it will disappear
+ QTest::keyClick(lv.viewport(), Qt::Key_Down, Qt::NoModifier);
+ QCOMPARE(lv.visualRect(index).y(), -itemsize.height());
+
+ QTest::keyClick(lv.viewport(), Qt::Key_Up, Qt::NoModifier);
+ QCOMPARE(lv.visualRect(index).y(), 0);
+
+ //Let's enable wrapping
+
+ lv.setWrapping(true);
+ lv.horizontalScrollBar()->setValue(0); //let's scroll to the beginning
+
+ //we click the item
+ p = lv.visualRect(index).center();
+ QTest::mouseClick(lv.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ //let's wait because the scrolling is delayed
+ QTest::qWait(QApplication::doubleClickInterval() + 150);
+ QTRY_COMPARE(lv.visualRect(index).x(),0);
+
+ //we scroll right. As the item is too wide for the view, it will disappear
+ QTest::keyClick(lv.viewport(), Qt::Key_Right, Qt::NoModifier);
+ QCOMPARE(lv.visualRect(index).x(), -itemsize.width());
+
+ QTest::keyClick(lv.viewport(), Qt::Key_Left, Qt::NoModifier);
+ QCOMPARE(lv.visualRect(index).x(), 0);
+
+ lv.setWrapping(false);
+ qApp->processEvents(); //let the layout happen
+
+ //Let's try with scrolling per pixel
+ lv.setHorizontalScrollMode( QListView::ScrollPerPixel);
+ lv.verticalScrollBar()->setValue(0); //scrolls back to the first item
+
+ //we click the item
+ p = lv.visualRect(index).center();
+ QTest::mouseClick(lv.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ //let's wait because the scrolling is delayed
+ QTest::qWait(QApplication::doubleClickInterval() + 150);
+ QTRY_COMPARE(lv.visualRect(index).y(),0);
+
+ //we scroll down. As the item is too tall for the view, it will partially disappear
+ QTest::keyClick(lv.viewport(), Qt::Key_Down, Qt::NoModifier);
+ QVERIFY(lv.visualRect(index).y()<0);
+
+ QTest::keyClick(lv.viewport(), Qt::Key_Up, Qt::NoModifier);
+ QCOMPARE(lv.visualRect(index).y(), 0);
+}
+
+
+void tst_QListView::scrollBarRanges()
+{
+ const int rowCount = 10;
+ const int rowHeight = 20;
+
+ QWidget topLevel;
+ QListView lv(&topLevel);
+ QStringListModel model(&lv);
+ QStringList list;
+ for (int i = 0; i < rowCount; ++i)
+ list << QString::fromAscii("Item %1").arg(i);
+
+ model.setStringList(list);
+ lv.setModel(&model);
+ lv.resize(250, 130);
+ TestDelegate *delegate = new TestDelegate(&lv);
+ delegate->m_sizeHint = QSize(100, rowHeight);
+ lv.setItemDelegate(delegate);
+ topLevel.show();
+
+ for (int h = 30; h <= 210; ++h) {
+ lv.resize(250, h);
+ QApplication::processEvents(); // wait for the layout to be done
+ int visibleRowCount = lv.viewport()->size().height() / rowHeight;
+ int invisibleRowCount = rowCount - visibleRowCount;
+ QCOMPARE(lv.verticalScrollBar()->maximum(), invisibleRowCount);
+ }
+}
+
+void tst_QListView::scrollBarAsNeeded_data()
+{
+ QTest::addColumn<QSize>("size");
+ QTest::addColumn<int>("itemCount");
+ QTest::addColumn<int>("flow");
+ QTest::addColumn<bool>("horizontalScrollBarVisible");
+ QTest::addColumn<bool>("verticalScrollBarVisible");
+
+
+ QTest::newRow("TopToBottom, count:0")
+ << QSize(200, 100)
+ << 0
+ << int(QListView::TopToBottom)
+ << false
+ << false;
+
+ QTest::newRow("TopToBottom, count:1")
+ << QSize(200, 100)
+ << 1
+ << int(QListView::TopToBottom)
+ << false
+ << false;
+
+ QTest::newRow("TopToBottom, count:20")
+ << QSize(200, 100)
+ << 20
+ << int(QListView::TopToBottom)
+ << false
+ << true;
+
+ QTest::newRow("LeftToRight, count:0")
+ << QSize(200, 100)
+ << 0
+ << int(QListView::LeftToRight)
+ << false
+ << false;
+
+ QTest::newRow("LeftToRight, count:1")
+ << QSize(200, 100)
+ << 1
+ << int(QListView::LeftToRight)
+ << false
+ << false;
+
+ QTest::newRow("LeftToRight, count:20")
+ << QSize(200, 100)
+ << 20
+ << int(QListView::LeftToRight)
+ << true
+ << false;
+
+
+}
+void tst_QListView::scrollBarAsNeeded()
+{
+
+ QFETCH(QSize, size);
+ QFETCH(int, itemCount);
+ QFETCH(int, flow);
+ QFETCH(bool, horizontalScrollBarVisible);
+ QFETCH(bool, verticalScrollBarVisible);
+
+
+ const int rowCounts[3] = {0, 1, 20};
+
+ QWidget topLevel;
+ QListView lv(&topLevel);
+ lv.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ lv.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ lv.setFlow((QListView::Flow)flow);
+ QStringListModel model(&lv);
+ lv.setModel(&model);
+ lv.resize(size);
+ topLevel.show();
+
+ for (uint r = 0; r < sizeof(rowCounts)/sizeof(int); ++r) {
+ QStringList list;
+ int i;
+ for (i = 0; i < rowCounts[r]; ++i)
+ list << QString::fromAscii("Item %1").arg(i);
+
+ model.setStringList(list);
+ QApplication::processEvents();
+ QTest::qWait(50);
+
+ QStringList replacement;
+ for (i = 0; i < itemCount; ++i) {
+ replacement << QString::fromAscii("Item %1").arg(i);
+ }
+ model.setStringList(replacement);
+
+ QApplication::processEvents();
+
+ QTRY_COMPARE(lv.horizontalScrollBar()->isVisible(), horizontalScrollBarVisible);
+ QTRY_COMPARE(lv.verticalScrollBar()->isVisible(), verticalScrollBarVisible);
+ }
+}
+
+void tst_QListView::moveItems()
+{
+ QStandardItemModel model;
+ for (int r = 0; r < 4; ++r) {
+ for (int c = 0; c < 4; ++c) {
+ QStandardItem* item = new QStandardItem(QString("standard item (%1,%2)").arg(r).arg(c));
+ model.setItem(r, c, item);
+ }
+ }
+
+ PublicListView view;
+ view.setViewMode(QListView::IconMode);
+ view.setResizeMode(QListView::Fixed);
+ view.setWordWrap(true);
+ view.setModel(&model);
+ view.setItemDelegate(new TestDelegate(&view));
+
+ for (int r = 0; r < model.rowCount(); ++r) {
+ for (int c = 0; c < model.columnCount(); ++c) {
+ const QModelIndex& idx = model.index(r, c);
+ view.setPositionForIndex(QPoint(r * 75, r * 75), idx);
+ }
+ }
+
+ QCOMPARE(view.contentsSize(), QSize(275, 275));
+}
+
+void tst_QListView::wordWrap()
+{
+ QListView lv;
+ lv.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ lv.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ QStringListModel model(&lv);
+ QStringList list;
+ list << "Short item 1";
+ list << "Short item 2";
+ list << "Short item 3";
+ list << "Begin\nThis item take severals Lines\nEnd";
+ list << "And this is a very long item very long item this is a very vary vary long item"
+ "very long very very long long long this is a long item a very long item a very very long item";
+ list << "And this is a second even a little more long very long item very long item this is a very vary vary long item"
+ "very long very very long long long this is a long item a very long item a very very long item";
+ list << "Short item";
+ list << "rzeofig zerig fslfgj smdlfkgj qmsdlfj amrzriougf qsla zrg fgsdf gsdfg sdfgs dfg sdfgcvb sdfg qsdjfh qsdfjklh qs";
+ list << "Short item";
+ model.setStringList(list);
+ lv.setModel(&model);
+ lv.setWordWrap(true);
+ lv.setFixedSize(150, 150);
+ lv.show();
+ QApplication::processEvents();
+
+ QTRY_COMPARE(lv.horizontalScrollBar()->isVisible(), false);
+ QTRY_COMPARE(lv.verticalScrollBar()->isVisible(), true);
+}
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+class SetCurrentIndexAfterAppendRowCrashDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ SetCurrentIndexAfterAppendRowCrashDialog()
+ {
+#if WINVER >= 0x0500
+ listView = new QListView();
+ listView->setViewMode(QListView::IconMode);
+
+ model = new QStandardItemModel(this);
+ listView->setModel(model);
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(buttonClicked()));
+ timer->start(1000);
+
+ DWORD lParam = 0xFFFFFFFC/*OBJID_CLIENT*/;
+ DWORD wParam = 0;
+ if (const HWND hwnd =getHWNDForWidget(this))
+ SendMessage(hwnd, WM_GETOBJECT, wParam, lParam);
+#endif
+ }
+
+private slots:
+ void buttonClicked()
+ {
+ timer->stop();
+ QStandardItem *item = new QStandardItem("test");
+ model->appendRow(item);
+ listView->setCurrentIndex(model->indexFromItem(item));
+ close();
+ }
+private:
+ QListView *listView;
+ QStandardItemModel *model;
+ QTimer *timer;
+};
+#endif
+
+// This test only makes sense on Windows 2000 and higher.
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && WINVER >= 0x0500
+void tst_QListView::setCurrentIndexAfterAppendRowCrash()
+{
+ SetCurrentIndexAfterAppendRowCrashDialog w;
+ w.exec();
+}
+#endif
+
+void tst_QListView::emptyItemSize()
+{
+ QStandardItemModel model;
+ for (int r = 0; r < 4; ++r) {
+ QStandardItem* item = new QStandardItem(QString("standard item (%1)").arg(r));
+ model.setItem(r, 0, item);
+ }
+ model.setItem(4, 0, new QStandardItem());
+
+ PublicListView view;
+ view.setModel(&model);
+
+ for (int i = 0; i < 5; ++i)
+ QVERIFY(!view.visualRect(model.index(i, 0)).isEmpty());
+}
+
+void tst_QListView::task203585_selectAll()
+{
+ //we make sure that "select all" doesn't select the hidden items
+ QListView view;
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view.setModel(new QStringListModel( QStringList() << "foo"));
+ view.setRowHidden(0, true);
+ view.selectAll();
+ QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
+ view.setRowHidden(0, false);
+ view.selectAll();
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
+}
+
+void tst_QListView::task228566_infiniteRelayout()
+{
+ QListView view;
+
+ QStringList list;
+ for (int i = 0; i < 10; ++i) {
+ list << "small";
+ }
+
+ list << "BIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIG";
+ list << "BIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIGBIG";
+
+ QStringListModel model(list);
+ view.setModel(&model);
+ view.setWrapping(true);
+ view.setResizeMode(QListView::Adjust);
+
+ const int itemHeight = view.visualRect( model.index(0, 0)).height();
+
+ view.setFixedHeight(itemHeight * 12);
+ view.show();
+ QTest::qWait(100); //make sure the layout is done once
+
+ QSignalSpy spy(view.horizontalScrollBar(), SIGNAL(rangeChanged(int, int)));
+
+ QTest::qWait(200);
+ //the layout should already have been done
+ //so there should be no change made to the scrollbar
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QListView::task248430_crashWith0SizedItem()
+{
+ QListView view;
+ view.setViewMode(QListView::IconMode);
+ QStringListModel model(QStringList() << QLatin1String("item1") << QString());
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTest::qWait(20);
+}
+
+void tst_QListView::task250446_scrollChanged()
+{
+ QStandardItemModel model(200, 1);
+ QListView view;
+ view.setModel(&model);
+ QModelIndex index = model.index(0, 0);
+ QVERIFY(index.isValid());
+ view.setCurrentIndex(index);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ const int scrollValue = view.verticalScrollBar()->maximum();
+ view.verticalScrollBar()->setValue(scrollValue);
+ QCOMPARE(view.verticalScrollBar()->value(), scrollValue);
+ QCOMPARE(view.currentIndex(), index);
+
+ view.showMinimized();
+ QTest::qWait(50);
+ QTRY_COMPARE(view.verticalScrollBar()->value(), scrollValue);
+ QTRY_COMPARE(view.currentIndex(), index);
+
+ view.showNormal();
+ QTest::qWait(50);
+ QTRY_COMPARE(view.verticalScrollBar()->value(), scrollValue);
+ QTRY_COMPARE(view.currentIndex(), index);
+}
+
+void tst_QListView::task196118_visualRegionForSelection()
+{
+ class MyListView : public QListView
+ {
+ public:
+ QRegion visualRegionForSelection() const
+ { return QListView::visualRegionForSelection( selectionModel()->selection()); }
+ } view;
+
+ QStandardItemModel model;
+ QStandardItem top1("top1");
+ QStandardItem sub1("sub1");
+ top1.appendRow(QList<QStandardItem*>() << &sub1);
+ model.appendColumn(QList<QStandardItem*>() << &top1);
+ view.setModel(&model);
+ view.setRootIndex(top1.index());
+
+ view.selectionModel()->select(top1.index(), QItemSelectionModel::Select);
+
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
+ QVERIFY(view.visualRegionForSelection().isEmpty());
+}
+
+void tst_QListView::task254449_draggingItemToNegativeCoordinates()
+{
+ //we'll check that the items are painted correctly
+ class MyListView : public QListView
+ {
+ public:
+ void setPositionForIndex(const QPoint &position, const QModelIndex &index)
+ { QListView::setPositionForIndex(position, index); }
+
+ } list;
+
+ QStandardItemModel model(1,1);
+ QModelIndex index = model.index(0,0);
+ model.setData(index, QLatin1String("foo"));
+ list.setModel(&model);
+ list.setViewMode(QListView::IconMode);
+ list.show();
+ QTest::qWaitForWindowShown(&list);
+ list.activateWindow();
+
+ class MyItemDelegate : public QStyledItemDelegate
+ {
+ public:
+ MyItemDelegate() : numPaints(0) { }
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ numPaints++;
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+
+ mutable int numPaints;
+ } delegate;
+ delegate.numPaints = 0;
+ list.setItemDelegate(&delegate);
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.numPaints > 0); //makes sure the layout is done
+
+ const QPoint topLeft(-6, 0);
+ list.setPositionForIndex(topLeft, index);
+
+ //we'll make sure the item is repainted
+ delegate.numPaints = 0;
+ QApplication::processEvents();
+ QTRY_COMPARE(delegate.numPaints, 1);
+ QCOMPARE(list.visualRect(index).topLeft(), topLeft);
+}
+
+
+void tst_QListView::keyboardSearch()
+{
+ QStringList items;
+ items << "AB" << "AC" << "BA" << "BB" << "BD" << "KAFEINE" << "KONQUEROR" << "KOPETE" << "KOOKA" << "OKULAR";
+ QStringListModel model(items);
+
+ QListView view;
+ view.setModel(&model);
+ view.show();
+ QTest::qWait(30);
+// QCOMPARE(view.currentIndex() , model.index(0,0));
+
+ QTest::keyClick(&view, Qt::Key_K);
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex() , model.index(5,0)); //KAFEINE
+
+ QTest::keyClick(&view, Qt::Key_O);
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex() , model.index(6,0)); //KONQUEROR
+
+ QTest::keyClick(&view, Qt::Key_N);
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex() , model.index(6,0)); //KONQUEROR
+}
+
+void tst_QListView::shiftSelectionWithNonUniformItemSizes()
+{
+ // This checks that no items are selected unexpectedly by Shift-Arrow
+ // when items with non-uniform sizes are laid out in a grid
+ { // First test: QListView::LeftToRight flow
+ QStringList items;
+ items << "Long\nText" << "Text" << "Text" << "Text";
+ QStringListModel model(items);
+
+ QListView view;
+ view.setFixedSize(250, 250);
+ view.setFlow(QListView::LeftToRight);
+ view.setGridSize(QSize(100, 100));
+ view.setSelectionMode(QListView::ExtendedSelection);
+ view.setViewMode(QListView::IconMode);
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ // Verfify that item sizes are non-uniform
+ QVERIFY(view.sizeHintForIndex(model.index(0, 0)).height() > view.sizeHintForIndex(model.index(1, 0)).height());
+
+ QModelIndex index = model.index(3, 0);
+ view.setCurrentIndex(index);
+ QCOMPARE(view.currentIndex(), index);
+
+ QTest::keyClick(&view, Qt::Key_Up, Qt::ShiftModifier);
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex(), model.index(1, 0));
+
+ QModelIndexList selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 3);
+ QVERIFY(!selected.contains(model.index(0, 0)));
+ }
+ { // Second test: QListView::TopToBottom flow
+ QStringList items;
+ items << "ab" << "a" << "a" << "a";
+ QStringListModel model(items);
+
+ QListView view;
+ view.setFixedSize(250, 250);
+ view.setFlow(QListView::TopToBottom);
+ view.setGridSize(QSize(100, 100));
+ view.setSelectionMode(QListView::ExtendedSelection);
+ view.setViewMode(QListView::IconMode);
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ // Verfify that item sizes are non-uniform
+ QVERIFY(view.sizeHintForIndex(model.index(0, 0)).width() > view.sizeHintForIndex(model.index(1, 0)).width());
+
+ QModelIndex index = model.index(3, 0);
+ view.setCurrentIndex(index);
+ QCOMPARE(view.currentIndex(), index);
+
+ QTest::keyClick(&view, Qt::Key_Left, Qt::ShiftModifier);
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex(), model.index(1, 0));
+
+ QModelIndexList selected = view.selectionModel()->selectedIndexes();
+ QCOMPARE(selected.count(), 3);
+ QVERIFY(!selected.contains(model.index(0, 0)));
+ }
+}
+
+void tst_QListView::clickOnViewportClearsSelection()
+{
+ QStringList items;
+ items << "Text1";
+ QStringListModel model(items);
+ QListView view;
+ view.setModel(&model);
+ view.setSelectionMode(QListView::ExtendedSelection);
+
+ view.selectAll();
+ QModelIndex index = model.index(0);
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
+ QVERIFY(view.selectionModel()->isSelected(index));
+
+ //we try to click outside of the index
+ const QPoint point = view.visualRect(index).bottomRight() + QPoint(10,10);
+
+ QTest::mousePress(view.viewport(), Qt::LeftButton, 0, point);
+ //at this point, the selection shouldn't have changed
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), 1);
+ QVERIFY(view.selectionModel()->isSelected(index));
+
+ QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, point);
+ //now the selection should be cleared
+ QVERIFY(!view.selectionModel()->hasSelection());
+}
+
+void tst_QListView::task262152_setModelColumnNavigate()
+{
+ QListView view;
+ QStandardItemModel model(3,2);
+ model.setItem(0,1,new QStandardItem("[0,1]"));
+ model.setItem(1,1,new QStandardItem("[1,1]"));
+ model.setItem(2,1,new QStandardItem("[2,1]"));
+
+ view.setModel(&model);
+ view.setModelColumn(1);
+
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_COMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
+ QTest::keyClick(&view, Qt::Key_Down);
+ QTest::qWait(30);
+ QTRY_COMPARE(view.currentIndex(), model.index(1,1));
+ QTest::keyClick(&view, Qt::Key_Down);
+ QTest::qWait(30);
+ QTRY_COMPARE(view.currentIndex(), model.index(2,1));
+}
+
+void tst_QListView::taskQTBUG_2233_scrollHiddenItems_data()
+{
+ QTest::addColumn<int>("flow");
+
+ QTest::newRow("TopToBottom") << static_cast<int>(QListView::TopToBottom);
+ QTest::newRow("LeftToRight") << static_cast<int>(QListView::LeftToRight);
+}
+
+void tst_QListView::taskQTBUG_2233_scrollHiddenItems()
+{
+ QFETCH(int, flow);
+ const int rowCount = 200;
+
+ QWidget topLevel;
+ QListView view(&topLevel);
+ QStringListModel model(&view);
+ QStringList list;
+ for (int i = 0; i < rowCount; ++i)
+ list << QString::fromAscii("Item %1").arg(i);
+
+ model.setStringList(list);
+ view.setModel(&model);
+ view.setViewMode(QListView::ListMode);
+ for (int i = 0; i < rowCount / 2; ++i)
+ view.setRowHidden(2 * i, true);
+ view.setFlow(static_cast<QListView::Flow>(flow));
+ view.resize(130, 130);
+
+ for (int i = 0; i < 10; ++i) {
+ (view.flow() == QListView::TopToBottom
+ ? view.verticalScrollBar()
+ : view.horizontalScrollBar())->setValue(i);
+ QModelIndex index = view.indexAt(QPoint(0,0));
+ QVERIFY(index.isValid());
+ QCOMPARE(index.row(), 2 * i + 1);
+ }
+
+ //QTBUG-7929 should not crash
+ topLevel.show();
+ QTest::qWaitForWindowShown(&topLevel);
+ QScrollBar *bar = view.flow() == QListView::TopToBottom
+ ? view.verticalScrollBar() : view.horizontalScrollBar();
+
+ int nbVisibleItem = rowCount / 2 - bar->maximum();
+
+ bar->setValue(bar->maximum());
+ QApplication::processEvents();
+ for (int i = rowCount; i > rowCount / 2; i--) {
+ view.setRowHidden(i, true);
+ }
+ QApplication::processEvents();
+ QTest::qWait(50);
+ QCOMPARE(bar->value(), bar->maximum());
+ QCOMPARE(bar->maximum(), rowCount/4 - nbVisibleItem);
+}
+
+void tst_QListView::taskQTBUG_633_changeModelData()
+{
+ QListView view;
+ view.setFlow(QListView::LeftToRight);
+ QStandardItemModel model(5,1);
+ for (int i = 0; i < model.rowCount(); ++i) {
+ model.setData( model.index(i, 0), QString::number(i));
+ }
+
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ model.setData( model.index(1, 0), QLatin1String("long long text"));
+ QTest::qWait(100); //leave time for relayouting the items
+ QRect rectLongText = view.visualRect(model.index(1,0));
+ QRect rect2 = view.visualRect(model.index(2,0));
+ QVERIFY( ! rectLongText.intersects(rect2) );
+}
+
+void tst_QListView::taskQTBUG_435_deselectOnViewportClick()
+{
+ QListView view;
+ QStringListModel model( QStringList() << "1" << "2" << "3" << "4");
+ view.setModel(&model);
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view.selectAll();
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), model.rowCount());
+
+
+ const QRect itemRect = view.visualRect(model.index(model.rowCount() - 1));
+ QPoint p = view.visualRect(model.index(model.rowCount() - 1)).center() + QPoint(0, itemRect.height());
+ //first the left button
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
+ QVERIFY(!view.selectionModel()->hasSelection());
+
+ view.selectAll();
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), model.rowCount());
+
+ //and now the right button
+ QTest::mouseClick(view.viewport(), Qt::RightButton, 0, p);
+ QVERIFY(!view.selectionModel()->hasSelection());
+}
+
+void tst_QListView::taskQTBUG_2678_spacingAndWrappedText()
+{
+ static const QString lorem("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
+ QStringListModel model(QStringList() << lorem << lorem << "foo" << lorem << "bar" << lorem << lorem);
+ QListView w;
+ w.setModel(&model);
+ w.setViewMode(QListView::ListMode);
+ w.setWordWrap(true);
+ w.setSpacing(10);
+ w.show();
+ QTest::qWaitForWindowShown(&w);
+ QCOMPARE(w.horizontalScrollBar()->minimum(), w.horizontalScrollBar()->maximum());
+}
+
+void tst_QListView::taskQTBUG_5877_skippingItemInPageDownUp()
+{
+ QList<int> currentItemIndexes;
+ QtTestModel model(0);
+ model.colCount = 1;
+ model.rCount = 100;
+
+ currentItemIndexes << 0 << 6 << 16 << 25 << 34 << 42 << 57 << 68 << 77
+ << 83 << 91 << 94;
+ QMoveCursorListView vu;
+ vu.setModel(&model);
+ vu.show();
+
+ QTest::qWaitForWindowShown(&vu);
+
+ int itemHeight = vu.visualRect(model.index(0, 0)).height();
+ int visibleRowCount = vu.viewport()->height() / itemHeight;
+ int scrolledRowCount = visibleRowCount - 1;
+
+ for (int i = 0; i < currentItemIndexes.size(); ++i) {
+ vu.selectionModel()->setCurrentIndex(model.index(currentItemIndexes[i], 0),
+ QItemSelectionModel::SelectCurrent);
+
+ QModelIndex idx = vu.moveCursor(QMoveCursorListView::MovePageDown, Qt::NoModifier);
+ int newCurrent = qMin(currentItemIndexes[i] + scrolledRowCount, 99);
+ QCOMPARE(idx, model.index(newCurrent, 0));
+
+ idx = vu.moveCursor(QMoveCursorListView::MovePageUp, Qt::NoModifier);
+ newCurrent = qMax(currentItemIndexes[i] - scrolledRowCount, 0);
+ QCOMPARE(idx, model.index(newCurrent, 0));
+ }
+}
+
+class ListView_9455 : public QListView
+{
+public:
+ QSize contentsSize() const
+ {
+ return QListView::contentsSize();
+ }
+};
+
+void tst_QListView::taskQTBUG_9455_wrongScrollbarRanges()
+{
+ QStringList list;
+ const int nrItems = 8;
+ for (int i = 0; i < nrItems; i++)
+ list << QString().sprintf("item %d", i);
+
+ QStringListModel model(list);
+ ListView_9455 w;
+ w.setModel(&model);
+ w.setViewMode(QListView::IconMode);
+ w.resize(116, 132);
+ w.setMovement(QListView::Static);
+ const int spacing = 40;
+ w.setSpacing(spacing);
+ w.show();
+ QTest::qWaitForWindowShown(&w);
+ QCOMPARE(w.verticalScrollBar()->maximum(), w.contentsSize().height() - w.viewport()->geometry().height());
+}
+
+void tst_QListView::styleOptionViewItem()
+{
+ class MyDelegate : public QStyledItemDelegate
+ {
+ public:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ QVERIFY(qstyleoption_cast<const QStyleOptionViewItemV4 *>(&option));
+ QStyleOptionViewItemV4 opt(option);
+ initStyleOption(&opt, index);
+
+ QCOMPARE(opt.index, index);
+
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+ };
+
+ QListView view;
+ QStandardItemModel model;
+ view.setModel(&model);
+ MyDelegate delegate;
+ view.setItemDelegate(&delegate);
+ model.appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Beginning") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
+
+ // Run test
+ view.showMaximized();
+ QApplication::processEvents();
+}
+
+void tst_QListView::taskQTBUG_12308_artihmeticException()
+{
+ QListWidget lw;
+ lw.setLayoutMode(QListView::Batched);
+ lw.setViewMode(QListView::IconMode);
+ for (int i = 0; i < lw.batchSize() + 1; i++) {
+ QListWidgetItem *item = new QListWidgetItem();
+ item->setText(QString("Item %L1").arg(i));
+ lw.addItem(item);
+ item->setHidden(true);
+ }
+ lw.show();
+ QTest::qWaitForWindowShown(&lw);
+ // No crash, it's all right.
+}
+
+class Delegate12308 : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ Delegate12308(QObject *parent = 0) : QStyledItemDelegate(parent)
+ { }
+
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ QVERIFY(option.rect.topLeft() != QPoint(-1, -1));
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+};
+
+void tst_QListView::taskQTBUG_12308_wrongFlowLayout()
+{
+ QListWidget lw;
+ Delegate12308 delegate;
+ lw.setLayoutMode(QListView::Batched);
+ lw.setViewMode(QListView::IconMode);
+ lw.setItemDelegate(&delegate);
+ for (int i = 0; i < lw.batchSize() + 1; i++) {
+ QListWidgetItem *item = new QListWidgetItem();
+ item->setText(QString("Item %L1").arg(i));
+ lw.addItem(item);
+ if (!item->text().contains(QString::fromAscii("1")))
+ item->setHidden(true);
+ }
+ lw.show();
+ QTest::qWaitForWindowShown(&lw);
+}
+
+QTEST_MAIN(tst_QListView)
+#include "tst_qlistview.moc"
diff --git a/tests/auto/widgets/itemviews/qlistwidget/.gitignore b/tests/auto/widgets/itemviews/qlistwidget/.gitignore
new file mode 100644
index 0000000000..085486b2de
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qlistwidget/.gitignore
@@ -0,0 +1 @@
+tst_qlistwidget
diff --git a/tests/auto/widgets/itemviews/qlistwidget/qlistwidget.pro b/tests/auto/widgets/itemviews/qlistwidget/qlistwidget.pro
new file mode 100644
index 0000000000..7343415e4c
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qlistwidget/qlistwidget.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+QT += widgets widgets-private
+QT += core-private gui-private
+SOURCES += tst_qlistwidget.cpp
+
+qpa:contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21098, fails unstably
diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
new file mode 100644
index 0000000000..9ede38f553
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
@@ -0,0 +1,1685 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+#include <qeventloop.h>
+#include <qlist.h>
+
+#include <qlistwidget.h>
+#include <private/qlistwidget_p.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QListWidget : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QListWidget();
+ ~tst_QListWidget();
+
+ enum ModelChanged {
+ RowsAboutToBeInserted,
+ RowsInserted,
+ RowsAboutToBeRemoved,
+ RowsRemoved,
+ ColumnsAboutToBeInserted,
+ ColumnsInserted,
+ ColumnsAboutToBeRemoved,
+ ColumnsRemoved
+ };
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void addItem();
+ void addItem2();
+ void addItems();
+ void openPersistentEditor();
+ void closePersistentEditor();
+ void count();
+ void currentItem();
+ void setCurrentItem_data();
+ void setCurrentItem();
+ void currentRow();
+ void setCurrentRow_data();
+ void setCurrentRow();
+ void editItem_data();
+ void editItem();
+ void findItems();
+ void insertItem_data();
+ void insertItem();
+ void insertItems_data();
+ void insertItems();
+ void moveItemsPriv_data();
+ void moveItemsPriv();
+
+ void itemAssignment();
+ void item_data();
+ void item();
+ void takeItem_data();
+ void takeItem();
+ void setItemHidden();
+ void selectedItems_data();
+ void selectedItems();
+ void removeItems_data();
+ void removeItems();
+ void itemStreaming_data();
+ void itemStreaming();
+ void sortItems_data();
+ void sortItems();
+ void sortHiddenItems();
+ void sortHiddenItems_data();
+ void closeEditor();
+ void setData_data();
+ void setData();
+ void insertItemsWithSorting_data();
+ void insertItemsWithSorting();
+ void changeDataWithSorting_data();
+ void changeDataWithSorting();
+ void itemData();
+ void itemWidget();
+#ifndef Q_WS_MAC
+ void fastScroll();
+#endif
+ void insertUnchanged();
+ void setSortingEnabled();
+ void task199503_crashWhenCleared();
+ void task217070_scrollbarsAdjusted();
+ void task258949_keypressHangup();
+ void QTBUG8086_currentItemChangedOnClick();
+ void QTBUG14363_completerWithAnyKeyPressedEditTriggers();
+
+
+protected slots:
+ void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsAboutToBeInserted, parent, first, last); }
+ void rowsInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsInserted, parent, first, last); }
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsAboutToBeRemoved, parent, first, last); }
+ void rowsRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsRemoved, parent, first, last); }
+ void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsAboutToBeInserted, parent, first, last); }
+ void columnsInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsInserted, parent, first, last); }
+ void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsAboutToBeRemoved, parent, first, last); }
+ void columnsRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsRemoved, parent, first, last); }
+
+ void modelChanged(ModelChanged change, const QModelIndex &parent, int first, int last);
+
+private:
+ QListWidget *testWidget;
+ QVector<QModelIndex> rcParent;
+ QVector<int> rcFirst;
+ QVector<int> rcLast;
+
+ void populate();
+ void checkDefaultValues();
+};
+
+
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
+Q_DECLARE_METATYPE(QVariantList)
+
+tst_QListWidget::tst_QListWidget(): testWidget(0), rcParent(8), rcFirst(8,0), rcLast(8,0)
+{
+}
+
+tst_QListWidget::~tst_QListWidget()
+{
+}
+
+void tst_QListWidget::initTestCase()
+{
+ testWidget = new QListWidget();
+ testWidget->show();
+
+ connect(testWidget->model(), SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
+ this, SLOT(rowsAboutToBeInserted(QModelIndex, int, int)));
+ connect(testWidget->model(), SIGNAL(rowsInserted(QModelIndex, int, int)),
+ this, SLOT(rowsInserted(QModelIndex, int, int)));
+ connect(testWidget->model(), SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int)));
+ connect(testWidget->model(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsRemoved(QModelIndex, int, int)));
+
+ connect(testWidget->model(), SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)),
+ this, SLOT(columnsAboutToBeInserted(QModelIndex, int, int)));
+ connect(testWidget->model(), SIGNAL(columnsInserted(QModelIndex, int, int)),
+ this, SLOT(columnsInserted(QModelIndex, int, int)));
+ connect(testWidget->model(), SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+ this, SLOT(columnsAboutToBeRemoved(QModelIndex, int, int)));
+ connect(testWidget->model(), SIGNAL(columnsRemoved(QModelIndex, int, int)),
+ this, SLOT(columnsRemoved(QModelIndex, int, int)));
+
+ checkDefaultValues();
+}
+
+void tst_QListWidget::cleanupTestCase()
+{
+ delete testWidget;
+}
+
+void tst_QListWidget::init()
+{
+ testWidget->clear();
+
+ if (testWidget->viewport()->children().count() > 0) {
+ QEventLoop eventLoop;
+ for (int i=0; i < testWidget->viewport()->children().count(); ++i)
+ connect(testWidget->viewport()->children().at(i), SIGNAL(destroyed()), &eventLoop, SLOT(quit()));
+ QTimer::singleShot(100, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+ }
+}
+
+void tst_QListWidget::checkDefaultValues()
+{
+ QCOMPARE(testWidget->currentItem(), (QListWidgetItem *)0);
+ QCOMPARE(testWidget->currentRow(), -1);
+ QCOMPARE(testWidget->count(), 0);
+}
+
+void tst_QListWidget::cleanup()
+{
+}
+
+void tst_QListWidget::populate()
+{
+ addItem();
+ addItem2();
+ addItems();
+ setItemHidden();
+
+ testWidget->setCurrentIndex(testWidget->model()->index(0,0));
+
+ // setCurrentItem();
+ // setCurrentRow();
+}
+
+void tst_QListWidget::addItem()
+{
+ int count = testWidget->count();
+ QString label = QString("%1").arg(count);
+ testWidget->addItem(label);
+ QCOMPARE(testWidget->count(), ++count);
+ QCOMPARE(testWidget->item(testWidget->count()-1)->text(), label);
+}
+
+void tst_QListWidget::addItem2()
+{
+ int count = testWidget->count();
+
+ // Boundary Checking
+ testWidget->addItem(0);
+ QCOMPARE(testWidget->count(), count);
+
+ QListWidgetItem *item = new QListWidgetItem(QString("%1").arg(count));
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ testWidget->addItem(item);
+ QCOMPARE(testWidget->count(), ++count);
+ QCOMPARE(testWidget->item(testWidget->count()-1), item);
+ QCOMPARE(testWidget->isItemHidden(item), false);
+}
+
+void tst_QListWidget::addItems()
+{
+ int count = testWidget->count();
+
+ // Boundary Checking
+ testWidget->addItems(QStringList());
+ QCOMPARE(testWidget->count(), count);
+
+ QStringList stringList;
+ QString label = QString("%1").arg(count);
+ stringList << QString("%1").arg(testWidget->count() + 1)
+ << QString("%1").arg(testWidget->count() + 2)
+ << QString("%1").arg(testWidget->count() + 3)
+ << label;
+ testWidget->addItems(stringList);
+ QCOMPARE(testWidget->count(), count + stringList.count());
+ QCOMPARE(testWidget->item(testWidget->count()-1)->text(), label);
+}
+
+
+void tst_QListWidget::openPersistentEditor()
+{
+ // Boundary checking
+ testWidget->openPersistentEditor(0);
+ QListWidgetItem *item = new QListWidgetItem(QString("%1").arg(testWidget->count()));
+ testWidget->openPersistentEditor(item);
+
+ int childCount = testWidget->viewport()->children().count();
+ testWidget->addItem(item);
+ testWidget->openPersistentEditor(item);
+ QCOMPARE(childCount + 1, testWidget->viewport()->children().count());
+}
+
+void tst_QListWidget::closePersistentEditor()
+{
+ // Boundary checking
+ int childCount = testWidget->viewport()->children().count();
+ testWidget->closePersistentEditor(0);
+ QListWidgetItem *item = new QListWidgetItem(QString("%1").arg(testWidget->count()));
+ testWidget->closePersistentEditor(item);
+ QCOMPARE(childCount, testWidget->viewport()->children().count());
+
+ // Create something
+ testWidget->addItem(item);
+ testWidget->openPersistentEditor(item);
+
+ // actual test
+ childCount = testWidget->viewport()->children().count();
+ testWidget->closePersistentEditor(item);
+ // Spin the event loop and hopefully it will die.
+ QEventLoop eventLoop;
+ for (int i=0; i < childCount; ++i)
+ connect(testWidget->viewport()->children().at(i), SIGNAL(destroyed()), &eventLoop, SLOT(quit()));
+ QTimer::singleShot(100, &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+ QCOMPARE(testWidget->viewport()->children().count(), childCount - 1);
+}
+
+void tst_QListWidget::setItemHidden()
+{
+ // Boundary checking
+ testWidget->setItemHidden(0, true);
+ testWidget->setItemHidden(0, false);
+
+ int totalHidden = 0;
+ for (int i = 0; i < testWidget->model()->rowCount(); ++i)
+ if (testWidget->isItemHidden(testWidget->item(i)))
+ totalHidden++;
+
+ QListWidgetItem *item = new QListWidgetItem(QString("%1").arg(testWidget->count()));
+ testWidget->addItem(item);
+
+ // Check that nothing else changed
+ int newTotal = 0;
+ for (int i = 0; i < testWidget->model()->rowCount(); ++i)
+ if (testWidget->isItemHidden(testWidget->item(i)))
+ newTotal++;
+ QCOMPARE(newTotal, totalHidden);
+
+ testWidget->setItemHidden(item, true);
+ QCOMPARE(testWidget->isItemHidden(item), true);
+
+ // Check that nothing else changed
+ newTotal = 0;
+ for (int i = 0; i < testWidget->model()->rowCount(); ++i)
+ if (testWidget->isItemHidden(testWidget->item(i)))
+ newTotal++;
+ QCOMPARE(newTotal, totalHidden + 1);
+
+ testWidget->setItemHidden(item, false);
+ QCOMPARE(testWidget->isItemHidden(item), false);
+
+ // Check that nothing else changed
+ newTotal = 0;
+ for (int i = 0; i < testWidget->model()->rowCount(); ++i)
+ if (testWidget->isItemHidden(testWidget->item(i)))
+ newTotal++;
+ QCOMPARE(newTotal, totalHidden);
+
+ testWidget->setItemHidden(item, true);
+}
+
+void tst_QListWidget::setCurrentItem_data()
+{
+ QTest::addColumn<int>("fill");
+ QTest::newRow("HasItems: 0") << 0;
+ QTest::newRow("HasItems: 1") << 1;
+ QTest::newRow("HasItems: 2") << 2;
+ QTest::newRow("HasItems: 3") << 3;
+}
+
+void tst_QListWidget::setCurrentItem()
+{
+ QFETCH(int, fill);
+ for (int i = 0; i < fill; ++i)
+ testWidget->addItem(QString("%1").arg(i));
+
+ // Boundary checking
+ testWidget->setCurrentItem((QListWidgetItem *)0);
+ QCOMPARE((QListWidgetItem *)0, testWidget->currentItem());
+ QListWidgetItem item;
+ testWidget->setCurrentItem(&item);
+ QCOMPARE((QListWidgetItem *)0, testWidget->currentItem());
+
+ // Make sure that currentItem changes to what is passed into setCurrentItem
+ for (int i = 0; i < testWidget->count(); ++i) {
+ testWidget->setCurrentItem(testWidget->item(i));
+ for (int j = 0; j < testWidget->count(); ++j) {
+ testWidget->setCurrentItem(testWidget->item(j));
+ QCOMPARE(testWidget->item(j), testWidget->currentItem());
+ }
+ }
+}
+
+void tst_QListWidget::setCurrentRow_data()
+{
+ QTest::addColumn<int>("fill");
+ QTest::newRow("HasItems: 0") << 0;
+ QTest::newRow("HasItems: 1") << 1;
+ QTest::newRow("HasItems: 2") << 2;
+ QTest::newRow("HasItems: 3") << 3;
+}
+
+void tst_QListWidget::setCurrentRow()
+{
+ QFETCH(int, fill);
+ for (int i = 0; i < fill; ++i)
+ testWidget->addItem(QString("%1").arg(i));
+
+ // Boundary checking
+ testWidget->setCurrentRow(-1);
+ QCOMPARE(-1, testWidget->currentRow());
+ testWidget->setCurrentRow(testWidget->count());
+ QCOMPARE(-1, testWidget->currentRow());
+
+ // Make sure that currentRow changes to what is passed into setCurrentRow
+ for (int i = 0; i < testWidget->count(); ++i) {
+ testWidget->setCurrentRow(i);
+ for (int j = 0; j < testWidget->count(); ++j) {
+ testWidget->setCurrentRow(j);
+ QCOMPARE(j, testWidget->currentRow());
+ }
+ }
+}
+
+void tst_QListWidget::count()
+{
+ populate();
+
+ // actual test
+ QCOMPARE(testWidget->model()->rowCount(), testWidget->count());
+}
+
+void tst_QListWidget::currentItem()
+{
+ populate();
+
+ // actual test
+ QModelIndex currentIndex = testWidget->selectionModel()->currentIndex();
+ if (currentIndex.isValid())
+ QVERIFY(testWidget->currentItem() == testWidget->item(currentIndex.row()));
+ else
+ QVERIFY(testWidget->currentItem() == (QListWidgetItem*)0);
+}
+
+void tst_QListWidget::currentRow()
+{
+ populate();
+
+ // actual test
+ QModelIndex currentIndex = testWidget->selectionModel()->currentIndex();
+ if (currentIndex.isValid())
+ QCOMPARE(testWidget->currentRow(), currentIndex.row());
+ else
+ QCOMPARE(testWidget->currentRow(), -1);
+}
+
+void tst_QListWidget::editItem_data()
+{
+ QTest::addColumn<bool>("editable");
+ QTest::newRow("editable") << true;
+ QTest::newRow("not editable") << false;
+}
+
+void tst_QListWidget::editItem()
+{
+ // Boundary checking
+ testWidget->editItem(0);
+ QListWidgetItem *item = new QListWidgetItem(QString("%1").arg(testWidget->count()));
+ testWidget->editItem(item);
+
+ QFETCH(bool, editable);
+ if (editable)
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ testWidget->addItem(item);
+
+ int childCount = testWidget->viewport()->children().count();
+ QWidget *existsAlready = testWidget->indexWidget(testWidget->model()->index(testWidget->row(item), 0));
+ testWidget->editItem(item);
+ Qt::ItemFlags flags = item->flags();
+
+ // There doesn't seem to be a way to detect if the item has already been edited...
+ if (!existsAlready && flags & Qt::ItemIsEditable && flags & Qt::ItemIsEnabled) {
+ QList<QObject *> children = testWidget->viewport()->children();
+ QVERIFY(children.count() > childCount);
+ bool found = false;
+ for (int i = 0; i < children.size(); ++i) {
+ if (children.at(i)->inherits("QExpandingLineEdit"))
+ found = true;
+ }
+ QVERIFY(found);
+ } else {
+ QCOMPARE(testWidget->viewport()->children().count(), childCount);
+ }
+}
+
+void tst_QListWidget::findItems()
+{
+ // This really just tests that the items that are returned are converted from index's to items correctly.
+
+ // Boundary checking
+ QCOMPARE(testWidget->findItems("GirlsCanWearJeansAndCutTheirHairShort", Qt::MatchExactly).count(), 0);
+
+ populate();
+
+ for (int i=0; i < testWidget->count(); ++i)
+ QCOMPARE(testWidget->findItems( (testWidget->item(i)->text()), Qt::MatchExactly).count(), 1);
+}
+
+
+void tst_QListWidget::insertItem_data()
+{
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<int>("insertIndex");
+ QTest::addColumn<QString>("itemLabel");
+ QTest::addColumn<int>("expectedIndex");
+
+ QStringList initialItems;
+ initialItems << "foo" << "bar";
+
+ QTest::newRow("Insert less then 0") << initialItems << -1 << "inserted" << 0;
+ QTest::newRow("Insert at 0") << initialItems << 0 << "inserted" << 0;
+ QTest::newRow("Insert beyond count") << initialItems << initialItems.count()+1 << "inserted" << initialItems.count();
+ QTest::newRow("Insert at count") << initialItems << initialItems.count() << "inserted" << initialItems.count();
+ QTest::newRow("Insert in the middle") << initialItems << 1 << "inserted" << 1;
+}
+
+void tst_QListWidget::insertItem()
+{
+ QFETCH(QStringList, initialItems);
+ QFETCH(int, insertIndex);
+ QFETCH(QString, itemLabel);
+ QFETCH(int, expectedIndex);
+
+ testWidget->insertItems(0, initialItems);
+ QCOMPARE(testWidget->count(), initialItems.count());
+
+ testWidget->insertItem(insertIndex, itemLabel);
+
+ QCOMPARE(rcFirst[RowsAboutToBeInserted], expectedIndex);
+ QCOMPARE(rcLast[RowsAboutToBeInserted], expectedIndex);
+ QCOMPARE(rcFirst[RowsInserted], expectedIndex);
+ QCOMPARE(rcLast[RowsInserted], expectedIndex);
+
+ QCOMPARE(testWidget->count(), initialItems.count() + 1);
+ QCOMPARE(testWidget->item(expectedIndex)->text(), itemLabel);
+}
+
+void tst_QListWidget::insertItems_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("insertType");
+
+ QTest::newRow("Insert 1 item using constructor") << 1 << 0;
+ QTest::newRow("Insert 10 items using constructor") << 10 << 0;
+ QTest::newRow("Insert 100 items using constructor") << 100 << 0;
+
+ QTest::newRow("Insert 1 item with insertItem") << 1 << 1;
+ QTest::newRow("Insert 10 items with insertItem") << 10 << 1;
+ QTest::newRow("Insert 100 items with insertItem") << 100 << 1;
+
+ QTest::newRow("Insert/Create 1 item using insertItem") << 1 << 2;
+ QTest::newRow("Insert/Create 10 items using insertItem") << 10 << 2;
+ QTest::newRow("Insert/Create 100 items using insertItem") << 100 << 2;
+
+ QTest::newRow("Insert 0 items with insertItems") << 0 << 3;
+ QTest::newRow("Insert 1 item with insertItems") << 1 << 3;
+ QTest::newRow("Insert 10 items with insertItems") << 10 << 3;
+ QTest::newRow("Insert 100 items with insertItems") << 100 << 3;
+}
+
+void tst_QListWidget::insertItems()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, insertType);
+
+ if (insertType == 3) {
+ QStringList strings;
+ for (int i=0; i<rowCount; ++i)
+ strings << QString::number(i);
+ testWidget->insertItems(0, strings);
+ } else {
+ for (int r = 0; r < rowCount; ++r) {
+ if (insertType == 0) {
+ // insert with QListWidgetItem constructor
+ new QListWidgetItem(QString::number(r), testWidget);
+ } else if (insertType == 1) {
+ // insert actual item
+ testWidget->insertItem(r, new QListWidgetItem(QString::number(r)));
+ } else if (insertType == 2) {
+ // insert/creating with string
+ testWidget->insertItem(r, QString::number(r));
+ } else if (insertType == 3) {
+ QStringList strings;
+ for (int i=0; i<rowCount; ++i)
+ strings << QString::number(i);
+ testWidget->insertItems(0, strings);
+ break;
+ } else {
+ QVERIFY(0);
+ }
+ }
+ }
+ // compare the results
+ QCOMPARE(testWidget->count(), rowCount);
+
+ // check if the text
+ for (int r = 0; r < rowCount; ++r)
+ QCOMPARE(testWidget->item(r)->text(), QString::number(r));
+
+ // make sure all items have view set correctly
+ for (int i=0; i<testWidget->count(); ++i)
+ QCOMPARE(testWidget->item(i)->listWidget(), testWidget);
+}
+
+void tst_QListWidget::itemAssignment()
+{
+ QListWidgetItem itemInWidget("inWidget", testWidget);
+ itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsTristate);
+ QListWidgetItem itemOutsideWidget("outsideWidget");
+
+ QVERIFY(itemInWidget.listWidget());
+ QCOMPARE(itemInWidget.text(), QString("inWidget"));
+ QVERIFY(itemInWidget.flags() & Qt::ItemIsTristate);
+
+ QVERIFY(!itemOutsideWidget.listWidget());
+ QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget"));
+ QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsTristate));
+
+ itemOutsideWidget = itemInWidget;
+ QVERIFY(!itemOutsideWidget.listWidget());
+ QCOMPARE(itemOutsideWidget.text(), QString("inWidget"));
+ QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsTristate);
+}
+
+void tst_QListWidget::item_data()
+{
+ QTest::addColumn<int>("row");
+ QTest::addColumn<bool>("outOfBounds");
+
+ QTest::newRow("First item, row: 0") << 0 << false;
+ QTest::newRow("Middle item, row: 1") << 1 << false;
+ QTest::newRow("Last item, row: 2") << 2 << false;
+ QTest::newRow("Out of bounds, row: -1") << -1 << true;
+ QTest::newRow("Out of bounds, row: 3") << 3 << true;
+}
+
+void tst_QListWidget::item()
+{
+ QFETCH(int, row);
+ QFETCH(bool, outOfBounds);
+
+ (new QListWidgetItem(testWidget))->setText("item0");
+ (new QListWidgetItem(testWidget))->setText("item1");
+ (new QListWidgetItem(testWidget))->setText("item2");
+
+ QCOMPARE(testWidget->count(), 3);
+
+ QListWidgetItem *item = testWidget->item(row);
+ if (outOfBounds) {
+ QCOMPARE(item, static_cast<QListWidgetItem*>(0));
+ QCOMPARE(testWidget->count(), 3);
+ } else {
+ QCOMPARE(item->text(), QString("item%1").arg(row));
+ QCOMPARE(testWidget->count(), 3);
+ }
+}
+
+void tst_QListWidget::takeItem_data()
+{
+ QTest::addColumn<int>("row");
+ QTest::addColumn<bool>("outOfBounds");
+
+ QTest::newRow("First item, row: 0") << 0 << false;
+ QTest::newRow("Middle item, row: 1") << 1 << false;
+ QTest::newRow("Last item, row: 2") << 2 << false;
+ QTest::newRow("Out of bounds, row: -1") << -1 << true;
+ QTest::newRow("Out of bounds, row: 3") << 3 << true;
+}
+
+void tst_QListWidget::takeItem()
+{
+ QFETCH(int, row);
+ QFETCH(bool, outOfBounds);
+
+ (new QListWidgetItem(testWidget))->setText("item0");
+ (new QListWidgetItem(testWidget))->setText("item1");
+ (new QListWidgetItem(testWidget))->setText("item2");
+
+ QCOMPARE(testWidget->count(), 3);
+
+ QListWidgetItem *item = testWidget->takeItem(row);
+ if (outOfBounds) {
+ QCOMPARE(item, static_cast<QListWidgetItem*>(0));
+ QCOMPARE(testWidget->count(), 3);
+ } else {
+ QCOMPARE(item->text(), QString("item%1").arg(row));
+ QCOMPARE(testWidget->count(), 2);
+ }
+
+ delete item;
+}
+
+void tst_QListWidget::selectedItems_data()
+{
+ QTest::addColumn<int>("itemCount");
+ QTest::addColumn<IntList>("hiddenRows");
+ QTest::addColumn<IntList>("selectedRows");
+ QTest::addColumn<IntList>("expectedRows");
+
+
+ QTest::newRow("none hidden, none selected")
+ << 3
+ << IntList()
+ << IntList()
+ << IntList();
+
+ QTest::newRow("none hidden, all selected")
+ << 3
+ << IntList()
+ << (IntList() << 0 << 1 << 2)
+ << (IntList() << 0 << 1 << 2);
+
+ QTest::newRow("first hidden, all selected")
+ << 3
+ << (IntList() << 0)
+ << (IntList() << 0 << 1 << 2)
+ << (IntList() << 0 << 1 << 2);
+
+ QTest::newRow("last hidden, all selected")
+ << 3
+ << (IntList() << 2)
+ << (IntList() << 0 << 1 << 2)
+ << (IntList() << 0 << 1 << 2);
+
+ QTest::newRow("middle hidden, all selected")
+ << 3
+ << (IntList() << 1)
+ << (IntList() << 0 << 1 << 2)
+ << (IntList() << 0 << 1 << 2);
+
+ QTest::newRow("all hidden, all selected")
+ << 3
+ << (IntList() << 0 << 1 << 2)
+ << (IntList() << 0 << 1 << 2)
+ << (IntList() << 0 << 1 << 2);
+}
+
+void tst_QListWidget::selectedItems()
+{
+ QFETCH(int, itemCount);
+ QFETCH(IntList, hiddenRows);
+ QFETCH(IntList, selectedRows);
+ QFETCH(IntList, expectedRows);
+
+ QVERIFY(testWidget->count() == 0);
+
+ //insert items
+ for (int i=0; i<itemCount; ++i)
+ new QListWidgetItem(QString("Item%1").arg(i), testWidget);
+
+ //test the selection
+ testWidget->setSelectionMode(QListWidget::SingleSelection);
+ for (int i=0; i<itemCount; ++i) {
+ QListWidgetItem *item = testWidget->item(i);
+ testWidget->setItemSelected(item, true);
+ QVERIFY(item->isSelected());
+ QCOMPARE(testWidget->selectedItems().count(), 1);
+ }
+ //let's clear the selection
+ testWidget->clearSelection();
+ //... and set the selection mode to allow more than 1 item to be selected
+ testWidget->setSelectionMode(QAbstractItemView::MultiSelection);
+
+ //verify items are inserted
+ QCOMPARE(testWidget->count(), itemCount);
+ // hide items
+ foreach (int row, hiddenRows)
+ testWidget->setItemHidden(testWidget->item(row), true);
+ // select items
+ foreach (int row, selectedRows)
+ testWidget->setItemSelected(testWidget->item(row), true);
+
+ // check that the correct number of items and the expected items are there
+ QList<QListWidgetItem *> selectedItems = testWidget->selectedItems();
+ QCOMPARE(selectedItems.count(), expectedRows.count());
+ foreach (int row, expectedRows)
+ QVERIFY(selectedItems.contains(testWidget->item(row)));
+
+ //check that isSelected agrees with selectedItems
+ for (int i=0; i<itemCount; ++i) {
+ QListWidgetItem *item = testWidget->item(i);
+ if (testWidget->isItemSelected(item))
+ QVERIFY(selectedItems.contains(item));
+ }
+}
+
+void tst_QListWidget::removeItems_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("removeRows");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("expectedRowCount");
+
+ QTest::newRow("Empty") << 0 << 1 << 0 << 0;
+ QTest::newRow("1:1") << 1 << 1 << 0 << 0;
+ QTest::newRow("3:1") << 3 << 1 << 0 << 2;
+ QTest::newRow("3:2") << 3 << 2 << 0 << 1;
+ QTest::newRow("100:10") << 100 << 10 << 0 << 90;
+}
+
+void tst_QListWidget::removeItems()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, removeRows);
+ QFETCH(int, row);
+ QFETCH(int, expectedRowCount);
+
+ //insert items
+ for (int r = 0; r < rowCount; ++r)
+ new QListWidgetItem(QString::number(r), testWidget);
+
+ // remove and compare the results
+ for (int r = 0; r < removeRows; ++r)
+ delete testWidget->item(row);
+ QCOMPARE(testWidget->count(), expectedRowCount);
+
+ // check if the correct items were removed
+ for (int r = 0; r < expectedRowCount; ++r)
+ if (r < row)
+ QCOMPARE(testWidget->item(r)->text(), QString::number(r));
+ else
+ QCOMPARE(testWidget->item(r)->text(), QString::number(r + removeRows));
+
+
+}
+
+void tst_QListWidget::moveItemsPriv_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("srcRow");
+ QTest::addColumn<int>("dstRow");
+ QTest::addColumn<bool>("shouldHaveSignaled");
+
+ QTest::newRow("Empty") << 0 << 0 << 0 << false;
+ QTest::newRow("Overflow src") << 5 << 5 << 2 << false;
+ QTest::newRow("Underflow src") << 5 << -1 << 2 << false;
+ QTest::newRow("Overflow dst") << 5 << 2 << 6 << false;
+ QTest::newRow("Underflow dst") << 5 << 2 << -1 << false;
+ QTest::newRow("Same place") << 5 << 2 << 2 << false;
+ QTest::newRow("Up") << 5 << 4 << 2 << true;
+ QTest::newRow("Down") << 5 << 2 << 4 << true;
+ QTest::newRow("QTBUG-6532 assert") << 5 << 0 << 1 << false;
+ QTest::newRow("QTBUG-6565 to the end") << 5 << 3 << 5 << true;
+ QTest::newRow("Same place 2") << 2 << 0 << 1 << false;
+ QTest::newRow("swap") << 2 << 0 << 2 << true;
+ QTest::newRow("swap2") << 4 << 1 << 3 << true;
+ QTest::newRow("swap3") << 4 << 3 << 2 << true;
+ QTest::newRow("swap4") << 2 << 1 << 0 << true;
+}
+
+void tst_QListWidget::moveItemsPriv()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, srcRow);
+ QFETCH(int, dstRow);
+ QFETCH(bool, shouldHaveSignaled);
+
+ for (int r = 0; r < rowCount; ++r)
+ new QListWidgetItem(QString::number(r), testWidget);
+
+ QListModel *model = qobject_cast<QListModel *>(testWidget->model());
+ QVERIFY(model);
+ QSignalSpy beginMoveSpy(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy movedSpy(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ model->move(srcRow, dstRow);
+
+ if (shouldHaveSignaled) {
+ if (srcRow < dstRow)
+ QCOMPARE(testWidget->item(dstRow - 1)->text(), QString::number(srcRow));
+ else
+ QCOMPARE(testWidget->item(dstRow)->text(), QString::number(srcRow));
+
+ QCOMPARE(beginMoveSpy.count(), 1);
+ const QList<QVariant> &beginMoveArgs = beginMoveSpy.takeFirst();
+ QCOMPARE(beginMoveArgs.at(1).toInt(), srcRow);
+ QCOMPARE(beginMoveArgs.at(2).toInt(), srcRow);
+ QCOMPARE(beginMoveArgs.at(4).toInt(), dstRow);
+
+ QCOMPARE(movedSpy.count(), 1);
+ const QList<QVariant> &movedArgs = movedSpy.takeFirst();
+ QCOMPARE(movedArgs.at(1).toInt(), srcRow);
+ QCOMPARE(movedArgs.at(2).toInt(), srcRow);
+ QCOMPARE(movedArgs.at(4).toInt(), dstRow);
+ } else {
+ QCOMPARE(beginMoveSpy.count(), 0);
+ QCOMPARE(movedSpy.count(), 0);
+ }
+}
+
+void tst_QListWidget::itemStreaming_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("toolTip");
+
+ QTest::newRow("Data") << "item text" << "tool tip text";
+}
+
+void tst_QListWidget::itemStreaming()
+{
+ QFETCH(QString, text);
+ QFETCH(QString, toolTip);
+
+ QListWidgetItem item;
+ QCOMPARE(item.text(), QString());
+ QCOMPARE(item.toolTip(), QString());
+
+ item.setText(text);
+ item.setToolTip(toolTip);
+ QCOMPARE(item.text(), text);
+ QCOMPARE(item.toolTip(), toolTip);
+
+ QByteArray buffer;
+ QDataStream out(&buffer, QIODevice::WriteOnly);
+ out << item;
+
+ QListWidgetItem item2;
+ QCOMPARE(item2.text(), QString());
+ QCOMPARE(item2.toolTip(), QString());
+
+ QVERIFY(!buffer.isEmpty());
+
+ QDataStream in(&buffer, QIODevice::ReadOnly);
+ in >> item2;
+ QCOMPARE(item2.text(), text);
+ QCOMPARE(item2.toolTip(), toolTip);
+}
+
+void tst_QListWidget::sortItems_data()
+{
+ QTest::addColumn<int>("order");
+ QTest::addColumn<QVariantList>("initialList");
+ QTest::addColumn<QVariantList>("expectedList");
+ QTest::addColumn<IntList>("expectedRows");
+
+ QTest::newRow("ascending strings")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QVariantList() << QString("c") << QString("d") << QString("a") << QString("b"))
+ << (QVariantList() << QString("a") << QString("b") << QString("c") << QString("d"))
+ << (IntList() << 2 << 3 << 0 << 1);
+
+ QTest::newRow("descending strings")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QVariantList() << QString("c") << QString("d") << QString("a") << QString("b"))
+ << (QVariantList() << QString("d") << QString("c") << QString("b") << QString("a"))
+ << (IntList() << 1 << 0 << 3 << 2);
+
+ QTest::newRow("ascending numbers")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QVariantList() << 1 << 11 << 2 << 22)
+ << (QVariantList() << 1 << 2 << 11 << 22)
+ << (IntList() << 0 << 2 << 1 << 3);
+
+ QTest::newRow("descending numbers")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QVariantList() << 1 << 11 << 2 << 22)
+ << (QVariantList() << 22 << 11 << 2 << 1)
+ << (IntList() << 3 << 1 << 2 << 0);
+}
+
+void tst_QListWidget::sortItems()
+{
+ QFETCH(int, order);
+ QFETCH(QVariantList, initialList);
+ QFETCH(QVariantList, expectedList);
+ QFETCH(IntList, expectedRows);
+
+ foreach (const QVariant &data, initialList) {
+ QListWidgetItem *item = new QListWidgetItem(testWidget);
+ item->setData(Qt::DisplayRole, data);
+ }
+
+ QAbstractItemModel *model = testWidget->model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ testWidget->sortItems(static_cast<Qt::SortOrder>(order));
+
+ QCOMPARE(testWidget->count(), expectedList.count());
+ for (int i = 0; i < testWidget->count(); ++i)
+ QCOMPARE(testWidget->item(i)->text(), expectedList.at(i).toString());
+
+ for (int k = 0; k < testWidget->count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+}
+
+void tst_QListWidget::sortHiddenItems_data()
+{
+ QTest::addColumn<int>("order");
+ QTest::addColumn<QStringList>("initialList");
+ QTest::addColumn<QStringList>("expectedList");
+ QTest::addColumn<IntList>("expectedRows");
+ QTest::addColumn<IntList>("expectedVisibility");
+
+ QStringList initial, expected;
+ IntList rowOrder;
+ IntList visible;
+ for (int i = 0; i < 20; ++i) {
+ initial << QString(QChar(0x41 + i));
+ expected << QString(QChar(0x54 - i));
+ rowOrder << 19 - i;
+ visible << (i % 2);
+
+ }
+ QTest::newRow("descending order, 20 items")
+ << static_cast<int>(Qt::DescendingOrder)
+ << initial
+ << expected
+ << rowOrder
+ << visible;
+
+ QTest::newRow("ascending order")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "d" << "a" << "b")
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (IntList() << 2 << 3 << 0 << 1)
+ << (IntList() << 1 << 0 << 1 << 0);
+
+ QTest::newRow("descending order")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "c" << "d" << "a" << "b")
+ << (QStringList() << "d" << "c" << "b" << "a")
+ << (IntList() << 1 << 0 << 3 << 2)
+ << (IntList() << 0 << 1 << 0 << 1);
+}
+
+void tst_QListWidget::sortHiddenItems()
+{
+ QFETCH(int, order);
+ QFETCH(QStringList, initialList);
+ QFETCH(QStringList, expectedList);
+ QFETCH(IntList, expectedRows);
+ QFETCH(IntList, expectedVisibility);
+
+ // init() won't clear hidden items...
+ QListWidget *tw = new QListWidget();
+ tw->addItems(initialList);
+
+ QAbstractItemModel *model = tw->model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j) {
+ persistent << model->index(j, 0, QModelIndex());
+ tw->setRowHidden(j, j & 1); // every odd is hidden
+ }
+
+ tw->setSortingEnabled(true);
+ tw->sortItems(static_cast<Qt::SortOrder>(order));
+
+ QCOMPARE(tw->count(), expectedList.count());
+ for (int i = 0; i < tw->count(); ++i) {
+ QCOMPARE(tw->item(i)->text(), expectedList.at(i));
+ QCOMPARE(tw->item(i)->isHidden(), !expectedVisibility.at(i));
+ }
+
+ for (int k = 0; k < tw->count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+
+ delete tw;
+}
+
+void tst_QListWidget::modelChanged(ModelChanged change, const QModelIndex &parent,
+ int first, int last)
+{
+ rcParent[change] = parent;
+ rcFirst[change] = first;
+ rcLast[change] = last;
+}
+
+class TestListWidget : public QListWidget {
+public:
+ TestListWidget() : QListWidget()
+ {
+
+ }
+ State getState() {return QListWidget::state();}
+
+ void closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint) {
+ QListWidget::closeEditor(w, hint);
+ }
+
+ bool isEditingState(QListWidgetItem *item) {
+ Q_UNUSED(item);
+ return (QListWidget::state() == QListWidget::EditingState ? true : false);
+ }
+};
+
+void tst_QListWidget::closeEditor()
+{
+ TestListWidget w;
+ QStringList labels = (QStringList() << "a" << "b" << "c" << "d");
+ w.addItems(labels);
+ QListWidgetItem *item = w.item(0);
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ QVERIFY(item);
+ w.editItem(item);
+
+ QVERIFY(w.isEditingState(item));
+
+ w.reset();
+
+ QVERIFY(!w.isEditingState(item));
+}
+
+void tst_QListWidget::setData_data()
+{
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<int>("itemIndex");
+ QTest::addColumn<IntList>("roles");
+ QTest::addColumn<QVariantList>("values");
+ QTest::addColumn<int>("expectedSignalCount");
+
+ QStringList initialItems;
+ IntList roles;
+ QVariantList values;
+
+ {
+ initialItems.clear(); roles.clear(); values.clear();
+ initialItems << "foo";
+ roles << Qt::DisplayRole;
+ values << "xxx";
+ QTest::newRow("changing a role should emit")
+ << initialItems << 0 << roles << values << 1;
+ }
+ {
+ initialItems.clear(); roles.clear(); values.clear();
+ initialItems << "foo";
+ roles << Qt::DisplayRole;
+ values << "foo";
+ QTest::newRow("setting the same value should not emit")
+ << initialItems << 0 << roles << values << 0;
+ }
+ {
+ initialItems.clear(); roles.clear(); values.clear();
+ initialItems << "foo";
+ roles << Qt::DisplayRole << Qt::DisplayRole;
+ values << "bar" << "bar";
+ QTest::newRow("setting the same value twice should only emit once")
+ << initialItems << 0 << roles << values << 1;
+ }
+ {
+ initialItems.clear(); roles.clear(); values.clear();
+ initialItems << "foo";
+ roles << Qt::DisplayRole << Qt::ToolTipRole << Qt::WhatsThisRole;
+ values << "bar" << "bartooltip" << "barwhatsthis";
+ QTest::newRow("changing three roles should emit three times")
+ << initialItems << 0 << roles << values << 3;
+ }
+}
+
+void tst_QListWidget::setData()
+{
+ QFETCH(QStringList, initialItems);
+ QFETCH(int, itemIndex);
+ QFETCH(IntList, roles);
+ QFETCH(QVariantList, values);
+ QFETCH(int, expectedSignalCount);
+ qRegisterMetaType<QListWidgetItem *>("QListWidgetItem*");
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+
+ QVERIFY(roles.count() == values.count());
+
+ for (int manipulateModel=0; manipulateModel<2; ++manipulateModel) {
+ testWidget->clear();
+ testWidget->insertItems(0, initialItems);
+ QCOMPARE(testWidget->count(), initialItems.count());
+
+ QSignalSpy itemChanged(testWidget, SIGNAL(itemChanged(QListWidgetItem *)));
+ QSignalSpy dataChanged(testWidget->model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+
+ for (int i=0; i < roles.count(); ++i) {
+ if (manipulateModel)
+ testWidget->model()->setData(
+ testWidget->model()->index(itemIndex, 0, testWidget->rootIndex()),
+ values.at(i),
+ roles.at(i));
+ else
+ testWidget->item(itemIndex)->setData(roles.at(i), values.at(i));
+ }
+
+ // make sure the data is actually set
+ for (int i=0; i < roles.count(); ++i)
+ QCOMPARE(testWidget->item(itemIndex)->data(roles.at(i)), values.at(i));
+
+ // make sure we get the right number of emits
+ QCOMPARE(itemChanged.count(), expectedSignalCount);
+ QCOMPARE(dataChanged.count(), expectedSignalCount);
+ }
+}
+
+void tst_QListWidget::insertItemsWithSorting_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<QStringList>("insertItems");
+ QTest::addColumn<QStringList>("expectedItems");
+ QTest::addColumn<IntList>("expectedRows");
+
+ QTest::newRow("() + (a) = (a)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList()
+ << (QStringList() << "a")
+ << (QStringList() << "a")
+ << IntList();
+ QTest::newRow("() + (c, b, a) = (a, b, c)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList()
+ << (QStringList() << "c" << "b" << "a")
+ << (QStringList() << "a" << "b" << "c")
+ << IntList();
+ QTest::newRow("() + (a, b, c) = (c, b, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QStringList()
+ << (QStringList() << "a" << "b" << "c")
+ << (QStringList() << "c" << "b" << "a")
+ << IntList();
+ QTest::newRow("(a) + (b) = (a, b)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList("a")
+ << (QStringList() << "b")
+ << (QStringList() << "a" << "b")
+ << (IntList() << 0);
+ QTest::newRow("(a) + (b) = (b, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QStringList("a")
+ << (QStringList() << "b")
+ << (QStringList() << "b" << "a")
+ << (IntList() << 1);
+ QTest::newRow("(a, c, b) + (d) = (a, b, c, d)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "b")
+ << (QStringList() << "d")
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (IntList() << 0 << 1 << 2);
+ QTest::newRow("(b, c, a) + (d) = (d, c, b, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "b" << "c" << "a")
+ << (QStringList() << "d")
+ << (QStringList() << "d" << "c" << "b" << "a")
+ << (IntList() << 1 << 2 << 3);
+ {
+ IntList ascendingRows;
+ IntList reverseRows;
+ QStringList ascendingItems;
+ QStringList reverseItems;
+ for (int i = 'a'; i <= 'z'; ++i) {
+ ascendingItems << QString("%0").arg(QLatin1Char(i));
+ reverseItems << QString("%0").arg(QLatin1Char('z' - i + 'a'));
+ ascendingRows << i - 'a';
+ reverseRows << 'z' - i + 'a';
+ }
+ QTest::newRow("() + (sorted items) = (sorted items)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList()
+ << ascendingItems
+ << ascendingItems
+ << IntList();
+ QTest::newRow("(sorted items) + () = (sorted items)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << ascendingItems
+ << QStringList()
+ << ascendingItems
+ << ascendingRows;
+ QTest::newRow("() + (ascending items) = (reverse items)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QStringList()
+ << ascendingItems
+ << reverseItems
+ << IntList();
+ QTest::newRow("(reverse items) + () = (ascending items)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << reverseItems
+ << QStringList()
+ << ascendingItems
+ << ascendingRows;
+ QTest::newRow("(reverse items) + () = (reverse items)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << reverseItems
+ << QStringList()
+ << reverseItems
+ << ascendingRows;
+ }
+}
+
+void tst_QListWidget::insertItemsWithSorting()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initialItems);
+ QFETCH(QStringList, insertItems);
+ QFETCH(QStringList, expectedItems);
+ QFETCH(IntList, expectedRows);
+
+ for (int method = 0; method < 5; ++method) {
+ QListWidget w;
+ w.setSortingEnabled(true);
+ w.sortItems(static_cast<Qt::SortOrder>(sortOrder));
+ w.addItems(initialItems);
+
+ QAbstractItemModel *model = w.model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ switch (method) {
+ case 0:
+ // insert using item constructor
+ for (int i = 0; i < insertItems.size(); ++i)
+ new QListWidgetItem(insertItems.at(i), &w);
+ break;
+ case 1:
+ // insert using insertItems()
+ w.insertItems(0, insertItems);
+ break;
+ case 2:
+ // insert using insertItem()
+ for (int i = 0; i < insertItems.size(); ++i)
+ w.insertItem(0, insertItems.at(i));
+ break;
+ case 3:
+ // insert using addItems()
+ w.addItems(insertItems);
+ break;
+ case 4:
+ // insert using addItem()
+ for (int i = 0; i < insertItems.size(); ++i)
+ w.addItem(insertItems.at(i));
+ break;
+ }
+ QCOMPARE(w.count(), expectedItems.count());
+ for (int i = 0; i < w.count(); ++i)
+ QCOMPARE(w.item(i)->text(), expectedItems.at(i));
+
+ for (int k = 0; k < persistent.count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+ }
+}
+
+void tst_QListWidget::changeDataWithSorting_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<int>("itemIndex");
+ QTest::addColumn<QString>("newValue");
+ QTest::addColumn<QStringList>("expectedItems");
+ QTest::addColumn<IntList>("expectedRows");
+ QTest::addColumn<bool>("reorderingExpected");
+
+ QTest::newRow("change a to b in (a)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a")
+ << 0 << "b"
+ << (QStringList() << "b")
+ << (IntList() << 0)
+ << false;
+ QTest::newRow("change a to b in (a, c)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c")
+ << 0 << "b"
+ << (QStringList() << "b" << "c")
+ << (IntList() << 0 << 1)
+ << false;
+ QTest::newRow("change a to c in (a, b)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "b")
+ << 0 << "c"
+ << (QStringList() << "b" << "c")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("change c to a in (c, b)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "c" << "b")
+ << 0 << "a"
+ << (QStringList() << "b" << "a")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("change e to i in (a, c, e, g)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "e" << "g")
+ << 2 << "i"
+ << (QStringList() << "a" << "c" << "g" << "i")
+ << (IntList() << 0 << 1 << 3 << 2)
+ << true;
+ QTest::newRow("change e to a in (c, e, g, i)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "e" << "g" << "i")
+ << 1 << "a"
+ << (QStringList() << "a" << "c" << "g" << "i")
+ << (IntList() << 1 << 0 << 2 << 3)
+ << true;
+ QTest::newRow("change e to f in (c, e, g, i)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "e" << "g" << "i")
+ << 1 << "f"
+ << (QStringList() << "c" << "f" << "g" << "i")
+ << (IntList() << 0 << 1 << 2 << 3)
+ << false;
+}
+
+void tst_QListWidget::itemData()
+{
+ QListWidget widget;
+ QListWidgetItem item(&widget);
+ item.setFlags(item.flags() | Qt::ItemIsEditable);
+ item.setData(Qt::DisplayRole, QString("0"));
+ item.setData(Qt::CheckStateRole, Qt::PartiallyChecked);
+ item.setData(Qt::UserRole + 0, QString("1"));
+ item.setData(Qt::UserRole + 1, QString("2"));
+ item.setData(Qt::UserRole + 2, QString("3"));
+ item.setData(Qt::UserRole + 3, QString("4"));
+ QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0));
+ QCOMPARE(flags.count(), 6);
+ QCOMPARE(flags[Qt::UserRole + 0].toString(), QString("1"));
+}
+
+void tst_QListWidget::changeDataWithSorting()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initialItems);
+ QFETCH(int, itemIndex);
+ QFETCH(QString, newValue);
+ QFETCH(QStringList, expectedItems);
+ QFETCH(IntList, expectedRows);
+ QFETCH(bool, reorderingExpected);
+
+ QListWidget w;
+ w.setSortingEnabled(true);
+ w.sortItems(static_cast<Qt::SortOrder>(sortOrder));
+ w.addItems(initialItems);
+
+ QAbstractItemModel *model = w.model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+ QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
+
+ QListWidgetItem *item = w.item(itemIndex);
+ item->setText(newValue);
+ for (int i = 0; i < expectedItems.count(); ++i) {
+ QCOMPARE(w.item(i)->text(), expectedItems.at(i));
+ for (int j = 0; j < persistent.count(); ++j) {
+ if (persistent.at(j).row() == i) // the same toplevel row
+ QCOMPARE(persistent.at(j).internalPointer(), (void *)w.item(i));
+ }
+ }
+
+ for (int k = 0; k < persistent.count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0);
+}
+
+void tst_QListWidget::itemWidget()
+{
+ QListWidget list;
+ QWidget widget;
+
+ QListWidgetItem *item = new QListWidgetItem(&list);
+
+
+ QCOMPARE(list.itemWidget(item), static_cast<QWidget*>(0));
+ list.setItemWidget(item, &widget);
+ QCOMPARE(list.itemWidget(item), &widget);
+ list.removeItemWidget(item);
+ QCOMPARE(list.itemWidget(item), static_cast<QWidget*>(0));
+}
+
+#ifndef Q_WS_MAC
+class MyListWidget : public QListWidget
+{
+public:
+ MyListWidget(QWidget *parent=0)
+ : QListWidget(parent)
+ {
+ }
+
+ void paintEvent(QPaintEvent *e) {
+ painted += e->region();
+ QListWidget::paintEvent(e);
+ }
+
+ QRegion painted;
+};
+
+void tst_QListWidget::fastScroll()
+{
+ QWidget topLevel;
+ MyListWidget widget(&topLevel);
+ for (int i = 0; i < 50; ++i)
+ widget.addItem(QString("Item %1").arg(i));
+
+ topLevel.resize(300, 300); // toplevel needs to be wide enough for the item
+ topLevel.show();
+ // Make sure the widget gets the first full repaint. On
+ // some WMs, we'll get two (first inactive exposure, then
+ // active exposure.
+ QTest::qWaitForWindowShown(&widget);
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(&widget);
+#endif
+ QApplication::processEvents();
+ QTest::qWait(500);
+
+ QSize itemSize = widget.visualItemRect(widget.item(0)).size();
+ QVERIFY(!itemSize.isEmpty());
+
+ QScrollBar *sbar = widget.verticalScrollBar();
+ widget.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+ widget.painted = QRegion();
+ sbar->setValue(sbar->value() + sbar->singleStep());
+ QApplication::processEvents();
+
+ // only one item should be repainted, the rest should be scrolled in memory
+ QCOMPARE(widget.painted.boundingRect().size(), itemSize);
+}
+#endif // Q_WS_MAC
+
+void tst_QListWidget::insertUnchanged()
+{
+ QListWidget w;
+ QSignalSpy itemChangedSpy(&w, SIGNAL(itemChanged(QListWidgetItem*)));
+ QListWidgetItem item("foo", &w);
+ QCOMPARE(itemChangedSpy.count(), 0);
+}
+
+void tst_QListWidget::setSortingEnabled()
+{
+ QListWidget w;
+ QListWidgetItem *item1 = new QListWidgetItem(&w);
+ QListWidgetItem *item2 = new QListWidgetItem(&w);
+
+ w.setSortingEnabled(true);
+ QCOMPARE(w.isSortingEnabled(), true);
+ QCOMPARE(w.item(0), item1);
+ QCOMPARE(w.item(1), item2);
+}
+
+void tst_QListWidget::task199503_crashWhenCleared()
+{
+ //we test here for a crash that would occur if you clear the items in the currentItemChanged signal
+ QListWidget w;
+ w.addItems( QStringList() << "item1" << "item2" << "item3");
+ w.setCurrentRow(0);
+ w.connect(&w, SIGNAL(currentItemChanged(QListWidgetItem *,QListWidgetItem*)), SLOT(clear()));
+ w.setCurrentRow(1);
+}
+
+void tst_QListWidget::task217070_scrollbarsAdjusted()
+{
+ //This task was mailing for style using SH_ScrollView_FrameOnlyAroundContents such as QMotifStyle
+ QListWidget v;
+ for (int i = 0; i<200;i++)
+ v.addItem(QString::number(i));
+ v.show();
+ v.setViewMode(QListView::IconMode);
+ v.setResizeMode(QListView::Adjust);
+ v.setUniformItemSizes(true);
+ v.resize(160,100);
+ QTest::qWait(50);
+ for(int f=150; f>90 ; f--) {
+ v.resize(f,100);
+ QTest::qWait(30);
+ QVERIFY(v.verticalScrollBar()->isVisible());
+ //the vertical scrollbar must not be visible.
+ QVERIFY(!v.horizontalScrollBar()->isVisible());
+ }
+}
+
+void tst_QListWidget::task258949_keypressHangup()
+{
+ QListWidget lw;
+ for (int y = 0; y < 5; y++) {
+ QListWidgetItem *lwi = new QListWidgetItem(&lw);
+ lwi->setText(y ? "1" : "0");
+ if (y)
+ lwi->setFlags(Qt::ItemIsSelectable);
+ }
+
+ lw.show();
+ lw.setCurrentIndex(lw.model()->index(0,0));
+ QCOMPARE(lw.currentIndex(), lw.model()->index(0,0));
+ QTest::qWait(30);
+ QTest::keyPress(&lw, '1'); //this used to freeze
+ QTest::qWait(30);
+ QCOMPARE(lw.currentIndex(), lw.model()->index(0,0));
+}
+
+void tst_QListWidget::QTBUG8086_currentItemChangedOnClick()
+{
+ qRegisterMetaType<QListWidgetItem*>("QListWidgetItem*");
+ QWidget win;
+ QHBoxLayout layout(&win);
+ QListWidget list;
+ for (int i = 0 ; i < 4; ++i)
+ new QListWidgetItem(QString::number(i), &list);
+
+ layout.addWidget(&list);
+
+ QLineEdit edit;
+ layout.addWidget(&edit);
+
+ edit.setFocus();
+ win.show();
+
+ QSignalSpy spy(&list, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)));
+
+ QTest::qWaitForWindowShown(&win);
+
+ QCOMPARE(spy.count(), 0);
+
+ QTest::mouseClick(list.viewport(), Qt::LeftButton, 0, list.visualItemRect(list.item(2)).center());
+
+ QCOMPARE(spy.count(), 1);
+
+}
+
+
+class ItemDelegate : public QItemDelegate
+{
+public:
+ ItemDelegate(QObject *parent = 0) : QItemDelegate(parent)
+ {}
+ virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
+ {
+ QLineEdit *lineEdit = new QLineEdit(parent);
+ lineEdit->setFrame(false);
+ QCompleter *completer = new QCompleter(QStringList() << "completer", lineEdit);
+ completer->setCompletionMode(QCompleter::InlineCompletion);
+ lineEdit->setCompleter(completer);
+ return lineEdit;
+ }
+};
+
+void tst_QListWidget::QTBUG14363_completerWithAnyKeyPressedEditTriggers()
+{
+ QListWidget listWidget;
+ listWidget.setEditTriggers(QAbstractItemView::AnyKeyPressed);
+ listWidget.setItemDelegate(new ItemDelegate);
+ QListWidgetItem *item = new QListWidgetItem(QLatin1String("select an item (don't start editing)"), &listWidget);
+ item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable);
+ new QListWidgetItem(QLatin1String("try to type the letter 'c'"), &listWidget);
+ new QListWidgetItem(QLatin1String("completer"), &listWidget);
+ listWidget.show();
+ listWidget.setCurrentItem(item);
+ QTest::qWaitForWindowShown(&listWidget);
+
+ QTest::keyClick(listWidget.viewport(), Qt::Key_C);
+
+ QLineEdit *le = qobject_cast<QLineEdit*>(listWidget.itemWidget(item));
+ QVERIFY(le);
+ QCOMPARE(le->text(), QString("completer"));
+ QCOMPARE(le->completer()->currentCompletion(), QString("completer"));
+}
+
+
+
+QTEST_MAIN(tst_QListWidget)
+#include "tst_qlistwidget.moc"
diff --git a/tests/auto/widgets/itemviews/qsortfilterproxymodel/.gitignore b/tests/auto/widgets/itemviews/qsortfilterproxymodel/.gitignore
new file mode 100644
index 0000000000..d3672fe4ae
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qsortfilterproxymodel/.gitignore
@@ -0,0 +1 @@
+tst_qsortfilterproxymodel
diff --git a/tests/auto/widgets/itemviews/qsortfilterproxymodel/qsortfilterproxymodel.pro b/tests/auto/widgets/itemviews/qsortfilterproxymodel/qsortfilterproxymodel.pro
new file mode 100644
index 0000000000..65207b6563
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qsortfilterproxymodel/qsortfilterproxymodel.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+
+QT += gui widgets
+mtdir = ../../../integrationtests/modeltest
+
+INCLUDEPATH += $$PWD/$${mtdir}
+SOURCES += tst_qsortfilterproxymodel.cpp $${mtdir}/dynamictreemodel.cpp $${mtdir}/modeltest.cpp
+HEADERS += $${mtdir}/dynamictreemodel.h $${mtdir}/modeltest.h
diff --git a/tests/auto/widgets/itemviews/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/widgets/itemviews/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
new file mode 100644
index 0000000000..96f7249e3c
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
@@ -0,0 +1,3274 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include "dynamictreemodel.h"
+#include "modeltest.h"
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWidgets>
+
+#include <qdebug.h>
+
+//TESTED CLASS=
+//TESTED_FILES=
+
+typedef QList<int> IntList;
+typedef QPair<int, int> IntPair;
+typedef QList<IntPair> IntPairList;
+
+Q_DECLARE_METATYPE(IntList)
+Q_DECLARE_METATYPE(IntPair)
+Q_DECLARE_METATYPE(IntPairList)
+Q_DECLARE_METATYPE(QModelIndex)
+
+class tst_QSortFilterProxyModel : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ tst_QSortFilterProxyModel();
+ virtual ~tst_QSortFilterProxyModel();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void getSetCheck();
+ void sort_data();
+ void sort();
+ void sortHierarchy_data();
+ void sortHierarchy();
+
+ void insertRows_data();
+ void insertRows();
+ void prependRow();
+// void insertColumns_data();
+// void insertColumns();
+ void removeRows_data();
+ void removeRows();
+ void removeColumns_data();
+ void removeColumns();
+ void insertAfterSelect();
+ void removeAfterSelect();
+ void filter_data();
+ void filter();
+ void filterHierarchy_data();
+ void filterHierarchy();
+ void filterColumns_data();
+ void filterColumns();
+
+ void filterTable();
+// void filterCurrent();
+
+ void changeSourceLayout();
+ void removeSourceRows_data();
+ void removeSourceRows();
+ void insertSourceRows_data();
+ void insertSourceRows();
+ void changeFilter_data();
+ void changeFilter();
+ void changeSourceData_data();
+ void changeSourceData();
+ void sortFilterRole();
+ void selectionFilteredOut();
+ void match_data();
+ void match();
+ void insertIntoChildrenlessItem();
+ void invalidateMappedChildren();
+ void insertRowIntoFilteredParent();
+ void filterOutParentAndFilterInChild();
+
+ void sourceInsertRows();
+ void sourceModelDeletion();
+
+ void sortColumnTracking1();
+ void sortColumnTracking2();
+
+ void sortStable();
+
+ void task236755_hiddenColumns();
+ void task247867_insertRowsSort();
+ void task248868_staticSorting();
+ void task248868_dynamicSorting();
+ void task250023_fetchMore();
+ void task251296_hiddenChildren();
+ void task252507_mapFromToSource();
+ void task255652_removeRowsRecursive();
+ void taskQTBUG_6205_doubleProxySelectionSetSourceModel();
+ void taskQTBUG_7537_appearsAndSort();
+ void taskQTBUG_7716_unnecessaryDynamicSorting();
+ void taskQTBUG_10287_unnecessaryMapCreation();
+ void taskQTBUG_17812_resetInvalidate_data();
+ void taskQTBUG_17812_resetInvalidate();
+
+ void testMultipleProxiesWithSelection();
+ void mapSelectionFromSource();
+ void filteredColumns();
+
+protected:
+ void buildHierarchy(const QStringList &data, QAbstractItemModel *model);
+ void checkHierarchy(const QStringList &data, const QAbstractItemModel *model);
+
+private:
+ QStandardItemModel *m_model;
+ QSortFilterProxyModel *m_proxy;
+};
+
+// Testing get/set functions
+void tst_QSortFilterProxyModel::getSetCheck()
+{
+ QSortFilterProxyModel obj1;
+ QCOMPARE(obj1.sourceModel(), (QAbstractItemModel *)0);
+ // int QSortFilterProxyModel::filterKeyColumn()
+ // void QSortFilterProxyModel::setFilterKeyColumn(int)
+ obj1.setFilterKeyColumn(0);
+ QCOMPARE(0, obj1.filterKeyColumn());
+ obj1.setFilterKeyColumn(INT_MIN);
+ QCOMPARE(INT_MIN, obj1.filterKeyColumn());
+ obj1.setFilterKeyColumn(INT_MAX);
+ QCOMPARE(INT_MAX, obj1.filterKeyColumn());
+}
+
+tst_QSortFilterProxyModel::tst_QSortFilterProxyModel()
+ : m_model(0), m_proxy(0)
+{
+
+}
+
+tst_QSortFilterProxyModel::~tst_QSortFilterProxyModel()
+{
+
+}
+
+void tst_QSortFilterProxyModel::initTestCase()
+{
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+ qRegisterMetaType<IntList>("IntList");
+ qRegisterMetaType<IntPair>("IntPair");
+ qRegisterMetaType<IntPairList>("IntPairList");
+ m_model = new QStandardItemModel(0, 1);
+ m_proxy = new QSortFilterProxyModel();
+ m_proxy->setSourceModel(m_model);
+}
+
+void tst_QSortFilterProxyModel::cleanupTestCase()
+{
+ delete m_proxy;
+ delete m_model;
+}
+
+void tst_QSortFilterProxyModel::init()
+{
+}
+
+void tst_QSortFilterProxyModel::cleanup()
+{
+ m_proxy->setFilterRegExp(QRegExp());
+ m_proxy->sort(-1, Qt::AscendingOrder);
+ m_model->clear();
+ m_model->insertColumns(0, 1);
+}
+
+/*
+ tests
+*/
+
+void tst_QSortFilterProxyModel::sort_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<int>("sortCaseSensitivity");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+ QTest::newRow("flat descending") << static_cast<int>(Qt::DescendingOrder)
+ << int(Qt::CaseSensitive)
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima"
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel"
+ << "uniform"
+ << "alpha"
+ << "echo"
+ << "golf"
+ << "quebec"
+ << "foxtrot"
+ << "india"
+ << "romeo"
+ << "november"
+ << "oskar"
+ << "zulu"
+ << "kilo"
+ << "whiskey"
+ << "mike"
+ << "papa"
+ << "sierra"
+ << "xray"
+ << "viktor")
+ << (QStringList()
+ << "zulu"
+ << "yankee"
+ << "xray"
+ << "whiskey"
+ << "viktor"
+ << "uniform"
+ << "tango"
+ << "sierra"
+ << "romeo"
+ << "quebec"
+ << "papa"
+ << "oskar"
+ << "november"
+ << "mike"
+ << "lima"
+ << "kilo"
+ << "juliet"
+ << "india"
+ << "hotel"
+ << "golf"
+ << "foxtrot"
+ << "echo"
+ << "delta"
+ << "charlie"
+ << "bravo"
+ << "alpha");
+ QTest::newRow("flat ascending") << static_cast<int>(Qt::AscendingOrder)
+ << int(Qt::CaseSensitive)
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima"
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel"
+ << "uniform"
+ << "alpha"
+ << "echo"
+ << "golf"
+ << "quebec"
+ << "foxtrot"
+ << "india"
+ << "romeo"
+ << "november"
+ << "oskar"
+ << "zulu"
+ << "kilo"
+ << "whiskey"
+ << "mike"
+ << "papa"
+ << "sierra"
+ << "xray"
+ << "viktor")
+ << (QStringList()
+ << "alpha"
+ << "bravo"
+ << "charlie"
+ << "delta"
+ << "echo"
+ << "foxtrot"
+ << "golf"
+ << "hotel"
+ << "india"
+ << "juliet"
+ << "kilo"
+ << "lima"
+ << "mike"
+ << "november"
+ << "oskar"
+ << "papa"
+ << "quebec"
+ << "romeo"
+ << "sierra"
+ << "tango"
+ << "uniform"
+ << "viktor"
+ << "whiskey"
+ << "xray"
+ << "yankee"
+ << "zulu");
+ QTest::newRow("case insensitive") << static_cast<int>(Qt::AscendingOrder)
+ << int(Qt::CaseInsensitive)
+ << (QStringList()
+ << "alpha" << "BETA" << "Gamma" << "delta")
+ << (QStringList()
+ << "alpha" << "BETA" << "delta" << "Gamma");
+ QTest::newRow("case sensitive") << static_cast<int>(Qt::AscendingOrder)
+ << int(Qt::CaseSensitive)
+ << (QStringList()
+ << "alpha" << "BETA" << "Gamma" << "delta")
+ << (QStringList()
+ << "BETA" << "Gamma" << "alpha" << "delta");
+
+
+ QStringList list;
+ for (int i = 10000; i < 20000; ++i)
+ list.append(QString("Number: %1").arg(i));
+ QTest::newRow("large set ascending") << static_cast<int>(Qt::AscendingOrder) << int(Qt::CaseSensitive) << list << list;
+}
+
+void tst_QSortFilterProxyModel::sort()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(int, sortCaseSensitivity);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+
+ // prepare model
+ QStandardItem *root = m_model->invisibleRootItem ();
+ QList<QStandardItem *> items;
+ for (int i = 0; i < initial.count(); ++i) {
+ items.append(new QStandardItem(initial.at(i)));
+ }
+ root->insertRows(0, items);
+ QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
+ QCOMPARE(m_model->columnCount(QModelIndex()), 1);
+
+ // make sure the proxy is unsorted
+ QCOMPARE(m_proxy->columnCount(QModelIndex()), 1);
+ QCOMPARE(m_proxy->rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ // sort
+ m_proxy->sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ m_proxy->setSortCaseSensitivity(static_cast<Qt::CaseSensitivity>(sortCaseSensitivity));
+
+ // make sure the model is unchanged
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+ // make sure the proxy is sorted
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ // restore the unsorted order
+ m_proxy->sort(-1);
+
+ // make sure the proxy is unsorted again
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+}
+
+void tst_QSortFilterProxyModel::sortHierarchy_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+#if 1
+ QTest::newRow("flat ascending")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList()
+ << "c" << "f" << "d" << "e" << "a" << "b")
+ << (QStringList()
+ << "a" << "b" << "c" << "d" << "e" << "f");
+#endif
+ QTest::newRow("simple hierarchy")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">")
+ << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">");
+
+#if 1
+ QTest::newRow("hierarchical ascending")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList()
+ << "c"
+ << "<"
+ << "h"
+ << "<"
+ << "2"
+ << "0"
+ << "1"
+ << ">"
+ << "g"
+ << "i"
+ << ">"
+ << "b"
+ << "<"
+ << "l"
+ << "k"
+ << "<"
+ << "8"
+ << "7"
+ << "9"
+ << ">"
+ << "m"
+ << ">"
+ << "a"
+ << "<"
+ << "z"
+ << "y"
+ << "x"
+ << ">")
+ << (QStringList()
+ << "a"
+ << "<"
+ << "x"
+ << "y"
+ << "z"
+ << ">"
+ << "b"
+ << "<"
+ << "k"
+ << "<"
+ << "7"
+ << "8"
+ << "9"
+ << ">"
+ << "l"
+ << "m"
+ << ">"
+ << "c"
+ << "<"
+ << "g"
+ << "h"
+ << "<"
+ << "0"
+ << "1"
+ << "2"
+ << ">"
+ << "i"
+ << ">");
+#endif
+}
+
+void tst_QSortFilterProxyModel::sortHierarchy()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+
+ buildHierarchy(initial, m_model);
+ checkHierarchy(initial, m_model);
+ checkHierarchy(initial, m_proxy);
+ m_proxy->sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ checkHierarchy(initial, m_model);
+ checkHierarchy(expected, m_proxy);
+}
+
+void tst_QSortFilterProxyModel::insertRows_data()
+{
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+ QTest::addColumn<QStringList>("insert");
+ QTest::addColumn<int>("position");
+
+ QTest::newRow("insert one row in the middle")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ << "Three")
+ << 2;
+
+ QTest::newRow("insert one row in the begining")
+ << (QStringList()
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ << "One")
+ << 0;
+
+ QTest::newRow("insert one row in the end")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ <<"Five")
+ << 4;
+}
+
+void tst_QSortFilterProxyModel::insertRows()
+{
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ QFETCH(QStringList, insert);
+ QFETCH(int, position);
+ // prepare model
+ m_model->insertRows(0, initial.count(), QModelIndex());
+ //m_model->insertColumns(0, 1, QModelIndex());
+ QCOMPARE(m_model->columnCount(QModelIndex()), 1);
+ QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ m_model->setData(index, initial.at(row), Qt::DisplayRole);
+ }
+ // make sure the model correct before insert
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+ // make sure the proxy is correct before insert
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ // insert the row
+ m_proxy->insertRows(position, insert.count(), QModelIndex());
+ QCOMPARE(m_model->rowCount(QModelIndex()), expected.count());
+ QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count());
+
+ // set the data for the inserted row
+ for (int i = 0; i < insert.count(); ++i) {
+ QModelIndex index = m_proxy->index(position + i, 0, QModelIndex());
+ m_proxy->setData(index, insert.at(i), Qt::DisplayRole);
+ }
+
+ // make sure the model correct after insert
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ // make sure the proxy is correct after insert
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+void tst_QSortFilterProxyModel::prependRow()
+{
+ //this tests that data is correctly handled by the sort filter when prepending a row
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QStandardItem item("root");
+ model.appendRow(&item);
+
+ QStandardItem sub("sub");
+ item.appendRow(&sub);
+
+ sub.appendRow(new QStandardItem("test1"));
+ sub.appendRow(new QStandardItem("test2"));
+
+ QStandardItem sub2("sub2");
+ sub2.appendRow(new QStandardItem("sub3"));
+ item.insertRow(0, &sub2);
+
+ QModelIndex index_sub2 = proxy.mapFromSource(model.indexFromItem(&sub2));
+
+ QCOMPARE(sub2.rowCount(), proxy.rowCount(index_sub2));
+ QCOMPARE(proxy.rowCount(QModelIndex()), 1); //only the "root" item is there
+}
+
+
+/*
+void tst_QSortFilterProxyModel::insertColumns_data()
+{
+
+}
+
+void tst_QSortFilterProxyModel::insertColumns()
+{
+
+}
+*/
+
+void tst_QSortFilterProxyModel::removeRows_data()
+{
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<int>("position");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<bool>("success");
+ QTest::addColumn<QStringList>("expectedProxy");
+ QTest::addColumn<QStringList>("expectedSource");
+
+ QTest::newRow("remove one row in the middle [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove one row in the beginning [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 0 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove one row in the end [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 4 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four");
+
+ QTest::newRow("remove all [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 0 // position
+ << 5 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << QStringList(); // expectedSource
+
+ QTest::newRow("remove one row past the end [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 5 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove row -1 [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << -1 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove three rows in the middle [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 1 // position
+ << 3 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Five");
+
+ QTest::newRow("remove one row in the middle [ascending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QString() // no filter
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "2"
+ << "4");
+
+ QTest::newRow("remove two rows in the middle [ascending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QString() // no filter
+ << 2 // position
+ << 2 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "2");
+
+ QTest::newRow("remove two rows in the middle [descending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QString() // no filter
+ << 2 // position
+ << 2 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "5"
+ << "4"
+ << "1")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "4");
+
+ QTest::newRow("remove one row in the middle [no sorting, filter=5|2|3]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << -1 // no sorting
+ << QString("5|2|3")
+ << 1 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "5"
+ << "3")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "4"
+ << "3");
+
+ QTest::newRow("remove all [ascending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QString() // no filter
+ << 0 // position
+ << 5 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << QStringList(); // expectedSource
+}
+
+void tst_QSortFilterProxyModel::removeRows()
+{
+ QFETCH(QStringList, initial);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, filter);
+ QFETCH(int, position);
+ QFETCH(int, count);
+ QFETCH(bool, success);
+ QFETCH(QStringList, expectedProxy);
+ QFETCH(QStringList, expectedSource);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ // prepare model
+ foreach (QString s, initial)
+ model.appendRow(new QStandardItem(s));
+
+ if (sortOrder != -1)
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ if (!filter.isEmpty())
+ proxy.setFilterRegExp(QRegExp(filter));
+
+ // remove the rows
+ QCOMPARE(proxy.removeRows(position, count, QModelIndex()), success);
+ QCOMPARE(model.rowCount(QModelIndex()), expectedSource.count());
+ QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxy.count());
+
+ // make sure the model is correct after remove
+ for (int row = 0; row < model.rowCount(QModelIndex()); ++row)
+ QCOMPARE(model.item(row)->text(), expectedSource.at(row));
+
+ // make sure the proxy is correct after remove
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expectedProxy.at(row));
+ }
+}
+
+class MyFilteredColumnProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ MyFilteredColumnProxyModel(QObject *parent = 0)
+ : QSortFilterProxyModel(parent) { }
+protected:
+ bool filterAcceptsColumn(int sourceColumn, const QModelIndex &) const
+ {
+ QString key = sourceModel()->headerData(sourceColumn, Qt::Horizontal).toString();
+ return key.contains(filterRegExp());
+ }
+};
+
+void tst_QSortFilterProxyModel::removeColumns_data()
+{
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<int>("position");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<bool>("success");
+ QTest::addColumn<QStringList>("expectedProxy");
+ QTest::addColumn<QStringList>("expectedSource");
+
+ QTest::newRow("remove one column in the middle [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove one column in the end [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 4 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "3"
+ << "4")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4");
+
+ QTest::newRow("remove one column past the end [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 5 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove column -1 [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << -1 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove all columns [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 0 // position
+ << 5 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << QStringList(); // expectedSource
+
+ QTest::newRow("remove one column in the middle [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 1 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove one column in the end [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "3")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4");
+
+ QTest::newRow("remove one column past the end [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 3 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "3"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove all columns [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 0 // position
+ << 3 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << (QStringList() // expectedSource
+ << "2"
+ << "4");
+}
+
+void tst_QSortFilterProxyModel::removeColumns()
+{
+ QFETCH(QStringList, initial);
+ QFETCH(QString, filter);
+ QFETCH(int, position);
+ QFETCH(int, count);
+ QFETCH(bool, success);
+ QFETCH(QStringList, expectedProxy);
+ QFETCH(QStringList, expectedSource);
+
+ QStandardItemModel model;
+ MyFilteredColumnProxyModel proxy;
+ proxy.setSourceModel(&model);
+ if (!filter.isEmpty())
+ proxy.setFilterRegExp(QRegExp(filter));
+
+ // prepare model
+ model.setHorizontalHeaderLabels(initial);
+
+ // remove the columns
+ QCOMPARE(proxy.removeColumns(position, count, QModelIndex()), success);
+ QCOMPARE(model.columnCount(QModelIndex()), expectedSource.count());
+ QCOMPARE(proxy.columnCount(QModelIndex()), expectedProxy.count());
+
+ // make sure the model is correct after remove
+ for (int col = 0; col < model.columnCount(QModelIndex()); ++col)
+ QCOMPARE(model.horizontalHeaderItem(col)->text(), expectedSource.at(col));
+
+ // make sure the proxy is correct after remove
+ for (int col = 0; col < proxy.columnCount(QModelIndex()); ++col) {
+ QCOMPARE(proxy.headerData(col, Qt::Horizontal, Qt::DisplayRole).toString(),
+ expectedProxy.at(col));
+ }
+}
+
+
+void tst_QSortFilterProxyModel::filterColumns_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<bool>("data");
+
+ QTest::newRow("all") << "a"
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima")
+ << true;
+
+ QTest::newRow("some") << "lie"
+ << (QStringList()
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel")
+ << true;
+
+ QTest::newRow("nothing") << "zoo"
+ << (QStringList()
+ << "foxtrot"
+ << "uniform"
+ << "alpha"
+ << "golf")
+ << false;
+}
+
+void tst_QSortFilterProxyModel::filterColumns()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, initial);
+ QFETCH(bool, data);
+ // prepare model
+ m_model->setColumnCount(initial.count());
+ m_model->setRowCount(1);
+ QCOMPARE(m_model->columnCount(QModelIndex()), initial.count());
+ QCOMPARE(m_model->rowCount(QModelIndex()), 1);
+ // set data
+ QCOMPARE(m_model->rowCount(QModelIndex()), 1);
+ for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) {
+ QModelIndex index = m_model->index(0, col, QModelIndex());
+ m_model->setData(index, initial.at(col), Qt::DisplayRole);
+ }
+ m_proxy->setFilterRegExp(pattern);
+ m_proxy->setFilterKeyColumn(-1);
+ // make sure the model is unchanged
+ for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) {
+ QModelIndex index = m_model->index(0, col, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(col));
+ }
+ // make sure the proxy is filtered
+ QModelIndex index = m_proxy->index(0, 0, QModelIndex());
+ QCOMPARE(index.isValid(), data);
+}
+
+void tst_QSortFilterProxyModel::filter_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+ QTest::newRow("flat") << "e"
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima"
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel"
+ << "uniform"
+ << "alpha"
+ << "echo"
+ << "golf"
+ << "quebec"
+ << "foxtrot"
+ << "india"
+ << "romeo"
+ << "november"
+ << "oskar"
+ << "zulu"
+ << "kilo"
+ << "whiskey"
+ << "mike"
+ << "papa"
+ << "sierra"
+ << "xray"
+ << "viktor")
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "charlie"
+ << "juliet"
+ << "hotel"
+ << "echo"
+ << "quebec"
+ << "romeo"
+ << "november"
+ << "whiskey"
+ << "mike"
+ << "sierra");
+}
+
+void tst_QSortFilterProxyModel::filter()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ // prepare model
+ QVERIFY(m_model->insertRows(0, initial.count(), QModelIndex()));
+ QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
+ // set data
+ QCOMPARE(m_model->columnCount(QModelIndex()), 1);
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ m_model->setData(index, initial.at(row), Qt::DisplayRole);
+ }
+ m_proxy->setFilterRegExp(pattern);
+ // make sure the proxy is unfiltered
+ QCOMPARE(m_proxy->columnCount(QModelIndex()), 1);
+ QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count());
+ // make sure the model is unchanged
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+ // make sure the proxy is filtered
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+void tst_QSortFilterProxyModel::filterHierarchy_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+ QTest::newRow("flat") << ".*oo"
+ << (QStringList()
+ << "foo" << "boo" << "baz" << "moo" << "laa" << "haa")
+ << (QStringList()
+ << "foo" << "boo" << "moo");
+
+ QTest::newRow("simple hierarchy") << "b.*z"
+ << (QStringList() << "baz" << "<" << "boz" << "<" << "moo" << ">" << ">")
+ << (QStringList() << "baz" << "<" << "boz" << ">");
+#if 0
+ QTest::newRow("hierarchical")
+ << (QStringList()
+ << "a"
+ << "<"
+ << "x"
+ << "y"
+ << "z"
+ << ">"
+ << "b"
+ << "<"
+ << "k"
+ << "<"
+ << "7"
+ << "8"
+ << "9"
+ << ">"
+ << "l"
+ << "m"
+ << ">"
+ << "c"
+ << "<"
+ << "g"
+ << "h"
+ << "<"
+ << "0"
+ << "1"
+ << "2"
+ << ">"
+ << "i"
+ << ">")
+ << (QStringList()
+ << "a"
+ << "<"
+ << "x"
+ << "z"
+ << ">"
+ << "c"
+ << "<"
+ << "g"
+ << "i"
+ << ">");
+#endif
+}
+
+void tst_QSortFilterProxyModel::filterHierarchy()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ buildHierarchy(initial, m_model);
+ m_proxy->setFilterRegExp(pattern);
+ checkHierarchy(initial, m_model);
+ checkHierarchy(expected, m_proxy);
+}
+
+void tst_QSortFilterProxyModel::buildHierarchy(const QStringList &l, QAbstractItemModel *m)
+{
+ int ind = 0;
+ int row = 0;
+ QStack<int> row_stack;
+ QModelIndex parent;
+ QStack<QModelIndex> parent_stack;
+ for (int i = 0; i < l.count(); ++i) {
+ QString token = l.at(i);
+ if (token == "<") { // start table
+ ++ind;
+ parent_stack.push(parent);
+ row_stack.push(row);
+ parent = m->index(row - 1, 0, parent);
+ row = 0;
+ QVERIFY(m->insertColumns(0, 1, parent)); // add column
+ } else if (token == ">") { // end table
+ --ind;
+ parent = parent_stack.pop();
+ row = row_stack.pop();
+ } else { // append row
+ QVERIFY(m->insertRows(row, 1, parent));
+ QModelIndex index = m->index(row, 0, parent);
+ QVERIFY(index.isValid());
+ m->setData(index, token, Qt::DisplayRole);
+ ++row;
+#if 0
+ {
+ QString txt = token;
+ for (int t = 0; t < ind; ++t)
+ txt.prepend(' ');
+ qDebug() << "#" << txt;
+ }
+#endif
+ }
+ }
+}
+
+void tst_QSortFilterProxyModel::checkHierarchy(const QStringList &l, const QAbstractItemModel *m)
+{
+ int row = 0;
+ int indent = 0;
+ QStack<int> row_stack;
+ QModelIndex parent;
+ QStack<QModelIndex> parent_stack;
+ for (int i = 0; i < l.count(); ++i) {
+ QString token = l.at(i);
+ if (token == "<") { // start table
+ ++indent;
+ parent_stack.push(parent);
+ row_stack.push(row);
+ parent = m->index(row - 1, 0, parent);
+ QVERIFY(parent.isValid());
+ row = 0;
+ } else if (token == ">") { // end table
+ --indent;
+ parent = parent_stack.pop();
+ row = row_stack.pop();
+ } else { // compare row
+ QModelIndex index = m->index(row, 0, parent);
+ QVERIFY(index.isValid());
+ QString str = m->data(index, Qt::DisplayRole).toString();
+#if 0
+ qDebug() << "proxy data is" << str << "level" << indent;
+#endif
+ QCOMPARE(str, token);
+ ++row;
+ }
+ }
+
+}
+
+
+
+class TestModel: public QAbstractTableModel
+{
+public:
+ int rowCount(const QModelIndex &) const { return 10000; }
+ int columnCount(const QModelIndex &) const { return 1; }
+ QVariant data(const QModelIndex &index, int role) const
+ {
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ return QString::number(index.row());
+ }
+};
+
+void tst_QSortFilterProxyModel::filterTable()
+{
+ TestModel model;
+ QSortFilterProxyModel filter;
+ filter.setSourceModel(&model);
+ filter.setFilterRegExp("9");
+
+ for (int i = 0; i < filter.rowCount(); ++i)
+ QVERIFY(filter.data(filter.index(i, 0)).toString().contains("9"));
+}
+
+void tst_QSortFilterProxyModel::insertAfterSelect()
+{
+ QStandardItemModel model(10, 2);
+ for (int i = 0; i<10;i++)
+ model.setData(model.index(i, 0), QVariant(i));
+ QSortFilterProxyModel filter;
+ filter.setSourceModel(&model);
+ QTreeView view;
+ view.setModel(&filter);
+ view.show();
+ QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex()));
+ QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model());
+ QVERIFY(firstIndex.isValid());
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ QPoint p(itemOffset, 1);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
+ model.insertRows(5, 1, QModelIndex());
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection
+}
+
+void tst_QSortFilterProxyModel::removeAfterSelect()
+{
+ QStandardItemModel model(10, 2);
+ for (int i = 0; i<10;i++)
+ model.setData(model.index(i, 0), QVariant(i));
+ QSortFilterProxyModel filter;
+ filter.setSourceModel(&model);
+ QTreeView view;
+ view.setModel(&filter);
+ view.show();
+ QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex()));
+ QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model());
+ QVERIFY(firstIndex.isValid());
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ QPoint p(itemOffset, 1);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
+ model.removeRows(5, 1, QModelIndex());
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection
+}
+
+#if 0 // this test is disabled for now
+void tst_QSortFilterProxyModel::filterCurrent()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), QString("AAA"));
+ model.setData(model.index(1, 0), QString("BBB"));
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QTreeView view;
+
+ view.show();
+ view.setModel(&proxy);
+ QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)));
+
+ view.setCurrentIndex(proxy.index(0, 0));
+ QCOMPARE(spy.count(), 1);
+ proxy.setFilterRegExp(QRegExp("^B"));
+ QCOMPARE(spy.count(), 2);
+}
+#endif
+
+void tst_QSortFilterProxyModel::changeSourceLayout()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), QString("b"));
+ model.setData(model.index(1, 0), QString("a"));
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QList<QPersistentModelIndex> persistentSourceIndexes;
+ QList<QPersistentModelIndex> persistentProxyIndexes;
+ for (int row = 0; row < model.rowCount(); ++row) {
+ persistentSourceIndexes.append(model.index(row, 0));
+ persistentProxyIndexes.append(proxy.index(row, 0));
+ }
+
+ // change layout of source model
+ model.sort(0, Qt::AscendingOrder);
+
+ for (int row = 0; row < model.rowCount(); ++row) {
+ QCOMPARE(persistentProxyIndexes.at(row).row(),
+ persistentSourceIndexes.at(row).row());
+ }
+}
+
+void tst_QSortFilterProxyModel::removeSourceRows_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("start");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<IntPairList>("expectedRemovedProxyIntervals");
+ QTest::addColumn<QStringList>("expectedProxyItems");
+
+ QTest::newRow("remove one, no sorting")
+ << (QStringList() << "a" << "b") // sourceItems
+ << 0 // start
+ << 1 // count
+ << -1 // sortOrder (no sorting)
+ << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b") // expectedProxyItems
+ ;
+ QTest::newRow("remove one, ascending sort (same order)")
+ << (QStringList() << "a" << "b") // sourceItems
+ << 0 // start
+ << 1 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b") // expectedProxyItems
+ ;
+ QTest::newRow("remove one, ascending sort (reverse order)")
+ << (QStringList() << "b" << "a") // sourceItems
+ << 0 // start
+ << 1 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(1, 1)) // expectedRemovedIntervals
+ << (QStringList() << "a") // expectedProxyItems
+ ;
+ QTest::newRow("remove two, multiple proxy intervals")
+ << (QStringList() << "c" << "d" << "a" << "b") // sourceItems
+ << 1 // start
+ << 2 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(3, 3) << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b" << "c") // expectedProxyItems
+ ;
+ QTest::newRow("remove three, multiple proxy intervals")
+ << (QStringList() << "b" << "d" << "f" << "a" << "c" << "e") // sourceItems
+ << 3 // start
+ << 3 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(4, 4) << IntPair(2, 2) << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b" << "d" << "f") // expectedProxyItems
+ ;
+ QTest::newRow("remove all, single proxy intervals")
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
+ << 0 // start
+ << 6 // count
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << (IntPairList() << IntPair(0, 5)) // expectedRemovedIntervals
+ << QStringList() // expectedProxyItems
+ ;
+}
+
+// Check that correct proxy model rows are removed when rows are removed
+// from the source model
+void tst_QSortFilterProxyModel::removeSourceRows()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, start);
+ QFETCH(int, count);
+ QFETCH(int, sortOrder);
+ QFETCH(IntPairList, expectedRemovedProxyIntervals);
+ QFETCH(QStringList, expectedProxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex sindex = model.index(i, 0, QModelIndex());
+ model.setData(sindex, sourceItems.at(i), Qt::DisplayRole);
+ QModelIndex pindex = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(pindex, Qt::DisplayRole), model.data(sindex, Qt::DisplayRole));
+ }
+
+ if (sortOrder != -1)
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+ QSignalSpy aboutToRemoveSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)));
+ QSignalSpy aboutToInsertSpy(&proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)));
+
+ model.removeRows(start, count, QModelIndex());
+
+ QCOMPARE(aboutToRemoveSpy.count(), expectedRemovedProxyIntervals.count());
+ for (int i = 0; i < aboutToRemoveSpy.count(); ++i) {
+ QList<QVariant> args = aboutToRemoveSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second);
+ }
+ QCOMPARE(removeSpy.count(), expectedRemovedProxyIntervals.count());
+ for (int i = 0; i < removeSpy.count(); ++i) {
+ QList<QVariant> args = removeSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second);
+ }
+
+ QCOMPARE(insertSpy.count(), 0);
+ QCOMPARE(aboutToInsertSpy.count(), 0);
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxyItems.count());
+ for (int i = 0; i < expectedProxyItems.count(); ++i) {
+ QModelIndex pindex = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(pindex, Qt::DisplayRole).toString(), expectedProxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::insertSourceRows_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("start");
+ QTest::addColumn<QStringList>("newItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("proxyItems");
+
+ QTest::newRow("insert (1)")
+ << (QStringList() << "c" << "b") // sourceItems
+ << 1 // start
+ << (QStringList() << "a") // newItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (QStringList() << "a" << "b" << "c") // proxyItems
+ ;
+
+ QTest::newRow("insert (2)")
+ << (QStringList() << "d" << "b" << "c") // sourceItems
+ << 3 // start
+ << (QStringList() << "a") // newItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << (QStringList() << "d" << "c" << "b" << "a") // proxyItems
+ ;
+}
+
+// Check that rows are inserted at correct position in proxy model when
+// rows are inserted into the source model
+void tst_QSortFilterProxyModel::insertSourceRows()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, start);
+ QFETCH(QStringList, newItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, proxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(true);
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ model.insertRows(start, newItems.size(), QModelIndex());
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count());
+ for (int i = 0; i < newItems.count(); ++i) {
+ QModelIndex index = model.index(start + i, 0, QModelIndex());
+ model.setData(index, newItems.at(i), Qt::DisplayRole);
+ }
+
+ for (int i = 0; i < proxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::changeFilter_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("initialFilter");
+ QTest::addColumn<IntPairList>("initialRemoveIntervals");
+ QTest::addColumn<QStringList>("initialProxyItems");
+ QTest::addColumn<QString>("finalFilter");
+ QTest::addColumn<IntPairList>("finalRemoveIntervals");
+ QTest::addColumn<IntPairList>("insertIntervals");
+ QTest::addColumn<QStringList>("finalProxyItems");
+
+ QTest::newRow("filter (1)")
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|b|c" // initialFilter
+ << (IntPairList() << IntPair(3, 5)) // initialRemoveIntervals
+ << (QStringList() << "a" << "b" << "c") // initialProxyItems
+ << "b|d|f" // finalFilter
+ << (IntPairList() << IntPair(2, 2) << IntPair(0, 0)) // finalRemoveIntervals
+ << (IntPairList() << IntPair(1, 2)) // insertIntervals
+ << (QStringList() << "b" << "d" << "f") // finalProxyItems
+ ;
+
+ QTest::newRow("filter (2)")
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|c|e" // initialFilter
+ << (IntPairList() << IntPair(5, 5) << IntPair(3, 3) << IntPair(1, 1)) // initialRemoveIntervals
+ << (QStringList() << "a" << "c" << "e") // initialProxyItems
+ << "" // finalFilter
+ << IntPairList() // finalRemoveIntervals
+ << (IntPairList() << IntPair(3, 3) << IntPair(2, 2) << IntPair(1, 1)) // insertIntervals
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // finalProxyItems
+ ;
+
+ QTest::newRow("filter (3)")
+ << (QStringList() << "a" << "b" << "c") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a" // initialFilter
+ << (IntPairList() << IntPair(1, 2)) // initialRemoveIntervals
+ << (QStringList() << "a") // initialProxyItems
+ << "a" // finalFilter
+ << IntPairList() // finalRemoveIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "a") // finalProxyItems
+ ;
+}
+
+// Check that rows are added/removed when filter changes
+void tst_QSortFilterProxyModel::changeFilter()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, initialFilter);
+ QFETCH(IntPairList, initialRemoveIntervals);
+ QFETCH(QStringList, initialProxyItems);
+ QFETCH(QString, finalFilter);
+ QFETCH(IntPairList, finalRemoveIntervals);
+ QFETCH(IntPairList, insertIntervals);
+ QFETCH(QStringList, finalProxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ QSignalSpy initialRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy initialInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+
+ proxy.setFilterRegExp(initialFilter);
+
+ QCOMPARE(initialRemoveSpy.count(), initialRemoveIntervals.count());
+ QCOMPARE(initialInsertSpy.count(), 0);
+ for (int i = 0; i < initialRemoveSpy.count(); ++i) {
+ QList<QVariant> args = initialRemoveSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), initialRemoveIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), initialRemoveIntervals.at(i).second);
+ }
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), initialProxyItems.count());
+ for (int i = 0; i < initialProxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initialProxyItems.at(i));
+ }
+
+ QSignalSpy finalRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy finalInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+
+ proxy.setFilterRegExp(finalFilter);
+
+ QCOMPARE(finalRemoveSpy.count(), finalRemoveIntervals.count());
+ for (int i = 0; i < finalRemoveSpy.count(); ++i) {
+ QList<QVariant> args = finalRemoveSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), finalRemoveIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), finalRemoveIntervals.at(i).second);
+ }
+
+#ifdef Q_OS_IRIX
+ QEXPECT_FAIL("filter (2)", "Not reliable on IRIX", Abort);
+#endif
+ QCOMPARE(finalInsertSpy.count(), insertIntervals.count());
+ for (int i = 0; i < finalInsertSpy.count(); ++i) {
+ QList<QVariant> args = finalInsertSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second);
+ }
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), finalProxyItems.count());
+ for (int i = 0; i < finalProxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), finalProxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::changeSourceData_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<bool>("dynamic");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<QString>("newValue");
+ QTest::addColumn<IntPairList>("removeIntervals");
+ QTest::addColumn<IntPairList>("insertIntervals");
+ QTest::addColumn<QStringList>("proxyItems");
+
+ QTest::newRow("changeSourceData (1)")
+ << (QStringList() << "c" << "b" << "a") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << true // dynamic
+ << 2 // row
+ << "z" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "b" << "c" << "z") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (2)")
+ << (QStringList() << "b" << "c" << "z") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "" // filter
+ << true // dynamic
+ << 1 // row
+ << "a" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "z" << "b" << "a") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (3)")
+ << (QStringList() << "a" << "b") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "" // filter
+ << true // dynamic
+ << 0 // row
+ << "a" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "b" << "a") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (4)")
+ << (QStringList() << "a" << "b" << "c" << "d") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|c" // filter
+ << true // dynamic
+ << 1 // row
+ << "x" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "a" << "c") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (5)")
+ << (QStringList() << "a" << "b" << "c" << "d") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|c|x" // filter
+ << true // dynamic
+ << 1 // row
+ << "x" // newValue
+ << IntPairList() // removeIntervals
+ << (IntPairList() << IntPair(2, 2)) // insertIntervals
+ << (QStringList() << "a" << "c" << "x") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (6)")
+ << (QStringList() << "c" << "b" << "a") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << false // dynamic
+ << 2 // row
+ << "x" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "x" << "b" << "c") // proxyItems
+ ;
+}
+
+void tst_QSortFilterProxyModel::changeSourceData()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, filter);
+ QFETCH(bool, dynamic);
+ QFETCH(int, row);
+ QFETCH(QString, newValue);
+ QFETCH(IntPairList, removeIntervals);
+ QFETCH(IntPairList, insertIntervals);
+ QFETCH(QStringList, proxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setDynamicSortFilter(dynamic);
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ proxy.setFilterRegExp(filter);
+
+ QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+
+ {
+ QModelIndex index = model.index(row, 0, QModelIndex());
+ model.setData(index, newValue, Qt::DisplayRole);
+ }
+
+ QCOMPARE(removeSpy.count(), removeIntervals.count());
+ for (int i = 0; i < removeSpy.count(); ++i) {
+ QList<QVariant> args = removeSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), removeIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), removeIntervals.at(i).second);
+ }
+
+ QCOMPARE(insertSpy.count(), insertIntervals.count());
+ for (int i = 0; i < insertSpy.count(); ++i) {
+ QList<QVariant> args = insertSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second);
+ }
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count());
+ for (int i = 0; i < proxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::sortFilterRole()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+
+ QList<QPair<QVariant, QVariant> > sourceItems;
+ sourceItems = QList<QPair<QVariant, QVariant> >()
+ << QPair<QVariant, QVariant>("b", 3)
+ << QPair<QVariant, QVariant>("c", 2)
+ << QPair<QVariant, QVariant>("a", 1);
+
+ QList<int> orderedItems;
+ orderedItems = QList<int>()
+ << 2 << 1;
+
+ model.insertRows(0, sourceItems.count());
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i).first, Qt::DisplayRole);
+ model.setData(index, sourceItems.at(i).second, Qt::UserRole);
+ }
+
+ proxy.setFilterRegExp("2");
+ QCOMPARE(proxy.rowCount(), 0); // Qt::DisplayRole is default role
+
+ proxy.setFilterRole(Qt::UserRole);
+ QCOMPARE(proxy.rowCount(), 1);
+
+ proxy.setFilterRole(Qt::DisplayRole);
+ QCOMPARE(proxy.rowCount(), 0);
+
+ proxy.setFilterRegExp("1|2|3");
+ QCOMPARE(proxy.rowCount(), 0);
+
+ proxy.setFilterRole(Qt::UserRole);
+ QCOMPARE(proxy.rowCount(), 3);
+
+ proxy.sort(0, Qt::AscendingOrder);
+ QCOMPARE(proxy.rowCount(), 3);
+
+ proxy.setSortRole(Qt::UserRole);
+ proxy.setFilterRole(Qt::DisplayRole);
+ proxy.setFilterRegExp("a|c");
+ QCOMPARE(proxy.rowCount(), orderedItems.count());
+ for (int i = 0; i < proxy.rowCount(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole), sourceItems.at(orderedItems.at(i)).first);
+ }
+}
+
+void tst_QSortFilterProxyModel::selectionFilteredOut()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), QString("AAA"));
+ model.setData(model.index(1, 0), QString("BBB"));
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QTreeView view;
+
+ view.show();
+ view.setModel(&proxy);
+ QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)));
+
+ view.setCurrentIndex(proxy.index(0, 0));
+ QCOMPARE(spy.count(), 1);
+ proxy.setFilterRegExp(QRegExp("^B"));
+ QCOMPARE(spy.count(), 2);
+}
+
+void tst_QSortFilterProxyModel::match_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<int>("proxyStartRow");
+ QTest::addColumn<QString>("what");
+ QTest::addColumn<int>("matchFlags");
+ QTest::addColumn<IntList>("expectedProxyItems");
+ QTest::newRow("1")
+ << (QStringList() << "a") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << 0 // proxyStartRow
+ << "a" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 0); // expectedProxyItems
+ QTest::newRow("2")
+ << (QStringList() << "a" << "b") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << 0 // proxyStartRow
+ << "b" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 1); // expectedProxyItems
+ QTest::newRow("3")
+ << (QStringList() << "a" << "b") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "" // filter
+ << 0 // proxyStartRow
+ << "a" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 1); // expectedProxyItems
+ QTest::newRow("4")
+ << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << 1 // proxyStartRow
+ << "a" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << IntList(); // expectedProxyItems
+ QTest::newRow("5")
+ << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|b" // filter
+ << 0 // proxyStartRow
+ << "c" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << IntList(); // expectedProxyItems
+ QTest::newRow("6")
+ << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "a|b" // filter
+ << 0 // proxyStartRow
+ << "b" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 0); // expectedProxyItems
+}
+
+void tst_QSortFilterProxyModel::match()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, filter);
+ QFETCH(int, proxyStartRow);
+ QFETCH(QString, what);
+ QFETCH(int, matchFlags);
+ QFETCH(IntList, expectedProxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ proxy.setFilterRegExp(filter);
+
+ QModelIndex startIndex = proxy.index(proxyStartRow, 0);
+ QModelIndexList indexes = proxy.match(startIndex, Qt::DisplayRole, what,
+ expectedProxyItems.count(),
+ Qt::MatchFlags(matchFlags));
+ QCOMPARE(indexes.count(), expectedProxyItems.count());
+ for (int i = 0; i < indexes.count(); ++i)
+ QCOMPARE(indexes.at(i).row(), expectedProxyItems.at(i));
+}
+
+void tst_QSortFilterProxyModel::insertIntoChildrenlessItem()
+{
+ QStandardItemModel model;
+ QStandardItem *itemA = new QStandardItem("a");
+ model.appendRow(itemA);
+ QStandardItem *itemB = new QStandardItem("b");
+ model.appendRow(itemB);
+ QStandardItem *itemC = new QStandardItem("c");
+ model.appendRow(itemC);
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QSignalSpy colsInsertedSpy(&proxy, SIGNAL(columnsInserted(const QModelIndex&, int, int)));
+ QSignalSpy rowsInsertedSpy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
+
+ (void)proxy.rowCount(QModelIndex()); // force mapping of "a", "b", "c"
+ QCOMPARE(colsInsertedSpy.count(), 0);
+ QCOMPARE(rowsInsertedSpy.count(), 0);
+
+ // now add a child to itemB ==> should get insert notification from the proxy
+ itemB->appendRow(new QStandardItem("a.0"));
+ QCOMPARE(colsInsertedSpy.count(), 1);
+ QCOMPARE(rowsInsertedSpy.count(), 1);
+
+ QVariantList args = colsInsertedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index()));
+ QCOMPARE(qvariant_cast<int>(args.at(1)), 0);
+ QCOMPARE(qvariant_cast<int>(args.at(2)), 0);
+
+ args = rowsInsertedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index()));
+ QCOMPARE(qvariant_cast<int>(args.at(1)), 0);
+ QCOMPARE(qvariant_cast<int>(args.at(2)), 0);
+}
+
+void tst_QSortFilterProxyModel::invalidateMappedChildren()
+{
+ QStandardItemModel model;
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QStandardItem *itemA = new QStandardItem("a");
+ model.appendRow(itemA);
+ QStandardItem *itemB = new QStandardItem("b");
+ itemA->appendRow(itemB);
+
+ QStandardItem *itemC = new QStandardItem("c");
+ itemB->appendRow(itemC);
+ itemC->appendRow(new QStandardItem("d"));
+
+ // force mappings
+ (void)proxy.hasChildren(QModelIndex());
+ (void)proxy.hasChildren(proxy.mapFromSource(itemA->index()));
+ (void)proxy.hasChildren(proxy.mapFromSource(itemB->index()));
+ (void)proxy.hasChildren(proxy.mapFromSource(itemC->index()));
+
+ itemB->removeRow(0); // should invalidate mapping of itemC
+ itemC = new QStandardItem("c");
+ itemA->appendRow(itemC);
+ itemC->appendRow(new QStandardItem("d"));
+
+ itemA->removeRow(1); // should invalidate mapping of itemC
+ itemC = new QStandardItem("c");
+ itemB->appendRow(itemC);
+ itemC->appendRow(new QStandardItem("d"));
+
+ QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemA->index())), 1);
+ QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemB->index())), 1);
+ QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemC->index())), 1);
+}
+
+class EvenOddFilterModel : public QSortFilterProxyModel
+{
+public:
+ virtual bool filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const
+ {
+ if (srcParent.isValid())
+ return (srcParent.row() % 2) ^ !(srcRow % 2);
+ return (srcRow % 2);
+ }
+};
+
+void tst_QSortFilterProxyModel::insertRowIntoFilteredParent()
+{
+ QStandardItemModel model;
+ EvenOddFilterModel proxy;
+ proxy.setSourceModel(&model);
+
+ QSignalSpy spy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
+
+ QStandardItem *itemA = new QStandardItem();
+ model.appendRow(itemA); // A will be filtered
+ QStandardItem *itemB = new QStandardItem();
+ itemA->appendRow(itemB);
+
+ QCOMPARE(spy.count(), 0);
+
+ itemA->removeRow(0);
+
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QSortFilterProxyModel::filterOutParentAndFilterInChild()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ proxy.setFilterRegExp("A|B");
+ QStandardItem *itemA = new QStandardItem("A");
+ model.appendRow(itemA); // not filtered
+ QStandardItem *itemB = new QStandardItem("B");
+ itemA->appendRow(itemB); // not filtered
+ QStandardItem *itemC = new QStandardItem("C");
+ itemA->appendRow(itemC); // filtered
+
+ QSignalSpy removedSpy(&proxy, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));
+ QSignalSpy insertedSpy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
+
+ proxy.setFilterRegExp("C"); // A and B will be filtered out, C filtered in
+
+ // we should now have been notified that the subtree represented by itemA has been removed
+ QCOMPARE(removedSpy.count(), 1);
+ // we should NOT get any inserts; itemC should be filtered because its parent (itemA) is
+ QCOMPARE(insertedSpy.count(), 0);
+}
+
+void tst_QSortFilterProxyModel::sourceInsertRows()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ model.insertColumns(0, 1, QModelIndex());
+ model.insertRows(0, 2, QModelIndex());
+
+ {
+ QModelIndex parent = model.index(0, 0, QModelIndex());
+ model.insertColumns(0, 1, parent);
+ model.insertRows(0, 1, parent);
+ }
+
+ {
+ QModelIndex parent = model.index(1, 0, QModelIndex());
+ model.insertColumns(0, 1, parent);
+ model.insertRows(0, 1, parent);
+ }
+
+ model.insertRows(0, 1, QModelIndex());
+ model.insertRows(0, 1, QModelIndex());
+
+ QVERIFY(true); // if you got here without asserting, it's all good
+}
+
+void tst_QSortFilterProxyModel::sourceModelDeletion()
+{
+
+ QSortFilterProxyModel proxyModel;
+ {
+ QStandardItemModel model;
+ proxyModel.setSourceModel(&model);
+ QCOMPARE(proxyModel.sourceModel(), static_cast<QAbstractItemModel*>(&model));
+ }
+ QCOMPARE(proxyModel.sourceModel(), static_cast<QAbstractItemModel*>(0));
+
+}
+
+void tst_QSortFilterProxyModel::sortColumnTracking1()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ model.insertColumns(0, 10);
+ model.insertRows(0, 10);
+
+ proxyModel.sort(1);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.insertColumn(8);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.removeColumn(8);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.insertColumn(2);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.removeColumn(2);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.insertColumn(1);
+ QCOMPARE(proxyModel.sortColumn(), 2);
+
+ model.removeColumn(1);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.removeColumn(1);
+ QCOMPARE(proxyModel.sortColumn(), -1);
+}
+
+void tst_QSortFilterProxyModel::sortColumnTracking2()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setDynamicSortFilter(true);
+ proxyModel.setSourceModel(&model);
+
+ proxyModel.sort(0);
+ QCOMPARE(proxyModel.sortColumn(), 0);
+
+ QList<QStandardItem *> items;
+ QStringList strings;
+ strings << "foo" << "bar" << "some" << "others" << "item" << "aa" << "zz";
+ foreach (QString s, strings)
+ items << new QStandardItem(s);
+
+ model.insertColumn(0,items);
+ QCOMPARE(proxyModel.sortColumn(), 0);
+ QCOMPARE(proxyModel.data(proxyModel.index(0,0)).toString(),QString::fromLatin1("aa"));
+ QCOMPARE(proxyModel.data(proxyModel.index(strings.count()-1,0)).toString(),QString::fromLatin1("zz"));
+}
+
+void tst_QSortFilterProxyModel::sortStable()
+{
+ QStandardItemModel* model = new QStandardItemModel(5, 2);
+ for (int r=0; r<5; r++) {
+ for (int c=0; c<2; c++) {
+ QStandardItem* item = new QStandardItem(
+ QString("Row:%0, Column:%1").arg(r).arg(c) );
+ for( int i=0; i<3; i++ ) {
+ QStandardItem* child = new QStandardItem(
+ QString("Item %0").arg(i) );
+ item->appendRow( child );
+ }
+ model->setItem(r, c, item);
+ }
+ }
+ model->setHorizontalHeaderItem( 0, new QStandardItem( "Name" ));
+ model->setHorizontalHeaderItem( 1, new QStandardItem( "Value" ) );
+
+
+ QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(model);
+ filterModel->setSourceModel(model);
+
+ QTreeView *view = new QTreeView;
+ view->setModel(filterModel);
+ QModelIndex firstRoot = filterModel->index(0,0);
+ view->expand(firstRoot);
+ view->setSortingEnabled(true);
+
+ view->model()->sort(1, Qt::DescendingOrder);
+ QVariant lastItemData =filterModel->index(2,0, firstRoot).data();
+ view->model()->sort(1, Qt::DescendingOrder);
+ QCOMPARE(lastItemData, filterModel->index(2,0, firstRoot).data());
+}
+
+void tst_QSortFilterProxyModel::task236755_hiddenColumns()
+{
+ class MyStandardItemModel : public QStandardItemModel
+ {
+ public:
+ MyStandardItemModel() : QStandardItemModel(0,5) {}
+ void reset()
+ { QStandardItemModel::reset(); }
+ friend class tst_QSortFilterProxyModel;
+ } model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QTableView view;
+ view.setModel(&proxy);
+
+ view.hideColumn(0);
+
+ QVERIFY(view.isColumnHidden(0));
+ model.blockSignals(true);
+ model.setRowCount(1);
+ model.blockSignals(false);
+ model.reset();
+
+ //in the initial task this would be false because resetting
+ //model would also reset the hidden columns
+ QVERIFY(view.isColumnHidden(0));
+}
+
+void tst_QSortFilterProxyModel::task247867_insertRowsSort()
+{
+ QStandardItemModel model(2,2);
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ proxyModel.sort(0);
+ QCOMPARE(proxyModel.sortColumn(), 0);
+
+ model.insertColumns(0, 3, model.index(0,0));
+ QCOMPARE(proxyModel.sortColumn(), 0);
+
+ model.removeColumns(0, 3, model.index(0,0));
+ QCOMPARE(proxyModel.sortColumn(), 0);
+}
+
+void tst_QSortFilterProxyModel::task248868_staticSorting()
+{
+ QStandardItemModel model(0, 1);
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ proxy.setDynamicSortFilter(false);
+ QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" ");
+
+ // prepare model
+ QStandardItem *root = model.invisibleRootItem ();
+ QList<QStandardItem *> items;
+ for (int i = 0; i < initial.count(); ++i) {
+ items.append(new QStandardItem(initial.at(i)));
+ }
+ root->insertRows(0, items);
+ QCOMPARE(model.rowCount(QModelIndex()), initial.count());
+ QCOMPARE(model.columnCount(QModelIndex()), 1);
+
+ // make sure the proxy is unsorted
+ QCOMPARE(proxy.columnCount(QModelIndex()), 1);
+ QCOMPARE(proxy.rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ // sort
+ proxy.sort(0);
+
+ QStringList expected = initial;
+ expected.sort();
+ // make sure the proxy is sorted
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ //update one item.
+ model.setItem(0, 0, new QStandardItem("girafe"));
+
+ // make sure the proxy is updated but not sorted
+ expected.replaceInStrings("bateau", "girafe");
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ // sort again
+ proxy.sort(0);
+ expected.sort();
+
+ // make sure the proxy is sorted
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+}
+
+void tst_QSortFilterProxyModel::task248868_dynamicSorting()
+{
+ QStringListModel model1;
+ const QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" ");
+ model1.setStringList(initial);
+ QSortFilterProxyModel proxy1;
+ proxy1.sort(0);
+ proxy1.setSourceModel(&model1);
+
+ QCOMPARE(proxy1.columnCount(QModelIndex()), 1);
+ //the model should not be sorted because sorting has not been set to dynamic yet.
+ QCOMPARE(proxy1.rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ proxy1.setDynamicSortFilter(true);
+
+ //now the model should be sorted.
+ QStringList expected = initial;
+ expected.sort();
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ QStringList initial2 = initial;
+ initial2.replaceInStrings("bateau", "girafe");
+ model1.setStringList(initial2); //this will cause a reset
+
+ QStringList expected2 = initial2;
+ expected2.sort();
+
+ //now the model should still be sorted.
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected2.at(row));
+ }
+
+ QStringListModel model2(initial);
+ proxy1.setSourceModel(&model2);
+
+ //the model should again be sorted
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ //set up the sorting before seting the model up
+ QSortFilterProxyModel proxy2;
+ proxy2.setDynamicSortFilter(true);
+ proxy2.sort(0);
+ proxy2.setSourceModel(&model2);
+ for (int row = 0; row < proxy2.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy2.index(row, 0, QModelIndex());
+ QCOMPARE(proxy2.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+class QtTestModel: public QAbstractItemModel
+{
+ public:
+ QtTestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
+ rows(_rows), cols(_cols), wrongIndex(false) { }
+
+ bool canFetchMore(const QModelIndex &idx) const {
+ return !fetched.contains(idx);
+ }
+
+ void fetchMore(const QModelIndex &idx) {
+ if (fetched.contains(idx))
+ return;
+ beginInsertRows(idx, 0, rows-1);
+ fetched.insert(idx);
+ endInsertRows();
+ }
+
+ bool hasChildren(const QModelIndex & = QModelIndex()) const {
+ return true;
+ }
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const {
+ return fetched.contains(parent) ? rows : 0;
+ }
+ int columnCount(const QModelIndex& parent = QModelIndex()) const {
+ Q_UNUSED(parent);
+ return cols;
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
+ {
+ if (row < 0 || column < 0 || column >= cols || row >= rows) {
+ return QModelIndex();
+ }
+ QModelIndex i = createIndex(row, column, int(parent.internalId() + 1));
+ parentHash[i] = parent;
+ return i;
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ if (!parentHash.contains(index))
+ return QModelIndex();
+ return parentHash[index];
+ }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (!idx.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
+ wrongIndex = true;
+ qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
+ idx.internalPointer());
+ }
+ return QString("[%1,%2]").arg(idx.row()).arg(idx.column());
+ }
+ return QVariant();
+ }
+
+ QSet<QModelIndex> fetched;
+ int rows, cols;
+ mutable bool wrongIndex;
+ mutable QMap<QModelIndex,QModelIndex> parentHash;
+};
+
+void tst_QSortFilterProxyModel::task250023_fetchMore()
+{
+ QtTestModel model(10,10);
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QVERIFY(proxy.canFetchMore(QModelIndex()));
+ QVERIFY(proxy.hasChildren());
+ while (proxy.canFetchMore(QModelIndex()))
+ proxy.fetchMore(QModelIndex());
+ QCOMPARE(proxy.rowCount(), 10);
+ QCOMPARE(proxy.columnCount(), 10);
+
+ QModelIndex idx = proxy.index(1,1);
+ QVERIFY(idx.isValid());
+ QVERIFY(proxy.canFetchMore(idx));
+ QVERIFY(proxy.hasChildren(idx));
+ while (proxy.canFetchMore(idx))
+ proxy.fetchMore(idx);
+ QCOMPARE(proxy.rowCount(idx), 10);
+ QCOMPARE(proxy.columnCount(idx), 10);
+}
+
+void tst_QSortFilterProxyModel::task251296_hiddenChildren()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ proxy.setDynamicSortFilter(true);
+
+ QStandardItem *itemA = new QStandardItem("A VISIBLE");
+ model.appendRow(itemA);
+ QStandardItem *itemB = new QStandardItem("B VISIBLE");
+ itemA->appendRow(itemB);
+ QStandardItem *itemC = new QStandardItem("C");
+ itemA->appendRow(itemC);
+ proxy.setFilterRegExp("VISIBLE");
+
+ QCOMPARE(proxy.rowCount(QModelIndex()) , 1);
+ QPersistentModelIndex indexA = proxy.index(0,0);
+ QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("A VISIBLE"));
+
+ QCOMPARE(proxy.rowCount(indexA) , 1);
+ QPersistentModelIndex indexB = proxy.index(0, 0, indexA);
+ QCOMPARE(proxy.data(indexB).toString(), QString::fromLatin1("B VISIBLE"));
+
+ itemA->setText("A");
+ QCOMPARE(proxy.rowCount(QModelIndex()), 0);
+ QVERIFY(!indexA.isValid());
+ QVERIFY(!indexB.isValid());
+
+ itemB->setText("B");
+ itemA->setText("A VISIBLE");
+ itemC->setText("C VISIBLE");
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), 1);
+ indexA = proxy.index(0,0);
+ QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("A VISIBLE"));
+
+ QCOMPARE(proxy.rowCount(indexA) , 1);
+ QModelIndex indexC = proxy.index(0, 0, indexA);
+ QCOMPARE(proxy.data(indexC).toString(), QString::fromLatin1("C VISIBLE"));
+
+ proxy.setFilterRegExp("C");
+ QCOMPARE(proxy.rowCount(QModelIndex()), 0);
+ itemC->setText("invisible");
+ itemA->setText("AC");
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), 1);
+ indexA = proxy.index(0,0);
+ QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("AC"));
+ QCOMPARE(proxy.rowCount(indexA) , 0);
+}
+
+void tst_QSortFilterProxyModel::task252507_mapFromToSource()
+{
+ QtTestModel source(10,10);
+ source.fetchMore(QModelIndex());
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&source);
+ QCOMPARE(proxy.mapFromSource(source.index(5, 4)), proxy.index(5, 4));
+ QCOMPARE(proxy.mapToSource(proxy.index(3, 2)), source.index(3, 2));
+ QCOMPARE(proxy.mapFromSource(QModelIndex()), QModelIndex());
+ QCOMPARE(proxy.mapToSource(QModelIndex()), QModelIndex());
+
+#ifdef QT_NO_DEBUG //if Qt is compiled in debug mode, this will assert
+ QTest::ignoreMessage(QtWarningMsg, "QSortFilterProxyModel: index from wrong model passed to mapToSource ");
+ QCOMPARE(proxy.mapToSource(source.index(2, 3)), QModelIndex());
+ QTest::ignoreMessage(QtWarningMsg, "QSortFilterProxyModel: index from wrong model passed to mapFromSource ");
+ QCOMPARE(proxy.mapFromSource(proxy.index(6, 2)), QModelIndex());
+#endif
+}
+
+static QStandardItem *addEntry(QStandardItem* pParent, const QString &description)
+{
+ QStandardItem* pItem = new QStandardItem(description);
+ pParent->appendRow(pItem);
+ return pItem;
+}
+
+
+void tst_QSortFilterProxyModel::task255652_removeRowsRecursive()
+{
+ QStandardItemModel pModel;
+ QStandardItem *pItem1 = new QStandardItem("root");
+ pModel.appendRow(pItem1);
+ QList<QStandardItem *> items;
+
+ QStandardItem *pItem11 = addEntry(pItem1,"Sub-heading");
+ items << pItem11;
+ QStandardItem *pItem111 = addEntry(pItem11,"A");
+ items << pItem111;
+ items << addEntry(pItem111,"A1");
+ items << addEntry(pItem111,"A2");
+ QStandardItem *pItem112 = addEntry(pItem11,"B");
+ items << pItem112;
+ items << addEntry(pItem112,"B1");
+ items << addEntry(pItem112,"B2");
+ QStandardItem *pItem1123 = addEntry(pItem112,"B3");
+ items << pItem1123;
+ items << addEntry(pItem1123,"B3-");
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&pModel);
+
+ QList<QPersistentModelIndex> sourceIndexes;
+ QList<QPersistentModelIndex> proxyIndexes;
+ foreach (QStandardItem *item, items) {
+ QModelIndex idx = item->index();
+ sourceIndexes << idx;
+ proxyIndexes << proxy.mapFromSource(idx);
+ }
+
+ foreach (const QPersistentModelIndex &pidx, sourceIndexes)
+ QVERIFY(pidx.isValid());
+ foreach (const QPersistentModelIndex &pidx, proxyIndexes)
+ QVERIFY(pidx.isValid());
+
+ QList<QStandardItem*> itemRow = pItem1->takeRow(0);
+
+ QCOMPARE(itemRow.count(), 1);
+ QCOMPARE(itemRow.first(), pItem11);
+
+ foreach (const QPersistentModelIndex &pidx, sourceIndexes)
+ QVERIFY(!pidx.isValid());
+ foreach (const QPersistentModelIndex &pidx, proxyIndexes)
+ QVERIFY(!pidx.isValid());
+
+ delete pItem11;
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_6205_doubleProxySelectionSetSourceModel()
+{
+ QStandardItemModel *model1 = new QStandardItemModel;
+ QStandardItem *parentItem = model1->invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("model1 item %0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+
+ QStandardItemModel *model2 = new QStandardItemModel;
+ QStandardItem *parentItem2 = model2->invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("model2 item %0").arg(i));
+ parentItem2->appendRow(item);
+ parentItem2 = item;
+ }
+
+ QSortFilterProxyModel *toggleProxy = new QSortFilterProxyModel;
+ toggleProxy->setSourceModel(model1);
+
+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel;
+ proxyModel->setSourceModel(toggleProxy);
+
+ QModelIndex mi = proxyModel->index(0, 0, proxyModel->index(0, 0, proxyModel->index(0, 0)));
+ QItemSelectionModel ism(proxyModel);
+ ism.select(mi, QItemSelectionModel::Select);
+ QModelIndexList mil = ism.selectedIndexes();
+ QCOMPARE(mil.count(), 1);
+ QCOMPARE(mil.first(), mi);
+
+ toggleProxy->setSourceModel(model2);
+ // No crash, it's good news!
+ QVERIFY(ism.selection().isEmpty());
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_7537_appearsAndSort()
+{
+ class PModel : public QSortFilterProxyModel
+ {
+ public:
+ PModel() : mVisible(false) {};
+ protected:
+ bool filterAcceptsRow(int, const QModelIndex &) const
+ {
+ return mVisible;
+ }
+
+ public:
+ void updateXX()
+ {
+ mVisible = true;
+ invalidate();
+ }
+ private:
+ bool mVisible;
+ } proxyModel;
+
+
+ QStringListModel sourceModel;
+ QStringList list;
+ list << "b" << "a" << "c";
+ sourceModel.setStringList(list);
+
+ proxyModel.setSourceModel(&sourceModel);
+ proxyModel.setDynamicSortFilter(true);
+ proxyModel.sort(0, Qt::AscendingOrder);
+
+ QApplication::processEvents();
+ QCOMPARE(sourceModel.rowCount(), 3);
+ QCOMPARE(proxyModel.rowCount(), 0); //all rows are hidden at first;
+
+ QSignalSpy spyAbout1(&proxyModel, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy spyChanged1(&proxyModel, SIGNAL(layoutChanged()));
+
+ //introducing secondProxyModel to test the layoutChange when many items appears at once
+ QSortFilterProxyModel secondProxyModel;
+ secondProxyModel.setSourceModel(&proxyModel);
+ secondProxyModel.setDynamicSortFilter(true);
+ secondProxyModel.sort(0, Qt::DescendingOrder);
+ QCOMPARE(secondProxyModel.rowCount(), 0); //all rows are hidden at first;
+ QSignalSpy spyAbout2(&secondProxyModel, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy spyChanged2(&secondProxyModel, SIGNAL(layoutChanged()));
+
+ proxyModel.updateXX();
+ QApplication::processEvents();
+ //now rows should be visible, and sorted
+ QCOMPARE(proxyModel.rowCount(), 3);
+ QCOMPARE(proxyModel.data(proxyModel.index(0,0), Qt::DisplayRole).toString(), QString::fromLatin1("a"));
+ QCOMPARE(proxyModel.data(proxyModel.index(1,0), Qt::DisplayRole).toString(), QString::fromLatin1("b"));
+ QCOMPARE(proxyModel.data(proxyModel.index(2,0), Qt::DisplayRole).toString(), QString::fromLatin1("c"));
+
+ //now rows should be visible, and sorted
+ QCOMPARE(secondProxyModel.rowCount(), 3);
+ QCOMPARE(secondProxyModel.data(secondProxyModel.index(0,0), Qt::DisplayRole).toString(), QString::fromLatin1("c"));
+ QCOMPARE(secondProxyModel.data(secondProxyModel.index(1,0), Qt::DisplayRole).toString(), QString::fromLatin1("b"));
+ QCOMPARE(secondProxyModel.data(secondProxyModel.index(2,0), Qt::DisplayRole).toString(), QString::fromLatin1("a"));
+
+ QCOMPARE(spyAbout1.count(), 1);
+ QCOMPARE(spyChanged1.count(), 1);
+ QCOMPARE(spyAbout2.count(), 1);
+ QCOMPARE(spyChanged2.count(), 1);
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_7716_unnecessaryDynamicSorting()
+{
+ QStringListModel model;
+ const QStringList initial = QString("bravo charlie delta echo").split(" ");
+ model.setStringList(initial);
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(false);
+ proxy.setSourceModel(&model);
+ proxy.sort(Qt::AscendingOrder);
+
+ //append two rows
+ int maxrows = proxy.rowCount(QModelIndex());
+ model.insertRows(maxrows, 2);
+ model.setData(model.index(maxrows, 0), QString("alpha"));
+ model.setData(model.index(maxrows + 1, 0), QString("fondue"));
+
+ //append new items to the initial string list and compare with model
+ QStringList expected = initial;
+ expected << QString("alpha") << QString("fondue");
+
+ //if bug 7716 is present, new rows were prepended, when they should have been appended
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+class SelectionProxyModel : QAbstractProxyModel
+{
+ Q_OBJECT
+public:
+ SelectionProxyModel()
+ : QAbstractProxyModel(), selectionModel(0)
+ {
+ }
+
+ QModelIndex mapFromSource(QModelIndex const&) const
+ { return QModelIndex(); }
+
+ QModelIndex mapToSource(QModelIndex const&) const
+ { return QModelIndex(); }
+
+ QModelIndex index(int, int, const QModelIndex&) const
+ { return QModelIndex(); }
+
+ QModelIndex parent(const QModelIndex&) const
+ { return QModelIndex(); }
+
+ int rowCount(const QModelIndex&) const
+ { return 0; }
+
+ int columnCount(const QModelIndex&) const
+ { return 0; }
+
+ void setSourceModel( QAbstractItemModel *sourceModel )
+ {
+ beginResetModel();
+ disconnect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()) );
+ QAbstractProxyModel::setSourceModel( sourceModel );
+ connect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()) );
+ endResetModel();
+ }
+
+ void setSelectionModel( QItemSelectionModel *_selectionModel )
+ {
+ selectionModel = _selectionModel;
+ }
+
+private slots:
+ void sourceModelAboutToBeReset()
+ {
+ QVERIFY( selectionModel->selectedIndexes().size() == 1 );
+ beginResetModel();
+ }
+
+ void sourceModelReset()
+ {
+ endResetModel();
+ }
+
+private:
+ QItemSelectionModel *selectionModel;
+
+};
+
+void tst_QSortFilterProxyModel::testMultipleProxiesWithSelection()
+{
+ QStringListModel model;
+ const QStringList initial = QString("bravo charlie delta echo").split(" ");
+ model.setStringList(initial);
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel( &model );
+
+ SelectionProxyModel proxy1;
+ QSortFilterProxyModel proxy2;
+
+ // Note that the order here matters. The order of the sourceAboutToBeReset
+ // exposes the bug in QSortFilterProxyModel.
+ proxy2.setSourceModel( &proxy );
+ proxy1.setSourceModel( &proxy );
+
+ QItemSelectionModel selectionModel(&proxy2);
+ proxy1.setSelectionModel( &selectionModel );
+
+ selectionModel.select( proxy2.index( 0, 0 ), QItemSelectionModel::Select );
+
+ // trick the proxy into emitting begin/end reset signals.
+ proxy.setSourceModel(0);
+
+}
+
+static bool isValid(const QItemSelection &selection) {
+ foreach(const QItemSelectionRange &range, selection)
+ if (!range.isValid())
+ return false;
+ return true;
+}
+
+void tst_QSortFilterProxyModel::mapSelectionFromSource()
+{
+ QStringListModel model;
+ const QStringList initial = QString("bravo charlie delta echo").split(" ");
+ model.setStringList(initial);
+
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(true);
+ proxy.setFilterRegExp("d.*");
+ proxy.setSourceModel(&model);
+
+ // Only "delta" remains.
+ QVERIFY(proxy.rowCount() == 1);
+
+ QItemSelection selection;
+ QModelIndex charlie = model.index(1, 0);
+ selection.append(QItemSelectionRange(charlie, charlie));
+ QModelIndex delta = model.index(2, 0);
+ selection.append(QItemSelectionRange(delta, delta));
+ QModelIndex echo = model.index(3, 0);
+ selection.append(QItemSelectionRange(echo, echo));
+
+ QVERIFY(isValid(selection));
+
+ QItemSelection proxiedSelection = proxy.mapSelectionFromSource(selection);
+
+ // Only "delta" is in the mapped result.
+ QVERIFY(proxiedSelection.size() == 1);
+ QVERIFY(isValid(proxiedSelection));
+}
+
+class Model10287 : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ Model10287(QObject *parent = 0)
+ : QStandardItemModel(0, 1, parent)
+ {
+ parentItem = new QStandardItem("parent");
+ parentItem->setData(false, Qt::UserRole);
+ appendRow(parentItem);
+
+ childItem = new QStandardItem("child");
+ childItem->setData(true, Qt::UserRole);
+ parentItem->appendRow(childItem);
+
+ childItem2 = new QStandardItem("child2");
+ childItem2->setData(true, Qt::UserRole);
+ parentItem->appendRow(childItem2);
+ }
+
+ void removeChild()
+ {
+ childItem2->setData(false, Qt::UserRole);
+ parentItem->removeRow(0);
+ }
+
+private:
+ QStandardItem *parentItem, *childItem, *childItem2;
+};
+
+class Proxy10287 : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ Proxy10287(QAbstractItemModel *model, QObject *parent = 0)
+ : QSortFilterProxyModel(parent)
+ {
+ setSourceModel(model);
+ setDynamicSortFilter(true);
+ }
+
+protected:
+ virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+ {
+ // Filter based on UserRole in model
+ QModelIndex i = sourceModel()->index(source_row, 0, source_parent);
+ return i.data(Qt::UserRole).toBool();
+ }
+};
+
+void tst_QSortFilterProxyModel::taskQTBUG_10287_unnecessaryMapCreation()
+{
+ Model10287 m;
+ Proxy10287 p(&m);
+ m.removeChild();
+ // No assert failure, it passes.
+}
+
+class FilteredColumnProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ FilteredColumnProxyModel(QObject *parent = 0)
+ : QSortFilterProxyModel(parent)
+ {
+
+ }
+
+protected:
+ bool filterAcceptsColumn(int column, const QModelIndex & /* source_parent */) const
+ {
+ return column % 2 != 0;
+ }
+};
+
+void tst_QSortFilterProxyModel::filteredColumns()
+{
+ DynamicTreeModel *model = new DynamicTreeModel(this);
+
+ FilteredColumnProxyModel *proxy = new FilteredColumnProxyModel(this);
+ proxy->setSourceModel(model);
+
+ new ModelTest(proxy, this);
+
+ ModelInsertCommand *insertCommand = new ModelInsertCommand(model, this);
+ insertCommand->setNumCols(2);
+ insertCommand->setStartRow(0);
+ insertCommand->setEndRow(0);
+ // Parent is QModelIndex()
+ insertCommand->doCommand();
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate_data()
+{
+ QTest::addColumn<int>("test");
+ QTest::addColumn<bool>("works");
+
+ QTest::newRow("nothing") << 0 << false;
+ QTest::newRow("reset") << 1 << true;
+ QTest::newRow("invalidate") << 2 << true;
+ QTest::newRow("invalidate_filter") << 3 << true;
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate()
+{
+ QFETCH(int, test);
+ QFETCH(bool, works);
+
+ struct Proxy : QSortFilterProxyModel {
+ QString pattern;
+ virtual bool filterAcceptsRow(int source_row, const QModelIndex&) const {
+ return sourceModel()->data(sourceModel()->index(source_row, 0)).toString().contains(pattern);
+ }
+ void notifyChange(int test) {
+ switch (test) {
+ case 0: break;
+ case 1: reset(); break;
+ case 2: invalidate(); break;
+ case 3: invalidateFilter(); break;
+ }
+ }
+ };
+
+ QStringListModel sourceModel(QStringList() << "Poisson" << "Vache" << "Brebis"
+ << "Elephant" << "Cochon" << "Serpent"
+ << "Mouton" << "Ecureuil" << "Mouche");
+ Proxy proxy;
+ proxy.pattern = QString::fromLatin1("n");
+ proxy.setSourceModel(&sourceModel);
+
+ QCOMPARE(proxy.rowCount(), 5);
+ for (int i = 0; i < proxy.rowCount(); i++) {
+ QVERIFY(proxy.data(proxy.index(i,0)).toString().contains('n'));
+ }
+
+ proxy.pattern = QString::fromLatin1("o");
+ proxy.notifyChange(test);
+
+ QCOMPARE(proxy.rowCount(), works ? 4 : 5);
+ bool ok = true;
+ for (int i = 0; i < proxy.rowCount(); i++) {
+ if (!proxy.data(proxy.index(i,0)).toString().contains('o'))
+ ok = false;
+ }
+ QCOMPARE(ok, works);
+}
+
+QTEST_MAIN(tst_QSortFilterProxyModel)
+#include "tst_qsortfilterproxymodel.moc"
diff --git a/tests/auto/widgets/itemviews/qstandarditem/.gitignore b/tests/auto/widgets/itemviews/qstandarditem/.gitignore
new file mode 100644
index 0000000000..6da85cc6c8
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstandarditem/.gitignore
@@ -0,0 +1 @@
+tst_qstandarditem
diff --git a/tests/auto/widgets/itemviews/qstandarditem/qstandarditem.pro b/tests/auto/widgets/itemviews/qstandarditem/qstandarditem.pro
new file mode 100644
index 0000000000..1d280fc2f5
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstandarditem/qstandarditem.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qstandarditem.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qstandarditem/tst_qstandarditem.cpp b/tests/auto/widgets/itemviews/qstandarditem/tst_qstandarditem.cpp
new file mode 100644
index 0000000000..206d469884
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstandarditem/tst_qstandarditem.cpp
@@ -0,0 +1,1110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qstandarditemmodel.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=gui/itemviews/qstandarditemmodel.h gui/itemviews/qstandarditemmodel.cpp
+
+class tst_QStandardItem : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QStandardItem();
+ virtual ~tst_QStandardItem();
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void ctor();
+ void textCtor();
+ void iconTextCtor();
+ void rowsColumnsCtor();
+ void getSetData();
+ void getSetFlags();
+ void getSetRowAndColumnCount();
+ void getSetChild_data();
+ void getSetChild();
+ void parent();
+ void insertColumn_data();
+ void insertColumn();
+ void insertColumns_data();
+ void insertColumns();
+ void insertRow_data();
+ void insertRow();
+ void insertRows_data();
+ void insertRows();
+ void appendColumn_data();
+ void appendColumn();
+ void appendRow_data();
+ void appendRow();
+ void takeChild();
+ void takeColumn_data();
+ void takeColumn();
+ void takeRow_data();
+ void takeRow();
+ void streamItem();
+ void deleteItem();
+ void clone();
+ void sortChildren();
+ void subclassing();
+};
+
+tst_QStandardItem::tst_QStandardItem()
+{
+}
+
+tst_QStandardItem::~tst_QStandardItem()
+{
+}
+
+void tst_QStandardItem::init()
+{
+}
+
+void tst_QStandardItem::cleanup()
+{
+}
+
+void tst_QStandardItem::ctor()
+{
+ QStandardItem item;
+ QVERIFY(!item.hasChildren());
+}
+
+void tst_QStandardItem::textCtor()
+{
+ QLatin1String text("text");
+ QStandardItem item(text);
+ QCOMPARE(item.text(), text);
+ QVERIFY(!item.hasChildren());
+}
+
+void tst_QStandardItem::iconTextCtor()
+{
+ QPixmap pixmap(32, 32);
+ pixmap.fill(Qt::red);
+ QIcon icon(pixmap);
+ QLatin1String text("text");
+ QStandardItem item(icon, text);
+ QCOMPARE(item.icon(), icon);
+ QCOMPARE(item.text(), text);
+ QVERIFY(!item.hasChildren());
+}
+
+void tst_QStandardItem::rowsColumnsCtor()
+{
+ const int rows = 5;
+ const int columns = 12;
+ QStandardItem item(rows, columns);
+ QCOMPARE(item.rowCount(), rows);
+ QCOMPARE(item.columnCount(), columns);
+}
+
+void tst_QStandardItem::getSetData()
+{
+ QStandardItem item;
+ for (int x = 0; x < 2; ++x) {
+ for (int i = 1; i <= 2; ++i) {
+ QString text = QString("text %0").arg(i);
+ item.setText(text);
+ QCOMPARE(item.text(), text);
+
+ QPixmap pixmap(32, 32);
+ pixmap.fill((i == 1) ? Qt::red : Qt::green);
+ QIcon icon(pixmap);
+ item.setIcon(icon);
+ QCOMPARE(item.icon(), icon);
+
+ QString toolTip = QString("toolTip %0").arg(i);
+ item.setToolTip(toolTip);
+ QCOMPARE(item.toolTip(), toolTip);
+
+ QString statusTip = QString("statusTip %0").arg(i);
+ item.setStatusTip(statusTip);
+ QCOMPARE(item.statusTip(), statusTip);
+
+ QString whatsThis = QString("whatsThis %0").arg(i);
+ item.setWhatsThis(whatsThis);
+ QCOMPARE(item.whatsThis(), whatsThis);
+
+ QSize sizeHint(64*i, 48*i);
+ item.setSizeHint(sizeHint);
+ QCOMPARE(item.sizeHint(), sizeHint);
+
+ QFont font;
+ item.setFont(font);
+ QCOMPARE(item.font(), font);
+
+ Qt::Alignment textAlignment((i == 1)
+ ? Qt::AlignLeft|Qt::AlignVCenter
+ : Qt::AlignRight);
+ item.setTextAlignment(textAlignment);
+ QCOMPARE(item.textAlignment(), textAlignment);
+
+ QColor backgroundColor((i == 1) ? Qt::blue : Qt::yellow);
+ item.setBackground(backgroundColor);
+ QCOMPARE(item.background().color(), backgroundColor);
+
+ QColor textColor((i == i) ? Qt::green : Qt::cyan);
+ item.setForeground(textColor);
+ QCOMPARE(item.foreground().color(), textColor);
+
+ Qt::CheckState checkState((i == 1) ? Qt::PartiallyChecked : Qt::Checked);
+ item.setCheckState(checkState);
+ QCOMPARE(item.checkState(), checkState);
+
+ QString accessibleText = QString("accessibleText %0").arg(i);
+ item.setAccessibleText(accessibleText);
+ QCOMPARE(item.accessibleText(), accessibleText);
+
+ QString accessibleDescription = QString("accessibleDescription %0").arg(i);
+ item.setAccessibleDescription(accessibleDescription);
+ QCOMPARE(item.accessibleDescription(), accessibleDescription);
+
+ QCOMPARE(item.text(), text);
+ QCOMPARE(item.icon(), icon);
+ QCOMPARE(item.toolTip(), toolTip);
+ QCOMPARE(item.statusTip(), statusTip);
+ QCOMPARE(item.whatsThis(), whatsThis);
+ QCOMPARE(item.sizeHint(), sizeHint);
+ QCOMPARE(item.font(), font);
+ QCOMPARE(item.textAlignment(), textAlignment);
+ QCOMPARE(item.background().color(), backgroundColor);
+ QCOMPARE(item.foreground().color(), textColor);
+ QCOMPARE(item.checkState(), checkState);
+ QCOMPARE(item.accessibleText(), accessibleText);
+ QCOMPARE(item.accessibleDescription(), accessibleDescription);
+
+ QCOMPARE(qvariant_cast<QString>(item.data(Qt::DisplayRole)), text);
+ QCOMPARE(qvariant_cast<QIcon>(item.data(Qt::DecorationRole)), icon);
+ QCOMPARE(qvariant_cast<QString>(item.data(Qt::ToolTipRole)), toolTip);
+ QCOMPARE(qvariant_cast<QString>(item.data(Qt::StatusTipRole)), statusTip);
+ QCOMPARE(qvariant_cast<QString>(item.data(Qt::WhatsThisRole)), whatsThis);
+ QCOMPARE(qvariant_cast<QSize>(item.data(Qt::SizeHintRole)), sizeHint);
+ QCOMPARE(qvariant_cast<QFont>(item.data(Qt::FontRole)), font);
+ QCOMPARE(qvariant_cast<int>(item.data(Qt::TextAlignmentRole)), int(textAlignment));
+ QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::BackgroundColorRole)), QBrush(backgroundColor));
+ QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::BackgroundRole)), QBrush(backgroundColor));
+ QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::TextColorRole)), QBrush(textColor));
+ QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::ForegroundRole)), QBrush(textColor));
+ QCOMPARE(qvariant_cast<int>(item.data(Qt::CheckStateRole)), int(checkState));
+ QCOMPARE(qvariant_cast<QString>(item.data(Qt::AccessibleTextRole)), accessibleText);
+ QCOMPARE(qvariant_cast<QString>(item.data(Qt::AccessibleDescriptionRole)), accessibleDescription);
+
+ item.setBackground(pixmap);
+ QCOMPARE(item.background().texture(), pixmap);
+ QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::BackgroundRole)).texture(), pixmap);
+ }
+ item.setData(QVariant(), Qt::DisplayRole);
+ item.setData(QVariant(), Qt::DecorationRole);
+ item.setData(QVariant(), Qt::ToolTipRole);
+ item.setData(QVariant(), Qt::StatusTipRole);
+ item.setData(QVariant(), Qt::WhatsThisRole);
+ item.setData(QVariant(), Qt::SizeHintRole);
+ item.setData(QVariant(), Qt::FontRole);
+ item.setData(QVariant(), Qt::TextAlignmentRole);
+ item.setData(QVariant(), Qt::BackgroundRole);
+ item.setData(QVariant(), Qt::ForegroundRole);
+ item.setData(QVariant(), Qt::CheckStateRole);
+ item.setData(QVariant(), Qt::AccessibleTextRole);
+ item.setData(QVariant(), Qt::AccessibleDescriptionRole);
+
+ QCOMPARE(item.data(Qt::DisplayRole), QVariant());
+ QCOMPARE(item.data(Qt::DecorationRole), QVariant());
+ QCOMPARE(item.data(Qt::ToolTipRole), QVariant());
+ QCOMPARE(item.data(Qt::StatusTipRole), QVariant());
+ QCOMPARE(item.data(Qt::WhatsThisRole), QVariant());
+ QCOMPARE(item.data(Qt::SizeHintRole), QVariant());
+ QCOMPARE(item.data(Qt::FontRole), QVariant());
+ QCOMPARE(item.data(Qt::TextAlignmentRole), QVariant());
+ QCOMPARE(item.data(Qt::BackgroundColorRole), QVariant());
+ QCOMPARE(item.data(Qt::BackgroundRole), QVariant());
+ QCOMPARE(item.data(Qt::TextColorRole), QVariant());
+ QCOMPARE(item.data(Qt::ForegroundRole), QVariant());
+ QCOMPARE(item.data(Qt::CheckStateRole), QVariant());
+ QCOMPARE(item.data(Qt::AccessibleTextRole), QVariant());
+ QCOMPARE(item.data(Qt::AccessibleDescriptionRole), QVariant());
+ }
+}
+
+void tst_QStandardItem::getSetFlags()
+{
+ QStandardItem item;
+ item.setEnabled(true);
+ QVERIFY(item.isEnabled());
+ QVERIFY(item.flags() & Qt::ItemIsEnabled);
+ item.setEditable(true);
+ QVERIFY(item.isEditable());
+ QVERIFY(item.flags() & Qt::ItemIsEditable);
+ item.setSelectable(true);
+ QVERIFY(item.isSelectable());
+ QVERIFY(item.flags() & Qt::ItemIsSelectable);
+ item.setCheckable(true);
+ QVERIFY(item.isCheckable());
+ QCOMPARE(item.checkState(), Qt::Unchecked);
+ QVERIFY(item.flags() & Qt::ItemIsUserCheckable);
+ item.setTristate(true);
+ QVERIFY(item.isTristate());
+ QVERIFY(item.flags() & Qt::ItemIsTristate);
+#ifndef QT_NO_DRAGANDDROP
+ item.setDragEnabled(true);
+ QVERIFY(item.isDragEnabled());
+ QVERIFY(item.flags() & Qt::ItemIsDragEnabled);
+ item.setDropEnabled(true);
+ QVERIFY(item.isDropEnabled());
+ QVERIFY(item.flags() & Qt::ItemIsDropEnabled);
+#endif
+
+ QVERIFY(item.isEnabled());
+ item.setEnabled(false);
+ QVERIFY(!item.isEnabled());
+ QVERIFY(!(item.flags() & Qt::ItemIsEnabled));
+ QVERIFY(item.isEditable());
+ item.setEditable(false);
+ QVERIFY(!item.isEditable());
+ QVERIFY(!(item.flags() & Qt::ItemIsEditable));
+ QVERIFY(item.isSelectable());
+ item.setSelectable(false);
+ QVERIFY(!item.isSelectable());
+ QVERIFY(!(item.flags() & Qt::ItemIsSelectable));
+ QVERIFY(item.isCheckable());
+ item.setCheckable(false);
+ QVERIFY(!item.isCheckable());
+ QVERIFY(!(item.flags() & Qt::ItemIsUserCheckable));
+ QVERIFY(item.isTristate());
+ item.setTristate(false);
+ QVERIFY(!item.isTristate());
+ QVERIFY(!(item.flags() & Qt::ItemIsTristate));
+#ifndef QT_NO_DRAGANDDROP
+ QVERIFY(item.isDragEnabled());
+ item.setDragEnabled(false);
+ QVERIFY(!item.isDragEnabled());
+ QVERIFY(!(item.flags() & Qt::ItemIsDragEnabled));
+ QVERIFY(item.isDropEnabled());
+ item.setDropEnabled(false);
+ QVERIFY(!item.isDropEnabled());
+ QVERIFY(!(item.flags() & Qt::ItemIsDropEnabled));
+#endif
+
+ item.setCheckable(false);
+ item.setCheckState(Qt::Checked);
+ item.setCheckable(true);
+ QCOMPARE(item.checkState(), Qt::Checked);
+}
+
+void tst_QStandardItem::getSetRowAndColumnCount()
+{
+ QStandardItem item;
+
+ item.setRowCount(-1);
+ QCOMPARE(item.rowCount(), 0);
+
+ item.setColumnCount(-1);
+ QCOMPARE(item.columnCount(), 0);
+
+ item.setRowCount(1);
+ QCOMPARE(item.rowCount(), 1);
+ QCOMPARE(item.columnCount(), 0);
+
+ item.setColumnCount(1);
+ QCOMPARE(item.columnCount(), 1);
+ QCOMPARE(item.rowCount(), 1);
+
+ item.setColumnCount(10);
+ QCOMPARE(item.columnCount(), 10);
+ QCOMPARE(item.rowCount(), 1);
+
+ item.setRowCount(20);
+ QCOMPARE(item.rowCount(), 20);
+ QCOMPARE(item.columnCount(), 10);
+
+ item.setRowCount(-1);
+ QCOMPARE(item.rowCount(), 20);
+
+ item.setColumnCount(-1);
+ QCOMPARE(item.columnCount(), 10);
+
+ item.setColumnCount(0);
+ QCOMPARE(item.columnCount(), 0);
+ QCOMPARE(item.rowCount(), 20);
+
+ item.setRowCount(0);
+ QCOMPARE(item.rowCount(), 0);
+}
+
+void tst_QStandardItem::getSetChild_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+
+ QTest::newRow("0x0 children, child at (-1,-1)") << 0 << 0 << -1 << -1;
+ QTest::newRow("0x0 children, child at (0,0)") << 0 << 0 << 0 << 0;
+}
+
+void tst_QStandardItem::getSetChild()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, row);
+ QFETCH(int, column);
+
+ QStandardItem item(rows, columns);
+ bool shouldHaveChildren = (rows > 0) && (columns > 0);
+ QCOMPARE(item.hasChildren(), shouldHaveChildren);
+ QCOMPARE(item.child(row, column), static_cast<QStandardItem*>(0));
+
+ QStandardItem *child = new QStandardItem;
+ item.setChild(row, column, child);
+ if ((row >= 0) && (column >= 0)) {
+ QCOMPARE(item.rowCount(), qMax(rows, row + 1));
+ QCOMPARE(item.columnCount(), qMax(columns, column + 1));
+
+ QCOMPARE(item.child(row, column), child);
+ QCOMPARE(child->row(), row);
+ QCOMPARE(child->column(), column);
+
+ QStandardItem *anotherChild = new QStandardItem;
+ item.setChild(row, column, anotherChild);
+ QCOMPARE(item.child(row, column), anotherChild);
+ QCOMPARE(anotherChild->row(), row);
+ QCOMPARE(anotherChild->column(), column);
+ item.setChild(row, column, 0);
+ } else {
+ delete child;
+ }
+ QCOMPARE(item.child(row, column), static_cast<QStandardItem*>(0));
+}
+
+void tst_QStandardItem::parent()
+{
+ {
+ QStandardItem item;
+ QStandardItem *child = new QStandardItem;
+ QCOMPARE(child->parent(), static_cast<QStandardItem*>(0));
+ item.setChild(0, 0, child);
+ QCOMPARE(child->parent(), &item);
+
+ QStandardItem *childOfChild = new QStandardItem;
+ child->setChild(0, 0, childOfChild);
+ QCOMPARE(childOfChild->parent(), child);
+ }
+
+ {
+ QStandardItemModel model;
+ QStandardItem *item = new QStandardItem;
+ model.appendRow(item);
+ // parent of a top-level item should be 0
+ QCOMPARE(item->parent(), static_cast<QStandardItem*>(0));
+ }
+}
+
+void tst_QStandardItem::insertColumn_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("insert 0 at -1 in 0x0") << 0 << 0 << -1 << 0;
+ QTest::newRow("insert 0 at 0 in 0x0") << 0 << 0 << 0 << 0;
+ QTest::newRow("insert 0 at 0 in 1x0") << 1 << 0 << 0 << 0;
+ QTest::newRow("insert 0 at 0 in 0x1") << 0 << 1 << 0 << 0;
+ QTest::newRow("insert 0 at 0 in 1x1") << 1 << 1 << 0 << 0;
+ QTest::newRow("insert 1 at -1 in 0x0") << 0 << 0 << -1 << 1;
+ QTest::newRow("insert 1 at 0 in 0x0") << 0 << 0 << 0 << 1;
+ QTest::newRow("insert 1 at 0 in 1x0") << 1 << 0 << 0 << 1;
+ QTest::newRow("insert 1 at 0 in 0x1") << 0 << 1 << 0 << 1;
+ QTest::newRow("insert 1 at 0 in 1x1") << 1 << 1 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 1x1") << 1 << 1 << 1 << 1;
+ QTest::newRow("insert 1 at 0 in 2x1") << 2 << 1 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 2x1") << 2 << 1 << 1 << 1;
+ QTest::newRow("insert 1 at 0 in 1x2") << 1 << 2 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 1x2") << 1 << 2 << 1 << 1;
+ QTest::newRow("insert 1 at 0 in 8x4") << 8 << 4 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 8x4") << 8 << 4 << 1 << 1;
+ QTest::newRow("insert 1 at 2 in 8x4") << 8 << 4 << 2 << 1;
+ QTest::newRow("insert 1 at 3 in 8x4") << 8 << 4 << 3 << 1;
+ QTest::newRow("insert 1 at 4 in 8x4") << 8 << 4 << 4 << 1;
+ QTest::newRow("insert 4 at 0 in 8x4") << 8 << 4 << 0 << 4;
+ QTest::newRow("insert 4 at 4 in 8x4") << 8 << 4 << 4 << 4;
+ QTest::newRow("insert 6 at 0 in 8x4") << 8 << 4 << 0 << 6;
+ QTest::newRow("insert 6 at 4 in 8x4") << 8 << 4 << 4 << 6;
+}
+
+void tst_QStandardItem::insertColumn()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, column);
+ QFETCH(int, count);
+
+ QStandardItem item(rows, columns);
+
+ // make items for a new column
+ QList<QStandardItem*> columnItems;
+ for (int i = 0; i < count; ++i)
+ columnItems.append(new QStandardItem);
+
+ item.insertColumn(column, columnItems);
+
+ if (column >= 0) {
+ QCOMPARE(item.columnCount(), columns + 1);
+ QCOMPARE(item.rowCount(), qMax(rows, count));
+ // check to make sure items were inserted in correct place
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(item.child(i, column), columnItems.at(i));
+ for (int i = count; i < item.rowCount(); ++i)
+ QCOMPARE(item.child(i, column), static_cast<QStandardItem*>(0));
+ } else {
+ QCOMPARE(item.columnCount(), columns);
+ QCOMPARE(item.rowCount(), rows);
+ qDeleteAll(columnItems);
+ }
+}
+
+void tst_QStandardItem::insertColumns_data()
+{
+}
+
+void tst_QStandardItem::insertColumns()
+{
+}
+
+void tst_QStandardItem::insertRow_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("insert 0 at -1 in 0x0") << 0 << 0 << -1 << 0;
+ QTest::newRow("insert 0 at 0 in 0x0") << 0 << 0 << 0 << 0;
+ QTest::newRow("insert 0 at 0 in 1x0") << 1 << 0 << 0 << 0;
+ QTest::newRow("insert 0 at 0 in 0x1") << 0 << 1 << 0 << 0;
+ QTest::newRow("insert 0 at 0 in 1x1") << 1 << 1 << 0 << 0;
+ QTest::newRow("insert 1 at -1 in 0x0") << 0 << 0 << -1 << 1;
+ QTest::newRow("insert 1 at 0 in 0x0") << 0 << 0 << 0 << 1;
+ QTest::newRow("insert 1 at 0 in 1x0") << 1 << 0 << 0 << 1;
+ QTest::newRow("insert 1 at 0 in 0x1") << 0 << 1 << 0 << 1;
+ QTest::newRow("insert 1 at 0 in 1x1") << 1 << 1 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 1x1") << 1 << 1 << 1 << 1;
+ QTest::newRow("insert 1 at 0 in 2x1") << 2 << 1 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 2x1") << 2 << 1 << 1 << 1;
+ QTest::newRow("insert 1 at 0 in 1x2") << 1 << 2 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 1x2") << 1 << 2 << 1 << 1;
+ QTest::newRow("insert 1 at 0 in 4x8") << 4 << 8 << 0 << 1;
+ QTest::newRow("insert 1 at 1 in 4x8") << 4 << 8 << 1 << 1;
+ QTest::newRow("insert 1 at 2 in 4x8") << 4 << 8 << 2 << 1;
+ QTest::newRow("insert 1 at 3 in 4x8") << 4 << 8 << 3 << 1;
+ QTest::newRow("insert 1 at 4 in 4x8") << 4 << 8 << 4 << 1;
+ QTest::newRow("insert 4 at 0 in 4x8") << 4 << 8 << 0 << 4;
+ QTest::newRow("insert 4 at 4 in 4x8") << 4 << 8 << 4 << 4;
+ QTest::newRow("insert 6 at 0 in 4x8") << 4 << 8 << 0 << 6;
+ QTest::newRow("insert 6 at 4 in 4x8") << 4 << 8 << 4 << 6;
+}
+
+void tst_QStandardItem::insertRow()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, row);
+ QFETCH(int, count);
+
+ QStandardItem item(rows, columns);
+
+ // make items for a new column
+ QList<QStandardItem*> rowItems;
+ for (int i = 0; i < count; ++i)
+ rowItems.append(new QStandardItem);
+
+ item.insertRow(row, rowItems);
+
+ if (row >= 0) {
+ QCOMPARE(item.columnCount(), qMax(columns, count));
+ QCOMPARE(item.rowCount(), rows + 1);
+ // check to make sure items were inserted in correct place
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(item.child(row, i), rowItems.at(i));
+ for (int i = count; i < item.columnCount(); ++i)
+ QCOMPARE(item.child(row, i), static_cast<QStandardItem*>(0));
+ } else {
+ QCOMPARE(item.columnCount(), columns);
+ QCOMPARE(item.rowCount(), rows);
+ qDeleteAll(rowItems);
+ }
+}
+
+void tst_QStandardItem::insertRows_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("insertAt");
+ QTest::addColumn<int>("insertCount");
+
+ QTest::newRow("insert {0,1} at 0 in 0x0") << 0 << 0 << 0 << 2;
+}
+
+void tst_QStandardItem::insertRows()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, insertAt);
+ QFETCH(int, insertCount);
+
+ QStandardItem item(rows, columns);
+
+ QList<QStandardItem*> items;
+ for (int i = 0; i < insertCount; ++i) {
+ items.append(new QStandardItem());
+ }
+ item.insertRows(insertAt, items);
+
+ QCOMPARE(item.rowCount(), rows + insertCount);
+}
+
+void tst_QStandardItem::appendColumn_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("append 0 to 0x0") << 0 << 0 << 0;
+ QTest::newRow("append 1 to 0x0") << 0 << 0 << 1;
+ QTest::newRow("append 1 to 1x0") << 1 << 0 << 1;
+ QTest::newRow("append 1 to 0x1") << 0 << 1 << 1;
+ QTest::newRow("append 1 to 1x1") << 1 << 1 << 1;
+ QTest::newRow("append 1 to 2x0") << 2 << 0 << 1;
+ QTest::newRow("append 1 to 0x2") << 0 << 2 << 1;
+ QTest::newRow("append 1 to 2x1") << 2 << 1 << 1;
+ QTest::newRow("append 1 to 1x2") << 1 << 2 << 1;
+ QTest::newRow("append 1 to 2x2") << 2 << 2 << 1;
+ QTest::newRow("append 2 to 0x0") << 0 << 0 << 2;
+ QTest::newRow("append 2 to 1x0") << 1 << 0 << 2;
+ QTest::newRow("append 2 to 0x1") << 0 << 1 << 2;
+ QTest::newRow("append 2 to 1x1") << 1 << 1 << 2;
+ QTest::newRow("append 2 to 2x0") << 2 << 0 << 2;
+ QTest::newRow("append 2 to 0x2") << 0 << 2 << 2;
+ QTest::newRow("append 2 to 2x1") << 2 << 1 << 2;
+ QTest::newRow("append 2 to 1x2") << 1 << 2 << 2;
+ QTest::newRow("append 2 to 2x2") << 2 << 2 << 2;
+ QTest::newRow("append 3 to 2x1") << 2 << 1 << 3;
+ QTest::newRow("append 3 to 1x2") << 1 << 2 << 3;
+ QTest::newRow("append 3 to 2x2") << 2 << 2 << 3;
+ QTest::newRow("append 3 to 4x2") << 4 << 2 << 3;
+ QTest::newRow("append 3 to 2x4") << 2 << 4 << 3;
+ QTest::newRow("append 3 to 4x4") << 4 << 4 << 3;
+ QTest::newRow("append 7 to 4x2") << 4 << 2 << 7;
+ QTest::newRow("append 7 to 2x4") << 2 << 4 << 7;
+ QTest::newRow("append 7 to 4x4") << 4 << 4 << 7;
+}
+
+void tst_QStandardItem::appendColumn()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, count);
+
+ QStandardItem item(rows, columns);
+ QList<QStandardItem*> originalChildren;
+ // initialize children
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j) {
+ QStandardItem *child = new QStandardItem;
+ originalChildren.append(child);
+ item.setChild(i, j, child);
+ }
+ }
+
+ // make items for a new column
+ QList<QStandardItem*> columnItems;
+ for (int i = 0; i < count; ++i)
+ columnItems.append(new QStandardItem);
+
+ item.appendColumn(columnItems);
+
+ QCOMPARE(item.columnCount(), columns + 1);
+ QCOMPARE(item.rowCount(), qMax(rows, count));
+ // check to make sure items were inserted in correct place
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(item.child(i, columns), columnItems.at(i));
+ for (int i = count; i < item.rowCount(); ++i)
+ QCOMPARE(item.child(i, columns), static_cast<QStandardItem*>(0));
+
+ // make sure original children remained unchanged
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j)
+ QCOMPARE(item.child(i, j), originalChildren.at(i*columns+j));
+ }
+}
+
+void tst_QStandardItem::appendRow_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("append 0 to 0x0") << 0 << 0 << 0;
+ QTest::newRow("append 1 to 0x0") << 0 << 0 << 1;
+ QTest::newRow("append 1 to 1x0") << 1 << 0 << 1;
+ QTest::newRow("append 1 to 0x1") << 0 << 1 << 1;
+ QTest::newRow("append 1 to 1x1") << 1 << 1 << 1;
+ QTest::newRow("append 1 to 2x0") << 2 << 0 << 1;
+ QTest::newRow("append 1 to 0x2") << 0 << 2 << 1;
+ QTest::newRow("append 1 to 2x1") << 2 << 1 << 1;
+ QTest::newRow("append 1 to 1x2") << 1 << 2 << 1;
+ QTest::newRow("append 1 to 2x2") << 2 << 2 << 1;
+ QTest::newRow("append 2 to 0x0") << 0 << 0 << 2;
+ QTest::newRow("append 2 to 1x0") << 1 << 0 << 2;
+ QTest::newRow("append 2 to 0x1") << 0 << 1 << 2;
+ QTest::newRow("append 2 to 1x1") << 1 << 1 << 2;
+ QTest::newRow("append 2 to 2x0") << 2 << 0 << 2;
+ QTest::newRow("append 2 to 0x2") << 0 << 2 << 2;
+ QTest::newRow("append 2 to 2x1") << 2 << 1 << 2;
+ QTest::newRow("append 2 to 1x2") << 1 << 2 << 2;
+ QTest::newRow("append 2 to 2x2") << 2 << 2 << 2;
+ QTest::newRow("append 3 to 2x1") << 2 << 1 << 3;
+ QTest::newRow("append 3 to 1x2") << 1 << 2 << 3;
+ QTest::newRow("append 3 to 2x2") << 2 << 2 << 3;
+ QTest::newRow("append 3 to 4x2") << 4 << 2 << 3;
+ QTest::newRow("append 3 to 2x4") << 2 << 4 << 3;
+ QTest::newRow("append 3 to 4x4") << 4 << 4 << 3;
+ QTest::newRow("append 7 to 4x2") << 4 << 2 << 7;
+ QTest::newRow("append 7 to 2x4") << 2 << 4 << 7;
+ QTest::newRow("append 7 to 4x4") << 4 << 4 << 7;
+}
+
+void tst_QStandardItem::appendRow()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, count);
+
+ QStandardItem item(rows, columns);
+ QList<QStandardItem*> originalChildren;
+ // initialize children
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j) {
+ QStandardItem *child = new QStandardItem;
+ originalChildren.append(child);
+ item.setChild(i, j, child);
+ }
+ }
+
+ // make items for a new row
+ QList<QStandardItem*> rowItems;
+ for (int i = 0; i < count; ++i)
+ rowItems.append(new QStandardItem);
+
+ item.appendRow(rowItems);
+
+ QCOMPARE(item.rowCount(), rows + 1);
+ QCOMPARE(item.columnCount(), qMax(columns, count));
+ // check to make sure items were inserted in correct place
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(item.child(rows, i), rowItems.at(i));
+ for (int i = count; i < item.columnCount(); ++i)
+ QCOMPARE(item.child(rows, i), static_cast<QStandardItem*>(0));
+
+ // make sure original children remained unchanged
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j)
+ QCOMPARE(item.child(i, j), originalChildren.at(i*columns+j));
+ }
+}
+
+void tst_QStandardItem::takeChild()
+{
+ QList<QStandardItem*> itemList;
+ for (int i = 0; i < 10; ++i)
+ itemList.append(new QStandardItem);
+ QStandardItem item;
+ item.appendColumn(itemList);
+
+ for (int i = 0; i < item.rowCount(); ++i) {
+ QCOMPARE(item.takeChild(i), itemList.at(i));
+ QCOMPARE(item.takeChild(0, 0), static_cast<QStandardItem*>(0));
+ for (int j = i + 1; j < item.rowCount(); ++j)
+ QCOMPARE(item.child(j), itemList.at(j));
+ }
+ qDeleteAll(itemList);
+}
+
+void tst_QStandardItem::takeColumn_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<bool>("expectSuccess");
+
+ QTest::newRow("take -1 from 0x0") << 0 << 0 << -1 << false;
+ QTest::newRow("take 0 from 0x0") << 0 << 0 << 0 << false;
+ QTest::newRow("take 0 from 1x0") << 1 << 0 << 0 << false;
+ QTest::newRow("take 0 from 0x1") << 0 << 1 << 0 << true;
+ QTest::newRow("take 1 from 0x1") << 0 << 1 << 1 << false;
+ QTest::newRow("take 0 from 1x1") << 1 << 1 << 0 << true;
+ QTest::newRow("take 1 from 1x1") << 0 << 1 << 1 << false;
+ QTest::newRow("take 0 from 4x1") << 4 << 1 << 0 << true;
+ QTest::newRow("take 1 from 4x1") << 4 << 1 << 1 << false;
+ QTest::newRow("take 0 from 4x8") << 4 << 8 << 0 << true;
+ QTest::newRow("take 7 from 4x8") << 4 << 8 << 7 << true;
+ QTest::newRow("take 8 from 4x8") << 4 << 8 << 8 << false;
+}
+
+void tst_QStandardItem::takeColumn()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, column);
+ QFETCH(bool, expectSuccess);
+
+ QStandardItem item(rows, columns);
+ QList<QStandardItem*> originalChildren;
+ // initialize children
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j) {
+ QStandardItem *child = new QStandardItem;
+ originalChildren.append(child);
+ item.setChild(i, j, child);
+ }
+ }
+
+ QList<QStandardItem *> taken = item.takeColumn(column);
+ if (expectSuccess) {
+ QCOMPARE(taken.count(), item.rowCount());
+ QCOMPARE(item.columnCount(), columns - 1);
+ int index = column;
+ for (int i = 0; i < taken.count(); ++i) {
+ QCOMPARE(taken.at(i), originalChildren.takeAt(index));
+ index += item.columnCount();
+ }
+ index = 0;
+ for (int i = 0; i < item.rowCount(); ++i) {
+ for (int j = 0; j < item.columnCount(); ++j) {
+ QCOMPARE(item.child(i, j), originalChildren.at(index));
+ ++index;
+ }
+ }
+ } else {
+ QVERIFY(taken.isEmpty());
+ }
+ qDeleteAll(taken);
+}
+
+void tst_QStandardItem::takeRow_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<bool>("expectSuccess");
+
+ QTest::newRow("take -1 from 0x0") << 0 << 0 << -1 << false;
+ QTest::newRow("take 0 from 0x0") << 0 << 0 << 0 << false;
+ QTest::newRow("take 0 from 1x0") << 1 << 0 << 0 << true;
+ QTest::newRow("take 0 from 0x1") << 0 << 1 << 0 << false;
+ QTest::newRow("take 1 from 0x1") << 0 << 1 << 1 << false;
+ QTest::newRow("take 0 from 1x1") << 1 << 1 << 0 << true;
+ QTest::newRow("take 1 from 1x1") << 0 << 1 << 1 << false;
+ QTest::newRow("take 0 from 1x4") << 1 << 4 << 0 << true;
+ QTest::newRow("take 1 from 1x4") << 1 << 4 << 1 << false;
+ QTest::newRow("take 0 from 8x4") << 8 << 4 << 0 << true;
+ QTest::newRow("take 7 from 8x4") << 8 << 4 << 7 << true;
+ QTest::newRow("take 8 from 8x4") << 8 << 4 << 8 << false;
+}
+
+void tst_QStandardItem::takeRow()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, row);
+ QFETCH(bool, expectSuccess);
+
+ QStandardItem item(rows, columns);
+ QList<QStandardItem*> originalChildren;
+ // initialize children
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < columns; ++j) {
+ QStandardItem *child = new QStandardItem;
+ originalChildren.append(child);
+ item.setChild(i, j, child);
+ }
+ }
+
+ QList<QStandardItem *> taken = item.takeRow(row);
+ if (expectSuccess) {
+ QCOMPARE(taken.count(), item.columnCount());
+ QCOMPARE(item.rowCount(), rows - 1);
+ int index = row * columns;
+ for (int i = 0; i < taken.count(); ++i) {
+ QCOMPARE(taken.at(i), originalChildren.takeAt(index));
+ }
+ index = 0;
+ for (int i = 0; i < item.rowCount(); ++i) {
+ for (int j = 0; j < item.columnCount(); ++j) {
+ QCOMPARE(item.child(i, j), originalChildren.at(index));
+ ++index;
+ }
+ }
+ } else {
+ QVERIFY(taken.isEmpty());
+ }
+ qDeleteAll(taken);
+}
+
+void tst_QStandardItem::streamItem()
+{
+ QStandardItem item;
+
+ item.setText(QLatin1String("text"));
+ item.setToolTip(QLatin1String("toolTip"));
+ item.setStatusTip(QLatin1String("statusTip"));
+ item.setWhatsThis(QLatin1String("whatsThis"));
+ item.setSizeHint(QSize(64, 48));
+ item.setFont(QFont());
+ item.setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+ item.setBackground(QColor(Qt::blue));
+ item.setForeground(QColor(Qt::green));
+ item.setCheckState(Qt::PartiallyChecked);
+ item.setAccessibleText(QLatin1String("accessibleText"));
+ item.setAccessibleDescription(QLatin1String("accessibleDescription"));
+
+ QByteArray ba;
+ {
+ QDataStream ds(&ba, QIODevice::WriteOnly);
+ ds << item;
+ }
+ {
+ QStandardItem streamedItem;
+ QDataStream ds(&ba, QIODevice::ReadOnly);
+ ds >> streamedItem;
+ QCOMPARE(streamedItem.text(), item.text());
+ QCOMPARE(streamedItem.toolTip(), item.toolTip());
+ QCOMPARE(streamedItem.statusTip(), item.statusTip());
+ QCOMPARE(streamedItem.whatsThis(), item.whatsThis());
+ QCOMPARE(streamedItem.sizeHint(), item.sizeHint());
+ QCOMPARE(streamedItem.font(), item.font());
+ QCOMPARE(streamedItem.textAlignment(), item.textAlignment());
+ QCOMPARE(streamedItem.background(), item.background());
+ QCOMPARE(streamedItem.foreground(), item.foreground());
+ QCOMPARE(streamedItem.checkState(), item.checkState());
+ QCOMPARE(streamedItem.accessibleText(), item.accessibleText());
+ QCOMPARE(streamedItem.accessibleDescription(), item.accessibleDescription());
+ QCOMPARE(streamedItem.flags(), item.flags());
+ }
+}
+
+void tst_QStandardItem::deleteItem()
+{
+ QStandardItemModel model(4, 6);
+ // initialize items
+ for (int i = 0; i < model.rowCount(); ++i) {
+ for (int j = 0; j < model.columnCount(); ++j) {
+ QStandardItem *item = new QStandardItem();
+ model.setItem(i, j, item);
+ }
+ }
+ // delete items
+ for (int i = 0; i < model.rowCount(); ++i) {
+ for (int j = 0; j < model.columnCount(); ++j) {
+ QStandardItem *item = model.item(i, j);
+ delete item;
+ QCOMPARE(model.item(i, j), static_cast<QStandardItem*>(0));
+ }
+ }
+}
+
+void tst_QStandardItem::clone()
+{
+ QStandardItem item;
+ item.setText(QLatin1String("text"));
+ item.setToolTip(QLatin1String("toolTip"));
+ item.setStatusTip(QLatin1String("statusTip"));
+ item.setWhatsThis(QLatin1String("whatsThis"));
+ item.setSizeHint(QSize(64, 48));
+ item.setFont(QFont());
+ item.setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+ item.setBackground(QColor(Qt::blue));
+ item.setForeground(QColor(Qt::green));
+ item.setCheckState(Qt::PartiallyChecked);
+ item.setAccessibleText(QLatin1String("accessibleText"));
+ item.setAccessibleDescription(QLatin1String("accessibleDescription"));
+ item.setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled);
+
+ QStandardItem *clone = item.clone();
+ QCOMPARE(clone->text(), item.text());
+ QCOMPARE(clone->toolTip(), item.toolTip());
+ QCOMPARE(clone->statusTip(), item.statusTip());
+ QCOMPARE(clone->whatsThis(), item.whatsThis());
+ QCOMPARE(clone->sizeHint(), item.sizeHint());
+ QCOMPARE(clone->font(), item.font());
+ QCOMPARE(clone->textAlignment(), item.textAlignment());
+ QCOMPARE(clone->background(), item.background());
+ QCOMPARE(clone->foreground(), item.foreground());
+ QCOMPARE(clone->checkState(), item.checkState());
+ QCOMPARE(clone->accessibleText(), item.accessibleText());
+ QCOMPARE(clone->accessibleDescription(), item.accessibleDescription());
+ QCOMPARE(clone->flags(), item.flags());
+ QVERIFY(!(*clone < item));
+ delete clone;
+}
+
+void tst_QStandardItem::sortChildren()
+{
+ for (int x = 0; x < 2; ++x) {
+ QStandardItemModel *model = new QStandardItemModel;
+ QStandardItem *item = (x == 0) ? new QStandardItem : model->invisibleRootItem();
+ QStandardItem *one = new QStandardItem;
+ one->appendRow(new QStandardItem(QLatin1String("a")));
+ one->appendRow(new QStandardItem(QLatin1String("b")));
+ one->appendRow(new QStandardItem(QLatin1String("c")));
+ QStandardItem *two = new QStandardItem;
+ two->appendRow(new QStandardItem(QLatin1String("f")));
+ two->appendRow(new QStandardItem(QLatin1String("d")));
+ two->appendRow(new QStandardItem(QLatin1String("e")));
+ item->appendRow(one);
+ item->appendRow(two);
+
+ QSignalSpy layoutAboutToBeChangedSpy(
+ model, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy layoutChangedSpy(
+ model, SIGNAL(layoutChanged()));
+
+ one->sortChildren(0, Qt::DescendingOrder);
+ // verify sorted
+ QCOMPARE(one->child(0)->text(), QLatin1String("c"));
+ QCOMPARE(one->child(1)->text(), QLatin1String("b"));
+ QCOMPARE(one->child(2)->text(), QLatin1String("a"));
+ // verify siblings unaffected
+ QCOMPARE(two->child(0)->text(), QLatin1String("f"));
+ QCOMPARE(two->child(1)->text(), QLatin1String("d"));
+ QCOMPARE(two->child(2)->text(), QLatin1String("e"));
+
+ two->sortChildren(0, Qt::AscendingOrder);
+ // verify sorted
+ QCOMPARE(two->child(0)->text(), QLatin1String("d"));
+ QCOMPARE(two->child(1)->text(), QLatin1String("e"));
+ QCOMPARE(two->child(2)->text(), QLatin1String("f"));
+ // verify siblings unaffected
+ QCOMPARE(one->child(0)->text(), QLatin1String("c"));
+ QCOMPARE(one->child(1)->text(), QLatin1String("b"));
+ QCOMPARE(one->child(2)->text(), QLatin1String("a"));
+
+ item->sortChildren(0, Qt::AscendingOrder);
+ // verify everything sorted
+ QCOMPARE(one->child(0)->text(), QLatin1String("a"));
+ QCOMPARE(one->child(1)->text(), QLatin1String("b"));
+ QCOMPARE(one->child(2)->text(), QLatin1String("c"));
+ QCOMPARE(two->child(0)->text(), QLatin1String("d"));
+ QCOMPARE(two->child(1)->text(), QLatin1String("e"));
+ QCOMPARE(two->child(2)->text(), QLatin1String("f"));
+
+ QCOMPARE(layoutAboutToBeChangedSpy.count(), (x == 0) ? 0 : 3);
+ QCOMPARE(layoutChangedSpy.count(), (x == 0) ? 0 : 3);
+
+ if (x == 0)
+ delete item;
+ delete model;
+ }
+}
+
+class CustomItem : public QStandardItem
+{
+public:
+ CustomItem(const QString &text) : QStandardItem(text) { }
+ CustomItem() { }
+ virtual ~CustomItem() { }
+
+ virtual int type() const { return QStandardItem::UserType + 1; }
+
+ virtual QStandardItem *clone() const { return QStandardItem::clone(); }
+
+ void emitDataChanged() { QStandardItem::emitDataChanged(); }
+
+ virtual bool operator<(const QStandardItem &other) const {
+ return text().length() < other.text().length();
+ }
+};
+
+Q_DECLARE_METATYPE(QStandardItem*)
+
+void tst_QStandardItem::subclassing()
+{
+ qMetaTypeId<QStandardItem*>();
+
+ CustomItem *item = new CustomItem;
+ QCOMPARE(item->type(), int(QStandardItem::UserType + 1));
+
+ item->setText(QString::fromLatin1("foo"));
+ QCOMPARE(item->text(), QString::fromLatin1("foo"));
+
+ item->emitDataChanged(); // does nothing
+
+ QStandardItemModel model;
+ model.appendRow(item);
+
+ QSignalSpy itemChangedSpy(&model, SIGNAL(itemChanged(QStandardItem*)));
+ item->emitDataChanged();
+ QCOMPARE(itemChangedSpy.count(), 1);
+ QCOMPARE(itemChangedSpy.at(0).count(), 1);
+ QCOMPARE(qvariant_cast<QStandardItem*>(itemChangedSpy.at(0).at(0)), (QStandardItem*)item);
+
+ CustomItem *child0 = new CustomItem("cc");
+ CustomItem *child1 = new CustomItem("bbb");
+ CustomItem *child2 = new CustomItem("a");
+ item->appendRow(child0);
+ item->appendRow(child1);
+ item->appendRow(child2);
+ item->sortChildren(0);
+ QCOMPARE(item->child(0), (QStandardItem*)child2);
+ QCOMPARE(item->child(1), (QStandardItem*)child0);
+ QCOMPARE(item->child(2), (QStandardItem*)child1);
+}
+
+QTEST_MAIN(tst_QStandardItem)
+#include "tst_qstandarditem.moc"
diff --git a/tests/auto/widgets/itemviews/qstandarditemmodel/.gitignore b/tests/auto/widgets/itemviews/qstandarditemmodel/.gitignore
new file mode 100644
index 0000000000..c218efce58
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstandarditemmodel/.gitignore
@@ -0,0 +1 @@
+tst_qstandarditemmodel
diff --git a/tests/auto/widgets/itemviews/qstandarditemmodel/qstandarditemmodel.pro b/tests/auto/widgets/itemviews/qstandarditemmodel/qstandarditemmodel.pro
new file mode 100644
index 0000000000..8c634b9630
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstandarditemmodel/qstandarditemmodel.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+
+QT += widgets widgets-private
+QT += core-private gui-private
+
+SOURCES += tst_qstandarditemmodel.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/widgets/itemviews/qstandarditemmodel/tst_qstandarditemmodel.cpp
new file mode 100644
index 0000000000..84a33107aa
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstandarditemmodel/tst_qstandarditemmodel.cpp
@@ -0,0 +1,1666 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qstandarditemmodel.h>
+#include <QTreeView>
+#include <private/qtreeview_p.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QStandardItemModel : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QStandardItemModel();
+ virtual ~tst_QStandardItemModel();
+
+ enum ModelChanged {
+ RowsAboutToBeInserted,
+ RowsInserted,
+ RowsAboutToBeRemoved,
+ RowsRemoved,
+ ColumnsAboutToBeInserted,
+ ColumnsInserted,
+ ColumnsAboutToBeRemoved,
+ ColumnsRemoved
+ };
+
+public slots:
+ void init();
+ void cleanup();
+
+protected slots:
+ void checkAboutToBeRemoved();
+ void checkRemoved();
+ void updateRowAboutToBeRemoved();
+
+ void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsAboutToBeInserted, parent, first, last); }
+ void rowsInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsInserted, parent, first, last); }
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsAboutToBeRemoved, parent, first, last); }
+ void rowsRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(RowsRemoved, parent, first, last); }
+ void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsAboutToBeInserted, parent, first, last); }
+ void columnsInserted(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsInserted, parent, first, last); }
+ void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsAboutToBeRemoved, parent, first, last); }
+ void columnsRemoved(const QModelIndex &parent, int first, int last)
+ { modelChanged(ColumnsRemoved, parent, first, last); }
+
+ void modelChanged(ModelChanged change, const QModelIndex &parent, int first, int last);
+
+private slots:
+ void insertRow_data();
+ void insertRow();
+ void insertRows();
+ void insertRowsItems();
+ void insertRowInHierarcy();
+ void insertColumn_data();
+ void insertColumn();
+ void insertColumns();
+ void removeRows();
+ void removeColumns();
+ void setHeaderData();
+ void persistentIndexes();
+ void removingPersistentIndexes();
+ void updatingPersistentIndexes();
+
+ void checkChildren();
+ void data();
+ void clear();
+ void sort_data();
+ void sort();
+ void sortRole_data();
+ void sortRole();
+ void findItems();
+ void getSetHeaderItem();
+ void indexFromItem();
+ void itemFromIndex();
+ void getSetItemPrototype();
+ void getSetItemData();
+ void setHeaderLabels_data();
+ void setHeaderLabels();
+ void itemDataChanged();
+ void takeHeaderItem();
+ void useCase1();
+ void useCase2();
+ void useCase3();
+
+ void rootItemFlags();
+ void treeDragAndDrop();
+ void removeRowsAndColumns();
+
+private:
+ QAbstractItemModel *m_model;
+ QPersistentModelIndex persistent;
+ QVector<QModelIndex> rcParent;
+ QVector<int> rcFirst;
+ QVector<int> rcLast;
+
+ //return true if models have the same structure, and all child have the same text
+ bool compareModels(QStandardItemModel *model1, QStandardItemModel *model2);
+ //return true if models have the same structure, and all child have the same text
+ bool compareItems(QStandardItem *item1, QStandardItem *item2);
+};
+
+static const int defaultSize = 3;
+
+Q_DECLARE_METATYPE(QModelIndex)
+Q_DECLARE_METATYPE(QStandardItem*)
+Q_DECLARE_METATYPE(Qt::Orientation)
+Q_DECLARE_METATYPE(QVariantList)
+
+tst_QStandardItemModel::tst_QStandardItemModel() : m_model(0), rcParent(8), rcFirst(8,0), rcLast(8,0)
+{
+}
+
+tst_QStandardItemModel::~tst_QStandardItemModel()
+{
+}
+
+/*
+ This test usually uses a model with a 3x3 table
+ ---------------------------
+ | 0,0 | 0,1 | 0,2 |
+ ---------------------------
+ | 1,0 | 1,1 | 1,2 |
+ ---------------------------
+ | 2,0 | 2,1 | 2,2 |
+ ---------------------------
+*/
+void tst_QStandardItemModel::init()
+{
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+ qRegisterMetaType<QStandardItem*>("QStandardItem*");
+ qRegisterMetaType<Qt::Orientation>("Qt::Orientation");
+
+ m_model = new QStandardItemModel(defaultSize, defaultSize);
+ connect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
+ this, SLOT(rowsAboutToBeInserted(QModelIndex, int, int)));
+ connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)),
+ this, SLOT(rowsInserted(QModelIndex, int, int)));
+ connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int)));
+ connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsRemoved(QModelIndex, int, int)));
+
+ connect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)),
+ this, SLOT(columnsAboutToBeInserted(QModelIndex, int, int)));
+ connect(m_model, SIGNAL(columnsInserted(QModelIndex, int, int)),
+ this, SLOT(columnsInserted(QModelIndex, int, int)));
+ connect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+ this, SLOT(columnsAboutToBeRemoved(QModelIndex, int, int)));
+ connect(m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)),
+ this, SLOT(columnsRemoved(QModelIndex, int, int)));
+
+ rcFirst.fill(-1);
+ rcLast.fill(-1);
+}
+
+void tst_QStandardItemModel::cleanup()
+{
+ disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
+ this, SLOT(rowsAboutToBeInserted(QModelIndex, int, int)));
+ disconnect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)),
+ this, SLOT(rowsInserted(QModelIndex, int, int)));
+ disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int)));
+ disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ this, SLOT(rowsRemoved(QModelIndex, int, int)));
+
+ disconnect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)),
+ this, SLOT(columnsAboutToBeInserted(QModelIndex, int, int)));
+ disconnect(m_model, SIGNAL(columnsInserted(QModelIndex, int, int)),
+ this, SLOT(columnsInserted(QModelIndex, int, int)));
+ disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+ this, SLOT(columnsAboutToBeRemoved(QModelIndex, int, int)));
+ disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)),
+ this, SLOT(columnsRemoved(QModelIndex, int, int)));
+ delete m_model;
+ m_model = 0;
+}
+
+void tst_QStandardItemModel::insertRow_data()
+{
+ QTest::addColumn<int>("insertRow");
+ QTest::addColumn<int>("expectedRow");
+
+ QTest::newRow("Insert less then 0") << -1 << 0;
+ QTest::newRow("Insert at 0") << 0 << 0;
+ QTest::newRow("Insert beyond count") << defaultSize+1 << defaultSize;
+ QTest::newRow("Insert at count") << defaultSize << defaultSize;
+ QTest::newRow("Insert in the middle") << 1 << 1;
+}
+
+void tst_QStandardItemModel::insertRow()
+{
+ QFETCH(int, insertRow);
+ QFETCH(int, expectedRow);
+
+ QIcon icon;
+ // default all initial items to DisplayRole: "initalitem"
+ for (int r=0; r < m_model->rowCount(); ++r) {
+ for (int c=0; c < m_model->columnCount(); ++c) {
+ m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole);
+ }
+ }
+
+ // check that inserts changes rowCount
+ QCOMPARE(m_model->rowCount(), defaultSize);
+ m_model->insertRow(insertRow);
+ if (insertRow >= 0 && insertRow <= defaultSize) {
+ QCOMPARE(m_model->rowCount(), defaultSize + 1);
+
+ // check that signals were emitted with correct info
+ QCOMPARE(rcFirst[RowsAboutToBeInserted], expectedRow);
+ QCOMPARE(rcLast[RowsAboutToBeInserted], expectedRow);
+ QCOMPARE(rcFirst[RowsInserted], expectedRow);
+ QCOMPARE(rcLast[RowsInserted], expectedRow);
+
+ //check that the inserted item has different DisplayRole than initial items
+ QVERIFY(m_model->data(m_model->index(expectedRow, 0), Qt::DisplayRole).toString() != "initialitem");
+ } else {
+ // We inserted something outside the bounds, do nothing
+ QCOMPARE(m_model->rowCount(), defaultSize);
+ QCOMPARE(rcFirst[RowsAboutToBeInserted], -1);
+ QCOMPARE(rcLast[RowsAboutToBeInserted], -1);
+ QCOMPARE(rcFirst[RowsInserted], -1);
+ QCOMPARE(rcLast[RowsInserted], -1);
+ }
+}
+
+void tst_QStandardItemModel::insertRows()
+{
+ int rowCount = m_model->rowCount();
+ QCOMPARE(rowCount, defaultSize);
+
+ // insert custom header label
+ QString headerLabel = "custom";
+ m_model->setHeaderData(0, Qt::Vertical, headerLabel);
+
+ // insert one row
+ m_model->insertRows(0, 1);
+ QCOMPARE(m_model->rowCount(), rowCount + 1);
+ rowCount = m_model->rowCount();
+
+ // check header data has moved
+ QCOMPARE(m_model->headerData(1, Qt::Vertical).toString(), headerLabel);
+
+ // insert two rows
+ m_model->insertRows(0, 2);
+ QCOMPARE(m_model->rowCount(), rowCount + 2);
+
+ // check header data has moved
+ QCOMPARE(m_model->headerData(3, Qt::Vertical).toString(), headerLabel);
+}
+
+void tst_QStandardItemModel::insertRowsItems()
+{
+ int rowCount = m_model->rowCount();
+
+ QList<QStandardItem *> items;
+ QStandardItemModel *m = qobject_cast<QStandardItemModel*>(m_model);
+ QStandardItem *hiddenRoot = m->invisibleRootItem();
+ for (int i = 0; i < 3; ++i)
+ items.append(new QStandardItem(QString("%1").arg(i + 10)));
+ hiddenRoot->appendRows(items);
+ QCOMPARE(m_model->rowCount(), rowCount + 3);
+ QCOMPARE(m_model->index(rowCount + 0, 0).data().toInt(), 10);
+ QCOMPARE(m_model->index(rowCount + 1, 0).data().toInt(), 11);
+ QCOMPARE(m_model->index(rowCount + 2, 0).data().toInt(), 12);
+ for (int i = rowCount; i < rowCount + 3; ++i) {
+ QVERIFY(m->item(i));
+ QCOMPARE(static_cast<QAbstractItemModel *>(m->item(i)->model()), m_model);
+ }
+}
+
+void tst_QStandardItemModel::insertRowInHierarcy()
+{
+ QVERIFY(m_model->insertRows(0, 1, QModelIndex()));
+ QVERIFY(m_model->insertColumns(0, 1, QModelIndex()));
+ QVERIFY(m_model->hasIndex(0, 0, QModelIndex()));
+
+ QModelIndex parent = m_model->index(0, 0, QModelIndex());
+ QVERIFY(parent.isValid());
+
+ QVERIFY(m_model->insertRows(0, 1, parent));
+ QVERIFY(m_model->insertColumns(0, 1, parent));
+ QVERIFY(m_model->hasIndex(0, 0, parent));
+
+ QModelIndex child = m_model->index(0, 0, parent);
+ QVERIFY(child.isValid());
+}
+
+void tst_QStandardItemModel::insertColumn_data()
+{
+ QTest::addColumn<int>("insertColumn");
+ QTest::addColumn<int>("expectedColumn");
+
+ QTest::newRow("Insert less then 0") << -1 << 0;
+ QTest::newRow("Insert at 0") << 0 << 0;
+ QTest::newRow("Insert beyond count") << defaultSize+1 << defaultSize;
+ QTest::newRow("Insert at count") << defaultSize << defaultSize;
+ QTest::newRow("Insert in the middle") << 1 << 1;
+}
+
+void tst_QStandardItemModel::insertColumn()
+{
+ QFETCH(int, insertColumn);
+ QFETCH(int, expectedColumn);
+
+ // default all initial items to DisplayRole: "initalitem"
+ for (int r=0; r < m_model->rowCount(); ++r) {
+ for (int c=0; c < m_model->columnCount(); ++c) {
+ m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole);
+ }
+ }
+
+ // check that inserts changes columnCount
+ QCOMPARE(m_model->columnCount(), defaultSize);
+ m_model->insertColumn(insertColumn);
+ if (insertColumn >= 0 && insertColumn <= defaultSize) {
+ QCOMPARE(m_model->columnCount(), defaultSize + 1);
+ // check that signals were emitted with correct info
+ QCOMPARE(rcFirst[ColumnsAboutToBeInserted], expectedColumn);
+ QCOMPARE(rcLast[ColumnsAboutToBeInserted], expectedColumn);
+ QCOMPARE(rcFirst[ColumnsInserted], expectedColumn);
+ QCOMPARE(rcLast[ColumnsInserted], expectedColumn);
+
+ //check that the inserted item has different DisplayRole than initial items
+ QVERIFY(m_model->data(m_model->index(0, expectedColumn), Qt::DisplayRole).toString() != "initialitem");
+ } else {
+ // We inserted something outside the bounds, do nothing
+ QCOMPARE(m_model->columnCount(), defaultSize);
+ QCOMPARE(rcFirst[ColumnsAboutToBeInserted], -1);
+ QCOMPARE(rcLast[ColumnsAboutToBeInserted], -1);
+ QCOMPARE(rcFirst[ColumnsInserted], -1);
+ QCOMPARE(rcLast[ColumnsInserted], -1);
+ }
+
+}
+
+void tst_QStandardItemModel::insertColumns()
+{
+ int columnCount = m_model->columnCount();
+ QCOMPARE(columnCount, defaultSize);
+
+ // insert custom header label
+ QString headerLabel = "custom";
+ m_model->setHeaderData(0, Qt::Horizontal, headerLabel);
+
+ // insert one column
+ m_model->insertColumns(0, 1);
+ QCOMPARE(m_model->columnCount(), columnCount + 1);
+ columnCount = m_model->columnCount();
+
+ // check header data has moved
+ QCOMPARE(m_model->headerData(1, Qt::Horizontal).toString(), headerLabel);
+
+ // insert two columns
+ m_model->insertColumns(0, 2);
+ QCOMPARE(m_model->columnCount(), columnCount + 2);
+
+ // check header data has moved
+ QCOMPARE(m_model->headerData(3, Qt::Horizontal).toString(), headerLabel);
+}
+
+void tst_QStandardItemModel::removeRows()
+{
+ int rowCount = m_model->rowCount();
+ QCOMPARE(rowCount, defaultSize);
+
+ // insert custom header label
+ QString headerLabel = "custom";
+ m_model->setHeaderData(rowCount - 1, Qt::Vertical, headerLabel);
+
+ // remove one row
+ m_model->removeRows(0, 1);
+ QCOMPARE(m_model->rowCount(), rowCount - 1);
+ rowCount = m_model->rowCount();
+
+ // check header data has moved
+ QCOMPARE(m_model->headerData(rowCount - 1, Qt::Vertical).toString(), headerLabel);
+
+ // remove two rows
+ m_model->removeRows(0, 2);
+ QCOMPARE(m_model->rowCount(), rowCount - 2);
+}
+
+void tst_QStandardItemModel::removeColumns()
+{
+ int columnCount = m_model->columnCount();
+ QCOMPARE(columnCount, defaultSize);
+
+ // insert custom header label
+ QString headerLabel = "custom";
+ m_model->setHeaderData(columnCount - 1, Qt::Horizontal, headerLabel);
+
+ // remove one column
+ m_model->removeColumns(0, 1);
+ QCOMPARE(m_model->columnCount(), columnCount - 1);
+ columnCount = m_model->columnCount();
+
+ // check header data has moved
+ QCOMPARE(m_model->headerData(columnCount - 1, Qt::Horizontal).toString(), headerLabel);
+
+ // remove two columns
+ m_model->removeColumns(0, 2);
+ QCOMPARE(m_model->columnCount(), columnCount - 2);
+}
+
+
+void tst_QStandardItemModel::setHeaderData()
+{
+ for (int x = 0; x < 2; ++x) {
+ bool vertical = (x == 0);
+ int count = vertical ? m_model->rowCount() : m_model->columnCount();
+ QCOMPARE(count, defaultSize);
+ Qt::Orientation orient = vertical ? Qt::Vertical : Qt::Horizontal;
+
+ // check default values are ok
+ for (int i = 0; i < count; ++i)
+ QCOMPARE(m_model->headerData(i, orient).toString(), QString::number(i + 1));
+
+ QSignalSpy headerDataChangedSpy(
+ m_model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)));
+ QSignalSpy dataChangedSpy(
+ m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex)));
+ // insert custom values and check
+ for (int i = 0; i < count; ++i) {
+ QString customString = QString("custom") + QString::number(i);
+ QCOMPARE(m_model->setHeaderData(i, orient, customString), true);
+ QCOMPARE(headerDataChangedSpy.count(), 1);
+ QCOMPARE(dataChangedSpy.count(), 0);
+ QVariantList args = headerDataChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<Qt::Orientation>(args.at(0)), orient);
+ QCOMPARE(args.at(1).toInt(), i);
+ QCOMPARE(args.at(2).toInt(), i);
+ QCOMPARE(m_model->headerData(i, orient).toString(), customString);
+ QCOMPARE(m_model->setHeaderData(i, orient, customString), true);
+ QCOMPARE(headerDataChangedSpy.count(), 0);
+ QCOMPARE(dataChangedSpy.count(), 0);
+ }
+
+ //check read from invalid sections
+ QVERIFY(!m_model->headerData(count, orient).isValid());
+ QVERIFY(!m_model->headerData(-1, orient).isValid());
+ //check write to invalid section
+ QCOMPARE(m_model->setHeaderData(count, orient, "foo"), false);
+ QCOMPARE(m_model->setHeaderData(-1, orient, "foo"), false);
+ QVERIFY(!m_model->headerData(count, orient).isValid());
+ QVERIFY(!m_model->headerData(-1, orient).isValid());
+ }
+}
+
+void tst_QStandardItemModel::persistentIndexes()
+{
+ QCOMPARE(m_model->rowCount(), defaultSize);
+ QCOMPARE(m_model->columnCount(), defaultSize);
+
+ // create a persisten index at 0,0
+ QPersistentModelIndex persistentIndex(m_model->index(0, 0));
+
+ // verify it is ok and at the correct spot
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 0);
+ QCOMPARE(persistentIndex.column(), 0);
+
+ // insert row and check that the persisten index has moved
+ QVERIFY(m_model->insertRow(0));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 1);
+ QCOMPARE(persistentIndex.column(), 0);
+
+ // insert row after the persisten index and see that it stays the same
+ QVERIFY(m_model->insertRow(m_model->rowCount()));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 1);
+ QCOMPARE(persistentIndex.column(), 0);
+
+ // insert column and check that the persisten index has moved
+ QVERIFY(m_model->insertColumn(0));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 1);
+ QCOMPARE(persistentIndex.column(), 1);
+
+ // insert column after the persisten index and see that it stays the same
+ QVERIFY(m_model->insertColumn(m_model->columnCount()));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 1);
+ QCOMPARE(persistentIndex.column(), 1);
+
+ // removes a row beyond the persistent index and see it stays the same
+ QVERIFY(m_model->removeRow(m_model->rowCount() - 1));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 1);
+ QCOMPARE(persistentIndex.column(), 1);
+
+ // removes a column beyond the persistent index and see it stays the same
+ QVERIFY(m_model->removeColumn(m_model->columnCount() - 1));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 1);
+ QCOMPARE(persistentIndex.column(), 1);
+
+ // removes a row before the persistent index and see it moves the same
+ QVERIFY(m_model->removeRow(0));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 0);
+ QCOMPARE(persistentIndex.column(), 1);
+
+ // removes a column before the persistent index and see it moves the same
+ QVERIFY(m_model->removeColumn(0));
+ QVERIFY(persistentIndex.isValid());
+ QCOMPARE(persistentIndex.row(), 0);
+ QCOMPARE(persistentIndex.column(), 0);
+
+ // remove the row where the persistent index is, and see that it becomes invalid
+ QVERIFY(m_model->removeRow(0));
+ QVERIFY(!persistentIndex.isValid());
+
+ // remove the row where the persistent index is, and see that it becomes invalid
+ persistentIndex = m_model->index(0, 0);
+ QVERIFY(persistentIndex.isValid());
+ QVERIFY(m_model->removeColumn(0));
+ QVERIFY(!persistentIndex.isValid());
+}
+
+void tst_QStandardItemModel::checkAboutToBeRemoved()
+{
+ QVERIFY(persistent.isValid());
+}
+
+void tst_QStandardItemModel::checkRemoved()
+{
+ QVERIFY(!persistent.isValid());
+}
+
+void tst_QStandardItemModel::removingPersistentIndexes()
+{
+ // add 10 rows and columns to model to make it big enough
+ QVERIFY(m_model->insertRows(0, 10));
+ QVERIFY(m_model->insertColumns(0, 10));
+
+ QObject::connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(checkAboutToBeRemoved()));
+ QObject::connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(checkRemoved()));
+ QObject::connect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(checkAboutToBeRemoved()));
+ QObject::connect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+ this, SLOT(checkRemoved()));
+
+
+ // test removeRow
+ // add child table 3x3 to parent index(0, 0)
+ QVERIFY(m_model->insertRows(0, 3, m_model->index(0, 0)));
+ QVERIFY(m_model->insertColumns(0, 3, m_model->index(0, 0)));
+
+ // set child to persistent and delete parent row
+ persistent = m_model->index(0, 0, m_model->index(0, 0));
+ QVERIFY(persistent.isValid());
+ QVERIFY(m_model->removeRow(0));
+
+ // set persistent to index(0, 0) and remove that row
+ persistent = m_model->index(0, 0);
+ QVERIFY(persistent.isValid());
+ QVERIFY(m_model->removeRow(0));
+
+
+ // test removeColumn
+ // add child table 3x3 to parent index (0, 0)
+ QVERIFY(m_model->insertRows(0, 3, m_model->index(0, 0)));
+ QVERIFY(m_model->insertColumns(0, 3, m_model->index(0, 0)));
+
+ // set child to persistent and delete parent column
+ persistent = m_model->index(0, 0, m_model->index(0, 0));
+ QVERIFY(persistent.isValid());
+ QVERIFY(m_model->removeColumn(0));
+
+ // set persistent to index(0, 0) and remove that column
+ persistent = m_model->index(0, 0);
+ QVERIFY(persistent.isValid());
+ QVERIFY(m_model->removeColumn(0));
+
+
+ QObject::disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(checkAboutToBeRemoved()));
+ QObject::disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(checkRemoved()));
+ QObject::disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(checkAboutToBeRemoved()));
+ QObject::disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+ this, SLOT(checkRemoved()));
+}
+
+void tst_QStandardItemModel::updateRowAboutToBeRemoved()
+{
+ QModelIndex idx = m_model->index(0, 0);
+ QVERIFY(idx.isValid());
+ persistent = idx;
+}
+
+void tst_QStandardItemModel::updatingPersistentIndexes()
+{
+ QObject::connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(updateRowAboutToBeRemoved()));
+
+ persistent = m_model->index(1, 0);
+ QVERIFY(persistent.isValid());
+ QVERIFY(m_model->removeRow(1));
+ QVERIFY(persistent.isValid());
+ QPersistentModelIndex tmp = m_model->index(0, 0);
+ QCOMPARE(persistent, tmp);
+
+ QObject::disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(updateRowAboutToBeRemoved()));
+}
+
+void tst_QStandardItemModel::modelChanged(ModelChanged change, const QModelIndex &parent,
+ int first, int last)
+{
+ rcParent[change] = parent;
+ rcFirst[change] = first;
+ rcLast[change] = last;
+}
+
+
+void tst_QStandardItemModel::checkChildren()
+{
+ QStandardItemModel model(0, 0);
+ QCOMPARE(model.rowCount(), 0);
+ QCOMPARE(model.columnCount(), 0);
+ QVERIFY(!model.hasChildren());
+
+ QVERIFY(model.insertRows(0, 1));
+ QVERIFY(!model.hasChildren());
+ QCOMPARE(model.rowCount(), 1);
+ QCOMPARE(model.columnCount(), 0);
+
+ QVERIFY(model.insertColumns(0, 1));
+ QVERIFY(model.hasChildren());
+ QCOMPARE(model.rowCount(), 1);
+ QCOMPARE(model.columnCount(), 1);
+
+ QModelIndex idx = model.index(0, 0);
+ QVERIFY(!model.hasChildren(idx));
+ QCOMPARE(model.rowCount(idx), 0);
+ QCOMPARE(model.columnCount(idx), 0);
+
+ QVERIFY(model.insertRows(0, 1, idx));
+ QVERIFY(!model.hasChildren(idx));
+ QCOMPARE(model.rowCount(idx), 1);
+ QCOMPARE(model.columnCount(idx), 0);
+
+ QVERIFY(model.insertColumns(0, 1, idx));
+ QVERIFY(model.hasChildren(idx));
+ QCOMPARE(model.rowCount(idx), 1);
+ QCOMPARE(model.columnCount(idx), 1);
+
+ QModelIndex idx2 = model.index(0, 0, idx);
+ QVERIFY(!model.hasChildren(idx2));
+ QCOMPARE(model.rowCount(idx2), 0);
+ QCOMPARE(model.columnCount(idx2), 0);
+
+ QVERIFY(model.removeRows(0, 1, idx));
+ QVERIFY(model.hasChildren());
+ QCOMPARE(model.rowCount(), 1);
+ QCOMPARE(model.columnCount(), 1);
+ QVERIFY(!model.hasChildren(idx));
+ QCOMPARE(model.rowCount(idx), 0);
+ QCOMPARE(model.columnCount(idx), 1);
+
+ QVERIFY(model.removeRows(0, 1));
+ QVERIFY(!model.hasChildren());
+ QCOMPARE(model.rowCount(), 0);
+ QCOMPARE(model.columnCount(), 1);
+}
+
+void tst_QStandardItemModel::data()
+{
+ // bad args
+ m_model->setData(QModelIndex(), "bla", Qt::DisplayRole);
+
+ QIcon icon;
+ for (int r=0; r < m_model->rowCount(); ++r) {
+ for (int c=0; c < m_model->columnCount(); ++c) {
+ m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole);
+ m_model->setData(m_model->index(r,c), "tooltip", Qt::ToolTipRole);
+ m_model->setData(m_model->index(r,c), icon, Qt::DecorationRole);
+ }
+ }
+
+ QVERIFY(m_model->data(m_model->index(0, 0), Qt::DisplayRole).toString() == "initialitem");
+ QVERIFY(m_model->data(m_model->index(0, 0), Qt::ToolTipRole).toString() == "tooltip");
+
+}
+
+void tst_QStandardItemModel::clear()
+{
+ QStandardItemModel model;
+ model.insertColumns(0, 10);
+ model.insertRows(0, 10);
+ QCOMPARE(model.columnCount(), 10);
+ QCOMPARE(model.rowCount(), 10);
+
+ QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
+ QSignalSpy layoutChangedSpy(&model, SIGNAL(layoutChanged()));
+ QSignalSpy rowsRemovedSpy(&model, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ model.clear();
+
+ QCOMPARE(modelResetSpy.count(), 1);
+ QCOMPARE(layoutChangedSpy.count(), 0);
+ QCOMPARE(rowsRemovedSpy.count(), 0);
+ QCOMPARE(model.index(0, 0), QModelIndex());
+ QCOMPARE(model.columnCount(), 0);
+ QCOMPARE(model.rowCount(), 0);
+ QCOMPARE(model.hasChildren(), false);
+}
+
+void tst_QStandardItemModel::sort_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+ QTest::newRow("flat descending") << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima"
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel"
+ << "uniform"
+ << "alpha"
+ << "echo"
+ << "golf"
+ << "quebec"
+ << "foxtrot"
+ << "india"
+ << "romeo"
+ << "november"
+ << "oskar"
+ << "zulu"
+ << "kilo"
+ << "whiskey"
+ << "mike"
+ << "papa"
+ << "sierra"
+ << "xray"
+ << "viktor")
+ << (QStringList()
+ << "zulu"
+ << "yankee"
+ << "xray"
+ << "whiskey"
+ << "viktor"
+ << "uniform"
+ << "tango"
+ << "sierra"
+ << "romeo"
+ << "quebec"
+ << "papa"
+ << "oskar"
+ << "november"
+ << "mike"
+ << "lima"
+ << "kilo"
+ << "juliet"
+ << "india"
+ << "hotel"
+ << "golf"
+ << "foxtrot"
+ << "echo"
+ << "delta"
+ << "charlie"
+ << "bravo"
+ << "alpha");
+ QTest::newRow("flat ascending") << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima"
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel"
+ << "uniform"
+ << "alpha"
+ << "echo"
+ << "golf"
+ << "quebec"
+ << "foxtrot"
+ << "india"
+ << "romeo"
+ << "november"
+ << "oskar"
+ << "zulu"
+ << "kilo"
+ << "whiskey"
+ << "mike"
+ << "papa"
+ << "sierra"
+ << "xray"
+ << "viktor")
+ << (QStringList()
+ << "alpha"
+ << "bravo"
+ << "charlie"
+ << "delta"
+ << "echo"
+ << "foxtrot"
+ << "golf"
+ << "hotel"
+ << "india"
+ << "juliet"
+ << "kilo"
+ << "lima"
+ << "mike"
+ << "november"
+ << "oskar"
+ << "papa"
+ << "quebec"
+ << "romeo"
+ << "sierra"
+ << "tango"
+ << "uniform"
+ << "viktor"
+ << "whiskey"
+ << "xray"
+ << "yankee"
+ << "zulu");
+ QStringList list;
+ for (int i=1000; i < 2000; ++i)
+ list.append(QString("Number: %1").arg(i));
+ QTest::newRow("large set ascending") << static_cast<int>(Qt::AscendingOrder) << list << list;
+}
+
+void tst_QStandardItemModel::sort()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ // prepare model
+ QStandardItemModel model;
+ QVERIFY(model.insertRows(0, initial.count(), QModelIndex()));
+ QCOMPARE(model.rowCount(QModelIndex()), initial.count());
+ model.insertColumns(0, 1, QModelIndex());
+ QCOMPARE(model.columnCount(QModelIndex()), 1);
+ for (int row = 0; row < model.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = model.index(row, 0, QModelIndex());
+ model.setData(index, initial.at(row), Qt::DisplayRole);
+ }
+
+ QSignalSpy layoutAboutToBeChangedSpy(
+ &model, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy layoutChangedSpy(
+ &model, SIGNAL(layoutChanged()));
+
+ // sort
+ model.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+
+ QCOMPARE(layoutAboutToBeChangedSpy.count(), 1);
+ QCOMPARE(layoutChangedSpy.count(), 1);
+
+ // make sure the model is sorted
+ for (int row = 0; row < model.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = model.index(row, 0, QModelIndex());
+ QCOMPARE(model.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+void tst_QStandardItemModel::sortRole_data()
+{
+ QTest::addColumn<QStringList>("initialText");
+ QTest::addColumn<QVariantList>("initialData");
+ QTest::addColumn<int>("sortRole");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("expectedText");
+ QTest::addColumn<QVariantList>("expectedData");
+
+ QTest::newRow("sort ascending with Qt::DisplayRole")
+ << (QStringList() << "b" << "a" << "c")
+ << (QVariantList() << 2 << 3 << 1)
+ << static_cast<int>(Qt::DisplayRole)
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "b" << "c")
+ << (QVariantList() << 3 << 2 << 1);
+ QTest::newRow("sort ascending with Qt::UserRole")
+ << (QStringList() << "a" << "b" << "c")
+ << (QVariantList() << 3 << 2 << 1)
+ << static_cast<int>(Qt::UserRole)
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "b" << "a")
+ << (QVariantList() << 1 << 2 << 3);
+}
+
+void tst_QStandardItemModel::sortRole()
+{
+ QFETCH(QStringList, initialText);
+ QFETCH(QVariantList, initialData);
+ QFETCH(int, sortRole);
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, expectedText);
+ QFETCH(QVariantList, expectedData);
+
+ QStandardItemModel model;
+ for (int i = 0; i < initialText.count(); ++i) {
+ QStandardItem *item = new QStandardItem;
+ item->setText(initialText.at(i));
+ item->setData(initialData.at(i), Qt::UserRole);
+ model.appendRow(item);
+ }
+ model.setSortRole(sortRole);
+ model.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ for (int i = 0; i < expectedText.count(); ++i) {
+ QStandardItem *item = model.item(i);
+ QCOMPARE(item->text(), expectedText.at(i));
+ QCOMPARE(item->data(Qt::UserRole), expectedData.at(i));
+ }
+}
+
+void tst_QStandardItemModel::findItems()
+{
+ QStandardItemModel model;
+ model.appendRow(new QStandardItem(QLatin1String("foo")));
+ model.appendRow(new QStandardItem(QLatin1String("bar")));
+ model.item(1)->appendRow(new QStandardItem(QLatin1String("foo")));
+ QList<QStandardItem*> matches;
+ matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly|Qt::MatchRecursive, 0);
+ QCOMPARE(matches.count(), 2);
+ matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly, 0);
+ QCOMPARE(matches.count(), 1);
+ matches = model.findItems(QLatin1String("food"), Qt::MatchExactly|Qt::MatchRecursive, 0);
+ QCOMPARE(matches.count(), 0);
+ matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly|Qt::MatchRecursive, -1);
+ QCOMPARE(matches.count(), 0);
+ matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly|Qt::MatchRecursive, 1);
+ QCOMPARE(matches.count(), 0);
+}
+
+void tst_QStandardItemModel::getSetHeaderItem()
+{
+ QStandardItemModel model;
+
+ QCOMPARE(model.horizontalHeaderItem(0), static_cast<QStandardItem*>(0));
+ QStandardItem *hheader = new QStandardItem();
+ model.setHorizontalHeaderItem(0, hheader);
+ QCOMPARE(model.columnCount(), 1);
+ QCOMPARE(model.horizontalHeaderItem(0), hheader);
+ QCOMPARE(hheader->model(), &model);
+ model.setHorizontalHeaderItem(0, 0);
+ QCOMPARE(model.horizontalHeaderItem(0), static_cast<QStandardItem*>(0));
+
+ QCOMPARE(model.verticalHeaderItem(0), static_cast<QStandardItem*>(0));
+ QStandardItem *vheader = new QStandardItem();
+ model.setVerticalHeaderItem(0, vheader);
+ QCOMPARE(model.rowCount(), 1);
+ QCOMPARE(model.verticalHeaderItem(0), vheader);
+ QCOMPARE(vheader->model(), &model);
+ model.setVerticalHeaderItem(0, 0);
+ QCOMPARE(model.verticalHeaderItem(0), static_cast<QStandardItem*>(0));
+}
+
+void tst_QStandardItemModel::indexFromItem()
+{
+ QStandardItemModel model;
+
+ QCOMPARE(model.indexFromItem(model.invisibleRootItem()), QModelIndex());
+
+ QStandardItem *item = new QStandardItem;
+ model.setItem(10, 20, item);
+ QCOMPARE(item->model(), &model);
+ QModelIndex itemIndex = model.indexFromItem(item);
+ QVERIFY(itemIndex.isValid());
+ QCOMPARE(itemIndex.row(), 10);
+ QCOMPARE(itemIndex.column(), 20);
+ QCOMPARE(itemIndex.parent(), QModelIndex());
+ QCOMPARE(itemIndex.model(), (const QAbstractItemModel*)(&model));
+
+ QStandardItem *child = new QStandardItem;
+ item->setChild(4, 2, child);
+ QModelIndex childIndex = model.indexFromItem(child);
+ QVERIFY(childIndex.isValid());
+ QCOMPARE(childIndex.row(), 4);
+ QCOMPARE(childIndex.column(), 2);
+ QCOMPARE(childIndex.parent(), itemIndex);
+
+ QStandardItem *dummy = new QStandardItem;
+ QModelIndex noSuchIndex = model.indexFromItem(dummy);
+ QVERIFY(!noSuchIndex.isValid());
+ delete dummy;
+
+ noSuchIndex = model.indexFromItem(0);
+ QVERIFY(!noSuchIndex.isValid());
+}
+
+void tst_QStandardItemModel::itemFromIndex()
+{
+ QStandardItemModel model;
+
+ QCOMPARE(model.itemFromIndex(QModelIndex()), (QStandardItem*)0);
+
+ QStandardItem *item = new QStandardItem;
+ model.setItem(10, 20, item);
+ QModelIndex itemIndex = model.index(10, 20, QModelIndex());
+ QVERIFY(itemIndex.isValid());
+ QCOMPARE(model.itemFromIndex(itemIndex), item);
+
+ QStandardItem *child = new QStandardItem;
+ item->setChild(4, 2, child);
+ QModelIndex childIndex = model.index(4, 2, itemIndex);
+ QVERIFY(childIndex.isValid());
+ QCOMPARE(model.itemFromIndex(childIndex), child);
+
+ QModelIndex noSuchIndex = model.index(99, 99, itemIndex);
+ QVERIFY(!noSuchIndex.isValid());
+}
+
+class CustomItem : public QStandardItem
+{
+public:
+ CustomItem() : QStandardItem() { }
+ ~CustomItem() { }
+ int type() const {
+ return UserType;
+ }
+ QStandardItem *clone() const {
+ return new CustomItem;
+ }
+};
+
+void tst_QStandardItemModel::getSetItemPrototype()
+{
+ QStandardItemModel model;
+ QCOMPARE(model.itemPrototype(), static_cast<const QStandardItem*>(0));
+
+ const CustomItem *proto = new CustomItem;
+ model.setItemPrototype(proto);
+ QCOMPARE(model.itemPrototype(), (const QStandardItem*)proto);
+
+ model.setRowCount(1);
+ model.setColumnCount(1);
+ QModelIndex index = model.index(0, 0, QModelIndex());
+ model.setData(index, "foo");
+ QStandardItem *item = model.itemFromIndex(index);
+ QVERIFY(item != 0);
+ QCOMPARE(item->type(), static_cast<int>(QStandardItem::UserType));
+
+ model.setItemPrototype(0);
+ QCOMPARE(model.itemPrototype(), static_cast<const QStandardItem*>(0));
+}
+
+void tst_QStandardItemModel::getSetItemData()
+{
+ QMap<int, QVariant> roles;
+ QLatin1String text("text");
+ roles.insert(Qt::DisplayRole, text);
+ QLatin1String statusTip("statusTip");
+ roles.insert(Qt::StatusTipRole, statusTip);
+ QLatin1String toolTip("toolTip");
+ roles.insert(Qt::ToolTipRole, toolTip);
+ QLatin1String whatsThis("whatsThis");
+ roles.insert(Qt::WhatsThisRole, whatsThis);
+ QSize sizeHint(64, 48);
+ roles.insert(Qt::SizeHintRole, sizeHint);
+ QFont font;
+ roles.insert(Qt::FontRole, font);
+ Qt::Alignment textAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+ roles.insert(Qt::TextAlignmentRole, int(textAlignment));
+ QColor backgroundColor(Qt::blue);
+ roles.insert(Qt::BackgroundRole, backgroundColor);
+ QColor textColor(Qt::green);
+ roles.insert(Qt::TextColorRole, textColor);
+ Qt::CheckState checkState(Qt::PartiallyChecked);
+ roles.insert(Qt::CheckStateRole, int(checkState));
+ QLatin1String accessibleText("accessibleText");
+ roles.insert(Qt::AccessibleTextRole, accessibleText);
+ QLatin1String accessibleDescription("accessibleDescription");
+ roles.insert(Qt::AccessibleDescriptionRole, accessibleDescription);
+
+ QStandardItemModel model;
+ model.insertRows(0, 1);
+ model.insertColumns(0, 1);
+ QModelIndex idx = model.index(0, 0, QModelIndex());
+
+ QSignalSpy modelDataChangedSpy(
+ &model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)));
+ QVERIFY(model.setItemData(idx, roles));
+ QCOMPARE(modelDataChangedSpy.count(), 1);
+ QVERIFY(model.setItemData(idx, roles));
+ QCOMPARE(modelDataChangedSpy.count(), 1); //it was already changed once
+ QCOMPARE(model.itemData(idx), roles);
+}
+
+void tst_QStandardItemModel::setHeaderLabels_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<int>("orientation");
+ QTest::addColumn<QStringList>("labels");
+ QTest::addColumn<QStringList>("expectedLabels");
+
+ QTest::newRow("horizontal labels")
+ << 1
+ << 4
+ << int(Qt::Horizontal)
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (QStringList() << "a" << "b" << "c" << "d");
+ QTest::newRow("vertical labels")
+ << 4
+ << 1
+ << int(Qt::Vertical)
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (QStringList() << "a" << "b" << "c" << "d");
+ QTest::newRow("too few (horizontal)")
+ << 1
+ << 4
+ << int(Qt::Horizontal)
+ << (QStringList() << "a" << "b")
+ << (QStringList() << "a" << "b" << "3" << "4");
+ QTest::newRow("too few (vertical)")
+ << 4
+ << 1
+ << int(Qt::Vertical)
+ << (QStringList() << "a" << "b")
+ << (QStringList() << "a" << "b" << "3" << "4");
+ QTest::newRow("too many (horizontal)")
+ << 1
+ << 2
+ << int(Qt::Horizontal)
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (QStringList() << "a" << "b" << "c" << "d");
+ QTest::newRow("too many (vertical)")
+ << 2
+ << 1
+ << int(Qt::Vertical)
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (QStringList() << "a" << "b" << "c" << "d");
+}
+
+void tst_QStandardItemModel::setHeaderLabels()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(int, orientation);
+ QFETCH(QStringList, labels);
+ QFETCH(QStringList, expectedLabels);
+ QStandardItemModel model(rows, columns);
+ QSignalSpy columnsInsertedSpy(
+ &model, SIGNAL(columnsInserted(QModelIndex,int,int)));
+ QSignalSpy rowsInsertedSpy(
+ &model, SIGNAL(rowsInserted(QModelIndex,int,int)));
+ if (orientation == Qt::Horizontal)
+ model.setHorizontalHeaderLabels(labels);
+ else
+ model.setVerticalHeaderLabels(labels);
+ for (int i = 0; i < expectedLabels.count(); ++i)
+ QCOMPARE(model.headerData(i, Qt::Orientation(orientation)).toString(), expectedLabels.at(i));
+ QCOMPARE(columnsInsertedSpy.count(),
+ (orientation == Qt::Vertical) ? 0 : labels.count() > columns);
+ QCOMPARE(rowsInsertedSpy.count(),
+ (orientation == Qt::Horizontal) ? 0 : labels.count() > rows);
+}
+
+void tst_QStandardItemModel::itemDataChanged()
+{
+ QStandardItemModel model(6, 4);
+ QStandardItem item;
+ QSignalSpy dataChangedSpy(
+ &model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+ QSignalSpy itemChangedSpy(
+ &model, SIGNAL(itemChanged(QStandardItem *)));
+
+ model.setItem(0, &item);
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ QModelIndex index = model.indexFromItem(&item);
+ QList<QVariant> args;
+ args = dataChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index);
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item);
+
+ item.setData(QLatin1String("foo"), Qt::DisplayRole);
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = dataChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index);
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item);
+
+ item.setData(item.data(Qt::DisplayRole), Qt::DisplayRole);
+ QCOMPARE(dataChangedSpy.count(), 0);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ item.setFlags(Qt::ItemIsEnabled);
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = dataChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index);
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item);
+
+ item.setFlags(item.flags());
+ QCOMPARE(dataChangedSpy.count(), 0);
+ QCOMPARE(itemChangedSpy.count(), 0);
+}
+
+void tst_QStandardItemModel::takeHeaderItem()
+{
+ QStandardItemModel model;
+ // set header items
+ QStandardItem *hheader = new QStandardItem();
+ model.setHorizontalHeaderItem(0, hheader);
+ QStandardItem *vheader = new QStandardItem();
+ model.setVerticalHeaderItem(0, vheader);
+ // take header items
+ QCOMPARE(model.takeHorizontalHeaderItem(0), hheader);
+ QCOMPARE(model.takeVerticalHeaderItem(0), vheader);
+ QCOMPARE(hheader->model(), static_cast<QStandardItemModel*>(0));
+ QCOMPARE(vheader->model(), static_cast<QStandardItemModel*>(0));
+ QCOMPARE(model.takeHorizontalHeaderItem(0), static_cast<QStandardItem*>(0));
+ QCOMPARE(model.takeVerticalHeaderItem(0), static_cast<QStandardItem*>(0));
+ delete hheader;
+ delete vheader;
+}
+
+void tst_QStandardItemModel::useCase1()
+{
+ const int rows = 5;
+ const int columns = 8;
+ QStandardItemModel model(rows, columns);
+ for (int i = 0; i < model.rowCount(); ++i) {
+ for (int j = 0; j < model.columnCount(); ++j) {
+ QCOMPARE(model.item(i, j), static_cast<QStandardItem*>(0));
+
+ QStandardItem *item = new QStandardItem();
+ model.setItem(i, j, item);
+ QCOMPARE(item->row(), i);
+ QCOMPARE(item->column(), j);
+ QCOMPARE(item->model(), &model);
+
+ QModelIndex index = model.indexFromItem(item);
+ QCOMPARE(index, model.index(i, j, QModelIndex()));
+ QStandardItem *sameItem = model.itemFromIndex(index);
+ QCOMPARE(sameItem, item);
+ }
+ }
+}
+
+static void createChildren(QStandardItemModel *model, QStandardItem *parent, int level)
+{
+ if (level > 4)
+ return;
+ for (int i = 0; i < 4; ++i) {
+ QCOMPARE(parent->rowCount(), i);
+ parent->appendRow(QList<QStandardItem*>());
+ for (int j = 0; j < parent->columnCount(); ++j) {
+ QStandardItem *item = new QStandardItem();
+ parent->setChild(i, j, item);
+ QCOMPARE(item->row(), i);
+ QCOMPARE(item->column(), j);
+
+ QModelIndex parentIndex = model->indexFromItem(parent);
+ QModelIndex index = model->indexFromItem(item);
+ QCOMPARE(index, model->index(i, j, parentIndex));
+ QStandardItem *theItem = model->itemFromIndex(index);
+ QCOMPARE(theItem, item);
+ QStandardItem *theParent = model->itemFromIndex(parentIndex);
+ QCOMPARE(theParent, (level == 0) ? (QStandardItem*)0 : parent);
+ }
+
+ {
+ QStandardItem *item = parent->child(i);
+ item->setColumnCount(parent->columnCount());
+ createChildren(model, item, level + 1);
+ }
+ }
+}
+
+void tst_QStandardItemModel::useCase2()
+{
+ QStandardItemModel model;
+ model.setColumnCount(2);
+ createChildren(&model, model.invisibleRootItem(), 0);
+}
+
+void tst_QStandardItemModel::useCase3()
+{
+ // create the tree structure first
+ QStandardItem *childItem = 0;
+ for (int i = 0; i < 100; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ if (childItem)
+ item->appendRow(childItem);
+ childItem = item;
+ }
+
+ // add to model as last step
+ QStandardItemModel model;
+ model.appendRow(childItem);
+
+ // make sure each item has the correct model and parent
+ QStandardItem *parentItem = 0;
+ while (childItem) {
+ QCOMPARE(childItem->model(), &model);
+ QCOMPARE(childItem->parent(), parentItem);
+ parentItem = childItem;
+ childItem = childItem->child(0);
+ }
+
+ // take the item, make sure model is set to 0, but that parents are the same
+ childItem = model.takeItem(0);
+ {
+ parentItem = 0;
+ QStandardItem *item = childItem;
+ while (item) {
+ QCOMPARE(item->model(), static_cast<QStandardItemModel*>(0));
+ QCOMPARE(item->parent(), parentItem);
+ parentItem = item;
+ item = item->child(0);
+ }
+ }
+ delete childItem;
+}
+
+void tst_QStandardItemModel::rootItemFlags()
+{
+ QStandardItemModel model(6, 4);
+ QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex()));
+ QCOMPARE(model.invisibleRootItem()->flags() , Qt::ItemIsDropEnabled);
+
+ Qt::ItemFlags f = Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
+ model.invisibleRootItem()->setFlags(f);
+ QCOMPARE(model.invisibleRootItem()->flags() , f);
+ QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex()));
+
+#ifndef QT_NO_DRAGANDDROP
+ model.invisibleRootItem()->setDropEnabled(false);
+#endif
+ QCOMPARE(model.invisibleRootItem()->flags() , Qt::ItemIsEnabled);
+ QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex()));
+}
+
+bool tst_QStandardItemModel::compareModels(QStandardItemModel *model1, QStandardItemModel *model2)
+{
+ return compareItems(model1->invisibleRootItem(), model2->invisibleRootItem());
+}
+
+bool tst_QStandardItemModel::compareItems(QStandardItem *item1, QStandardItem *item2)
+{
+ if (!item1 && !item2)
+ return true;
+ if (!item1 || !item2)
+ return false;
+ if (item1->text() != item2->text()){
+ qDebug() << item1->text() << item2->text();
+ return false;
+ }
+ if (item1->rowCount() != item2->rowCount()) {
+ // qDebug() << "RowCount" << item1->text() << item1->rowCount() << item2->rowCount();
+ return false;
+ }
+ if (item1->columnCount() != item2->columnCount()) {
+ // qDebug() << "ColumnCount" << item1->text() << item1->columnCount() << item2->columnCount();
+ return false;
+ }
+ for (int row = 0; row < item1->columnCount(); row++)
+ for (int col = 0; col < item1->columnCount(); col++) {
+
+ if (!compareItems(item1->child(row, col), item2->child(row, col)))
+ return false;
+ }
+ return true;
+}
+
+static QStandardItem *itemFromText(QStandardItem *parent, const QString &text)
+{
+ QStandardItem *item = 0;
+ for(int i = 0; i < parent->columnCount(); i++)
+ for(int j = 0; j < parent->rowCount(); j++) {
+
+ QStandardItem *child = parent->child(j, i);
+
+ if(!child)
+ continue;
+
+ if (child->text() == text) {
+ if (item) {
+ return 0;
+ }
+ item = child;
+ }
+
+ QStandardItem *candidate = itemFromText(child, text);
+ if(candidate) {
+ if (item) {
+ return 0;
+ }
+ item = candidate;
+ }
+ }
+ return item;
+}
+
+#ifdef QT_BUILD_INTERNAL
+static QModelIndex indexFromText(QStandardItemModel *model, const QString &text)
+{
+ QStandardItem *item = itemFromText(model->invisibleRootItem(), text);
+ /*QVERIFY(item);*/
+ return model->indexFromItem(item);
+}
+
+
+struct FriendlyTreeView : public QTreeView
+{
+ friend class tst_QStandardItemModel;
+ Q_DECLARE_PRIVATE(QTreeView)
+};
+#endif
+
+void tst_QStandardItemModel::treeDragAndDrop()
+{
+#ifdef QT_BUILD_INTERNAL
+ const int nRow = 5;
+ const int nCol = 3;
+
+ QStandardItemModel model;
+ QStandardItemModel checkModel;
+
+ for (int i = 0; i < nRow; ++i) {
+ QList<QStandardItem *> colItems1;
+ for (int c = 0 ; c < nCol; c ++)
+ colItems1 << new QStandardItem(QString("item %1 - %0").arg(c).arg(i));
+ model.appendRow(colItems1);
+
+ for (int j = 0; j < nRow; ++j) {
+ QList<QStandardItem *> colItems2;
+ for (int c = 0 ; c < nCol; c ++)
+ colItems2 << new QStandardItem(QString("item %1/%2 - %0").arg(c).arg(i).arg(j));
+ colItems1.at(0)->appendRow(colItems2);
+
+ for (int k = 0; k < nRow; ++k) {
+ QList<QStandardItem *> colItems3;
+ for (int c = 0 ; c < nCol; c ++)
+ colItems3 << new QStandardItem(QString("item %1/%2/%3 - %0").arg(c).arg(i).arg(j).arg(k));
+ colItems2.at(0)->appendRow(colItems3);
+ }
+ }
+ }
+
+ for (int i = 0; i < nRow; ++i) {
+ QList<QStandardItem *> colItems1;
+ for (int c = 0 ; c < nCol; c ++)
+ colItems1 << new QStandardItem(QString("item %1 - %0").arg(c).arg(i));
+ checkModel.appendRow(colItems1);
+
+ for (int j = 0; j < nRow; ++j) {
+ QList<QStandardItem *> colItems2;
+ for (int c = 0 ; c < nCol; c ++)
+ colItems2 << new QStandardItem(QString("item %1/%2 - %0").arg(c).arg(i).arg(j));
+ colItems1.at(0)->appendRow(colItems2);
+
+ for (int k = 0; k < nRow; ++k) {
+ QList<QStandardItem *> colItems3;
+ for (int c = 0 ; c < nCol; c ++)
+ colItems3 << new QStandardItem(QString("item %1/%2/%3 - %0").arg(c).arg(i).arg(j).arg(k));
+ colItems2.at(0)->appendRow(colItems3);
+ }
+ }
+ }
+
+ QVERIFY(compareModels(&model, &checkModel));
+
+ FriendlyTreeView view;
+ view.setModel(&model);
+ view.expandAll();
+ view.show();
+#ifndef QT_NO_DRAGANDDROP
+ view.setDragDropMode(QAbstractItemView::InternalMove);
+#endif
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ QItemSelectionModel *selection = view.selectionModel();
+
+ //
+ // step1 drag "item 1" and "item 2" into "item 4"
+ //
+ {
+ selection->clear();
+ selection->select(QItemSelection(indexFromText(&model, QString("item 1 - 0")),
+ indexFromText(&model, QString("item 1 - %0").arg(nCol-1))), QItemSelectionModel::Select);
+
+ selection->select(QItemSelection(indexFromText(&model, QString("item 2 - 0")),
+ indexFromText(&model, QString("item 2 - %0").arg(nCol-1))), QItemSelectionModel::Select);
+
+ //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent
+ QModelIndexList indexes = view.selectedIndexes();
+ QMimeData *data = model.mimeData(indexes);
+ if(model.dropMimeData(data, Qt::MoveAction, 0, 0, indexFromText(&model, "item 4 - 0")))
+ view.d_func()->clearOrRemove();
+ delete data;
+
+ QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point
+ QStandardItem *item4 = itemFromText(checkModel.invisibleRootItem(), "item 4 - 0");
+ item4->insertRow(0, checkModel.takeRow(1));
+ item4->insertRow(1, checkModel.takeRow(1));
+ QVERIFY(compareModels(&model, &checkModel));
+ }
+
+ //
+ // step2 drag "item 3" and "item 3/0" into "item 4"
+ //
+ {
+ selection->clear();
+ selection->select(QItemSelection(indexFromText(&model, QString("item 3 - 0")),
+ indexFromText(&model, QString("item 3 - %0").arg(nCol-1))), QItemSelectionModel::Select);
+
+ selection->select(QItemSelection(indexFromText(&model, QString("item 3/0 - 0")),
+ indexFromText(&model, QString("item 3/0 - %0").arg(nCol-1))), QItemSelectionModel::Select);
+
+ //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent
+ QModelIndexList indexes = view.selectedIndexes();
+ QMimeData *data = model.mimeData(indexes);
+ if(model.dropMimeData(data, Qt::MoveAction, 0, 0, indexFromText(&model, "item 4 - 0")))
+ view.d_func()->clearOrRemove();
+ delete data;
+
+ QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point
+ QStandardItem *item4 = itemFromText(checkModel.invisibleRootItem(), "item 4 - 0");
+ item4->insertRow(0, checkModel.takeRow(1));
+
+ QVERIFY(compareModels(&model, &checkModel));
+ }
+
+ //
+ // step2 drag "item 3" and "item 3/0/2" into "item 0/2"
+ // ( remember "item 3" is now the first child of "item 4")
+ //
+ {
+ selection->clear();
+ selection->select(QItemSelection(indexFromText(&model, QString("item 3 - 0")),
+ indexFromText(&model, QString("item 3 - %0").arg(nCol-1))), QItemSelectionModel::Select);
+
+ selection->select(QItemSelection(indexFromText(&model, QString("item 3/0/2 - 0")),
+ indexFromText(&model, QString("item 3/0/2 - %0").arg(nCol-1))), QItemSelectionModel::Select);
+
+ //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent
+ QModelIndexList indexes = view.selectedIndexes();
+ QMimeData *data = model.mimeData(indexes);
+ if(model.dropMimeData(data, Qt::MoveAction, 0, 0, indexFromText(&model, "item 0/2 - 0")))
+ view.d_func()->clearOrRemove();
+ delete data;
+
+ QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point
+ QStandardItem *item02 = itemFromText(checkModel.invisibleRootItem(), "item 0/2 - 0");
+ QStandardItem *item4 = itemFromText(checkModel.invisibleRootItem(), "item 4 - 0");
+ item02->insertRow(0, item4->takeRow(0));
+
+ QVERIFY(compareModels(&model, &checkModel));
+ }
+#endif
+}
+
+void tst_QStandardItemModel::removeRowsAndColumns()
+{
+#define VERIFY_MODEL \
+ for (int c = 0; c < col_list.count(); c++) \
+ for (int r = 0; r < row_list.count(); r++) \
+ QCOMPARE(model.item(r,c)->text() , row_list[r] + "x" + col_list[c]);
+
+ QVector<QString> row_list = QString("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20").split(',').toVector();
+ QVector<QString> col_list = row_list;
+ QStandardItemModel model;
+ for (int c = 0; c < col_list.count(); c++)
+ for (int r = 0; r < row_list.count(); r++)
+ model.setItem(r, c, new QStandardItem(row_list[r] + "x" + col_list[c]));
+ VERIFY_MODEL
+
+ row_list.remove(3);
+ model.removeRow(3);
+ VERIFY_MODEL
+
+ col_list.remove(5);
+ model.removeColumn(5);
+ VERIFY_MODEL
+
+ row_list.remove(2, 5);
+ model.removeRows(2, 5);
+ VERIFY_MODEL
+
+ col_list.remove(1, 6);
+ model.removeColumns(1, 6);
+ VERIFY_MODEL
+
+ QList<QStandardItem *> row_taken = model.takeRow(6);
+ QCOMPARE(row_taken.count(), col_list.count());
+ for (int c = 0; c < col_list.count(); c++)
+ QCOMPARE(row_taken[c]->text() , row_list[6] + "x" + col_list[c]);
+ row_list.remove(6);
+ VERIFY_MODEL
+
+ QList<QStandardItem *> col_taken = model.takeColumn(10);
+ QCOMPARE(col_taken.count(), row_list.count());
+ for (int r = 0; r < row_list.count(); r++)
+ QCOMPARE(col_taken[r]->text() , row_list[r] + "x" + col_list[10]);
+ col_list.remove(10);
+ VERIFY_MODEL
+}
+
+
+QTEST_MAIN(tst_QStandardItemModel)
+#include "tst_qstandarditemmodel.moc"
diff --git a/tests/auto/widgets/itemviews/qstringlistmodel/.gitignore b/tests/auto/widgets/itemviews/qstringlistmodel/.gitignore
new file mode 100644
index 0000000000..9c14561e3c
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstringlistmodel/.gitignore
@@ -0,0 +1 @@
+tst_qstringlistmodel
diff --git a/tests/auto/widgets/itemviews/qstringlistmodel/qmodellistener.h b/tests/auto/widgets/itemviews/qstringlistmodel/qmodellistener.h
new file mode 100644
index 0000000000..f3ed3c1793
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstringlistmodel/qmodellistener.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QObject>
+#include <QModelIndex>
+#include <qdebug.h>
+
+
+QT_FORWARD_DECLARE_CLASS(QStringListModel)
+
+class QModelListener : public QObject
+{
+ Q_OBJECT
+public:
+ QModelListener(QStringList *pAboutToStringlist, QStringList *pExpectedStringlist, QStringListModel *pModel)
+ {
+ setTestData(pAboutToStringlist, pExpectedStringlist, pModel);
+ }
+ virtual ~QModelListener() { }
+
+ void setTestData(QStringList *pAboutToStringlist, QStringList *pExpectedStringlist, QStringListModel *pModel)
+ {
+ m_pAboutToStringlist = pAboutToStringlist;
+ m_pExpectedStringlist = pExpectedStringlist;
+ m_pModel = pModel;
+ }
+
+private:
+ QStringList *m_pAboutToStringlist;
+ QStringList *m_pExpectedStringlist;
+ QStringListModel *m_pModel;
+
+public slots:
+ void rowsAboutToBeRemovedOrInserted(const QModelIndex & parent, int start, int end );
+ void rowsRemovedOrInserted(const QModelIndex & parent, int start, int end );
+
+};
+
diff --git a/tests/auto/widgets/itemviews/qstringlistmodel/qstringlistmodel.pro b/tests/auto/widgets/itemviews/qstringlistmodel/qstringlistmodel.pro
new file mode 100644
index 0000000000..fe70ed7345
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstringlistmodel/qstringlistmodel.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+QT += widgets
+HEADERS += qmodellistener.h
+
+SOURCES += tst_qstringlistmodel.cpp
+
+
+
diff --git a/tests/auto/widgets/itemviews/qstringlistmodel/tst_qstringlistmodel.cpp b/tests/auto/widgets/itemviews/qstringlistmodel/tst_qstringlistmodel.cpp
new file mode 100644
index 0000000000..2542496f14
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qstringlistmodel/tst_qstringlistmodel.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qabstractitemmodel.h>
+#include <qapplication.h>
+#include <qmap.h>
+#include <qstringlistmodel.h>
+#include <qstringlist.h>
+#include <qlistview.h>
+#include "qmodellistener.h"
+#include <qstringlistmodel.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+void QModelListener::rowsAboutToBeRemovedOrInserted(const QModelIndex & parent, int start, int end )
+{
+ int i;
+ for (i = 0; start + i <= end; i++)
+ {
+ QModelIndex mIndex = m_pModel->index(start + i, 0, parent);
+ QVariant var = m_pModel->data(mIndex, Qt::DisplayRole);
+ QString str = var.toString();
+
+ QCOMPARE(str, m_pAboutToStringlist->at(i));
+ }
+}
+
+void QModelListener::rowsRemovedOrInserted(const QModelIndex & parent, int , int)
+{
+ int i;
+ // Can the rows that *are* removed be iterated now ?
+
+ // What about rowsAboutToBeInserted - what will the indices be?
+ // will insertRow() overwrite existing, or insert (and conseq. grow the model?)
+ // What will the item then contain? empty data?
+
+ // RemoveColumn. Does that also fire the rowsRemoved-family signals?
+
+ for (i = 0; i < m_pExpectedStringlist->size(); i++)
+ {
+ QModelIndex mIndex = m_pModel->index(i, 0, parent);
+ QVariant var = m_pModel->data(mIndex, Qt::DisplayRole);
+ QString str = var.toString();
+
+ //qDebug() << "index: " << i << " start: " << start << "end: " << end;
+ QCOMPARE(str, m_pExpectedStringlist->at(i));
+ }
+}
+
+
+class tst_QStringListModel : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ tst_QStringListModel();
+ virtual ~tst_QStringListModel();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+
+ void rowsAboutToBeRemoved_rowsRemoved();
+ void rowsAboutToBeRemoved_rowsRemoved_data();
+
+ void rowsAboutToBeInserted_rowsInserted();
+ void rowsAboutToBeInserted_rowsInserted_data();
+};
+
+
+tst_QStringListModel::tst_QStringListModel()
+
+{
+}
+
+tst_QStringListModel::~tst_QStringListModel()
+{
+}
+
+void tst_QStringListModel::initTestCase()
+{
+}
+
+void tst_QStringListModel::cleanupTestCase()
+{
+}
+
+void tst_QStringListModel::init()
+{
+}
+
+void tst_QStringListModel::cleanup()
+{
+}
+
+/*
+ tests
+*/
+
+
+void tst_QStringListModel::rowsAboutToBeRemoved_rowsRemoved_data()
+{
+ QTest::addColumn<QStringList>("input");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<QStringList>("aboutto");
+ QTest::addColumn<QStringList>("res");
+
+ QStringList strings0; strings0 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto0; aboutto0 << "Two" << "Three";
+ QStringList res0; res0 << "One" << "Four" << "Five";
+ QTest::newRow( "data0" ) << strings0 << 1 << 2 << aboutto0 << res0;
+
+ QStringList strings1; strings1 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto1; aboutto1 << "One" << "Two";
+ QStringList res1; res1 << "Three" << "Four" << "Five";
+ QTest::newRow( "data1" ) << strings1 << 0 << 2 << aboutto1 << res1;
+
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three";
+ QTest::newRow( "data2" ) << strings2 << 3 << 2 << aboutto2 << res2;
+
+ QStringList strings3; strings3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto3; aboutto3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res3; res3 ;
+ QTest::newRow( "data3" ) << strings3 << 0 << 5 << aboutto3 << res3;
+
+ /* Not sure if this is a valid test */
+ QStringList strings4; strings4 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto4; aboutto4 << "Five" << "";
+ QStringList res4; res4 << "One" << "Two" << "Three" << "Four";
+ QTest::newRow( "data4" ) << strings4 << 4 << 2 << aboutto4 << res4;
+
+ /*
+ * Keep this, template to add more data
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data2" ) << strings2 << 0 << 5 << aboutto2 << res2;
+*/
+
+}
+
+void tst_QStringListModel::rowsAboutToBeRemoved_rowsRemoved()
+{
+ QFETCH(QStringList, input);
+ QFETCH(int, row);
+ QFETCH(int, count);
+ QFETCH(QStringList, aboutto);
+ QFETCH(QStringList, res);
+
+ QStringListModel *model = new QStringListModel(input);
+ QModelListener *pListener = new QModelListener(&aboutto, &res, model);
+ pListener->connect(model, SIGNAL( rowsAboutToBeRemoved(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsAboutToBeRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ pListener->connect(model, SIGNAL( rowsRemoved(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ model->removeRows(row,count);
+ // At this point, control goes to our connected slots inn this order:
+ // 1. rowsAboutToBeRemovedOrInserted
+ // 2. rowsRemovedOrInserted
+ // Control returns here
+
+ delete pListener;
+ delete model;
+
+}
+
+void tst_QStringListModel::rowsAboutToBeInserted_rowsInserted_data()
+{
+ QTest::addColumn<QStringList>("input");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<QStringList>("aboutto");
+ QTest::addColumn<QStringList>("res");
+
+ QStringList strings0; strings0 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto0; aboutto0 << "Two" << "Three";
+ QStringList res0; res0 << "One" << "" << "" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data0" ) << strings0 << 1 << 2 << aboutto0 << res0;
+
+ QStringList strings1; strings1 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto1; aboutto1 << "One" << "Two";
+ QStringList res1; res1 << "" << "" << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data1" ) << strings1 << 0 << 2 << aboutto1 << res1;
+
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three" << "" << "" << "Four" << "Five";
+ QTest::newRow( "data2" ) << strings2 << 3 << 2 << aboutto2 << res2;
+
+ QStringList strings3; strings3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto3; aboutto3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res3; res3 << "" << "" << "" << "" << "" << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data3" ) << strings3 << 0 << 5 << aboutto3 << res3;
+
+ /*
+ * Keep this, template to add more data
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data2" ) << strings2 << 0 << 5 << aboutto2 << res2;
+*/
+
+}
+
+void tst_QStringListModel::rowsAboutToBeInserted_rowsInserted()
+{
+ QFETCH(QStringList, input);
+ QFETCH(int, row);
+ QFETCH(int, count);
+ QFETCH(QStringList, aboutto);
+ QFETCH(QStringList, res);
+
+ QStringListModel *model = new QStringListModel(input);
+ QModelListener *pListener = new QModelListener(&aboutto, &res, model);
+ connect(model, SIGNAL( rowsAboutToBeInserted(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsAboutToBeRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ connect(model, SIGNAL( rowsInserted(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ model->insertRows(row,count);
+ // At this point, control goes to our connected slots inn this order:
+ // 1. rowsAboutToBeRemovedOrInserted
+ // 2. rowsRemovedOrInserted
+ // Control returns here
+
+ delete pListener;
+ delete model;
+
+}
+
+
+QTEST_MAIN(tst_QStringListModel)
+#include "tst_qstringlistmodel.moc"
+
diff --git a/tests/auto/widgets/itemviews/qtableview/.gitignore b/tests/auto/widgets/itemviews/qtableview/.gitignore
new file mode 100644
index 0000000000..e2c6365d65
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtableview/.gitignore
@@ -0,0 +1 @@
+tst_qtableview
diff --git a/tests/auto/widgets/itemviews/qtableview/qtableview.pro b/tests/auto/widgets/itemviews/qtableview/qtableview.pro
new file mode 100644
index 0000000000..408119a782
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtableview/qtableview.pro
@@ -0,0 +1,7 @@
+load(qttest_p4)
+
+QT += widgets widgets-private
+QT += core-private gui-private
+
+TARGET.EPOCHEAPSIZE = 0x200000 0x800000
+SOURCES += tst_qtableview.cpp
diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
new file mode 100644
index 0000000000..2242490a44
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
@@ -0,0 +1,4075 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+#include <private/qtablewidget_p.h>
+#include <QtTest/QtTest>
+#include "private/qapplication_p.h"
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+// Will try to wait for the condition while allowing event processing
+// for a maximum of 2 seconds.
+#define WAIT_FOR_CONDITION(expr, expected) \
+ do { \
+ const int step = 100; \
+ for (int i = 0; i < 2000 && expr != expected; i+=step) { \
+ QTest::qWait(step); \
+ } \
+ } while(0)
+
+#ifdef QT_BUILD_INTERNAL
+#define VERIFY_SPANS_CONSISTENCY(TEST_VIEW_) \
+ QVERIFY(static_cast<QTableViewPrivate*>(QObjectPrivate::get(TEST_VIEW_))->spans.checkConsistency())
+#else
+#define VERIFY_SPANS_CONSISTENCY(TEST_VIEW_) (void)false
+#endif
+
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
+
+typedef QList<bool> BoolList;
+Q_DECLARE_METATYPE(BoolList)
+
+class tst_QTableView : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTableView();
+ virtual ~tst_QTableView();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void getSetCheck();
+
+ void noDelegate();
+ void noModel();
+ void emptyModel();
+
+ void removeRows_data();
+ void removeRows();
+
+ void removeColumns_data();
+ void removeColumns();
+
+ void keyboardNavigation_data();
+ void keyboardNavigation();
+
+ void headerSections_data();
+ void headerSections();
+
+ void moveCursor_data();
+ void moveCursor();
+
+ void moveCursorStrikesBack_data();
+ void moveCursorStrikesBack();
+
+ void hideRows_data();
+ void hideRows();
+
+ void hideColumns_data();
+ void hideColumns();
+
+ void selection_data();
+ void selection();
+
+ void selectRow_data();
+ void selectRow();
+
+ void selectColumn_data();
+ void selectColumn();
+
+ void visualRect_data();
+ void visualRect();
+
+ void fetchMore();
+ void setHeaders();
+
+ void resizeRowsToContents_data();
+ void resizeRowsToContents();
+
+ void resizeColumnsToContents_data();
+ void resizeColumnsToContents();
+
+ void rowViewportPosition_data();
+ void rowViewportPosition();
+
+ void rowAt_data();
+ void rowAt();
+
+ void rowHeight_data();
+ void rowHeight();
+
+ void columnViewportPosition_data();
+ void columnViewportPosition();
+
+ void columnAt_data();
+ void columnAt();
+
+ void columnWidth_data();
+ void columnWidth();
+
+ void hiddenRow_data();
+ void hiddenRow();
+
+ void hiddenColumn_data();
+ void hiddenColumn();
+
+ void sortingEnabled_data();
+ void sortingEnabled();
+
+ void scrollTo_data();
+ void scrollTo();
+
+ void indexAt_data();
+ void indexAt();
+
+ void span_data();
+ void span();
+ void spans();
+ void spans_data();
+ void spansAfterRowInsertion();
+ void spansAfterColumnInsertion();
+ void spansAfterRowRemoval();
+ void spansAfterColumnRemoval();
+
+ void checkHeaderReset();
+ void checkHeaderMinSize();
+
+ void resizeToContents();
+
+ void tabFocus();
+ void bigModel();
+ void selectionSignal();
+
+ // task-specific tests:
+ void task173773_updateVerticalHeader();
+ void task227953_setRootIndex();
+ void task240266_veryBigColumn();
+ void task248688_autoScrollNavigation();
+ void task259308_scrollVerticalHeaderSwappedSections();
+ void task191545_dragSelectRows();
+ void taskQTBUG_5062_spansInconsistency();
+ void taskQTBUG_4516_clickOnRichTextLabel();
+ void taskQTBUG_5237_wheelEventOnHeader();
+ void taskQTBUG_8585_crashForNoGoodReason();
+ void taskQTBUG_7774_RtoLVisualRegionForSelection();
+ void taskQTBUG_8777_scrollToSpans();
+ void taskQTBUG_10169_sizeHintForRow();
+
+#ifndef Q_OS_WINCE
+ void mouseWheel_data();
+ void mouseWheel();
+#endif
+
+ void addColumnWhileEditing();
+ void task234926_setHeaderSorting();
+
+ void changeHeaderData();
+};
+
+// Testing get/set functions
+void tst_QTableView::getSetCheck()
+{
+ QTableView obj1;
+
+ obj1.setSortingEnabled(false);
+ QCOMPARE(false, obj1.isSortingEnabled());
+ obj1.setSortingEnabled(true);
+ QCOMPARE(true, obj1.isSortingEnabled());
+
+ obj1.setShowGrid(false);
+ QCOMPARE(false, obj1.showGrid());
+ obj1.setShowGrid(true);
+ QCOMPARE(true, obj1.showGrid());
+
+ obj1.setGridStyle(Qt::NoPen);
+ QCOMPARE(Qt::NoPen, obj1.gridStyle());
+ obj1.setGridStyle(Qt::SolidLine);
+ QCOMPARE(Qt::SolidLine, obj1.gridStyle());
+
+ obj1.setRootIndex(QModelIndex());
+ QCOMPARE(QModelIndex(), obj1.rootIndex());
+ QStandardItemModel model(10, 10);
+ obj1.setModel(&model);
+ QModelIndex index = model.index(0, 0);
+ obj1.setRootIndex(index);
+ QCOMPARE(index, obj1.rootIndex());
+
+ QHeaderView *var1 = new QHeaderView(Qt::Horizontal);
+ obj1.setHorizontalHeader(var1);
+ QCOMPARE(var1, obj1.horizontalHeader());
+ obj1.setHorizontalHeader((QHeaderView *)0);
+ QCOMPARE(var1, obj1.horizontalHeader());
+ delete var1;
+
+ QHeaderView *var2 = new QHeaderView(Qt::Vertical);
+ obj1.setVerticalHeader(var2);
+ QCOMPARE(var2, obj1.verticalHeader());
+ obj1.setVerticalHeader((QHeaderView *)0);
+ QCOMPARE(var2, obj1.verticalHeader());
+ delete var2;
+
+ QCOMPARE(obj1.isCornerButtonEnabled(), true);
+ obj1.setCornerButtonEnabled(false);
+ QCOMPARE(obj1.isCornerButtonEnabled(), false);
+}
+
+class QtTestTableModel: public QAbstractTableModel
+{
+ Q_OBJECT
+
+signals:
+ void invalidIndexEncountered() const;
+
+public:
+ QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = 0)
+ : QAbstractTableModel(parent),
+ row_count(rows),
+ column_count(columns),
+ can_fetch_more(false),
+ fetch_more_count(0),
+ disabled_rows(),
+ disabled_columns() {}
+
+ int rowCount(const QModelIndex& = QModelIndex()) const { return row_count; }
+ int columnCount(const QModelIndex& = QModelIndex()) const { return column_count; }
+ bool isEditable(const QModelIndex &) const { return true; }
+
+ Qt::ItemFlags flags(const QModelIndex &index) const
+ {
+ Qt::ItemFlags index_flags = QAbstractTableModel::flags(index);
+ if (disabled_rows.contains(index.row())
+ || disabled_columns.contains(index.column()))
+ index_flags &= ~Qt::ItemIsEnabled;
+ return index_flags;
+ }
+
+ void disableRow(int row)
+ {
+ disabled_rows.insert(row);
+ }
+
+ void enableRow(int row)
+ {
+ disabled_rows.remove(row);
+ }
+
+ void disableColumn(int column)
+ {
+ disabled_columns.insert(column);
+ }
+
+ void enableColumn(int column)
+ {
+ disabled_columns.remove(column);
+ }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (!idx.isValid() || idx.row() >= row_count || idx.column() >= column_count) {
+ qWarning() << "Invalid modelIndex [%d,%d,%p]" << idx;
+ emit invalidIndexEncountered();
+ return QVariant();
+ }
+
+ if (role == Qt::DisplayRole || role == Qt::EditRole)
+ return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column()).arg(0);
+
+ return QVariant();
+ }
+
+ bool insertRows(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start > row_count)
+ return false;
+
+ beginInsertRows(parent, start, start + count - 1);
+ row_count += count;
+ endInsertRows();
+ return true;
+ }
+
+ bool removeRows(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start >= row_count || row_count < count)
+ return false;
+
+ beginRemoveRows(parent, start, start + count - 1);
+ row_count -= count;
+ endRemoveRows();
+ return true;
+ }
+
+ void removeLastRow()
+ {
+ beginRemoveRows(QModelIndex(), row_count - 1, row_count - 1);
+ --row_count;
+ endRemoveRows();
+ }
+
+ void removeAllRows()
+ {
+ beginRemoveRows(QModelIndex(), 0, row_count - 1);
+ row_count = 0;
+ endRemoveRows();
+ }
+
+ bool insertColumns(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start > column_count)
+ return false;
+
+ beginInsertColumns(parent, start, start + count - 1);
+ column_count += count;
+ endInsertColumns();
+ return true;
+ }
+
+ bool removeColumns(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start >= column_count || column_count < count)
+ return false;
+
+ beginRemoveColumns(parent, start, start + count - 1);
+ column_count -= count;
+ endRemoveColumns();
+ return true;
+ }
+
+ void removeLastColumn()
+ {
+ beginRemoveColumns(QModelIndex(), column_count - 1, column_count - 1);
+ --column_count;
+ endRemoveColumns();
+ }
+
+ void removeAllColumns()
+ {
+ beginRemoveColumns(QModelIndex(), 0, column_count - 1);
+ column_count = 0;
+ endRemoveColumns();
+ }
+
+ bool canFetchMore(const QModelIndex &) const
+ {
+ return can_fetch_more;
+ }
+
+ void fetchMore(const QModelIndex &)
+ {
+ ++fetch_more_count;
+ }
+
+ void reset()
+ {
+ QAbstractTableModel::reset();
+ }
+
+ int row_count;
+ int column_count;
+ bool can_fetch_more;
+ int fetch_more_count;
+ QSet<int> disabled_rows;
+ QSet<int> disabled_columns;
+};
+
+class QtTestTableView : public QTableView
+{
+Q_OBJECT
+
+public:
+ QtTestTableView(QWidget *parent = 0) : QTableView(parent), checkSignalOrder(false), hasCurrentChanged(0), hasSelectionChanged(0) {}
+
+ void setModel(QAbstractItemModel *model)
+ {
+ QTableView::setModel(model);
+ connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this, SLOT(currentChanged(QModelIndex,QModelIndex)));
+ connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(itemSelectionChanged(QItemSelection,QItemSelection)));
+ }
+
+ enum CursorAction {
+ MoveUp = QAbstractItemView::MoveUp,
+ MoveDown = QAbstractItemView::MoveDown,
+ MoveLeft = QAbstractItemView::MoveLeft,
+ MoveRight = QAbstractItemView::MoveRight,
+ MoveHome = QAbstractItemView::MoveHome,
+ MoveEnd = QAbstractItemView::MoveEnd,
+ MovePageUp = QAbstractItemView::MovePageUp,
+ MovePageDown = QAbstractItemView::MovePageDown,
+ MoveNext = QAbstractItemView::MoveNext,
+ MovePrevious = QAbstractItemView::MovePrevious
+ };
+
+ QModelIndex moveCursor(QtTestTableView::CursorAction cursorAction,
+ Qt::KeyboardModifiers modifiers)
+ {
+ return QTableView::moveCursor((QAbstractItemView::CursorAction)cursorAction, modifiers);
+ }
+
+ int columnWidthHint(int column) const
+ {
+ return sizeHintForColumn(column);
+ }
+
+ int rowHeightHint(int row) const
+ {
+ return sizeHintForRow(row);
+ }
+
+ bool isIndexHidden(const QModelIndex &index) const
+ {
+ return QTableView::isIndexHidden(index);
+ }
+
+ void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+ {
+ QTableView::setSelection(rect, command);
+ }
+
+ QModelIndexList selectedIndexes() const
+ {
+ return QTableView::selectedIndexes();
+ }
+
+ int sizeHintForRow(int row) const
+ {
+ return QTableView::sizeHintForRow(row);
+ }
+
+ bool checkSignalOrder;
+public slots:
+ void currentChanged(QModelIndex , QModelIndex ) {
+ hasCurrentChanged++;
+ if (checkSignalOrder)
+ QVERIFY(hasCurrentChanged > hasSelectionChanged);
+ }
+
+ void itemSelectionChanged(QItemSelection , QItemSelection ) {
+ hasSelectionChanged++;
+ if (checkSignalOrder)
+ QVERIFY(hasCurrentChanged >= hasSelectionChanged);
+ }
+private:
+ int hasCurrentChanged;
+ int hasSelectionChanged;
+
+};
+
+class QtTestItemDelegate : public QItemDelegate
+{
+public:
+ QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const
+ {
+ return hint;
+ }
+
+ QSize hint;
+};
+
+tst_QTableView::tst_QTableView()
+{
+}
+
+tst_QTableView::~tst_QTableView()
+{
+}
+
+void tst_QTableView::initTestCase()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+}
+
+void tst_QTableView::cleanupTestCase()
+{
+}
+
+void tst_QTableView::init()
+{
+}
+
+void tst_QTableView::cleanup()
+{
+}
+
+void tst_QTableView::noDelegate()
+{
+ QtTestTableModel model(3, 3);
+ QTableView view;
+ view.setModel(&model);
+ view.setItemDelegate(0);
+ view.show();
+}
+
+void tst_QTableView::noModel()
+{
+ QTableView view;
+ view.show();
+}
+
+void tst_QTableView::emptyModel()
+{
+ QtTestTableModel model;
+ QTableView view;
+ QSignalSpy spy(&model, SIGNAL(invalidIndexEncountered()));
+ view.setModel(&model);
+ view.show();
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QTableView::removeRows_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+
+ QTest::newRow("2x2") << 2 << 2;
+ QTest::newRow("10x10") << 10 << 10;
+}
+
+void tst_QTableView::removeRows()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QSignalSpy spy(&model, SIGNAL(invalidIndexEncountered()));
+
+ QTableView view;
+ view.setModel(&model);
+ view.show();
+
+ model.removeLastRow();
+ QCOMPARE(spy.count(), 0);
+
+ model.removeAllRows();
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QTableView::removeColumns_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+
+ QTest::newRow("2x2") << 2 << 2;
+ QTest::newRow("10x10") << 10 << 10;
+}
+
+void tst_QTableView::removeColumns()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QSignalSpy spy(&model, SIGNAL(invalidIndexEncountered()));
+
+ QTableView view;
+ view.setModel(&model);
+ view.show();
+
+ model.removeLastColumn();
+ QCOMPARE(spy.count(), 0);
+
+ model.removeAllColumns();
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QTableView::keyboardNavigation_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<bool>("tabKeyNavigation");
+ QTest::addColumn<IntList>("keyPresses");
+
+ QTest::newRow("16x16 model") << 16 << 16 << true
+ << (IntList()
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Right
+ << Qt::Key_Right
+ << Qt::Key_Up
+ << Qt::Key_Left
+ << Qt::Key_Left
+ << Qt::Key_Up
+ << Qt::Key_Down
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Left
+ << Qt::Key_Left
+ << Qt::Key_Up
+ << Qt::Key_Down
+ << Qt::Key_Down
+ << Qt::Key_Tab
+ << Qt::Key_Backtab);
+
+
+ QTest::newRow("no tab") << 8 << 8 << false
+ << (IntList()
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Right
+ << Qt::Key_Right
+ << Qt::Key_Up
+ << Qt::Key_Left
+ << Qt::Key_Left
+ << Qt::Key_Up
+ << Qt::Key_Down
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Up
+ << Qt::Key_Left
+ << Qt::Key_Left
+ << Qt::Key_Up
+ << Qt::Key_Down
+ << Qt::Key_Down
+ << Qt::Key_Tab
+ << Qt::Key_Backtab);
+}
+
+void tst_QTableView::keyboardNavigation()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(bool, tabKeyNavigation);
+ QFETCH(IntList, keyPresses);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QTableView view;
+ view.setModel(&model);
+
+ view.setTabKeyNavigation(tabKeyNavigation);
+ QModelIndex index = model.index(rowCount - 1, columnCount - 1);
+ view.setCurrentIndex(index);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ qApp->setActiveWindow(&view);
+
+ int row = rowCount - 1;
+ int column = columnCount - 1;
+ for (int i = 0; i < keyPresses.count(); ++i) {
+
+ Qt::Key key = (Qt::Key)keyPresses.at(i);
+
+ switch (key) {
+ case Qt::Key_Up:
+ row = qMax(0, row - 1);
+ break;
+ case Qt::Key_Down:
+ row = qMin(rowCount - 1, row + 1);
+ break;
+ case Qt::Key_Backtab:
+ if (!tabKeyNavigation)
+ break;
+ case Qt::Key_Left:
+ column = qMax(0, column - 1);
+ break;
+ case Qt::Key_Tab:
+ if (!tabKeyNavigation)
+ break;
+ case Qt::Key_Right:
+ column = qMin(columnCount - 1, column + 1);
+ break;
+ default:
+ break;
+ }
+
+ QTest::keyClick(&view, key);
+ QApplication::processEvents();
+
+ QModelIndex index = model.index(row, column);
+ QCOMPARE(view.currentIndex(), index);
+ }
+}
+
+void tst_QTableView::headerSections_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+
+ QTest::newRow("") << 10 << 10 << 5 << 5 << 30 << 30;
+}
+
+void tst_QTableView::headerSections()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+
+ QtTestTableModel model(rowCount, columnCount);
+
+ QTableView view;
+ QHeaderView *hheader = view.horizontalHeader();
+ QHeaderView *vheader = view.verticalHeader();
+
+ view.setModel(&model);
+ view.show();
+
+ hheader->doItemsLayout();
+ vheader->doItemsLayout();
+
+ QCOMPARE(hheader->count(), model.columnCount());
+ QCOMPARE(vheader->count(), model.rowCount());
+
+ view.setRowHeight(row, rowHeight);
+ QCOMPARE(view.rowHeight(row), rowHeight);
+ view.hideRow(row);
+ QCOMPARE(view.rowHeight(row), 0);
+ view.showRow(row);
+ QCOMPARE(view.rowHeight(row), rowHeight);
+
+ view.setColumnWidth(column, columnWidth);
+ QCOMPARE(view.columnWidth(column), columnWidth);
+ view.hideColumn(column);
+ QCOMPARE(view.columnWidth(column), 0);
+ view.showColumn(column);
+ QCOMPARE(view.columnWidth(column), columnWidth);
+}
+
+typedef QPair<int,int> IntPair;
+Q_DECLARE_METATYPE(IntPair)
+
+void tst_QTableView::moveCursor_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("hideRow");
+ QTest::addColumn<int>("hideColumn");
+
+ QTest::addColumn<int>("startRow");
+ QTest::addColumn<int>("startColumn");
+
+ QTest::addColumn<int>("cursorMoveAction");
+ QTest::addColumn<int>("modifier");
+
+ QTest::addColumn<int>("expectedRow");
+ QTest::addColumn<int>("expectedColumn");
+ QTest::addColumn<IntPair>("moveRow");
+ QTest::addColumn<IntPair>("moveColumn");
+
+ // MoveRight
+ QTest::newRow("MoveRight (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveRight) << int(Qt::NoModifier)
+ << 0 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveRight (3,0)")
+ << 4 << 4 << -1 << -1
+ << 3 << 0
+ << int(QtTestTableView::MoveRight) << int(Qt::NoModifier)
+ << 3 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveRight (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveRight) << int(Qt::NoModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0); // ###
+
+ QTest::newRow("MoveRight, hidden column 1 (0,0)")
+ << 4 << 4 << -1 << 1
+ << 0 << 0
+ << int(QtTestTableView::MoveRight) << int(Qt::NoModifier)
+ << 0 << 2 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveRight, hidden column 3 (0,2)")
+ << 4 << 4 << -1 << 3
+ << 0 << 2
+ << int(QtTestTableView::MoveRight) << int(Qt::NoModifier)
+ << 0 << 2 << IntPair(0,0) << IntPair(0,0); // ###
+
+ // MoveNext should in addition wrap
+ QTest::newRow("MoveNext (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 0 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext (0,2)")
+ << 4 << 4 << -1 << -1
+ << 0 << 2
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 0 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, wrap (0,3)")
+ << 4 << 4 << -1 << -1
+ << 0 << 3
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 1 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, wrap (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, hidden column 1 (0,0)")
+ << 4 << 4 << -1 << 1
+ << 0 << 0
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 0 << 2 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, wrap, hidden column 3 (0,2)")
+ << 4 << 4 << -1 << 3
+ << 0 << 2
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 1 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, wrap, hidden column 3 (3,2)")
+ << 4 << 4 << -1 << 3
+ << 3 << 2
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, wrapy, wrapx, hidden column 3, hidden row 3 (2,2)")
+ << 4 << 4 << 3 << 3
+ << 2 << 2
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveNext, wrap, hidden column 2, moved column from 3 to 0. (0,2)")
+ << 4 << 4 << -1 << 2
+ << 0 << 2
+ << int(QtTestTableView::MoveNext) << int(Qt::NoModifier)
+ << 1 << 3 << IntPair(0,0) << IntPair(3,0);
+
+ // MoveLeft
+ QTest::newRow("MoveLeft (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveLeft (0,3)")
+ << 4 << 4 << -1 << -1
+ << 0 << 3
+ << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier)
+ << 0 << 2 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveLeft (1,0)")
+ << 4 << 4 << -1 << -1
+ << 1 << 0
+ << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier)
+ << 1 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveLeft, hidden column 0 (0,2)")
+ << 4 << 4 << -1 << 1
+ << 0 << 2
+ << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveLeft, hidden column 0 (0,1)")
+ << 4 << 4 << -1 << 0
+ << 0 << 1
+ << int(QtTestTableView::MoveLeft) << int(Qt::NoModifier)
+ << 0 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ // MovePrevious should in addition wrap
+ QTest::newRow("MovePrevious (0,3)")
+ << 4 << 4 << -1 << -1
+ << 0 << 3
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 0 << 2 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious (0,1)")
+ << 4 << 4 << -1 << -1
+ << 0 << 1
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, wrap (1,0)")
+ << 4 << 4 << -1 << -1
+ << 1 << 0
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 0 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, wrap, (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, hidden column 1 (0,2)")
+ << 4 << 4 << -1 << 1
+ << 0 << 2
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, wrap, hidden column 3 (0,2)")
+ << 4 << 4 << -1 << 3
+ << 0 << 2
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 0 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, wrapy, hidden column 0 (0,1)")
+ << 4 << 4 << -1 << 0
+ << 0 << 1
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, wrap, hidden column 0, hidden row 0 (1,1)")
+ << 4 << 4 << 0 << 0
+ << 1 << 1
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePrevious, wrap, hidden column 1, moved column from 0 to 3. (1,2)")
+ << 4 << 4 << -1 << 1
+ << 1 << 2
+ << int(QtTestTableView::MovePrevious) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,3);
+
+ // MoveDown
+ QTest::newRow("MoveDown (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveDown) << int(Qt::NoModifier)
+ << 1 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveDown (3,0)")
+ << 4 << 4 << -1 << -1
+ << 3 << 0
+ << int(QtTestTableView::MoveDown) << int(Qt::NoModifier)
+ << 3 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveDown (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveDown) << int(Qt::NoModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveDown, hidden row 1 (0,0)")
+ << 4 << 4 << 1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveDown) << int(Qt::NoModifier)
+ << 2 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveDown, hidden row 3 (2,0)")
+ << 4 << 4 << 3 << -1
+ << 2 << 0
+ << int(QtTestTableView::MoveDown) << int(Qt::NoModifier)
+ << 2 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveDown, hidden row 0 hidden column 0 (0,0)")
+ << 4 << 4 << 0 << 0
+ << 0 << 0
+ << int(QtTestTableView::MoveDown) << int(Qt::NoModifier)
+ << 1 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ // MoveUp
+ QTest::newRow("MoveUp (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveUp) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveUp (3, 0)")
+ << 4 << 4 << -1 << -1
+ << 3 << 0
+ << int(QtTestTableView::MoveUp) << int(Qt::NoModifier)
+ << 2 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveUp (0,1)")
+ << 4 << 4 << -1 << -1
+ << 0 << 1
+ << int(QtTestTableView::MoveUp) << int(Qt::NoModifier)
+ << 0 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveUp, hidden row 1 (2,0)")
+ << 4 << 4 << 1 << -1
+ << 2 << 0
+ << int(QtTestTableView::MoveUp) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveUp, hidden row (1,0)")
+ << 4 << 4 << 0 << -1
+ << 1 << 0
+ << int(QtTestTableView::MoveUp) << int(Qt::NoModifier)
+ << 1 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ // MoveHome
+ QTest::newRow("MoveHome (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveHome) << int(Qt::NoModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveHome (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveHome) << int(Qt::NoModifier)
+ << 3 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveHome, hidden column 0 (3,3)")
+ << 4 << 4 << -1 << 0
+ << 3 << 3
+ << int(QtTestTableView::MoveHome) << int(Qt::NoModifier)
+ << 3 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ // Use Ctrl modifier
+ QTest::newRow("MoveHome + Ctrl (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveHome) << int(Qt::ControlModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveHome + Ctrl (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveHome) << int(Qt::ControlModifier)
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveHome + Ctrl, hidden column 0, hidden row 0 (3,3)")
+ << 4 << 4 << 0 << 0
+ << 3 << 3
+ << int(QtTestTableView::MoveHome) << int(Qt::ControlModifier)
+ << 1 << 1 << IntPair(0,0) << IntPair(0,0);
+
+ // MoveEnd
+ QTest::newRow("MoveEnd (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveEnd) << int(Qt::NoModifier)
+ << 0 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveEnd (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveEnd) << int(Qt::NoModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveEnd, hidden column (0,0)")
+ << 4 << 4 << -1 << 3
+ << 0 << 0
+ << int(QtTestTableView::MoveEnd) << int(Qt::NoModifier)
+ << 0<< 2 << IntPair(0,0) << IntPair(0,0);
+
+ // Use Ctrl modifier
+ QTest::newRow("MoveEnd + Ctrl (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveEnd + Ctrl (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier)
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveEnd + Ctrl, hidden column 3 (0,0)")
+ << 4 << 4 << -1 << 3
+ << 0 << 0
+ << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier)
+ << 3 << 2 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MoveEnd + Ctrl, hidden column 3, hidden row 3 (0,0)")
+ << 4 << 4 << 3 << 3
+ << 0 << 0
+ << int(QtTestTableView::MoveEnd) << int(Qt::ControlModifier)
+ << 2 << 2 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePageUp (0,0)")
+ << 4 << 4 << -1 << -1
+ << 0 << 0
+ << int(QtTestTableView::MovePageUp) << 0
+ << 0 << 0 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePageUp (3,3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MovePageUp) << 0
+ << 0 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePageDown (3, 3)")
+ << 4 << 4 << -1 << -1
+ << 3 << 3
+ << int(QtTestTableView::MovePageDown) << 0
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+
+ QTest::newRow("MovePageDown (0, 3)")
+ << 4 << 4 << -1 << -1
+ << 0 << 3
+ << int(QtTestTableView::MovePageDown) << 0
+ << 3 << 3 << IntPair(0,0) << IntPair(0,0);
+}
+
+void tst_QTableView::moveCursor()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, hideRow);
+ QFETCH(int, hideColumn);
+ QFETCH(int, startRow);
+ QFETCH(int, startColumn);
+ QFETCH(int, cursorMoveAction);
+ QFETCH(int, modifier);
+ QFETCH(int, expectedRow);
+ QFETCH(int, expectedColumn);
+ QFETCH(IntPair, moveRow);
+ QFETCH(IntPair, moveColumn);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QtTestTableView view;
+
+ view.setModel(&model);
+ view.hideRow(hideRow);
+ view.hideColumn(hideColumn);
+ if (moveColumn.first != moveColumn.second)
+ view.horizontalHeader()->moveSection(moveColumn.first, moveColumn.second);
+ if (moveRow.first != moveRow.second)
+ view.verticalHeader()->moveSection(moveRow.first, moveRow.second);
+
+ view.show();
+
+ QModelIndex index = model.index(startRow, startColumn);
+ view.setCurrentIndex(index);
+
+ QModelIndex newIndex = view.moveCursor((QtTestTableView::CursorAction)cursorMoveAction,
+ (Qt::KeyboardModifiers)modifier);
+ // expected fails, task 119433
+ if(newIndex.row() == -1)
+ return;
+ QCOMPARE(newIndex.row(), expectedRow);
+ QCOMPARE(newIndex.column(), expectedColumn);
+}
+
+void tst_QTableView::moveCursorStrikesBack_data()
+{
+ QTest::addColumn<int>("hideRow");
+ QTest::addColumn<int>("hideColumn");
+ QTest::addColumn<IntList>("disableRows");
+ QTest::addColumn<IntList>("disableColumns");
+ QTest::addColumn<QRect>("span");
+
+ QTest::addColumn<int>("startRow");
+ QTest::addColumn<int>("startColumn");
+ QTest::addColumn<IntList>("cursorMoveActions");
+ QTest::addColumn<int>("expectedRow");
+ QTest::addColumn<int>("expectedColumn");
+
+ QTest::newRow("Last column disabled. Task QTBUG-3878") << -1 << -1
+ << IntList()
+ << (IntList() << 6)
+ << QRect()
+ << 0 << 5 << (IntList() << int(QtTestTableView::MoveNext))
+ << 1 << 0;
+
+ QTest::newRow("Last column disabled. Task QTBUG-3878") << -1 << -1
+ << IntList()
+ << (IntList() << 6)
+ << QRect()
+ << 1 << 0 << (IntList() << int(QtTestTableView::MovePrevious))
+ << 0 << 5;
+
+ QTest::newRow("Span, anchor column hidden") << -1 << 1
+ << IntList()
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 2 << 0 << (IntList() << int(QtTestTableView::MoveNext))
+ << 2 << 2;
+
+ QTest::newRow("Span, anchor column disabled") << -1 << -1
+ << IntList()
+ << (IntList() << 1)
+ << QRect(1, 2, 2, 3)
+ << 2 << 0 << (IntList() << int(QtTestTableView::MoveNext))
+ << 2 << 2;
+
+ QTest::newRow("Span, anchor row hidden") << 2 << -1
+ << IntList()
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown))
+ << 3 << 2;
+
+ QTest::newRow("Span, anchor row disabled") << -1 << -1
+ << (IntList() << 2)
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown))
+ << 3 << 2;
+
+ QTest::newRow("Move through span right") << -1 << -1
+ << IntList()
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 3 << 0 << (IntList() << int(QtTestTableView::MoveRight) << int(QtTestTableView::MoveRight))
+ << 3 << 3;
+
+ QTest::newRow("Move through span left") << -1 << -1
+ << IntList()
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 3 << 3 << (IntList() << int(QtTestTableView::MoveLeft) << int(QtTestTableView::MoveLeft))
+ << 3 << 0;
+
+ QTest::newRow("Move through span down") << -1 << -1
+ << IntList()
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown) << int(QtTestTableView::MoveDown))
+ << 5 << 2;
+
+ QTest::newRow("Move through span up") << -1 << -1
+ << IntList()
+ << IntList()
+ << QRect(1, 2, 2, 3)
+ << 5 << 2 << (IntList() << int(QtTestTableView::MoveUp) << int(QtTestTableView::MoveUp))
+ << 1 << 2;
+
+ IntList fullList;
+ for (int i = 0; i < 7; ++i)
+ fullList << i;
+
+ QTest::newRow("All disabled, wrap forward. Timeout => FAIL") << -1 << -1
+ << fullList
+ << fullList
+ << QRect()
+ << 1 << 0 << (IntList() << int(QtTestTableView::MoveNext))
+ << 1 << 0;
+
+ QTest::newRow("All disabled, wrap backwards. Timeout => FAIL") << -1 << -1
+ << fullList
+ << fullList
+ << QRect()
+ << 1 << 0 << (IntList() << int(QtTestTableView::MovePrevious))
+ << 1 << 0;
+}
+
+void tst_QTableView::moveCursorStrikesBack()
+{
+ QFETCH(int, hideRow);
+ QFETCH(int, hideColumn);
+ QFETCH(IntList, disableRows);
+ QFETCH(IntList, disableColumns);
+ QFETCH(QRect, span);
+
+ QFETCH(int, startRow);
+ QFETCH(int, startColumn);
+ QFETCH(IntList, cursorMoveActions);
+ QFETCH(int, expectedRow);
+ QFETCH(int, expectedColumn);
+
+ QtTestTableModel model(7, 7);
+ QtTestTableView view;
+ view.setModel(&model);
+ view.hideRow(hideRow);
+ view.hideColumn(hideColumn);
+
+ if (span.height() && span.width())
+ view.setSpan(span.top(), span.left(), span.height(), span.width());
+ view.show();
+
+ QModelIndex index = model.index(startRow, startColumn);
+ view.setCurrentIndex(index);
+
+ foreach (int row, disableRows)
+ model.disableRow(row);
+ foreach (int column, disableColumns)
+ model.disableColumn(column);
+
+ int newRow = -1;
+ int newColumn = -1;
+ foreach (int cursorMoveAction, cursorMoveActions) {
+ QModelIndex newIndex = view.moveCursor((QtTestTableView::CursorAction)cursorMoveAction, 0);
+ view.setCurrentIndex(newIndex);
+ newRow = newIndex.row();
+ newColumn = newIndex.column();
+ }
+
+ // expected fails, task 119433
+ if(newRow == -1)
+ return;
+ QCOMPARE(newRow, expectedRow);
+ QCOMPARE(newColumn, expectedColumn);
+}
+
+void tst_QTableView::hideRows_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("showRow"); // hide, then show
+ QTest::addColumn<int>("hideRow"); // hide only
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowSpan");
+ QTest::addColumn<int>("columnSpan");
+
+ QTest::newRow("show row 0, hide row 3, no span")
+ << 10 << 10
+ << 0
+ << 3
+ << -1 << -1
+ << 1 << 1;
+
+ QTest::newRow("show row 0, hide row 3, span")
+ << 10 << 10
+ << 0
+ << 3
+ << 0 << 0
+ << 3 << 2;
+}
+
+void tst_QTableView::hideRows()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, showRow);
+ QFETCH(int, hideRow);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowSpan);
+ QFETCH(int, columnSpan);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QTableView view;
+
+ view.setModel(&model);
+ view.setSpan(row, column, rowSpan, columnSpan);
+
+ view.hideRow(showRow);
+ QVERIFY(view.isRowHidden(showRow));
+
+ view.hideRow(hideRow);
+ QVERIFY(view.isRowHidden(hideRow));
+
+ view.showRow(showRow);
+ QVERIFY(!view.isRowHidden(showRow));
+ QVERIFY(view.isRowHidden(hideRow));
+}
+
+void tst_QTableView::hideColumns_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("showColumn"); // hide, then show
+ QTest::addColumn<int>("hideColumn"); // hide only
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowSpan");
+ QTest::addColumn<int>("columnSpan");
+
+ QTest::newRow("show col 0, hide col 3, no span")
+ << 10 << 10
+ << 0
+ << 3
+ << -1 << -1
+ << 1 << 1;
+
+ QTest::newRow("show col 0, hide col 3, span")
+ << 10 << 10
+ << 0
+ << 3
+ << 0 << 0
+ << 3 << 2;
+}
+
+void tst_QTableView::hideColumns()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, showColumn);
+ QFETCH(int, hideColumn);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowSpan);
+ QFETCH(int, columnSpan);
+
+ QtTestTableModel model(rowCount, columnCount);
+
+ QTableView view;
+ view.setModel(&model);
+ view.setSpan(row, column, rowSpan, columnSpan);
+
+ view.hideColumn(showColumn);
+ QVERIFY(view.isColumnHidden(showColumn));
+
+ view.hideColumn(hideColumn);
+ QVERIFY(view.isColumnHidden(hideColumn));
+
+ view.showColumn(showColumn);
+ QVERIFY(!view.isColumnHidden(showColumn));
+ QVERIFY(view.isColumnHidden(hideColumn));
+}
+
+void tst_QTableView::selection_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowSpan");
+ QTest::addColumn<int>("columnSpan");
+ QTest::addColumn<int>("hideRow");
+ QTest::addColumn<int>("hideColumn");
+ QTest::addColumn<int>("moveRowFrom");
+ QTest::addColumn<int>("moveRowTo");
+ QTest::addColumn<int>("moveColumnFrom");
+ QTest::addColumn<int>("moveColumnTo");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+ QTest::addColumn<int>("x");
+ QTest::addColumn<int>("y");
+ QTest::addColumn<int>("width");
+ QTest::addColumn<int>("height");
+ QTest::addColumn<int>("command");
+ QTest::addColumn<int>("selectedCount"); // ### make this more detailed
+
+ QTest::newRow("no span, no hidden, no moved, 3x3 select")
+ << 10 << 10 // dim
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << -1 << -1 // hide
+ << -1 << -1 // move row
+ << -1 << -1 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 9; // selected count
+
+ QTest::newRow("row span, no hidden, no moved, 3x3 select")
+ << 10 << 10 // dim
+ << 1 << 1 // pos
+ << 2 << 1 // span
+ << -1 << -1 // hide
+ << -1 << -1 // move row
+ << -1 << -1 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 8; // selected count
+
+ QTest::newRow("col span, no hidden, no moved, 3x3 select")
+ << 10 << 10 // dim
+ << 1 << 1 // pos
+ << 1 << 2 // span
+ << -1 << -1 // hide
+ << -1 << -1 // move row
+ << -1 << -1 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 8; // selected count
+
+ QTest::newRow("no span, row hidden, no moved, 3x3 select")
+ << 10 << 10 // dim
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 1 << -1 // hide
+ << -1 << -1 // move row
+ << -1 << -1 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 9; // selected count
+
+ QTest::newRow("no span, col hidden, no moved, 3x3 select")
+ << 10 << 10 // dim
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << -1 << 1 // hide
+ << -1 << -1 // move row
+ << -1 << -1 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 9; // selected count
+
+ QTest::newRow("no span, no hidden, row moved, 3x3 select")
+ << 10 << 10 // dim
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << -1 << -1 // hide
+ << 1 << 3 // move row
+ << -1 << -1 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 9; // selected count
+
+ QTest::newRow("no span, no hidden, col moved, 3x3 select")
+ << 10 << 10 // dim
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << -1 << -1 // hide
+ << -1 << -1 // move row
+ << 1 << 3 // move col
+ << 40 << 40 // cell size
+ << 20 << 20 << 80 << 80 // rect
+ << int(QItemSelectionModel::Select) // command
+ << 9; // selected count
+}
+
+void tst_QTableView::selection()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowSpan);
+ QFETCH(int, columnSpan);
+ QFETCH(int, hideRow);
+ QFETCH(int, hideColumn);
+ QFETCH(int, moveRowFrom);
+ QFETCH(int, moveRowTo);
+ QFETCH(int, moveColumnFrom);
+ QFETCH(int, moveColumnTo);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+ QFETCH(int, x);
+ QFETCH(int, y);
+ QFETCH(int, width);
+ QFETCH(int, height);
+ QFETCH(int, command);
+ QFETCH(int, selectedCount);
+
+ QtTestTableModel model(rowCount, columnCount);
+
+ QtTestTableView view;
+ view.show();
+ view.setModel(&model);
+
+ view.setSpan(row, column, rowSpan, columnSpan);
+
+ view.hideRow(hideRow);
+ view.hideColumn(hideColumn);
+
+ view.verticalHeader()->moveSection(moveRowFrom, moveRowTo);
+ view.horizontalHeader()->moveSection(moveColumnFrom, moveColumnTo);
+
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHeight(r, rowHeight);
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnWidth(c, columnWidth);
+
+ view.setSelection(QRect(x, y, width, height),
+ QItemSelectionModel::SelectionFlags(command));
+
+ QCOMPARE(view.selectedIndexes().count(), selectedCount);
+}
+
+void tst_QTableView::selectRow_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("behavior");
+ QTest::addColumn<int>("selectedItems");
+
+ QTest::newRow("SingleSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::SingleSelection
+ << (int)QAbstractItemView::SelectItems
+ << 0;
+
+ QTest::newRow("SingleSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::SingleSelection
+ << (int)QAbstractItemView::SelectRows
+ << 10;
+
+ QTest::newRow("SingleSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::SingleSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 0;
+
+ QTest::newRow("MultiSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::MultiSelection
+ << (int)QAbstractItemView::SelectItems
+ << 10;
+
+ QTest::newRow("MultiSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::MultiSelection
+ << (int)QAbstractItemView::SelectRows
+ << 10;
+
+ QTest::newRow("MultiSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::MultiSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 0;
+
+ QTest::newRow("ExtendedSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ExtendedSelection
+ << (int)QAbstractItemView::SelectItems
+ << 10;
+
+ QTest::newRow("ExtendedSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ExtendedSelection
+ << (int)QAbstractItemView::SelectRows
+ << 10;
+
+ QTest::newRow("ExtendedSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ExtendedSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 0;
+
+ QTest::newRow("ContiguousSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ContiguousSelection
+ << (int)QAbstractItemView::SelectItems
+ << 10;
+
+ QTest::newRow("ContiguousSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ContiguousSelection
+ << (int)QAbstractItemView::SelectRows
+ << 10;
+
+ QTest::newRow("ContiguousSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ContiguousSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 0;
+}
+
+void tst_QTableView::selectRow()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, mode);
+ QFETCH(int, behavior);
+ QFETCH(int, selectedItems);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QTableView view;
+
+ view.setModel(&model);
+ view.setSelectionMode((QAbstractItemView::SelectionMode)mode);
+ view.setSelectionBehavior((QAbstractItemView::SelectionBehavior)behavior);
+
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), 0);
+
+ view.selectRow(row);
+
+ //test we have 10 items selected
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedItems);
+ //test that all 10 items are in the same row
+ for (int i = 0; selectedItems > 0 && i < rowCount; ++i)
+ QCOMPARE(view.selectionModel()->selectedIndexes().at(i).row(), row);
+}
+
+void tst_QTableView::selectColumn_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("behavior");
+ QTest::addColumn<int>("selectedItems");
+
+ QTest::newRow("SingleSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::SingleSelection
+ << (int)QAbstractItemView::SelectItems
+ << 0;
+
+ QTest::newRow("SingleSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::SingleSelection
+ << (int)QAbstractItemView::SelectRows
+ << 0;
+
+ QTest::newRow("SingleSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::SingleSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 10;
+
+ QTest::newRow("MultiSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::MultiSelection
+ << (int)QAbstractItemView::SelectItems
+ << 10;
+
+ QTest::newRow("MultiSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::MultiSelection
+ << (int)QAbstractItemView::SelectRows
+ << 0;
+
+ QTest::newRow("MultiSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::MultiSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 10;
+
+ QTest::newRow("ExtendedSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ExtendedSelection
+ << (int)QAbstractItemView::SelectItems
+ << 10;
+
+ QTest::newRow("ExtendedSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ExtendedSelection
+ << (int)QAbstractItemView::SelectRows
+ << 0;
+
+ QTest::newRow("ExtendedSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ExtendedSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 10;
+
+ QTest::newRow("ContiguousSelection and SelectItems")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ContiguousSelection
+ << (int)QAbstractItemView::SelectItems
+ << 10;
+
+ QTest::newRow("ContiguousSelection and SelectRows")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ContiguousSelection
+ << (int)QAbstractItemView::SelectRows
+ << 0;
+
+ QTest::newRow("ContiguousSelection and SelectColumns")
+ << 10 << 10
+ << 0
+ << (int)QAbstractItemView::ContiguousSelection
+ << (int)QAbstractItemView::SelectColumns
+ << 10;
+}
+
+void tst_QTableView::selectColumn()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, column);
+ QFETCH(int, mode);
+ QFETCH(int, behavior);
+ QFETCH(int, selectedItems);
+
+ QtTestTableModel model(rowCount, columnCount);
+
+ QTableView view;
+ view.setModel(&model);
+ view.setSelectionMode((QAbstractItemView::SelectionMode)mode);
+ view.setSelectionBehavior((QAbstractItemView::SelectionBehavior)behavior);
+
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), 0);
+
+ view.selectColumn(column);
+
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedItems);
+ for (int i = 0; selectedItems > 0 && i < columnCount; ++i)
+ QCOMPARE(view.selectionModel()->selectedIndexes().at(i).column(), column);
+}
+
+Q_DECLARE_METATYPE(QRect)
+void tst_QTableView::visualRect_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("hideRow");
+ QTest::addColumn<int>("hideColumn");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+ QTest::addColumn<QRect>("expectedRect");
+
+ QTest::newRow("(0,0)")
+ << 10 << 10
+ << -1 << -1
+ << 0 << 0
+ << 20 << 30
+ << QRect(0, 0, 29, 19);
+
+ QTest::newRow("(0,0) hidden row")
+ << 10 << 10
+ << 0 << -1
+ << 0 << 0
+ << 20 << 30
+ << QRect();
+
+ QTest::newRow("(0,0) hidden column")
+ << 10 << 10
+ << -1 << 0
+ << 0 << 0
+ << 20 << 30
+ << QRect();
+
+ QTest::newRow("(0,0) hidden row and column")
+ << 10 << 10
+ << 0 << 0
+ << 0 << 0
+ << 20 << 30
+ << QRect();
+
+ QTest::newRow("(0,0) out of bounds")
+ << 10 << 10
+ << -1 << -1
+ << 20 << 20
+ << 20 << 30
+ << QRect();
+
+ QTest::newRow("(5,5), hidden row")
+ << 10 << 10
+ << 5 << -1
+ << 5 << 5
+ << 20 << 30
+ << QRect();
+
+ QTest::newRow("(9,9)")
+ << 10 << 10
+ << -1 << -1
+ << 9 << 9
+ << 20 << 30
+ << QRect(30*9, 20*9, 29, 19);
+}
+
+void tst_QTableView::visualRect()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, hideRow);
+ QFETCH(int, hideColumn);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+ QFETCH(QRect, expectedRect);
+
+ QtTestTableModel model(rowCount, columnCount);
+
+ QTableView view;
+ view.setModel(&model);
+ // Make sure that it has 1 pixel between each cell.
+ view.setGridStyle(Qt::SolidLine);
+ for (int i = 0; i < view.verticalHeader()->count(); ++i)
+ view.verticalHeader()->resizeSection(i, rowHeight);
+ for (int i = 0; i < view.horizontalHeader()->count(); ++i)
+ view.horizontalHeader()->resizeSection(i, columnWidth);
+
+ view.hideRow(hideRow);
+ view.hideColumn(hideColumn);
+
+ QRect rect = view.visualRect(model.index(row, column));
+ QCOMPARE(rect, expectedRect);
+}
+
+void tst_QTableView::fetchMore()
+{
+ QtTestTableModel model(64, 64);
+
+ model.can_fetch_more = true;
+
+ QTableView view;
+ view.setModel(&model);
+ view.show();
+
+ QCOMPARE(model.fetch_more_count, 0);
+ view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum());
+ QVERIFY(model.fetch_more_count > 0);
+
+ model.fetch_more_count = 0; //reset
+ view.scrollToTop();
+ QCOMPARE(model.fetch_more_count, 0);
+
+ view.scrollToBottom();
+ QVERIFY(model.fetch_more_count > 0);
+
+ model.fetch_more_count = 0; //reset
+ view.scrollToTop();
+ view.setCurrentIndex(model.index(0, 0));
+ QCOMPARE(model.fetch_more_count, 0);
+
+ for (int i = 0; i < 64; ++i)
+ QTest::keyClick(&view, Qt::Key_Down);
+ QCOMPARE(view.currentIndex(), model.index(63, 0));
+ QVERIFY(model.fetch_more_count > 0);
+}
+
+void tst_QTableView::setHeaders()
+{
+ QTableView view;
+
+ // Make sure we don't delete ourselves
+ view.setVerticalHeader(view.verticalHeader());
+ view.verticalHeader()->count();
+ view.setHorizontalHeader(view.horizontalHeader());
+ view.horizontalHeader()->count();
+
+ // Try passing around a header without it being deleted
+ QTableView view2;
+ view2.setVerticalHeader(view.verticalHeader());
+ view2.setHorizontalHeader(view.horizontalHeader());
+ view.setHorizontalHeader(new QHeaderView(Qt::Horizontal));
+ view.setVerticalHeader(new QHeaderView(Qt::Vertical));
+ view2.verticalHeader()->count();
+ view2.horizontalHeader()->count();
+
+}
+
+void tst_QTableView::resizeRowsToContents_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<bool>("showGrid");
+ QTest::addColumn<int>("cellWidth");
+ QTest::addColumn<int>("cellHeight");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+
+ QTest::newRow("10x10 grid shown 40x40")
+ << 10 << 10 << false << 40 << 40 << 40 << 40;
+
+ QTest::newRow("10x10 grid not shown 40x40")
+ << 10 << 10 << true << 40 << 40 << 41 << 41;
+}
+
+void tst_QTableView::resizeRowsToContents()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(bool, showGrid);
+ QFETCH(int, cellWidth);
+ QFETCH(int, cellHeight);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+ Q_UNUSED(columnWidth);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QtTestTableView view;
+ QtTestItemDelegate delegate;
+
+ view.setModel(&model);
+ view.setItemDelegate(&delegate);
+ view.setShowGrid(showGrid); // the grid will add to the row height
+
+ delegate.hint = QSize(cellWidth, cellHeight);
+
+ QSignalSpy resizedSpy(view.verticalHeader(), SIGNAL(sectionResized(int, int, int)));
+ view.resizeRowsToContents();
+
+ QCOMPARE(resizedSpy.count(), model.rowCount());
+ for (int r = 0; r < model.rowCount(); ++r) {
+ QCOMPARE(view.rowHeight(r), rowHeight);
+ }
+}
+
+void tst_QTableView::resizeColumnsToContents_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<bool>("showGrid");
+ QTest::addColumn<int>("cellWidth");
+ QTest::addColumn<int>("cellHeight");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+
+ QTest::newRow("10x10 grid shown 40x40")
+ << 10 << 10 << false << 40 << 40 << 40 << 40;
+
+ QTest::newRow("10x10 grid not shown 40x40")
+ << 10 << 10 << true << 40 << 40 << 41 << 41;
+}
+
+void tst_QTableView::resizeColumnsToContents()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(bool, showGrid);
+ QFETCH(int, cellWidth);
+ QFETCH(int, cellHeight);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+ Q_UNUSED(rowHeight);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QtTestTableView view;
+ QtTestItemDelegate delegate;
+
+ view.setModel(&model);
+ view.setItemDelegate(&delegate);
+ view.setShowGrid(showGrid); // the grid will add to the row height
+
+ delegate.hint = QSize(cellWidth, cellHeight);
+
+ QSignalSpy resizedSpy(view.horizontalHeader(), SIGNAL(sectionResized(int, int, int)));
+ view.resizeColumnsToContents();
+
+ QCOMPARE(resizedSpy.count(), model.columnCount());
+ for (int c = 0; c < model.columnCount(); ++c)
+ QCOMPARE(view.columnWidth(c), columnWidth);
+}
+
+void tst_QTableView::rowViewportPosition_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("verticalScrollMode");
+ QTest::addColumn<int>("verticalScrollValue");
+ QTest::addColumn<int>("rowViewportPosition");
+
+ QTest::newRow("row 0, scroll per item 0")
+ << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerItem) << 0 << 0;
+
+ QTest::newRow("row 1, scroll per item, 0")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 0 << 1 * 40;
+
+ QTest::newRow("row 1, scroll per item, 1")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 1 << 0;
+
+ QTest::newRow("row 5, scroll per item, 0")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 0 << 5 * 40;
+
+ QTest::newRow("row 5, scroll per item, 5")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 5 << 0;
+
+ QTest::newRow("row 9, scroll per item, 0")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 0 << 9 * 40;
+
+ QTest::newRow("row 9, scroll per item, 5")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 5 << 4 * 40;
+
+ QTest::newRow("row 0, scroll per pixel 0")
+ << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerPixel) << 0 << 0;
+
+ QTest::newRow("row 1, scroll per pixel, 0")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 0 << 1 * 40;
+
+ QTest::newRow("row 1, scroll per pixel, 1")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 1 * 40 << 0;
+
+ QTest::newRow("row 5, scroll per pixel, 0")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 0 << 5 * 40;
+
+ QTest::newRow("row 5, scroll per pixel, 5")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 0;
+
+ QTest::newRow("row 9, scroll per pixel, 0")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 0 << 9 * 40;
+
+ QTest::newRow("row 9, scroll per pixel, 5")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 4 * 40;
+}
+
+void tst_QTableView::rowViewportPosition()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, rowHeight);
+ QFETCH(int, row);
+ QFETCH(int, verticalScrollMode);
+ QFETCH(int, verticalScrollValue);
+ QFETCH(int, rowViewportPosition);
+
+ QtTestTableModel model(rowCount, 1);
+ QtTestTableView view;
+ view.resize(100, 2 * rowHeight);
+ view.show();
+
+ view.setModel(&model);
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHeight(r, rowHeight);
+
+ view.setVerticalScrollMode((QAbstractItemView::ScrollMode)verticalScrollMode);
+ view.verticalScrollBar()->setValue(verticalScrollValue);
+
+ QCOMPARE(view.rowViewportPosition(row), rowViewportPosition);
+}
+
+void tst_QTableView::rowAt_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<IntList>("hiddenRows");
+ QTest::addColumn<int>("coordinate");
+ QTest::addColumn<int>("row");
+
+ QTest::newRow("row at 100") << 5 << 40 << IntList() << 100 << 2;
+ QTest::newRow("row at 180") << 5 << 40 << IntList() << 180 << 4;
+ QTest::newRow("row at 20") << 5 << 40 << IntList() << 20 << 0;
+
+ // ### expand the dataset to include hidden rows
+}
+
+void tst_QTableView::rowAt()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, rowHeight);
+ QFETCH(IntList, hiddenRows);
+ QFETCH(int, coordinate);
+ QFETCH(int, row);
+
+ QtTestTableModel model(rowCount, 1);
+ QtTestTableView view;
+ view.resize(100, 2 * rowHeight);
+
+ view.setModel(&model);
+
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHeight(r, rowHeight);
+
+ for (int i = 0; i < hiddenRows.count(); ++i)
+ view.hideRow(hiddenRows.at(i));
+
+ QCOMPARE(view.rowAt(coordinate), row);
+}
+
+void tst_QTableView::rowHeight_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<IntList>("rowHeights");
+ QTest::addColumn<BoolList>("hiddenRows");
+
+ QTest::newRow("increasing")
+ << 5
+ << (IntList() << 20 << 30 << 40 << 50 << 60)
+ << (BoolList() << false << false << false << false << false);
+
+ QTest::newRow("decreasing")
+ << 5
+ << (IntList() << 60 << 50 << 40 << 30 << 20)
+ << (BoolList() << false << false << false << false << false);
+
+ QTest::newRow("random")
+ << 5
+ << (IntList() << 87 << 34 << 68 << 91 << 27)
+ << (BoolList() << false << false << false << false << false);
+
+ // ### expand the dataset to include hidden rows
+}
+
+void tst_QTableView::rowHeight()
+{
+ QFETCH(int, rowCount);
+ QFETCH(IntList, rowHeights);
+ QFETCH(BoolList, hiddenRows);
+
+ QtTestTableModel model(rowCount, 1);
+ QtTestTableView view;
+
+ view.setModel(&model);
+
+ for (int r = 0; r < rowCount; ++r) {
+ view.setRowHeight(r, rowHeights.at(r));
+ view.setRowHidden(r, hiddenRows.at(r));
+ }
+
+ for (int r = 0; r < rowCount; ++r) {
+ if (hiddenRows.at(r))
+ QCOMPARE(view.rowHeight(r), 0);
+ else
+ QCOMPARE(view.rowHeight(r), rowHeights.at(r));
+ }
+}
+
+void tst_QTableView::columnViewportPosition_data()
+{
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("columnWidth");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("horizontalScrollMode");
+ QTest::addColumn<int>("horizontalScrollValue");
+ QTest::addColumn<int>("columnViewportPosition");
+
+ QTest::newRow("column 0, scroll per item 0")
+ << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerItem) << 0 << 0;
+
+ QTest::newRow("column 1, scroll per item, 0")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 0 << 1 * 40;
+
+ QTest::newRow("column 1, scroll per item, 1")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerItem) << 1 << 0;
+
+ QTest::newRow("column 5, scroll per item, 0")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 0 << 5 * 40;
+
+ QTest::newRow("column 5, scroll per item, 5")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerItem) << 5 << 0;
+
+ QTest::newRow("column 9, scroll per item, 0")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 0 << 9 * 40;
+
+ QTest::newRow("column 9, scroll per item, 5")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerItem) << 5 << 4 * 40;
+
+ QTest::newRow("column 0, scroll per pixel 0")
+ << 10 << 40 << 0 << int(QAbstractItemView::ScrollPerPixel) << 0 << 0;
+
+ QTest::newRow("column 1, scroll per pixel 0")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 0 << 1 * 40;
+
+ QTest::newRow("column 1, scroll per pixel 1")
+ << 10 << 40 << 1 << int(QAbstractItemView::ScrollPerPixel) << 1 * 40 << 0;
+
+ QTest::newRow("column 5, scroll per pixel 0")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 0 << 5 * 40;
+
+ QTest::newRow("column 5, scroll per pixel 5")
+ << 10 << 40 << 5 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 0;
+
+ QTest::newRow("column 9, scroll per pixel 0")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 0 << 9 * 40;
+
+ QTest::newRow("column 9, scroll per pixel 5")
+ << 10 << 40 << 9 << int(QAbstractItemView::ScrollPerPixel) << 5 * 40 << 4 * 40;
+}
+
+void tst_QTableView::columnViewportPosition()
+{
+ QFETCH(int, columnCount);
+ QFETCH(int, columnWidth);
+ QFETCH(int, column);
+ QFETCH(int, horizontalScrollMode);
+ QFETCH(int, horizontalScrollValue);
+ QFETCH(int, columnViewportPosition);
+
+ QtTestTableModel model(1, columnCount);
+ QtTestTableView view;
+ view.resize(2 * columnWidth, 100);
+ view.show();
+
+ view.setModel(&model);
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnWidth(c, columnWidth);
+
+ view.setHorizontalScrollMode((QAbstractItemView::ScrollMode)horizontalScrollMode);
+ view.horizontalScrollBar()->setValue(horizontalScrollValue);
+
+ QCOMPARE(view.columnViewportPosition(column), columnViewportPosition);
+}
+
+void tst_QTableView::columnAt_data()
+{
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("columnWidth");
+ QTest::addColumn<IntList>("hiddenColumns");
+ QTest::addColumn<int>("coordinate");
+ QTest::addColumn<int>("column");
+
+ QTest::newRow("column at 100") << 5 << 40 << IntList() << 100 << 2;
+ QTest::newRow("column at 180") << 5 << 40 << IntList() << 180 << 4;
+ QTest::newRow("column at 20") << 5 << 40 << IntList() << 20 << 0;
+
+ // ### expand the dataset to include hidden coumns
+}
+
+void tst_QTableView::columnAt()
+{
+ QFETCH(int, columnCount);
+ QFETCH(int, columnWidth);
+ QFETCH(IntList, hiddenColumns);
+ QFETCH(int, coordinate);
+ QFETCH(int, column);
+
+ QtTestTableModel model(1, columnCount);
+ QtTestTableView view;
+ view.resize(2 * columnWidth, 100);
+
+ view.setModel(&model);
+
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnWidth(c, columnWidth);
+
+ for (int i = 0; i < hiddenColumns.count(); ++i)
+ view.hideColumn(hiddenColumns.at(i));
+
+ QCOMPARE(view.columnAt(coordinate), column);
+}
+
+void tst_QTableView::columnWidth_data()
+{
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<IntList>("columnWidths");
+ QTest::addColumn<BoolList>("hiddenColumns");
+
+ QTest::newRow("increasing")
+ << 5
+ << (IntList() << 20 << 30 << 40 << 50 << 60)
+ << (BoolList() << false << false << false << false << false);
+
+ QTest::newRow("decreasing")
+ << 5
+ << (IntList() << 60 << 50 << 40 << 30 << 20)
+ << (BoolList() << false << false << false << false << false);
+
+ QTest::newRow("random")
+ << 5
+ << (IntList() << 87 << 34 << 68 << 91 << 27)
+ << (BoolList() << false << false << false << false << false);
+
+ // ### expand the dataset to include hidden columns
+}
+
+void tst_QTableView::columnWidth()
+{
+ QFETCH(int, columnCount);
+ QFETCH(IntList, columnWidths);
+ QFETCH(BoolList, hiddenColumns);
+
+ QtTestTableModel model(1, columnCount);
+ QtTestTableView view;
+
+ view.setModel(&model);
+
+ for (int c = 0; c < columnCount; ++c) {
+ view.setColumnWidth(c, columnWidths.at(c));
+ view.setColumnHidden(c, hiddenColumns.at(c));
+ }
+
+ for (int c = 0; c < columnCount; ++c) {
+ if (hiddenColumns.at(c))
+ QCOMPARE(view.columnWidth(c), 0);
+ else
+ QCOMPARE(view.columnWidth(c), columnWidths.at(c));
+ }
+}
+
+void tst_QTableView::hiddenRow_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<BoolList>("hiddenRows");
+
+ QTest::newRow("first hidden")
+ << 5 << (BoolList() << true << false << false << false << false);
+
+ QTest::newRow("last hidden")
+ << 5 << (BoolList() << false << false << false << false << true);
+
+ QTest::newRow("none hidden")
+ << 5 << (BoolList() << false << false << false << false << false);
+
+ QTest::newRow("all hidden")
+ << 5 << (BoolList() << true << true << true << true << true);
+ }
+
+void tst_QTableView::hiddenRow()
+{
+ QFETCH(int, rowCount);
+ QFETCH(BoolList, hiddenRows);
+
+
+ QtTestTableModel model(rowCount, 1);
+ QtTestTableView view;
+
+ view.setModel(&model);
+
+ for (int r = 0; r < rowCount; ++r)
+ QVERIFY(!view.isRowHidden(r));
+
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHidden(r, hiddenRows.at(r));
+
+ for (int r = 0; r < rowCount; ++r)
+ QCOMPARE(view.isRowHidden(r), hiddenRows.at(r));
+
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHidden(r, false);
+
+ for (int r = 0; r < rowCount; ++r)
+ QVERIFY(!view.isRowHidden(r));
+}
+
+void tst_QTableView::hiddenColumn_data()
+{
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<BoolList>("hiddenColumns");
+
+ QTest::newRow("first hidden")
+ << 5 << (BoolList() << true << false << false << false << false);
+
+ QTest::newRow("last hidden")
+ << 5 << (BoolList() << false << false << false << false << true);
+
+ QTest::newRow("none hidden")
+ << 5 << (BoolList() << false << false << false << false << false);
+
+ QTest::newRow("all hidden")
+ << 5 << (BoolList() << true << true << true << true << true);
+}
+
+void tst_QTableView::hiddenColumn()
+{
+ QFETCH(int, columnCount);
+ QFETCH(BoolList, hiddenColumns);
+
+ QtTestTableModel model(1, columnCount);
+ QtTestTableView view;
+
+ view.setModel(&model);
+
+ for (int c = 0; c < columnCount; ++c)
+ QVERIFY(!view.isColumnHidden(c));
+
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnHidden(c, hiddenColumns.at(c));
+
+ for (int c = 0; c < columnCount; ++c)
+ QCOMPARE(view.isColumnHidden(c), hiddenColumns.at(c));
+
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnHidden(c, false);
+
+ for (int c = 0; c < columnCount; ++c)
+ QVERIFY(!view.isColumnHidden(c));
+}
+
+void tst_QTableView::sortingEnabled_data()
+{
+// QTest::addColumn<int>("columnCount");
+}
+
+void tst_QTableView::sortingEnabled()
+{
+// QFETCH(int, columnCount);
+}
+
+void tst_QTableView::scrollTo_data()
+{
+ QTest::addColumn<int>("verticalScrollMode");
+ QTest::addColumn<int>("horizontalScrollMode");
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+ QTest::addColumn<int>("hiddenRow");
+ QTest::addColumn<int>("hiddenColumn");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowSpan");
+ QTest::addColumn<int>("columnSpan");
+ QTest::addColumn<int>("horizontalScroll");
+ QTest::addColumn<int>("verticalScroll");
+ QTest::addColumn<int>("scrollHint");
+ QTest::addColumn<int>("expectedHorizontalScroll");
+ QTest::addColumn<int>("expectedVerticalScroll");
+
+ QTest::newRow("no hidden, no span, no scroll, per item")
+ << (int)QAbstractItemView::ScrollPerItem
+ << (int)QAbstractItemView::ScrollPerItem
+ << 10 << 10 // table
+ << 80 << 80 // size
+ << -1 << -1 // hide
+ << 0 << 0 // cell
+ << 1 << 1 // span
+ << 0 << 0 // scroll
+ << (int)QAbstractItemView::PositionAtTop
+ << 0 << 0; // expected
+
+ QTest::newRow("no hidden, no span, no scroll, per pixel")
+ << (int)QAbstractItemView::ScrollPerPixel
+ << (int)QAbstractItemView::ScrollPerPixel
+ << 10 << 10 // table
+ << 80 << 80 // size
+ << -1 << -1 // hide
+ << 0 << 0 // cell
+ << 1 << 1 // span
+ << 0 << 0 // scroll
+ << (int)QAbstractItemView::PositionAtTop
+ << 0 << 0; // expected
+
+ QTest::newRow("hidden, no span, no scroll, per item")
+ << (int)QAbstractItemView::ScrollPerItem
+ << (int)QAbstractItemView::ScrollPerItem
+ << 10 << 10 // table
+ << 80 << 80 // size
+ << 3 << 3 // hide
+ << 5 << 5 // cell
+ << 1 << 1 // span
+ << 0 << 0 // scroll
+ << (int)QAbstractItemView::PositionAtTop
+ << 4 << 4; // expected
+}
+
+void tst_QTableView::scrollTo()
+{
+ QFETCH(int, horizontalScrollMode);
+ QFETCH(int, verticalScrollMode);
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+ QFETCH(int, hiddenRow);
+ QFETCH(int, hiddenColumn);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowSpan);
+ QFETCH(int, columnSpan);
+ QFETCH(int, horizontalScroll);
+ QFETCH(int, verticalScroll);
+ QFETCH(int, scrollHint);
+ QFETCH(int, expectedHorizontalScroll);
+ QFETCH(int, expectedVerticalScroll);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QWidget toplevel;
+ QtTestTableView view(&toplevel);
+
+ toplevel.show();
+ // resizing to this size will ensure that there can ONLY_BE_ONE_CELL inside the view.
+ QSize forcedSize(columnWidth * 2, rowHeight * 2);
+ view.resize(forcedSize);
+ QTest::qWaitForWindowShown(&view);
+ QTest::qWait(50);
+ QTRY_COMPARE(view.size(), forcedSize);
+
+ view.setModel(&model);
+ view.setSpan(row, column, rowSpan, columnSpan);
+ view.hideRow(hiddenRow);
+ view.hideColumn(hiddenColumn);
+ view.setHorizontalScrollMode((QAbstractItemView::ScrollMode)horizontalScrollMode);
+ view.setVerticalScrollMode((QAbstractItemView::ScrollMode)verticalScrollMode);
+
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHeight(r, rowHeight);
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnWidth(c, columnWidth);
+
+ QTest::qWait(150); // ### needed to pass the test
+ view.horizontalScrollBar()->setValue(horizontalScroll);
+ view.verticalScrollBar()->setValue(verticalScroll);
+
+ QModelIndex index = model.index(row, column);
+ QVERIFY(index.isValid());
+ view.scrollTo(index, (QAbstractItemView::ScrollHint)scrollHint);
+ QCOMPARE(view.verticalScrollBar()->value(), expectedVerticalScroll);
+ QCOMPARE(view.horizontalScrollBar()->value(), expectedHorizontalScroll);
+}
+
+void tst_QTableView::indexAt_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+
+ QTest::addColumn<int>("rowHeight");
+ QTest::addColumn<int>("columnWidth");
+
+ QTest::addColumn<int>("hiddenRow");
+ QTest::addColumn<int>("hiddenColumn");
+
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowSpan");
+ QTest::addColumn<int>("columnSpan");
+ QTest::addColumn<int>("horizontalScroll");
+ QTest::addColumn<int>("verticalScroll");
+ QTest::addColumn<int>("x");
+ QTest::addColumn<int>("y");
+ QTest::addColumn<int>("expectedRow");
+ QTest::addColumn<int>("expectedColumn");
+
+ QTest::newRow("no hidden, no span, no scroll, (20,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << -1 // hide
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 0 << 0 // scroll
+ << 20 << 20 // point
+ << 0 << 0; // expected
+
+ QTest::newRow("row hidden, no span, no scroll, at (20,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << 0 << -1 // hide
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 0 << 0 // scroll
+ << 20 << 20 // point
+ << 1 << 0; // expected
+
+ QTest::newRow("col hidden, no span, no scroll, at (20,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << 0 // hide
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 0 << 0 // scroll
+ << 20 << 20 // point
+ << 0 << 1; // expected
+
+ QTest::newRow("no hidden, row span, no scroll, at (60,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << -1 // hide
+ << 0 << 0 // pos
+ << 2 << 1 // span
+ << 0 << 0 // scroll
+ << 20 << 60 // point
+ << 0 << 0; // expected
+
+
+ QTest::newRow("no hidden, col span, no scroll, at (60,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << -1 // hide
+ << 0 << 0 // pos
+ << 1 << 2 // span
+ << 0 << 0 // scroll
+ << 60 << 20 // point
+ << 0 << 0; // expected
+
+ QTest::newRow("no hidden, no span, scroll (5,0), at (20,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << -1 // hide
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 5 << 0 // scroll
+ << 20 << 20 // point
+ << 0 << 5; // expected
+
+ QTest::newRow("no hidden, no span, scroll (0,5), at (20,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << -1 // hide
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 0 << 5 // scroll
+ << 20 << 20 // point
+ << 5 << 0; // expected
+
+ QTest::newRow("no hidden, no span, scroll (5,5), at (20,20)")
+ << 10 << 10 // dim
+ << 40 << 40 // size
+ << -1 << -1 // hide
+ << -1 << -1 // pos
+ << 1 << 1 // span
+ << 5 << 5 // scroll
+ << 20 << 20 // point
+ << 5 << 5; // expected
+}
+
+void tst_QTableView::indexAt()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, rowHeight);
+ QFETCH(int, columnWidth);
+ QFETCH(int, hiddenRow);
+ QFETCH(int, hiddenColumn);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowSpan);
+ QFETCH(int, columnSpan);
+ QFETCH(int, horizontalScroll);
+ QFETCH(int, verticalScroll);
+ QFETCH(int, x);
+ QFETCH(int, y);
+ QFETCH(int, expectedRow);
+ QFETCH(int, expectedColumn);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QWidget toplevel;
+ QtTestTableView view(&toplevel);
+
+ toplevel.show();
+ QTest::qWaitForWindowShown(&toplevel);
+
+ //some styles change the scroll mode in their polish
+ view.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
+ view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+
+ view.setModel(&model);
+ view.setSpan(row, column, rowSpan, columnSpan);
+ view.hideRow(hiddenRow);
+ view.hideColumn(hiddenColumn);
+
+ for (int r = 0; r < rowCount; ++r)
+ view.setRowHeight(r, rowHeight);
+ for (int c = 0; c < columnCount; ++c)
+ view.setColumnWidth(c, columnWidth);
+
+ QTest::qWait(20);
+ view.horizontalScrollBar()->setValue(horizontalScroll);
+ view.verticalScrollBar()->setValue(verticalScroll);
+ QTest::qWait(20);
+
+ QModelIndex index = view.indexAt(QPoint(x, y));
+ QCOMPARE(index.row(), expectedRow);
+ QCOMPARE(index.column(), expectedColumn);
+}
+
+void tst_QTableView::span_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("hiddenRow");
+ QTest::addColumn<int>("hiddenColumn");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("rowSpan");
+ QTest::addColumn<int>("columnSpan");
+ QTest::addColumn<int>("expectedRowSpan");
+ QTest::addColumn<int>("expectedColumnSpan");
+ QTest::addColumn<bool>("clear");
+
+ QTest::newRow("top left 2x2")
+ << 10 << 10
+ << -1 << -1
+ << 0 << 0
+ << 2 << 2
+ << 2 << 2
+ << false;
+
+ QTest::newRow("top left 1x2")
+ << 10 << 10
+ << 3 << 3
+ << 0 << 0
+ << 1 << 2
+ << 1 << 2
+ << false;
+
+ QTest::newRow("top left 2x1")
+ << 10 << 10
+ << -1 << -1
+ << 0 << 0
+ << 2 << 1
+ << 2 << 1
+ << false;
+
+ /* This makes no sens.
+ QTest::newRow("top left 2x0")
+ << 10 << 10
+ << -1 << -1
+ << 0 << 0
+ << 2 << 0
+ << 2 << 0
+ << false;
+
+ QTest::newRow("top left 0x2")
+ << 10 << 10
+ << -1 << -1
+ << 0 << 0
+ << 0 << 2
+ << 0 << 2
+ << false;*/
+
+ QTest::newRow("invalid 2x2")
+ << 10 << 10
+ << -1 << -1
+ << -1 << -1
+ << 2 << 2
+ << 1 << 1
+ << false;
+
+ QTest::newRow("top left 2x2")
+ << 10 << 10
+ << -1 << -1
+ << 0 << 0
+ << 2 << 2
+ << 2 << 2
+ << false;
+
+ QTest::newRow("bottom right 2x2")
+ << 10 << 10
+ << -1 << -1
+ << 8 << 8
+ << 2 << 2
+ << 2 << 2
+ << false;
+
+ QTest::newRow("invalid span 2x2")
+ << 10 << 10
+ << -1 << -1
+ << 8 << 8
+ << 2 << 2
+ << 2 << 2
+ << false;
+
+ QTest::newRow("invalid span 3x3")
+ << 10 << 10
+ << -1 << -1
+ << 6 << 6
+ << 3 << 3
+ << 2 << 3
+ << true;
+
+}
+
+void tst_QTableView::span()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, hiddenRow);
+ QFETCH(int, hiddenColumn);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, rowSpan);
+ QFETCH(int, columnSpan);
+ QFETCH(int, expectedRowSpan);
+ QFETCH(int, expectedColumnSpan);
+ QFETCH(bool, clear);
+
+ QtTestTableModel model(rowCount, columnCount);
+ QtTestTableView view;
+
+ view.setModel(&model);
+ view.show();
+
+ view.setSpan(row, column, rowSpan, columnSpan);
+ if (clear) {
+ model.removeLastRow();
+ model.removeLastRow();
+ view.update();
+ }
+
+ view.hideRow(hiddenRow);
+ view.hideColumn(hiddenColumn);
+ view.show();
+
+ QCOMPARE(view.rowSpan(row, column), expectedRowSpan);
+ QCOMPARE(view.columnSpan(row, column), expectedColumnSpan);
+
+ if (hiddenRow > -1) {
+ QModelIndex hidden = model.index(hiddenRow, columnCount - 1);
+ QVERIFY(view.isIndexHidden(hidden));
+ }
+
+ if (hiddenColumn > -1) {
+ QModelIndex hidden = model.index(rowCount - 1, hiddenColumn);
+ QVERIFY(view.isIndexHidden(hidden));
+ }
+
+ view.clearSpans();
+ QCOMPARE(view.rowSpan(row, column), 1);
+ QCOMPARE(view.columnSpan(row, column), 1);
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+typedef QVector<QRect> SpanList;
+Q_DECLARE_METATYPE(SpanList)
+
+void tst_QTableView::spans_data()
+{
+ QTest::addColumn<int>("rows");
+ QTest::addColumn<int>("columns");
+ QTest::addColumn<SpanList>("spans");
+ QTest::addColumn<bool>("hideRowLastRowOfFirstSpan");
+ QTest::addColumn<QPoint>("pos");
+ QTest::addColumn<int>("expectedRowSpan");
+ QTest::addColumn<int>("expectedColumnSpan");
+
+ QTest::newRow("1x3 span, query 3,0")
+ << 5 << 5
+ << (SpanList() << QRect(3, 0, 1, 3))
+ << false //no hidden row
+ << QPoint(3, 0)
+ << 1
+ << 3;
+
+ QTest::newRow("1x3 span, query 3,1")
+ << 5 << 5
+ << (SpanList() << QRect(3, 0, 1, 3))
+ << false //no hidden row
+ << QPoint(3, 1)
+ << 1
+ << 3;
+
+ QTest::newRow("1x3 span, query 3,2")
+ << 5 << 5
+ << (SpanList() << QRect(3, 0, 1, 3))
+ << false //no hidden row
+ << QPoint(3, 2)
+ << 1
+ << 3;
+
+ QTest::newRow("two 1x2 spans at the same column, query at 3,0")
+ << 5 << 5
+ << (SpanList() << QRect(3, 0, 1, 2) << QRect(4, 0, 1, 2))
+ << false //no hidden row
+ << QPoint(3, 0)
+ << 1
+ << 2;
+
+ QTest::newRow("two 1x2 spans at the same column, query at 4,0")
+ << 5 << 5
+ << (SpanList() << QRect(3, 0, 1, 2) << QRect(4, 0, 1, 2))
+ << false //no hidden row
+ << QPoint(4, 0)
+ << 1
+ << 2;
+
+ QTest::newRow("how to order spans (1,1)")
+ << 5 << 5
+ << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
+ << false //no hidden row
+ << QPoint(1, 1)
+ << 3
+ << 1;
+
+ QTest::newRow("how to order spans (2,1)")
+ << 5 << 5
+ << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
+ << false //no hidden row
+ << QPoint(2, 1)
+ << 3
+ << 1;
+
+ QTest::newRow("how to order spans (3,1)")
+ << 5 << 5
+ << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
+ << false //no hidden row
+ << QPoint(3, 1)
+ << 3
+ << 1;
+
+ QTest::newRow("how to order spans (1,2)")
+ << 5 << 5
+ << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
+ << false //no hidden row
+ << QPoint(1, 2)
+ << 2
+ << 1;
+
+ QTest::newRow("how to order spans (2,2)")
+ << 5 << 5
+ << (SpanList() << QRect(1, 1, 3, 1) << QRect(1, 2, 2, 1))
+ << false //no hidden row
+ << QPoint(2, 2)
+ << 2
+ << 1;
+
+ QTest::newRow("spans with hidden rows")
+ << 3 << 2
+ << (SpanList() << QRect(0, 0, 2, 2) << QRect(2, 0, 1, 2))
+ << true //we hide the last row of the first span
+ << QPoint(2, 0)
+ << 1
+ << 2;
+
+ QTest::newRow("QTBUG-6004: No failing assertion, then it passes.")
+ << 5 << 5
+ << (SpanList() << QRect(0, 0, 2, 2) << QRect(0, 0, 1, 1))
+ << false
+ << QPoint(0, 0)
+ << 1
+ << 1;
+
+ QTest::newRow("QTBUG-6004 (follow-up): No failing assertion, then it passes.")
+ << 10 << 10
+ << (SpanList() << QRect(2, 2, 1, 3) << QRect(2, 2, 1, 1))
+ << false
+ << QPoint(0, 0)
+ << 1
+ << 1;
+
+ QTest::newRow("QTBUG-9631: remove one span")
+ << 10 << 10
+ << (SpanList() << QRect(1, 1, 2, 1) << QRect(2, 2, 2, 2) << QRect(1, 1, 1, 1))
+ << false
+ << QPoint(1, 1)
+ << 1
+ << 1;
+}
+
+void tst_QTableView::spans()
+{
+ QFETCH(int, rows);
+ QFETCH(int, columns);
+ QFETCH(SpanList, spans);
+ QFETCH(bool, hideRowLastRowOfFirstSpan);
+ QFETCH(QPoint, pos);
+ QFETCH(int, expectedRowSpan);
+ QFETCH(int, expectedColumnSpan);
+
+ QtTestTableModel model(rows, columns);
+ QtTestTableView view;
+
+ view.setModel(&model);
+ view.show();
+
+ for (int i = 0; i < spans.count(); ++i) {
+ QRect sp = spans.at(i);
+ view.setSpan(sp.x(), sp.y(), sp.width(), sp.height());
+ }
+
+ if (hideRowLastRowOfFirstSpan) {
+ view.setRowHidden(spans.at(0).bottom(), true);
+ //we check that the span didn't break the visual rects of the model indexes
+ QRect first = view.visualRect( model.index(spans.at(0).top(), 0));
+ QRect next = view.visualRect( model.index(spans.at(0).bottom() + 1, 0));
+ QVERIFY(first.intersected(next).isEmpty());
+ }
+
+ QCOMPARE(view.columnSpan(pos.x(), pos.y()), expectedColumnSpan);
+ QCOMPARE(view.rowSpan(pos.x(), pos.y()), expectedRowSpan);
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+void tst_QTableView::spansAfterRowInsertion()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+ view.setSpan(3, 3, 3, 3);
+ view.show();
+ QTest::qWait(50);
+
+ // Insertion before the span only shifts the span.
+ view.model()->insertRows(0, 2);
+ QCOMPARE(view.rowSpan(3, 3), 1);
+ QCOMPARE(view.columnSpan(3, 3), 1);
+ QCOMPARE(view.rowSpan(5, 3), 3);
+ QCOMPARE(view.columnSpan(5, 3), 3);
+
+ // Insertion happens before the given row, so it only shifts the span also.
+ view.model()->insertRows(5, 2);
+ QCOMPARE(view.rowSpan(5, 3), 1);
+ QCOMPARE(view.columnSpan(5, 3), 1);
+ QCOMPARE(view.rowSpan(7, 3), 3);
+ QCOMPARE(view.columnSpan(7, 3), 3);
+
+ // Insertion inside the span expands it.
+ view.model()->insertRows(8, 2);
+ QCOMPARE(view.rowSpan(7, 3), 5);
+ QCOMPARE(view.columnSpan(7, 3), 3);
+
+ // Insertion after the span does nothing to it.
+ view.model()->insertRows(12, 2);
+ QCOMPARE(view.rowSpan(7, 3), 5);
+ QCOMPARE(view.columnSpan(7, 3), 3);
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+void tst_QTableView::spansAfterColumnInsertion()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+ view.setSpan(3, 3, 3, 3);
+ view.show();
+ QTest::qWait(50);
+
+ // Insertion before the span only shifts the span.
+ view.model()->insertColumns(0, 2);
+ QCOMPARE(view.rowSpan(3, 3), 1);
+ QCOMPARE(view.columnSpan(3, 3), 1);
+ QCOMPARE(view.rowSpan(3, 5), 3);
+ QCOMPARE(view.columnSpan(3, 5), 3);
+
+ // Insertion happens before the given column, so it only shifts the span also.
+ view.model()->insertColumns(5, 2);
+ QCOMPARE(view.rowSpan(3, 5), 1);
+ QCOMPARE(view.columnSpan(3, 5), 1);
+ QCOMPARE(view.rowSpan(3, 7), 3);
+ QCOMPARE(view.columnSpan(3, 7), 3);
+
+ // Insertion inside the span expands it.
+ view.model()->insertColumns(8, 2);
+ QCOMPARE(view.rowSpan(3, 7), 3);
+ QCOMPARE(view.columnSpan(3, 7), 5);
+
+ // Insertion after the span does nothing to it.
+ view.model()->insertColumns(12, 2);
+ QCOMPARE(view.rowSpan(3, 7), 3);
+ QCOMPARE(view.columnSpan(3, 7), 5);
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+void tst_QTableView::spansAfterRowRemoval()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+
+ QList<QRect> spans;
+ spans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 2)
+ << QRect(2, 2, 1, 5)
+ << QRect(2, 8, 1, 2)
+ << QRect(3, 4, 1, 2)
+ << QRect(4, 4, 1, 4)
+ << QRect(5, 6, 1, 3)
+ << QRect(6, 7, 1, 3);
+ foreach (QRect span, spans)
+ view.setSpan(span.top(), span.left(), span.height(), span.width());
+
+ view.show();
+ QTest::qWait(100);
+ view.model()->removeRows(3, 3);
+
+ QList<QRect> expectedSpans;
+ expectedSpans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 1)
+ << QRect(2, 2, 1, 2)
+ << QRect(2, 5, 1, 2)
+ << QRect(3, 4, 1, 1)
+ << QRect(4, 3, 1, 2)
+ << QRect(5, 3, 1, 3)
+ << QRect(6, 4, 1, 3);
+ foreach (QRect span, expectedSpans) {
+ QCOMPARE(view.columnSpan(span.top(), span.left()), span.width());
+ QCOMPARE(view.rowSpan(span.top(), span.left()), span.height());
+ }
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+void tst_QTableView::spansAfterColumnRemoval()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+
+ // Same set as above just swapping columns and rows.
+ QList<QRect> spans;
+ spans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 2)
+ << QRect(2, 2, 1, 5)
+ << QRect(2, 8, 1, 2)
+ << QRect(3, 4, 1, 2)
+ << QRect(4, 4, 1, 4)
+ << QRect(5, 6, 1, 3)
+ << QRect(6, 7, 1, 3);
+ foreach (QRect span, spans)
+ view.setSpan(span.left(), span.top(), span.width(), span.height());
+
+ view.show();
+ QTest::qWait(100);
+ view.model()->removeColumns(3, 3);
+
+ QList<QRect> expectedSpans;
+ expectedSpans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 1)
+ << QRect(2, 2, 1, 2)
+ << QRect(2, 5, 1, 2)
+ << QRect(3, 4, 1, 1)
+ << QRect(4, 3, 1, 2)
+ << QRect(5, 3, 1, 3)
+ << QRect(6, 4, 1, 3);
+ foreach (QRect span, expectedSpans) {
+ QCOMPARE(view.columnSpan(span.left(), span.top()), span.height());
+ QCOMPARE(view.rowSpan(span.left(), span.top()), span.width());
+ }
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+class Model : public QAbstractTableModel {
+
+Q_OBJECT
+
+public:
+ Model(QObject * parent = 0) : QAbstractTableModel(parent) {
+ }
+
+ int rowCount(const QModelIndex &) const {
+ return rows;
+ }
+ int columnCount(const QModelIndex &) const {
+ return columns;
+ }
+ QVariant data(const QModelIndex &, int) const
+ {
+ return QVariant();
+ }
+ void res() { reset(); }
+
+ int rows;
+ int columns;
+};
+
+void tst_QTableView::checkHeaderReset()
+{
+ QTableView view;
+ Model m;
+ m.rows = 3;
+ m.columns = 3;
+ view.setModel(&m);
+
+ m.rows = 4;
+ m.columns = 4;
+ m.res();
+ QCOMPARE(view.horizontalHeader()->count(), 4);
+}
+
+void tst_QTableView::checkHeaderMinSize()
+{
+ //tests if the minimumsize is of a header is taken into account
+ //while computing QTableView geometry. For that we test the position of the
+ //viewport.
+ QTableView view;
+ QStringListModel m;
+ m.setStringList( QStringList() << QLatin1String("one cell is enough"));
+ view.setModel(&m);
+
+ //setting the minimum height on the horizontal header
+ //and the minimum width on the vertical header
+ view.horizontalHeader()->setMinimumHeight(50);
+ view.verticalHeader()->setMinimumWidth(100);
+
+ view.show();
+
+ QVERIFY( view.verticalHeader()->y() >= view.horizontalHeader()->minimumHeight());
+ QVERIFY( view.horizontalHeader()->x() >= view.verticalHeader()->minimumWidth());
+}
+
+void tst_QTableView::resizeToContents()
+{
+ //checks that the resize to contents is consistent
+ QTableWidget table(2,3);
+ QTableWidget table2(2,3);
+ QTableWidget table3(2,3);
+
+
+ table.setHorizontalHeaderItem(0, new QTableWidgetItem("A Lot of text here: BLA BLA BLA"));
+ table2.setHorizontalHeaderItem(0, new QTableWidgetItem("A Lot of text here: BLA BLA BLA"));
+ table3.setHorizontalHeaderItem(0, new QTableWidgetItem("A Lot of text here: BLA BLA BLA"));
+ table.horizontalHeader()->setVisible(false);
+ table2.horizontalHeader()->setVisible(false);
+ table.verticalHeader()->setVisible(false);
+ table2.verticalHeader()->setVisible(false);
+
+
+ for(int i = 0;i<table.columnCount();i++) {
+ table.resizeColumnToContents(i);
+ }
+ for(int i = 0;i<table.rowCount();i++) {
+ table.resizeRowToContents(i);
+ }
+ table2.resizeColumnsToContents();
+ table2.resizeRowsToContents();
+ table3.resizeColumnsToContents();
+ table3.resizeRowsToContents();
+
+ //now let's check the row/col sizes
+ for(int i = 0;i<table.columnCount();i++) {
+ QCOMPARE( table.columnWidth(i), table2.columnWidth(i));
+ QCOMPARE( table2.columnWidth(i), table3.columnWidth(i));
+ }
+ for(int i = 0;i<table.rowCount();i++) {
+ QCOMPARE( table.rowHeight(i), table2.rowHeight(i));
+ QCOMPARE( table2.rowHeight(i), table3.rowHeight(i));
+ }
+
+}
+
+QT_BEGIN_NAMESPACE
+extern bool Q_GUI_EXPORT qt_tab_all_widgets; // qapplication.cpp
+QT_END_NAMESPACE
+
+void tst_QTableView::tabFocus()
+{
+ if (!qt_tab_all_widgets)
+ QSKIP("This test requires full keyboard control to be enabled.", SkipAll);
+
+ // QTableView enables tabKeyNavigation by default, but you should be able
+ // to change focus on an empty table view, or on a table view that doesn't
+ // have this property set.
+ QWidget window;
+
+ QTableView *view = new QTableView(&window);
+ QLineEdit *edit = new QLineEdit(&window);
+
+ window.show();
+ QApplication::setActiveWindow(&window);
+ QTest::qWaitForWindowShown(&window);
+ window.setFocus();
+ QTest::qWait(100);
+ window.activateWindow();
+ QTest::qWait(100);
+
+ qApp->processEvents();
+
+ WAIT_FOR_CONDITION(window.hasFocus(), true);
+
+ qApp->processEvents();
+
+ // window
+ QVERIFY(window.hasFocus());
+ QVERIFY(!view->hasFocus());
+ QVERIFY(!edit->hasFocus());
+
+ for (int i = 0; i < 2; ++i) {
+ // tab to view
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab);
+ QTRY_VERIFY(!window.hasFocus());
+ QVERIFY(view->hasFocus());
+ QVERIFY(!edit->hasFocus());
+
+ // tab to edit
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab);
+ QTRY_VERIFY(edit->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!view->hasFocus());
+ }
+
+ // backtab to view
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QTRY_VERIFY(view->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!edit->hasFocus());
+
+ // backtab to edit
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QTRY_VERIFY(edit->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!view->hasFocus());
+
+ QStandardItemModel *model = new QStandardItemModel;
+ view->setModel(model);
+
+ // backtab to view
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QTRY_VERIFY(view->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!edit->hasFocus());
+
+ // backtab to edit
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QTRY_VERIFY(edit->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!view->hasFocus());
+
+ model->insertRow(0, new QStandardItem("Hei"));
+ model->insertRow(0, new QStandardItem("Hei"));
+ model->insertRow(0, new QStandardItem("Hei"));
+
+ // backtab to view
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QTRY_VERIFY(view->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!edit->hasFocus());
+
+ // backtab to edit doesn't work
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QVERIFY(!window.hasFocus());
+ QVERIFY(view->hasFocus());
+ QVERIFY(!edit->hasFocus());
+
+ view->setTabKeyNavigation(false);
+
+ // backtab to edit
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Backtab);
+ QTRY_VERIFY(edit->hasFocus());
+ QVERIFY(!window.hasFocus());
+ QVERIFY(!view->hasFocus());
+
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab);
+ QTRY_VERIFY(view->hasFocus());
+ QTest::keyPress(qApp->focusWidget(), Qt::Key_Tab);
+ QTRY_VERIFY(edit->hasFocus());
+
+ delete model;
+}
+
+class BigModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ virtual QVariant data(const QModelIndex &index,
+ int role = Qt::DisplayRole) const
+ {
+ if (role == Qt::DisplayRole)
+ return QString("%1 - %2").arg(index.column()).arg(index.row());
+ return QVariant();
+ }
+
+
+ int rowCount(const QModelIndex & parent = QModelIndex()) const
+ {
+ Q_UNUSED(parent);
+ return 10000000;
+ }
+
+ int columnCount(const QModelIndex & parent = QModelIndex()) const
+ {
+ Q_UNUSED(parent);
+ return 20000000;
+ }
+};
+
+void tst_QTableView::bigModel()
+{
+ //should not crash
+ QTableView view;
+ BigModel model;
+ view.setModel(&model);
+ view.show();
+ view.setSpan(10002,10002,6,6);
+ QTest::qWait(100);
+ view.resize(1000,1000);
+ QTest::qWait(100);
+ view.scrollTo(model.index(10010,10010));
+ QTest::qWait(100);
+}
+
+void tst_QTableView::selectionSignal()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.checkSignalOrder = true;
+ view.setModel(&model);
+ view.resize(200, 200);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(model.index(2, 0)).center());
+}
+
+class task173773_EventFilter : public QObject
+{
+ int paintEventCount_;
+public:
+ task173773_EventFilter() : paintEventCount_(0) {}
+ int paintEventCount() const { return paintEventCount_; }
+private:
+ bool eventFilter(QObject *obj, QEvent *e)
+ {
+ Q_UNUSED(obj);
+ if (e->type() == QEvent::Paint)
+ ++paintEventCount_;
+ return false;
+ }
+};
+
+void tst_QTableView::task173773_updateVerticalHeader()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), 0);
+ model.setData(model.index(1, 0), 1);
+
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ QTableView view;
+ view.setModel(&proxyModel);
+ view.setSortingEnabled(true);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ view.sortByColumn(0, Qt::AscendingOrder);
+ QTest::qWait(100);
+
+ task173773_EventFilter eventFilter;
+ view.verticalHeader()->viewport()->installEventFilter(&eventFilter);
+
+ view.sortByColumn(0, Qt::DescendingOrder);
+ QTest::qWait(100);
+
+ // ### note: this test may occasionally pass even if the bug is present!
+ QVERIFY(eventFilter.paintEventCount() > 0);
+}
+
+void tst_QTableView::task227953_setRootIndex()
+{
+ QTableView tableView;
+
+ //model = tree with two items with tables as children
+ QStandardItemModel model;
+ QStandardItem item1, item2;
+ model.appendColumn(QList<QStandardItem*>() << &item1 << &item2);
+
+
+ //setup the first table as a child of the first item
+ for ( int row = 0; row < 40; ++row ) {
+ item1.appendRow(QList<QStandardItem*>() << new QStandardItem(QString("row %0").arg(row)));
+ }
+
+ //setup the second table as a child of the second item
+ for ( int row = 0; row < 10; ++row ) {
+ item2.appendRow(QList<QStandardItem*>() << new QStandardItem(QString("row %0").arg(row)));
+ }
+
+ tableView.setModel(&model);
+
+ //show the first 10 rows of the first table
+ QModelIndex root = model.indexFromItem(&item1);
+ tableView.setRootIndex(root);
+ for (int i = 10; i != 40; ++i) {
+ tableView.setRowHidden(i, true);
+ }
+
+ QCOMPARE(tableView.verticalHeader()->count(), 40);
+ QCOMPARE(tableView.verticalHeader()->hiddenSectionCount(), 30);
+
+ //show the first 10 rows of the second table
+ tableView.setRootIndex(model.indexFromItem(&item2));
+
+ QCOMPARE(tableView.verticalHeader()->count(), 10);
+ QCOMPARE(tableView.verticalHeader()->hiddenSectionCount(), 0);
+ QVERIFY(!tableView.verticalHeader()->isHidden());
+}
+
+void tst_QTableView::task240266_veryBigColumn()
+{
+ QTableView table;
+ table.setFixedSize(500, 300); //just to make sure we have the 2 first columns visible
+ QStandardItemModel model(1, 3);
+ table.setModel(&model);
+ table.setColumnWidth(0, 100); //normal column
+ table.setColumnWidth(1, 100); //normal column
+ table.setColumnWidth(2, 9000); //very big column
+ table.show();
+ QTest::qWaitForWindowShown(&table);
+
+ //some styles change the scroll mode in their polish
+ table.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
+ table.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+
+ QScrollBar *scroll = table.horizontalScrollBar();
+ QCOMPARE(scroll->minimum(), 0);
+ QCOMPARE(scroll->maximum(), model.columnCount() - 1);
+ QCOMPARE(scroll->singleStep(), 1);
+
+ //1 is not always a very correct value for pageStep. Ideally this should be dynamic.
+ //Maybe something for Qt 5 ;-)
+ QCOMPARE(scroll->pageStep(), 1);
+
+}
+
+void tst_QTableView::task248688_autoScrollNavigation()
+{
+ //we make sure that when navigating with the keyboard the view is correctly scrolled
+ //to the current item
+ QStandardItemModel model(16, 16);
+ QTableView view;
+ view.setModel(&model);
+
+ view.hideColumn(8);
+ view.hideRow(8);
+ view.show();
+ for (int r = 0; r < model.rowCount(); ++r) {
+ if (view.isRowHidden(r))
+ continue;
+ for (int c = 0; c < model.columnCount(); ++c) {
+ if (view.isColumnHidden(c))
+ continue;
+ QModelIndex index = model.index(r, c);
+ view.setCurrentIndex(index);
+ QVERIFY(view.viewport()->rect().contains(view.visualRect(index)));
+ }
+ }
+}
+
+
+// Since different Windows CE versions sport different taskbars, we skip this test.
+#ifndef Q_OS_WINCE
+void tst_QTableView::mouseWheel_data()
+{
+ QTest::addColumn<int>("scrollMode");
+ QTest::addColumn<int>("delta");
+ QTest::addColumn<int>("horizontalPositon");
+ QTest::addColumn<int>("verticalPosition");
+
+ QTest::newRow("scroll up per item")
+ << int(QAbstractItemView::ScrollPerItem) << 120
+ << 10 - qApp->wheelScrollLines() << 10 - qApp->wheelScrollLines();
+ QTest::newRow("scroll down per item")
+ << int(QAbstractItemView::ScrollPerItem) << -120
+ << 10 + qApp->wheelScrollLines() << 10 + qApp->wheelScrollLines();
+ QTest::newRow("scroll down per pixel")
+ << int(QAbstractItemView::ScrollPerPixel) << -120
+ << 10 + qApp->wheelScrollLines() * 89 << 10 + qApp->wheelScrollLines() * 28;
+}
+
+void tst_QTableView::mouseWheel()
+{
+
+ QFETCH(int, scrollMode);
+ QFETCH(int, delta);
+ QFETCH(int, horizontalPositon);
+ QFETCH(int, verticalPosition);
+
+ QtTestTableModel model(100, 100);
+ QWidget topLevel;
+ QtTestTableView view(&topLevel);
+ view.resize(500, 500);
+ for (int r = 0; r < 100; ++r)
+ view.setRowHeight(r, 50);
+ for (int c = 0; c < 100; ++c)
+ view.setColumnWidth(c, 100);
+ topLevel.show();
+
+ QTest::qWaitForWindowShown(&topLevel);
+
+ view.setModel(&model);
+
+ view.setHorizontalScrollMode((QAbstractItemView::ScrollMode)scrollMode);
+ view.setVerticalScrollMode((QAbstractItemView::ScrollMode)scrollMode);
+ view.horizontalScrollBar()->setValue(10);
+ view.verticalScrollBar()->setValue(10);
+
+ QPoint pos = view.viewport()->geometry().center();
+ QWheelEvent verticalEvent(pos, delta, 0, 0, Qt::Vertical);
+ QWheelEvent horizontalEvent(pos, delta, 0, 0, Qt::Horizontal);
+ QApplication::sendEvent(view.viewport(), &horizontalEvent);
+ QVERIFY(qAbs(view.horizontalScrollBar()->value() - horizontalPositon) < 10);
+ QApplication::sendEvent(view.viewport(), &verticalEvent);
+ QVERIFY(qAbs(view.verticalScrollBar()->value() - verticalPosition) < 10);
+}
+#endif
+
+void tst_QTableView::addColumnWhileEditing()
+{
+ QTableView view;
+ QStandardItemModel model(1, 10);
+ view.setModel(&model);
+ QModelIndex last = model.index(0,9);
+ view.show();
+
+ view.openPersistentEditor(last);
+ view.scrollTo(last);
+
+ //let's see if the editor is moved to the right location
+ //after adding a column
+ model.setColumnCount(model.columnCount() + 1);
+ QPointer<QLineEdit> editor = qFindChild<QLineEdit*>(&view);
+ QVERIFY(editor);
+ QCOMPARE(editor->geometry(), view.visualRect(last));
+
+ //let's see if the editor is moved to the right location
+ //after removing a column
+ view.scrollTo(model.index(0, model.columnCount()-1));
+ model.setColumnCount(model.columnCount() - 1);
+ QVERIFY(editor);
+ QCOMPARE(editor->geometry(), view.visualRect(last));
+}
+
+void tst_QTableView::task259308_scrollVerticalHeaderSwappedSections()
+{
+ QStandardItemModel model;
+ model.setRowCount(50);
+ model.setColumnCount(2);
+ for (int row = 0; row < model.rowCount(); ++row)
+ for (int col = 0; col < model.columnCount(); ++col) {
+ const QModelIndex &idx = model.index(row, col);
+ model.setData(idx, QVariant(row), Qt::EditRole);
+ }
+
+ QTableView tv;
+ tv.setModel(&model);
+ tv.show();
+ tv.verticalHeader()->swapSections(0, model.rowCount() - 1);
+ tv.setCurrentIndex(model.index(model.rowCount() - 1, 0));
+
+ QTest::qWaitForWindowShown(&tv);
+ QTest::keyClick(&tv, Qt::Key_PageUp); // PageUp won't scroll when at top
+ QTRY_COMPARE(tv.rowAt(0), tv.verticalHeader()->logicalIndex(0));
+
+ int newRow = tv.rowAt(tv.viewport()->height());
+ if (newRow == tv.rowAt(tv.viewport()->height() - 1)) // Overlapping row
+ newRow++;
+ QTest::keyClick(&tv, Qt::Key_PageDown); // Scroll down and check current
+ QTRY_COMPARE(tv.currentIndex().row(), newRow);
+
+ tv.setCurrentIndex(model.index(0, 0));
+ QTest::qWait(60);
+ QTest::keyClick(&tv, Qt::Key_PageDown); // PageDown won't scroll when at the bottom
+ QTRY_COMPARE(tv.rowAt(tv.viewport()->height() - 1), tv.verticalHeader()->logicalIndex(model.rowCount() - 1));
+}
+
+template <typename T>
+struct ValueSaver {
+ T &var, value;
+ ValueSaver(T &v) : var(v), value(v) { }
+ ~ValueSaver() { var = value; }
+};
+
+void tst_QTableView::task191545_dragSelectRows()
+{
+ QStandardItemModel model(10, 10);
+ QTableView table;
+ table.setModel(&model);
+ table.setSelectionBehavior(QAbstractItemView::SelectItems);
+ table.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ table.setMinimumSize(1000, 400);
+ table.show();
+ QTest::qWait(200);
+
+ ValueSaver<Qt::KeyboardModifiers> saver(QApplicationPrivate::modifier_buttons);
+ QApplicationPrivate::modifier_buttons = Qt::ControlModifier;
+
+ {
+ QRect cellRect = table.visualRect(model.index(3, 0));
+ QHeaderView *vHeader = table.verticalHeader();
+ QWidget *vHeaderVp = vHeader->viewport();
+ QPoint rowPos(cellRect.center());
+ QMouseEvent rowPressEvent(QEvent::MouseButtonPress, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(vHeaderVp, &rowPressEvent);
+
+ for (int i = 0; i < 4; ++i) {
+ rowPos.setY(rowPos.y() + cellRect.height());
+ QMouseEvent moveEvent(QEvent::MouseMove, rowPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
+ qApp->sendEvent(vHeaderVp, &moveEvent);
+ }
+ QMouseEvent rowReleaseEvent(QEvent::MouseButtonRelease, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(vHeaderVp, &rowReleaseEvent);
+
+ for (int i = 0; i < 4; ++i) {
+ QModelIndex index = model.index(3 + i, 0, table.rootIndex());
+ QVERIFY(vHeader->selectionModel()->selectedRows().contains(index));
+ }
+ }
+
+ {
+ QRect cellRect = table.visualRect(model.index(0, 3));
+ QHeaderView *hHeader = table.horizontalHeader();
+ QWidget *hHeaderVp = hHeader->viewport();
+ QPoint colPos((cellRect.left() + cellRect.right()) / 2, 5);
+ QMouseEvent colPressEvent(QEvent::MouseButtonPress, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(hHeaderVp, &colPressEvent);
+
+ for (int i = 0; i < 4; ++i) {
+ colPos.setX(colPos.x() + cellRect.width());
+ QMouseEvent moveEvent(QEvent::MouseMove, colPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
+ qApp->sendEvent(hHeaderVp, &moveEvent);
+ }
+ QMouseEvent colReleaseEvent(QEvent::MouseButtonRelease, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(hHeaderVp, &colReleaseEvent);
+
+ for (int i = 0; i < 4; ++i) {
+ QModelIndex index = model.index(0, 3 + i, table.rootIndex());
+ QVERIFY(hHeader->selectionModel()->selectedColumns().contains(index));
+ }
+ }
+
+ {
+ QRect cellRect = table.visualRect(model.index(2, 2));
+ QWidget *tableVp = table.viewport();
+ QPoint cellPos = cellRect.center();
+ QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(tableVp, &cellPressEvent);
+
+ for (int i = 0; i < 6; ++i) {
+ cellPos.setX(cellPos.x() + cellRect.width());
+ cellPos.setY(cellPos.y() + cellRect.height());
+ QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
+ qApp->sendEvent(tableVp, &moveEvent);
+ }
+ QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(tableVp, &cellReleaseEvent);
+
+ for (int i = 0; i < 6; ++i)
+ for (int j = 0; j < 6; ++j) {
+ QModelIndex index = model.index(2 + i, 2 + j, table.rootIndex());
+ QVERIFY(table.selectionModel()->isSelected(index));
+ }
+ }
+
+ {
+ QRect cellRect = table.visualRect(model.index(3, 3));
+ QWidget *tableVp = table.viewport();
+ QPoint cellPos = cellRect.center();
+ QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(tableVp, &cellPressEvent);
+
+ for (int i = 0; i < 6; ++i) {
+ cellPos.setX(cellPos.x() + cellRect.width());
+ cellPos.setY(cellPos.y() + cellRect.height());
+ QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
+ qApp->sendEvent(tableVp, &moveEvent);
+ }
+ QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier);
+ qApp->sendEvent(tableVp, &cellReleaseEvent);
+
+ QTest::qWait(200);
+ for (int i = 0; i < 6; ++i)
+ for (int j = 0; j < 6; ++j) {
+ QModelIndex index = model.index(3 + i, 3 + j, table.rootIndex());
+ QVERIFY(!table.selectionModel()->isSelected(index));
+ }
+ }
+}
+
+void tst_QTableView::task234926_setHeaderSorting()
+{
+ QStringListModel model;
+ QStringList data;
+ data << "orange" << "apple" << "banana" << "lemon" << "pumpkin";
+ QStringList sortedDataA = data;
+ QStringList sortedDataD = data;
+ qSort(sortedDataA);
+ qSort(sortedDataD.begin(), sortedDataD.end(), qGreater<QString>());
+ model.setStringList(data);
+ QTableView view;
+ view.setModel(&model);
+// view.show();
+ QTest::qWait(20);
+ QCOMPARE(model.stringList(), data);
+ view.setSortingEnabled(true);
+ view.sortByColumn(0, Qt::AscendingOrder);
+ QApplication::processEvents();
+ QCOMPARE(model.stringList() , sortedDataA);
+
+ view.horizontalHeader()->setSortIndicator(0, Qt::DescendingOrder);
+ QApplication::processEvents();
+ QCOMPARE(model.stringList() , sortedDataD);
+
+ QHeaderView *h = new QHeaderView(Qt::Horizontal);
+ h->setModel(&model);
+ view.setHorizontalHeader(h);
+ h->setSortIndicator(0, Qt::AscendingOrder);
+ QApplication::processEvents();
+ QCOMPARE(model.stringList() , sortedDataA);
+
+ h->setSortIndicator(0, Qt::DescendingOrder);
+ QApplication::processEvents();
+ QCOMPARE(model.stringList() , sortedDataD);
+}
+
+void tst_QTableView::taskQTBUG_5062_spansInconsistency()
+{
+ const int nRows = 5;
+ const int nColumns = 5;
+
+ QtTestTableModel model(nRows, nColumns);
+ QtTestTableView view;
+ view.setModel(&model);
+
+ for (int i = 0; i < nRows; ++i)
+ view.setSpan(i, 0, 1, nColumns);
+ view.setSpan(2, 0, 1, 1);
+ view.setSpan(3, 0, 1, 1);
+
+ VERIFY_SPANS_CONSISTENCY(&view);
+}
+
+void tst_QTableView::taskQTBUG_4516_clickOnRichTextLabel()
+{
+ QTableView view;
+ QStandardItemModel model(5,5);
+ view.setModel(&model);
+ QLabel label("rich text");
+ label.setTextFormat(Qt::RichText);
+ view.setIndexWidget(model.index(1,1), &label);
+ view.setCurrentIndex(model.index(0,0));
+ QCOMPARE(view.currentIndex(), model.index(0,0));
+
+ QTest::mouseClick(&label, Qt::LeftButton);
+ QCOMPARE(view.currentIndex(), model.index(1,1));
+
+
+}
+
+
+void tst_QTableView::changeHeaderData()
+{
+ QTableView view;
+ QStandardItemModel model(5,5);
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ QString text = "long long long text";
+ const int textWidth = view.verticalHeader()->fontMetrics().width(text);
+ QVERIFY(view.verticalHeader()->width() < textWidth);
+
+ model.setHeaderData(2, Qt::Vertical, text);
+ QTest::qWait(100); //leave time for layout
+
+ QVERIFY(view.verticalHeader()->width() > textWidth);
+}
+
+void tst_QTableView::taskQTBUG_5237_wheelEventOnHeader()
+{
+ QTableView view;
+ QStandardItemModel model(500,5);
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ int sbValueBefore = view.verticalScrollBar()->value();
+ QHeaderView *header = view.verticalHeader();
+ QTest::mouseMove(header);
+ QWheelEvent wheelEvent(header->geometry().center(), -720, 0, 0);
+ QApplication::sendEvent(header->viewport(), &wheelEvent);
+ int sbValueAfter = view.verticalScrollBar()->value();
+ QVERIFY(sbValueBefore != sbValueAfter);
+}
+
+class TestTableView : public QTableView {
+Q_OBJECT
+public:
+ TestTableView(QWidget *parent = 0) : QTableView(parent)
+ {
+ connect(this, SIGNAL(entered(const QModelIndex&)), this, SLOT(openEditor(const QModelIndex&)));
+ }
+ ~TestTableView(){}
+public slots:
+ void onDataChanged()
+ {
+ for (int i = 0; i < model()->rowCount(); i++) {
+ setRowHidden(i, model()->data(model()->index(i, 0)).toBool());
+ }
+ }
+
+ void openEditor(const QModelIndex& index)
+ { openPersistentEditor(index); }
+};
+
+
+void tst_QTableView::taskQTBUG_8585_crashForNoGoodReason()
+{
+ QStandardItemModel model;
+ model.insertColumn(0, QModelIndex());
+ for(int i = 0; i < 20; i++)
+ {
+ model.insertRow(i);
+ }
+
+ TestTableView w;
+ w.setMouseTracking(true);
+ w.setModel(&model);
+ connect(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), &w, SLOT(onDataChanged()));
+ w.show();
+ QTest::qWaitForWindowShown(&w);
+ for (int i = 0; i < 10; i++)
+ {
+ QTest::mouseMove(w.viewport(), QPoint(50, 20));
+ w.model()->setData(w.indexAt(QPoint(50, 20)), true);
+ QTest::mouseMove(w.viewport(), QPoint(50, 25));
+ }
+}
+
+class TableView7774 : public QTableView
+{
+public:
+ QRegion visualRegionForSelection(const QItemSelection &selection) const
+ {
+ return QTableView::visualRegionForSelection(selection);
+ }
+};
+
+void tst_QTableView::taskQTBUG_7774_RtoLVisualRegionForSelection()
+{
+ TableView7774 view;
+ QStandardItemModel model(5,5);
+ view.setModel(&model);
+ view.setLayoutDirection(Qt::RightToLeft);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ QItemSelectionRange range(model.index(2, 0), model.index(2, model.columnCount() - 1));
+ QItemSelection selection;
+ selection << range;
+ QRegion region = view.visualRegionForSelection(selection);
+ QCOMPARE(region.rects().at(0), view.visualRect(range.topLeft()) | view.visualRect(range.bottomRight()));
+}
+
+void tst_QTableView::taskQTBUG_8777_scrollToSpans()
+{
+ QTableWidget table(75,5);
+ for (int i=0; i<50; i++)
+ table.setSpan(2+i, 0, 1, 5);
+ table.setCurrentCell(0,2);
+ table.show();
+
+ for (int i = 0; i < 45; ++i)
+ QTest::keyClick(&table, Qt::Key_Down);
+
+ QVERIFY(table.verticalScrollBar()->value() > 10);
+}
+
+void tst_QTableView::taskQTBUG_10169_sizeHintForRow()
+{
+ QtTestTableView tableView;
+ QStandardItemModel model(1, 3);
+ model.setData(model.index(0, 0), "Word wrapping text goes here.");
+ tableView.setModel(&model);
+ tableView.verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
+ const int orderedHeight = tableView.sizeHintForRow(0);
+ tableView.horizontalHeader()->moveSection(2, 0);
+ const int reorderedHeight = tableView.sizeHintForRow(0);
+
+ //the order of the columns shouldn't matter.
+ QCOMPARE(orderedHeight, reorderedHeight);
+}
+
+QTEST_MAIN(tst_QTableView)
+#include "tst_qtableview.moc"
diff --git a/tests/auto/widgets/itemviews/qtablewidget/.gitignore b/tests/auto/widgets/itemviews/qtablewidget/.gitignore
new file mode 100644
index 0000000000..13a9c67c0a
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtablewidget/.gitignore
@@ -0,0 +1 @@
+tst_qtablewidget
diff --git a/tests/auto/widgets/itemviews/qtablewidget/qtablewidget.pro b/tests/auto/widgets/itemviews/qtablewidget/qtablewidget.pro
new file mode 100644
index 0000000000..eff12c83dc
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtablewidget/qtablewidget.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qtablewidget.cpp
diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp
new file mode 100644
index 0000000000..6c32caadbb
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp
@@ -0,0 +1,1500 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qeventloop.h>
+#include <qlist.h>
+#include <qpair.h>
+#include <qheaderview.h>
+
+#include <qtablewidget.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class QObjectTableItem : public QObject, public QTableWidgetItem
+{
+ Q_OBJECT
+};
+
+class tst_QTableWidget : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTableWidget();
+ ~tst_QTableWidget();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+ void getSetCheck();
+ void clear();
+ void clearContents();
+ void rowCount();
+ void columnCount();
+ void itemAssignment();
+ void item_data();
+ void item();
+ void takeItem_data();
+ void takeItem();
+ void selectedItems_data();
+ void selectedItems();
+ void removeRow_data();
+ void removeRow();
+ void removeColumn_data();
+ void removeColumn();
+ void insertRow_data();
+ void insertRow();
+ void insertColumn_data();
+ void insertColumn();
+ void itemStreaming_data();
+ void itemStreaming();
+ void itemOwnership();
+ void sortItems_data();
+ void sortItems();
+ void setItemWithSorting_data();
+ void setItemWithSorting();
+ void itemData();
+ void setItemData();
+ void cellWidget();
+ void task231094();
+ void task219380_removeLastRow();
+ void task262056_sortDuplicate();
+
+private:
+ QTableWidget *testWidget;
+};
+
+typedef QPair<int, int> IntPair;
+typedef QList<int> IntList;
+typedef QList<IntPair> IntIntList;
+
+Q_DECLARE_METATYPE(IntList)
+Q_DECLARE_METATYPE(IntIntList)
+Q_DECLARE_METATYPE(QTableWidgetSelectionRange)
+Q_DECLARE_METATYPE(QModelIndex)
+
+
+// Testing get/set functions
+void tst_QTableWidget::getSetCheck()
+{
+ QTableWidget obj1;
+ // int QTableWidget::rowCount()
+ // void QTableWidget::setRowCount(int)
+ obj1.setRowCount(0);
+ QCOMPARE(0, obj1.rowCount());
+ obj1.setRowCount(INT_MIN);
+ QCOMPARE(0, obj1.rowCount()); // Row count can never be negative
+// obj1.setRowCount(INT_MAX);
+// QCOMPARE(INT_MAX, obj1.rowCount());
+ obj1.setRowCount(100);
+ QCOMPARE(100, obj1.rowCount());
+
+
+ // int QTableWidget::columnCount()
+ // void QTableWidget::setColumnCount(int)
+ obj1.setColumnCount(0);
+ QCOMPARE(0, obj1.columnCount());
+ obj1.setColumnCount(INT_MIN);
+ QCOMPARE(0, obj1.columnCount()); // Column count can never be negative
+ obj1.setColumnCount(1000);
+ QCOMPARE(1000, obj1.columnCount());
+// obj1.setColumnCount(INT_MAX);
+// QCOMPARE(INT_MAX, obj1.columnCount());
+
+ // QTableWidgetItem * QTableWidget::currentItem()
+ // void QTableWidget::setCurrentItem(QTableWidgetItem *)
+ QTableWidgetItem *var3 = new QTableWidgetItem("0,0");
+ obj1.setItem(0, 0, var3);
+ obj1.setItem(1, 1, new QTableWidgetItem("1,1"));
+ obj1.setItem(2, 2, new QTableWidgetItem("2,2"));
+ obj1.setItem(3, 3, new QTableWidgetItem("3,3"));
+ obj1.setCurrentItem(var3);
+ QCOMPARE(var3, obj1.currentItem());
+ obj1.setCurrentItem((QTableWidgetItem *)0);
+ QCOMPARE((QTableWidgetItem *)0, obj1.currentItem());
+ obj1.setItem(0, 0, 0);
+ QCOMPARE((QTableWidgetItem *)0, obj1.item(0, 0));
+
+ // const QTableWidgetItem * QTableWidget::itemPrototype()
+ // void QTableWidget::setItemPrototype(const QTableWidgetItem *)
+ const QTableWidgetItem *var4 = new QTableWidgetItem;
+ obj1.setItemPrototype(var4);
+ QCOMPARE(var4, obj1.itemPrototype());
+ obj1.setItemPrototype((QTableWidgetItem *)0);
+ QCOMPARE((const QTableWidgetItem *)0, obj1.itemPrototype());
+}
+
+tst_QTableWidget::tst_QTableWidget(): testWidget(0)
+{
+}
+
+tst_QTableWidget::~tst_QTableWidget()
+{
+}
+
+void tst_QTableWidget::initTestCase()
+{
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+ testWidget = new QTableWidget();
+ testWidget->show();
+}
+
+void tst_QTableWidget::cleanupTestCase()
+{
+ delete testWidget;
+}
+
+void tst_QTableWidget::init()
+{
+ testWidget->clear();
+ testWidget->setRowCount(5);
+ testWidget->setColumnCount(5);
+
+ for (int row=0; row < testWidget->rowCount(); ++row)
+ testWidget->showRow(row);
+ for (int column=0; column < testWidget->columnCount(); ++column)
+ testWidget->showColumn(column);
+}
+
+void tst_QTableWidget::cleanup()
+{
+
+}
+
+void tst_QTableWidget::clearContents()
+{
+ QTableWidgetItem *item = new QTableWidgetItem("test");
+ testWidget->setHorizontalHeaderItem(0, item);
+ QVERIFY(testWidget->horizontalHeaderItem(0) == item);
+ testWidget->clearContents();
+ QVERIFY(testWidget->horizontalHeaderItem(0) == item);
+}
+
+void tst_QTableWidget::clear()
+{
+ QTableWidgetItem *item = new QTableWidgetItem("foo");
+ testWidget->setItem(0, 0, item);
+ testWidget->setItemSelected(item, true);
+
+ QVERIFY(testWidget->item(0, 0) == item);
+ QVERIFY(testWidget->isItemSelected(item));
+
+
+ QPointer<QObjectTableItem> bla = new QObjectTableItem();
+ testWidget->setItem(1, 1, bla);
+
+ testWidget->clear();
+
+ QVERIFY(bla.isNull());
+
+ QVERIFY(!testWidget->item(0,0));
+ QVERIFY(!testWidget->selectedRanges().count());
+ QVERIFY(!testWidget->selectedItems().count());
+}
+
+void tst_QTableWidget::rowCount()
+{
+ int rowCountBefore = 5;
+ int rowCountAfter = 10;
+
+ int rowCount = testWidget->rowCount();
+ QCOMPARE(rowCount, rowCountBefore);
+
+ testWidget->setRowCount(rowCountAfter);
+ rowCount = testWidget->rowCount();
+ QCOMPARE(rowCount, rowCountAfter);
+
+ QPersistentModelIndex index(testWidget->model()->index(rowCountAfter - 1, 0,
+ testWidget->rootIndex()));
+ QCOMPARE(index.row(), rowCountAfter - 1);
+ QCOMPARE(index.column(), 0);
+ QVERIFY(index.isValid());
+ testWidget->setRowCount(rowCountBefore);
+ QCOMPARE(index.row(), -1);
+ QCOMPARE(index.column(), -1);
+ QVERIFY(!index.isValid());
+
+ rowCountBefore = testWidget->rowCount();
+ testWidget->setRowCount(-1);
+ QCOMPARE(testWidget->rowCount(), rowCountBefore);
+}
+
+void tst_QTableWidget::columnCount()
+{
+ int columnCountBefore = 5;
+ int columnCountAfter = 10;
+
+ int columnCount = testWidget->columnCount();
+ QCOMPARE(columnCount, columnCountBefore);
+
+ testWidget->setColumnCount(columnCountAfter);
+ columnCount = testWidget->columnCount();
+ QCOMPARE(columnCount, columnCountAfter);
+
+ QPersistentModelIndex index(testWidget->model()->index(0, columnCountAfter - 1,
+ testWidget->rootIndex()));
+ QCOMPARE(index.row(), 0);
+ QCOMPARE(index.column(), columnCountAfter - 1);
+ QVERIFY(index.isValid());
+ testWidget->setColumnCount(columnCountBefore);
+ QCOMPARE(index.row(), -1);
+ QCOMPARE(index.column(), -1);
+ QVERIFY(!index.isValid());
+
+ columnCountBefore = testWidget->columnCount();
+ testWidget->setColumnCount(-1);
+ QCOMPARE(testWidget->columnCount(), columnCountBefore);
+}
+
+void tst_QTableWidget::itemAssignment()
+{
+ QTableWidgetItem itemInWidget("inWidget");
+ testWidget->setItem(0, 0, &itemInWidget);
+ itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsTristate);
+ QTableWidgetItem itemOutsideWidget("outsideWidget");
+
+ QVERIFY(itemInWidget.tableWidget());
+ QCOMPARE(itemInWidget.text(), QString("inWidget"));
+ QVERIFY(itemInWidget.flags() & Qt::ItemIsTristate);
+
+ QVERIFY(!itemOutsideWidget.tableWidget());
+ QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget"));
+ QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsTristate));
+
+ itemOutsideWidget = itemInWidget;
+ QVERIFY(!itemOutsideWidget.tableWidget());
+ QCOMPARE(itemOutsideWidget.text(), QString("inWidget"));
+ QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsTristate);
+}
+
+void tst_QTableWidget::item_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<bool>("expectItem");
+
+ QTest::newRow("0x0 take [0,0]") << 0 << 0 << 0 << 0 << false;
+ QTest::newRow("0x0 take [4,4]") << 0 << 0 << 4 << 4 << false;
+ QTest::newRow("4x4 take [0,0]") << 4 << 4 << 0 << 0 << true;
+ QTest::newRow("4x4 take [4,4]") << 4 << 4 << 4 << 4 << false;
+ QTest::newRow("4x4 take [2,2]") << 4 << 4 << 2 << 2 << true;
+}
+
+void tst_QTableWidget::item()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(bool, expectItem);
+
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ for (int r = 0; r < testWidget->rowCount(); ++r)
+ for (int c = 0; c < testWidget->columnCount(); ++c)
+ testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c)));
+
+ for (int r = 0; r < testWidget->rowCount(); ++r)
+ for (int c = 0; c < testWidget->columnCount(); ++c)
+ QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c));
+
+ QTableWidgetItem *item = testWidget->item(row, column);
+ QCOMPARE(!!item, expectItem);
+ if (expectItem)
+ QCOMPARE(item->text(), QString::number(row * column + column));
+}
+
+void tst_QTableWidget::takeItem_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<bool>("expectItem");
+
+ QTest::newRow("0x0 take [0,0]") << 0 << 0 << 0 << 0 << false;
+ QTest::newRow("0x0 take [4,4]") << 0 << 0 << 4 << 4 << false;
+ QTest::newRow("4x4 take [0,0]") << 4 << 4 << 0 << 0 << true;
+ QTest::newRow("4x4 take [4,4]") << 4 << 4 << 4 << 4 << false;
+ QTest::newRow("4x4 take [2,2]") << 4 << 4 << 2 << 2 << true;
+}
+
+void tst_QTableWidget::takeItem()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(bool, expectItem);
+
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ for (int r = 0; r < testWidget->rowCount(); ++r)
+ for (int c = 0; c < testWidget->columnCount(); ++c)
+ testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c)));
+
+ for (int r = 0; r < testWidget->rowCount(); ++r)
+ for (int c = 0; c < testWidget->columnCount(); ++c)
+ QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c));
+
+ QTableWidgetItem *item = testWidget->takeItem(row, column);
+ QCOMPARE(!!item, expectItem);
+ if (expectItem) {
+ QCOMPARE(item->text(), QString::number(row * column + column));
+ delete item;
+ }
+ QVERIFY(!testWidget->takeItem(row, column));
+}
+
+void tst_QTableWidget::selectedItems_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<IntIntList>("createItems");
+ QTest::addColumn<IntList>("hiddenRows");
+ QTest::addColumn<IntList>("hiddenColumns");
+ QTest::addColumn<QTableWidgetSelectionRange>("selectionRange");
+ QTest::addColumn<IntIntList>("expectedItems");
+
+ QTest::newRow("3x3 empty cells, no hidden rows/columns, none selected")
+ << 3 << 3
+ << IntIntList()
+ << IntList()
+ << IntList()
+ << QTableWidgetSelectionRange()
+ << IntIntList();
+
+ QTest::newRow("3x3 empty cells,no hidden rows/columnms, all selected")
+ << 3 << 3
+ << IntIntList()
+ << IntList()
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << IntIntList();
+
+ QTest::newRow("3x3 (1,1) exists, no hidden rows/columnms, all selected")
+ << 3 << 3
+ << (IntIntList() << IntPair(1,1))
+ << IntList()
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << (IntIntList() << IntPair(1,1));
+
+ QTest::newRow("3x3 (1,1) exists, row 1 hidden, all selected")
+ << 3 << 3
+ << (IntIntList() << IntPair(1,1))
+ << (IntList() << 1)
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << IntIntList();
+
+ QTest::newRow("3x3 (1,1) exists, column 1 hidden, all selected")
+ << 3 << 3
+ << (IntIntList() << IntPair(1,1))
+ << IntList()
+ << (IntList() << 1)
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << IntIntList();
+
+ QTest::newRow("3x3 all exists, no hidden rows/columns, all selected")
+ << 3 << 3
+ << (IntIntList()
+ << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+ << IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
+ << IntPair(2,0) << IntPair(2,1) << IntPair(2,2))
+ << IntList()
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << (IntIntList()
+ << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+ << IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
+ << IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
+
+ QTest::newRow("3x3 all exists, row 1 hidden, all selected")
+ << 3 << 3
+ << (IntIntList()
+ << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+ << IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
+ << IntPair(2,0) << IntPair(2,1) << IntPair(2,2))
+ << (IntList() << 1)
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << (IntIntList()
+ << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+ << IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
+
+ QTest::newRow("3x3 all exists, column 1 hidden, all selected")
+ << 3 << 3
+ << (IntIntList()
+ << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+ << IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
+ << IntPair(2,0) << IntPair(2,1) << IntPair(2,2))
+ << IntList()
+ << (IntList() << 1)
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << (IntIntList()
+ << IntPair(0,0) << IntPair(0,2)
+ << IntPair(1,0) << IntPair(1,2)
+ << IntPair(2,0) << IntPair(2,2));
+
+ QTest::newRow("3x3 none exists, no hidden rows/columns, all selected")
+ << 3 << 3
+ << IntIntList()
+ << IntList()
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << IntIntList();
+// << (IntIntList()
+// << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+// << IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
+// << IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
+
+ QTest::newRow("3x3 none exists, row 1 hidden, all selected, filling empty cells")
+ << 3 << 3
+ << IntIntList()
+ << (IntList() << 1)
+ << IntList()
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << IntIntList();
+// << (IntIntList()
+// << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
+// << IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
+
+ QTest::newRow("3x3 none exists, column 1 hidden, all selected")
+ << 3 << 3
+ << IntIntList()
+ << IntList()
+ << (IntList() << 1)
+ << QTableWidgetSelectionRange(0, 0, 2, 2)
+ << IntIntList();
+// << (IntIntList()
+// << IntPair(0,0) << IntPair(0,2)
+// << IntPair(1,0) << IntPair(1,2)
+// << IntPair(2,0) << IntPair(2,2));
+}
+
+void tst_QTableWidget::selectedItems()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(IntIntList, createItems);
+ QFETCH(IntList, hiddenRows);
+ QFETCH(IntList, hiddenColumns);
+ QFETCH(QTableWidgetSelectionRange, selectionRange);
+ QFETCH(IntIntList, expectedItems);
+
+ // set dimensions and test they are ok
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ // create and set items
+ foreach (IntPair intPair, createItems) {
+ testWidget->setItem(intPair.first, intPair.second,
+ new QTableWidgetItem(QString("Item %1 %2")
+ .arg(intPair.first).arg(intPair.second)));
+ }
+ // hide rows/columns
+ foreach (int row, hiddenRows)
+ testWidget->setRowHidden(row, true);
+ foreach (int column, hiddenColumns)
+ testWidget->setColumnHidden(column, true);
+
+ // make sure we don't have any previous selections hanging around
+ QVERIFY(!testWidget->selectedRanges().count());
+ QVERIFY(!testWidget->selectedItems().count());
+
+ // select range and check that it is set correctly
+ testWidget->setRangeSelected(selectionRange, true);
+ if (selectionRange.topRow() >= 0) {
+ QCOMPARE(testWidget->selectedRanges().count(), 1);
+ QCOMPARE(testWidget->selectedRanges().at(0).topRow(), selectionRange.topRow());
+ QCOMPARE(testWidget->selectedRanges().at(0).bottomRow(), selectionRange.bottomRow());
+ QCOMPARE(testWidget->selectedRanges().at(0).leftColumn(), selectionRange.leftColumn());
+ QCOMPARE(testWidget->selectedRanges().at(0).rightColumn(), selectionRange.rightColumn());
+ } else {
+ QCOMPARE(testWidget->selectedRanges().count(), 0);
+ }
+
+ // check that the correct number of items and the expected items are there
+ QList<QTableWidgetItem *> selectedItems = testWidget->selectedItems();
+ QCOMPARE(selectedItems.count(), expectedItems.count());
+ foreach (IntPair intPair, expectedItems)
+ QVERIFY(selectedItems.contains(testWidget->item(intPair.first, intPair.second)));
+
+ // check that setItemSelected agrees with selectedItems
+ for (int row = 0; row<testWidget->rowCount(); ++row) {
+ bool hidden = false;
+ foreach (int hiddenRow, hiddenRows){
+ if(hiddenRow == row){
+ hidden = true;
+ break;
+ }
+ }
+ if (hidden)
+ continue;
+
+ for (int column = 0; column<testWidget->columnCount(); ++column) {
+ foreach (int hiddenColumn, hiddenColumns){
+ if(hiddenColumn == column){
+ hidden = true;
+ break;
+ }
+ }
+ if (hidden)
+ continue;
+
+ QTableWidgetItem *item = testWidget->item(row, column);
+ if (item && testWidget->isItemSelected(item))
+ QVERIFY(selectedItems.contains(item));
+ }
+ }
+}
+
+void tst_QTableWidget::removeRow_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("expectedRowCount");
+ QTest::addColumn<int>("expectedColumnCount");
+
+ QTest::newRow("Empty") << 0 << 0 << 0 << 0 << 0;
+ QTest::newRow("1x1:0") << 1 << 1 << 0 << 0 << 1;
+ QTest::newRow("3x3:0") << 3 << 3 << 0 << 2 << 3;
+ QTest::newRow("3x3:1") << 3 << 3 << 1 << 2 << 3;
+ QTest::newRow("3x3:2") << 3 << 3 << 2 << 2 << 3;
+}
+
+void tst_QTableWidget::removeRow()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, expectedRowCount);
+ QFETCH(int, expectedColumnCount);
+
+ // set dimensions and test they are ok
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ // fill table with items
+ for (int r = 0; r < rowCount; ++r)
+ for (int c = 0; c < columnCount; ++c)
+ testWidget->setItem(r, c,
+ new QTableWidgetItem(
+ QString::number(r) + ":" + QString::number(c)));
+
+ // remove and compare the results
+ testWidget->removeRow(row);
+ QCOMPARE(testWidget->rowCount(), expectedRowCount);
+ QCOMPARE(testWidget->columnCount(), expectedColumnCount);
+
+ // check if the correct items were removed
+ for (int r = 0; r < expectedRowCount; ++r)
+ for (int c = 0; c < expectedColumnCount; ++c)
+ if (r < row)
+ QCOMPARE(testWidget->item(r, c)->text(),
+ QString::number(r) + ":" + QString::number(c));
+ else
+ QCOMPARE(testWidget->item(r, c)->text(),
+ QString::number(r + 1) + ":" + QString::number(c));
+}
+
+void tst_QTableWidget::removeColumn_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("expectedRowCount");
+ QTest::addColumn<int>("expectedColumnCount");
+
+ QTest::newRow("Empty") << 0 << 0 << 0 << 0 << 0;
+ QTest::newRow("1x1:0") << 1 << 1 << 0 << 1 << 0;
+ QTest::newRow("3x3:0") << 3 << 3 << 0 << 3 << 2;
+ QTest::newRow("3x3:1") << 3 << 3 << 1 << 3 << 2;
+ QTest::newRow("3x3:2") << 3 << 3 << 2 << 3 << 2;
+}
+
+void tst_QTableWidget::removeColumn()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, column);
+ QFETCH(int, expectedRowCount);
+ QFETCH(int, expectedColumnCount);
+
+ // set dimensions and test they are ok
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ // fill table with items
+ for (int r = 0; r < rowCount; ++r)
+ for (int c = 0; c < columnCount; ++c)
+ testWidget->setItem(r, c,
+ new QTableWidgetItem(
+ QString::number(r) + ":" + QString::number(c)));
+
+ // remove and compare the results
+ testWidget->removeColumn(column);
+ QCOMPARE(testWidget->rowCount(), expectedRowCount);
+ QCOMPARE(testWidget->columnCount(), expectedColumnCount);
+
+
+ // check if the correct items were removed
+ for (int r = 0; r < expectedRowCount; ++r)
+ for (int c = 0; c < expectedColumnCount; ++c)
+ if (c < column)
+ QCOMPARE(testWidget->item(r, c)->text(),
+ QString::number(r) + ":" + QString::number(c));
+ else
+ QCOMPARE(testWidget->item(r, c)->text(),
+ QString::number(r) + ":" + QString::number(c + 1));
+}
+
+void tst_QTableWidget::insertRow_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("expectedRowCount");
+ QTest::addColumn<int>("expectedColumnCount");
+
+ QTest::newRow("Empty") << 0 << 0 << 0 << 1 << 0;
+ QTest::newRow("1x1:0") << 1 << 1 << 0 << 2 << 1;
+ QTest::newRow("3x3:-1") << 3 << 3 << -1 << 3 << 3;
+ QTest::newRow("3x3:0") << 3 << 3 << 0 << 4 << 3;
+ QTest::newRow("3x3:1") << 3 << 3 << 1 << 4 << 3;
+ QTest::newRow("3x3:2") << 3 << 3 << 2 << 4 << 3;
+ QTest::newRow("3x3:3") << 3 << 3 << 3 << 4 << 3;
+ QTest::newRow("3x3:4") << 3 << 3 << 4 << 3 << 3;
+}
+
+void tst_QTableWidget::insertRow()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, row);
+ QFETCH(int, expectedRowCount);
+ QFETCH(int, expectedColumnCount);
+
+ // set dimensions and test they are ok
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ // insert and compare the results
+ testWidget->insertRow(row);
+ QCOMPARE(testWidget->rowCount(), expectedRowCount);
+ QCOMPARE(testWidget->columnCount(), expectedColumnCount);
+}
+
+void tst_QTableWidget::insertColumn_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("expectedRowCount");
+ QTest::addColumn<int>("expectedColumnCount");
+
+ QTest::newRow("Empty") << 0 << 0 << 0 << 0 << 1;
+ QTest::newRow("1x1:0") << 1 << 1 << 0 << 1 << 2;
+ QTest::newRow("3x3:-1") << 3 << 3 << -1 << 3 << 3;
+ QTest::newRow("3x3:0") << 3 << 3 << 0 << 3 << 4;
+ QTest::newRow("3x3:1") << 3 << 3 << 1 << 3 << 4;
+ QTest::newRow("3x3:2") << 3 << 3 << 2 << 3 << 4;
+ QTest::newRow("3x3:3") << 3 << 3 << 3 << 3 << 4;
+ QTest::newRow("3x3:4") << 3 << 3 << 4 << 3 << 3;
+}
+
+void tst_QTableWidget::insertColumn()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, column);
+ QFETCH(int, expectedRowCount);
+ QFETCH(int, expectedColumnCount);
+
+ // set dimensions and test they are ok
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+ QCOMPARE(testWidget->rowCount(), rowCount);
+ QCOMPARE(testWidget->columnCount(), columnCount);
+
+ // insert and compare the results
+ testWidget->insertColumn(column);
+ QCOMPARE(testWidget->rowCount(), expectedRowCount);
+ QCOMPARE(testWidget->columnCount(), expectedColumnCount);
+}
+
+void tst_QTableWidget::itemStreaming_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("toolTip");
+
+ QTest::newRow("Data") << "item text" << "tool tip text";
+}
+
+void tst_QTableWidget::itemStreaming()
+{
+ QFETCH(QString, text);
+ QFETCH(QString, toolTip);
+
+ QTableWidgetItem item;
+ QCOMPARE(item.text(), QString());
+ QCOMPARE(item.toolTip(), QString());
+
+ item.setText(text);
+ item.setToolTip(toolTip);
+ QCOMPARE(item.text(), text);
+ QCOMPARE(item.toolTip(), toolTip);
+
+ QByteArray buffer;
+ QDataStream out(&buffer, QIODevice::WriteOnly);
+ out << item;
+
+ QTableWidgetItem item2;
+ QCOMPARE(item2.text(), QString());
+ QCOMPARE(item2.toolTip(), QString());
+
+ QVERIFY(!buffer.isEmpty());
+
+ QDataStream in(&buffer, QIODevice::ReadOnly);
+ in >> item2;
+ QCOMPARE(item2.text(), text);
+ QCOMPARE(item2.toolTip(), toolTip);
+}
+
+void tst_QTableWidget::itemOwnership()
+{
+ QPointer<QObjectTableItem> item;
+ QPointer<QObjectTableItem> headerItem;
+
+ //delete from outside
+ item = new QObjectTableItem();
+ testWidget->setItem(0, 0, item);
+ delete item;
+ QCOMPARE(testWidget->item(0, 0), (QTableWidgetItem *)0);
+
+ //delete vertical headeritem from outside
+ headerItem = new QObjectTableItem();
+ testWidget->setVerticalHeaderItem(0, headerItem);
+ delete headerItem;
+ QCOMPARE(testWidget->verticalHeaderItem(0), (QTableWidgetItem *)0);
+
+ //delete horizontal headeritem from outside
+ headerItem = new QObjectTableItem();
+ testWidget->setHorizontalHeaderItem(0, headerItem);
+ delete headerItem;
+ QCOMPARE(testWidget->horizontalHeaderItem(0), (QTableWidgetItem *)0);
+
+ //setItem
+ item = new QObjectTableItem();
+ testWidget->setItem(0, 0, item);
+ testWidget->setItem(0, 0, new QTableWidgetItem());
+ QVERIFY(item.isNull());
+
+ //setHorizontalHeaderItem
+ headerItem = new QObjectTableItem();
+ testWidget->setHorizontalHeaderItem(0, headerItem);
+ testWidget->setHorizontalHeaderItem(0, new QTableWidgetItem());
+ QVERIFY(headerItem.isNull());
+
+ //setVerticalHeaderItem
+ headerItem = new QObjectTableItem();
+ testWidget->setVerticalHeaderItem(0, headerItem);
+ testWidget->setVerticalHeaderItem(0, new QTableWidgetItem());
+ QVERIFY(headerItem.isNull());
+
+ //takeItem
+ item = new QObjectTableItem();
+ testWidget->setItem(0, 0, item);
+ testWidget->takeItem(0, 0);
+ QVERIFY(!item.isNull());
+ delete item;
+
+ // removeRow
+ item = new QObjectTableItem();
+ headerItem = new QObjectTableItem();
+ testWidget->setItem(0, 0, item);
+ testWidget->setVerticalHeaderItem(0, headerItem);
+ testWidget->removeRow(0);
+ QVERIFY(item.isNull());
+ QVERIFY(headerItem.isNull());
+
+ // removeColumn
+ item = new QObjectTableItem();
+ headerItem = new QObjectTableItem();
+ testWidget->setItem(0, 0, item);
+ testWidget->setHorizontalHeaderItem(0, headerItem);
+ testWidget->removeColumn(0);
+ QVERIFY(item.isNull());
+ QVERIFY(headerItem.isNull());
+
+ // clear
+ item = new QObjectTableItem();
+ testWidget->setItem(0, 0, item);
+ testWidget->clear();
+ QVERIFY(item.isNull());
+}
+
+void tst_QTableWidget::sortItems_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<int>("sortColumn");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+ QTest::addColumn<IntList>("rows");
+ QTest::addColumn<IntList>("initialHidden");
+ QTest::addColumn<IntList>("expectedHidden");
+
+ QTest::newRow("ascending")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "1" << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "1" << "b" << "7" << "3" << "u"
+ << "2" << "c" << "9" << "y" << "8"
+ << "3" << "d" << "k" << "o" << "6")
+ << (IntList() << 0 << 3 << 2 << 1)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("descending")
+ << 4 << 5
+ << static_cast<int>(Qt::DescendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "1" << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "1" << "b" << "7" << "3" << "u"
+ << "0" << "a" << "o" << "8" << "k")
+ << (IntList() << 3 << 0 << 1 << 2)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("empty table")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0)
+ << (QStringList()
+ << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0)
+ << IntList()
+ << IntList()
+ << IntList();
+
+
+ QTest::newRow("half-empty table")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << 0 << 0 << 0 << 0
+ << "3" << "d" << 0 << 0 << 0
+ << "2" << "c" << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0)
+ << (QStringList()
+ << "0" << 0 << 0 << 0 << 0
+ << "2" << "c" << 0 << 0 << 0
+ << "3" << "d" << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0)
+ << (IntList() << 0 << 2 << 1)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("empty column, should not sort.")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 3
+ << (QStringList()
+ << "0" << 0 << 0 << 0 << 0
+ << "3" << "d" << 0 << 0 << 0
+ << "2" << "c" << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0)
+ << (QStringList()
+ << "0" << 0 << 0 << 0 << 0
+ << "3" << "d" << 0 << 0 << 0
+ << "2" << "c" << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0)
+ << IntList()
+ << IntList()
+ << IntList();
+
+ QTest::newRow("descending with null cell, the null cell should be placed at the bottom")
+ << 4 << 5
+ << static_cast<int>(Qt::DescendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << 0 << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "0" << "a" << "o" << "8" << "k"
+ << 0 << "b" << "7" << "3" << "u")
+ << (IntList() << 2 << 0 << 1)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("ascending with null cell, the null cell should be placed at the bottom")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << 0 << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "2" << "c" << "9" << "y" << "8"
+ << "3" << "d" << "k" << "o" << "6"
+ << 0 << "b" << "7" << "3" << "u")
+ << (IntList() << 0 << 2 << 1)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("ascending with null cells, the null cells should be placed at the bottom")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << "3" << "d" << "k" << "o" << "6"
+ << "0" << "a" << "o" << "8" << "k"
+ << 0 << "c" << "9" << "y" << "8"
+ << 0 << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << 0 << "c" << "9" << "y" << "8"
+ << 0 << "b" << "7" << "3" << "u")
+ << (IntList() << 1 << 0)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("ascending... Check a bug in PersistentIndexes")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << "3" << "c" << "9" << "y" << "8"
+ << "2" << "b" << "7" << "3" << "u"
+ << "4" << "d" << "k" << "o" << "6"
+ << "1" << "a" << "o" << "8" << "k"
+ )
+ << (QStringList()
+ << "1" << "a" << "o" << "8" << "k"
+ << "2" << "b" << "7" << "3" << "u"
+ << "3" << "c" << "9" << "y" << "8"
+ << "4" << "d" << "k" << "o" << "6"
+ )
+ << (IntList() << 2 << 1 << 3 << 0)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("ascending with some null cells inbetween")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << 0 << "a" << "o" << "8" << "k"
+ << "2" << "c" << "9" << "y" << "8"
+ << 0 << "d" << "k" << "o" << "6"
+ << "1" << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "1" << "b" << "7" << "3" << "u"
+ << "2" << "c" << "9" << "y" << "8"
+ << 0 << "a" << "o" << "8" << "k"
+ << 0 << "d" << "k" << "o" << "6")
+ << (IntList() << 1 << 0)
+ << IntList()
+ << IntList();
+
+ QTest::newRow("ascending hidden")
+ << 4 << 5
+ << static_cast<int>(Qt::AscendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "1" << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "1" << "b" << "7" << "3" << "u"
+ << "2" << "c" << "9" << "y" << "8"
+ << "3" << "d" << "k" << "o" << "6")
+ << (IntList() << 0 << 3 << 2 << 1)
+ << (IntList() << 0 << 2)
+ << (IntList() << 0 << 2);
+
+ QTest::newRow("descending hidden")
+ << 4 << 5
+ << static_cast<int>(Qt::DescendingOrder)
+ << 0
+ << (QStringList()
+ << "0" << "a" << "o" << "8" << "k"
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "1" << "b" << "7" << "3" << "u")
+ << (QStringList()
+ << "3" << "d" << "k" << "o" << "6"
+ << "2" << "c" << "9" << "y" << "8"
+ << "1" << "b" << "7" << "3" << "u"
+ << "0" << "a" << "o" << "8" << "k")
+ << (IntList() << 3 << 0 << 1 << 2)
+ << (IntList() << 0 << 2)
+ << (IntList() << 3 << 1);
+}
+
+void tst_QTableWidget::sortItems()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, sortOrder);
+ QFETCH(int, sortColumn);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ QFETCH(IntList, rows);
+ QFETCH(IntList, initialHidden);
+ QFETCH(IntList, expectedHidden);
+
+ testWidget->setRowCount(rowCount);
+ testWidget->setColumnCount(columnCount);
+
+ QAbstractItemModel *model = testWidget->model();
+ QList<QPersistentModelIndex> persistent;
+
+ int ti = 0;
+ for (int r = 0; r < rowCount; ++r) {
+ for (int c = 0; c < columnCount; ++c) {
+ QString str = initial.at(ti++);
+ if (!str.isNull()) {
+ testWidget->setItem(r, c, new QTableWidgetItem(str));
+ }
+ }
+ if (testWidget->item(r, sortColumn))
+ persistent << model->index(r, sortColumn, QModelIndex());
+ }
+
+ for (int h = 0; h < initialHidden.count(); ++h)
+ testWidget->hideRow(initialHidden.at(h));
+
+ QCOMPARE(testWidget->verticalHeader()->hiddenSectionCount(), initialHidden.count());
+
+ testWidget->sortItems(sortColumn, static_cast<Qt::SortOrder>(sortOrder));
+
+ int te = 0;
+ for (int i = 0; i < rows.count(); ++i) {
+ for (int j = 0; j < columnCount; ++j) {
+ QString value;
+ QTableWidgetItem *itm = testWidget->item(i, j);
+ if (itm) {
+ value = itm->text();
+ }
+ QCOMPARE(value, expected.at(te++));
+ }
+ QCOMPARE(persistent.at(i).row(), rows.at(i));
+ //qDebug() << "persistent" << persistent.at(i).row()
+ // << "expected" << rows.at(i);
+ }
+
+ for (int k = 0; k < expectedHidden.count(); ++k)
+ QVERIFY(testWidget->isRowHidden(expectedHidden.at(k)));
+}
+
+void tst_QTableWidget::setItemWithSorting_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<int>("sortColumn");
+ QTest::addColumn<QStringList>("initialValues");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<QString>("newValue");
+ QTest::addColumn<QStringList>("expectedValues");
+ QTest::addColumn<IntList>("expectedRows");
+ QTest::addColumn<bool>("reorderingExpected");
+
+ QTest::newRow("2x1 no change (ascending)")
+ << 2 << 1
+ << static_cast<int>(Qt::AscendingOrder) << 0
+ << (QStringList() << "0" << "1")
+ << 1 << 0 << "2"
+ << (QStringList() << "0" << "2")
+ << (IntList() << 0 << 1)
+ << false;
+ QTest::newRow("2x1 no change (descending)")
+ << 2 << 1
+ << static_cast<int>(Qt::DescendingOrder) << 0
+ << (QStringList() << "1" << "0")
+ << 0 << 0 << "2"
+ << (QStringList() << "2" << "0")
+ << (IntList() << 0 << 1)
+ << false;
+ QTest::newRow("2x1 reorder (ascending)")
+ << 2 << 1
+ << static_cast<int>(Qt::AscendingOrder) << 0
+ << (QStringList() << "0" << "1")
+ << 0 << 0 << "2"
+ << (QStringList() << "1" << "2")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("2x1 reorder (descending)")
+ << 2 << 1
+ << static_cast<int>(Qt::DescendingOrder) << 0
+ << (QStringList() << "1" << "0")
+ << 1 << 0 << "2"
+ << (QStringList() << "2" << "1")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("2x2 no change (ascending)")
+ << 2 << 2
+ << static_cast<int>(Qt::AscendingOrder) << 0
+ << (QStringList()
+ << "0" << "00"
+ << "1" << "11")
+ << 1 << 0 << "2"
+ << (QStringList()
+ << "0" << "00"
+ << "2" << "11")
+ << (IntList() << 0 << 1)
+ << false;
+ QTest::newRow("2x2 reorder (ascending)")
+ << 2 << 2
+ << static_cast<int>(Qt::AscendingOrder) << 0
+ << (QStringList()
+ << "0" << "00"
+ << "1" << "11")
+ << 0 << 0 << "2"
+ << (QStringList()
+ << "1" << "11"
+ << "2" << "00")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("2x2 reorder (ascending, sortColumn = 1)")
+ << 2 << 2
+ << static_cast<int>(Qt::AscendingOrder) << 1
+ << (QStringList()
+ << "00" << "0"
+ << "11" << "1")
+ << 0 << 1 << "2"
+ << (QStringList()
+ << "11" << "1"
+ << "00" << "2")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("2x2 no change (column != sortColumn)")
+ << 2 << 2
+ << static_cast<int>(Qt::AscendingOrder) << 1
+ << (QStringList()
+ << "00" << "0"
+ << "11" << "1")
+ << 0 << 0 << "22"
+ << (QStringList()
+ << "22" << "0"
+ << "11" << "1")
+ << (IntList() << 0 << 1)
+ << false;
+ QTest::newRow("8x4 reorder (ascending, sortColumn = 3)")
+ << 8 << 4
+ << static_cast<int>(Qt::AscendingOrder) << 3
+ << (QStringList()
+ << "q" << "v" << "u" << "0"
+ << "e" << "j" << "i" << "10"
+ << "h" << "d" << "c" << "12"
+ << "k" << "g" << "f" << "14"
+ << "w" << "y" << "x" << "2"
+ << "t" << "s" << "o" << "4"
+ << "z" << "p" << "r" << "6"
+ << "n" << "m" << "l" << "8")
+ << 2 << 3 << "5"
+ << (QStringList()
+ << "q" << "v" << "u" << "0"
+ << "e" << "j" << "i" << "10"
+ << "k" << "g" << "f" << "14"
+ << "w" << "y" << "x" << "2"
+ << "t" << "s" << "o" << "4"
+ << "h" << "d" << "c" << "5"
+ << "z" << "p" << "r" << "6"
+ << "n" << "m" << "l" << "8")
+ << (IntList() << 0 << 1 << 5 << 2 << 3 << 4 << 6 << 7)
+ << true;
+}
+
+void tst_QTableWidget::setItemWithSorting()
+{
+ QFETCH(int, rowCount);
+ QFETCH(int, columnCount);
+ QFETCH(int, sortOrder);
+ QFETCH(int, sortColumn);
+ QFETCH(QStringList, initialValues);
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(QString, newValue);
+ QFETCH(QStringList, expectedValues);
+ QFETCH(IntList, expectedRows);
+ QFETCH(bool, reorderingExpected);
+
+ for (int i = 0; i < 2; ++i) {
+ QTableWidget w(rowCount, columnCount);
+
+ QAbstractItemModel *model = w.model();
+ QList<QPersistentModelIndex> persistent;
+
+ int ti = 0;
+ for (int r = 0; r < rowCount; ++r) {
+ for (int c = 0; c < columnCount; ++c) {
+ QString str = initialValues.at(ti++);
+ w.setItem(r, c, new QTableWidgetItem(str));
+ }
+ persistent << model->index(r, sortColumn);
+ }
+
+ w.sortItems(sortColumn, static_cast<Qt::SortOrder>(sortOrder));
+ w.setSortingEnabled(true);
+
+ QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+ QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
+
+ if (i == 0) {
+ // set a new item
+ QTableWidgetItem *item = new QTableWidgetItem(newValue);
+ w.setItem(row, column, item);
+ } else {
+ // change the data of existing item
+ QTableWidgetItem *item = w.item(row, column);
+ item->setText(newValue);
+ }
+
+ ti = 0;
+ for (int r = 0; r < rowCount; ++r) {
+ for (int c = 0; c < columnCount; ++c) {
+ QString str = expectedValues.at(ti++);
+ QCOMPARE(w.item(r, c)->text(), str);
+ }
+ }
+
+ for (int k = 0; k < persistent.count(); ++k) {
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+ int i = (persistent.at(k).row() * columnCount) + sortColumn;
+ QCOMPARE(persistent.at(k).data().toString(), expectedValues.at(i));
+ }
+
+ if (i == 0)
+ QCOMPARE(dataChangedSpy.count(), reorderingExpected ? 0 : 1);
+ else
+ QCOMPARE(dataChangedSpy.count(), 1);
+
+ QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0);
+ }
+}
+
+void tst_QTableWidget::itemData()
+{
+ QTableWidget widget(2, 2);
+ widget.setItem(0, 0, new QTableWidgetItem());
+ QTableWidgetItem *item = widget.item(0, 0);
+ QVERIFY(item);
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ item->setData(Qt::DisplayRole, QString("0"));
+ item->setData(Qt::CheckStateRole, Qt::PartiallyChecked);
+ item->setData(Qt::UserRole + 0, QString("1"));
+ item->setData(Qt::UserRole + 1, QString("2"));
+ item->setData(Qt::UserRole + 2, QString("3"));
+ item->setData(Qt::UserRole + 3, QString("4"));
+ QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0));
+ QCOMPARE(flags.count(), 6);
+ QCOMPARE(flags[(Qt::UserRole + 0)].toString(), QString("1"));
+}
+
+void tst_QTableWidget::setItemData()
+{
+ QTableWidget table(10, 10);
+ table.setSortingEnabled(false);
+ QSignalSpy dataChangedSpy(table.model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)));
+
+ QTableWidgetItem *item = new QTableWidgetItem;
+ table.setItem(0, 0, item);
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QModelIndex idx = qvariant_cast<QModelIndex>(dataChangedSpy.takeFirst().at(0));
+
+ QMap<int, QVariant> data;
+ data.insert(Qt::DisplayRole, QLatin1String("Display"));
+ data.insert(Qt::ToolTipRole, QLatin1String("ToolTip"));
+ table.model()->setItemData(idx, data);
+
+ QCOMPARE(table.model()->data(idx, Qt::DisplayRole).toString(), QLatin1String("Display"));
+ QCOMPARE(table.model()->data(idx, Qt::ToolTipRole).toString(), QLatin1String("ToolTip"));
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(idx, qvariant_cast<QModelIndex>(dataChangedSpy.takeFirst().at(0)));
+
+ table.model()->setItemData(idx, data);
+ QCOMPARE(dataChangedSpy.count(), 0);
+
+ data.clear();
+ data.insert(Qt::DisplayRole, QLatin1String("dizplaye"));
+ table.model()->setItemData(idx, data);
+ QCOMPARE(table.model()->data(idx, Qt::DisplayRole).toString(), QLatin1String("dizplaye"));
+ QCOMPARE(dataChangedSpy.count(), 1);
+}
+
+void tst_QTableWidget::cellWidget()
+{
+ QTableWidget table(10, 10);
+ QWidget widget;
+
+ QCOMPARE(table.cellWidget(5, 5), static_cast<QWidget*>(0));
+ table.setCellWidget(5, 5, &widget);
+ QCOMPARE(table.cellWidget(5, 5), &widget);
+ table.removeCellWidget(5, 5);
+ QCOMPARE(table.cellWidget(5, 5), static_cast<QWidget*>(0));
+}
+
+void tst_QTableWidget::task231094()
+{
+ QTableWidget tw(5, 3);
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 5; y++) {
+ QTableWidgetItem *twi = new QTableWidgetItem(QLatin1String("1"));
+ if (y == 1)
+ twi->setFlags(Qt::ItemIsEnabled);
+ else
+ twi->setFlags(0);
+ tw.setItem(y, x, twi);
+ }
+ }
+
+ tw.setCurrentCell(1, 1);
+ QCOMPARE(tw.currentRow(), 1);
+ QCOMPARE(tw.currentColumn(), 1);
+
+ //this would provoke a end-less loop
+ QTest::keyClick(&tw, '1');
+
+ //all the items are disabled: the current item shouldn't have changed
+ QCOMPARE(tw.currentRow(), 1);
+ QCOMPARE(tw.currentColumn(), 1);
+}
+
+void tst_QTableWidget::task219380_removeLastRow()
+{
+ testWidget->setColumnCount(1);
+ testWidget->setRowCount(20);
+ QTableWidgetItem item;
+ testWidget->setItem(18, 0, &item); //we put the item in the the second last row
+ testWidget->openPersistentEditor(&item);
+
+ testWidget->scrollToBottom();
+
+ testWidget->removeRow(19); //we remove the last row
+
+ //we make sure the editor is at the cell position
+ QTRY_COMPARE(testWidget->cellWidget(18, 0)->geometry(), testWidget->visualItemRect(&item));
+}
+
+void tst_QTableWidget::task262056_sortDuplicate()
+{
+ testWidget->setColumnCount(2);
+ testWidget->setRowCount(8);
+ testWidget->setSortingEnabled(true);
+ QStringList items = (QStringList() << "AAA" << "BBB" << "CCC" << "CCC" << "DDD"\
+ << "EEE" << "FFF" << "GGG");
+ for (int i = 0; i<8; i++ ) {
+ QTableWidgetItem *twi = new QTableWidgetItem(items.at(i));
+ testWidget->setItem(i,0,twi);
+ testWidget->setItem(i,1,new QTableWidgetItem(QString("item %1").arg(i)));
+ }
+ testWidget->sortItems(0, Qt::AscendingOrder);
+ QSignalSpy layoutChangedSpy(testWidget->model(), SIGNAL(layoutChanged()));
+ testWidget->item(3,0)->setBackgroundColor(Qt::red);
+
+ QCOMPARE(layoutChangedSpy.count(),0);
+
+}
+
+
+QTEST_MAIN(tst_QTableWidget)
+#include "tst_qtablewidget.moc"
diff --git a/tests/auto/widgets/itemviews/qtreeview/.gitignore b/tests/auto/widgets/itemviews/qtreeview/.gitignore
new file mode 100644
index 0000000000..4e72cdb157
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreeview/.gitignore
@@ -0,0 +1 @@
+tst_qtreeview
diff --git a/tests/auto/widgets/itemviews/qtreeview/qtreeview.pro b/tests/auto/widgets/itemviews/qtreeview/qtreeview.pro
new file mode 100644
index 0000000000..ea53bbdc1d
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreeview/qtreeview.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qtreeview.cpp
diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
new file mode 100644
index 0000000000..d6cdf00218
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
@@ -0,0 +1,3942 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qabstractitemview.h>
+#include <QtTest/QtTest>
+#include <QtGui/QtGui>
+#include <QtWidgets/QtWidgets>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+Q_DECLARE_METATYPE(QModelIndex)
+#ifndef QT_NO_DRAGANDDROP
+Q_DECLARE_METATYPE(QAbstractItemView::DragDropMode)
+#endif
+Q_DECLARE_METATYPE(QAbstractItemView::EditTriggers)
+Q_DECLARE_METATYPE(QAbstractItemView::EditTrigger)
+
+static void initStandardTreeModel(QStandardItemModel *model)
+{
+ QStandardItem *item;
+ item = new QStandardItem(QLatin1String("Row 1 Item"));
+ model->insertRow(0, item);
+
+ item = new QStandardItem(QLatin1String("Row 2 Item"));
+ item->setCheckable(true);
+ model->insertRow(1, item);
+
+ QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
+ item->setChild(0, childItem);
+
+ item = new QStandardItem(QLatin1String("Row 3 Item"));
+ item->setIcon(QIcon());
+ model->insertRow(2, item);
+}
+
+struct PublicView : public QTreeView
+{
+ inline void executeDelayedItemsLayout()
+ { QTreeView::executeDelayedItemsLayout(); }
+
+ enum PublicCursorAction {
+ MoveUp = QAbstractItemView::MoveUp,
+ MoveDown = QAbstractItemView::MoveDown,
+ MoveLeft = QAbstractItemView::MoveLeft,
+ MoveRight = QAbstractItemView::MoveRight,
+ MoveHome = QAbstractItemView::MoveHome,
+ MoveEnd = QAbstractItemView::MoveEnd,
+ MovePageUp = QAbstractItemView::MovePageUp,
+ MovePageDown = QAbstractItemView::MovePageDown,
+ MoveNext = QAbstractItemView::MoveNext,
+ MovePrevious = QAbstractItemView::MovePrevious
+ };
+
+ inline QModelIndex moveCursor(PublicCursorAction ca, Qt::KeyboardModifiers kbm)
+ { return QTreeView::moveCursor((CursorAction)ca, kbm); }
+
+ inline void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+ {
+ QTreeView::setSelection(rect, command);
+ }
+ inline int state()
+ {
+ return QTreeView::state();
+ }
+
+ inline int rowHeight(QModelIndex idx) { return QTreeView::rowHeight(idx); }
+ inline int indexRowSizeHint(const QModelIndex &index) const { return QTreeView::indexRowSizeHint(index); }
+
+ inline QModelIndexList selectedIndexes() const { return QTreeView::selectedIndexes(); }
+
+ inline QStyleOptionViewItem viewOptions() const { return QTreeView::viewOptions(); }
+ inline int sizeHintForColumn(int column) const { return QTreeView::sizeHintForColumn(column); }
+};
+
+class tst_QTreeView : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTreeView();
+ virtual ~tst_QTreeView();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+ void selectionOrderTest();
+
+private slots:
+ void getSetCheck();
+
+ // one test per QTreeView property
+ void construction();
+ void alternatingRowColors();
+ void currentIndex_data();
+ void currentIndex();
+#ifndef QT_NO_DRAGANDDROP
+ void dragDropMode_data();
+ void dragDropMode();
+ void dragDropModeFromDragEnabledAndAcceptDrops_data();
+ void dragDropModeFromDragEnabledAndAcceptDrops();
+ void dragDropOverwriteMode();
+#endif
+ void editTriggers_data();
+ void editTriggers();
+ void hasAutoScroll();
+ void horizontalScrollMode();
+ void iconSize();
+ void indexAt();
+ void indexWidget();
+ void itemDelegate();
+ void itemDelegateForColumnOrRow();
+ void keyboardSearch();
+ void setModel();
+ void openPersistentEditor();
+ void rootIndex();
+
+ // specialized tests below
+ void setHeader();
+ void columnHidden();
+ void rowHidden();
+ void noDelegate();
+ void noModel();
+ void emptyModel();
+ void removeRows();
+ void removeCols();
+ void expandAndCollapse_data();
+ void expandAndCollapse();
+ void expandAndCollapseAll();
+ void expandWithNoChildren();
+ void keyboardNavigation();
+ void headerSections();
+ void moveCursor_data();
+ void moveCursor();
+ void setSelection_data();
+ void setSelection();
+ void extendedSelection_data();
+ void extendedSelection();
+ void indexAbove();
+ void indexBelow();
+ void clicked();
+ void mouseDoubleClick();
+ void rowsAboutToBeRemoved();
+ void headerSections_unhideSection();
+ void columnAt();
+ void scrollTo();
+ void rowsAboutToBeRemoved_move();
+ void resizeColumnToContents();
+ void insertAfterSelect();
+ void removeAfterSelect();
+ void hiddenItems();
+ void spanningItems();
+ void rowSizeHint();
+ void setSortingEnabled();
+ void headerHidden();
+
+ void selection();
+ void removeAndInsertExpandedCol0();
+ void selectionWithHiddenItems();
+ void selectAll();
+
+ void disabledButCheckable();
+ void sortByColumn_data();
+ void sortByColumn();
+
+ void evilModel_data();
+ void evilModel();
+
+ void indexRowSizeHint();
+ void addRowsWhileSectionsAreHidden();
+ void filterProxyModelCrash();
+ void styleOptionViewItem();
+ void keyboardNavigationWithDisabled();
+
+ // task-specific tests:
+ void task174627_moveLeftToRoot();
+ void task171902_expandWith1stColHidden();
+ void task203696_hidingColumnsAndRowsn();
+ void task211293_removeRootIndex();
+ void task216717_updateChildren();
+ void task220298_selectColumns();
+ void task224091_appendColumns();
+ void task225539_deleteModel();
+ void task230123_setItemsExpandable();
+ void task202039_closePersistentEditor();
+ void task238873_avoidAutoReopening();
+ void task244304_clickOnDecoration();
+ void task246536_scrollbarsNotWorking();
+ void task250683_wrongSectionSize();
+ void task239271_addRowsWithFirstColumnHidden();
+ void task254234_proxySort();
+ void task248022_changeSelection();
+ void task245654_changeModelAndExpandAll();
+ void doubleClickedWithSpans();
+ void taskQTBUG_6450_selectAllWith1stColumnHidden();
+ void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint();
+ void taskQTBUG_11466_keyboardNavigationRegression();
+ void taskQTBUG_13567_removeLastItemRegression();
+};
+
+class QtTestModel: public QAbstractItemModel
+{
+public:
+ QtTestModel(QObject *parent = 0): QAbstractItemModel(parent),
+ fetched(false), rows(0), cols(0), levels(INT_MAX), wrongIndex(false) { init(); }
+
+ QtTestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
+ fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); }
+
+ void init() {
+ decorationsEnabled = false;
+ }
+
+ inline qint32 level(const QModelIndex &index) const {
+ return index.isValid() ? qint32(index.internalId()) : qint32(-1);
+ }
+
+ bool canFetchMore(const QModelIndex &) const {
+ return !fetched;
+ }
+
+ void fetchMore(const QModelIndex &) {
+ fetched = true;
+ }
+
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const {
+ bool hasFetched = fetched;
+ fetched = true;
+ bool r = QAbstractItemModel::hasChildren(parent);
+ fetched = hasFetched;
+ return r;
+ }
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const {
+ if (!fetched)
+ qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO);
+ if ((parent.column() > 0) || (level(parent) > levels))
+ return 0;
+ return rows;
+ }
+ int columnCount(const QModelIndex& parent = QModelIndex()) const {
+ if ((parent.column() > 0) || (level(parent) > levels))
+ return 0;
+ return cols;
+ }
+
+ bool isEditable(const QModelIndex &index) const {
+ if (index.isValid())
+ return true;
+ return false;
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
+ {
+ if (row < 0 || column < 0 || (level(parent) > levels) || column >= cols || row >= rows) {
+ return QModelIndex();
+ }
+ QModelIndex i = createIndex(row, column, level(parent) + 1);
+ parentHash[i] = parent;
+ return i;
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ if (!parentHash.contains(index))
+ return QModelIndex();
+ return parentHash[index];
+ }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (!idx.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
+ wrongIndex = true;
+ qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
+ idx.internalPointer());
+ }
+ if (idx.row() & 1)
+ return QString("[%1,%2,%3] - this item is extra wide").arg(idx.row()).arg(idx.column()).arg(level(idx));
+ return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column()).arg(level(idx));
+ }
+ if (decorationsEnabled && role == Qt::DecorationRole) {
+ QPixmap pm(16,16);
+ pm.fill(QColor::fromHsv((idx.column() % 16)*8 + 64, 254, (idx.row() % 16)*8 + 32));
+ return pm;
+ }
+ return QVariant();
+ }
+
+ void removeLastRow()
+ {
+ beginRemoveRows(QModelIndex(), rows - 1, rows - 1);
+ --rows;
+ endRemoveRows();
+ }
+
+ void removeAllRows()
+ {
+ beginRemoveRows(QModelIndex(), 0, rows - 1);
+ rows = 0;
+ endRemoveRows();
+ }
+
+ void removeLastColumn()
+ {
+ beginRemoveColumns(QModelIndex(), cols - 1, cols - 1);
+ --cols;
+ endRemoveColumns();
+ }
+
+ void removeAllColumns()
+ {
+ beginRemoveColumns(QModelIndex(), 0, cols - 1);
+ cols = 0;
+ endRemoveColumns();
+ }
+
+ void insertNewRow()
+ {
+ beginInsertRows(QModelIndex(), rows - 1, rows - 1);
+ ++rows;
+ endInsertRows();
+ }
+
+ void setDecorationsEnabled(bool enable)
+ {
+ decorationsEnabled = enable;
+ }
+
+ mutable bool fetched;
+ bool decorationsEnabled;
+ int rows, cols;
+ int levels;
+ mutable bool wrongIndex;
+ mutable QMap<QModelIndex,QModelIndex> parentHash;
+};
+
+tst_QTreeView::tst_QTreeView()
+{
+}
+
+tst_QTreeView::~tst_QTreeView()
+{
+}
+
+void tst_QTreeView::initTestCase()
+{
+#ifdef Q_OS_WINCE //disable magic for WindowsCE
+ qApp->setAutoMaximizeThreshold(-1);
+#endif
+ qRegisterMetaType<QModelIndex>("QModelIndex");
+}
+
+void tst_QTreeView::cleanupTestCase()
+{
+}
+
+void tst_QTreeView::init()
+{
+}
+
+void tst_QTreeView::cleanup()
+{
+}
+
+// Testing get/set functions
+void tst_QTreeView::getSetCheck()
+{
+ QTreeView obj1;
+
+ // int QTreeView::indentation()
+ // void QTreeView::setIndentation(int)
+ QCOMPARE(obj1.indentation(), 20);
+ obj1.setIndentation(0);
+ QCOMPARE(obj1.indentation(), 0);
+ obj1.setIndentation(INT_MIN);
+ QCOMPARE(obj1.indentation(), INT_MIN);
+ obj1.setIndentation(INT_MAX);
+ QCOMPARE(obj1.indentation(), INT_MAX);
+
+ // bool QTreeView::rootIsDecorated()
+ // void QTreeView::setRootIsDecorated(bool)
+ QCOMPARE(obj1.rootIsDecorated(), true);
+ obj1.setRootIsDecorated(false);
+ QCOMPARE(obj1.rootIsDecorated(), false);
+ obj1.setRootIsDecorated(true);
+ QCOMPARE(obj1.rootIsDecorated(), true);
+
+ // bool QTreeView::uniformRowHeights()
+ // void QTreeView::setUniformRowHeights(bool)
+ QCOMPARE(obj1.uniformRowHeights(), false);
+ obj1.setUniformRowHeights(false);
+ QCOMPARE(obj1.uniformRowHeights(), false);
+ obj1.setUniformRowHeights(true);
+ QCOMPARE(obj1.uniformRowHeights(), true);
+
+ // bool QTreeView::itemsExpandable()
+ // void QTreeView::setItemsExpandable(bool)
+ QCOMPARE(obj1.itemsExpandable(), true);
+ obj1.setItemsExpandable(false);
+ QCOMPARE(obj1.itemsExpandable(), false);
+ obj1.setItemsExpandable(true);
+ QCOMPARE(obj1.itemsExpandable(), true);
+
+ // bool QTreeView::allColumnsShowFocus
+ // void QTreeView::setAllColumnsShowFocus
+ QCOMPARE(obj1.allColumnsShowFocus(), false);
+ obj1.setAllColumnsShowFocus(false);
+ QCOMPARE(obj1.allColumnsShowFocus(), false);
+ obj1.setAllColumnsShowFocus(true);
+ QCOMPARE(obj1.allColumnsShowFocus(), true);
+
+ // bool QTreeView::isAnimated
+ // void QTreeView::setAnimated
+ QCOMPARE(obj1.isAnimated(), false);
+ obj1.setAnimated(false);
+ QCOMPARE(obj1.isAnimated(), false);
+ obj1.setAnimated(true);
+ QCOMPARE(obj1.isAnimated(), true);
+
+ // bool QTreeView::setSortingEnabled
+ // void QTreeView::isSortingEnabled
+ QCOMPARE(obj1.isSortingEnabled(), false);
+ obj1.setSortingEnabled(false);
+ QCOMPARE(obj1.isSortingEnabled(), false);
+ obj1.setSortingEnabled(true);
+ QCOMPARE(obj1.isSortingEnabled(), true);
+}
+
+void tst_QTreeView::construction()
+{
+ QTreeView view;
+
+ // QAbstractItemView properties
+ QVERIFY(!view.alternatingRowColors());
+ QCOMPARE(view.currentIndex(), QModelIndex());
+#ifndef QT_NO_DRAGANDDROP
+ QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
+ QVERIFY(!view.dragDropOverwriteMode());
+ QVERIFY(!view.dragEnabled());
+#endif
+ QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked);
+ QVERIFY(view.hasAutoScroll());
+ QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
+ QCOMPARE(view.iconSize(), QSize());
+ QCOMPARE(view.indexAt(QPoint()), QModelIndex());
+ QVERIFY(!view.indexWidget(QModelIndex()));
+ QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate()));
+ QVERIFY(!view.itemDelegateForColumn(-1));
+ QVERIFY(!view.itemDelegateForColumn(0));
+ QVERIFY(!view.itemDelegateForColumn(1));
+ QVERIFY(!view.itemDelegateForRow(-1));
+ QVERIFY(!view.itemDelegateForRow(0));
+ QVERIFY(!view.itemDelegateForRow(1));
+ QVERIFY(!view.model());
+ QCOMPARE(view.rootIndex(), QModelIndex());
+ QCOMPARE(view.selectionBehavior(), QAbstractItemView::SelectRows);
+ QCOMPARE(view.selectionMode(), QAbstractItemView::SingleSelection);
+ QVERIFY(!view.selectionModel());
+#ifndef QT_NO_DRAGANDDROP
+ QVERIFY(view.showDropIndicator());
+#endif
+ QCOMPARE(view.QAbstractItemView::sizeHintForColumn(-1), -1); // <- protected in QTreeView
+ QCOMPARE(view.QAbstractItemView::sizeHintForColumn(0), -1); // <- protected in QTreeView
+ QCOMPARE(view.QAbstractItemView::sizeHintForColumn(1), -1); // <- protected in QTreeView
+ QCOMPARE(view.sizeHintForIndex(QModelIndex()), QSize());
+ QCOMPARE(view.sizeHintForRow(-1), -1);
+ QCOMPARE(view.sizeHintForRow(0), -1);
+ QCOMPARE(view.sizeHintForRow(1), -1);
+ QVERIFY(!view.tabKeyNavigation());
+ QCOMPARE(view.textElideMode(), Qt::ElideRight);
+ QCOMPARE(view.verticalScrollMode(), QAbstractItemView::ScrollPerItem);
+ QCOMPARE(view.visualRect(QModelIndex()), QRect());
+
+ // QTreeView properties
+ QVERIFY(!view.allColumnsShowFocus());
+ QCOMPARE(view.autoExpandDelay(), -1);
+ QCOMPARE(view.columnAt(-1), -1);
+ QCOMPARE(view.columnAt(0), -1);
+ QCOMPARE(view.columnAt(1), -1);
+ QCOMPARE(view.columnViewportPosition(-1), -1);
+ QCOMPARE(view.columnViewportPosition(0), -1);
+ QCOMPARE(view.columnViewportPosition(1), -1);
+ QCOMPARE(view.columnWidth(-1), 0);
+ QCOMPARE(view.columnWidth(0), 0);
+ QCOMPARE(view.columnWidth(1), 0);
+ QVERIFY(view.header());
+ QCOMPARE(view.indentation(), 20);
+ QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
+ QCOMPARE(view.indexBelow(QModelIndex()), QModelIndex());
+ QVERIFY(!view.isAnimated());
+ QVERIFY(!view.isColumnHidden(-1));
+ QVERIFY(!view.isColumnHidden(0));
+ QVERIFY(!view.isColumnHidden(1));
+ QVERIFY(!view.isExpanded(QModelIndex()));
+ QVERIFY(!view.isRowHidden(-1, QModelIndex()));
+ QVERIFY(!view.isRowHidden(0, QModelIndex()));
+ QVERIFY(!view.isRowHidden(1, QModelIndex()));
+ QVERIFY(!view.isFirstColumnSpanned(-1, QModelIndex()));
+ QVERIFY(!view.isFirstColumnSpanned(0, QModelIndex()));
+ QVERIFY(!view.isFirstColumnSpanned(1, QModelIndex()));
+ QVERIFY(!view.isSortingEnabled());
+ QVERIFY(view.itemsExpandable());
+ QVERIFY(view.rootIsDecorated());
+ QVERIFY(!view.uniformRowHeights());
+ QCOMPARE(view.visualRect(QModelIndex()), QRect());
+ QVERIFY(!view.wordWrap());
+}
+
+void tst_QTreeView::alternatingRowColors()
+{
+ QTreeView view;
+ QVERIFY(!view.alternatingRowColors());
+ view.setAlternatingRowColors(true);
+ QVERIFY(view.alternatingRowColors());
+ view.setAlternatingRowColors(false);
+ QVERIFY(!view.alternatingRowColors());
+
+ // ### Test visual effect.
+}
+
+void tst_QTreeView::currentIndex_data()
+{
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("indexRow");
+ QTest::addColumn<int>("indexColumn");
+ QTest::addColumn<int>("parentIndexRow");
+ QTest::addColumn<int>("parentIndexColumn");
+
+ QTest::newRow("-1, -1") << -1 << -1 << -1 << -1 << -1 << -1;
+ QTest::newRow("-1, 0") << -1 << 0 << -1 << -1 << -1 << -1;
+ QTest::newRow("0, -1") << 0 << -1 << -1 << -1 << -1 << -1;
+ QTest::newRow("0, 0") << 0 << 0 << 0 << 0 << -1 << -1;
+ QTest::newRow("0, 1") << 0 << 0 << 0 << 0 << -1 << -1;
+ QTest::newRow("1, 0") << 1 << 0 << 1 << 0 << -1 << -1;
+ QTest::newRow("1, 1") << 1 << 1 << -1 << -1 << -1 << -1;
+ QTest::newRow("2, 0") << 2 << 0 << 2 << 0 << -1 << -1;
+ QTest::newRow("2, 1") << 2 << 1 << -1 << -1 << -1 << -1;
+ QTest::newRow("3, -1") << 3 << -1 << -1 << -1 << -1 << -1;
+ QTest::newRow("3, 0") << 3 << 0 << -1 << -1 << -1 << -1;
+ QTest::newRow("3, 1") << 3 << 1 << -1 << -1 << -1 << -1;
+}
+
+void tst_QTreeView::currentIndex()
+{
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(int, indexRow);
+ QFETCH(int, indexColumn);
+ QFETCH(int, parentIndexRow);
+ QFETCH(int, parentIndexColumn);
+
+ QTreeView view;
+ QStandardItemModel treeModel;
+ initStandardTreeModel(&treeModel);
+ view.setModel(&treeModel);
+
+ QCOMPARE(view.currentIndex(), QModelIndex());
+ view.setCurrentIndex(view.model()->index(row, column));
+ QCOMPARE(view.currentIndex().row(), indexRow);
+ QCOMPARE(view.currentIndex().column(), indexColumn);
+ QCOMPARE(view.currentIndex().parent().row(), parentIndexRow);
+ QCOMPARE(view.currentIndex().parent().column(), parentIndexColumn);
+
+ // ### Test child and grandChild indexes.
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+void tst_QTreeView::dragDropMode_data()
+{
+ QTest::addColumn<QAbstractItemView::DragDropMode>("dragDropMode");
+ QTest::addColumn<bool>("acceptDrops");
+ QTest::addColumn<bool>("dragEnabled");
+ QTest::newRow("NoDragDrop") << QAbstractItemView::NoDragDrop << false << false;
+ QTest::newRow("DragOnly") << QAbstractItemView::DragOnly << false << true;
+ QTest::newRow("DropOnly") << QAbstractItemView::DropOnly << true << false;
+ QTest::newRow("DragDrop") << QAbstractItemView::DragDrop << true << true;
+ QTest::newRow("InternalMove") << QAbstractItemView::InternalMove << true << true;
+}
+
+void tst_QTreeView::dragDropMode()
+{
+ QFETCH(QAbstractItemView::DragDropMode, dragDropMode);
+ QFETCH(bool, acceptDrops);
+ QFETCH(bool, dragEnabled);
+
+ QTreeView view;
+ QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
+ QVERIFY(!view.acceptDrops());
+ QVERIFY(!view.dragEnabled());
+
+ view.setDragDropMode(dragDropMode);
+ QCOMPARE(view.dragDropMode(), dragDropMode);
+ QCOMPARE(view.acceptDrops(), acceptDrops);
+ QCOMPARE(view.dragEnabled(), dragEnabled);
+
+ // ### Test effects of this mode
+}
+
+void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops_data()
+{
+ QTest::addColumn<bool>("dragEnabled");
+ QTest::addColumn<bool>("acceptDrops");
+ QTest::addColumn<QAbstractItemView::DragDropMode>("dragDropMode");
+ QTest::addColumn<QAbstractItemView::DragDropMode>("setBehavior");
+
+ QTest::newRow("NoDragDrop -1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDropMode(-1);
+ QTest::newRow("NoDragDrop 0") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::NoDragDrop;
+ QTest::newRow("NoDragDrop 1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragOnly;
+ QTest::newRow("NoDragDrop 2") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DropOnly;
+ QTest::newRow("NoDragDrop 3") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDrop;
+ QTest::newRow("NoDragDrop 4") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::InternalMove;
+ QTest::newRow("DragOnly -1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDropMode(-1);
+ QTest::newRow("DragOnly 0") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::NoDragDrop;
+ QTest::newRow("DragOnly 1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragOnly;
+ QTest::newRow("DragOnly 2") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DropOnly;
+ QTest::newRow("DragOnly 3") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDrop;
+ QTest::newRow("DragOnly 4") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::InternalMove;
+ QTest::newRow("DropOnly -1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDropMode(-1);
+ QTest::newRow("DropOnly 0") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::NoDragDrop;
+ QTest::newRow("DropOnly 1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragOnly;
+ QTest::newRow("DropOnly 2") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DropOnly;
+ QTest::newRow("DropOnly 3") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDrop;
+ QTest::newRow("DropOnly 4") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::InternalMove;
+ QTest::newRow("DragDrop -1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1);
+ QTest::newRow("DragDrop 0") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1);
+ QTest::newRow("DragDrop 1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::NoDragDrop;
+ QTest::newRow("DragDrop 2") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragOnly;
+ QTest::newRow("DragDrop 3") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DropOnly;
+ QTest::newRow("DragDrop 4") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDrop;
+ QTest::newRow("DragDrop 5") << true << true << QAbstractItemView::InternalMove << QAbstractItemView::InternalMove;
+}
+
+void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops()
+{
+ QFETCH(bool, acceptDrops);
+ QFETCH(bool, dragEnabled);
+ QFETCH(QAbstractItemView::DragDropMode, dragDropMode);
+ QFETCH(QAbstractItemView::DragDropMode, setBehavior);
+
+ QTreeView view;
+ QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop);
+
+ if (setBehavior != QAbstractItemView::DragDropMode(-1))
+ view.setDragDropMode(setBehavior);
+
+ view.setAcceptDrops(acceptDrops);
+ view.setDragEnabled(dragEnabled);
+ QCOMPARE(view.dragDropMode(), dragDropMode);
+
+ // ### Test effects of this mode
+}
+
+void tst_QTreeView::dragDropOverwriteMode()
+{
+ QTreeView view;
+ QVERIFY(!view.dragDropOverwriteMode());
+ view.setDragDropOverwriteMode(true);
+ QVERIFY(view.dragDropOverwriteMode());
+ view.setDragDropOverwriteMode(false);
+ QVERIFY(!view.dragDropOverwriteMode());
+
+ // ### This property changes the behavior of dropIndicatorPosition(),
+ // which is protected and called only from within QListWidget and
+ // QTableWidget, from their reimplementations of dropMimeData(). Hard to
+ // test.
+}
+#endif
+
+void tst_QTreeView::editTriggers_data()
+{
+ QTest::addColumn<QAbstractItemView::EditTriggers>("editTriggers");
+ QTest::addColumn<QAbstractItemView::EditTrigger>("triggeredTrigger");
+ QTest::addColumn<bool>("editorOpened");
+
+ // NoEditTriggers
+ QTest::newRow("NoEditTriggers 0") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
+ << QAbstractItemView::NoEditTriggers << false;
+ QTest::newRow("NoEditTriggers 1") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
+ << QAbstractItemView::CurrentChanged << false;
+ QTest::newRow("NoEditTriggers 2") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
+ << QAbstractItemView::DoubleClicked << false;
+ QTest::newRow("NoEditTriggers 3") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
+ << QAbstractItemView::SelectedClicked << false;
+ QTest::newRow("NoEditTriggers 4") << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)
+ << QAbstractItemView::EditKeyPressed << false;
+
+ // CurrentChanged
+ QTest::newRow("CurrentChanged 0") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
+ << QAbstractItemView::NoEditTriggers << false;
+ QTest::newRow("CurrentChanged 1") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
+ << QAbstractItemView::CurrentChanged << true;
+ QTest::newRow("CurrentChanged 2") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
+ << QAbstractItemView::DoubleClicked << false;
+ QTest::newRow("CurrentChanged 3") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
+ << QAbstractItemView::SelectedClicked << false;
+ QTest::newRow("CurrentChanged 4") << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)
+ << QAbstractItemView::EditKeyPressed << false;
+
+ // DoubleClicked
+ QTest::newRow("DoubleClicked 0") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
+ << QAbstractItemView::NoEditTriggers << false;
+ QTest::newRow("DoubleClicked 1") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
+ << QAbstractItemView::CurrentChanged << false;
+ QTest::newRow("DoubleClicked 2") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
+ << QAbstractItemView::DoubleClicked << true;
+ QTest::newRow("DoubleClicked 3") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
+ << QAbstractItemView::SelectedClicked << false;
+ QTest::newRow("DoubleClicked 4") << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)
+ << QAbstractItemView::EditKeyPressed << false;
+
+ // SelectedClicked
+ QTest::newRow("SelectedClicked 0") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
+ << QAbstractItemView::NoEditTriggers << false;
+ QTest::newRow("SelectedClicked 1") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
+ << QAbstractItemView::CurrentChanged << false;
+ QTest::newRow("SelectedClicked 2") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
+ << QAbstractItemView::DoubleClicked << false;
+ QTest::newRow("SelectedClicked 3") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
+ << QAbstractItemView::SelectedClicked << true;
+ QTest::newRow("SelectedClicked 4") << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)
+ << QAbstractItemView::EditKeyPressed << false;
+
+ // EditKeyPressed
+ QTest::newRow("EditKeyPressed 0") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
+ << QAbstractItemView::NoEditTriggers << false;
+ QTest::newRow("EditKeyPressed 1") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
+ << QAbstractItemView::CurrentChanged << false;
+ QTest::newRow("EditKeyPressed 2") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
+ << QAbstractItemView::DoubleClicked << false;
+ QTest::newRow("EditKeyPressed 3") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
+ << QAbstractItemView::SelectedClicked << false;
+ QTest::newRow("EditKeyPressed 4") << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)
+ << QAbstractItemView::EditKeyPressed << true;
+}
+
+void tst_QTreeView::editTriggers()
+{
+ QFETCH(QAbstractItemView::EditTriggers, editTriggers);
+ QFETCH(QAbstractItemView::EditTrigger, triggeredTrigger);
+ QFETCH(bool, editorOpened);
+
+ QTreeView view;
+ QStandardItemModel treeModel;
+ initStandardTreeModel(&treeModel);
+ view.setModel(&treeModel);
+ view.show();
+
+ QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked);
+
+ // Initialize the first index
+ view.setCurrentIndex(view.model()->index(0, 0));
+
+ // Verify that we don't have any editor initially
+ QVERIFY(!qFindChild<QLineEdit *>(&view, QString()));
+
+ // Set the triggers
+ view.setEditTriggers(editTriggers);
+
+ // Interact with the view
+ switch (triggeredTrigger) {
+ case QAbstractItemView::NoEditTriggers:
+ // Do nothing, the editor shouldn't be there
+ break;
+ case QAbstractItemView::CurrentChanged:
+ // Change the index to open an editor
+ view.setCurrentIndex(view.model()->index(1, 0));
+ break;
+ case QAbstractItemView::DoubleClicked:
+ // Doubleclick the center of the current cell
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
+ view.visualRect(view.model()->index(0, 0)).center());
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0,
+ view.visualRect(view.model()->index(0, 0)).center());
+ break;
+ case QAbstractItemView::SelectedClicked:
+ // Click the center of the current cell
+ view.selectionModel()->select(view.model()->index(0, 0), QItemSelectionModel::Select);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
+ view.visualRect(view.model()->index(0, 0)).center());
+ QTest::qWait(int(QApplication::doubleClickInterval() * 1.5));
+ break;
+ case QAbstractItemView::EditKeyPressed:
+ view.setFocus();
+#ifdef Q_OS_MAC
+ // Mac OS X uses Enter for editing
+ QTest::keyPress(&view, Qt::Key_Enter);
+#else
+ // All other platforms use F2
+ QTest::keyPress(&view, Qt::Key_F2);
+#endif
+ break;
+ default:
+ break;
+ }
+
+ // Check if we got an editor
+ QTRY_COMPARE(qFindChild<QLineEdit *>(&view, QString()) != 0, editorOpened);
+}
+
+void tst_QTreeView::hasAutoScroll()
+{
+ QTreeView view;
+ QVERIFY(view.hasAutoScroll());
+ view.setAutoScroll(false);
+ QVERIFY(!view.hasAutoScroll());
+ view.setAutoScroll(true);
+ QVERIFY(view.hasAutoScroll());
+}
+
+void tst_QTreeView::horizontalScrollMode()
+{
+ QStandardItemModel model;
+ for (int i = 0; i < 100; ++i) {
+ model.appendRow(QList<QStandardItem *>()
+ << new QStandardItem("An item that has very long text and should"
+ " cause the horizontal scroll bar to appear.")
+ << new QStandardItem("An item that has very long text and should"
+ " cause the horizontal scroll bar to appear."));
+ }
+
+ QTreeView view;
+ view.setModel(&model);
+ view.setFixedSize(100, 100);
+ view.header()->resizeSection(0, 200);
+ view.show();
+
+ QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
+ QCOMPARE(view.horizontalScrollBar()->minimum(), 0);
+ QVERIFY(view.horizontalScrollBar()->maximum() > 2);
+
+ view.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem);
+ QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerItem);
+ QCOMPARE(view.horizontalScrollBar()->minimum(), 0);
+ QCOMPARE(view.horizontalScrollBar()->maximum(), 1);
+
+ view.setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel);
+ QCOMPARE(view.horizontalScrollBar()->minimum(), 0);
+ QVERIFY(view.horizontalScrollBar()->maximum() > 2);
+}
+
+class RepaintTreeView : public QTreeView
+{
+public:
+ RepaintTreeView() : repainted(false) { }
+ bool repainted;
+
+protected:
+ void paintEvent(QPaintEvent *event)
+ { repainted = true; QTreeView::paintEvent(event); }
+};
+
+void tst_QTreeView::iconSize()
+{
+ RepaintTreeView view;
+ QCOMPARE(view.iconSize(), QSize());
+
+ QStandardItemModel treeModel;
+ initStandardTreeModel(&treeModel);
+ view.setModel(&treeModel);
+ QCOMPARE(view.iconSize(), QSize());
+ QVERIFY(!view.repainted);
+
+ view.show();
+ view.update();
+ QTest::qWaitForWindowShown(&view);
+ QTRY_VERIFY(view.repainted);
+ QCOMPARE(view.iconSize(), QSize());
+
+ view.repainted = false;
+ view.setIconSize(QSize());
+ QTRY_VERIFY(!view.repainted);
+ QCOMPARE(view.iconSize(), QSize());
+
+ view.setIconSize(QSize(10, 10));
+ QTRY_VERIFY(view.repainted);
+ QCOMPARE(view.iconSize(), QSize(10, 10));
+
+ view.repainted = false;
+ view.setIconSize(QSize(10000, 10000));
+ QTRY_VERIFY(view.repainted);
+ QCOMPARE(view.iconSize(), QSize(10000, 10000));
+}
+
+void tst_QTreeView::indexAt()
+{
+ QtTestModel model;
+ model.rows = model.cols = 5;
+
+ QTreeView view;
+ QCOMPARE(view.indexAt(QPoint()), QModelIndex());
+ view.setModel(&model);
+ QVERIFY(view.indexAt(QPoint()) != QModelIndex());
+
+ QSize itemSize = view.visualRect(model.index(0, 0)).size();
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QPoint pos(itemSize.width() / 2, (i * itemSize.height()) + (itemSize.height() / 2));
+ QModelIndex index = view.indexAt(pos);
+ QCOMPARE(index, model.index(i, 0));
+ }
+
+ /*
+ // ### this is wrong; the widget _will_ affect the item size
+ for (int j = 0; j < model.rowCount(); ++j)
+ view.setIndexWidget(model.index(j, 0), new QPushButton);
+ */
+
+ for (int k = 0; k < model.rowCount(); ++k) {
+ QPoint pos(itemSize.width() / 2, (k * itemSize.height()) + (itemSize.height() / 2));
+ QModelIndex index = view.indexAt(pos);
+ QCOMPARE(index, model.index(k, 0));
+ }
+
+ view.show();
+ view.resize(600, 600);
+ view.header()->setStretchLastSection(false);
+ QCOMPARE(view.indexAt(QPoint(550, 20)), QModelIndex());
+}
+
+void tst_QTreeView::indexWidget()
+{
+ QTreeView view;
+ QStandardItemModel treeModel;
+ initStandardTreeModel(&treeModel);
+ view.setModel(&treeModel);
+
+ QModelIndex index = view.model()->index(0, 0);
+
+ QVERIFY(!view.indexWidget(QModelIndex()));
+ QVERIFY(!view.indexWidget(index));
+
+ QString text = QLatin1String("TestLabel");
+
+ QWidget *label = new QLabel(text);
+ view.setIndexWidget(QModelIndex(), label);
+ QVERIFY(!view.indexWidget(QModelIndex()));
+ QVERIFY(!label->parent());
+ view.setIndexWidget(index, label);
+ QCOMPARE(view.indexWidget(index), label);
+ QCOMPARE(label->parentWidget(), view.viewport());
+
+
+ QTextEdit *widget = new QTextEdit(text);
+ widget->setFixedSize(200,100);
+ view.setIndexWidget(index, widget);
+ QCOMPARE(view.indexWidget(index), static_cast<QWidget *>(widget));
+
+ QCOMPARE(widget->parentWidget(), view.viewport());
+ QCOMPARE(widget->geometry(), view.visualRect(index).intersected(widget->geometry()));
+ QCOMPARE(widget->toPlainText(), text);
+
+ //now let's try to do that later when the widget is already shown
+ view.show();
+ index = view.model()->index(1, 0);
+ QVERIFY(!view.indexWidget(index));
+
+ widget = new QTextEdit(text);
+ widget->setFixedSize(200,100);
+ view.setIndexWidget(index, widget);
+ QCOMPARE(view.indexWidget(index), static_cast<QWidget *>(widget));
+
+ QCOMPARE(widget->parentWidget(), view.viewport());
+ QCOMPARE(widget->geometry(), view.visualRect(index).intersect(widget->geometry()));
+ QCOMPARE(widget->toPlainText(), text);
+}
+
+void tst_QTreeView::itemDelegate()
+{
+ QPointer<QAbstractItemDelegate> oldDelegate;
+ QPointer<QItemDelegate> otherItemDelegate;
+
+ {
+ QTreeView view;
+ QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate()));
+ QPointer<QAbstractItemDelegate> oldDelegate = view.itemDelegate();
+
+ otherItemDelegate = new QItemDelegate;
+ view.setItemDelegate(otherItemDelegate);
+ QVERIFY(!otherItemDelegate->parent());
+ QVERIFY(oldDelegate);
+
+ QCOMPARE(view.itemDelegate(), (QAbstractItemDelegate *)otherItemDelegate);
+
+ view.setItemDelegate(0);
+ QVERIFY(!view.itemDelegate()); // <- view does its own drawing?
+ QVERIFY(otherItemDelegate);
+ }
+
+ // This is strange. Why doesn't setItemDelegate() reparent the delegate?
+ QVERIFY(!oldDelegate);
+ QVERIFY(otherItemDelegate);
+
+ delete otherItemDelegate;
+}
+
+void tst_QTreeView::itemDelegateForColumnOrRow()
+{
+ QTreeView view;
+ QAbstractItemDelegate *defaultDelegate = view.itemDelegate();
+ QVERIFY(defaultDelegate);
+
+ QVERIFY(!view.itemDelegateForRow(0));
+ QVERIFY(!view.itemDelegateForColumn(0));
+ QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate);
+
+ QStandardItemModel model;
+ for (int i = 0; i < 100; ++i) {
+ model.appendRow(QList<QStandardItem *>()
+ << new QStandardItem("An item that has very long text and should"
+ " cause the horizontal scroll bar to appear.")
+ << new QStandardItem("An item that has very long text and should"
+ " cause the horizontal scroll bar to appear.")
+ << new QStandardItem("An item that has very long text and should"
+ " cause the horizontal scroll bar to appear."));
+ }
+ view.setModel(&model);
+
+ QVERIFY(!view.itemDelegateForRow(0));
+ QVERIFY(!view.itemDelegateForColumn(0));
+ QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), defaultDelegate);
+
+ QPointer<QAbstractItemDelegate> rowDelegate = new QItemDelegate;
+ view.setItemDelegateForRow(0, rowDelegate);
+ QVERIFY(!rowDelegate->parent());
+ QCOMPARE(view.itemDelegateForRow(0), (QAbstractItemDelegate *)rowDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), (QAbstractItemDelegate *)rowDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), (QAbstractItemDelegate *)rowDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), defaultDelegate);
+
+ QPointer<QAbstractItemDelegate> columnDelegate = new QItemDelegate;
+ view.setItemDelegateForColumn(1, columnDelegate);
+ QVERIFY(!columnDelegate->parent());
+ QCOMPARE(view.itemDelegateForColumn(1), (QAbstractItemDelegate *)columnDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), (QAbstractItemDelegate *)rowDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), (QAbstractItemDelegate *)rowDelegate); // row wins
+ QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate);
+ QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), (QAbstractItemDelegate *)columnDelegate);
+
+ view.setItemDelegateForRow(0, 0);
+ QVERIFY(!view.itemDelegateForRow(0));
+ QVERIFY(rowDelegate); // <- wasn't deleted
+
+ view.setItemDelegateForColumn(1, 0);
+ QVERIFY(!view.itemDelegateForColumn(1));
+ QVERIFY(columnDelegate); // <- wasn't deleted
+
+ delete rowDelegate;
+ delete columnDelegate;
+}
+
+void tst_QTreeView::keyboardSearch()
+{
+ QTreeView view;
+ QStandardItemModel model;
+ model.appendRow(new QStandardItem("Andreas"));
+ model.appendRow(new QStandardItem("Baldrian"));
+ model.appendRow(new QStandardItem("Cecilie"));
+ view.setModel(&model);
+ view.show();
+
+ // Nothing is selected
+ QVERIFY(!view.selectionModel()->hasSelection());
+ QVERIFY(!view.selectionModel()->isSelected(model.index(0, 0)));
+
+ // First item is selected
+ view.keyboardSearch(QLatin1String("A"));
+ QTRY_VERIFY(view.selectionModel()->isSelected(model.index(0, 0)));
+
+ // First item is still selected
+ view.keyboardSearch(QLatin1String("n"));
+ QVERIFY(view.selectionModel()->isSelected(model.index(0, 0)));
+
+ // No "AnB" item - keep the same selection.
+ view.keyboardSearch(QLatin1String("B"));
+ QVERIFY(view.selectionModel()->isSelected(model.index(0, 0)));
+
+ // Wait a bit.
+ QTest::qWait(QApplication::keyboardInputInterval() * 2);
+
+ // The item that starts with B is selected.
+ view.keyboardSearch(QLatin1String("B"));
+ QVERIFY(view.selectionModel()->isSelected(model.index(1, 0)));
+}
+
+void tst_QTreeView::setModel()
+{
+ QTreeView view;
+ view.show();
+ QCOMPARE(view.model(), (QAbstractItemModel*)0);
+ QCOMPARE(view.selectionModel(), (QItemSelectionModel*)0);
+ QCOMPARE(view.header()->model(), (QAbstractItemModel*)0);
+ QCOMPARE(view.header()->selectionModel(), (QItemSelectionModel*)0);
+
+ for (int x = 0; x < 2; ++x) {
+ QtTestModel *model = new QtTestModel(10, 8);
+ QAbstractItemModel *oldModel = view.model();
+ QSignalSpy modelDestroyedSpy(oldModel ? oldModel : model, SIGNAL(destroyed()));
+ // set the same model twice
+ for (int i = 0; i < 2; ++i) {
+ QItemSelectionModel *oldSelectionModel = view.selectionModel();
+ QItemSelectionModel *dummy = new QItemSelectionModel(model);
+ QSignalSpy selectionModelDestroyedSpy(
+ oldSelectionModel ? oldSelectionModel : dummy, SIGNAL(destroyed()));
+ view.setModel(model);
+// QCOMPARE(selectionModelDestroyedSpy.count(), (x == 0 || i == 1) ? 0 : 1);
+ QCOMPARE(view.model(), (QAbstractItemModel *)model);
+ QCOMPARE(view.header()->model(), (QAbstractItemModel *)model);
+ QCOMPARE(view.selectionModel() != oldSelectionModel, (i == 0));
+ }
+ QTRY_COMPARE(modelDestroyedSpy.count(), 0);
+
+ view.setModel(0);
+ QCOMPARE(view.model(), (QAbstractItemModel*)0);
+ // ### shouldn't selectionModel also be 0 now?
+// QCOMPARE(view.selectionModel(), (QItemSelectionModel*)0);
+ delete model;
+ }
+}
+
+void tst_QTreeView::openPersistentEditor()
+{
+ QTreeView view;
+ QStandardItemModel treeModel;
+ initStandardTreeModel(&treeModel);
+ view.setModel(&treeModel);
+ view.show();
+
+ QVERIFY(!qFindChild<QLineEdit *>(view.viewport()));
+ view.openPersistentEditor(view.model()->index(0, 0));
+ QVERIFY(qFindChild<QLineEdit *>(view.viewport()));
+
+ view.closePersistentEditor(view.model()->index(0, 0));
+ QVERIFY(!qFindChild<QLineEdit *>(view.viewport())->isVisible());
+
+ qApp->sendPostedEvents(0, QEvent::DeferredDelete);
+ QVERIFY(!qFindChild<QLineEdit *>(view.viewport()));
+}
+
+void tst_QTreeView::rootIndex()
+{
+ QTreeView view;
+ QCOMPARE(view.rootIndex(), QModelIndex());
+ QStandardItemModel treeModel;
+ initStandardTreeModel(&treeModel);
+ view.setModel(&treeModel);
+ QCOMPARE(view.rootIndex(), QModelIndex());
+
+ view.setRootIndex(view.model()->index(1, 0));
+
+ QCOMPARE(view.model()->data(view.model()->index(0, view.header()->visualIndex(0), view.rootIndex()), Qt::DisplayRole)
+ .toString(), QString("Row 2 Child Item"));
+}
+
+void tst_QTreeView::setHeader()
+{
+ QTreeView view;
+ QVERIFY(view.header() != 0);
+ QCOMPARE(view.header()->orientation(), Qt::Horizontal);
+ QCOMPARE(view.header()->parent(), (QObject *)&view);
+ for (int x = 0; x < 2; ++x) {
+ QSignalSpy destroyedSpy(view.header(), SIGNAL(destroyed()));
+ Qt::Orientation orient = x ? Qt::Vertical : Qt::Horizontal;
+ QHeaderView *head = new QHeaderView(orient);
+ view.setHeader(head);
+ QCOMPARE(destroyedSpy.count(), 1);
+ QCOMPARE(head->parent(), (QObject *)&view);
+ QCOMPARE(view.header(), head);
+ view.setHeader(head);
+ QCOMPARE(view.header(), head);
+ // Itemviews in Qt < 4.2 have asserts for this. Qt >= 4.2 should handle this gracefully
+ view.setHeader((QHeaderView *)0);
+ QCOMPARE(view.header(), head);
+ }
+}
+
+void tst_QTreeView::columnHidden()
+{
+ QTreeView view;
+ QtTestModel model(10, 8);
+ view.setModel(&model);
+ view.show();
+ for (int c = 0; c < model.columnCount(); ++c)
+ QCOMPARE(view.isColumnHidden(c), false);
+ // hide even columns
+ for (int c = 0; c < model.columnCount(); c+=2)
+ view.setColumnHidden(c, true);
+ for (int c = 0; c < model.columnCount(); ++c)
+ QCOMPARE(view.isColumnHidden(c), (c & 1) == 0);
+ view.update();
+ // hide odd columns too
+ for (int c = 1; c < model.columnCount(); c+=2)
+ view.setColumnHidden(c, true);
+ for (int c = 0; c < model.columnCount(); ++c)
+ QCOMPARE(view.isColumnHidden(c), true);
+ view.update();
+}
+
+void tst_QTreeView::rowHidden()
+{
+ QtTestModel model(4, 6);
+ model.levels = 3;
+ QTreeView view;
+ view.resize(500,500);
+ view.setModel(&model);
+ view.show();
+
+ QCOMPARE(view.isRowHidden(-1, QModelIndex()), false);
+ QCOMPARE(view.isRowHidden(999999, QModelIndex()), false);
+ view.setRowHidden(-1, QModelIndex(), true);
+ view.setRowHidden(999999, QModelIndex(), true);
+ QCOMPARE(view.isRowHidden(-1, QModelIndex()), false);
+ QCOMPARE(view.isRowHidden(999999, QModelIndex()), false);
+
+ view.setRowHidden(0, QModelIndex(), true);
+ QCOMPARE(view.isRowHidden(0, QModelIndex()), true);
+ view.setRowHidden(0, QModelIndex(), false);
+ QCOMPARE(view.isRowHidden(0, QModelIndex()), false);
+
+ QStack<QModelIndex> parents;
+ parents.push(QModelIndex());
+ while (!parents.isEmpty()) {
+ QModelIndex p = parents.pop();
+ if (model.canFetchMore(p))
+ model.fetchMore(p);
+ int rows = model.rowCount(p);
+ // hide all
+ for (int r = 0; r < rows; ++r) {
+ view.setRowHidden(r, p, true);
+ QCOMPARE(view.isRowHidden(r, p), true);
+ }
+ // hide none
+ for (int r = 0; r < rows; ++r) {
+ view.setRowHidden(r, p, false);
+ QCOMPARE(view.isRowHidden(r, p), false);
+ }
+ // hide only even rows
+ for (int r = 0; r < rows; ++r) {
+ bool hide = (r & 1) == 0;
+ view.setRowHidden(r, p, hide);
+ QCOMPARE(view.isRowHidden(r, p), hide);
+ }
+ for (int r = 0; r < rows; ++r)
+ parents.push(model.index(r, 0, p));
+ }
+
+ parents.push(QModelIndex());
+ while (!parents.isEmpty()) {
+ QModelIndex p = parents.pop();
+ // all even rows should still be hidden
+ for (int r = 0; r < model.rowCount(p); ++r)
+ QCOMPARE(view.isRowHidden(r, p), (r & 1) == 0);
+ if (model.rowCount(p) > 0) {
+ for (int r = 0; r < model.rowCount(p); ++r)
+ parents.push(model.index(r, 0, p));
+ }
+ }
+}
+
+void tst_QTreeView::noDelegate()
+{
+ QtTestModel model(10, 7);
+ QTreeView view;
+ view.setModel(&model);
+ view.setItemDelegate(0);
+ QCOMPARE(view.itemDelegate(), (QAbstractItemDelegate *)0);
+}
+
+void tst_QTreeView::noModel()
+{
+ QTreeView view;
+ view.show();
+ view.setRowHidden(0, QModelIndex(), true);
+}
+
+void tst_QTreeView::emptyModel()
+{
+ QtTestModel model;
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+ QVERIFY(!model.wrongIndex);
+}
+
+void tst_QTreeView::removeRows()
+{
+ QtTestModel model(7, 10);
+
+ QTreeView view;
+
+ view.setModel(&model);
+ view.show();
+
+ model.removeLastRow();
+ QVERIFY(!model.wrongIndex);
+
+ model.removeAllRows();
+ QVERIFY(!model.wrongIndex);
+}
+
+void tst_QTreeView::removeCols()
+{
+ QtTestModel model(5, 8);
+
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+ model.fetched = true;
+ model.removeLastColumn();
+ QVERIFY(!model.wrongIndex);
+ QCOMPARE(view.header()->count(), model.cols);
+
+ model.removeAllColumns();
+ QVERIFY(!model.wrongIndex);
+ QCOMPARE(view.header()->count(), model.cols);
+}
+
+void tst_QTreeView::expandAndCollapse_data()
+{
+ QTest::addColumn<bool>("animationEnabled");
+ QTest::newRow("normal") << false;
+ QTest::newRow("animated") << true;
+
+}
+
+void tst_QTreeView::expandAndCollapse()
+{
+ QFETCH(bool, animationEnabled);
+
+ QtTestModel model(10, 9);
+
+ QTreeView view;
+ view.setUniformRowHeights(true);
+ view.setModel(&model);
+ view.setAnimated(animationEnabled);
+ view.show();
+
+ QModelIndex a = model.index(0, 0, QModelIndex());
+ QModelIndex b = model.index(0, 0, a);
+
+ QSignalSpy expandedSpy(&view, SIGNAL(expanded(const QModelIndex&)));
+ QSignalSpy collapsedSpy(&view, SIGNAL(collapsed(const QModelIndex&)));
+ QVariantList args;
+
+ for (int y = 0; y < 2; ++y) {
+ view.setVisible(y == 0);
+ for (int x = 0; x < 2; ++x) {
+ view.setItemsExpandable(x == 0);
+
+ // Test bad args
+ view.expand(QModelIndex());
+ QCOMPARE(view.isExpanded(QModelIndex()), false);
+ view.collapse(QModelIndex());
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 0);
+
+ // expand a first level item
+ QVERIFY(!view.isExpanded(a));
+ view.expand(a);
+ QVERIFY(view.isExpanded(a));
+ QCOMPARE(expandedSpy.count(), 1);
+ QCOMPARE(collapsedSpy.count(), 0);
+ args = expandedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
+
+ view.expand(a);
+ QVERIFY(view.isExpanded(a));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 0);
+
+ // expand a second level item
+ QVERIFY(!view.isExpanded(b));
+ view.expand(b);
+ QVERIFY(view.isExpanded(a));
+ QVERIFY(view.isExpanded(b));
+ QCOMPARE(expandedSpy.count(), 1);
+ QCOMPARE(collapsedSpy.count(), 0);
+ args = expandedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
+
+ view.expand(b);
+ QVERIFY(view.isExpanded(b));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 0);
+
+ // collapse the first level item
+ view.collapse(a);
+ QVERIFY(!view.isExpanded(a));
+ QVERIFY(view.isExpanded(b));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 1);
+ args = collapsedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
+
+ view.collapse(a);
+ QVERIFY(!view.isExpanded(a));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 0);
+
+ // expand the first level item again
+ view.expand(a);
+ QVERIFY(view.isExpanded(a));
+ QVERIFY(view.isExpanded(b));
+ QCOMPARE(expandedSpy.count(), 1);
+ QCOMPARE(collapsedSpy.count(), 0);
+ args = expandedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
+
+ // collapse the second level item
+ view.collapse(b);
+ QVERIFY(view.isExpanded(a));
+ QVERIFY(!view.isExpanded(b));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 1);
+ args = collapsedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
+
+ // collapse the first level item
+ view.collapse(a);
+ QVERIFY(!view.isExpanded(a));
+ QVERIFY(!view.isExpanded(b));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 1);
+ args = collapsedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
+
+ // expand and remove row
+ QPersistentModelIndex c = model.index(9, 0, b);
+ view.expand(a);
+ view.expand(b);
+ model.removeLastRow(); // remove c
+ QVERIFY(view.isExpanded(a));
+ QVERIFY(view.isExpanded(b));
+ QVERIFY(!view.isExpanded(c));
+ QCOMPARE(expandedSpy.count(), 2);
+ QCOMPARE(collapsedSpy.count(), 0);
+ args = expandedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
+ args = expandedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
+
+ view.collapse(a);
+ view.collapse(b);
+ QVERIFY(!view.isExpanded(a));
+ QVERIFY(!view.isExpanded(b));
+ QVERIFY(!view.isExpanded(c));
+ QCOMPARE(expandedSpy.count(), 0);
+ QCOMPARE(collapsedSpy.count(), 2);
+ args = collapsedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a);
+ args = collapsedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b);
+ }
+ }
+}
+
+void tst_QTreeView::expandAndCollapseAll()
+{
+ QtTestModel model(3, 2);
+ model.levels = 2;
+ QTreeView view;
+ view.setUniformRowHeights(true);
+ view.setModel(&model);
+
+ QSignalSpy expandedSpy(&view, SIGNAL(expanded(const QModelIndex&)));
+ QSignalSpy collapsedSpy(&view, SIGNAL(collapsed(const QModelIndex&)));
+
+ view.expandAll();
+ view.show();
+
+ QCOMPARE(collapsedSpy.count(), 0);
+
+ QStack<QModelIndex> parents;
+ parents.push(QModelIndex());
+ int count = 0;
+ while (!parents.isEmpty()) {
+ QModelIndex p = parents.pop();
+ int rows = model.rowCount(p);
+ for (int r = 0; r < rows; ++r)
+ QVERIFY(view.isExpanded(model.index(r, 0, p)));
+ count += rows;
+ for (int r = 0; r < rows; ++r)
+ parents.push(model.index(r, 0, p));
+ }
+// ### why is expanded() signal not emitted?
+// QCOMPARE(expandedSpy.count(), count);
+
+ view.collapseAll();
+
+ QCOMPARE(expandedSpy.count(), 0);
+
+ parents.push(QModelIndex());
+ count = 0;
+ while (!parents.isEmpty()) {
+ QModelIndex p = parents.pop();
+ int rows = model.rowCount(p);
+ for (int r = 0; r < rows; ++r)
+ QVERIFY(!view.isExpanded(model.index(r, 0, p)));
+ count += rows;
+ for (int r = 0; r < rows; ++r)
+ parents.push(model.index(r, 0, p));
+ }
+// ### why is collapsed() signal not emitted?
+// QCOMPARE(collapsedSpy.count(), count);
+}
+
+void tst_QTreeView::expandWithNoChildren()
+{
+ QTreeView tree;
+ QStandardItemModel model(1,1);
+ tree.setModel(&model);
+ tree.setAnimated(true);
+ tree.doItemsLayout();
+ //this test should not output warnings
+ tree.expand(model.index(0,0));
+}
+
+
+
+void tst_QTreeView::keyboardNavigation()
+{
+ const int rows = 10;
+ const int columns = 7;
+
+ QtTestModel model(rows, columns);
+
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+
+ QVector<Qt::Key> keymoves;
+ keymoves << Qt::Key_Down << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right
+ << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down
+ << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right
+ << Qt::Key_Left << Qt::Key_Up << Qt::Key_Left << Qt::Key_Left
+ << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up << Qt::Key_Up
+ << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up
+ << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down;
+
+ int row = 0;
+ int column = 0;
+ QModelIndex index = model.index(row, column, QModelIndex());
+ view.setCurrentIndex(index);
+ QCOMPARE(view.currentIndex(), index);
+
+ for (int i = 0; i < keymoves.size(); ++i) {
+ Qt::Key key = keymoves.at(i);
+ QTest::keyClick(&view, key);
+
+ switch (key) {
+ case Qt::Key_Up:
+ if (row > 0) {
+ index = index.sibling(row - 1, column);
+ row -= 1;
+ } else if (index.parent() != QModelIndex()) {
+ index = index.parent();
+ row = index.row();
+ }
+ break;
+ case Qt::Key_Down:
+ if (view.isExpanded(index)) {
+ row = 0;
+ index = index.child(row, column);
+ } else {
+ row = qMin(rows - 1, row + 1);
+ index = index.sibling(row, column);
+ }
+ break;
+ case Qt::Key_Left: {
+ QScrollBar *b = view.horizontalScrollBar();
+ if (b->value() == b->minimum())
+ QVERIFY(!view.isExpanded(index));
+ // windows style right will walk to the parent
+ if (view.currentIndex() != index) {
+ QCOMPARE(view.currentIndex(), index.parent());
+ index = view.currentIndex();
+ row = index.row();
+ column = index.column();
+ }
+ break;
+ }
+ case Qt::Key_Right:
+ QVERIFY(view.isExpanded(index));
+ // windows style right will walk to the first child
+ if (view.currentIndex() != index) {
+ QCOMPARE(view.currentIndex().parent(), index);
+ row = view.currentIndex().row();
+ column = view.currentIndex().column();
+ index = view.currentIndex();
+ }
+ break;
+ default:
+ QVERIFY(false);
+ }
+
+ QCOMPARE(view.currentIndex().row(), row);
+ QCOMPARE(view.currentIndex().column(), column);
+ QCOMPARE(view.currentIndex(), index);
+ }
+}
+
+class Dmodel : public QtTestModel
+{
+public:
+ Dmodel() : QtTestModel(10, 10){}
+
+ int columnCount(const QModelIndex &parent) const
+ {
+ if (parent.row() == 5)
+ return 1;
+ return QtTestModel::columnCount(parent);
+ }
+};
+
+void tst_QTreeView::headerSections()
+{
+ Dmodel model;
+
+ QTreeView view;
+ QHeaderView *header = view.header();
+
+ view.setModel(&model);
+ QModelIndex index = model.index(5, 0);
+ view.setRootIndex(index);
+ QCOMPARE(model.columnCount(QModelIndex()), 10);
+ QCOMPARE(model.columnCount(index), 1);
+ QCOMPARE(header->count(), model.columnCount(index));
+}
+
+void tst_QTreeView::moveCursor_data()
+{
+ QTest::addColumn<bool>("uniformRowHeights");
+ QTest::addColumn<bool>("scrollPerPixel");
+ QTest::newRow("uniformRowHeights = false, scrollPerPixel = false")
+ << false << false;
+ QTest::newRow("uniformRowHeights = true, scrollPerPixel = false")
+ << true << false;
+ QTest::newRow("uniformRowHeights = false, scrollPerPixel = true")
+ << false << true;
+ QTest::newRow("uniformRowHeights = true, scrollPerPixel = true")
+ << true << true;
+}
+
+void tst_QTreeView::moveCursor()
+{
+ QFETCH(bool, uniformRowHeights);
+ QFETCH(bool, scrollPerPixel);
+ QtTestModel model(8, 6);
+
+ PublicView view;
+ view.setUniformRowHeights(uniformRowHeights);
+ view.setModel(&model);
+ view.setRowHidden(0, QModelIndex(), true);
+ view.setVerticalScrollMode(scrollPerPixel ?
+ QAbstractItemView::ScrollPerPixel :
+ QAbstractItemView::ScrollPerItem);
+ QVERIFY(view.isRowHidden(0, QModelIndex()));
+ view.setColumnHidden(0, true);
+ QVERIFY(view.isColumnHidden(0));
+ view.show();
+ qApp->setActiveWindow(&view);
+
+ //here the first visible index should be selected
+ //because the view got the focus
+ QModelIndex expected = model.index(1, 1, QModelIndex());
+ QCOMPARE(view.currentIndex(), expected);
+
+ //then pressing down should go to the next line
+ QModelIndex actual = view.moveCursor(PublicView::MoveDown, Qt::NoModifier);
+ expected = model.index(2, 1, QModelIndex());
+ QCOMPARE(actual, expected);
+
+ view.setRowHidden(0, QModelIndex(), false);
+ view.setColumnHidden(0, false);
+
+ // PageUp was broken with uniform row heights turned on
+ view.setCurrentIndex(model.index(1, 0));
+ actual = view.moveCursor(PublicView::MovePageUp, Qt::NoModifier);
+ expected = model.index(0, 0, QModelIndex());
+ QCOMPARE(actual, expected);
+
+ //let's try another column
+ view.setCurrentIndex(model.index(1, 1));
+ view.setSelectionBehavior(QAbstractItemView::SelectItems);
+ QTest::keyClick(view.viewport(), Qt::Key_Up);
+ expected = model.index(0, 1, QModelIndex());
+ QCOMPARE(view.currentIndex(), expected);
+ QTest::keyClick(view.viewport(), Qt::Key_Down);
+ expected = model.index(1, 1, QModelIndex());
+ QCOMPARE(view.currentIndex(), expected);
+ QTest::keyClick(view.viewport(), Qt::Key_Up);
+ expected = model.index(0, 1, QModelIndex());
+ QCOMPARE(view.currentIndex(), expected);
+ view.setColumnHidden(0, true);
+ QTest::keyClick(view.viewport(), Qt::Key_Left);
+ expected = model.index(0, 1, QModelIndex()); //it shouldn't have changed
+ QCOMPARE(view.currentIndex(), expected);
+ view.setColumnHidden(0, false);
+ QTest::keyClick(view.viewport(), Qt::Key_Left);
+ expected = model.index(0, 0, QModelIndex());
+ QCOMPARE(view.currentIndex(), expected);
+}
+
+class TestDelegate : public QItemDelegate
+{
+public:
+ TestDelegate(QObject *parent) : QItemDelegate(parent) {}
+ QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(200, 50); }
+};
+
+typedef QList<QPoint> PointList;
+Q_DECLARE_METATYPE(PointList)
+
+void tst_QTreeView::setSelection_data()
+{
+ QTest::addColumn<QRect>("selectionRect");
+ QTest::addColumn<int>("selectionMode");
+ QTest::addColumn<int>("selectionCommand");
+ QTest::addColumn<PointList>("expectedItems");
+ QTest::addColumn<int>("verticalOffset");
+
+ QTest::newRow("(0,0,50,20),rows") << QRect(0,0,50,20)
+ << int(QAbstractItemView::SingleSelection)
+ << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
+ << (PointList()
+ << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
+ )
+ << 0;
+
+ QTest::newRow("(0,0,50,90),rows") << QRect(0,0,50,90)
+ << int(QAbstractItemView::ExtendedSelection)
+ << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
+ << (PointList()
+ << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
+ << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
+ )
+ << 0;
+
+ QTest::newRow("(50,0,0,90),rows,invalid rect") << QRect(QPoint(50, 0), QPoint(0, 90))
+ << int(QAbstractItemView::ExtendedSelection)
+ << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
+ << (PointList()
+ << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
+ << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
+ )
+ << 0;
+
+ QTest::newRow("(0,-20,20,50),rows") << QRect(0,-20,20,50)
+ << int(QAbstractItemView::ExtendedSelection)
+ << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
+ << (PointList()
+ << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
+ << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
+ )
+ << 1;
+ QTest::newRow("(0,-50,20,90),rows") << QRect(0,-50,20,90)
+ << int(QAbstractItemView::ExtendedSelection)
+ << int(QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows)
+ << (PointList()
+ << QPoint(0,0) << QPoint(1,0) << QPoint(2,0) << QPoint(3,0) << QPoint(4,0)
+ << QPoint(0,1) << QPoint(1,1) << QPoint(2,1) << QPoint(3,1) << QPoint(4,1)
+ )
+ << 1;
+
+}
+
+void tst_QTreeView::setSelection()
+{
+ QFETCH(QRect, selectionRect);
+ QFETCH(int, selectionMode);
+ QFETCH(int, selectionCommand);
+ QFETCH(PointList, expectedItems);
+ QFETCH(int, verticalOffset);
+
+ QtTestModel model(10, 5);
+ model.levels = 1;
+ model.setDecorationsEnabled(true);
+ PublicView view;
+ view.resize(400, 300);
+ view.show();
+ view.setRootIsDecorated(false);
+ view.setItemDelegate(new TestDelegate(&view));
+ view.setSelectionMode(QAbstractItemView::SelectionMode(selectionMode));
+ view.setModel(&model);
+ view.setUniformRowHeights(true);
+ view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+ view.scrollTo(model.index(verticalOffset, 0), QAbstractItemView::PositionAtTop);
+ view.setSelection(selectionRect, QItemSelectionModel::SelectionFlags(selectionCommand));
+ QItemSelectionModel *selectionModel = view.selectionModel();
+ QVERIFY(selectionModel);
+
+ QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
+ QCOMPARE(selectedIndexes.count(), expectedItems.count());
+ for (int i = 0; i < selectedIndexes.count(); ++i) {
+ QModelIndex idx = selectedIndexes.at(i);
+ QVERIFY(expectedItems.contains(QPoint(idx.column(), idx.row())));
+ }
+}
+
+void tst_QTreeView::indexAbove()
+{
+ QtTestModel model(6, 7);
+ model.levels = 2;
+ QTreeView view;
+
+ QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
+ view.setModel(&model);
+ QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex());
+
+ QStack<QModelIndex> parents;
+ parents.push(QModelIndex());
+ while (!parents.isEmpty()) {
+ QModelIndex p = parents.pop();
+ if (model.canFetchMore(p))
+ model.fetchMore(p);
+ int rows = model.rowCount(p);
+ for (int r = rows - 1; r > 0; --r) {
+ QModelIndex idx = model.index(r, 0, p);
+ QModelIndex expected = model.index(r - 1, 0, p);
+ QCOMPARE(view.indexAbove(idx), expected);
+ }
+ // hide even rows
+ for (int r = 0; r < rows; r+=2)
+ view.setRowHidden(r, p, true);
+ for (int r = rows - 1; r > 0; r-=2) {
+ QModelIndex idx = model.index(r, 0, p);
+ QModelIndex expected = model.index(r - 2, 0, p);
+ QCOMPARE(view.indexAbove(idx), expected);
+ }
+// for (int r = 0; r < rows; ++r)
+// parents.push(model.index(r, 0, p));
+ }
+}
+
+void tst_QTreeView::indexBelow()
+{
+ QtTestModel model(2, 1);
+
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex i = model.index(0, 0, view.rootIndex());
+ QVERIFY(i.isValid());
+ QCOMPARE(i.row(), 0);
+
+ i = view.indexBelow(i);
+ QVERIFY(i.isValid());
+ QCOMPARE(i.row(), 1);
+ i = view.indexBelow(i);
+ QVERIFY(!i.isValid());
+}
+
+void tst_QTreeView::clicked()
+{
+ QtTestModel model(10, 2);
+
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex firstIndex = model.index(0, 0, QModelIndex());
+ QVERIFY(firstIndex.isValid());
+ int itemHeight = view.visualRect(firstIndex).height();
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ view.resize(200, itemHeight * (model.rows + 2));
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QPoint p(itemOffset, 1 + itemHeight * i);
+ QModelIndex index = view.indexAt(p);
+ if (!index.isValid())
+ continue;
+ QSignalSpy spy(&view, SIGNAL(clicked(const QModelIndex&)));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QTRY_COMPARE(spy.count(), 1);
+ }
+}
+
+void tst_QTreeView::mouseDoubleClick()
+{
+ // Test double clicks outside the viewport.
+ // (Should be a no-op and should not expand any item.)
+
+ QStandardItemModel model(20, 2);
+ for (int i = 0; i < model.rowCount(); i++) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.insertRows(0, 20, index);
+ model.insertColumns(0,2,index);
+ for (int i1 = 0; i1 < model.rowCount(index); i1++) {
+ QModelIndex index2 = model.index(i1, 0, index);
+ }
+ }
+
+ QTreeView view;
+ view.setModel(&model);
+
+ // make sure the viewport height is smaller than the contents height.
+ view.resize(200,200);
+ view.move(0,0);
+ view.show();
+ QModelIndex index = model.index(0, 0, QModelIndex());
+ view.setCurrentIndex(index);
+
+ view.setExpanded(model.index(0,0, QModelIndex()), true);
+ view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+
+ // Make sure all items are collapsed
+ for (int i = 0; i < model.rowCount(QModelIndex()); i++) {
+ view.setExpanded(model.index(i,0, QModelIndex()), false);
+ }
+
+ int maximum = view.verticalScrollBar()->maximum();
+
+ // Doubleclick in the bottom right corner, in the unused area between the vertical and horizontal scrollbar.
+ int vsw = view.verticalScrollBar()->width();
+ int hsh = view.horizontalScrollBar()->height();
+ QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, QPoint(view.width() - vsw + 1, view.height() - hsh + 1));
+ // Should not have expanded, thus maximum() should have the same value.
+ QCOMPARE(maximum, view.verticalScrollBar()->maximum());
+
+ view.setExpandsOnDoubleClick(false);
+ QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, view.visualRect(index).center());
+ QVERIFY(!view.isExpanded(index));
+}
+
+void tst_QTreeView::rowsAboutToBeRemoved()
+{
+ QStandardItemModel model(3, 1);
+ for (int i = 0; i < model.rowCount(); i++) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, QString("%1").arg(i));
+ model.insertRows(0, 4, index);
+ model.insertColumns(0,1,index);
+ for (int i1 = 0; i1 < model.rowCount(index); i1++) {
+ QModelIndex index2 = model.index(i1, 0, index);
+ model.setData(index2, QString("%1%2").arg(i).arg(i1));
+ }
+ }
+
+ PublicView view;
+ view.setModel(&model);
+ view.show();
+ QModelIndex index = model.index(0,0, QModelIndex());
+ view.setCurrentIndex(index);
+ view.setExpanded(model.index(0,0, QModelIndex()), true);
+
+ for (int i = 0; i < model.rowCount(QModelIndex()); i++) {
+ view.setExpanded(model.index(i,0, QModelIndex()), true);
+ }
+
+ QSignalSpy spy1(&model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
+
+ model.removeRows(1,1);
+ QCOMPARE(view.state(), 0);
+ // Should not be 5 (or any other number for that sake :)
+ QCOMPARE(spy1.count(), 1);
+
+}
+
+void tst_QTreeView::headerSections_unhideSection()
+{
+ QtTestModel model(10, 7);
+
+ QTreeView view;
+
+ view.setModel(&model);
+ view.show();
+ int size = view.header()->sectionSize(0);
+ view.setColumnHidden(0, true);
+
+ // should go back to old size
+ view.setColumnHidden(0, false);
+ QCOMPARE(size, view.header()->sectionSize(0));
+}
+
+void tst_QTreeView::columnAt()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+ QTreeView view;
+ view.resize(500,500);
+ view.setModel(&model);
+
+ QCOMPARE(view.columnAt(0), 0);
+ // really this is testing the header... so not much more should be needed if the header is working...
+}
+
+void tst_QTreeView::scrollTo()
+{
+#define CHECK_VISIBLE(ROW,COL) QVERIFY(QRect(QPoint(),view.viewport()->size()).contains(\
+ view.visualRect(model.index((ROW),(COL),QModelIndex()))))
+
+ QtTestModel model;
+ model.rows = model.cols = 100;
+ QTreeView view;
+ view.setUniformRowHeights(true);
+ view.scrollTo(QModelIndex(), QTreeView::PositionAtTop);
+ view.setModel(&model);
+
+ // ### check the scrollbar values an make sure it actually scrolls to the item
+ // ### check for bot item based and pixel based scrolling
+ // ### create a data function for this test
+
+ view.scrollTo(QModelIndex());
+ view.scrollTo(model.index(0,0,QModelIndex()));
+ view.scrollTo(model.index(0,0,QModelIndex()), QTreeView::PositionAtTop);
+ view.scrollTo(model.index(0,0,QModelIndex()), QTreeView::PositionAtBottom);
+
+ //
+
+ view.show();
+ view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); //some styles change that in Polish
+
+ view.resize(300, 200);
+ //view.verticalScrollBar()->setValue(0);
+
+ view.scrollTo(model.index(0,0,QModelIndex()));
+ CHECK_VISIBLE(0,0);
+ QCOMPARE(view.verticalScrollBar()->value(), 0);
+
+ view.header()->resizeSection(0, 5); // now we only see the branches
+ view.scrollTo(model.index(5, 0, QModelIndex()), QTreeView::PositionAtTop);
+ QCOMPARE(view.verticalScrollBar()->value(), 5);
+
+ view.scrollTo(model.index(60, 60, QModelIndex()));
+
+ CHECK_VISIBLE(60,60);
+ view.scrollTo(model.index(60, 30, QModelIndex()));
+ CHECK_VISIBLE(60,30);
+ view.scrollTo(model.index(30, 30, QModelIndex()));
+ CHECK_VISIBLE(30,30);
+
+ // TODO force it to move to the left and then the right
+}
+
+void tst_QTreeView::rowsAboutToBeRemoved_move()
+{
+ QStandardItemModel model(3,1);
+ QTreeView view;
+ view.setModel(&model);
+ QModelIndex indexThatWantsToLiveButWillDieDieITellYou;
+ QModelIndex parent = model.index(2, 0 );
+ view.expand(parent);
+ for (int i = 0; i < 6; ++i) {
+ model.insertRows(0, 1, parent);
+ model.insertColumns(0, 1, parent);
+ QModelIndex index = model.index(0, 0, parent);
+ view.expand(index);
+ if ( i == 3 )
+ indexThatWantsToLiveButWillDieDieITellYou = index;
+ model.setData(index, i);
+ parent = index;
+ }
+ view.resize(600,800);
+ view.show();
+ view.doItemsLayout();
+ static_cast<PublicView *>(&view)->executeDelayedItemsLayout();
+ parent = indexThatWantsToLiveButWillDieDieITellYou.parent();
+ QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true);
+ QCOMPARE(parent.isValid(), true);
+ QCOMPARE(parent.parent().isValid(), true);
+ view.expand(parent);
+ QCOMPARE(view.isExpanded(parent), true);
+ QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true);
+ model.removeRow(0, indexThatWantsToLiveButWillDieDieITellYou);
+ QCOMPARE(view.isExpanded(parent), true);
+ QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true);
+}
+
+void tst_QTreeView::resizeColumnToContents()
+{
+ QStandardItemModel model(50,2);
+ for (int r = 0; r < model.rowCount(); ++r) {
+ for (int c = 0; c < model.columnCount(); ++c) {
+ QModelIndex idx = model.index(r, c);
+ model.setData(idx, QString::fromAscii("%1,%2").arg(r).arg(c) );
+ model.insertColumns(0, 2, idx);
+ model.insertRows(0, 6, idx);
+ for (int i = 0; i < 6; ++i) {
+ for (int j = 0; j < 2 ; ++j) {
+ model.setData(model.index(i, j, idx), QString::fromAscii("child%1%2").arg(i).arg(j));
+ }
+ }
+ }
+ }
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+ qApp->processEvents(); //must have this, or else it will not scroll
+ view.scrollToBottom();
+ view.resizeColumnToContents(0);
+ int oldColumnSize = view.header()->sectionSize(0);
+ view.setRootIndex(model.index(0, 0));
+ view.resizeColumnToContents(0); //Earlier, this gave an assert
+ QVERIFY(view.header()->sectionSize(0) > oldColumnSize);
+}
+
+void tst_QTreeView::insertAfterSelect()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+ QModelIndex firstIndex = model.index(0, 0, QModelIndex());
+ QVERIFY(firstIndex.isValid());
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ QPoint p(itemOffset, 1);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QVERIFY(view.selectionModel()->isSelected(firstIndex));
+ model.insertNewRow();
+ QVERIFY(view.selectionModel()->isSelected(firstIndex)); // Should still be selected
+}
+
+void tst_QTreeView::removeAfterSelect()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+ QModelIndex firstIndex = model.index(0, 0, QModelIndex());
+ QVERIFY(firstIndex.isValid());
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ QPoint p(itemOffset, 1);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QVERIFY(view.selectionModel()->isSelected(firstIndex));
+ model.removeLastRow();
+ QVERIFY(view.selectionModel()->isSelected(firstIndex)); // Should still be selected
+}
+
+void tst_QTreeView::hiddenItems()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+
+ QModelIndex firstIndex = model.index(1, 0, QModelIndex());
+ QVERIFY(firstIndex.isValid());
+ if (model.canFetchMore(firstIndex))
+ model.fetchMore(firstIndex);
+ for (int i=0; i < model.rowCount(firstIndex); i++)
+ view.setRowHidden(i , firstIndex, true );
+
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ int itemHeight = view.visualRect(firstIndex).height();
+ QPoint p(itemOffset, itemHeight + 1);
+ view.setExpanded(firstIndex, false);
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QCOMPARE(view.isExpanded(firstIndex), false);
+
+ p.setX( 5 );
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QCOMPARE(view.isExpanded(firstIndex), false);
+}
+
+void tst_QTreeView::spanningItems()
+{
+ QtTestModel model;
+ model.rows = model.cols = 10;
+ PublicView view;
+ view.setModel(&model);
+ view.show();
+
+ int itemWidth = view.header()->sectionSize(0);
+ int itemHeight = view.visualRect(model.index(0, 0, QModelIndex())).height();
+
+ // every second row is spanning
+ for (int i = 1; i < model.rowCount(QModelIndex()); i += 2)
+ view.setFirstColumnSpanned(i , QModelIndex(), true);
+
+ // non-spanning item
+ QPoint p(itemWidth / 2, itemHeight / 2); // column 0, row 0
+ view.setCurrentIndex(QModelIndex());
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QCOMPARE(view.currentIndex(), model.index(0, 0, QModelIndex()));
+ QCOMPARE(view.header()->sectionSize(0) - view.indentation(),
+ view.visualRect(model.index(0, 0, QModelIndex())).width());
+
+ // spanning item
+ p.setX(itemWidth + (itemWidth / 2)); // column 1
+ p.setY(itemHeight + (itemHeight / 2)); // row 1
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QCOMPARE(view.currentIndex(), model.index(1, 0, QModelIndex()));
+ QCOMPARE(view.header()->length() - view.indentation(),
+ view.visualRect(model.index(1, 0, QModelIndex())).width());
+
+ // size hint
+ // every second row is un-spanned
+ QStyleOptionViewItem option = view.viewOptions();
+ int w = view.header()->sectionSizeHint(0);
+ for (int i = 0; i < model.rowCount(QModelIndex()); ++i) {
+ if (!view.isFirstColumnSpanned(i, QModelIndex())) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ w = qMax(w, view.itemDelegate(index)->sizeHint(option, index).width() + view.indentation());
+ }
+ }
+ QCOMPARE(view.sizeHintForColumn(0), w);
+}
+
+void tst_QTreeView::selectionOrderTest()
+{
+ QVERIFY(((QItemSelectionModel*)sender())->currentIndex().row() != -1);
+}
+
+void tst_QTreeView::selection()
+{
+ QTreeView treeView;
+ QStandardItemModel m(10, 2);
+ for (int i = 0;i < 10; ++i)
+ m.setData(m.index(i, 0), i);
+ treeView.setModel(&m);
+
+ treeView.setSelectionBehavior(QAbstractItemView::SelectRows);
+ treeView.setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ connect(treeView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+ this, SLOT(selectionOrderTest()));
+
+ treeView.show();
+
+ QTest::mousePress(treeView.viewport(), Qt::LeftButton, 0, treeView.visualRect(m.index(1, 0)).center());
+ QTest::keyPress(treeView.viewport(), Qt::Key_Down);
+}
+
+//From task 151686 QTreeView ExtendedSelection selects hidden rows
+void tst_QTreeView::selectionWithHiddenItems()
+{
+ QStandardItemModel model;
+ for (int i = 0; i < model.rowCount(); ++i)
+ model.setData(model.index(i,0), QString("row %1").arg(i));
+
+ QStandardItem item0("row 0");
+ QStandardItem item1("row 1");
+ QStandardItem item2("row 2");
+ QStandardItem item3("row 3");
+ model.appendColumn( QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3);
+
+ QStandardItem child("child");
+ item1.appendRow( &child);
+
+ QTreeView view;
+ view.setModel(&model);
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view.show();
+ qApp->processEvents();
+
+ //child should not be selected as it is hidden (its parent is not expanded)
+ view.selectAll();
+ QCOMPARE(view.selectionModel()->selection().count(), 1); //one range
+ QCOMPARE(view.selectionModel()->selectedRows().count(), 4);
+ view.expandAll();
+ QVERIFY(view.isExpanded(item1.index()));
+ QCOMPARE(view.selectionModel()->selection().count(), 1);
+ QCOMPARE(view.selectionModel()->selectedRows().count(), 4);
+ QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&child)));
+ view.clearSelection();
+ QVERIFY(view.isExpanded(item1.index()));
+
+ //child should be selected as it is visible (its parent is expanded)
+ view.selectAll();
+ QCOMPARE(view.selectionModel()->selection().count(), 2);
+ QCOMPARE(view.selectionModel()->selectedRows().count(), 5); //everything is selected
+ view.clearSelection();
+
+ //we hide the node with a child (there should then be 3 items selected in 2 ranges)
+ view.setRowHidden(1, QModelIndex(), true);
+ QVERIFY(view.isExpanded(item1.index()));
+ qApp->processEvents();
+ view.selectAll();
+ QCOMPARE(view.selectionModel()->selection().count(), 2);
+ QCOMPARE(view.selectionModel()->selectedRows().count(), 3);
+ QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&item1)));
+ QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&child)));
+
+ view.setRowHidden(1, QModelIndex(), false);
+ QVERIFY(view.isExpanded(item1.index()));
+ view.clearSelection();
+
+ //we hide a node without children (there should then be 4 items selected in 3 ranges)
+ view.setRowHidden(2, QModelIndex(), true);
+ qApp->processEvents();
+ QVERIFY(view.isExpanded(item1.index()));
+ view.selectAll();
+ QVERIFY(view.isExpanded(item1.index()));
+ QCOMPARE(view.selectionModel()->selection().count(), 3);
+ QCOMPARE(view.selectionModel()->selectedRows().count(), 4);
+ QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&item2)));
+ view.setRowHidden(2, QModelIndex(), false);
+ QVERIFY(view.isExpanded(item1.index()));
+ view.clearSelection();
+}
+
+void tst_QTreeView::selectAll()
+{
+ QStandardItemModel model(4,4);
+ PublicView view2;
+ view2.setModel(&model);
+ view2.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view2.selectAll(); // Should work with an empty model
+ //everything should be selected since we are in ExtendedSelection mode
+ QCOMPARE(view2.selectedIndexes().count(), model.rowCount() * model.columnCount());
+
+ for (int i = 0; i < model.rowCount(); ++i)
+ model.setData(model.index(i,0), QString("row %1").arg(i));
+ PublicView view;
+ view.setModel(&model);
+ int selectedCount = view.selectedIndexes().count();
+ view.selectAll();
+ QCOMPARE(view.selectedIndexes().count(), selectedCount);
+}
+
+void tst_QTreeView::extendedSelection_data()
+{
+ QTest::addColumn<QPoint>("mousePressPos");
+ QTest::addColumn<int>("selectedCount");
+
+ QTest::newRow("select") << QPoint(10, 10) << 2;
+ QTest::newRow("unselect") << QPoint(10, 150) << 0;
+}
+
+void tst_QTreeView::extendedSelection()
+{
+ QFETCH(QPoint, mousePressPos);
+ QFETCH(int, selectedCount);
+
+ QStandardItemModel model(5, 2);
+ QWidget topLevel;
+ QTreeView view(&topLevel);
+ view.resize(qMax(mousePressPos.x() * 2, 200), qMax(mousePressPos.y() * 2, 200));
+ view.setModel(&model);
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ topLevel.show();
+ QTest::mousePress(view.viewport(), Qt::LeftButton, 0, mousePressPos);
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedCount);
+}
+
+void tst_QTreeView::rowSizeHint()
+{
+ //tests whether the correct visible columns are taken into account when
+ //calculating the height of a line
+ QStandardItemModel model(1,3);
+ model.setData( model.index(0,0), QSize(20,40), Qt::SizeHintRole);
+ model.setData( model.index(0,1), QSize(20,10), Qt::SizeHintRole);
+ model.setData( model.index(0,2), QSize(20,10), Qt::SizeHintRole);
+ QTreeView view;
+ view.setModel(&model);
+
+ view.header()->moveSection(1, 0); //the 2nd column goes to the 1st place
+
+ view.show();
+
+ //it must be 40 since the tallest item that defines the height of a line
+ QCOMPARE( view.visualRect(model.index(0,0)).height(), 40);
+ QCOMPARE( view.visualRect(model.index(0,1)).height(), 40);
+ QCOMPARE( view.visualRect(model.index(0,2)).height(), 40);
+}
+
+
+//From task 155449 (QTreeWidget has a large width for the first section when sorting
+//is turned on before items are added)
+void tst_QTreeView::setSortingEnabled()
+{
+ //1st the treeview is a top-level
+ {
+ QTreeView view;
+ QStandardItemModel model(1,1);
+ view.setModel(&model);
+ const int size = view.header()->sectionSize(0);
+ view.setSortingEnabled(true);
+ model.setColumnCount(3);
+ //we test that changing the column count doesn't change the 1st column size
+ QCOMPARE(view.header()->sectionSize(0), size);
+ }
+
+ //then it is no more a top-level
+ {
+ QMainWindow win;
+ QTreeView view;
+ QStandardItemModel model(1,1);
+ view.setModel(&model);
+ win.setCentralWidget(&view);
+ const int size = view.header()->sectionSize(0);
+ view.setSortingEnabled(true);
+ model.setColumnCount(3);
+ //we test that changing the column count doesn't change the 1st column size
+ QCOMPARE(view.header()->sectionSize(0), size);
+ }
+}
+
+void tst_QTreeView::headerHidden()
+{
+ QTreeView view;
+ QStandardItemModel model;
+ view.setModel(&model);
+ QCOMPARE(view.isHeaderHidden(), false);
+ QCOMPARE(view.header()->isHidden(), false);
+ view.setHeaderHidden(true);
+ QCOMPARE(view.isHeaderHidden(), true);
+ QCOMPARE(view.header()->isHidden(), true);
+}
+
+// From Task 145199 (crash when column 0 having at least one expanded item is removed and then
+// inserted). The test passes simply if it doesn't crash, hence there are no calls
+// to QCOMPARE() or QVERIFY().
+void tst_QTreeView::removeAndInsertExpandedCol0()
+{
+ QTreeView view;
+ QStandardItemModel model;
+ view.setModel(&model);
+
+ model.setColumnCount(1);
+
+ QStandardItem *item0 = new QStandardItem(QString("item 0"));
+ model.invisibleRootItem()->appendRow(item0);
+ view.expand(item0->index());
+ QStandardItem *item1 = new QStandardItem(QString("item 1"));
+ item0->appendRow(item1);
+
+ model.removeColumns(0, 1);
+ model.insertColumns(0, 1);
+
+ view.show();
+ qApp->processEvents();
+}
+
+void tst_QTreeView::disabledButCheckable()
+{
+ QTreeView view;
+ QStandardItemModel model;
+ QStandardItem *item;
+ item = new QStandardItem(QLatin1String("Row 1 Item"));
+ model.insertRow(0, item);
+
+ item = new QStandardItem(QLatin1String("Row 2 Item"));
+ item->setCheckable(true);
+ item->setEnabled(false);
+ model.insertRow(1, item);
+
+ view.setModel(&model);
+ view.setCurrentIndex(model.index(1,0));
+ QCOMPARE(item->checkState(), Qt::Unchecked);
+ view.show();
+
+ QTest::keyClick(&view, Qt::Key_Space);
+ QCOMPARE(item->checkState(), Qt::Unchecked);
+}
+
+void tst_QTreeView::sortByColumn_data()
+{
+ QTest::addColumn<bool>("sortingEnabled");
+ QTest::newRow("sorting enabled") << true;
+ QTest::newRow("sorting disabled") << false;
+}
+
+// Checks sorting and that sortByColumn also sets the sortIndicator
+void tst_QTreeView::sortByColumn()
+{
+ QFETCH(bool, sortingEnabled);
+ QTreeView view;
+ QStandardItemModel model(4,2);
+ model.setItem(0,0,new QStandardItem("b"));
+ model.setItem(1,0,new QStandardItem("d"));
+ model.setItem(2,0,new QStandardItem("c"));
+ model.setItem(3,0,new QStandardItem("a"));
+ model.setItem(0,1,new QStandardItem("e"));
+ model.setItem(1,1,new QStandardItem("g"));
+ model.setItem(2,1,new QStandardItem("h"));
+ model.setItem(3,1,new QStandardItem("f"));
+
+ view.setSortingEnabled(sortingEnabled);
+ view.setModel(&model);
+ view.sortByColumn(1);
+ QCOMPARE(view.header()->sortIndicatorSection(), 1);
+ QCOMPARE(view.model()->data(view.model()->index(0,1)).toString(), QString::fromLatin1("h"));
+ QCOMPARE(view.model()->data(view.model()->index(1,1)).toString(), QString::fromLatin1("g"));
+ view.sortByColumn(0, Qt::AscendingOrder);
+ QCOMPARE(view.header()->sortIndicatorSection(), 0);
+ QCOMPARE(view.model()->data(view.model()->index(0,0)).toString(), QString::fromLatin1("a"));
+ QCOMPARE(view.model()->data(view.model()->index(1,0)).toString(), QString::fromLatin1("b"));
+}
+
+/*
+ This is a model that every time kill() is called it will completely change
+ all of its nodes for new nodes. It then qFatal's if you later use a dead node.
+ */
+class EvilModel: public QAbstractItemModel
+{
+
+public:
+ class Node {
+ public:
+ Node(Node *p = 0, int level = 0) : parent(p), isDead(false) {
+ populate(level);
+ }
+ ~Node()
+ {
+ qDeleteAll(children.begin(), children.end());
+ qDeleteAll(deadChildren.begin(), deadChildren.end());
+ }
+
+ void populate(int level = 0) {
+ if (level < 4)
+ for (int i = 0; i < 5; ++i)
+ children.append(new Node(this, level + 1));
+ }
+ void kill() {
+ for (int i = children.count() -1; i >= 0; --i) {
+ children.at(i)->kill();
+ if (parent == 0) {
+ deadChildren.append(children.at(i));
+ children.removeAt(i);
+ }
+ }
+ if (parent == 0) {
+ if (!children.isEmpty())
+ qFatal("%s: children should be empty when parent is null", Q_FUNC_INFO);
+ populate();
+ } else {
+ isDead = true;
+ }
+ }
+
+ QList<Node*> children;
+ QList<Node*> deadChildren;
+ Node *parent;
+ bool isDead;
+ };
+
+ Node *root;
+
+ EvilModel(QObject *parent = 0): QAbstractItemModel(parent), root(new Node)
+ {
+ }
+ ~EvilModel()
+ {
+ delete root;
+ }
+
+ void change()
+ {
+ emit layoutAboutToBeChanged();
+ QModelIndexList oldList = persistentIndexList();
+ QList<QStack<int> > oldListPath;
+ for (int i = 0; i < oldList.count(); ++i) {
+ QModelIndex idx = oldList.at(i);
+ QStack<int> path;
+ while (idx.isValid()) {
+ path.push(idx.row());
+ idx = idx.parent();
+ }
+ oldListPath.append(path);
+ }
+ root->kill();
+
+ QModelIndexList newList;
+ for (int i = 0; i < oldListPath.count(); ++i) {
+ QStack<int> path = oldListPath[i];
+ QModelIndex idx;
+ while(!path.isEmpty()) {
+ idx = index(path.pop(), 0, idx);
+ }
+ newList.append(idx);
+ }
+
+ changePersistentIndexList(oldList, newList);
+ emit layoutChanged();
+ }
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const {
+ Node *parentNode = root;
+ if (parent.isValid()) {
+ parentNode = static_cast<Node*>(parent.internalPointer());
+ if (parentNode->isDead)
+ qFatal("%s: parentNode is dead!", Q_FUNC_INFO);
+ }
+ return parentNode->children.count();
+ }
+ int columnCount(const QModelIndex& parent = QModelIndex()) const {
+ if (parent.column() > 0)
+ return 0;
+ return 1;
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
+ {
+ Node *grandparentNode = static_cast<Node*>(parent.internalPointer());
+ Node *parentNode = root;
+ if (parent.isValid()) {
+ if (grandparentNode->isDead)
+ qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
+ parentNode = grandparentNode->children[parent.row()];
+ if (parentNode->isDead)
+ qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
+ }
+ return createIndex(row, column, parentNode);
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ Node *parent = static_cast<Node*>(index.internalPointer());
+ Node *grandparent = parent->parent;
+ if (!grandparent)
+ return QModelIndex();
+ return createIndex(grandparent->children.indexOf(parent), 0, grandparent);
+ }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (idx.isValid() && role == Qt::DisplayRole) {
+ Node *parentNode = root;
+ if (idx.isValid()) {
+ parentNode = static_cast<Node*>(idx.internalPointer());
+ if (parentNode->isDead)
+ qFatal("%s: grandparentNode is dead!", Q_FUNC_INFO);
+ }
+ return QString("[%1,%2,%3]").arg(idx.row()).arg(idx.column())
+ .arg(parentNode->isDead ? "dead" : "alive");
+ }
+ return QVariant();
+ }
+};
+
+void tst_QTreeView::evilModel_data()
+{
+ QTest::addColumn<bool>("visible");
+ QTest::newRow("visible") << false;
+}
+
+void tst_QTreeView::evilModel()
+{
+ QFETCH(bool, visible);
+ // init
+ PublicView view;
+ EvilModel model;
+ view.setModel(&model);
+ view.setVisible(visible);
+ QPersistentModelIndex firstLevel = model.index(0, 0);
+ QPersistentModelIndex secondLevel = model.index(1, 0, firstLevel);
+ QPersistentModelIndex thirdLevel = model.index(2, 0, secondLevel);
+ view.setExpanded(firstLevel, true);
+ view.setExpanded(secondLevel, true);
+ view.setExpanded(thirdLevel, true);
+ model.change();
+
+ // tests
+ view.setRowHidden(0, firstLevel, true);
+ model.change();
+
+ return;
+ view.setFirstColumnSpanned(1, QModelIndex(), true);
+ model.change();
+
+ view.expand(secondLevel);
+ model.change();
+
+ view.collapse(secondLevel);
+ model.change();
+
+ view.isExpanded(secondLevel);
+ view.setCurrentIndex(firstLevel);
+ model.change();
+
+ view.keyboardSearch("foo");
+ model.change();
+
+ view.visualRect(secondLevel);
+ model.change();
+
+ view.scrollTo(thirdLevel);
+ model.change();
+
+ view.repaint();
+ model.change();
+
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton);
+ model.change();
+
+ view.indexAt(QPoint(10, 10));
+ model.change();
+
+ view.indexAbove(model.index(2, 0));
+ model.change();
+
+ view.indexBelow(model.index(1, 0));
+ model.change();
+
+ QRect rect(0, 0, 10, 10);
+ view.setSelection(rect, QItemSelectionModel::Select);
+ model.change();
+
+ view.moveCursor(PublicView::MoveDown, Qt::NoModifier);
+ model.change();
+
+ view.resizeColumnToContents(1);
+ model.change();
+
+ view.QAbstractItemView::sizeHintForColumn(1);
+ model.change();
+
+ view.rowHeight(secondLevel);
+ model.change();
+
+ view.setRootIsDecorated(true);
+ model.change();
+
+ view.setItemsExpandable(false);
+ model.change();
+
+ view.columnViewportPosition(0);
+ model.change();
+
+ view.columnWidth(0);
+ model.change();
+
+ view.setColumnWidth(0, 30);
+ model.change();
+
+ view.columnAt(15);
+ model.change();
+
+ view.isColumnHidden(1);
+ model.change();
+
+ view.setColumnHidden(2, true);
+ model.change();
+
+ view.isHeaderHidden();
+ model.change();
+
+ view.setHeaderHidden(true);
+ model.change();
+
+ view.isRowHidden(2, secondLevel);
+ model.change();
+
+ view.setRowHidden(3, secondLevel, true);
+ model.change();
+
+ view.isFirstColumnSpanned(3, thirdLevel);
+ model.change();
+
+ view.setSortingEnabled(true);
+ model.change();
+
+ view.isSortingEnabled();
+ model.change();
+
+ view.setAnimated(true);
+ model.change();
+
+ view.isAnimated();
+ model.change();
+
+ view.setAllColumnsShowFocus(true);
+ model.change();
+
+ view.allColumnsShowFocus();
+ model.change();
+
+ view.doItemsLayout();
+ model.change();
+
+ view.reset();
+ model.change();
+
+ view.sortByColumn(1, Qt::AscendingOrder);
+ model.change();
+
+ view.dataChanged(secondLevel, secondLevel);
+ model.change();
+
+ view.hideColumn(1);
+ model.change();
+
+ view.showColumn(1);
+ model.change();
+
+ view.resizeColumnToContents(1);
+ model.change();
+
+ view.sortByColumn(1);
+ model.change();
+
+ view.selectAll();
+ model.change();
+
+ view.expandAll();
+ model.change();
+
+ view.collapseAll();
+ model.change();
+
+ view.expandToDepth(3);
+ model.change();
+
+ view.setRootIndex(secondLevel);
+}
+
+void tst_QTreeView::indexRowSizeHint()
+{
+ QStandardItemModel model(10, 1);
+ PublicView view;
+
+ view.setModel(&model);
+
+ QModelIndex index = model.index(5, 0);
+ QPushButton *w = new QPushButton("Test");
+ view.setIndexWidget(index, w);
+
+ view.show();
+
+ QCOMPARE(view.indexRowSizeHint(index), w->sizeHint().height());
+}
+
+void tst_QTreeView::filterProxyModelCrash()
+{
+ QStandardItemModel model;
+ QList<QStandardItem *> items;
+ for (int i = 0; i < 100; i++)
+ items << new QStandardItem(QString::fromLatin1("item %1").arg(i));
+ model.appendColumn(items);
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QTreeView view;
+ view.setModel(&proxy);
+ view.show();
+ QTest::qWait(30);
+ proxy.invalidate();
+ view.verticalScrollBar()->setValue(15);
+ QTest::qWait(20);
+
+ proxy.invalidate();
+ view.repaint(); //used to crash
+}
+
+void tst_QTreeView::styleOptionViewItem()
+{
+ class MyDelegate : public QStyledItemDelegate
+ {
+ public:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
+ {
+ QVERIFY(qstyleoption_cast<const QStyleOptionViewItemV4 *>(&option));
+ QStyleOptionViewItemV4 opt(option);
+ initStyleOption(&opt, index);
+
+ QVERIFY(!opt.text.isEmpty());
+ QCOMPARE(opt.index, index);
+ //qDebug() << index << opt.text;
+
+ if (allCollapsed)
+ QCOMPARE(!(opt.features & QStyleOptionViewItemV2::Alternate), !(index.row() % 2));
+ QCOMPARE(!(opt.features & QStyleOptionViewItemV2::HasCheckIndicator), !opt.text.contains("Checkable"));
+
+ if (opt.text.contains("Beginning"))
+ QCOMPARE(opt.viewItemPosition, QStyleOptionViewItemV4::Beginning);
+
+ if (opt.text.contains("Middle"))
+ QCOMPARE(opt.viewItemPosition, QStyleOptionViewItemV4::Middle);
+
+ if (opt.text.contains("End"))
+ QCOMPARE(opt.viewItemPosition, QStyleOptionViewItemV4::End);
+
+ if (opt.text.contains("OnlyOne"))
+ QCOMPARE(opt.viewItemPosition, QStyleOptionViewItemV4::OnlyOne);
+
+ if (opt.text.contains("Checked"))
+ QCOMPARE(opt.checkState, Qt::Checked);
+ else
+ QCOMPARE(opt.checkState, Qt::Unchecked);
+
+ QCOMPARE(!(opt.state & QStyle::State_Children) , !opt.text.contains("HasChildren"));
+ QCOMPARE(!!(opt.state & QStyle::State_Sibling) , !opt.text.contains("Last"));
+
+ QVERIFY(!opt.text.contains("Assert"));
+
+ QStyledItemDelegate::paint(painter, option, index);
+ count++;
+ }
+ mutable int count;
+ bool allCollapsed;
+ };
+
+ QTreeView view;
+ QStandardItemModel model;
+ view.setModel(&model);
+ MyDelegate delegate;
+ view.setItemDelegate(&delegate);
+ model.appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Beginning") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
+ QStandardItem *par1 = new QStandardItem("Beginning HasChildren");
+ model.appendRow(QList<QStandardItem*>()
+ << par1 << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") );
+ model.appendRow(QList<QStandardItem*>()
+ << new QStandardItem("OnlyOne") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Assert") );
+ QStandardItem *checkable = new QStandardItem("Checkable");
+ checkable->setCheckable(true);
+ QStandardItem *checked = new QStandardItem("Checkable Checked");
+ checkable->setCheckable(true);
+ checked->setCheckState(Qt::Checked);
+ model.appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Beginning") << checkable << checked << new QStandardItem("End") );
+ model.appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Beginning Last") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
+
+ par1->appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Beginning") << new QStandardItem("Middle") << new QStandardItem("Middle") << new QStandardItem("End") );
+ QStandardItem *par2 = new QStandardItem("Beginning HasChildren");
+ par1->appendRow(QList<QStandardItem*>()
+ << par2 << new QStandardItem("Middle HasChildren") << new QStandardItem("Middle HasChildren") << new QStandardItem("End HasChildren") );
+ par2->appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Beginning Last") << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
+
+ QStandardItem *par3 = new QStandardItem("Beginning Last");
+ par1->appendRow(QList<QStandardItem*>()
+ << par3 << new QStandardItem("Middle Last") << new QStandardItem("Middle Last") << new QStandardItem("End Last") );
+ par3->appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") );
+ view.setRowHidden(0, par3->index(), true);
+ par1->appendRow(QList<QStandardItem*>()
+ << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Assert") << new QStandardItem("Asser") );
+ view.setRowHidden(3, par1->index(), true);
+
+
+ view.setFirstColumnSpanned(2, QModelIndex(), true);
+ view.setAlternatingRowColors(true);
+
+ delegate.count = 0;
+ delegate.allCollapsed = true;
+ view.showMaximized();
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 13);
+ delegate.count = 0;
+ delegate.allCollapsed = false;
+ view.expandAll();
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 13);
+ delegate.count = 0;
+ view.collapse(par2->index());
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 4);
+
+
+ //test dynamic models
+ {
+ delegate.count = 0;
+ QStandardItemModel model2;
+ QStandardItem *item0 = new QStandardItem("OnlyOne Last");
+ model2.appendRow(QList<QStandardItem*>() << item0);
+ view.setModel(&model2);
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 1);
+ QApplication::processEvents();
+
+ QStandardItem *item00 = new QStandardItem("OnlyOne Last");
+ item0->appendRow(QList<QStandardItem*>() << item00);
+ item0->setText("OnlyOne Last HasChildren");
+ QApplication::processEvents();
+ delegate.count = 0;
+ view.expandAll();
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 2);
+ QApplication::processEvents();
+
+ QStandardItem *item1 = new QStandardItem("OnlyOne Last");
+ delegate.count = 0;
+ item0->setText("OnlyOne HasChildren");
+ model2.appendRow(QList<QStandardItem*>() << item1);
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 3);
+ QApplication::processEvents();
+
+ QStandardItem *item01 = new QStandardItem("OnlyOne Last");
+ delegate.count = 0;
+ item00->setText("OnlyOne");
+ item0->appendRow(QList<QStandardItem*>() << item01);
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 4);
+ QApplication::processEvents();
+
+ QStandardItem *item000 = new QStandardItem("OnlyOne Last");
+ delegate.count = 0;
+ item00->setText("OnlyOne HasChildren");
+ item00->appendRow(QList<QStandardItem*>() << item000);
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 5);
+ QApplication::processEvents();
+
+ delegate.count = 0;
+ item0->removeRow(0);
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 3);
+ QApplication::processEvents();
+
+ item00 = new QStandardItem("OnlyOne");
+ item0->insertRow(0, QList<QStandardItem*>() << item00);
+ QApplication::processEvents();
+ delegate.count = 0;
+ view.expandAll();
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 4);
+ QApplication::processEvents();
+
+ delegate.count = 0;
+ item0->removeRow(1);
+ item00->setText("OnlyOne Last");
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 3);
+ QApplication::processEvents();
+
+ delegate.count = 0;
+ item0->removeRow(0);
+ item0->setText("OnlyOne");
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 2);
+ QApplication::processEvents();
+
+ //with hidden items
+ item0->setText("OnlyOne HasChildren");
+ item00 = new QStandardItem("OnlyOne");
+ item0->appendRow(QList<QStandardItem*>() << item00);
+ item01 = new QStandardItem("Assert");
+ item0->appendRow(QList<QStandardItem*>() << item01);
+ view.setRowHidden(1, item0->index(), true);
+ view.expandAll();
+ QStandardItem *item02 = new QStandardItem("OnlyOne Last");
+ item0->appendRow(QList<QStandardItem*>() << item02);
+ delegate.count = 0;
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 4);
+ QApplication::processEvents();
+
+ item0->removeRow(2);
+ item00->setText("OnlyOne Last");
+ delegate.count = 0;
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.count >= 3);
+ QApplication::processEvents();
+
+ item00->setText("OnlyOne");
+ item0->insertRow(2, new QStandardItem("OnlyOne Last"));
+ view.collapse(item0->index());
+ item0->removeRow(0);
+ delegate.count = 0;
+ QTRY_VERIFY(delegate.count >= 2);
+ QApplication::processEvents();
+
+ item0->removeRow(1);
+ item0->setText("OnlyOne");
+ delegate.count = 0;
+ QTRY_VERIFY(delegate.count >= 2);
+ QApplication::processEvents();
+ }
+}
+
+class task174627_TreeView : public QTreeView
+{
+ Q_OBJECT
+protected slots:
+ void currentChanged(const QModelIndex &current, const QModelIndex &)
+ { emit currentChanged(current); }
+signals:
+ void currentChanged(const QModelIndex &);
+};
+
+void tst_QTreeView::task174627_moveLeftToRoot()
+{
+ QStandardItemModel model;
+ QStandardItem *item1 = new QStandardItem(QString("item 1"));
+ model.invisibleRootItem()->appendRow(item1);
+ QStandardItem *item2 = new QStandardItem(QString("item 2"));
+ item1->appendRow(item2);
+
+ task174627_TreeView view;
+ view.setModel(&model);
+ view.setRootIndex(item1->index());
+ view.setCurrentIndex(item2->index());
+
+ QSignalSpy spy(&view, SIGNAL(currentChanged(QModelIndex)));
+ QTest::keyClick(&view, Qt::Key_Left);
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QTreeView::task171902_expandWith1stColHidden()
+{
+ //the task was: if the first column of a treeview is hidden, the expanded state is not correctly restored
+ QStandardItemModel model;
+ QStandardItem root("root"), root2("root"),
+ subitem("subitem"), subitem2("subitem"),
+ subsubitem("subsubitem"), subsubitem2("subsubitem");
+
+ model.appendRow( QList<QStandardItem *>() << &root << &root2);
+ root.appendRow( QList<QStandardItem *>() << &subitem << &subitem2);
+ subitem.appendRow( QList<QStandardItem *>() << &subsubitem << &subsubitem2);
+
+ QTreeView view;
+ view.setModel(&model);
+
+ view.setColumnHidden(0, true);
+ view.expandAll();
+ view.collapse(root.index());
+ view.expand(root.index());
+
+ QCOMPARE(view.isExpanded(root.index()), true);
+ QCOMPARE(view.isExpanded(subitem.index()), true);
+
+}
+
+void tst_QTreeView::task203696_hidingColumnsAndRowsn()
+{
+ QTreeView view;
+ QStandardItemModel *model = new QStandardItemModel(0, 3, &view);
+ for (int i = 0; i < 3; ++i)
+ {
+ model->insertRow(model->rowCount());
+ for (int j = 0; j < model->columnCount(); ++j)
+ model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
+ }
+ view.setModel(model);
+ view.show();
+ view.setColumnHidden(0, true);
+ view.setRowHidden(0, QModelIndex(), true);
+ QCOMPARE(view.indexAt(QPoint(0, 0)), model->index(1, 1));
+}
+
+
+void tst_QTreeView::addRowsWhileSectionsAreHidden()
+{
+ QTreeView view;
+ for (int pass = 1; pass <= 2; ++pass) {
+ QStandardItemModel *model = new QStandardItemModel(6, pass, &view);
+ view.setModel(model);
+ view.show();
+
+ int i;
+ for (i = 0; i < 3; ++i)
+ {
+ model->insertRow(model->rowCount());
+ for (int j = 0; j < model->columnCount(); ++j) {
+ model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
+ }
+ }
+ int col;
+ for (col = 0; col < pass; ++col)
+ view.setColumnHidden(col, true);
+ for (i = 3; i < 6; ++i)
+ {
+ model->insertRow(model->rowCount());
+ for (int j = 0; j < model->columnCount(); ++j) {
+ model->setData(model->index(i, j), QString("row %1 col %2").arg(i).arg(j));
+ }
+ }
+ for (col = 0; col < pass; ++col)
+ view.setColumnHidden(col, false);
+ QTest::qWait(250);
+
+ for (i = 0; i < 6; ++i) {
+ QRect rect = view.visualRect(model->index(i, 0));
+ QCOMPARE(rect.isValid(), true);
+ }
+
+ delete model;
+ }
+}
+
+void tst_QTreeView::task216717_updateChildren()
+{
+ class Tree : public QTreeWidget {
+ protected:
+ void paintEvent(QPaintEvent *e)
+ {
+ QTreeWidget::paintEvent(e);
+ refreshed=true;
+ }
+ public:
+ bool refreshed;
+ } tree;
+ tree.show();
+ QTest::qWaitForWindowShown(&tree);
+ tree.refreshed = false;
+ QTreeWidgetItem *parent = new QTreeWidgetItem(QStringList() << "parent");
+ tree.addTopLevelItem(parent);
+ QTest::qWait(10);
+ QTRY_VERIFY(tree.refreshed);
+ tree.refreshed = false;
+ parent->addChild(new QTreeWidgetItem(QStringList() << "child"));
+ QTest::qWait(10);
+ QTRY_VERIFY(tree.refreshed);
+
+}
+
+void tst_QTreeView::task220298_selectColumns()
+{
+ //this is a very simple 3x3 model where the internalId of the index are different for each cell
+ class Model : public QAbstractTableModel
+ { public:
+ virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const
+ { return parent.isValid() ? 0 : 3; }
+ virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const
+ { return parent.isValid() ? 0 : 3; }
+
+ virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
+ {
+ if(role == Qt::DisplayRole)
+ return QVariant(QString("%1-%2").arg(index.column()).arg(index.row()));
+ return QVariant();
+ }
+
+ virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const
+ {
+ return hasIndex(row, column, parent) ? createIndex(row, column, column*10+row) : QModelIndex();
+ }
+ };
+
+ class TreeView : public QTreeView { public: QModelIndexList selectedIndexes () const { return QTreeView::selectedIndexes(); } } view;
+ Model model;
+ view.setModel(&model);
+ view.show();
+ QTest::qWait(50);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0,
+ view.visualRect(view.model()->index(1, 1)).center());
+ QTest::qWait(50);
+ QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 2)));
+ QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 1)));
+ QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 0)));
+}
+
+
+void tst_QTreeView::task224091_appendColumns()
+{
+ QStandardItemModel *model = new QStandardItemModel();
+ QWidget* topLevel= new QWidget;
+ QTreeView *treeView = new QTreeView(topLevel);
+ treeView->setModel(model);
+ topLevel->show();
+ treeView->resize(50,50);
+
+ QTest::qWaitForWindowShown(treeView);
+ qApp->processEvents();
+
+ QList<QStandardItem *> projlist;
+ for (int k = 0; k < 10; ++k)
+ projlist.append(new QStandardItem(QString("Top Level %0").arg(k)));
+ model->appendColumn(projlist);
+ model->invisibleRootItem()->appendRow(new QStandardItem("end"));
+
+ QTest::qWait(50);
+ qApp->processEvents();
+
+ QTRY_VERIFY(treeView->verticalScrollBar()->isVisible());
+
+ delete topLevel;
+ delete model;
+}
+
+void tst_QTreeView::task211293_removeRootIndex()
+{
+ QTreeView view;
+ QStandardItemModel model;
+ QStandardItem *A1 = new QStandardItem("A1");
+ QStandardItem *B11 = new QStandardItem("B1.1");
+ QStandardItem *C111 = new QStandardItem("C1.1.1");
+ QStandardItem *C112 = new QStandardItem("C1.1.2");
+ QStandardItem *C113 = new QStandardItem("C1.1.3");
+ QStandardItem *D1131 = new QStandardItem("D1.1.3.1");
+ QStandardItem *E11311 = new QStandardItem("E1.1.3.1.1");
+ QStandardItem *E11312 = new QStandardItem("E1.1.3.1.2");
+ QStandardItem *E11313 = new QStandardItem("E1.1.3.1.3");
+ QStandardItem *E11314 = new QStandardItem("E1.1.3.1.4");
+ QStandardItem *D1132 = new QStandardItem("D1.1.3.2");
+ QStandardItem *E11321 = new QStandardItem("E1.1.3.2.1");
+ D1132->appendRow(E11321);
+ D1131->appendRow(E11311);
+ D1131->appendRow(E11312);
+ D1131->appendRow(E11313);
+ D1131->appendRow(E11314);
+ C113->appendRow(D1131);
+ C113->appendRow(D1132);
+ B11->appendRow(C111);
+ B11->appendRow(C112);
+ B11->appendRow(C113);
+ A1->appendRow(B11);
+ model.appendRow(A1);
+ view.setModel(&model);
+ view.setRootIndex(model.indexFromItem(B11));
+ view.setExpanded(model.indexFromItem(B11), true);
+ view.setCurrentIndex(model.indexFromItem(E11314));
+ view.setExpanded(model.indexFromItem(E11314), true);
+ view.show();
+ qApp->processEvents();
+ model.removeRows(0, 1);
+ qApp->processEvents();
+}
+
+void tst_QTreeView::task225539_deleteModel()
+{
+ QTreeView treeView;
+ treeView.show();
+ QStandardItemModel *model = new QStandardItemModel(&treeView);
+
+ QStandardItem* parentItem = model->invisibleRootItem();
+ QStandardItem* item = new QStandardItem(QString("item"));
+ parentItem->appendRow(item);
+
+ treeView.setModel(model);
+
+ QCOMPARE(item->index(), treeView.indexAt(QPoint()));
+
+ delete model;
+
+ QVERIFY(!treeView.indexAt(QPoint()).isValid());
+}
+
+void tst_QTreeView::task230123_setItemsExpandable()
+{
+ //let's check that we prevent the expansion inside a treeview
+ //when the property is set.
+ QTreeWidget tree;
+
+ QTreeWidgetItem root;
+ QTreeWidgetItem child;
+ root.addChild(&child);
+ tree.addTopLevelItem(&root);
+
+ tree.setCurrentItem(&root);
+
+ tree.setItemsExpandable(false);
+
+ QTest::keyClick(&tree, Qt::Key_Plus);
+ QVERIFY(!root.isExpanded());
+
+ QTest::keyClick(&tree, Qt::Key_Right);
+ QVERIFY(!root.isExpanded());
+
+ tree.setItemsExpandable(true);
+
+ QTest::keyClick(&tree, Qt::Key_Plus);
+ QVERIFY(root.isExpanded());
+
+ QTest::keyClick(&tree, Qt::Key_Minus);
+ QVERIFY(!root.isExpanded());
+
+ QTest::keyClick(&tree, Qt::Key_Right);
+ QVERIFY(root.isExpanded());
+
+ QTest::keyClick(&tree, Qt::Key_Left);
+ QVERIFY(!root.isExpanded());
+
+ QTest::keyClick(&tree, Qt::Key_Right);
+ QVERIFY(root.isExpanded());
+
+ const bool navToChild = tree.style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, &tree);
+ QTest::keyClick(&tree, Qt::Key_Right);
+ QCOMPARE(tree.currentItem(), navToChild ? &child : &root);
+
+ QTest::keyClick(&tree, Qt::Key_Right);
+ //it should not be expanded: it has no leaf
+ QCOMPARE(child.isExpanded(), false);
+
+ QTest::keyClick(&tree, Qt::Key_Left);
+ QCOMPARE(tree.currentItem(), &root);
+
+ QTest::keyClick(&tree, Qt::Key_Left);
+ QVERIFY(!root.isExpanded());
+
+
+}
+
+void tst_QTreeView::task202039_closePersistentEditor()
+{
+ QStandardItemModel model(1,1);
+ QTreeView view;
+ view.setModel(&model);
+
+ QModelIndex current = model.index(0,0);
+ QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
+ QCOMPARE(view.currentIndex(), current);
+ QVERIFY(view.indexWidget(current));
+
+ view.closePersistentEditor(current);
+ QVERIFY(view.indexWidget(current) == 0);
+
+ //here was the bug: closing the persistent editor would not reset the state
+ //and it was impossible to go into editinon again
+ QTest::mousePress(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(current).center());
+ QCOMPARE(view.currentIndex(), current);
+ QVERIFY(view.indexWidget(current));
+}
+
+void tst_QTreeView::task238873_avoidAutoReopening()
+{
+ QStandardItemModel model;
+
+ QStandardItem item0("row 0");
+ QStandardItem item1("row 1");
+ QStandardItem item2("row 2");
+ QStandardItem item3("row 3");
+ model.appendColumn( QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3);
+
+ QStandardItem child("child");
+ item1.appendRow( &child);
+
+ QTreeView view;
+ view.setModel(&model);
+ view.show();
+ view.expandAll();
+ QTest::qWait(100);
+
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(child.index()).center());
+ QTest::qWait(20);
+ QCOMPARE(view.currentIndex(), child.index());
+
+ view.setExpanded(item1.index(), false);
+
+ QTest::qWait(500); //enough to trigger the delayedAutoScroll timer
+ QVERIFY(!view.isExpanded(item1.index()));
+}
+
+void tst_QTreeView::task244304_clickOnDecoration()
+{
+ QTreeView view;
+ QStandardItemModel model;
+ QStandardItem item0("row 0");
+ QStandardItem item00("row 0");
+ item0.appendRow(&item00);
+ QStandardItem item1("row 1");
+ model.appendColumn(QList<QStandardItem*>() << &item0 << &item1);
+ view.setModel(&model);
+
+ QVERIFY(!view.currentIndex().isValid());
+ QRect rect = view.visualRect(item0.index());
+ //we click on the decoration
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, rect.topLeft()+QPoint(-rect.left()/2,rect.height()/2));
+ QVERIFY(!view.currentIndex().isValid());
+ QVERIFY(view.isExpanded(item0.index()));
+
+ rect = view.visualRect(item1.index());
+ //the item has no decoration, it should get selected
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, rect.topLeft()+QPoint(-rect.left()/2,rect.height()/2));
+ QCOMPARE(view.currentIndex(), item1.index());
+}
+
+void tst_QTreeView::task246536_scrollbarsNotWorking()
+{
+ struct MyObject : public QObject
+ {
+ MyObject() : count(0)
+ {
+ }
+
+ bool eventFilter(QObject*, QEvent *e)
+ {
+ if (e->type() == QEvent::Paint)
+ count++;
+
+ return false;
+ }
+
+ int count;
+ };
+ QTreeView tree;
+ MyObject o;
+ tree.viewport()->installEventFilter(&o);
+ QStandardItemModel model;
+ tree.setModel(&model);
+ tree.show();
+ QTest::qWaitForWindowShown(&tree);
+ QList<QStandardItem *> items;
+ for(int i=0; i<100; ++i){
+ items << new QStandardItem(QString::fromLatin1("item %1").arg(i));
+ }
+ model.invisibleRootItem()->appendColumn(items);
+ QTest::qWait(100);
+ o.count = 0;
+ tree.verticalScrollBar()->setValue(50);
+ QTest::qWait(100);
+ QTRY_VERIFY(o.count > 0);
+}
+
+void tst_QTreeView::task250683_wrongSectionSize()
+{
+ QDirModel model;
+ QTreeView treeView;
+ treeView.header()->setResizeMode(QHeaderView::ResizeToContents);
+ treeView.setModel(&model);
+ treeView.setColumnHidden(2, true);
+ treeView.setColumnHidden(3, true);
+
+ treeView.show();
+ QTest::qWait(100);
+
+ QCOMPARE(treeView.header()->sectionSize(0) + treeView.header()->sectionSize(1), treeView.viewport()->width());
+}
+
+void tst_QTreeView::task239271_addRowsWithFirstColumnHidden()
+{
+ class MyDelegate : public QStyledItemDelegate
+ {
+ public:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
+ {
+ paintedIndexes << index;
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+
+ mutable QSet<QModelIndex> paintedIndexes;
+ };
+
+ QTreeView view;
+ QStandardItemModel model;
+ view.setModel(&model);
+ MyDelegate delegate;
+ view.setItemDelegate(&delegate);
+ QStandardItem root0("root0"), root1("root1");
+ model.invisibleRootItem()->appendRow(QList<QStandardItem*>() << &root0 << &root1);
+ QStandardItem sub0("sub0"), sub00("sub00");
+ root0.appendRow(QList<QStandardItem*>() << &sub0 << &sub00);
+ view.expand(root0.index());
+
+ view.hideColumn(0);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ delegate.paintedIndexes.clear();
+ QStandardItem sub1("sub1"), sub11("sub11");
+ root0.appendRow(QList<QStandardItem*>() << &sub1 << &sub11);
+
+ QTest::qWait(20);
+ //items in the 2nd column should have been painted
+ QTRY_VERIFY(!delegate.paintedIndexes.isEmpty());
+ QVERIFY(delegate.paintedIndexes.contains(sub00.index()));
+ QVERIFY(delegate.paintedIndexes.contains(sub11.index()));
+}
+
+void tst_QTreeView::task254234_proxySort()
+{
+ //based on tst_QTreeView::sortByColumn
+ // it used not to work when setting the source of a proxy after enabling sorting
+ QTreeView view;
+ QStandardItemModel model(4,2);
+ model.setItem(0,0,new QStandardItem("b"));
+ model.setItem(1,0,new QStandardItem("d"));
+ model.setItem(2,0,new QStandardItem("c"));
+ model.setItem(3,0,new QStandardItem("a"));
+ model.setItem(0,1,new QStandardItem("e"));
+ model.setItem(1,1,new QStandardItem("g"));
+ model.setItem(2,1,new QStandardItem("h"));
+ model.setItem(3,1,new QStandardItem("f"));
+
+ view.sortByColumn(1);
+ view.setSortingEnabled(true);
+
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(true);
+ view.setModel(&proxy);
+ proxy.setSourceModel(&model);
+ QCOMPARE(view.header()->sortIndicatorSection(), 1);
+ QCOMPARE(view.model()->data(view.model()->index(0,1)).toString(), QString::fromLatin1("h"));
+ QCOMPARE(view.model()->data(view.model()->index(1,1)).toString(), QString::fromLatin1("g"));
+}
+
+class TreeView : public QTreeView
+{
+ Q_OBJECT
+public slots:
+ void handleSelectionChanged()
+ {
+ //let's select the last item
+ QModelIndex idx = model()->index(0, 0);
+ selectionModel()->select(QItemSelection(idx, idx), QItemSelectionModel::Select);
+ disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(handleSelectionChanged()));
+ }
+};
+
+void tst_QTreeView::task248022_changeSelection()
+{
+ //we check that changing the selection between the mouse press and the mouse release
+ //works correctly
+ TreeView view;
+ QStringList list = QStringList() << "1" << "2";
+ QStringListModel model(list);
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view.setModel(&model);
+ view.connect(view.selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(handleSelectionChanged()));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, view.visualRect(model.index(1)).center());
+ QCOMPARE(view.selectionModel()->selectedIndexes().count(), list.count());
+}
+
+void tst_QTreeView::task245654_changeModelAndExpandAll()
+{
+ QTreeView view;
+ QStandardItemModel *model = new QStandardItemModel;
+ QStandardItem *top = new QStandardItem("top");
+ QStandardItem *sub = new QStandardItem("sub");
+ top->appendRow(sub);
+ model->appendRow(top);
+ view.setModel(model);
+ view.expandAll();
+ QApplication::processEvents();
+ QVERIFY(view.isExpanded(top->index()));
+
+ //now let's try to delete the model
+ //then repopulate and expand again
+ delete model;
+ model = new QStandardItemModel;
+ top = new QStandardItem("top");
+ sub = new QStandardItem("sub");
+ top->appendRow(sub);
+ model->appendRow(top);
+ view.setModel(model);
+ view.expandAll();
+ QApplication::processEvents();
+ QVERIFY(view.isExpanded(top->index()));
+
+}
+
+void tst_QTreeView::doubleClickedWithSpans()
+{
+ QTreeView view;
+ QStandardItemModel model(1, 2);
+ view.setModel(&model);
+ view.setFirstColumnSpanned(0, QModelIndex(), true);
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QTest::qWaitForWindowShown(&view);
+ QTRY_VERIFY(view.isActiveWindow());
+
+ QPoint p(10, 10);
+ QCOMPARE(view.indexAt(p), model.index(0, 0));
+ QSignalSpy spy(&view, SIGNAL(doubleClicked(QModelIndex)));
+ QTest::mousePress(view.viewport(), Qt::LeftButton, 0, p);
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, p);
+ QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, p);
+ QCOMPARE(spy.count(), 1);
+
+ //let's click on the 2nd column
+ p.setX(p.x() + view.header()->sectionSize(0));
+ QCOMPARE(view.indexAt(p), model.index(0, 0));
+
+ //end the previous edition
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
+ QTest::qWait(150);
+ QTest::mousePress(view.viewport(), Qt::LeftButton, 0, p);
+ QTest::mouseDClick(view.viewport(), Qt::LeftButton, 0, p);
+ QTest::mouseRelease(view.viewport(), Qt::LeftButton, 0, p);
+ QTRY_COMPARE(spy.count(), 2);
+}
+
+void tst_QTreeView::taskQTBUG_6450_selectAllWith1stColumnHidden()
+{
+ QTreeWidget tree;
+ tree.setSelectionMode(QAbstractItemView::MultiSelection);
+ tree.setColumnCount(2);
+ QList<QTreeWidgetItem *> items;
+ const int nrRows = 10;
+ for (int i = 0; i < nrRows; ++i) {
+ items.append(new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item: %1").arg(i))));
+ items.last()->setText(1, QString("is an item"));
+ }
+ tree.insertTopLevelItems(0, items);
+
+ tree.hideColumn(0);
+ tree.selectAll();
+
+ QVERIFY(tree.selectionModel()->hasSelection());
+ for (int i = 0; i < nrRows; ++i)
+ QVERIFY(tree.selectionModel()->isRowSelected(i, QModelIndex()));
+}
+
+class TreeViewQTBUG_9216 : public QTreeView
+{
+ Q_OBJECT
+public:
+ void paintEvent(QPaintEvent *event)
+ {
+ if (doCompare)
+ QCOMPARE(event->rect(), viewport()->rect());
+ QTreeView::paintEvent(event);
+ painted++;
+ }
+ int painted;
+ bool doCompare;
+};
+
+void tst_QTreeView::taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint()
+{
+ QStandardItemModel model(10, 10, this);
+ for (int row = 0; row < 10; row++)
+ for (int col = 0; col < 10; col++)
+ model.setItem(row, col, new QStandardItem(QString("row %0, col %1").arg(row).arg(col)));
+ TreeViewQTBUG_9216 view;
+ view.setUniformRowHeights(true);
+ view.setModel(&model);
+ view.painted = 0;
+ view.doCompare = false;
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QTRY_VERIFY(view.painted > 0);
+
+ QTest::qWait(100); // This one is needed to make the test fail before the patch.
+ view.painted = 0;
+ view.doCompare = true;
+ model.setData(model.index(0, 0), QVariant(QSize(50, 50)), Qt::SizeHintRole);
+ QTest::qWait(100);
+ QTRY_VERIFY(view.painted > 0);
+}
+
+void tst_QTreeView::keyboardNavigationWithDisabled()
+{
+ QWidget topLevel;
+ QTreeView view(&topLevel);
+ QStandardItemModel model(90, 0);
+ for (int i = 0; i < 90; i ++) {
+ model.setItem(i, new QStandardItem(QString::number(i)));
+ model.item(i)->setEnabled(i%6 == 0);
+ }
+ view.setModel(&model);
+
+ view.resize(200, view.visualRect(model.index(0,0)).height()*10);
+ topLevel.show();
+ QApplication::setActiveWindow(&topLevel);
+ QTest::qWaitForWindowShown(&topLevel);
+ QTRY_VERIFY(topLevel.isActiveWindow());
+
+ view.setCurrentIndex(model.index(1, 0));
+ QTest::keyClick(view.viewport(), Qt::Key_Up);
+ QCOMPARE(view.currentIndex(), model.index(0, 0));
+ QTest::keyClick(view.viewport(), Qt::Key_Down);
+ QCOMPARE(view.currentIndex(), model.index(6, 0));
+ QTest::keyClick(view.viewport(), Qt::Key_PageDown);
+ QCOMPARE(view.currentIndex(), model.index(18, 0));
+ QTest::keyClick(view.viewport(), Qt::Key_Down);
+ QCOMPARE(view.currentIndex(), model.index(24, 0));
+ QTest::keyClick(view.viewport(), Qt::Key_PageUp);
+ QCOMPARE(view.currentIndex(), model.index(12, 0));
+ QTest::keyClick(view.viewport(), Qt::Key_Up);
+ QCOMPARE(view.currentIndex(), model.index(6, 0));
+}
+
+class Model_11466 : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ Model_11466(QObject * /* parent */) :
+ m_block(false)
+ {
+ // set up the model to have two top level items and a few others
+ m_selectionModel = new QItemSelectionModel(this, this); // owned by this
+
+ connect(m_selectionModel, SIGNAL(currentChanged(const QModelIndex &,const QModelIndex &)),
+ this, SLOT(slotCurrentChanged(const QModelIndex &,const QModelIndex &)));
+ };
+
+ int rowCount(const QModelIndex &parent) const
+ {
+ if (parent.isValid())
+ return (parent.internalId() == 0) ? 4 : 0;
+ return 2; // two top level items
+ }
+
+ int columnCount(const QModelIndex & /* parent */) const
+ {
+ return 2;
+ }
+
+ QVariant data(const QModelIndex &index, int role) const
+ {
+ if (role == Qt::DisplayRole && index.isValid()) {
+ qint64 parentRowPlusOne = index.internalId();
+ QString str;
+ QTextStream stream(&str);
+ if (parentRowPlusOne > 0)
+ stream << parentRowPlusOne << " -> " << index.row() << " : " << index.column();
+ else
+ stream << index.row() << " : " << index.column();
+ return QVariant(str);
+ }
+ return QVariant();
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ if (index.isValid()) {
+ qint64 parentRowPlusOne = index.internalId();
+ if (parentRowPlusOne > 0) {
+ int row = static_cast<int>(parentRowPlusOne - 1);
+ return createIndex(row, 0, (quint32)0);
+ }
+ }
+ return QModelIndex();
+ }
+
+ void bindView(QTreeView *view)
+ {
+ // sets the view to this model with a shared selection model
+ QItemSelectionModel *oldModel = view->selectionModel();
+ if (oldModel != m_selectionModel)
+ delete oldModel;
+ view->setModel(this); // this creates a new selection model for the view, but we dont want it either ...
+ oldModel = view->selectionModel();
+ view->setSelectionModel(m_selectionModel);
+ delete oldModel;
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const
+ {
+ return createIndex(row, column, parent.isValid() ? (quint32)(parent.row() + 1) : (quint32)0);
+ }
+
+public slots:
+ void slotCurrentChanged(const QModelIndex &current,const QModelIndex &)
+ {
+ if (m_block)
+ return;
+
+ if (current.isValid()) {
+ int selectedRow = current.row();
+ quint32 parentRowPlusOne = static_cast<quint32>(current.internalId());
+
+ for (int i = 0; i < 2; ++i) {
+ // announce the removal of all non top level items
+ beginRemoveRows(createIndex(i, 0, 0), 0, 3);
+ // nothing to actually do for the removal
+ endRemoveRows();
+
+ // put them back in again
+ beginInsertRows(createIndex(i, 0, 0), 0, 3);
+ // nothing to actually do for the insertion
+ endInsertRows();
+ }
+ // reselect the current item ...
+ QModelIndex selectedIndex = createIndex(selectedRow, 0, parentRowPlusOne);
+
+ m_block = true; // recursion block
+ m_selectionModel->select(selectedIndex, QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current|QItemSelectionModel::Rows);
+ m_selectionModel->setCurrentIndex(selectedIndex, QItemSelectionModel::NoUpdate);
+ m_block = false;
+ } else {
+ m_selectionModel->clear();
+ }
+ }
+
+private:
+ bool m_block;
+ QItemSelectionModel *m_selectionModel;
+};
+
+void tst_QTreeView::taskQTBUG_11466_keyboardNavigationRegression()
+{
+ QTreeView treeView;
+ treeView.setSelectionBehavior(QAbstractItemView::SelectRows);
+ treeView.setSelectionMode(QAbstractItemView::SingleSelection);
+ Model_11466 model(&treeView);
+ model.bindView(&treeView);
+ treeView.expandAll();
+ treeView.show();
+ QTest::qWaitForWindowShown(&treeView);
+
+ QTest::keyPress(treeView.viewport(), Qt::Key_Down);
+ QTest::qWait(10);
+ QTRY_COMPARE(treeView.currentIndex(), treeView.selectionModel()->selection().indexes().first());
+}
+
+void tst_QTreeView::taskQTBUG_13567_removeLastItemRegression()
+{
+ QtTestModel model(200, 1);
+
+ QTreeView view;
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ view.scrollToBottom();
+ QTest::qWait(10);
+ CHECK_VISIBLE(199, 0);
+
+ view.setCurrentIndex(model.index(199, 0));
+ model.removeLastRow();
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex(), model.index(198, 0));
+ CHECK_VISIBLE(198, 0);
+}
+
+QTEST_MAIN(tst_QTreeView)
+#include "tst_qtreeview.moc"
diff --git a/tests/auto/widgets/itemviews/qtreewidget/.gitignore b/tests/auto/widgets/itemviews/qtreewidget/.gitignore
new file mode 100644
index 0000000000..08c63b4b52
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreewidget/.gitignore
@@ -0,0 +1 @@
+tst_qtreewidget
diff --git a/tests/auto/widgets/itemviews/qtreewidget/qtreewidget.pro b/tests/auto/widgets/itemviews/qtreewidget/qtreewidget.pro
new file mode 100644
index 0000000000..763c0d3c63
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreewidget/qtreewidget.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qtreewidget.cpp
diff --git a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp
new file mode 100644
index 0000000000..5e1faf97c4
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp
@@ -0,0 +1,3349 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qtreewidget.h>
+#include <qtreewidgetitemiterator.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qdebug.h>
+#include <qheaderview.h>
+#include <qlineedit.h>
+#include <QScrollBar>
+#include <QStyledItemDelegate>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class CustomTreeWidget : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const
+ { return QTreeWidget::indexFromItem(item, column); }
+};
+
+class tst_QTreeWidget : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTreeWidget();
+ ~tst_QTreeWidget();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void getSetCheck();
+ void addTopLevelItem();
+ void currentItem_data();
+ void currentItem();
+ void editItem_data();
+ void editItem();
+ void takeItem_data();
+ void takeItem();
+ void removeChild_data();
+ void removeChild();
+ void setItemHidden();
+ void setItemHidden2();
+ void selectedItems_data();
+ void selectedItems();
+ void itemAssignment();
+ void clone_data();
+ void clone();
+ void expand_data();
+ void expand();
+ void checkState_data();
+ void checkState();
+ void findItems_data();
+ void findItems();
+ void findItemsInColumn();
+ void sortItems_data();
+ void sortItems();
+ void deleteItems_data();
+ void deleteItems();
+ void itemAboveOrBelow();
+ void itemStreaming_data();
+ void itemStreaming();
+ void insertTopLevelItems_data();
+ void insertTopLevelItems();
+ void keyboardNavigation();
+ void scrollToItem();
+ void setSortingEnabled();
+ void match();
+ void columnCount();
+ void setHeaderLabels();
+ void setHeaderItem();
+ void itemWidget_data();
+ void itemWidget();
+ void insertItemsWithSorting_data();
+ void insertItemsWithSorting();
+ void insertExpandedItemsWithSorting_data();
+ void insertExpandedItemsWithSorting();
+ void changeDataWithSorting_data();
+ void changeDataWithSorting();
+ void changeDataWithStableSorting_data();
+ void changeDataWithStableSorting();
+
+ void sortedIndexOfChild_data();
+ void sortedIndexOfChild();
+ void defaultRowSizes();
+
+ void task191552_rtl();
+ void task203673_selection();
+ void rootItemFlags();
+ void task218661_setHeaderData();
+ void task245280_sortChildren();
+ void task253109_itemHeight();
+
+ // QTreeWidgetItem
+ void itemOperatorLessThan();
+ void addChild();
+ void setData();
+ void enableDisable();
+
+ void expandAndCallapse();
+ void itemData();
+ void setDisabled();
+ void removeSelectedItem();
+ void removeCurrentItem();
+ void removeCurrentItem_task186451();
+ void randomExpand();
+ void crashTest();
+ void sortAndSelect();
+
+ void task206367_duplication();
+ void selectionOrder();
+
+ void setSelectionModel();
+ void task217309();
+ void setCurrentItemExpandsParent();
+ void task239150_editorWidth();
+ void setTextUpdate();
+ void taskQTBUG2844_visualItemRect();
+ void setChildIndicatorPolicy();
+
+
+public slots:
+ void itemSelectionChanged();
+ void emitDataChanged();
+
+private:
+ CustomTreeWidget *testWidget;
+};
+
+// Testing get/set functions
+void tst_QTreeWidget::getSetCheck()
+{
+ QTreeWidget obj1;
+ // int QTreeWidget::columnCount()
+ // void QTreeWidget::setColumnCount(int)
+ obj1.setColumnCount(0);
+ QCOMPARE(obj1.columnCount(), 0);
+
+ obj1.setColumnCount(INT_MIN);
+ QCOMPARE(obj1.columnCount(), 0);
+
+ //obj1.setColumnCount(INT_MAX);
+ //QCOMPARE(obj1.columnCount(), INT_MAX);
+ // Since setColumnCount allocates memory, there is no way this will succeed
+
+ obj1.setColumnCount(100);
+ QCOMPARE(obj1.columnCount(), 100);
+
+ // QTreeWidgetItem * QTreeWidget::headerItem()
+ // void QTreeWidget::setHeaderItem(QTreeWidgetItem *)
+ QTreeWidgetItem *var2 = new QTreeWidgetItem();
+ obj1.setHeaderItem(var2);
+ QCOMPARE(obj1.headerItem(), var2);
+
+ obj1.setHeaderItem((QTreeWidgetItem *)0);
+// QCOMPARE(obj1.headerItem(), (QTreeWidgetItem *)0);
+
+ // QTreeWidgetItem * QTreeWidget::currentItem()
+ // void QTreeWidget::setCurrentItem(QTreeWidgetItem *)
+ QTreeWidgetItem *var3 = new QTreeWidgetItem(&obj1);
+ obj1.setCurrentItem(var3);
+ QCOMPARE(obj1.currentItem(), var3);
+
+ obj1.setCurrentItem((QTreeWidgetItem *)0);
+ QCOMPARE(obj1.currentItem(), (QTreeWidgetItem *)0);
+}
+
+typedef QList<int> IntList;
+typedef QList<IntList> ListIntList;
+
+Q_DECLARE_METATYPE(IntList)
+Q_DECLARE_METATYPE(ListIntList)
+Q_DECLARE_METATYPE(QModelIndex)
+Q_DECLARE_METATYPE(Qt::Orientation)
+
+typedef QTreeWidgetItem TreeItem;
+typedef QList<TreeItem*> TreeItemList;
+
+Q_DECLARE_METATYPE(QTreeWidgetItem*)
+Q_DECLARE_METATYPE(TreeItemList)
+
+tst_QTreeWidget::tst_QTreeWidget(): testWidget(0)
+{
+}
+
+tst_QTreeWidget::~tst_QTreeWidget()
+{
+}
+
+void tst_QTreeWidget::initTestCase()
+{
+ qMetaTypeId<QModelIndex>();
+ qMetaTypeId<Qt::Orientation>();
+ qRegisterMetaType<QTreeWidgetItem*>("QTreeWidgetItem*");
+
+ testWidget = new CustomTreeWidget();
+ testWidget->show();
+#ifdef Q_WS_X11
+ qt_x11_wait_for_window_manager(testWidget);
+#endif
+}
+
+void tst_QTreeWidget::cleanupTestCase()
+{
+ testWidget->hide();
+ delete testWidget;
+}
+
+void tst_QTreeWidget::init()
+{
+ testWidget->clear();
+ testWidget->setColumnCount(2);
+}
+
+void tst_QTreeWidget::cleanup()
+{
+}
+
+TreeItem *operator<<(TreeItem *parent, const TreeItemList &children) {
+ for (int i = 0; i < children.count(); ++i)
+ parent->addChild(children.at(i));
+ return parent;
+}
+
+static void populate(QTreeWidget *widget, const TreeItemList &topLevelItems,
+ TreeItem *headerItem = 0)
+{
+ widget->clear();
+ widget->setHeaderItem(headerItem);
+ foreach (TreeItem *item, topLevelItems)
+ widget->addTopLevelItem(item);
+}
+
+void tst_QTreeWidget::addTopLevelItem()
+{
+ QTreeWidget tree;
+ QCOMPARE(tree.topLevelItemCount(), 0);
+
+ // try to add 0
+ tree.addTopLevelItem(0);
+ QCOMPARE(tree.topLevelItemCount(), 0);
+ QCOMPARE(tree.indexOfTopLevelItem(0), -1);
+
+ // add one at a time
+ QList<TreeItem*> tops;
+ for (int i = 0; i < 10; ++i) {
+ TreeItem *ti = new TreeItem();
+ QCOMPARE(tree.indexOfTopLevelItem(ti), -1);
+ tree.addTopLevelItem(ti);
+ QCOMPARE(tree.topLevelItemCount(), i+1);
+ QCOMPARE(tree.topLevelItem(i), ti);
+ QCOMPARE(tree.topLevelItem(-1), static_cast<TreeItem*>(0));
+ QCOMPARE(tree.indexOfTopLevelItem(ti), i);
+ QCOMPARE(ti->parent(), static_cast<TreeItem*>(0));
+ tree.addTopLevelItem(ti);
+ QCOMPARE(tree.topLevelItemCount(), i+1);
+ tops.append(ti);
+ }
+
+ // delete one at a time
+ while (!tops.isEmpty()) {
+ TreeItem *ti = tops.takeFirst();
+ delete ti;
+ QCOMPARE(tree.topLevelItemCount(), tops.count());
+ for (int i = 0; i < tops.count(); ++i)
+ QCOMPARE(tree.topLevelItem(i), tops.at(i));
+ }
+
+ // add none
+ {
+ int count = tree.topLevelItemCount();
+ tree.addTopLevelItems(tops);
+ QCOMPARE(tree.topLevelItemCount(), count);
+ }
+
+ // add many at a time
+ {
+ const int count = 10;
+ for (int i = 0; i < 100; i += count) {
+ tops.clear();
+ for (int j = 0; j < count; ++j)
+ tops << new TreeItem(QStringList() << QString("%0").arg(j));
+ tree.addTopLevelItems(tops);
+ QCOMPARE(tree.topLevelItemCount(), count + i);
+ for (int j = 0; j < count; ++j)
+ QCOMPARE(tree.topLevelItem(i+j), tops.at(j));
+
+ tree.addTopLevelItems(tops);
+ QCOMPARE(tree.topLevelItemCount(), count + i);
+ }
+ }
+
+ // insert
+ {
+ tops.clear();
+ for (int i = 0; i < 10; ++i)
+ tops << new TreeItem();
+ int count = tree.topLevelItemCount();
+ tree.insertTopLevelItems(100000, tops);
+ // ### fixme
+ QCOMPARE(tree.topLevelItemCount(), count + 10);
+ }
+}
+
+void tst_QTreeWidget::currentItem_data()
+{
+ QTest::addColumn<TreeItemList>("topLevelItems");
+
+ QTest::newRow("only top-level items, 2 columns")
+ << (TreeItemList()
+ << new TreeItem(QStringList() << "a" << "b")
+ << new TreeItem(QStringList() << "c" << "d"));
+ TreeItemList lst;
+ lst << (new TreeItem(QStringList() << "a" << "b")
+ << (TreeItemList()
+ << new TreeItem(QStringList() << "c" << "d")
+ << new TreeItem(QStringList() << "c" << "d")
+ )
+ )
+ << (new TreeItem(QStringList() << "e" << "f")
+ << (TreeItemList()
+ << new TreeItem(QStringList() << "g" << "h")
+ << new TreeItem(QStringList() << "g" << "h")
+ )
+ );
+ QTest::newRow("hierarchy, 2 columns") << lst;
+}
+
+void tst_QTreeWidget::currentItem()
+{
+ QFETCH(TreeItemList, topLevelItems);
+
+ QTreeWidget tree;
+ tree.show();
+ populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2"));
+ QTreeWidgetItem *previous = 0;
+ for (int x = 0; x < 2; ++x) {
+ tree.setSelectionBehavior(x ? QAbstractItemView::SelectItems
+ : QAbstractItemView::SelectRows);
+ QSignalSpy currentItemChangedSpy(
+ &tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+ QSignalSpy itemSelectionChangedSpy(
+ &tree, SIGNAL(itemSelectionChanged()));
+
+ QTreeWidgetItemIterator it(&tree);
+ // do all items
+ while (QTreeWidgetItem *item = (*it++)) {
+ tree.setCurrentItem(item);
+ QCOMPARE(tree.currentItem(), item);
+
+ QCOMPARE(currentItemChangedSpy.count(), 1);
+ QVariantList args = currentItemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(1)), previous);
+
+ QCOMPARE(itemSelectionChangedSpy.count(), 1);
+ itemSelectionChangedSpy.clear();
+
+ previous = item;
+ // do all columns
+ for (int col = 0; col < item->columnCount(); ++col) {
+ tree.setCurrentItem(item, col);
+ QCOMPARE(tree.currentItem(), item);
+ QCOMPARE(tree.currentColumn(), col);
+
+ if (!currentItemChangedSpy.isEmpty()) {
+ // ### we get a currentItemChanged() when what really
+ // changed was just currentColumn(). Should it be like this?
+ QCOMPARE(currentItemChangedSpy.count(), 1);
+ QVariantList args = currentItemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(1)), item);
+ if (tree.selectionBehavior() == QAbstractItemView::SelectItems) {
+ QCOMPARE(itemSelectionChangedSpy.count(), 1);
+ itemSelectionChangedSpy.clear();
+ } else {
+ QCOMPARE(itemSelectionChangedSpy.count(), 0);
+ }
+ }
+ }
+ }
+ }
+
+ // can't set the headerItem to be the current item
+ tree.setCurrentItem(tree.headerItem());
+ QCOMPARE(tree.currentItem(), static_cast<TreeItem*>(0));
+}
+
+void tst_QTreeWidget::editItem_data()
+{
+ QTest::addColumn<TreeItemList>("topLevelItems");
+
+ {
+ TreeItemList list;
+ for (int i = 0; i < 10; i++) {
+ TreeItem *item = new TreeItem(QStringList() << "col1" << "col2");
+ if ((i & 1) == 0)
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ else
+ item->setFlags(item->flags() & ~Qt::ItemIsEditable);
+ list << item;
+ }
+ QTest::newRow("2 columns, only even items editable")
+ << list;
+ }
+}
+
+void tst_QTreeWidget::editItem()
+{
+ QFETCH(TreeItemList, topLevelItems);
+
+ QTreeWidget tree;
+ populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2"));
+ tree.show();
+ QTest::qWaitForWindowShown(&tree);
+
+ QSignalSpy itemChangedSpy(
+ &tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
+
+ QTreeWidgetItemIterator it(&tree);
+ while (QTreeWidgetItem *item = (*it++)) {
+ for (int col = 0; col < item->columnCount(); ++col) {
+ if (!(item->flags() & Qt::ItemIsEditable))
+ QTest::ignoreMessage(QtWarningMsg, "edit: editing failed");
+ tree.editItem(item, col);
+ QApplication::instance()->processEvents();
+ QApplication::instance()->processEvents();
+ QLineEdit *editor = qFindChild<QLineEdit*>(&tree);
+ if (editor) {
+ QVERIFY(item->flags() & Qt::ItemIsEditable);
+ QCOMPARE(editor->selectedText(), editor->text());
+ QTest::keyClick(editor, Qt::Key_A);
+ QTest::keyClick(editor, Qt::Key_Enter);
+ QApplication::instance()->processEvents();
+ QCOMPARE(itemChangedSpy.count(), 1);
+ QVariantList args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), col);
+ } else {
+ QVERIFY(!(item->flags() & Qt::ItemIsEditable));
+ }
+ }
+ }
+}
+
+void tst_QTreeWidget::takeItem_data()
+{
+ QTest::addColumn<int>("index");
+ QTest::addColumn<bool>("topLevel");
+ QTest::addColumn<bool>("outOfBounds");
+
+ QTest::newRow("First, topLevel") << 0 << true << false;
+ QTest::newRow("Last, topLevel") << 2 << true << false;
+ QTest::newRow("Middle, topLevel") << 1 << true << false;
+ QTest::newRow("Out of bounds, toplevel, (index: -1)") << -1 << true << true;
+ QTest::newRow("Out of bounds, toplevel, (index: 3)") << 3 << true << true;
+
+ QTest::newRow("First, child of topLevel") << 0 << false << false;
+ QTest::newRow("Last, child of topLevel") << 2 << false << false;
+ QTest::newRow("Middle, child of topLevel") << 1 << false << false;
+ QTest::newRow("Out of bounds, child of toplevel, (index: -1)") << -1 << false << true;
+ QTest::newRow("Out of bounds, child of toplevel, (index: 3)") << 3 << false << true;
+}
+
+void tst_QTreeWidget::takeItem()
+{
+ QFETCH(int, index);
+ QFETCH(bool, topLevel);
+ QFETCH(bool, outOfBounds);
+
+ for (int i=0; i<3; ++i) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
+ top->setText(0, QString("top%1").arg(i));
+ for (int j=0; j<3; ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(top);
+ child->setText(0, QString("child%1").arg(j));
+ }
+ }
+
+ QCOMPARE(testWidget->topLevelItemCount(), 3);
+ QCOMPARE(testWidget->topLevelItem(0)->childCount(), 3);
+
+ if (topLevel) {
+ int count = testWidget->topLevelItemCount();
+ QTreeWidgetItem *item = testWidget->takeTopLevelItem(index);
+ if (outOfBounds) {
+ QCOMPARE(item, (QTreeWidgetItem *)0);
+ QCOMPARE(count, testWidget->topLevelItemCount());
+ } else {
+ QCOMPARE(item->text(0), QString("top%1").arg(index));
+ QCOMPARE(count-1, testWidget->topLevelItemCount());
+ delete item;
+ }
+ } else {
+ int count = testWidget->topLevelItem(0)->childCount();
+ QTreeWidgetItem *item = testWidget->topLevelItem(0)->takeChild(index);
+ if (outOfBounds) {
+ QCOMPARE(item, (QTreeWidgetItem *)0);
+ QCOMPARE(count, testWidget->topLevelItem(0)->childCount());
+ } else {
+ QCOMPARE(item->text(0), QString("child%1").arg(index));
+ QCOMPARE(count-1, testWidget->topLevelItem(0)->childCount());
+ delete item;
+ }
+ }
+}
+
+void tst_QTreeWidget::removeChild_data()
+{
+ QTest::addColumn<int>("childCount");
+ QTest::addColumn<int>("removeAt");
+
+ QTest::newRow("10 remove 3") << 10 << 3;
+}
+
+void tst_QTreeWidget::removeChild()
+{
+ QFETCH(int, childCount);
+ QFETCH(int, removeAt);
+
+ QTreeWidgetItem *root = new QTreeWidgetItem;
+ for (int i = 0; i < childCount; ++i)
+ new QTreeWidgetItem(root, QStringList(QString::number(i)));
+
+ QCOMPARE(root->childCount(), childCount);
+ for (int j = 0; j < childCount; ++j)
+ QCOMPARE(root->child(j)->text(0), QString::number(j));
+
+ QTreeWidgetItem *remove = root->child(removeAt);
+ root->removeChild(remove);
+
+ QCOMPARE(root->childCount(), childCount - 1);
+ for (int k = 0; k < childCount; ++k) {
+ if (k == removeAt)
+ QCOMPARE(remove->text(0), QString::number(k));
+ else if (k < removeAt)
+ QCOMPARE(root->child(k)->text(0), QString::number(k));
+ else if (k > removeAt)
+ QCOMPARE(root->child(k - 1)->text(0), QString::number(k));
+ }
+ delete root;
+}
+
+void tst_QTreeWidget::setItemHidden()
+{
+ QTreeWidgetItem *parent = new QTreeWidgetItem(testWidget);
+ parent->setText(0, "parent");
+ QTreeWidgetItem *child = new QTreeWidgetItem(parent);
+ child->setText(0, "child");
+ QVERIFY(child->parent());
+
+ testWidget->expandItem(parent);
+ testWidget->scrollToItem(child);
+
+ QVERIFY(testWidget->visualItemRect(parent).isValid()
+ && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(parent)));
+ QVERIFY(testWidget->visualItemRect(child).isValid()
+ && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(child)));
+
+ QVERIFY(!testWidget->isItemHidden(parent));
+ QVERIFY(!testWidget->isItemHidden(child));
+
+ testWidget->setItemHidden(parent, true);
+
+ QVERIFY(!(testWidget->visualItemRect(parent).isValid()
+ && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(parent))));
+ QVERIFY(!(testWidget->visualItemRect(child).isValid()
+ && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(child))));
+
+ QVERIFY(testWidget->isItemHidden(parent));
+ QVERIFY(!testWidget->isItemHidden(child));
+
+ // From task 78670 (This caused an core dump)
+ // Check if we can set an item visible if it already is visible.
+ testWidget->setItemHidden(parent, false);
+ testWidget->setItemHidden(parent, false);
+ QVERIFY(!testWidget->isItemHidden(parent));
+
+
+ // hide, hide and then unhide.
+ testWidget->setItemHidden(parent, true);
+ testWidget->setItemHidden(parent, true);
+ testWidget->setItemHidden(parent, false);
+ QVERIFY(!testWidget->isItemHidden(parent));
+
+
+}
+
+
+void tst_QTreeWidget::setItemHidden2()
+{
+ // From Task 78587
+ QStringList hl;
+ hl << "ID" << "Desc";
+ testWidget->setColumnCount(hl.count());
+ testWidget->setHeaderLabels(hl);
+ testWidget->setSortingEnabled(true);
+
+ QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
+ QTreeWidgetItem *leaf = 0;
+ top->setText(0, "ItemList");
+ for (int i = 1; i <= 4; i++) {
+ leaf = new QTreeWidgetItem(top);
+ leaf->setText(0, QString().sprintf("%d", i));
+ leaf->setText(1, QString().sprintf("Item %d", i));
+ }
+
+ if (testWidget->topLevelItemCount() > 0) {
+ top = testWidget->topLevelItem(0);
+ testWidget->setItemExpanded(top, true);
+ }
+
+ if (testWidget->topLevelItemCount() > 0) {
+ top = testWidget->topLevelItem(0);
+ for (int i = 0; i < top->childCount(); i++) {
+ leaf = top->child(i);
+ if (leaf->text(0).toInt() % 2 == 0) {
+ if (!testWidget->isItemHidden(leaf)) {
+ testWidget->setItemHidden(leaf, true);
+ }
+ }
+ }
+ }
+}
+
+
+void tst_QTreeWidget::selectedItems_data()
+{
+ QTest::addColumn<int>("topLevel");
+ QTest::addColumn<int>("children");
+ QTest::addColumn<bool>("closeTopLevel");
+ QTest::addColumn<ListIntList>("selectedItems");
+ QTest::addColumn<ListIntList>("hiddenItems");
+ QTest::addColumn<ListIntList>("expectedItems");
+
+ ListIntList selectedItems;
+ ListIntList hiddenItems;
+ ListIntList expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems
+ << (IntList()
+ << 0);
+ expectedItems
+ << (IntList() << 0);
+ QTest::newRow("2 top with 2 children, closed, top0 selected, no hidden")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems
+ << (IntList()
+ << 0 << 0);
+ expectedItems
+ << (IntList() << 0 << 0);
+ QTest::newRow("2 top with 2 children, closed, top0child0 selected, no hidden")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems
+ << (IntList()
+ << 0 << 0);
+ expectedItems
+ << (IntList()
+ << 0 << 0);
+ QTest::newRow("2 top with 2 children, open, top0child0 selected, no hidden")
+ << 2 << 2 << false << selectedItems << hiddenItems << expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems << (IntList() << 0);
+ hiddenItems << (IntList() << 0);
+ QTest::newRow("2 top with 2 children, closed, top0 selected, top0 hidden")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems << (IntList() << 0 << 0);
+ hiddenItems << (IntList() << 0);
+ expectedItems << (IntList() << 0 << 0);
+ QTest::newRow("2 top with 2 children, closed, top0child0 selected, top0 hidden")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems
+ << (IntList() << 0)
+ << (IntList() << 0 << 0)
+ << (IntList() << 0 << 1)
+ << (IntList() << 1)
+ << (IntList() << 1 << 0)
+ << (IntList() << 1 << 1);
+ expectedItems
+ << (IntList() << 0)
+ << (IntList() << 0 << 0)
+ << (IntList() << 0 << 1)
+ << (IntList() << 1)
+ << (IntList() << 1 << 0)
+ << (IntList() << 1 << 1);
+ QTest::newRow("2 top with 2 children, closed, all selected, no hidden")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems
+ << (IntList() << 0)
+ << (IntList() << 0 << 0)
+ << (IntList() << 0 << 1)
+ << (IntList() << 1)
+ << (IntList() << 1 << 0)
+ << (IntList() << 1 << 1);
+ hiddenItems
+ << (IntList() << 0);
+ expectedItems
+ //<< (IntList() << 0)
+ << (IntList() << 0 << 0)
+ << (IntList() << 0 << 1)
+ << (IntList() << 1)
+ << (IntList() << 1 << 0)
+ << (IntList() << 1 << 1);
+ QTest::newRow("2 top with 2 children, closed, all selected, top0 hidden")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+ selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
+ selectedItems
+ << (IntList() << 0)
+ << (IntList() << 0 << 0)
+ << (IntList() << 0 << 1)
+ << (IntList() << 1)
+ << (IntList() << 1 << 0)
+ << (IntList() << 1 << 1);
+ hiddenItems
+ << (IntList() << 0 << 1)
+ << (IntList() << 1);
+ expectedItems
+ << (IntList() << 0)
+ << (IntList() << 0 << 0)
+ //<< (IntList() << 0 << 1)
+ //<< (IntList() << 1)
+ << (IntList() << 1 << 0)
+ << (IntList() << 1 << 1);
+
+ QTest::newRow("2 top with 2 children, closed, all selected, top0child1 and top1")
+ << 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
+
+}
+
+void tst_QTreeWidget::selectedItems()
+{
+ QFETCH(int, topLevel);
+ QFETCH(int, children);
+ QFETCH(bool, closeTopLevel);
+ QFETCH(ListIntList, selectedItems);
+ QFETCH(ListIntList, hiddenItems);
+ QFETCH(ListIntList, expectedItems);
+
+ // create items
+ for (int t=0; t<topLevel; ++t) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
+ top->setText(0, QString("top%1").arg(t));
+ for (int c=0; c<children; ++c) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(top);
+ child->setText(0, QString("top%1child%2").arg(t).arg(c));
+ }
+ }
+
+ // set selected
+ foreach (IntList itemPath, selectedItems) {
+ QTreeWidgetItem *item = 0;
+ foreach(int index, itemPath) {
+ if (!item)
+ item = testWidget->topLevelItem(index);
+ else
+ item = item->child(index);
+ }
+ testWidget->setItemSelected(item, true);
+ }
+
+ // hide rows
+ foreach (IntList itemPath, hiddenItems) {
+ QTreeWidgetItem *item = 0;
+ foreach(int index, itemPath) {
+ if (!item)
+ item = testWidget->topLevelItem(index);
+ else
+ item = item->child(index);
+ }
+ testWidget->setItemHidden(item, true);
+ }
+
+ // open/close toplevel
+ for (int i=0; i<testWidget->topLevelItemCount(); ++i) {
+ if (closeTopLevel)
+ testWidget->collapseItem(testWidget->topLevelItem(i));
+ else
+ testWidget->expandItem(testWidget->topLevelItem(i));
+ }
+
+ // check selectedItems
+ QList<QTreeWidgetItem*> sel = testWidget->selectedItems();
+ QCOMPARE(sel.count(), expectedItems.count());
+ foreach (IntList itemPath, expectedItems) {
+ QTreeWidgetItem *item = 0;
+ foreach(int index, itemPath) {
+ if (!item)
+ item = testWidget->topLevelItem(index);
+ else
+ item = item->child(index);
+ }
+ if (item)
+ QVERIFY(sel.contains(item));
+ }
+
+ // compare isSelected
+ for (int t=0; t<testWidget->topLevelItemCount(); ++t) {
+ QTreeWidgetItem *top = testWidget->topLevelItem(t);
+ if (testWidget->isItemSelected(top) && !testWidget->isItemHidden(top))
+ QVERIFY(sel.contains(top));
+ for (int c=0; c<top->childCount(); ++c) {
+ QTreeWidgetItem *child = top->child(c);
+ if (testWidget->isItemSelected(child) && !testWidget->isItemHidden(child))
+ QVERIFY(sel.contains(child));
+ }
+ }
+
+ // Possible to select null without crashing?
+ testWidget->setItemSelected(0, true);
+ QVERIFY(!testWidget->isItemSelected(0));
+
+ // unselect
+ foreach (IntList itemPath, selectedItems) {
+ QTreeWidgetItem *item = 0;
+ foreach(int index, itemPath) {
+ if (!item)
+ item = testWidget->topLevelItem(index);
+ else
+ item = item->child(index);
+ }
+ testWidget->setItemSelected(item, false);
+ }
+ QCOMPARE(testWidget->selectedItems().count(), 0);
+}
+
+void tst_QTreeWidget::itemAssignment()
+{
+ // create item with children and parent but not insert in the view
+ QTreeWidgetItem grandParent;
+ QTreeWidgetItem *parent = new QTreeWidgetItem(&grandParent);
+ parent->setText(0, "foo");
+ parent->setText(1, "bar");
+ for (int i=0; i<5; ++i) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(parent);
+ child->setText(0, "bingo");
+ child->setText(1, "bango");
+ }
+ QCOMPARE(parent->parent(), &grandParent);
+ QVERIFY(!parent->treeWidget());
+ QCOMPARE(parent->columnCount(), 2);
+ QCOMPARE(parent->text(0), QString("foo"));
+ QCOMPARE(parent->childCount(), 5);
+ QCOMPARE(parent->child(0)->parent(), parent);
+
+ // create item which is inserted in the widget
+ QTreeWidgetItem item(testWidget);
+ item.setText(0, "baz");
+ QVERIFY(!item.parent());
+ QCOMPARE(item.treeWidget(), static_cast<QTreeWidget *>(testWidget));
+ QCOMPARE(item.columnCount(), 1);
+ QCOMPARE(item.text(0), QString("baz"));
+ QCOMPARE(item.childCount(), 0);
+
+ // assign and test
+ *parent = item;
+ QCOMPARE(parent->parent(), &grandParent);
+ QVERIFY(!parent->treeWidget());
+ QCOMPARE(parent->columnCount(), 1);
+ QCOMPARE(parent->text(0), QString("baz"));
+ QCOMPARE(parent->childCount(), 5);
+ QCOMPARE(parent->child(0)->parent(), parent);
+}
+
+void tst_QTreeWidget::clone_data()
+{
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("topLevelIndex");
+ QTest::addColumn<int>("childIndex");
+ QTest::addColumn<QStringList>("topLevelText");
+ QTest::addColumn<QStringList>("childText");
+ QTest::addColumn<bool>("cloneChild");
+
+ QTest::newRow("clone parent with child") << 0 << 0 << 0
+ << (QStringList() << "some text")
+ << (QStringList() << "more text")
+ << false;
+
+ QTest::newRow("clone child") << 0 << 0 << 0
+ << (QStringList() << "some text")
+ << (QStringList() << "more text")
+ << true;
+}
+
+void tst_QTreeWidget::clone()
+{
+ QFETCH(int, column);
+ QFETCH(int, topLevelIndex);
+ QFETCH(int, childIndex);
+ QFETCH(QStringList, topLevelText);
+ QFETCH(QStringList, childText);
+ QFETCH(bool, cloneChild);
+
+ for (int i = 0; i < topLevelText.count(); ++i) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
+ item->setText(column, topLevelText.at(i));
+ for (int j = 0; j < childText.count(); ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(item);
+ child->setText(column, childText.at(j));
+ }
+ }
+
+ QTreeWidgetItem *original = testWidget->topLevelItem(topLevelIndex);
+ QTreeWidgetItem *copy = original->clone();
+ QCOMPARE(copy->text(column), original->text(column));
+ QCOMPARE(copy->childCount(), original->childCount());
+ QVERIFY(!copy->parent());
+ QVERIFY(!copy->treeWidget());
+
+ QTreeWidgetItem *originalChild = original->child(childIndex);
+ QTreeWidgetItem *copiedChild = cloneChild ? originalChild->clone() : copy->child(childIndex);
+ QVERIFY(copiedChild != originalChild);
+ QCOMPARE(copiedChild->text(column), originalChild->text(column));
+ QCOMPARE(copiedChild->childCount(), originalChild->childCount());
+ QCOMPARE(copiedChild->parent(), cloneChild ? 0 : copy);
+ QVERIFY(!copiedChild->treeWidget());
+ if (cloneChild)
+ delete copiedChild;
+ delete copy;
+}
+
+void tst_QTreeWidget::expand_data()
+{
+ QTest::addColumn<int>("topLevelIndex");
+ QTest::addColumn<int>("topLevelCount");
+ QTest::addColumn<int>("childIndex");
+ QTest::addColumn<int>("childCount");
+
+ QTest::newRow("the only test data for now") << 0 << 1 << 0 << 1;
+}
+
+void tst_QTreeWidget::expand()
+{
+ QFETCH(int, topLevelIndex);
+ QFETCH(int, topLevelCount);
+ QFETCH(int, childIndex);
+ QFETCH(int, childCount);
+
+ for (int i = 0; i < topLevelCount; ++i) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
+ for (int j = 0; j < childCount; ++j)
+ new QTreeWidgetItem(item);
+ }
+
+ QTreeWidgetItem *topLevelItem = testWidget->topLevelItem(topLevelIndex);
+ QTreeWidgetItem *childItem = topLevelItem->child(childIndex);
+
+ QVERIFY(!testWidget->isItemExpanded(topLevelItem));
+ testWidget->setItemExpanded(topLevelItem, true);
+ QVERIFY(testWidget->isItemExpanded(topLevelItem));
+
+ QVERIFY(!testWidget->isItemExpanded(childItem));
+ testWidget->setItemExpanded(childItem, true);
+ QVERIFY(testWidget->isItemExpanded(childItem));
+
+ QVERIFY(testWidget->isItemExpanded(topLevelItem));
+ testWidget->setItemExpanded(topLevelItem, false);
+ QVERIFY(!testWidget->isItemExpanded(topLevelItem));
+
+ QVERIFY(testWidget->isItemExpanded(childItem));
+ testWidget->setItemExpanded(childItem, false);
+ QVERIFY(!testWidget->isItemExpanded(childItem));
+}
+
+void tst_QTreeWidget::checkState_data()
+{
+}
+
+void tst_QTreeWidget::checkState()
+{
+ QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
+ item->setCheckState(0, Qt::Unchecked);
+ QTreeWidgetItem *firstChild = new QTreeWidgetItem(item);
+ firstChild->setCheckState(0, Qt::Unchecked);
+ QTreeWidgetItem *seccondChild = new QTreeWidgetItem(item);
+ seccondChild->setCheckState(0, Qt::Unchecked);
+
+ QCOMPARE(item->checkState(0), Qt::Unchecked);
+ QCOMPARE(firstChild->checkState(0), Qt::Unchecked);
+ QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
+
+ firstChild->setCheckState(0, Qt::Checked);
+ QCOMPARE(item->checkState(0), Qt::Unchecked);
+ QCOMPARE(firstChild->checkState(0), Qt::Checked);
+ QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
+
+ item->setFlags(item->flags()|Qt::ItemIsTristate);
+ QCOMPARE(item->checkState(0), Qt::PartiallyChecked);
+ QCOMPARE(firstChild->checkState(0), Qt::Checked);
+ QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
+
+ seccondChild->setCheckState(0, Qt::Checked);
+ QCOMPARE(item->checkState(0), Qt::Checked);
+ QCOMPARE(firstChild->checkState(0), Qt::Checked);
+ QCOMPARE(seccondChild->checkState(0), Qt::Checked);
+
+ firstChild->setCheckState(0, Qt::Unchecked);
+ seccondChild->setCheckState(0, Qt::Unchecked);
+ QCOMPARE(item->checkState(0), Qt::Unchecked);
+ QCOMPARE(firstChild->checkState(0), Qt::Unchecked);
+ QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
+}
+
+void tst_QTreeWidget::findItems_data()
+{
+ QTest::addColumn<int>("column");
+ QTest::addColumn<QStringList>("topLevelText");
+ QTest::addColumn<QStringList>("childText");
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<int>("resultCount");
+ QTest::addColumn<QStringList>("resultText");
+
+ QTest::newRow("find in toplevel")
+ << 0
+ << (QStringList() << "This is a text" << "This is another" << "This is the one")
+ << (QStringList() << "A child" << "This is not the one" << "And yet another child")
+ << "This is the one"
+ << 1
+ << (QStringList() << "This is the one");
+
+ QTest::newRow("find child")
+ << 0
+ << (QStringList() << "This is a text" << "This is another" << "This is the one")
+ << (QStringList() << "A child" << "This is not the one" << "And yet another child")
+ << "A child"
+ << 3 // once for each branch
+ << (QStringList() << "A child");
+
+}
+
+void tst_QTreeWidget::findItems()
+{
+ QFETCH(int, column);
+ QFETCH(QStringList, topLevelText);
+ QFETCH(QStringList, childText);
+ QFETCH(QString, pattern);
+ QFETCH(int, resultCount);
+ QFETCH(QStringList, resultText);
+
+ for (int i = 0; i < topLevelText.count(); ++i) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
+ item->setText(column, topLevelText.at(i));
+ for (int j = 0; j < childText.count(); ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(item);
+ child->setText(column, childText.at(j));
+ }
+ }
+
+ QList<QTreeWidgetItem*> result = testWidget->findItems(pattern,
+ Qt::MatchExactly|Qt::MatchRecursive);
+ QCOMPARE(result.count(), resultCount);
+
+ for (int k = 0; k < result.count() && k < resultText.count(); ++k)
+ QCOMPARE(result.at(k)->text(column), resultText.at(k));
+}
+
+void tst_QTreeWidget::findItemsInColumn()
+{
+ // Create 5 root items.
+ for (int i = 0; i < 5; i++)
+ new QTreeWidgetItem(testWidget, QStringList() << QString::number(i));
+
+ // Create a child with two columns for each root item.
+ for (int i = 0; i < 5; i++) {
+ QTreeWidgetItem * const parent = testWidget->topLevelItem(i);
+ new QTreeWidgetItem(parent, QStringList() << QString::number(i * 10) << QString::number(i * 100));
+ }
+
+ // Recursively search column one for 400.
+ QList<QTreeWidgetItem*> items = testWidget->findItems("400", Qt::MatchExactly|Qt::MatchRecursive, 1);
+ QCOMPARE(items.count(), 1);
+}
+
+void tst_QTreeWidget::sortItems_data()
+{
+ QTest::addColumn<int>("column");
+ QTest::addColumn<int>("order");
+ QTest::addColumn<QStringList>("topLevelText");
+ QTest::addColumn<QStringList>("childText");
+ QTest::addColumn<QStringList>("topLevelResult");
+ QTest::addColumn<QStringList>("childResult");
+ QTest::addColumn<IntList>("expectedTopRows");
+ QTest::addColumn<IntList>("expectedChildRows");
+
+ QTest::newRow("ascending order")
+ << 0
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "d" << "a" << "b")
+ << (QStringList() << "e" << "h" << "g" << "f")
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (QStringList() << "e" << "f" << "g" << "h")
+ << (IntList() << 2 << 3 << 0 << 1)
+ << (IntList() << 0 << 3 << 2 << 1);
+
+ QTest::newRow("descending order")
+ << 0
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "c" << "d" << "a" << "b")
+ << (QStringList() << "e" << "h" << "g" << "f")
+ << (QStringList() << "d" << "c" << "b" << "a")
+ << (QStringList() << "h" << "g" << "f" << "e")
+ << (IntList() << 1 << 0 << 3 << 2)
+ << (IntList() << 3 << 0 << 1 << 2);
+}
+
+void tst_QTreeWidget::sortItems()
+{
+ QFETCH(int, column);
+ QFETCH(int, order);
+ QFETCH(QStringList, topLevelText);
+ QFETCH(QStringList, childText);
+ QFETCH(QStringList, topLevelResult);
+ QFETCH(QStringList, childResult);
+ QFETCH(IntList, expectedTopRows);
+ QFETCH(IntList, expectedChildRows);
+ testWidget->setSortingEnabled(false);
+
+ for (int i = 0; i < topLevelText.count(); ++i) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
+ item->setText(column, topLevelText.at(i));
+ for (int j = 0; j < childText.count(); ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(item);
+ child->setText(column, childText.at(j));
+ }
+ }
+
+ QAbstractItemModel *model = testWidget->model();
+ QList<QPersistentModelIndex> tops;
+ for (int r = 0; r < model->rowCount(QModelIndex()); ++r) {
+ QPersistentModelIndex p = model->index(r, 0, QModelIndex());
+ tops << p;
+ }
+ QList<QPersistentModelIndex> children;
+ for (int s = 0; s < model->rowCount(tops.first()); ++s) {
+ QPersistentModelIndex c = model->index(s, 0, tops.first());
+ children << c;
+ }
+
+ testWidget->sortItems(column, static_cast<Qt::SortOrder>(order));
+ QCOMPARE(testWidget->sortColumn(), column);
+
+ for (int k = 0; k < topLevelResult.count(); ++k) {
+ QTreeWidgetItem *item = testWidget->topLevelItem(k);
+ QCOMPARE(item->text(column), topLevelResult.at(k));
+ for (int l = 0; l < childResult.count(); ++l)
+ QCOMPARE(item->child(l)->text(column), childResult.at(l));
+ }
+
+ for (int m = 0; m < tops.count(); ++m)
+ QCOMPARE(tops.at(m).row(), expectedTopRows.at(m));
+ for (int n = 0; n < children.count(); ++n)
+ QCOMPARE(children.at(n).row(), expectedChildRows.at(n));
+}
+
+void tst_QTreeWidget::deleteItems_data()
+{
+ QTest::addColumn<int>("topLevelCount");
+ QTest::addColumn<int>("childCount");
+ QTest::addColumn<int>("grandChildCount");
+
+ QTest::addColumn<int>("deleteTopLevelCount");
+ QTest::addColumn<int>("deleteChildCount");
+ QTest::addColumn<int>("deleteGrandChildCount");
+
+ QTest::addColumn<int>("expectedTopLevelCount");
+ QTest::addColumn<int>("expectedChildCount");
+ QTest::addColumn<int>("expectedGrandChildCount");
+
+ QTest::addColumn<int>("persistentRow");
+ QTest::addColumn<int>("persistentColumn");
+ QTest::addColumn<bool>("persistentIsValid");
+
+ QTest::newRow("start with 10, delete 1")
+ << 10 << 10 << 10
+ << 1 << 1 << 1
+ << 9 << 9 << 9
+ << 0 << 0 << false;
+ QTest::newRow("start with 10, delete 5")
+ << 10 << 10 << 10
+ << 5 << 5 << 5
+ << 5 << 5 << 5
+ << 0 << 0 << false;
+ QTest::newRow("mixed")
+ << 10 << 13 << 7
+ << 3 << 7 << 4
+ << 7 << 6 << 3
+ << 0 << 0 << false;
+ QTest::newRow("all")
+ << 10 << 10 << 10
+ << 10 << 10 << 10
+ << 0 << 0 << 0
+ << 0 << 0 << false;
+}
+
+void tst_QTreeWidget::deleteItems()
+{
+ QFETCH(int, topLevelCount);
+ QFETCH(int, childCount);
+ QFETCH(int, grandChildCount);
+
+ QFETCH(int, deleteTopLevelCount);
+ QFETCH(int, deleteChildCount);
+ QFETCH(int, deleteGrandChildCount);
+
+ QFETCH(int, expectedTopLevelCount);
+ QFETCH(int, expectedChildCount);
+ QFETCH(int, expectedGrandChildCount);
+
+ QFETCH(int, persistentRow);
+ QFETCH(int, persistentColumn);
+ QFETCH(bool, persistentIsValid);
+
+ for (int i = 0; i < topLevelCount; ++i) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
+ for (int j = 0; j < childCount; ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(top);
+ for (int k = 0; k < grandChildCount; ++k) {
+ new QTreeWidgetItem(child);
+ }
+ }
+ }
+
+ QPersistentModelIndex persistent = testWidget->model()->index(persistentRow,
+ persistentColumn);
+ QVERIFY(persistent.isValid());
+
+ QTreeWidgetItem *top = testWidget->topLevelItem(0);
+ QTreeWidgetItem *child = top->child(0);
+
+ for (int n = 0; n < deleteGrandChildCount; ++n)
+ delete child->child(0);
+ QCOMPARE(child->childCount(), expectedGrandChildCount);
+
+ for (int m = 0; m < deleteChildCount; ++m)
+ delete top->child(0);
+ QCOMPARE(top->childCount(), expectedChildCount);
+
+ for (int l = 0; l < deleteTopLevelCount; ++l)
+ delete testWidget->topLevelItem(0);
+ QCOMPARE(testWidget->topLevelItemCount(), expectedTopLevelCount);
+
+ QCOMPARE(persistent.isValid(), persistentIsValid);
+}
+
+
+void tst_QTreeWidget::itemAboveOrBelow()
+{
+ QTreeWidget tw;
+ tw.setColumnCount(1);
+ QTreeWidgetItem *twi = new QTreeWidgetItem(&tw, QStringList() << "Test");
+ QTreeWidgetItem *twi2 = new QTreeWidgetItem(&tw, QStringList() << "Test 2");
+ QTreeWidgetItem *twi3 = new QTreeWidgetItem(&tw, QStringList() << "Test 3");
+ tw.show();
+ QCOMPARE(tw.itemAbove(twi2), twi);
+ QCOMPARE(tw.itemBelow(twi2), twi3);
+}
+
+void tst_QTreeWidget::itemStreaming_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("toolTip");
+ QTest::addColumn<int>("column");
+
+ QTest::newRow("Data") << "item text" << "tool tip text" << 0;
+}
+
+void tst_QTreeWidget::itemStreaming()
+{
+ QFETCH(QString, text);
+ QFETCH(QString, toolTip);
+ QFETCH(int, column);
+
+ QTreeWidgetItem item(testWidget);
+ QCOMPARE(item.text(column), QString());
+ QCOMPARE(item.toolTip(column), QString());
+
+ item.setText(column, text);
+ item.setToolTip(column, toolTip);
+ QCOMPARE(item.text(column), text);
+ QCOMPARE(item.toolTip(column), toolTip);
+
+ QByteArray buffer;
+ QDataStream out(&buffer, QIODevice::WriteOnly);
+ out << item;
+
+ QTreeWidgetItem item2(testWidget);
+ QCOMPARE(item2.text(column), QString());
+ QCOMPARE(item2.toolTip(column), QString());
+
+ QVERIFY(!buffer.isEmpty());
+
+ QDataStream in(&buffer, QIODevice::ReadOnly);
+ in >> item2;
+ QCOMPARE(item2.text(column), text);
+ QCOMPARE(item2.toolTip(column), toolTip);
+}
+
+void tst_QTreeWidget::insertTopLevelItems_data()
+{
+ QTest::addColumn<QStringList>("initialText");
+ QTest::addColumn<QStringList>("insertText");
+ QTest::addColumn<int>("insertTopLevelIndex");
+ QTest::addColumn<int>("expectedTopLevelIndex");
+ QTest::addColumn<int>("insertChildIndex");
+ QTest::addColumn<int>("expectedChildIndex");
+
+ QStringList initial = (QStringList() << "foo" << "bar");
+ QStringList insert = (QStringList() << "baz");
+
+ QTest::newRow("Insert at count") << initial << insert
+ << initial.count() << initial.count()
+ << initial.count() << initial.count();
+ QTest::newRow("Insert in the middle") << initial << insert
+ << (initial.count() / 2) << (initial.count() / 2)
+ << (initial.count() / 2) << (initial.count() / 2);
+ QTest::newRow("Insert less than 0") << initial << insert
+ << -1 << -1
+ << -1 << -1;
+ QTest::newRow("Insert beyond count") << initial << insert
+ << initial.count() + 1 << -1
+ << initial.count() + 1 << -1;
+}
+
+void tst_QTreeWidget::insertTopLevelItems()
+{
+ QFETCH(QStringList, initialText);
+ QFETCH(QStringList, insertText);
+ QFETCH(int, insertTopLevelIndex);
+ QFETCH(int, expectedTopLevelIndex);
+ QFETCH(int, insertChildIndex);
+ QFETCH(int, expectedChildIndex);
+ testWidget->setSortingEnabled(false);
+
+ { // insert the initial items
+ QCOMPARE(testWidget->topLevelItemCount(), 0);
+ for (int i = 0; i < initialText.count(); ++i) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(QStringList(initialText.at(i)));
+ testWidget->addTopLevelItem(top);
+ QCOMPARE(testWidget->indexOfTopLevelItem(top), i);
+ }
+ QCOMPARE(testWidget->topLevelItemCount(), initialText.count());
+ }
+
+ { // test adding children
+ QTreeWidgetItem *topLevel = testWidget->topLevelItem(0);
+ for (int i = 0; i < initialText.count(); ++i)
+ topLevel->addChild(new QTreeWidgetItem(QStringList(initialText.at(i))));
+ QCOMPARE(topLevel->childCount(), initialText.count());
+ }
+
+ { // test adding more top level items
+ QTreeWidgetItem *topsy = new QTreeWidgetItem(QStringList(insertText.at(0)));
+ testWidget->insertTopLevelItem(insertTopLevelIndex, topsy);
+ if (expectedTopLevelIndex == -1) {
+ QCOMPARE(testWidget->topLevelItemCount(), initialText.count());
+ delete topsy;
+ } else {
+ QTreeWidgetItem *item = testWidget->topLevelItem(expectedTopLevelIndex);
+ QVERIFY(item != 0);
+ QCOMPARE(item->text(0), insertText.at(0));
+ QCOMPARE(testWidget->indexOfTopLevelItem(item), expectedTopLevelIndex);
+ }
+ }
+
+ { // test adding more children
+ QTreeWidgetItem *topLevel = testWidget->topLevelItem(0);
+ QVERIFY(topLevel != 0);
+ QTreeWidgetItem *child = new QTreeWidgetItem(QStringList(insertText.at(0)));
+ topLevel->insertChild(insertChildIndex, child);
+ if (expectedChildIndex == -1) {
+ QCOMPARE(topLevel->childCount(), initialText.count());
+ delete child;
+ } else {
+ QTreeWidgetItem *item = topLevel->child(expectedChildIndex);
+ QVERIFY(item != 0);
+ QCOMPARE(item->text(0), insertText.at(0));
+ }
+ }
+}
+
+static void fillTreeWidget(QTreeWidgetItem *parent, int rows)
+{
+ const int columns = parent->treeWidget()->columnCount();
+ for (int r = 0; r < rows; ++r) {
+ QTreeWidgetItem *w = new QTreeWidgetItem(parent);
+ for ( int c = 0; c < columns; ++c ) {
+ QString s = QString("[r:%1,c:%2]").arg(r).arg(c);
+ w->setText(c, s);
+ }
+ fillTreeWidget(w, rows - r - 1);
+ }
+}
+
+static void fillTreeWidget(QTreeWidget *tree, int rows)
+{
+ for (int r = 0; r < rows; ++r) {
+ QTreeWidgetItem *w = new QTreeWidgetItem();
+ for ( int c = 0; c < tree->columnCount(); ++c ) {
+ QString s = QString("[r:%1,c:%2]").arg(r).arg(c);
+ w->setText(c, s);
+ }
+ tree->insertTopLevelItem(r, w);
+ fillTreeWidget(w, rows - r - 1);
+ }
+}
+
+void tst_QTreeWidget::keyboardNavigation()
+{
+ int rows = 8;
+
+ fillTreeWidget(testWidget, rows);
+
+ QVector<Qt::Key> keymoves;
+ keymoves << Qt::Key_Down << Qt::Key_Right << Qt::Key_Left
+ << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down
+ << Qt::Key_Right
+ << Qt::Key_Up << Qt::Key_Left << Qt::Key_Left
+ << Qt::Key_Up << Qt::Key_Down << Qt::Key_Up << Qt::Key_Up
+ << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up
+ << Qt::Key_Down << Qt::Key_Right << Qt::Key_Down << Qt::Key_Down
+ << Qt::Key_Down << Qt::Key_Right << Qt::Key_Down << Qt::Key_Down
+ << Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down
+ << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Left
+ << Qt::Key_Down << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right
+ << Qt::Key_Left << Qt::Key_Left << Qt::Key_Right << Qt::Key_Left;
+
+ int row = 0;
+ QTreeWidgetItem *item = testWidget->topLevelItem(0);
+ testWidget->setCurrentItem(item);
+ QCOMPARE(testWidget->currentItem(), item);
+ QApplication::instance()->processEvents();
+
+ QScrollBar *scrollBar = testWidget->horizontalScrollBar();
+ bool checkScroll = false;
+ for (int i = 0; i < keymoves.size(); ++i) {
+ Qt::Key key = keymoves.at(i);
+ int valueBeforeClick = scrollBar->value();
+ if (valueBeforeClick >= scrollBar->singleStep())
+ checkScroll = true;
+ else
+ checkScroll = false;
+ QTest::keyClick(testWidget, key);
+ QApplication::instance()->processEvents();
+
+ switch (key) {
+ case Qt::Key_Up:
+ if (row > 0) {
+ if (item->parent())
+ item = item->parent()->child(row - 1);
+ else
+ item = testWidget->topLevelItem(row - 1);
+ row -= 1;
+ } else if (item->parent()) {
+ item = item->parent();
+ row = item->parent() ? item->parent()->indexOfChild(item) : testWidget->indexOfTopLevelItem(item);
+ }
+ break;
+ case Qt::Key_Down:
+ if (testWidget->isItemExpanded(item)) {
+ row = 0;
+ item = item->child(row);
+ } else {
+ row = qMin(rows - 1, row + 1);
+ if (item->parent())
+ item = item->parent()->child(row);
+ else
+ item = testWidget->topLevelItem(row);
+ }
+ break;
+ case Qt::Key_Left:
+ if (checkScroll) {
+ QVERIFY(testWidget->isItemExpanded(item));
+ QCOMPARE(scrollBar->value(), valueBeforeClick - scrollBar->singleStep());
+ }
+ // windows style right will walk to the parent
+ if (testWidget->currentItem() != item) {
+ QCOMPARE(testWidget->currentItem(), item->parent());
+ item = testWidget->currentItem();
+ row = item->parent() ? item->parent()->indexOfChild(item) : testWidget->indexOfTopLevelItem(item);;
+ }
+ break;
+ case Qt::Key_Right:
+ if (checkScroll)
+ QCOMPARE(scrollBar->value(), valueBeforeClick + scrollBar->singleStep());
+ // windows style right will walk to the first child
+ if (testWidget->currentItem() != item) {
+ QCOMPARE(testWidget->currentItem()->parent(), item);
+ row = item->indexOfChild(testWidget->currentItem());
+ item = testWidget->currentItem();
+ QCOMPARE(row, 0);
+ }
+ break;
+ default:
+ QVERIFY(false);
+ }
+
+ QTreeWidgetItem *current = testWidget->currentItem();
+ QCOMPARE(current->text(0), QString("[r:%1,c:0]").arg(row));
+ if (current->parent())
+ QCOMPARE(current->parent()->indexOfChild(current), row);
+ else
+ QCOMPARE(testWidget->indexOfTopLevelItem(current), row);
+ }
+}
+
+void tst_QTreeWidget::scrollToItem()
+{
+ // Check if all parent nodes of the item found are expanded.
+ // Reported in task #78761
+ QTreeWidgetItem *bar;
+ QTreeWidgetItem *search;
+ for (int i=0; i<2; ++i) {
+ bar = new QTreeWidgetItem(testWidget);
+ bar->setText(0, QString::number(i));
+
+ for (int j=0; j<2; ++j) {
+ QTreeWidgetItem *foo = new QTreeWidgetItem(bar);
+ foo->setText(0, bar->text(0) + QString::number(j));
+
+ for (int k=0; k<2; ++k) {
+ QTreeWidgetItem *yo = new QTreeWidgetItem(foo);
+ yo->setText(0, foo->text(0) + QString::number(k));
+ search = yo;
+ }
+ }
+ }
+
+ testWidget->setHeaderLabels(QStringList() << "foo");
+ testWidget->scrollToItem(search);
+ QVERIFY(search->text(0) == "111");
+
+ bar = search->parent();
+ QVERIFY(testWidget->isItemExpanded(bar));
+ bar = bar->parent();
+ QVERIFY(testWidget->isItemExpanded(bar));
+}
+
+// From task #85413
+void tst_QTreeWidget::setSortingEnabled()
+{
+ QStringList hl;
+ hl << "ID";
+ testWidget->setColumnCount(hl.count());
+ testWidget->setHeaderLabels(hl);
+
+ QTreeWidgetItem *item1 = new QTreeWidgetItem(testWidget);
+ QTreeWidgetItem *item2 = new QTreeWidgetItem(testWidget);
+
+ testWidget->setSortingEnabled(true);
+ QCOMPARE(testWidget->isSortingEnabled(), true);
+ QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
+ QCOMPARE(testWidget->topLevelItem(0), item1);
+ QCOMPARE(testWidget->topLevelItem(1), item2);
+
+ // Make sure we do it twice
+ testWidget->setSortingEnabled(true);
+ QCOMPARE(testWidget->isSortingEnabled(), true);
+ QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
+
+ testWidget->setSortingEnabled(false);
+ QCOMPARE(testWidget->isSortingEnabled(), false);
+ QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
+
+ testWidget->setSortingEnabled(false);
+ QCOMPARE(testWidget->isSortingEnabled(), false);
+ QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
+
+ // And back again so that we make sure that we test the transition from false to true
+ testWidget->setSortingEnabled(true);
+ QCOMPARE(testWidget->isSortingEnabled(), true);
+ QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
+
+ testWidget->setSortingEnabled(true);
+ QCOMPARE(testWidget->isSortingEnabled(), true);
+ QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
+
+ testWidget->setSortingEnabled(false);
+}
+
+void tst_QTreeWidget::addChild()
+{
+ QTreeWidget tree;
+ for (int x = 0; x < 2; ++x) {
+ QTreeWidget *view = x ? &tree : static_cast<QTreeWidget*>(0);
+ QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)view);
+ QCOMPARE(item->childCount(), 0);
+
+ // try to add 0
+ item->addChild(0);
+ QCOMPARE(item->childCount(), 0);
+ QCOMPARE(item->indexOfChild(0), -1);
+
+ // add one at a time
+ QList<QTreeWidgetItem*> children;
+ for (int i = 0; i < 10; ++i) {
+ QTreeWidgetItem *child = new QTreeWidgetItem();
+ item->addChild(child);
+ QCOMPARE(item->childCount(), i+1);
+ QCOMPARE(item->child(i), child);
+ QCOMPARE(item->indexOfChild(child), i);
+ QCOMPARE(child->parent(), item);
+ QCOMPARE(child->treeWidget(), view);
+ item->addChild(child);
+ QCOMPARE(item->childCount(), i+1);
+ children.append(child);
+ }
+
+ // take them all
+ QList<QTreeWidgetItem*> taken = item->takeChildren();
+ QCOMPARE(taken, children);
+ QCOMPARE(item->childCount(), 0);
+ for (int i = 0; i < taken.count(); ++i) {
+ QCOMPARE(taken.at(i)->parent(), static_cast<QTreeWidgetItem*>(0));
+ QCOMPARE(taken.at(i)->treeWidget(), static_cast<QTreeWidget*>(0));
+ item->addChild(taken.at(i)); // re-add
+ }
+
+ // delete one at a time
+ while (!children.isEmpty()) {
+ QTreeWidgetItem *ti = children.takeFirst();
+ delete ti;
+ QCOMPARE(item->childCount(), children.count());
+ for (int i = 0; i < children.count(); ++i)
+ QCOMPARE(item->child(i), children.at(i));
+ }
+
+ // add none
+ {
+ int count = item->childCount();
+ item->addChildren(QList<QTreeWidgetItem*>());
+ QCOMPARE(item->childCount(), count);
+ }
+
+ // add many at a time
+ const int count = 10;
+ for (int i = 0; i < 100; i += count) {
+ QList<QTreeWidgetItem*> list;
+ for (int j = 0; j < count; ++j)
+ list << new QTreeWidgetItem(QStringList() << QString("%0").arg(j));
+ item->addChildren(list);
+ QCOMPARE(item->childCount(), count + i);
+ for (int j = 0; j < count; ++j) {
+ QCOMPARE(item->child(i+j), list.at(j));
+ QCOMPARE(item->child(i+j)->parent(), item);
+ }
+
+ item->addChildren(list);
+ QCOMPARE(item->childCount(), count + i);
+ }
+
+ if (!view)
+ delete item;
+ }
+}
+
+void tst_QTreeWidget::setData()
+{
+ {
+ QTreeWidgetItem *headerItem = new QTreeWidgetItem();
+ headerItem->setText(0, "Item1");
+ testWidget->setHeaderItem(headerItem);
+
+ QSignalSpy headerDataChangedSpy(
+ testWidget->model(), SIGNAL(headerDataChanged(Qt::Orientation, int, int)));
+ QSignalSpy dataChangedSpy(
+ testWidget->model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+ QSignalSpy itemChangedSpy(
+ testWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
+ headerItem->setText(0, "test");
+ QCOMPARE(dataChangedSpy.count(), 0);
+ QCOMPARE(headerDataChangedSpy.count(), 1);
+ QCOMPARE(itemChangedSpy.count(), 0); // no itemChanged() signal for header item
+
+ headerItem->setData(-1, -1, QVariant());
+ }
+
+ {
+ QSignalSpy itemChangedSpy(
+ testWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
+ QTreeWidgetItem *item = new QTreeWidgetItem();
+ testWidget->addTopLevelItem(item);
+ for (int x = 0; x < 2; ++x) {
+ for (int i = 1; i <= 2; ++i) {
+ for (int j = 0; j < 5; ++j) {
+ QVariantList args;
+ QString text = QString("text %0").arg(i);
+ item->setText(j, text);
+ QCOMPARE(item->text(j), text);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setText(j, text);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QPixmap pixmap(32, 32);
+ pixmap.fill((i == 1) ? Qt::red : Qt::green);
+ QIcon icon(pixmap);
+ item->setIcon(j, icon);
+ QCOMPARE(item->icon(j), icon);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setIcon(j, icon);
+ // #### shouldn't cause dataChanged()
+ QCOMPARE(itemChangedSpy.count(), 1);
+ itemChangedSpy.clear();
+
+ QString toolTip = QString("toolTip %0").arg(i);
+ item->setToolTip(j, toolTip);
+ QCOMPARE(item->toolTip(j), toolTip);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setToolTip(j, toolTip);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QString statusTip = QString("statusTip %0").arg(i);
+ item->setStatusTip(j, statusTip);
+ QCOMPARE(item->statusTip(j), statusTip);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setStatusTip(j, statusTip);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QString whatsThis = QString("whatsThis %0").arg(i);
+ item->setWhatsThis(j, whatsThis);
+ QCOMPARE(item->whatsThis(j), whatsThis);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setWhatsThis(j, whatsThis);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QSize sizeHint(64*i, 48*i);
+ item->setSizeHint(j, sizeHint);
+ QCOMPARE(item->sizeHint(j), sizeHint);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setSizeHint(j, sizeHint);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QFont font;
+ item->setFont(j, font);
+ QCOMPARE(item->font(j), font);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setFont(j, font);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ Qt::Alignment textAlignment((i == 1)
+ ? Qt::AlignLeft|Qt::AlignVCenter
+ : Qt::AlignRight);
+ item->setTextAlignment(j, textAlignment);
+ QCOMPARE(item->textAlignment(j), int(textAlignment));
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setTextAlignment(j, textAlignment);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QColor backgroundColor((i == 1) ? Qt::blue : Qt::yellow);
+ item->setBackground(j, backgroundColor);
+ QCOMPARE(item->background(j).color(), backgroundColor);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setBackground(j, backgroundColor);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QColor textColor((i == i) ? Qt::green : Qt::cyan);
+ item->setTextColor(j, textColor);
+ QCOMPARE(item->textColor(j), textColor);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setTextColor(j, textColor);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ Qt::CheckState checkState((i == 1) ? Qt::PartiallyChecked : Qt::Checked);
+ item->setCheckState(j, checkState);
+ QCOMPARE(item->checkState(j), checkState);
+ QCOMPARE(itemChangedSpy.count(), 1);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setCheckState(j, checkState);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ QCOMPARE(item->text(j), text);
+ QCOMPARE(item->icon(j), icon);
+ QCOMPARE(item->toolTip(j), toolTip);
+ QCOMPARE(item->statusTip(j), statusTip);
+ QCOMPARE(item->whatsThis(j), whatsThis);
+ QCOMPARE(item->sizeHint(j), sizeHint);
+ QCOMPARE(item->font(j), font);
+ QCOMPARE(item->textAlignment(j), int(textAlignment));
+ QCOMPARE(item->background(j).color(), backgroundColor);
+ QCOMPARE(item->textColor(j), textColor);
+ QCOMPARE(item->checkState(j), checkState);
+
+ QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::DisplayRole)), text);
+ QCOMPARE(qvariant_cast<QIcon>(item->data(j, Qt::DecorationRole)), icon);
+ QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::ToolTipRole)), toolTip);
+ QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::StatusTipRole)), statusTip);
+ QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::WhatsThisRole)), whatsThis);
+ QCOMPARE(qvariant_cast<QSize>(item->data(j, Qt::SizeHintRole)), sizeHint);
+ QCOMPARE(qvariant_cast<QFont>(item->data(j, Qt::FontRole)), font);
+ QCOMPARE(qvariant_cast<int>(item->data(j, Qt::TextAlignmentRole)), int(textAlignment));
+ QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundColorRole)), QBrush(backgroundColor));
+ QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundRole)), QBrush(backgroundColor));
+ QCOMPARE(qvariant_cast<QColor>(item->data(j, Qt::TextColorRole)), textColor);
+ QCOMPARE(qvariant_cast<int>(item->data(j, Qt::CheckStateRole)), int(checkState));
+
+ item->setBackground(j, pixmap);
+ QCOMPARE(item->background(j).texture(), pixmap);
+ QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundRole)).texture(), pixmap);
+ args = itemChangedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
+ QCOMPARE(qvariant_cast<int>(args.at(1)), j);
+ item->setBackground(j, pixmap);
+ QCOMPARE(itemChangedSpy.count(), 0);
+
+ item->setData(j, Qt::DisplayRole, QVariant());
+ item->setData(j, Qt::DecorationRole, QVariant());
+ item->setData(j, Qt::ToolTipRole, QVariant());
+ item->setData(j, Qt::StatusTipRole, QVariant());
+ item->setData(j, Qt::WhatsThisRole, QVariant());
+ item->setData(j, Qt::SizeHintRole, QVariant());
+ item->setData(j, Qt::FontRole, QVariant());
+ item->setData(j, Qt::TextAlignmentRole, QVariant());
+ item->setData(j, Qt::BackgroundColorRole, QVariant());
+ item->setData(j, Qt::TextColorRole, QVariant());
+ item->setData(j, Qt::CheckStateRole, QVariant());
+ QCOMPARE(itemChangedSpy.count(), 11);
+ itemChangedSpy.clear();
+
+ QCOMPARE(item->data(j, Qt::DisplayRole).toString(), QString());
+ QCOMPARE(item->data(j, Qt::DecorationRole), QVariant());
+ QCOMPARE(item->data(j, Qt::ToolTipRole), QVariant());
+ QCOMPARE(item->data(j, Qt::StatusTipRole), QVariant());
+ QCOMPARE(item->data(j, Qt::WhatsThisRole), QVariant());
+ QCOMPARE(item->data(j, Qt::SizeHintRole), QVariant());
+ QCOMPARE(item->data(j, Qt::FontRole), QVariant());
+ QCOMPARE(item->data(j, Qt::TextAlignmentRole), QVariant());
+ QCOMPARE(item->data(j, Qt::BackgroundColorRole), QVariant());
+ QCOMPARE(item->data(j, Qt::BackgroundRole), QVariant());
+ QCOMPARE(item->data(j, Qt::TextColorRole), QVariant());
+ QCOMPARE(item->data(j, Qt::CheckStateRole), QVariant());
+ }
+ }
+ }
+
+ // ### add more data types here
+
+ item->setData(0, Qt::DisplayRole, 5);
+ QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::Int);
+
+ item->setData(0, Qt::DisplayRole, "test");
+ QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::String);
+
+ item->setData(0, Qt::DisplayRole, 0.4);
+ QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::Double);
+
+ delete item;
+ }
+}
+
+void tst_QTreeWidget::itemData()
+{
+ QTreeWidget widget;
+ QTreeWidgetItem item(&widget);
+ widget.setColumnCount(2);
+ item.setFlags(item.flags() | Qt::ItemIsEditable);
+ item.setData(0, Qt::DisplayRole, QString("0"));
+ item.setData(0, Qt::CheckStateRole, Qt::PartiallyChecked);
+ item.setData(0, Qt::UserRole + 0, QString("1"));
+ item.setData(0, Qt::UserRole + 1, QString("2"));
+ item.setData(0, Qt::UserRole + 2, QString("3"));
+ item.setData(0, Qt::UserRole + 3, QString("4"));
+
+ QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0));
+ QCOMPARE(flags.count(), 6);
+ QCOMPARE(flags[Qt::UserRole + 0].toString(), QString("1"));
+
+ flags = widget.model()->itemData(widget.model()->index(0, 1));
+ QCOMPARE(flags.count(), 0);
+}
+
+void tst_QTreeWidget::enableDisable()
+{
+ QTreeWidgetItem *itm = new QTreeWidgetItem();
+ for (int i = 0; i < 10; ++i)
+ new QTreeWidgetItem(itm);
+
+ // make sure all items are enabled
+ QVERIFY(itm->flags() & Qt::ItemIsEnabled);
+ for (int j = 0; j < itm->childCount(); ++j)
+ QVERIFY(itm->child(j)->flags() & Qt::ItemIsEnabled);
+
+ // disable root and make sure they are all disabled
+ itm->setFlags(itm->flags() & ~Qt::ItemIsEnabled);
+ QVERIFY(!(itm->flags() & Qt::ItemIsEnabled));
+ for (int k = 0; k < itm->childCount(); ++k)
+ QVERIFY(!(itm->child(k)->flags() & Qt::ItemIsEnabled));
+
+ // disable a child and make sure they are all still disabled
+ itm->child(5)->setFlags(itm->child(5)->flags() & ~Qt::ItemIsEnabled);
+ QVERIFY(!(itm->flags() & Qt::ItemIsEnabled));
+ for (int l = 0; l < itm->childCount(); ++l)
+ QVERIFY(!(itm->child(l)->flags() & Qt::ItemIsEnabled));
+
+ // enable root and make sure all items except one are enabled
+ itm->setFlags(itm->flags() | Qt::ItemIsEnabled);
+ QVERIFY(itm->flags() & Qt::ItemIsEnabled);
+ for (int m = 0; m < itm->childCount(); ++m)
+ if (m == 5)
+ QVERIFY(!(itm->child(m)->flags() & Qt::ItemIsEnabled));
+ else
+ QVERIFY(itm->child(m)->flags() & Qt::ItemIsEnabled);
+}
+
+void tst_QTreeWidget::match()
+{
+ QTreeWidget tree;
+ QModelIndexList list = tree.model()->match(QModelIndex(), Qt::DisplayRole, QString());
+
+ QVERIFY(list.isEmpty());
+}
+
+void tst_QTreeWidget::columnCount()
+{
+ int columnCountBefore = testWidget->columnCount();
+ testWidget->setColumnCount(-1);
+ QCOMPARE(testWidget->columnCount(), columnCountBefore);
+}
+
+void tst_QTreeWidget::setHeaderLabels()
+{
+ QStringList list = QString("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z").split(",");
+ testWidget->setHeaderLabels(list);
+ QCOMPARE(testWidget->header()->count(), list.count());
+}
+
+void tst_QTreeWidget::setHeaderItem()
+{
+ testWidget->setHeaderItem(0);
+ QTreeWidgetItem *headerItem = new QTreeWidgetItem();
+
+ testWidget->setColumnCount(0);
+ QCOMPARE(testWidget->header()->count(), 0);
+ QCOMPARE(testWidget->columnCount(), 0);
+
+ headerItem->setText(0, "0");
+ headerItem->setText(1, "1");
+ testWidget->setHeaderItem(headerItem);
+ QTest::qWait(100);
+ QCOMPARE(testWidget->headerItem(), headerItem);
+ QCOMPARE(headerItem->treeWidget(), static_cast<QTreeWidget *>(testWidget));
+
+ QCOMPARE(testWidget->header()->count(), 2);
+ QCOMPARE(testWidget->columnCount(), 2);
+
+ headerItem->setText(2, "2");
+ QCOMPARE(testWidget->header()->count(), 3);
+ QCOMPARE(testWidget->columnCount(), 3);
+
+ delete headerItem;
+ testWidget->setColumnCount(3);
+ testWidget->setColumnCount(5);
+ QCOMPARE(testWidget->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), QString("1"));
+ QCOMPARE(testWidget->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), QString("2"));
+ QCOMPARE(testWidget->model()->headerData(2, Qt::Horizontal, Qt::DisplayRole).toString(), QString("3"));
+ QCOMPARE(testWidget->model()->headerData(3, Qt::Horizontal, Qt::DisplayRole).toString(), QString("4"));
+ QCOMPARE(testWidget->model()->headerData(4, Qt::Horizontal, Qt::DisplayRole).toString(), QString("5"));
+
+ headerItem = new QTreeWidgetItem();
+ testWidget->setHeaderItem(headerItem);
+ testWidget->model()->insertColumns(0, 5, QModelIndex());
+ QCOMPARE(testWidget->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), QString("1"));
+ QCOMPARE(testWidget->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), QString("2"));
+ QCOMPARE(testWidget->model()->headerData(2, Qt::Horizontal, Qt::DisplayRole).toString(), QString("3"));
+ QCOMPARE(testWidget->model()->headerData(3, Qt::Horizontal, Qt::DisplayRole).toString(), QString("4"));
+ QCOMPARE(testWidget->model()->headerData(4, Qt::Horizontal, Qt::DisplayRole).toString(), QString("5"));
+}
+
+void tst_QTreeWidget::itemWidget_data()
+{
+ editItem_data();
+}
+
+void tst_QTreeWidget::itemWidget()
+{
+ QFETCH(TreeItemList, topLevelItems);
+
+ QTreeWidget tree;
+ populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2"));
+ tree.show();
+
+ for (int x = 0; x < 2; ++x) {
+ QTreeWidgetItemIterator it(&tree);
+ while (QTreeWidgetItem *item = (*it++)) {
+ for (int col = 0; col < item->columnCount(); ++col) {
+ if (x == 0) {
+ QCOMPARE(tree.itemWidget(item, col), static_cast<QWidget*>(0));
+ QWidget *editor = new QLineEdit();
+ tree.setItemWidget(item, col, editor);
+ QCOMPARE(tree.itemWidget(item, col), editor);
+ tree.removeItemWidget(item, col);
+ QCOMPARE(tree.itemWidget(item, col), static_cast<QWidget*>(0));
+ } else {
+ // ### should you really be able to open a persistent
+ // editor for an item that isn't editable??
+ tree.openPersistentEditor(item, col);
+ QWidget *editor = qFindChild<QLineEdit*>(&tree);
+ QVERIFY(editor != 0);
+ tree.closePersistentEditor(item, col);
+ }
+ }
+ }
+ }
+}
+
+void tst_QTreeWidget::insertItemsWithSorting_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<QStringList>("insertItems");
+ QTest::addColumn<QStringList>("expectedItems");
+ QTest::addColumn<IntList>("expectedRows");
+
+ QTest::newRow("() + (a) = (a)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList()
+ << (QStringList() << "a")
+ << (QStringList() << "a")
+ << IntList();
+ QTest::newRow("() + (c, b, a) = (a, b, c)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList()
+ << (QStringList() << "c" << "b" << "a")
+ << (QStringList() << "a" << "b" << "c")
+ << IntList();
+ QTest::newRow("() + (a, b, c) = (c, b, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QStringList()
+ << (QStringList() << "a" << "b" << "c")
+ << (QStringList() << "c" << "b" << "a")
+ << IntList();
+ QTest::newRow("(a) + (b) = (a, b)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList("a")
+ << (QStringList() << "b")
+ << (QStringList() << "a" << "b")
+ << (IntList() << 0);
+ QTest::newRow("(a) + (b) = (b, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QStringList("a")
+ << (QStringList() << "b")
+ << (QStringList() << "b" << "a")
+ << (IntList() << 1);
+ QTest::newRow("(a, c, b) + (d) = (a, b, c, d)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "b")
+ << (QStringList() << "d")
+ << (QStringList() << "a" << "b" << "c" << "d")
+ << (IntList() << 0 << 1 << 2);
+ QTest::newRow("(b, c, a) + (d) = (d, c, b, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "b" << "c" << "a")
+ << (QStringList() << "d")
+ << (QStringList() << "d" << "c" << "b" << "a")
+ << (IntList() << 1 << 2 << 3);
+ {
+ IntList ascendingRows;
+ IntList reverseRows;
+ QStringList ascendingItems;
+ QStringList reverseItems;
+ for (int i = 'a'; i <= 'z'; ++i) {
+ ascendingItems << QString("%0").arg(QLatin1Char(i));
+ reverseItems << QString("%0").arg(QLatin1Char('z' - i + 'a'));
+ ascendingRows << i - 'a';
+ reverseRows << 'z' - i + 'a';
+ }
+ QTest::newRow("() + (sorted items) = (sorted items)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QStringList()
+ << ascendingItems
+ << ascendingItems
+ << IntList();
+ QTest::newRow("(sorted items) + () = (sorted items)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << ascendingItems
+ << QStringList()
+ << ascendingItems
+ << ascendingRows;
+ QTest::newRow("() + (ascending items) = (reverse items)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QStringList()
+ << ascendingItems
+ << reverseItems
+ << IntList();
+ QTest::newRow("(reverse items) + () = (ascending items)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << reverseItems
+ << QStringList()
+ << ascendingItems
+ << ascendingRows;
+ QTest::newRow("(reverse items) + () = (reverse items)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << reverseItems
+ << QStringList()
+ << reverseItems
+ << ascendingRows;
+ }
+}
+
+void tst_QTreeWidget::insertItemsWithSorting()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initialItems);
+ QFETCH(QStringList, insertItems);
+ QFETCH(QStringList, expectedItems);
+ QFETCH(IntList, expectedRows);
+
+ for (int method = 0; method < 5; ++method) {
+ QTreeWidget w;
+ w.setSortingEnabled(true);
+ w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder));
+ for (int i = 0; i < initialItems.count(); ++i)
+ w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i)));
+
+ QAbstractItemModel *model = w.model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ switch (method) {
+ case 0:
+ // insert using item constructor
+ for (int i = 0; i < insertItems.size(); ++i)
+ new QTreeWidgetItem(&w, QStringList() << insertItems.at(i));
+ break;
+ case 1:
+ {
+ // insert using insertTopLevelItems()
+ QList<QTreeWidgetItem*> lst;
+ for (int i = 0; i < insertItems.size(); ++i)
+ lst << new QTreeWidgetItem(QStringList() << insertItems.at(i));
+ w.insertTopLevelItems(0, lst);
+ break;
+ }
+ case 2:
+ // insert using insertTopLevelItem()
+ for (int i = 0; i < insertItems.size(); ++i)
+ w.insertTopLevelItem(0, new QTreeWidgetItem(QStringList() << insertItems.at(i)));
+ break;
+ case 3:
+ {
+ // insert using addTopLevelItems()
+ QList<QTreeWidgetItem*> lst;
+ for (int i = 0; i < insertItems.size(); ++i)
+ lst << new QTreeWidgetItem(QStringList() << insertItems.at(i));
+ w.addTopLevelItems(lst);
+ break;
+ }
+ case 4:
+ // insert using addTopLevelItem()
+ for (int i = 0; i < insertItems.size(); ++i)
+ w.addTopLevelItem(new QTreeWidgetItem(QStringList() << insertItems.at(i)));
+ break;
+ }
+ QCOMPARE(w.topLevelItemCount(), expectedItems.count());
+ for (int i = 0; i < w.topLevelItemCount(); ++i)
+ QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i));
+
+ for (int k = 0; k < persistent.count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+ }
+}
+
+void tst_QTreeWidget::insertExpandedItemsWithSorting_data()
+{
+ QTest::addColumn<QStringList>("parentText");
+ QTest::addColumn<QStringList>("childText");
+ QTest::addColumn<QStringList>("parentResult");
+ QTest::addColumn<QStringList>("childResult");
+ QTest::newRow("test 1")
+ << (QStringList() << "c" << "d" << "a" << "b")
+ << (QStringList() << "e" << "h" << "g" << "f")
+ << (QStringList() << "d" << "c" << "b" << "a")
+ << (QStringList() << "h" << "g" << "f" << "e");
+}
+
+// From Task 134978
+void tst_QTreeWidget::insertExpandedItemsWithSorting()
+{
+ QFETCH(QStringList, parentText);
+ QFETCH(QStringList, childText);
+ QFETCH(QStringList, parentResult);
+ QFETCH(QStringList, childResult);
+
+ // create a tree with autosorting enabled
+ CustomTreeWidget tree;
+ tree.setSortingEnabled(true);
+
+ // insert expanded items in unsorted order
+ QList<QTreeWidgetItem *> items;
+ for (int i = 0; i < parentText.count(); ++i) {
+ QTreeWidgetItem *parent = new QTreeWidgetItem(&tree, QStringList(parentText.at(i)));
+ parent->setExpanded(true);
+ QVERIFY(parent->isExpanded());
+ items << parent;
+ for (int j = 0; j < childText.count(); ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(parent, QStringList(childText.at(j)));
+ items << child;
+ }
+ QCOMPARE(parent->childCount(), childText.count());
+ QVERIFY(parent->isExpanded());
+ }
+ QVERIFY(tree.model()->rowCount() == parentText.count());
+
+ // verify that the items are still expanded
+ foreach (QTreeWidgetItem *item, items) {
+ if (item->childCount() > 0)
+ QVERIFY(item->isExpanded());
+ QModelIndex idx = tree.indexFromItem(const_cast<QTreeWidgetItem *>(item));
+ QVERIFY(idx.isValid());
+ //QRect rect = tree.visualRect(idx);
+ //QVERIFY(rect.isValid());
+ // ### it is not guarantied that the index is in the viewport
+ }
+
+ // verify that the tree is sorted
+ QAbstractItemModel *model = tree.model();
+ QList<QPersistentModelIndex> parents;
+ for (int i = 0; i < model->rowCount(QModelIndex()); ++i) {
+ QPersistentModelIndex parent = model->index(i, 0, QModelIndex());
+ parents << parent;
+ }
+ QList<QPersistentModelIndex> children;
+ for (int i = 0; i < model->rowCount(parents.first()); ++i) {
+ QPersistentModelIndex child = model->index(i, 0, parents.first());
+ children << child;
+ }
+ for (int i = 0; i < parentResult.count(); ++i) {
+ QTreeWidgetItem *item = tree.topLevelItem(i);
+ QCOMPARE(item->text(0), parentResult.at(i));
+ for (int j = 0; j < childResult.count(); ++j)
+ QCOMPARE(item->child(j)->text(0), childResult.at(j));
+ }
+}
+
+void tst_QTreeWidget::changeDataWithSorting_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<int>("itemIndex");
+ QTest::addColumn<QString>("newValue");
+ QTest::addColumn<QStringList>("expectedItems");
+ QTest::addColumn<IntList>("expectedRows");
+ QTest::addColumn<bool>("reorderingExpected");
+
+ QTest::newRow("change a to b in (a)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a")
+ << 0 << "b"
+ << (QStringList() << "b")
+ << (IntList() << 0)
+ << false;
+ QTest::newRow("change a to b in (a, c)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c")
+ << 0 << "b"
+ << (QStringList() << "b" << "c")
+ << (IntList() << 0 << 1)
+ << false;
+ QTest::newRow("change a to c in (a, b)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "b")
+ << 0 << "c"
+ << (QStringList() << "b" << "c")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("change c to a in (c, b)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "c" << "b")
+ << 0 << "a"
+ << (QStringList() << "b" << "a")
+ << (IntList() << 1 << 0)
+ << true;
+ QTest::newRow("change e to i in (a, c, e, g)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "e" << "g")
+ << 2 << "i"
+ << (QStringList() << "a" << "c" << "g" << "i")
+ << (IntList() << 0 << 1 << 3 << 2)
+ << true;
+ QTest::newRow("change e to a in (c, e, g, i)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "e" << "g" << "i")
+ << 1 << "a"
+ << (QStringList() << "a" << "c" << "g" << "i")
+ << (IntList() << 1 << 0 << 2 << 3)
+ << true;
+ QTest::newRow("change e to f in (c, e, g, i)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "c" << "e" << "g" << "i")
+ << 1 << "f"
+ << (QStringList() << "c" << "f" << "g" << "i")
+ << (IntList() << 0 << 1 << 2 << 3)
+ << false;
+}
+
+void tst_QTreeWidget::changeDataWithSorting()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initialItems);
+ QFETCH(int, itemIndex);
+ QFETCH(QString, newValue);
+ QFETCH(QStringList, expectedItems);
+ QFETCH(IntList, expectedRows);
+ QFETCH(bool, reorderingExpected);
+
+ QTreeWidget w;
+ w.setSortingEnabled(true);
+ w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder));
+ for (int i = 0; i < initialItems.count(); ++i)
+ w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i)));
+
+ QAbstractItemModel *model = w.model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+ QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
+
+ QTreeWidgetItem *item = w.topLevelItem(itemIndex);
+ item->setText(0, newValue);
+ for (int i = 0; i < expectedItems.count(); ++i) {
+ QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i));
+ for (int j = 0; j < persistent.count(); ++j) {
+ if (persistent.at(j).row() == i) // the same toplevel row
+ QCOMPARE(persistent.at(j).internalPointer(), (void *)w.topLevelItem(i));
+ }
+ }
+
+ for (int k = 0; k < persistent.count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0);
+}
+
+void tst_QTreeWidget::changeDataWithStableSorting_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("initialItems");
+ QTest::addColumn<int>("itemIndex");
+ QTest::addColumn<QString>("newValue");
+ QTest::addColumn<QStringList>("expectedItems");
+ QTest::addColumn<IntList>("expectedRows");
+ QTest::addColumn<bool>("reorderingExpected");
+ QTest::addColumn<bool>("forceChange");
+
+ QTest::newRow("change a to c in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 0 << "c"
+ << (QStringList() << "c" << "c" << "c" << "c" << "e")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << false;
+ QTest::newRow("change e to c in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 4 << "c"
+ << (QStringList() << "a" << "c" << "c" << "c" << "c")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << false;
+ QTest::newRow("change 1st c to c in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 1 << "c"
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << true;
+ QTest::newRow("change 2nd c to c in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 2 << "c"
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << true;
+ QTest::newRow("change 3rd c to c in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 3 << "c"
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << true;
+ QTest::newRow("change 1st c to c in (e, c, c, c, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "e" << "c" << "c" << "c" << "a")
+ << 1 << "c"
+ << (QStringList() << "e" << "c" << "c" << "c" << "a")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << true;
+ QTest::newRow("change 2nd c to c in (e, c, c, c, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "e" << "c" << "c" << "c" << "a")
+ << 2 << "c"
+ << (QStringList() << "e" << "c" << "c" << "c" << "a")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << true;
+ QTest::newRow("change 3rd c to c in (e, c, c, c, a)")
+ << static_cast<int>(Qt::DescendingOrder)
+ << (QStringList() << "e" << "c" << "c" << "c" << "a")
+ << 3 << "c"
+ << (QStringList() << "e" << "c" << "c" << "c" << "a")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << true;
+ QTest::newRow("change 1st c to b in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 1 << "b"
+ << (QStringList() << "a" << "b" << "c" << "c" << "e")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << false;
+ QTest::newRow("change 2nd c to b in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 2 << "b"
+ << (QStringList() << "a" << "b" << "c" << "c" << "e")
+ << (IntList() << 0 << 2 << 1 << 3 << 4)
+ << true
+ << false;
+ QTest::newRow("change 3rd c to b in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 3 << "b"
+ << (QStringList() << "a" << "b" << "c" << "c" << "e")
+ << (IntList() << 0 << 2 << 3 << 1 << 4)
+ << true
+ << false;
+ QTest::newRow("change 1st c to d in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 1 << "d"
+ << (QStringList() << "a" << "c" << "c" << "d" << "e")
+ << (IntList() << 0 << 3 << 1 << 2 << 4)
+ << true
+ << false;
+ QTest::newRow("change 2nd c to d in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 2 << "d"
+ << (QStringList() << "a" << "c" << "c" << "d" << "e")
+ << (IntList() << 0 << 1 << 3 << 2 << 4)
+ << true
+ << false;
+ QTest::newRow("change 3rd c to d in (a, c, c, c, e)")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "c" << "c" << "c" << "e")
+ << 3 << "d"
+ << (QStringList() << "a" << "c" << "c" << "d" << "e")
+ << (IntList() << 0 << 1 << 2 << 3 << 4)
+ << false
+ << false;
+}
+
+void tst_QTreeWidget::changeDataWithStableSorting()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, initialItems);
+ QFETCH(int, itemIndex);
+ QFETCH(QString, newValue);
+ QFETCH(QStringList, expectedItems);
+ QFETCH(IntList, expectedRows);
+ QFETCH(bool, reorderingExpected);
+ QFETCH(bool, forceChange);
+
+ class StableItem : public QTreeWidgetItem
+ {
+ public:
+ StableItem(const QStringList &strings) : QTreeWidgetItem(strings, QTreeWidgetItem::UserType) {}
+ void forceChangeData() {
+ emitDataChanged();
+ }
+ };
+
+ QTreeWidget w;
+ w.setSortingEnabled(true);
+ w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder));
+ for (int i = 0; i < initialItems.count(); ++i)
+ w.addTopLevelItem(new StableItem(QStringList() << initialItems.at(i)));
+
+ QAbstractItemModel *model = w.model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)));
+ QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
+
+ StableItem *item = static_cast<StableItem *>(w.topLevelItem(itemIndex));
+ item->setText(0, newValue);
+ if (forceChange)
+ item->forceChangeData();
+ for (int i = 0; i < expectedItems.count(); ++i) {
+ QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i));
+ for (int j = 0; j < persistent.count(); ++j) {
+ if (persistent.at(j).row() == i) // the same toplevel row
+ QCOMPARE(persistent.at(j).internalPointer(), (void *)w.topLevelItem(i));
+ }
+ }
+
+ for (int k = 0; k < persistent.count(); ++k)
+ QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
+
+ QCOMPARE(dataChangedSpy.count(), 1);
+ QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0);
+}
+
+void tst_QTreeWidget::itemOperatorLessThan()
+{
+ QTreeWidget tw;
+ tw.setColumnCount(2);
+ {
+ QTreeWidgetItem item1(&tw);
+ QTreeWidgetItem item2(&tw);
+ QCOMPARE(item1 < item2, false);
+ item1.setText(1, "a");
+ item2.setText(1, "b");
+ QCOMPARE(item1 < item2, false);
+ item1.setText(0, "a");
+ item2.setText(0, "b");
+ QCOMPARE(item1 < item2, true);
+ tw.sortItems(1, Qt::AscendingOrder);
+ item1.setText(0, "b");
+ item2.setText(0, "a");
+ QCOMPARE(item1 < item2, true);
+ tw.sortItems(0, Qt::AscendingOrder);
+ item1.setData(0, Qt::DisplayRole, 11);
+ item2.setData(0, Qt::DisplayRole, 2);
+ QCOMPARE(item1 < item2, false);
+ }
+}
+
+void tst_QTreeWidget::sortedIndexOfChild_data()
+{
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("itemTexts");
+ QTest::addColumn<QList<int> >("expectedIndexes");
+
+ QTest::newRow("three ascending")
+ << int(Qt::AscendingOrder)
+ << (QStringList() << "A" << "B" << "C")
+ << (QList<int>() << 0 << 1 << 2);
+
+
+ QTest::newRow("three descending")
+ << int(Qt::DescendingOrder)
+ << (QStringList() << "A" << "B" << "C")
+ << (QList<int>() << 2 << 1 << 0);
+}
+
+void tst_QTreeWidget::sortedIndexOfChild()
+{
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, itemTexts);
+ QFETCH(QList<int>, expectedIndexes);
+
+ QTreeWidget tw;
+ QList<QTreeWidgetItem*> itms;
+ QTreeWidgetItem *top = new QTreeWidgetItem(&tw, QStringList() << "top");
+
+ for (int i = 0; i < itemTexts.count(); ++i)
+ itms << new QTreeWidgetItem(top, QStringList() << itemTexts.at(i));
+
+ tw.sortItems(0, (Qt::SortOrder)sortOrder);
+ tw.expandAll();
+
+ QVERIFY(itms.count() == expectedIndexes.count());
+ for (int j = 0; j < expectedIndexes.count(); ++j)
+ QCOMPARE(top->indexOfChild(itms.at(j)), expectedIndexes.at(j));
+}
+
+void tst_QTreeWidget::expandAndCallapse()
+{
+ QTreeWidget tw;
+ QTreeWidgetItem *top = new QTreeWidgetItem(&tw, QStringList() << "top");
+ QTreeWidgetItem *p;
+ for (int i = 0; i < 10; ++i) {
+ p = new QTreeWidgetItem(top, QStringList() << QString("%1").arg(i));
+ for (int j = 0; j < 10; ++j)
+ new QTreeWidgetItem(p, QStringList() << QString("%1").arg(j));
+ }
+ QSignalSpy spy0(&tw, SIGNAL(itemExpanded(QTreeWidgetItem *)));
+ QSignalSpy spy1(&tw, SIGNAL(itemCollapsed(QTreeWidgetItem *)));
+
+
+ tw.expandItem(p);
+ tw.collapseItem(p);
+ tw.expandItem(p);
+ tw.expandItem(top);
+ tw.collapseItem(top);
+ tw.collapseItem(top);
+
+ QCOMPARE(spy0.count(), 3);
+ QCOMPARE(spy1.count(), 2);
+}
+
+void tst_QTreeWidget::setDisabled()
+{
+ QTreeWidget w;
+ QTreeWidgetItem *i1 = new QTreeWidgetItem();
+ QTreeWidgetItem *i2 = new QTreeWidgetItem(i1);
+ QTreeWidgetItem *i3 = new QTreeWidgetItem(i1);
+
+ QTreeWidgetItem *top = new QTreeWidgetItem(&w);
+ top->setDisabled(true);
+ top->addChild(i1);
+ QCOMPARE(i1->isDisabled(), true);
+ QCOMPARE(i2->isDisabled(), true);
+ QCOMPARE(i3->isDisabled(), true);
+
+ i1 = top->takeChild(0);
+ QCOMPARE(i1->isDisabled(), false);
+ QCOMPARE(i2->isDisabled(), false);
+ QCOMPARE(i3->isDisabled(), false);
+
+ top->addChild(i1);
+ QCOMPARE(i1->isDisabled(), true);
+ QCOMPARE(i2->isDisabled(), true);
+ QCOMPARE(i3->isDisabled(), true);
+
+ top->setDisabled(false);
+ QCOMPARE(i1->isDisabled(), false);
+ QCOMPARE(i2->isDisabled(), false);
+ QCOMPARE(i3->isDisabled(), false);
+
+
+
+ QList<QTreeWidgetItem*> children;
+ children.append(new QTreeWidgetItem());
+ children.append(new QTreeWidgetItem());
+ children.append(new QTreeWidgetItem());
+ i1 = top->takeChild(0);
+
+ top->addChildren(children);
+ QCOMPARE(top->child(0)->isDisabled(), false);
+ QCOMPARE(top->child(1)->isDisabled(), false);
+ QCOMPARE(top->child(1)->isDisabled(), false);
+
+ top->setDisabled(true);
+ QCOMPARE(top->child(0)->isDisabled(), true);
+ QCOMPARE(top->child(1)->isDisabled(), true);
+ QCOMPARE(top->child(1)->isDisabled(), true);
+
+ children = top->takeChildren();
+ QCOMPARE(children.at(0)->isDisabled(), false);
+ QCOMPARE(children.at(1)->isDisabled(), false);
+ QCOMPARE(children.at(1)->isDisabled(), false);
+
+}
+
+void tst_QTreeWidget::removeSelectedItem()
+{
+ QTreeWidget *w = new QTreeWidget();
+ w->setSortingEnabled(true);
+
+ QTreeWidgetItem *first = new QTreeWidgetItem();
+ first->setText(0, QLatin1String("D"));
+ w->addTopLevelItem(first);
+
+ QTreeWidgetItem *itm = new QTreeWidgetItem();
+ itm->setText(0, QLatin1String("D"));
+ w->addTopLevelItem(itm);
+
+ itm = new QTreeWidgetItem();
+ itm->setText(0, QLatin1String("C"));
+ w->addTopLevelItem(itm);
+ itm->setSelected(true);
+
+ itm = new QTreeWidgetItem();
+ itm->setText(0, QLatin1String("A"));
+ w->addTopLevelItem(itm);
+
+ //w->show();
+
+ QItemSelectionModel *selModel = w->selectionModel();
+ QCOMPARE(selModel->hasSelection(), true);
+ QCOMPARE(selModel->selectedRows().count(), 1);
+
+ QTreeWidgetItem *taken = w->takeTopLevelItem(2);
+ QCOMPARE(taken->text(0), QLatin1String("C"));
+
+ QCOMPARE(selModel->hasSelection(), false);
+ QCOMPARE(selModel->selectedRows().count(), 0);
+ QItemSelection sel = selModel->selection();
+ QCOMPARE(selModel->isSelected(w->model()->index(0,0)), false);
+
+ delete w;
+}
+
+class AnotherTreeWidget : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ AnotherTreeWidget(QWidget *parent = 0) : QTreeWidget(parent) {}
+ void deleteCurrent() { if (currentItem()) delete currentItem(); }
+};
+
+void tst_QTreeWidget::removeCurrentItem()
+{
+ AnotherTreeWidget widget;
+ QObject::connect(widget.selectionModel(),
+ SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ &widget, SLOT(clear()));
+ QTreeWidgetItem *item = new QTreeWidgetItem(&widget);
+ widget.setCurrentItem(item);
+ widget.deleteCurrent();
+}
+
+void tst_QTreeWidget::removeCurrentItem_task186451()
+{
+ AnotherTreeWidget widget;
+ QTreeWidgetItem *item = new QTreeWidgetItem(&widget, QStringList() << "1");
+ QTreeWidgetItem *item2 = new QTreeWidgetItem(&widget, QStringList() << "2");
+ widget.setCurrentItem(item);
+ widget.deleteCurrent();
+
+ QVERIFY(item2->isSelected());
+ QCOMPARE(item2, widget.currentItem());
+}
+
+
+class TreeWidget : QTreeWidget {
+
+public:
+ QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const {
+ return QTreeWidget::indexFromItem(item, column);
+ }
+ QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const {
+ return QTreeWidget::itemFromIndex(index);
+ }
+};
+
+
+void tst_QTreeWidget::randomExpand()
+{
+ QTreeWidget tree;
+ QTreeWidgetItem *item1 = new QTreeWidgetItem(&tree);
+ QTreeWidgetItem *item3 = new QTreeWidgetItem(&tree, item1);
+ new QTreeWidgetItem(item1);
+ new QTreeWidgetItem(item3);
+
+ tree.expandAll();
+
+ /*
+ item1
+ \- item2
+ item3
+ \- item4
+ */
+
+ QTreeWidgetItem *newItem1 = 0;
+ for (int i = 0; i < 100; i++) {
+ newItem1 = new QTreeWidgetItem(&tree, item1);
+ tree.setItemExpanded(newItem1, true);
+ QCOMPARE(tree.isItemExpanded(newItem1), true);
+
+ QTreeWidgetItem *x = new QTreeWidgetItem();
+ QCOMPARE(tree.isItemExpanded(newItem1), true);
+ newItem1->addChild(x);
+
+ QCOMPARE(tree.isItemExpanded(newItem1), true);
+ }
+
+}
+
+void tst_QTreeWidget::crashTest()
+{
+ QTreeWidget *tree = new QTreeWidget();
+ tree->setColumnCount(1);
+ tree->show();
+
+ QTreeWidgetItem *item1 = new QTreeWidgetItem(tree);
+ item1->setText(0, "item1");
+ tree->setItemExpanded(item1, true);
+ QTreeWidgetItem *item2 = new QTreeWidgetItem(item1);
+ item2->setText(0, "item2");
+
+ QTreeWidgetItem *item3 = new QTreeWidgetItem(tree, item1);
+ item3->setText(0, "item3");
+ tree->setItemExpanded(item3, true);
+ QTreeWidgetItem *item4 = new QTreeWidgetItem(item3);
+ item4->setText(0, "item4");
+
+ QTreeWidgetItem *item5 = new QTreeWidgetItem(tree, item3);
+ item5->setText(0, "item5");
+ tree->setItemExpanded(item5, true);
+ QTreeWidgetItem *item6 = new QTreeWidgetItem(item5);
+ item6->setText(0, "item6");
+
+ for (int i = 0; i < 1000; i++) {
+ QTreeWidgetItem *newItem1 = new QTreeWidgetItem(tree, item1);
+ newItem1->setText(0, "newItem");
+ QTreeWidgetItem *newItem2 = new QTreeWidgetItem(newItem1);
+ newItem2->setText(0, "subItem1");
+ QTreeWidgetItem *newItem3 = new QTreeWidgetItem(newItem1, newItem2);
+ newItem3->setText(0, "subItem2");
+ delete item3;
+ item3 = newItem1;
+ }
+ QApplication::instance()->processEvents();
+
+ delete tree;
+}
+
+class CrashWidget : public QTreeWidget
+{
+public:
+ CrashWidget(QWidget *parent = 0) : QTreeWidget(parent), i(0) {
+ setSortingEnabled(true);
+ timerId = startTimer(10);
+ }
+ int i;
+protected:
+ void timerEvent(QTimerEvent * event) {
+ if (event->timerId() == timerId) {
+ QTreeWidgetItem *newItem = new QTreeWidgetItem((QStringList() << QString::number(i++)));
+ m_list.append(newItem);
+ insertTopLevelItem(0, newItem);
+ while (m_list.count() > 10)
+ delete m_list.takeFirst();
+ }
+ QTreeWidget::timerEvent(event);
+ }
+private:
+ int timerId;
+ QList<QTreeWidgetItem*> m_list;
+};
+
+void tst_QTreeWidget::sortAndSelect()
+{
+ CrashWidget w;
+ w.resize(1, 1);
+ w.show();
+ while (w.i < 100) {
+ QApplication::processEvents();
+ if (w.i & 16) {
+ QPoint pt = w.viewport()->rect().center();
+ QTest::mouseClick(w.viewport(), Qt::LeftButton, Qt::NoModifier, pt);
+ }
+ }
+ QVERIFY(true);
+}
+
+void tst_QTreeWidget::defaultRowSizes()
+{
+ QTreeWidget *tw = new QTreeWidget();
+ tw->setIconSize(QSize(50, 50));
+ tw->setColumnCount(6);
+ for (int i=0; i<10; ++i) {
+ QTreeWidgetItem *it = new QTreeWidgetItem(tw);
+ for (int j=0; j<tw->columnCount() - 1; ++j) {
+ it->setText(j, "This is a test");
+ }
+ QPixmap icon = tw->style()->standardPixmap((QStyle::StandardPixmap)(i + QStyle::SP_TitleBarMenuButton));
+ if (icon.isNull())
+ QSKIP("No pixmap found on current style, skipping this test.", SkipSingle);
+ it->setIcon(tw->columnCount() - 1,
+ icon.scaled(tw->iconSize()));
+ }
+ tw->resize(100,100);
+ tw->show();
+ QApplication::processEvents();
+
+ QRect visualRect = tw->visualItemRect(tw->topLevelItem(0));
+ QVERIFY(visualRect.height() >= 50);
+}
+
+void tst_QTreeWidget::task191552_rtl()
+{
+ Qt::LayoutDirection oldDir = qApp->layoutDirection();
+ qApp->setLayoutDirection(Qt::RightToLeft);
+
+ QTreeWidget tw;
+ tw.setColumnCount(1);
+ QTreeWidgetItem *item = new QTreeWidgetItem(&tw);
+ item->setText(0, "item 1");
+ item->setCheckState(0, Qt::Checked);
+ QCOMPARE(item->checkState(0), Qt::Checked);
+ tw.show();
+ QTest::qWait(50);
+ QStyleOptionViewItem opt;
+ opt.initFrom(&tw);
+ opt.rect = tw.visualItemRect(item);
+ const QRect checkRect = tw.style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, &tw);
+ QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::NoModifier, checkRect.center());
+ QTest::qWait(200);
+ QCOMPARE(item->checkState(0), Qt::Unchecked);
+
+ qApp->setLayoutDirection(oldDir);
+}
+
+void tst_QTreeWidget::task203673_selection()
+{
+ //we try to change the selection by rightclick + ctrl
+ //it should do anything when using ExtendedSelection
+
+ QTreeWidget tw;
+ tw.setColumnCount(1);
+ QTreeWidgetItem *item1 = new QTreeWidgetItem(&tw);
+ item1->setText(0, "item 1");
+ tw.setSelectionMode(QTreeView::ExtendedSelection);
+
+ QPoint center = tw.visualItemRect(item1).center();
+ QCOMPARE(item1->isSelected(), false);
+
+ QTest::mouseClick(tw.viewport(), Qt::RightButton, Qt::ControlModifier, center);
+ QCOMPARE(item1->isSelected(), false);
+
+ QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::ControlModifier, center);
+ QCOMPARE(item1->isSelected(), true);
+
+ QTest::mouseClick(tw.viewport(), Qt::RightButton, Qt::ControlModifier, center);
+ QCOMPARE(item1->isSelected(), true); //it shouldn't change
+
+ QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::ControlModifier, center);
+ QCOMPARE(item1->isSelected(), false);
+}
+
+
+void tst_QTreeWidget::rootItemFlags()
+{
+ QTreeWidget tw;
+ tw.setColumnCount(1);
+ QTreeWidgetItem *item = new QTreeWidgetItem(&tw);
+ item->setText(0, "item 1");
+
+ QVERIFY(tw.invisibleRootItem()->flags() & Qt::ItemIsDropEnabled);
+
+ tw.invisibleRootItem()->setFlags(tw.invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled);
+
+ QVERIFY(!(tw.invisibleRootItem()->flags() & Qt::ItemIsDropEnabled));
+}
+
+void tst_QTreeWidget::task218661_setHeaderData()
+{
+ //We check that setting header data out of bounds returns false
+ //and doesn't increase the size of the model
+ QTreeWidget tw;
+ tw.setColumnCount(1);
+ QCOMPARE(tw.columnCount(), 1);
+
+ QCOMPARE(tw.model()->setHeaderData(99999, Qt::Horizontal, QVariant()), false);
+
+ QCOMPARE(tw.columnCount(), 1);
+}
+
+void tst_QTreeWidget::task245280_sortChildren()
+{
+ QTreeWidget tw;
+ tw.setColumnCount(2);
+
+ QTreeWidgetItem top(&tw);
+ top.setText(0,"Col 0");
+ top.setText(1,"Col 1");
+ QTreeWidgetItem item1(&top);
+ item1.setText(0,"X");
+ item1.setText(1,"0");
+ QTreeWidgetItem item2(&top);
+ item2.setText(0,"A");
+ item2.setText(1,"4");
+ QTreeWidgetItem item3(&top);
+ item3.setText(0,"E");
+ item3.setText(1,"1");
+ QTreeWidgetItem item4(&top);
+ item4.setText(0,"Z");
+ item4.setText(1,"3");
+ QTreeWidgetItem item5(&top);
+ item5.setText(0,"U");
+ item5.setText(1,"2");
+ tw.expandAll();
+ tw.show();
+ top.sortChildren(1,Qt::AscendingOrder);
+
+ for (int i = 0; i < top.childCount(); ++i)
+ QCOMPARE(top.child(i)->text(1), QString::number(i));
+}
+
+void tst_QTreeWidget::task253109_itemHeight()
+{
+ QTreeWidget treeWidget;
+ treeWidget.setColumnCount(1);
+ treeWidget.show();
+ QTest::qWait(200);
+
+ QTreeWidgetItem item(&treeWidget);
+ class MyWidget : public QWidget
+ {
+ virtual QSize sizeHint() const { return QSize(200,100); }
+ } w;
+ treeWidget.setItemWidget(&item, 0, &w);
+
+ QTest::qWait(200);
+ QCOMPARE(w.geometry(), treeWidget.visualItemRect(&item));
+
+}
+
+void tst_QTreeWidget::task206367_duplication()
+{
+ QWidget topLevel;
+ QTreeWidget treeWidget(&topLevel);
+ topLevel.show();
+ treeWidget.resize(200, 200);
+
+ treeWidget.setSortingEnabled(true);
+ QTreeWidgetItem* rootItem = new QTreeWidgetItem( &treeWidget, QStringList("root") );
+ for (int nFile = 0; nFile < 2; nFile++ ) {
+ QTreeWidgetItem* itemFile = new QTreeWidgetItem(rootItem, QStringList(QString::number(nFile)));
+ for (int nRecord = 0; nRecord < 2; nRecord++)
+ new QTreeWidgetItem(itemFile , QStringList(QString::number(nRecord)));
+ itemFile->setExpanded(true);
+ }
+ rootItem->setExpanded(true);
+ QTest::qWait(2000);
+
+ //there should be enough room for 2x2 items. If there is a scrollbar, it means the items are duplicated
+ QVERIFY(!treeWidget.verticalScrollBar()->isVisible());
+
+}
+
+void tst_QTreeWidget::itemSelectionChanged()
+{
+ QVERIFY(testWidget);
+ if(testWidget->topLevelItem(0))
+ QVERIFY(testWidget->topLevelItem(0)->isSelected());
+}
+
+void tst_QTreeWidget::selectionOrder()
+{
+ testWidget->setColumnCount(1);
+ QList<QTreeWidgetItem *> items;
+ for (int i = 0; i < 10; ++i)
+ items.append(new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item: %1").arg(i))));
+ testWidget->insertTopLevelItems(0, items);
+
+ QModelIndex idx = testWidget->indexFromItem(items[0]);
+ connect(testWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
+ testWidget->selectionModel()->select(idx, QItemSelectionModel::SelectCurrent);
+ disconnect(testWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
+}
+
+void tst_QTreeWidget::setSelectionModel()
+{
+ QTreeWidget tree;
+ for(int i = 0; i < 3; ++i)
+ new QTreeWidgetItem(&tree, QStringList(QString::number(i)));
+ QItemSelectionModel selection(tree.model());
+ selection.select(tree.model()->index(1,0), QItemSelectionModel::Select);
+ tree.setSelectionModel(&selection);
+ QCOMPARE(tree.topLevelItem(1)->isSelected(), true);
+}
+
+void tst_QTreeWidget::task217309()
+{
+ QTreeWidgetItem item;
+ item.setFlags(item.flags() | Qt::ItemIsTristate);
+ QTreeWidgetItem subitem1;
+ subitem1.setFlags(subitem1.flags() | Qt::ItemIsTristate);
+ QTreeWidgetItem subitem2;
+ subitem2.setFlags(subitem2.flags() | Qt::ItemIsTristate);
+ item.addChild(&subitem1);
+ item.addChild(&subitem2);
+ subitem1.setCheckState(0, Qt::Checked);
+ subitem2.setCheckState(0, Qt::Unchecked);
+
+ QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::PartiallyChecked);
+
+ subitem2.setCheckState(0, Qt::PartiallyChecked);
+ QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::PartiallyChecked);
+
+ subitem2.setCheckState(0, Qt::Checked);
+ QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::Checked);
+}
+
+class TreeWidgetItem : public QTreeWidgetItem
+{
+
+public:
+ void _emitDataChanged() { emitDataChanged(); }
+
+};
+
+void tst_QTreeWidget::emitDataChanged()
+{
+
+ QTreeWidget *tree = new QTreeWidget;
+ QSignalSpy spy(tree, SIGNAL(itemChanged(QTreeWidgetItem *, int)));
+ TreeWidgetItem *item = new TreeWidgetItem();
+ tree->insertTopLevelItem(0, item);
+ item->_emitDataChanged();
+ QCOMPARE(spy.count(), 1);
+
+}
+
+void tst_QTreeWidget::setCurrentItemExpandsParent()
+{
+ QTreeWidget w;
+ w.setColumnCount(1);
+ QTreeWidgetItem *i1 = new QTreeWidgetItem(&w, QStringList() << "parent");
+ QTreeWidgetItem *i2 = new QTreeWidgetItem(i1, QStringList() << "child");
+ QVERIFY(!i2->isExpanded());
+ QVERIFY(w.currentItem() == 0);
+ w.setCurrentItem(i2);
+ QVERIFY(!i2->isExpanded());
+ QCOMPARE(w.currentItem(), i2);
+}
+
+void tst_QTreeWidget::task239150_editorWidth()
+{
+ //we check that an item with no text will get an editor with a correct size
+ QTreeWidget tree;
+
+ QStyleOptionFrameV2 opt;
+ opt.init(&tree);
+ const int minWidth = tree.style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(0, 0).
+ expandedTo(QApplication::globalStrut()), 0).width();
+
+ {
+ QTreeWidgetItem item;
+ item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
+ tree.addTopLevelItem(&item);
+ QVERIFY(tree.itemWidget(&item, 0) == 0);
+ tree.editItem(&item);
+ QVERIFY(tree.itemWidget(&item, 0));
+ QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth);
+ }
+
+ //now let's test it with an item with a lot of text
+ {
+ QTreeWidgetItem item;
+ item.setText(0, "foooooooooooooooooooooooo");
+ item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
+ tree.addTopLevelItem(&item);
+ QVERIFY(tree.itemWidget(&item, 0) == 0);
+ tree.editItem(&item);
+ QVERIFY(tree.itemWidget(&item, 0));
+ QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth + tree.fontMetrics().width(item.text(0)));
+ }
+}
+
+
+
+void tst_QTreeWidget::setTextUpdate()
+{
+ QTreeWidget treeWidget;
+ treeWidget.setColumnCount(2);
+
+ class MyItemDelegate : public QStyledItemDelegate
+ {
+ public:
+ MyItemDelegate() : numPaints(0) { }
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ numPaints++;
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+
+ mutable int numPaints;
+ } delegate;
+
+ treeWidget.setItemDelegate(&delegate);
+ treeWidget.show();
+ QStringList strList;
+ strList << "variable1" << "0";
+ QTreeWidgetItem *item = new QTreeWidgetItem(strList);
+ treeWidget.insertTopLevelItem(0, item);
+ QTest::qWait(50);
+ QTRY_VERIFY(delegate.numPaints > 0);
+ delegate.numPaints = 0;
+
+ item->setText(1, "42");
+ QApplication::processEvents();
+ QTRY_VERIFY(delegate.numPaints > 0);
+}
+
+void tst_QTreeWidget::taskQTBUG2844_visualItemRect()
+{
+ CustomTreeWidget tree;
+ tree.resize(150, 100);
+ tree.setColumnCount(3);
+ QTreeWidgetItem item(&tree);
+
+ QRect itemRect = tree.visualItemRect(&item);
+
+ QRect rectCol0 = tree.visualRect(tree.indexFromItem(&item, 0));
+ QRect rectCol1 = tree.visualRect(tree.indexFromItem(&item, 1));
+ QRect rectCol2 = tree.visualRect(tree.indexFromItem(&item, 2));
+
+ QCOMPARE(tree.visualItemRect(&item), rectCol0 | rectCol2);
+ tree.setColumnHidden(2, true);
+ QCOMPARE(tree.visualItemRect(&item), rectCol0 | rectCol1);
+}
+
+void tst_QTreeWidget::setChildIndicatorPolicy()
+{
+ QTreeWidget treeWidget;
+ treeWidget.setColumnCount(1);
+
+ class MyItemDelegate : public QStyledItemDelegate
+ {
+ public:
+ MyItemDelegate() : numPaints(0), expectChildren(false) { }
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ numPaints++;
+ QCOMPARE(!(option.state & QStyle::State_Children), !expectChildren);
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+ mutable int numPaints;
+ bool expectChildren;
+ } delegate;
+
+ treeWidget.setItemDelegate(&delegate);
+ treeWidget.show();
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(QStringList("Hello"));
+ treeWidget.insertTopLevelItem(0, item);
+ QTest::qWait(50);
+ QTRY_VERIFY(delegate.numPaints > 0);
+
+ delegate.numPaints = 0;
+ delegate.expectChildren = true;
+ item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
+ QApplication::processEvents();
+ QTRY_COMPARE(delegate.numPaints, 1);
+
+ delegate.numPaints = 0;
+ delegate.expectChildren = false;
+ item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
+ QApplication::processEvents();
+ QTRY_COMPARE(delegate.numPaints, 1);
+
+ delegate.numPaints = 0;
+ delegate.expectChildren = true;
+ new QTreeWidgetItem(item);
+ QApplication::processEvents();
+ QTRY_COMPARE(delegate.numPaints, 1);
+
+ delegate.numPaints = 0;
+ delegate.expectChildren = false;
+ item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
+ QApplication::processEvents();
+ QTRY_COMPARE(delegate.numPaints, 1);
+}
+
+
+
+QTEST_MAIN(tst_QTreeWidget)
+#include "tst_qtreewidget.moc"
diff --git a/tests/auto/widgets/itemviews/qtreewidgetitemiterator/.gitignore b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/.gitignore
new file mode 100644
index 0000000000..6595518de7
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/.gitignore
@@ -0,0 +1 @@
+tst_qtreewidgetitemiterator
diff --git a/tests/auto/widgets/itemviews/qtreewidgetitemiterator/qtreewidgetitemiterator.pro b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/qtreewidgetitemiterator.pro
new file mode 100644
index 0000000000..de7762e773
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/qtreewidgetitemiterator.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+QT += widgets
+SOURCES += tst_qtreewidgetitemiterator.cpp
+
+
diff --git a/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp
new file mode 100644
index 0000000000..92a1b7cce3
--- /dev/null
+++ b/tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp
@@ -0,0 +1,1243 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qtreewidget.h>
+#include <qtreewidgetitemiterator.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qdebug.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QTreeWidgetItemIterator : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTreeWidgetItemIterator();
+ ~tst_QTreeWidgetItemIterator();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void postincrement();
+ void preincrement();
+ void postdecrement();
+ void predecrement();
+ void plus_eq_data();
+ void plus_eq();
+ void minus_eq_data();
+ void minus_eq();
+ void iteratorflags_data();
+ void iteratorflags();
+ void updateIfModifiedFromWidget_data();
+ void updateIfModifiedFromWidget();
+ void constructIteratorWithItem_data();
+ void constructIteratorWithItem();
+ void updateIteratorAfterDeletedItem_and_ContinueIteration_data();
+ void updateIteratorAfterDeletedItem_and_ContinueIteration();
+ void initializeIterator();
+private:
+ QTreeWidget *testWidget;
+};
+
+tst_QTreeWidgetItemIterator::tst_QTreeWidgetItemIterator(): testWidget(0)
+{
+}
+
+tst_QTreeWidgetItemIterator::~tst_QTreeWidgetItemIterator()
+{
+}
+
+void tst_QTreeWidgetItemIterator::initTestCase()
+{
+ testWidget = new QTreeWidget();
+ testWidget->clear();
+ testWidget->setColumnCount(2);
+ testWidget->show();
+
+
+ /**
+ * These are default:
+ *
+ * Qt::ItemIsSelectable
+ * |Qt::ItemIsUserCheckable
+ * |Qt::ItemIsEnabled
+ * |Qt::ItemIsDragEnabled
+ * |Qt::ItemIsDropEnabled
+ *
+ */
+ for (int i=0; i <= 16; ++i) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
+ top->setText(0, QString("top%1").arg(i));
+ switch (i) {
+ case 0: testWidget->setItemHidden(top, true);break;
+ case 1: testWidget->setItemHidden(top, false);break;
+
+ case 2: testWidget->setItemSelected(top, true);break;
+ case 3: testWidget->setItemSelected(top, false);break;
+
+ case 4: top->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);break;
+ case 5: top->setFlags(Qt::ItemIsEnabled);break;
+
+ case 6: top->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);break;
+ case 7: top->setFlags(Qt::ItemIsEnabled);break;
+
+ case 8: top->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled);break;
+ case 9: top->setFlags(Qt::ItemIsEnabled);break;
+
+ case 10: top->setFlags(Qt::ItemIsEnabled);break;
+ case 11:
+ top->setFlags(0);
+ break;
+
+ case 12: top->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);break;
+ case 13: top->setFlags(Qt::ItemIsEnabled);break;
+
+ case 14: top->setCheckState(0, Qt::Checked);break;
+ case 15: top->setCheckState(0, Qt::Unchecked);break;
+ case 16: top->setCheckState(0, Qt::PartiallyChecked);break;
+ }
+ for (int j=0; j <= 16; ++j) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(top);
+ child->setText(0, QString("top%1,child%2").arg(i).arg(j));
+ switch (j) {
+ case 0: testWidget->setItemHidden(child, true);break;
+ case 1: testWidget->setItemHidden(child, false);break;
+
+ case 2: testWidget->setItemSelected(child, true);break;
+ case 3: testWidget->setItemSelected(child, false);break;
+
+ case 4: child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);break;
+ case 5: child->setFlags(Qt::ItemIsEnabled);break;
+
+ case 6: child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);break;
+ case 7: child->setFlags(Qt::ItemIsEnabled);break;
+
+ case 8: child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled);break;
+ case 9: child->setFlags(Qt::ItemIsEnabled);break;
+
+ case 10: child->setFlags(Qt::ItemIsEnabled);break;
+ case 11: child->setFlags(0);break;
+
+ case 12: child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);break;
+ case 13: child->setFlags(Qt::ItemIsEnabled);break;
+
+ case 14: child->setCheckState(0, Qt::Checked);break;
+ case 15: child->setCheckState(0, Qt::Unchecked);break;
+ case 16: child->setCheckState(0, Qt::PartiallyChecked);break;
+ }
+
+ }
+ }
+}
+
+void tst_QTreeWidgetItemIterator::cleanupTestCase()
+{
+ testWidget->hide();
+ delete testWidget;
+}
+
+void tst_QTreeWidgetItemIterator::init()
+{
+}
+
+void tst_QTreeWidgetItemIterator::cleanup()
+{
+}
+
+void tst_QTreeWidgetItemIterator::iteratorflags_data()
+{
+ /*
+ // Should preferably test for all these flags (and combinations).....
+
+ All = 0x00000000,
+ Hidden = 0x00000001,
+ NotHidden = 0x00000002,
+ Selected = 0x00000004,
+ Unselected = 0x00000008,
+ Selectable = 0x00000010,
+ NotSelectable = 0x00000020,
+ DragEnabled = 0x00000040,
+ DragDisabled = 0x00000080,
+ DropEnabled = 0x00000100,
+ DropDisabled = 0x00000200,
+ HasChildren = 0x00000400,
+ NoChildren = 0x00000800,
+ Checked = 0x00001000,
+ NotChecked = 0x00002000,
+ Enabled = 0x00004000,
+ Disabled = 0x00008000,
+ Editable = 0x00010000,
+ NotEditable = 0x00020000
+*/
+ QTest::addColumn<int>("start");
+ QTest::addColumn<int>("iteratorflags");
+ QTest::addColumn<QStringList>("matches");
+
+ QTest::newRow("Match all") << 0 << (int)QTreeWidgetItemIterator::All
+ << (QStringList()
+ << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3"
+ << "top0,child4" << "top0,child5" << "top0,child6" << "top0,child7"
+ << "top0,child8" << "top0,child9" << "top0,child10" << "top0,child11"
+ << "top0,child12" << "top0,child13" << "top0,child14" << "top0,child15"
+ << "top0,child16"
+ << "top1" << "top1,child0" << "top1,child1" << "top1,child2" << "top1,child3"
+ << "top1,child4" << "top1,child5" << "top1,child6" << "top1,child7"
+ << "top1,child8" << "top1,child9" << "top1,child10" << "top1,child11"
+ << "top1,child12" << "top1,child13" << "top1,child14" << "top1,child15"
+ << "top1,child16"
+ << "top2" << "top2,child0" << "top2,child1" << "top2,child2" << "top2,child3"
+ << "top2,child4" << "top2,child5" << "top2,child6" << "top2,child7"
+ << "top2,child8" << "top2,child9" << "top2,child10" << "top2,child11"
+ << "top2,child12" << "top2,child13" << "top2,child14" << "top2,child15"
+ << "top2,child16"
+ << "top3" << "top3,child0" << "top3,child1" << "top3,child2" << "top3,child3"
+ << "top3,child4" << "top3,child5" << "top3,child6" << "top3,child7"
+ << "top3,child8" << "top3,child9" << "top3,child10" << "top3,child11"
+ << "top3,child12" << "top3,child13" << "top3,child14" << "top3,child15"
+ << "top3,child16"
+ << "top4" << "top4,child0" << "top4,child1" << "top4,child2" << "top4,child3"
+ << "top4,child4" << "top4,child5" << "top4,child6" << "top4,child7"
+ << "top4,child8" << "top4,child9" << "top4,child10" << "top4,child11"
+ << "top4,child12" << "top4,child13" << "top4,child14" << "top4,child15"
+ << "top4,child16"
+ << "top5" << "top5,child0" << "top5,child1" << "top5,child2" << "top5,child3"
+ << "top5,child4" << "top5,child5" << "top5,child6" << "top5,child7"
+ << "top5,child8" << "top5,child9" << "top5,child10" << "top5,child11"
+ << "top5,child12" << "top5,child13" << "top5,child14" << "top5,child15"
+ << "top5,child16"
+ << "top6" << "top6,child0" << "top6,child1" << "top6,child2" << "top6,child3"
+ << "top6,child4" << "top6,child5" << "top6,child6" << "top6,child7"
+ << "top6,child8" << "top6,child9" << "top6,child10" << "top6,child11"
+ << "top6,child12" << "top6,child13" << "top6,child14" << "top6,child15"
+ << "top6,child16"
+ << "top7" << "top7,child0" << "top7,child1" << "top7,child2" << "top7,child3"
+ << "top7,child4" << "top7,child5" << "top7,child6" << "top7,child7"
+ << "top7,child8" << "top7,child9" << "top7,child10" << "top7,child11"
+ << "top7,child12" << "top7,child13" << "top7,child14" << "top7,child15"
+ << "top7,child16"
+ << "top8" << "top8,child0" << "top8,child1" << "top8,child2" << "top8,child3"
+ << "top8,child4" << "top8,child5" << "top8,child6" << "top8,child7"
+ << "top8,child8" << "top8,child9" << "top8,child10" << "top8,child11"
+ << "top8,child12" << "top8,child13" << "top8,child14" << "top8,child15"
+ << "top8,child16"
+ << "top9" << "top9,child0" << "top9,child1" << "top9,child2" << "top9,child3"
+ << "top9,child4" << "top9,child5" << "top9,child6" << "top9,child7"
+ << "top9,child8" << "top9,child9" << "top9,child10" << "top9,child11"
+ << "top9,child12" << "top9,child13" << "top9,child14" << "top9,child15"
+ << "top9,child16"
+ << "top10" << "top10,child0" << "top10,child1" << "top10,child2" << "top10,child3"
+ << "top10,child4" << "top10,child5" << "top10,child6" << "top10,child7"
+ << "top10,child8" << "top10,child9" << "top10,child10" << "top10,child11"
+ << "top10,child12" << "top10,child13" << "top10,child14" << "top10,child15"
+ << "top10,child16"
+ << "top11" << "top11,child0" << "top11,child1" << "top11,child2" << "top11,child3"
+ << "top11,child4" << "top11,child5" << "top11,child6" << "top11,child7"
+ << "top11,child8" << "top11,child9" << "top11,child10" << "top11,child11"
+ << "top11,child12" << "top11,child13" << "top11,child14" << "top11,child15"
+ << "top11,child16"
+ << "top12" << "top12,child0" << "top12,child1" << "top12,child2" << "top12,child3"
+ << "top12,child4" << "top12,child5" << "top12,child6" << "top12,child7"
+ << "top12,child8" << "top12,child9" << "top12,child10" << "top12,child11"
+ << "top12,child12" << "top12,child13" << "top12,child14" << "top12,child15"
+ << "top12,child16"
+ << "top13" << "top13,child0" << "top13,child1" << "top13,child2" << "top13,child3"
+ << "top13,child4" << "top13,child5" << "top13,child6" << "top13,child7"
+ << "top13,child8" << "top13,child9" << "top13,child10" << "top13,child11"
+ << "top13,child12" << "top13,child13" << "top13,child14" << "top13,child15"
+ << "top13,child16"
+ << "top14" << "top14,child0" << "top14,child1" << "top14,child2" << "top14,child3"
+ << "top14,child4" << "top14,child5" << "top14,child6" << "top14,child7"
+ << "top14,child8" << "top14,child9" << "top14,child10" << "top14,child11"
+ << "top14,child12" << "top14,child13" << "top14,child14" << "top14,child15"
+ << "top14,child16"
+ << "top15" << "top15,child0" << "top15,child1" << "top15,child2" << "top15,child3"
+ << "top15,child4" << "top15,child5" << "top15,child6" << "top15,child7"
+ << "top15,child8" << "top15,child9" << "top15,child10" << "top15,child11"
+ << "top15,child12" << "top15,child13" << "top15,child14" << "top15,child15"
+ << "top15,child16"
+ << "top16" << "top16,child0" << "top16,child1" << "top16,child2" << "top16,child3"
+ << "top16,child4" << "top16,child5" << "top16,child6" << "top16,child7"
+ << "top16,child8" << "top16,child9" << "top16,child10" << "top16,child11"
+ << "top16,child12" << "top16,child13" << "top16,child14" << "top16,child15"
+ << "top16,child16");
+
+ QTest::newRow("Match hidden") << 0 << (int)QTreeWidgetItemIterator::Hidden
+ << (QStringList()
+ << "top0" << "top0,child0" // fails due to hidden row
+ << "top1,child0"
+ << "top2,child0"
+ << "top3,child0"
+ << "top4,child0"
+ << "top5,child0"
+ << "top6,child0"
+ << "top7,child0"
+ << "top8,child0"
+ << "top9,child0"
+ << "top10,child0"
+ << "top11,child0"
+ << "top12,child0"
+ << "top13,child0"
+ << "top14,child0"
+ << "top15,child0"
+ << "top16,child0");
+
+ QTest::newRow("Match not hidden") << 0 << (int)QTreeWidgetItemIterator::NotHidden
+ << (QStringList()
+ << "top0,child1" << "top0,child2" << "top0,child3"
+ << "top0,child4" << "top0,child5" << "top0,child6" << "top0,child7"
+ << "top0,child8" << "top0,child9" << "top0,child10" << "top0,child11"
+ << "top0,child12" << "top0,child13" << "top0,child14" << "top0,child15"
+ << "top0,child16"
+ << "top1" << "top1,child1" << "top1,child2" << "top1,child3"
+ << "top1,child4" << "top1,child5" << "top1,child6" << "top1,child7"
+ << "top1,child8" << "top1,child9" << "top1,child10" << "top1,child11"
+ << "top1,child12" << "top1,child13" << "top1,child14" << "top1,child15"
+ << "top1,child16"
+ << "top2" << "top2,child1" << "top2,child2" << "top2,child3"
+ << "top2,child4" << "top2,child5" << "top2,child6" << "top2,child7"
+ << "top2,child8" << "top2,child9" << "top2,child10" << "top2,child11"
+ << "top2,child12" << "top2,child13" << "top2,child14" << "top2,child15"
+ << "top2,child16"
+ << "top3" << "top3,child1" << "top3,child2" << "top3,child3"
+ << "top3,child4" << "top3,child5" << "top3,child6" << "top3,child7"
+ << "top3,child8" << "top3,child9" << "top3,child10" << "top3,child11"
+ << "top3,child12" << "top3,child13" << "top3,child14" << "top3,child15"
+ << "top3,child16"
+ << "top4" << "top4,child1" << "top4,child2" << "top4,child3"
+ << "top4,child4" << "top4,child5" << "top4,child6" << "top4,child7"
+ << "top4,child8" << "top4,child9" << "top4,child10" << "top4,child11"
+ << "top4,child12" << "top4,child13" << "top4,child14" << "top4,child15"
+ << "top4,child16"
+ << "top5" << "top5,child1" << "top5,child2" << "top5,child3"
+ << "top5,child4" << "top5,child5" << "top5,child6" << "top5,child7"
+ << "top5,child8" << "top5,child9" << "top5,child10" << "top5,child11"
+ << "top5,child12" << "top5,child13" << "top5,child14" << "top5,child15"
+ << "top5,child16"
+ << "top6" << "top6,child1" << "top6,child2" << "top6,child3"
+ << "top6,child4" << "top6,child5" << "top6,child6" << "top6,child7"
+ << "top6,child8" << "top6,child9" << "top6,child10" << "top6,child11"
+ << "top6,child12" << "top6,child13" << "top6,child14" << "top6,child15"
+ << "top6,child16"
+ << "top7" << "top7,child1" << "top7,child2" << "top7,child3"
+ << "top7,child4" << "top7,child5" << "top7,child6" << "top7,child7"
+ << "top7,child8" << "top7,child9" << "top7,child10" << "top7,child11"
+ << "top7,child12" << "top7,child13" << "top7,child14" << "top7,child15"
+ << "top7,child16"
+ << "top8" << "top8,child1" << "top8,child2" << "top8,child3"
+ << "top8,child4" << "top8,child5" << "top8,child6" << "top8,child7"
+ << "top8,child8" << "top8,child9" << "top8,child10" << "top8,child11"
+ << "top8,child12" << "top8,child13" << "top8,child14" << "top8,child15"
+ << "top8,child16"
+ << "top9" << "top9,child1" << "top9,child2" << "top9,child3"
+ << "top9,child4" << "top9,child5" << "top9,child6" << "top9,child7"
+ << "top9,child8" << "top9,child9" << "top9,child10" << "top9,child11"
+ << "top9,child12" << "top9,child13" << "top9,child14" << "top9,child15"
+ << "top9,child16"
+ << "top10" << "top10,child1" << "top10,child2" << "top10,child3"
+ << "top10,child4" << "top10,child5" << "top10,child6" << "top10,child7"
+ << "top10,child8" << "top10,child9" << "top10,child10" << "top10,child11"
+ << "top10,child12" << "top10,child13" << "top10,child14" << "top10,child15"
+ << "top10,child16"
+ << "top11" << "top11,child1" << "top11,child2" << "top11,child3"
+ << "top11,child4" << "top11,child5" << "top11,child6" << "top11,child7"
+ << "top11,child8" << "top11,child9" << "top11,child10" << "top11,child11"
+ << "top11,child12" << "top11,child13" << "top11,child14" << "top11,child15"
+ << "top11,child16"
+ << "top12" << "top12,child1" << "top12,child2" << "top12,child3"
+ << "top12,child4" << "top12,child5" << "top12,child6" << "top12,child7"
+ << "top12,child8" << "top12,child9" << "top12,child10" << "top12,child11"
+ << "top12,child12" << "top12,child13" << "top12,child14" << "top12,child15"
+ << "top12,child16"
+ << "top13" << "top13,child1" << "top13,child2" << "top13,child3"
+ << "top13,child4" << "top13,child5" << "top13,child6" << "top13,child7"
+ << "top13,child8" << "top13,child9" << "top13,child10" << "top13,child11"
+ << "top13,child12" << "top13,child13" << "top13,child14" << "top13,child15"
+ << "top13,child16"
+ << "top14" << "top14,child1" << "top14,child2" << "top14,child3"
+ << "top14,child4" << "top14,child5" << "top14,child6" << "top14,child7"
+ << "top14,child8" << "top14,child9" << "top14,child10" << "top14,child11"
+ << "top14,child12" << "top14,child13" << "top14,child14" << "top14,child15"
+ << "top14,child16"
+ << "top15" << "top15,child1" << "top15,child2" << "top15,child3"
+ << "top15,child4" << "top15,child5" << "top15,child6" << "top15,child7"
+ << "top15,child8" << "top15,child9" << "top15,child10" << "top15,child11"
+ << "top15,child12" << "top15,child13" << "top15,child14" << "top15,child15"
+ << "top15,child16"
+ << "top16" << "top16,child1" << "top16,child2" << "top16,child3"
+ << "top16,child4" << "top16,child5" << "top16,child6" << "top16,child7"
+ << "top16,child8" << "top16,child9" << "top16,child10" << "top16,child11"
+ << "top16,child12" << "top16,child13" << "top16,child14" << "top16,child15"
+ << "top16,child16");
+
+ QTest::newRow("Match selected") << 0 << (int)QTreeWidgetItemIterator::Selected
+ << (QStringList()
+ << "top0,child2"
+ << "top1,child2"
+ << "top2" << "top2,child2"
+ << "top3,child2"
+ << "top4,child2"
+ << "top5,child2"
+ << "top6,child2"
+ << "top7,child2"
+ << "top8,child2"
+ << "top9,child2"
+ << "top10,child2"
+ << "top11,child2"
+ << "top12,child2"
+ << "top13,child2"
+ << "top14,child2"
+ << "top15,child2"
+ << "top16,child2");
+
+ QTest::newRow("Match selectable") << 0 << (int)QTreeWidgetItemIterator::Selectable
+ << (QStringList()
+ << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3"
+ << "top0,child4"
+ << "top0,child14" << "top0,child15"
+ << "top0,child16"
+ << "top1" << "top1,child0" << "top1,child1" << "top1,child2" << "top1,child3"
+ << "top1,child4"
+ << "top1,child14" << "top1,child15"
+ << "top1,child16"
+ << "top2" << "top2,child0" << "top2,child1" << "top2,child2" << "top2,child3"
+ << "top2,child4"
+ << "top2,child14" << "top2,child15"
+ << "top2,child16"
+ << "top3" << "top3,child0" << "top3,child1" << "top3,child2" << "top3,child3"
+ << "top3,child4"
+ << "top3,child14" << "top3,child15"
+ << "top3,child16"
+ << "top4" << "top4,child0" << "top4,child1" << "top4,child2" << "top4,child3"
+ << "top4,child4"
+ << "top4,child14" << "top4,child15"
+ << "top4,child16"
+ /* "top5"*/ << "top5,child0" << "top5,child1" << "top5,child2" << "top5,child3"
+ << "top5,child4"
+ << "top5,child14" << "top5,child15"
+ << "top5,child16"
+ /* "top6"*/ << "top6,child0" << "top6,child1" << "top6,child2" << "top6,child3"
+ << "top6,child4"
+ << "top6,child14" << "top6,child15"
+ << "top6,child16"
+ /* "top7"*/ << "top7,child0" << "top7,child1" << "top7,child2" << "top7,child3"
+ << "top7,child4"
+ << "top7,child14" << "top7,child15"
+ << "top7,child16"
+ /* "top8"*/ << "top8,child0" << "top8,child1" << "top8,child2" << "top8,child3"
+ << "top8,child4"
+ << "top8,child14" << "top8,child15"
+ << "top8,child16"
+ /* "top9"*/ << "top9,child0" << "top9,child1" << "top9,child2" << "top9,child3"
+ << "top9,child4"
+ << "top9,child14" << "top9,child15"
+ << "top9,child16"
+ /* "top10*/ << "top10,child0" << "top10,child1" << "top10,child2" << "top10,child3"
+ << "top10,child4"
+ << "top10,child14" << "top10,child15"
+ << "top10,child16"
+ /* "top11*/ << "top11,child0" << "top11,child1" << "top11,child2" << "top11,child3"
+ << "top11,child4"
+ << "top11,child14" << "top11,child15"
+ << "top11,child16"
+ /* "top12*/ << "top12,child0" << "top12,child1" << "top12,child2" << "top12,child3"
+ << "top12,child4"
+ << "top12,child14" << "top12,child15"
+ << "top12,child16"
+ /* "top13*/ << "top13,child0" << "top13,child1" << "top13,child2" << "top13,child3"
+ << "top13,child4"
+ << "top13,child14" << "top13,child15"
+ << "top13,child16"
+ << "top14" << "top14,child0" << "top14,child1" << "top14,child2" << "top14,child3"
+ << "top14,child4"
+ << "top14,child14" << "top14,child15"
+ << "top14,child16"
+ << "top15" << "top15,child0" << "top15,child1" << "top15,child2" << "top15,child3"
+ << "top15,child4"
+ << "top15,child14" << "top15,child15"
+ << "top15,child16"
+ << "top16" << "top16,child0" << "top16,child1" << "top16,child2" << "top16,child3"
+ << "top16,child4"
+ << "top16,child14" << "top16,child15"
+ << "top16,child16");
+
+
+ QTest::newRow("Match DragEnabled") << 0 << (int)QTreeWidgetItemIterator::DragEnabled
+ << (QStringList()
+ << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3"
+ << "top0,child6"
+ << "top0,child14" << "top0,child15"
+ << "top0,child16"
+ << "top1" << "top1,child0" << "top1,child1" << "top1,child2" << "top1,child3"
+ << "top1,child6"
+ << "top1,child14" << "top1,child15"
+ << "top1,child16"
+ << "top2" << "top2,child0" << "top2,child1" << "top2,child2" << "top2,child3"
+ << "top2,child6"
+ << "top2,child14" << "top2,child15"
+ << "top2,child16"
+ << "top3" << "top3,child0" << "top3,child1" << "top3,child2" << "top3,child3"
+ << "top3,child6"
+ << "top3,child14" << "top3,child15"
+ << "top3,child16"
+ /* "top4"*/ << "top4,child0" << "top4,child1" << "top4,child2" << "top4,child3"
+ << "top4,child6"
+ << "top4,child14" << "top4,child15"
+ << "top4,child16"
+ /* "top5"*/ << "top5,child0" << "top5,child1" << "top5,child2" << "top5,child3"
+ << "top5,child6"
+ << "top5,child14" << "top5,child15"
+ << "top5,child16"
+ << "top6" << "top6,child0" << "top6,child1" << "top6,child2" << "top6,child3"
+ << "top6,child6"
+ << "top6,child14" << "top6,child15"
+ << "top6,child16"
+ /* "top7"*/ << "top7,child0" << "top7,child1" << "top7,child2" << "top7,child3"
+ << "top7,child6"
+ << "top7,child14" << "top7,child15"
+ << "top7,child16"
+ /* "top8"*/ << "top8,child0" << "top8,child1" << "top8,child2" << "top8,child3"
+ << "top8,child6"
+ << "top8,child14" << "top8,child15"
+ << "top8,child16"
+ /* "top9"*/ << "top9,child0" << "top9,child1" << "top9,child2" << "top9,child3"
+ << "top9,child6"
+ << "top9,child14" << "top9,child15"
+ << "top9,child16"
+ /* "top10*/ << "top10,child0" << "top10,child1" << "top10,child2" << "top10,child3"
+ << "top10,child6"
+ << "top10,child14" << "top10,child15"
+ << "top10,child16"
+ /* "top11*/ << "top11,child0" << "top11,child1" << "top11,child2" << "top11,child3"
+ << "top11,child6"
+ << "top11,child14" << "top11,child15"
+ << "top11,child16"
+ /* "top12*/ << "top12,child0" << "top12,child1" << "top12,child2" << "top12,child3"
+ << "top12,child6"
+ << "top12,child14" << "top12,child15"
+ << "top12,child16"
+ /* "top13*/ << "top13,child0" << "top13,child1" << "top13,child2" << "top13,child3"
+ << "top13,child6"
+ << "top13,child14" << "top13,child15"
+ << "top13,child16"
+ << "top14" << "top14,child0" << "top14,child1" << "top14,child2" << "top14,child3"
+ << "top14,child6"
+ << "top14,child14" << "top14,child15"
+ << "top14,child16"
+ << "top15" << "top15,child0" << "top15,child1" << "top15,child2" << "top15,child3"
+ << "top15,child6"
+ << "top15,child14" << "top15,child15"
+ << "top15,child16"
+ << "top16" << "top16,child0" << "top16,child1" << "top16,child2" << "top16,child3"
+ << "top16,child6"
+ << "top16,child14" << "top16,child15"
+ << "top16,child16");
+
+ QTest::newRow("Match DragDisabled") << 0 << (int)QTreeWidgetItemIterator::DragDisabled
+ << (QStringList()
+
+ /* top0 */
+ << "top0,child4" << "top0,child5" << "top0,child7" << "top0,child8"
+ << "top0,child9" << "top0,child10" << "top0,child11" << "top0,child12"
+ << "top0,child13"
+ /* top1 */
+ << "top1,child4" << "top1,child5" << "top1,child7" << "top1,child8"
+ << "top1,child9" << "top1,child10" << "top1,child11" << "top1,child12"
+ << "top1,child13"
+ /* top2 */
+ << "top2,child4" << "top2,child5" << "top2,child7" << "top2,child8"
+ << "top2,child9" << "top2,child10" << "top2,child11" << "top2,child12"
+ << "top2,child13"
+ /* top3 */
+ << "top3,child4" << "top3,child5" << "top3,child7" << "top3,child8"
+ << "top3,child9" << "top3,child10" << "top3,child11" << "top3,child12"
+ << "top3,child13"
+ << "top4"
+ << "top4,child4" << "top4,child5" << "top4,child7" << "top4,child8"
+ << "top4,child9" << "top4,child10" << "top4,child11" << "top4,child12"
+ << "top4,child13"
+ << "top5"
+ << "top5,child4" << "top5,child5" << "top5,child7" << "top5,child8"
+ << "top5,child9" << "top5,child10" << "top5,child11" << "top5,child12"
+ << "top5,child13"
+ /* "top6"*/
+ << "top6,child4" << "top6,child5" << "top6,child7" << "top6,child8"
+ << "top6,child9" << "top6,child10" << "top6,child11" << "top6,child12"
+ << "top6,child13"
+ << "top7"
+ << "top7,child4" << "top7,child5" << "top7,child7" << "top7,child8"
+ << "top7,child9" << "top7,child10" << "top7,child11" << "top7,child12"
+ << "top7,child13"
+ << "top8"
+ << "top8,child4" << "top8,child5" << "top8,child7" << "top8,child8"
+ << "top8,child9" << "top8,child10" << "top8,child11" << "top8,child12"
+ << "top8,child13"
+ << "top9"
+ << "top9,child4" << "top9,child5" << "top9,child7" << "top9,child8"
+ << "top9,child9" << "top9,child10" << "top9,child11" << "top9,child12"
+ << "top9,child13"
+ << "top10"
+ << "top10,child4" << "top10,child5" << "top10,child7" << "top10,child8"
+ << "top10,child9" << "top10,child10" << "top10,child11" << "top10,child12"
+ << "top10,child13"
+ << "top11"
+ << "top11,child4" << "top11,child5" << "top11,child7" << "top11,child8"
+ << "top11,child9" << "top11,child10" << "top11,child11" << "top11,child12"
+ << "top11,child13"
+ << "top12"
+ << "top12,child4" << "top12,child5" << "top12,child7" << "top12,child8"
+ << "top12,child9" << "top12,child10" << "top12,child11" << "top12,child12"
+ << "top12,child13"
+ << "top13"
+ << "top13,child4" << "top13,child5" << "top13,child7" << "top13,child8"
+ << "top13,child9" << "top13,child10" << "top13,child11" << "top13,child12"
+ << "top13,child13"
+ /* top14 */
+ << "top14,child4" << "top14,child5" << "top14,child7" << "top14,child8"
+ << "top14,child9" << "top14,child10" << "top14,child11" << "top14,child12"
+ << "top14,child13"
+ /* top15 */
+ << "top15,child4" << "top15,child5" << "top15,child7" << "top15,child8"
+ << "top15,child9" << "top15,child10" << "top15,child11" << "top15,child12"
+ << "top15,child13"
+ /* top16 */
+ << "top16,child4" << "top16,child5" << "top16,child7" << "top16,child8"
+ << "top16,child9" << "top16,child10" << "top16,child11" << "top16,child12"
+ << "top16,child13" );
+
+
+ QTest::newRow("Match DropEnabled") << 0 << (int)QTreeWidgetItemIterator::DropEnabled
+ << (QStringList()
+ << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3"
+ << "top0,child8"
+ << "top0,child14" << "top0,child15"
+ << "top0,child16"
+ << "top1" << "top1,child0" << "top1,child1" << "top1,child2" << "top1,child3"
+ << "top1,child8"
+ << "top1,child14" << "top1,child15"
+ << "top1,child16"
+ << "top2" << "top2,child0" << "top2,child1" << "top2,child2" << "top2,child3"
+ << "top2,child8"
+ << "top2,child14" << "top2,child15"
+ << "top2,child16"
+ << "top3" << "top3,child0" << "top3,child1" << "top3,child2" << "top3,child3"
+ << "top3,child8"
+ << "top3,child14" << "top3,child15"
+ << "top3,child16"
+ /* "top4"*/ << "top4,child0" << "top4,child1" << "top4,child2" << "top4,child3"
+ << "top4,child8"
+ << "top4,child14" << "top4,child15"
+ << "top4,child16"
+ /* "top5"*/ << "top5,child0" << "top5,child1" << "top5,child2" << "top5,child3"
+ << "top5,child8"
+ << "top5,child14" << "top5,child15"
+ << "top5,child16"
+ /* "top6"*/ << "top6,child0" << "top6,child1" << "top6,child2" << "top6,child3"
+ << "top6,child8"
+ << "top6,child14" << "top6,child15"
+ << "top6,child16"
+ /* "top7"*/ << "top7,child0" << "top7,child1" << "top7,child2" << "top7,child3"
+ << "top7,child8"
+ << "top7,child14" << "top7,child15"
+ << "top7,child16"
+ << "top8" << "top8,child0" << "top8,child1" << "top8,child2" << "top8,child3"
+ << "top8,child8"
+ << "top8,child14" << "top8,child15"
+ << "top8,child16"
+ /* "top9"*/ << "top9,child0" << "top9,child1" << "top9,child2" << "top9,child3"
+ << "top9,child8"
+ << "top9,child14" << "top9,child15"
+ << "top9,child16"
+ /* "top10*/ << "top10,child0" << "top10,child1" << "top10,child2" << "top10,child3"
+ << "top10,child8"
+ << "top10,child14" << "top10,child15"
+ << "top10,child16"
+ /* "top11*/ << "top11,child0" << "top11,child1" << "top11,child2" << "top11,child3"
+ << "top11,child8"
+ << "top11,child14" << "top11,child15"
+ << "top11,child16"
+ /* "top12*/ << "top12,child0" << "top12,child1" << "top12,child2" << "top12,child3"
+ << "top12,child8"
+ << "top12,child14" << "top12,child15"
+ << "top12,child16"
+ /* "top13*/ << "top13,child0" << "top13,child1" << "top13,child2" << "top13,child3"
+ << "top13,child8"
+ << "top13,child14" << "top13,child15"
+ << "top13,child16"
+ << "top14" << "top14,child0" << "top14,child1" << "top14,child2" << "top14,child3"
+ << "top14,child8"
+ << "top14,child14" << "top14,child15"
+ << "top14,child16"
+ << "top15" << "top15,child0" << "top15,child1" << "top15,child2" << "top15,child3"
+ << "top15,child8"
+ << "top15,child14" << "top15,child15"
+ << "top15,child16"
+ << "top16" << "top16,child0" << "top16,child1" << "top16,child2" << "top16,child3"
+ << "top16,child8"
+ << "top16,child14" << "top16,child15"
+ << "top16,child16");
+
+ QTest::newRow("Match HasChildren") << 0 << (int)QTreeWidgetItemIterator::HasChildren
+ << (QStringList() << "top0" << "top1" << "top2" << "top3" << "top4" << "top5"
+ << "top6" << "top7" << "top8" << "top9" << "top10" << "top11" << "top12"
+ << "top13" << "top14" << "top15" << "top16");
+
+ QTest::newRow("Match Checked") << 0 << (int)QTreeWidgetItemIterator::Checked
+ << (QStringList()
+ << "top0,child14" << "top0,child16"
+ << "top1,child14" << "top1,child16"
+ << "top2,child14" << "top2,child16"
+ << "top3,child14" << "top3,child16"
+ << "top4,child14" << "top4,child16"
+ << "top5,child14" << "top5,child16"
+ << "top6,child14" << "top6,child16"
+ << "top7,child14" << "top7,child16"
+ << "top8,child14" << "top8,child16"
+ << "top9,child14" << "top9,child16"
+ << "top10,child14" << "top10,child16"
+ << "top11,child14" << "top11,child16"
+ << "top12,child14" << "top12,child16"
+ << "top13,child14" << "top13,child16"
+ << "top14"
+ << "top14,child14" << "top14,child16"
+ << "top15,child14" << "top15,child16"
+ << "top16"
+ << "top16,child14" << "top16,child16");
+
+ QTest::newRow("Match NotChecked") << 0 << (int)QTreeWidgetItemIterator::NotChecked
+ << (QStringList()
+ << "top0" << "top0,child0" << "top0,child1" << "top0,child2" << "top0,child3"
+ << "top0,child4" << "top0,child5" << "top0,child6" << "top0,child7"
+ << "top0,child8" << "top0,child9" << "top0,child10" << "top0,child11"
+ << "top0,child12" << "top0,child13" << "top0,child15"
+
+ << "top1" << "top1,child0" << "top1,child1" << "top1,child2" << "top1,child3"
+ << "top1,child4" << "top1,child5" << "top1,child6" << "top1,child7"
+ << "top1,child8" << "top1,child9" << "top1,child10" << "top1,child11"
+ << "top1,child12" << "top1,child13" << "top1,child15"
+
+ << "top2" << "top2,child0" << "top2,child1" << "top2,child2" << "top2,child3"
+ << "top2,child4" << "top2,child5" << "top2,child6" << "top2,child7"
+ << "top2,child8" << "top2,child9" << "top2,child10" << "top2,child11"
+ << "top2,child12" << "top2,child13" << "top2,child15"
+
+ << "top3" << "top3,child0" << "top3,child1" << "top3,child2" << "top3,child3"
+ << "top3,child4" << "top3,child5" << "top3,child6" << "top3,child7"
+ << "top3,child8" << "top3,child9" << "top3,child10" << "top3,child11"
+ << "top3,child12" << "top3,child13" << "top3,child15"
+
+ << "top4" << "top4,child0" << "top4,child1" << "top4,child2" << "top4,child3"
+ << "top4,child4" << "top4,child5" << "top4,child6" << "top4,child7"
+ << "top4,child8" << "top4,child9" << "top4,child10" << "top4,child11"
+ << "top4,child12" << "top4,child13" << "top4,child15"
+
+ << "top5" << "top5,child0" << "top5,child1" << "top5,child2" << "top5,child3"
+ << "top5,child4" << "top5,child5" << "top5,child6" << "top5,child7"
+ << "top5,child8" << "top5,child9" << "top5,child10" << "top5,child11"
+ << "top5,child12" << "top5,child13" << "top5,child15"
+
+ << "top6" << "top6,child0" << "top6,child1" << "top6,child2" << "top6,child3"
+ << "top6,child4" << "top6,child5" << "top6,child6" << "top6,child7"
+ << "top6,child8" << "top6,child9" << "top6,child10" << "top6,child11"
+ << "top6,child12" << "top6,child13" << "top6,child15"
+
+ << "top7" << "top7,child0" << "top7,child1" << "top7,child2" << "top7,child3"
+ << "top7,child4" << "top7,child5" << "top7,child6" << "top7,child7"
+ << "top7,child8" << "top7,child9" << "top7,child10" << "top7,child11"
+ << "top7,child12" << "top7,child13" << "top7,child15"
+
+ << "top8" << "top8,child0" << "top8,child1" << "top8,child2" << "top8,child3"
+ << "top8,child4" << "top8,child5" << "top8,child6" << "top8,child7"
+ << "top8,child8" << "top8,child9" << "top8,child10" << "top8,child11"
+ << "top8,child12" << "top8,child13" << "top8,child15"
+
+ << "top9" << "top9,child0" << "top9,child1" << "top9,child2" << "top9,child3"
+ << "top9,child4" << "top9,child5" << "top9,child6" << "top9,child7"
+ << "top9,child8" << "top9,child9" << "top9,child10" << "top9,child11"
+ << "top9,child12" << "top9,child13" << "top9,child15"
+
+ << "top10" << "top10,child0" << "top10,child1" << "top10,child2" << "top10,child3"
+ << "top10,child4" << "top10,child5" << "top10,child6" << "top10,child7"
+ << "top10,child8" << "top10,child9" << "top10,child10" << "top10,child11"
+ << "top10,child12" << "top10,child13" << "top10,child15"
+
+ << "top11" << "top11,child0" << "top11,child1" << "top11,child2" << "top11,child3"
+ << "top11,child4" << "top11,child5" << "top11,child6" << "top11,child7"
+ << "top11,child8" << "top11,child9" << "top11,child10" << "top11,child11"
+ << "top11,child12" << "top11,child13" << "top11,child15"
+
+ << "top12" << "top12,child0" << "top12,child1" << "top12,child2" << "top12,child3"
+ << "top12,child4" << "top12,child5" << "top12,child6" << "top12,child7"
+ << "top12,child8" << "top12,child9" << "top12,child10" << "top12,child11"
+ << "top12,child12" << "top12,child13" << "top12,child15"
+
+ << "top13" << "top13,child0" << "top13,child1" << "top13,child2" << "top13,child3"
+ << "top13,child4" << "top13,child5" << "top13,child6" << "top13,child7"
+ << "top13,child8" << "top13,child9" << "top13,child10" << "top13,child11"
+ << "top13,child12" << "top13,child13" << "top13,child15"
+
+ /* "top14"*/<< "top14,child0" << "top14,child1" << "top14,child2" << "top14,child3"
+ << "top14,child4" << "top14,child5" << "top14,child6" << "top14,child7"
+ << "top14,child8" << "top14,child9" << "top14,child10" << "top14,child11"
+ << "top14,child12" << "top14,child13" << "top14,child15"
+
+ << "top15" << "top15,child0" << "top15,child1" << "top15,child2" << "top15,child3"
+ << "top15,child4" << "top15,child5" << "top15,child6" << "top15,child7"
+ << "top15,child8" << "top15,child9" << "top15,child10" << "top15,child11"
+ << "top15,child12" << "top15,child13" << "top15,child15"
+
+ /* "top16"*/<< "top16,child0" << "top16,child1" << "top16,child2" << "top16,child3"
+ << "top16,child4" << "top16,child5" << "top16,child6" << "top16,child7"
+ << "top16,child8" << "top16,child9" << "top16,child10" << "top16,child11"
+ << "top16,child12" << "top16,child13" << "top16,child15");
+
+
+
+ QTest::newRow("Match Disabled") << 0 << (int)QTreeWidgetItemIterator::Disabled
+ << (QStringList()
+ << "top0,child11"
+ << "top1,child11"
+ << "top2,child11"
+ << "top3,child11"
+ << "top4,child11"
+ << "top5,child11"
+ << "top6,child11"
+ << "top7,child11"
+ << "top8,child11"
+ << "top9,child11"
+ << "top10,child11"
+ << "top11"
+ << "top11,child0"
+ << "top11,child1"
+ << "top11,child2"
+ << "top11,child3"
+ << "top11,child4"
+ << "top11,child5"
+ << "top11,child6"
+ << "top11,child7"
+ << "top11,child8"
+ << "top11,child9"
+ << "top11,child10"
+ << "top11,child11"
+ << "top11,child12"
+ << "top11,child13"
+ << "top11,child14"
+ << "top11,child15"
+ << "top11,child16"
+
+ << "top12,child11"
+ << "top13,child11"
+ << "top14,child11"
+ << "top15,child11"
+ << "top16,child11");
+
+ QTest::newRow("Match Editable") << 0 << (int)QTreeWidgetItemIterator::Editable
+ << (QStringList()
+ << "top0,child12"
+ << "top1,child12"
+ << "top2,child12"
+ << "top3,child12"
+ << "top4,child12"
+ << "top5,child12"
+ << "top6,child12"
+ << "top7,child12"
+ << "top8,child12"
+ << "top9,child12"
+ << "top10,child12"
+ << "top11,child12"
+ << "top12"
+ << "top12,child12"
+ << "top13,child12"
+ << "top14,child12"
+ << "top15,child12"
+ << "top16,child12");
+
+ QTest::newRow("Match mutually exclusive Hidden|NotHidden") << 0 << (int)(QTreeWidgetItemIterator::Hidden|QTreeWidgetItemIterator::NotHidden)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive Selected|Unselected") << 0 << (int)(QTreeWidgetItemIterator::Selected|QTreeWidgetItemIterator::Unselected)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive Selectable|NotSelectable") << 0 << (int)(QTreeWidgetItemIterator::Selectable|QTreeWidgetItemIterator::NotSelectable)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive DragEnabled|DragDisabled") << 0 << (int)(QTreeWidgetItemIterator::DragEnabled|QTreeWidgetItemIterator::DragDisabled)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive DropEnabled|DropDisabled") << 0 << (int)(QTreeWidgetItemIterator::DropEnabled|QTreeWidgetItemIterator::DropDisabled)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive HasChildren|NoChildren") << 0 << (int)(QTreeWidgetItemIterator::HasChildren|QTreeWidgetItemIterator::NoChildren)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive Checked|NotChecked") << 0 << (int)(QTreeWidgetItemIterator::Checked|QTreeWidgetItemIterator::NotChecked)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive Disabled|Enabled") << 0 << (int)(QTreeWidgetItemIterator::Disabled|QTreeWidgetItemIterator::Enabled)
+ << QStringList();
+ QTest::newRow("Match mutually exclusive Editable|NotEditable") << 0 << (int)(QTreeWidgetItemIterator::Editable|QTreeWidgetItemIterator::NotEditable)
+ << QStringList();
+}
+
+void tst_QTreeWidgetItemIterator::iteratorflags()
+{
+ QFETCH(int, start);
+ QFETCH(int, iteratorflags);
+ QFETCH(QStringList, matches);
+
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::IteratorFlags(iteratorflags));
+ it+=start;
+ int iMatch = 0;
+ while (*it && iMatch < matches.count()) {
+ QTreeWidgetItem *item = *it;
+ QCOMPARE(item->text(0), matches[iMatch]);
+ ++it;
+ ++iMatch;
+ }
+ // Make sure the expected result does not contain *more* items than the actual result.
+ QCOMPARE(iMatch, matches.size());
+}
+
+void tst_QTreeWidgetItemIterator::preincrement()
+{
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::All);
+ QTreeWidgetItem *item = *(++it);
+ // should be the second one
+ QCOMPARE(item->text(0), QString("top0,child0"));
+}
+
+void tst_QTreeWidgetItemIterator::postincrement()
+{
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::All);
+ QTreeWidgetItem *item = *(it++);
+ // should be the first one
+ QCOMPARE(item->text(0), QString("top0"));
+}
+
+void tst_QTreeWidgetItemIterator::predecrement()
+{
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::All);
+ QTreeWidgetItem *item = *(++it);
+ // should be the second one
+ QCOMPARE(item->text(0), QString("top0,child0"));
+
+ item = *(--it);
+ QCOMPARE(item->text(0), QString("top0"));
+
+}
+
+void tst_QTreeWidgetItemIterator::postdecrement()
+{
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::All);
+ QTreeWidgetItem *item = *(it++);
+ // should be the first one
+ QCOMPARE(item->text(0), QString("top0"));
+
+ //Iterator points to second one
+ item = *(it--);
+ QCOMPARE(item->text(0), QString("top0,child0"));
+
+}
+
+void tst_QTreeWidgetItemIterator::plus_eq_data()
+{
+ QTest::addColumn<int>("start");
+ QTest::addColumn<int>("addition");
+ QTest::addColumn<int>("iteratorflags");
+ QTest::addColumn<QString>("expecteditem");
+
+ QTest::newRow("+=0") << 0 << 0 << (int)QTreeWidgetItemIterator::All << QString("top0");
+ QTest::newRow("+=1") << 0 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0,child0");
+ QTest::newRow("+=2") << 0 << 2 << (int)QTreeWidgetItemIterator::All << QString("top0,child1");
+ QTest::newRow("+=(-1)") << 1 << -1 << (int)QTreeWidgetItemIterator::All << QString("top0");
+ QTest::newRow("+=(-2)") << 3 << -2 << (int)QTreeWidgetItemIterator::All << QString("top0,child0");
+}
+
+void tst_QTreeWidgetItemIterator::plus_eq()
+{
+ QFETCH(int, start);
+ QFETCH(int, addition);
+ QFETCH(int, iteratorflags);
+ QFETCH(QString, expecteditem);
+
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::IteratorFlags(iteratorflags));
+ it+=start;
+ it+=addition;
+ QTreeWidgetItem *item = *it;
+
+ QVERIFY(item);
+ QCOMPARE(item->text(0), expecteditem);
+
+}
+
+void tst_QTreeWidgetItemIterator::minus_eq_data()
+{
+ QTest::addColumn<int>("start");
+ QTest::addColumn<int>("subtraction");
+ QTest::addColumn<int>("iteratorflags");
+ QTest::addColumn<QString>("expecteditem");
+
+ QTest::newRow("-=0") << 0 << 0 << (int)QTreeWidgetItemIterator::All << QString("top0");
+ QTest::newRow("-=1") << 2 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0,child0");
+ QTest::newRow("-=2") << 4 << 2 << (int)QTreeWidgetItemIterator::All << QString("top0,child1");
+ QTest::newRow("-=(-1)") << 0 << -1 << (int)QTreeWidgetItemIterator::All << QString("top0,child0");
+ QTest::newRow("-=(-2)") << 0 << -2 << (int)QTreeWidgetItemIterator::All << QString("top0,child1");
+ QTest::newRow("-=1)") << 18 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0,child16");
+ QTest::newRow("-=1)") << 1 << 1 << (int)QTreeWidgetItemIterator::All << QString("top0");
+}
+
+void tst_QTreeWidgetItemIterator::minus_eq()
+{
+ QFETCH(int, start);
+ QFETCH(int, subtraction);
+ QFETCH(int, iteratorflags);
+ QFETCH(QString, expecteditem);
+
+ QTreeWidgetItemIterator it(testWidget, QTreeWidgetItemIterator::IteratorFlags(iteratorflags));
+ it+=start;
+ it-=subtraction;
+ QTreeWidgetItem *item = *it;
+ // should be the first one
+ QVERIFY(item);
+ QCOMPARE(item->text(0), expecteditem);
+}
+
+void tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget_data()
+{
+ QTest::addColumn<int>("topLevelItems");
+ QTest::addColumn<int>("childItems");
+ QTest::addColumn<int>("grandChildItems");
+ QTest::addColumn<int>("iteratorflags");
+ QTest::addColumn<int>("removeindex");
+ QTest::addColumn<int>("expecteditemindex");
+ QTest::addColumn<QString>("expecteditemvalue");
+ QTest::addColumn<QString>("expectedUpdatedCurrent");
+ QTest::addColumn<int>("expecteditemIsNull");
+
+ QTest::newRow("Remove 3, check 1") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All
+ << 3 << 1 << QString("top0,child0") << QString("top1") << 0;
+ QTest::newRow("Remove 1, check 0") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All
+ << 1 << 0 << QString("top0") << QString("top0,child1") << 0;
+ QTest::newRow("Remove 2, check 2") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All
+ << 2 << 2 << QString("top0,child2") << QString("top0,child2") << 0;
+ QTest::newRow("Remove 0, check 0") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 0 << 0 << QString("top1") << QString("top1") << 0;
+ QTest::newRow("Remove top1, check top1") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 13 << 13 << QString("top2") << QString("top2") << 0;
+ QTest::newRow("Remove top0, check top1") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 0 << 13 << QString("top1") << QString("top1") << 0;
+ QTest::newRow("Remove (top0,child1), check (top0,child1)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 5 << 5 << QString("top0,child2") << QString("top0,child2") << 0;
+ QTest::newRow("Remove (t0,c0) check (t0,c0)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 1 << 1 << QString("top0,child1") << QString("top0,child1") << 0;
+ QTest::newRow("Remove (t0,c1) check (t0,c1)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 5 << 5 << QString("top0,child2") << QString("top0,child2") << 0;
+ QTest::newRow("Remove (t0) check (t0,c1)") << 3 << 3 << 0 << (int)QTreeWidgetItemIterator::All
+ << 0 << 4 << QString("top1") << QString("top1") << 0;
+ QTest::newRow("Remove (t0) check (t0,c0,g1)") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 0 << 3 << QString("top1") << QString("top1") << 0;
+ QTest::newRow("Remove (top2), check if top2 is null") << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All
+ << 2*13 << 2*13 << QString() << QString() << 1;
+ QTest::newRow("Remove last item, check if iterator::current returns 0")
+ << 3 << 0 << 0 << (int)QTreeWidgetItemIterator::All << 2 << 2 << QString() << QString() << 1;
+ QTest::newRow("remove 1, iterator points to 3, should move to 1")
+ << 3 << 3 << 3 << (int)QTreeWidgetItemIterator::All << 1 << 3 << QString("top0,child1") << QString("top0,child1") << 0;
+}
+
+void tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget()
+{
+ QFETCH(int, topLevelItems);
+ QFETCH(int, childItems);
+ QFETCH(int, grandChildItems);
+ QFETCH(int, iteratorflags);
+ QFETCH(int, removeindex);
+ QFETCH(int, expecteditemindex);
+ QFETCH(QString, expecteditemvalue);
+ QFETCH(QString, expectedUpdatedCurrent);
+ QFETCH(int, expecteditemIsNull);
+
+ QTreeWidget tw;
+ tw.clear();
+ tw.setColumnCount(2);
+ for (int i1=0; i1 < topLevelItems; ++i1) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(&tw);
+ top->setText(0, QString("top%1").arg(i1));
+ for (int i2=0; i2 < childItems; ++i2) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(top);
+ child->setText(0, QString("top%1,child%2").arg(i1).arg(i2));
+ for (int i3=0; i3 < grandChildItems; ++i3) {
+ QTreeWidgetItem *grandChild = new QTreeWidgetItem(child);
+ grandChild->setText(0, QString("top%1,child%2,grandchild%3").arg(i1).arg(i2).arg(i3));
+ }
+ }
+ }
+
+ QTreeWidgetItemIterator it(&tw, QTreeWidgetItemIterator::IteratorFlags(iteratorflags));
+ it+=expecteditemindex;
+ QTreeWidgetItem *item = 0;
+ QTreeWidgetItemIterator itRemove(&tw, QTreeWidgetItemIterator::IteratorFlags(iteratorflags));
+ itRemove+=removeindex;
+ item = *itRemove;
+ QVERIFY(item);
+ delete item;
+ item = *it;
+ if (expecteditemIsNull) {
+ QVERIFY(item == 0);
+ } else {
+ QVERIFY(item);
+ QCOMPARE(item->text(0), expecteditemvalue);
+ item = *itRemove;
+ if (expectedUpdatedCurrent.isNull()) {
+ QVERIFY(item == 0);
+ } else {
+ QCOMPARE(item->text(0), expectedUpdatedCurrent);
+ }
+ }
+}
+
+void tst_QTreeWidgetItemIterator::updateIteratorAfterDeletedItem_and_ContinueIteration_data()
+{
+ QTest::addColumn<int>("topLevelItems");
+ QTest::addColumn<int>("childItems");
+ QTest::addColumn<int>("grandChildItems"); // Populate the tree data
+ // we have one iterator pointing to an item in the tree.
+ // This iterator will be updated if we delete the item it is pointing to.
+ //
+ QTest::addColumn<int>("removeindex"); // The index of the node we want to remove
+ QTest::addColumn<int>("iterator_initial_index"); // The new expected index of
+ QTest::addColumn<int>("iterator_advance_after_removal");
+ QTest::addColumn<QString>("iterator_new_value"); // The new current item value of the iterator
+ QTest::newRow("Remove 13, it points to 25, it-=1. We should get top0,child2,grandchild2") << 3 << 3 << 3 << 13 << 25 << -1 << QString("top0,child2,grandchild2");
+ QTest::newRow("Remove 0, it points to 12, it+=1. We should get top1,child0") << 3 << 3 << 3 << 0 << 12 << 1 << QString("top1,child0");
+ QTest::newRow("Remove 0, it points to 12, it-=1. We should get 0") << 3 << 3 << 3 << 0 << 12 << -1 << QString();
+ QTest::newRow("Remove 0, it points to 1, it+=1. We should get top2") << 4 << 0 << 0 << 0 << 1 << 1 << QString("top2");
+ QTest::newRow("Remove 2, it points to 1, it+=0. We should get top1") << 4 << 0 << 0 << 2 << 1 << 0 << QString("top1");
+ QTest::newRow("Remove 2, it points to 1, it+=1. We should get top3") << 4 << 0 << 0 << 2 << 1 << 1 << QString("top3");
+ QTest::newRow("Remove 1, it points to 2, it+=1. We should get top0,child2") << 3 << 3 << 0 << 1 << 2 << 1 << QString("top0,child2");
+ QTest::newRow("Remove 1, it points to 2, it+=0. We should get top0,child1") << 3 << 3 << 0 << 1 << 2 << 0 << QString("top0,child1");
+ QTest::newRow("Remove 1, it points to 2, it-=1. We should get top0") << 3 << 3 << 0 << 1 << 2 << -1 << QString("top0");
+}
+
+void tst_QTreeWidgetItemIterator::updateIteratorAfterDeletedItem_and_ContinueIteration()
+{
+ QFETCH(int, topLevelItems);
+ QFETCH(int, childItems);
+ QFETCH(int, grandChildItems);
+ QFETCH(int, removeindex);
+ QFETCH(int, iterator_initial_index);
+ QFETCH(int, iterator_advance_after_removal);
+ QFETCH(QString, iterator_new_value);
+
+ QTreeWidget tw;
+ tw.clear();
+ tw.setColumnCount(2);
+ for (int i1=0; i1 < topLevelItems; ++i1) {
+ QTreeWidgetItem *top = new QTreeWidgetItem(&tw);
+ top->setText(0, QString("top%1").arg(i1));
+ for (int i2=0; i2 < childItems; ++i2) {
+ QTreeWidgetItem *child = new QTreeWidgetItem(top);
+ child->setText(0, QString("top%1,child%2").arg(i1).arg(i2));
+ for (int i3=0; i3 < grandChildItems; ++i3) {
+ QTreeWidgetItem *grandChild = new QTreeWidgetItem(child);
+ grandChild->setText(0, QString("top%1,child%2,grandchild%3").arg(i1).arg(i2).arg(i3));
+ }
+ }
+ }
+
+ QTreeWidgetItemIterator it(&tw, QTreeWidgetItemIterator::All);
+ it += iterator_initial_index;
+ QTreeWidgetItem *item = 0;
+ QTreeWidgetItemIterator itRemove(&tw, QTreeWidgetItemIterator::All);
+ itRemove+=removeindex;
+ item = *itRemove;
+ QVERIFY(item);
+ delete item;
+ it+=iterator_advance_after_removal;
+ if (iterator_new_value.isNull()) {
+ QCOMPARE((*it), (QTreeWidgetItem*)0);
+ } else {
+ QCOMPARE((*it)->text(0), iterator_new_value);
+ }
+}
+
+void tst_QTreeWidgetItemIterator::constructIteratorWithItem_data()
+{
+ QTest::addColumn<int>("indextoitem");
+ QTest::addColumn<int>("iteratorflags");
+ QTest::addColumn<QString>("expecteditem");
+
+ QTest::newRow("index 0") << 0 << 0 << QString("top0");
+ QTest::newRow("index 1") << 1 << 0 << QString("top0,child0");
+ QTest::newRow("index 2") << 2 << 0 << QString("top0,child1");
+ QTest::newRow("index 30") << 30 << 0 << QString("top1,child11");
+ QTest::newRow("305 (last item)") << 305 << 0 << QString("top16,child16");
+ QTest::newRow("index 0, advance to next matching node") << 0 << (int)QTreeWidgetItemIterator::NotHidden << QString("top0,child1");
+}
+
+void tst_QTreeWidgetItemIterator::constructIteratorWithItem()
+{
+ QFETCH(int, indextoitem);
+ QFETCH(int, iteratorflags);
+ QFETCH(QString, expecteditem);
+
+ QTreeWidgetItemIterator it(testWidget);
+ it+=indextoitem;
+ QTreeWidgetItem *item = *it;
+ QTreeWidgetItemIterator it2(item, QTreeWidgetItemIterator::IteratorFlags(iteratorflags));
+ QTreeWidgetItem *item2 = *it2;
+
+ QVERIFY(item2);
+ QCOMPARE(item2->text(0), expecteditem);
+
+}
+
+void tst_QTreeWidgetItemIterator::initializeIterator()
+{
+ QTreeWidget tw;
+ QTreeWidgetItemIterator it(&tw);
+
+ QCOMPARE((*it), static_cast<QTreeWidgetItem*>(0));
+}
+
+QTEST_MAIN(tst_QTreeWidgetItemIterator)
+#include "tst_qtreewidgetitemiterator.moc"