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
+