summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/itemmodels
diff options
context:
space:
mode:
authorStephen Kelly <stephen.kelly@kdab.com>2011-12-10 19:13:51 +0100
committerQt by Nokia <qt-info@nokia.com>2011-12-16 13:00:57 +0100
commit211e434a05c666e172b2f1e2f72c7695adac52a1 (patch)
tree6315f01354f3627bab40e334b5752eb1d17f17b6 /tests/auto/corelib/itemmodels
parent9bc4b56656a5acabba09093e3da145bf6a4bca62 (diff)
Move proxy and selection models to QtCore.
Change-Id: I71097855cb9e28105238e496778f29f99f7fc84e Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'tests/auto/corelib/itemmodels')
-rw-r--r--tests/auto/corelib/itemmodels/itemmodels.pro7
-rw-r--r--tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp4
-rw-r--r--tests/auto/corelib/itemmodels/qabstractproxymodel/.gitignore1
-rw-r--r--tests/auto/corelib/itemmodels/qabstractproxymodel/qabstractproxymodel.pro4
-rw-r--r--tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp449
-rw-r--r--tests/auto/corelib/itemmodels/qidentityproxymodel/qidentityproxymodel.pro8
-rw-r--r--tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp330
-rw-r--r--tests/auto/corelib/itemmodels/qitemselectionmodel/.gitignore1
-rw-r--r--tests/auto/corelib/itemmodels/qitemselectionmodel/qitemselectionmodel.pro6
-rw-r--r--tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp2752
-rw-r--r--tests/auto/corelib/itemmodels/qsortfilterproxymodel/.gitignore1
-rw-r--r--tests/auto/corelib/itemmodels/qsortfilterproxymodel/qsortfilterproxymodel.pro9
-rw-r--r--tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp3463
-rw-r--r--tests/auto/corelib/itemmodels/qstringlistmodel/.gitignore1
-rw-r--r--tests/auto/corelib/itemmodels/qstringlistmodel/qmodellistener.h75
-rw-r--r--tests/auto/corelib/itemmodels/qstringlistmodel/qstringlistmodel.pro9
-rw-r--r--tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp283
17 files changed, 7400 insertions, 3 deletions
diff --git a/tests/auto/corelib/itemmodels/itemmodels.pro b/tests/auto/corelib/itemmodels/itemmodels.pro
index c11a1f120b..c5124c3241 100644
--- a/tests/auto/corelib/itemmodels/itemmodels.pro
+++ b/tests/auto/corelib/itemmodels/itemmodels.pro
@@ -1,5 +1,10 @@
TEMPLATE=subdirs
-SUBDIRS = qabstractitemmodel
+SUBDIRS = qabstractitemmodel \
+ qabstractproxymodel \
+ qidentityproxymodel \
+ qitemselectionmodel \
+ qsortfilterproxymodel \
+ qstringlistmodel
mac: qabstractitemmodel.CONFIG = no_check_target # QTBUG-22748
diff --git a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
index 2340c86207..199d96c0d1 100644
--- a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
+++ b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
@@ -42,8 +42,8 @@
#include <QtTest/QtTest>
#include <QtCore/QtCore>
-#include <QtWidgets/QSortFilterProxyModel>
-#include <QtWidgets/QStringListModel>
+#include <QtCore/QSortFilterProxyModel>
+#include <QtCore/QStringListModel>
#include "dynamictreemodel.h"
diff --git a/tests/auto/corelib/itemmodels/qabstractproxymodel/.gitignore b/tests/auto/corelib/itemmodels/qabstractproxymodel/.gitignore
new file mode 100644
index 0000000000..bffc04d632
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qabstractproxymodel/.gitignore
@@ -0,0 +1 @@
+tst_qabstractproxymodel
diff --git a/tests/auto/corelib/itemmodels/qabstractproxymodel/qabstractproxymodel.pro b/tests/auto/corelib/itemmodels/qabstractproxymodel/qabstractproxymodel.pro
new file mode 100644
index 0000000000..5ded15ad5c
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qabstractproxymodel/qabstractproxymodel.pro
@@ -0,0 +1,4 @@
+CONFIG += testcase
+TARGET = tst_qabstractproxymodel
+QT += widgets testlib
+SOURCES += tst_qabstractproxymodel.cpp
diff --git a/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp b/tests/auto/corelib/itemmodels/qabstractproxymodel/tst_qabstractproxymodel.cpp
new file mode 100644
index 0000000000..b6557c45ec
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/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/corelib/itemmodels/qidentityproxymodel/qidentityproxymodel.pro b/tests/auto/corelib/itemmodels/qidentityproxymodel/qidentityproxymodel.pro
new file mode 100644
index 0000000000..4fb8c98fe7
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qidentityproxymodel/qidentityproxymodel.pro
@@ -0,0 +1,8 @@
+CONFIG += testcase
+TARGET = tst_qidentityproxymodel
+
+mtdir = ../../../other/modeltest
+INCLUDEPATH += $$PWD/$${mtdir}
+QT += widgets testlib
+SOURCES += tst_qidentityproxymodel.cpp $${mtdir}/dynamictreemodel.cpp $${mtdir}/modeltest.cpp
+HEADERS += $${mtdir}/dynamictreemodel.h $${mtdir}/modeltest.h
diff --git a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp
new file mode 100644
index 0000000000..86ff00f9d4
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp
@@ -0,0 +1,330 @@
+/****************************************************************************
+**
+** 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"
+
+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/corelib/itemmodels/qitemselectionmodel/.gitignore b/tests/auto/corelib/itemmodels/qitemselectionmodel/.gitignore
new file mode 100644
index 0000000000..aa543a200a
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/.gitignore
@@ -0,0 +1 @@
+tst_qitemselectionmodel
diff --git a/tests/auto/corelib/itemmodels/qitemselectionmodel/qitemselectionmodel.pro b/tests/auto/corelib/itemmodels/qitemselectionmodel/qitemselectionmodel.pro
new file mode 100644
index 0000000000..a4c7ba3786
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/qitemselectionmodel.pro
@@ -0,0 +1,6 @@
+CONFIG += testcase
+TARGET = tst_qitemselectionmodel
+QT += widgets testlib
+SOURCES += tst_qitemselectionmodel.cpp
+
+
diff --git a/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp
new file mode 100644
index 0000000000..2097cb31ee
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qitemselectionmodel/tst_qitemselectionmodel.cpp
@@ -0,0 +1,2752 @@
+/****************************************************************************
+**
+** 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>
+
+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();
+ void testClearCurrentIndex();
+
+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;
+
+ void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
+ {
+ QItemSelectionModel::setCurrentIndex(index, command);
+ m_target->setCurrentIndex(index, command);
+ }
+
+ void clearCurrentIndex()
+ {
+ QItemSelectionModel::clearCurrentIndex();
+ m_target->clearCurrentIndex();
+ }
+
+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);
+ }
+
+ duplicate.setCurrentIndex(model.index(0, 0), QItemSelectionModel::NoUpdate);
+
+ QVERIFY(selectionModel.currentIndex() == duplicate.currentIndex());
+
+ duplicate.clearCurrentIndex();
+
+ QVERIFY(!duplicate.currentIndex().isValid());
+ QVERIFY(selectionModel.currentIndex() == duplicate.currentIndex());
+}
+
+void tst_QItemSelectionModel::testClearCurrentIndex()
+{
+ QStringListModel model(QStringList() << "Apples" << "Pears");
+
+ QItemSelectionModel selectionModel(&model, 0);
+
+ QSignalSpy currentIndexSpy(&selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)));
+
+ QModelIndex firstIndex = model.index(0, 0);
+ QVERIFY(firstIndex.isValid());
+ selectionModel.setCurrentIndex(firstIndex, QItemSelectionModel::NoUpdate);
+ QVERIFY(selectionModel.currentIndex() == firstIndex);
+ QVERIFY(currentIndexSpy.size() == 1);
+
+ selectionModel.clearCurrentIndex();
+
+ QVERIFY(selectionModel.currentIndex() == QModelIndex());
+ QVERIFY(currentIndexSpy.size() == 2);
+}
+
+QTEST_MAIN(tst_QItemSelectionModel)
+#include "tst_qitemselectionmodel.moc"
diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/.gitignore b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/.gitignore
new file mode 100644
index 0000000000..d3672fe4ae
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/.gitignore
@@ -0,0 +1 @@
+tst_qsortfilterproxymodel
diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/qsortfilterproxymodel.pro b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/qsortfilterproxymodel.pro
new file mode 100644
index 0000000000..d6e949f73d
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/qsortfilterproxymodel.pro
@@ -0,0 +1,9 @@
+CONFIG += testcase
+TARGET = tst_qsortfilterproxymodel
+
+QT += gui widgets testlib
+mtdir = ../../../other/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/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
new file mode 100644
index 0000000000..cc8299e28f
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
@@ -0,0 +1,3463 @@
+/****************************************************************************
+**
+** 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>
+
+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();
+
+ void testParentLayoutChanged();
+ void moveSourceRows();
+
+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");
+
+ QTest::newRow("flat ascending")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList()
+ << "c" << "f" << "d" << "e" << "a" << "b")
+ << (QStringList()
+ << "a" << "b" << "c" << "d" << "e" << "f");
+
+ QTest::newRow("simple hierarchy")
+ << static_cast<int>(Qt::AscendingOrder)
+ << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">")
+ << (QStringList() << "a" << "<" << "b" << "<" << "c" << ">" << ">");
+
+ 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"
+ << ">");
+}
+
+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 beginning")
+ << (QStringList()
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ << "One")
+ << 0;
+
+ QTest::newRow("insert one row in the end")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList()
+ <<"Five")
+ << 4;
+}
+
+void tst_QSortFilterProxyModel::insertRows()
+{
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ QFETCH(QStringList, insert);
+ QFETCH(int, position);
+ // prepare model
+ m_model->insertRows(0, initial.count(), QModelIndex());
+ //m_model->insertColumns(0, 1, QModelIndex());
+ QCOMPARE(m_model->columnCount(QModelIndex()), 1);
+ QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ m_model->setData(index, initial.at(row), Qt::DisplayRole);
+ }
+ // make sure the model correct before insert
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+ // make sure the proxy is correct before insert
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ // insert the row
+ m_proxy->insertRows(position, insert.count(), QModelIndex());
+ QCOMPARE(m_model->rowCount(QModelIndex()), expected.count());
+ QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count());
+
+ // set the data for the inserted row
+ for (int i = 0; i < insert.count(); ++i) {
+ QModelIndex index = m_proxy->index(position + i, 0, QModelIndex());
+ m_proxy->setData(index, insert.at(i), Qt::DisplayRole);
+ }
+
+ // make sure the model correct after insert
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ // make sure the proxy is correct after insert
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+void tst_QSortFilterProxyModel::prependRow()
+{
+ //this tests that data is correctly handled by the sort filter when prepending a row
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QStandardItem item("root");
+ model.appendRow(&item);
+
+ QStandardItem sub("sub");
+ item.appendRow(&sub);
+
+ sub.appendRow(new QStandardItem("test1"));
+ sub.appendRow(new QStandardItem("test2"));
+
+ QStandardItem sub2("sub2");
+ sub2.appendRow(new QStandardItem("sub3"));
+ item.insertRow(0, &sub2);
+
+ QModelIndex index_sub2 = proxy.mapFromSource(model.indexFromItem(&sub2));
+
+ QCOMPARE(sub2.rowCount(), proxy.rowCount(index_sub2));
+ QCOMPARE(proxy.rowCount(QModelIndex()), 1); //only the "root" item is there
+}
+
+
+/*
+void tst_QSortFilterProxyModel::insertColumns_data()
+{
+
+}
+
+void tst_QSortFilterProxyModel::insertColumns()
+{
+
+}
+*/
+
+void tst_QSortFilterProxyModel::removeRows_data()
+{
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<int>("position");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<bool>("success");
+ QTest::addColumn<QStringList>("expectedProxy");
+ QTest::addColumn<QStringList>("expectedSource");
+
+ QTest::newRow("remove one row in the middle [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove one row in the beginning [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 0 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove one row in the end [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 4 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four");
+
+ QTest::newRow("remove all [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 0 // position
+ << 5 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << QStringList(); // expectedSource
+
+ QTest::newRow("remove one row past the end [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 5 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove row -1 [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << -1 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five");
+
+ QTest::newRow("remove three rows in the middle [no sorting/filter]")
+ << (QStringList()
+ << "One"
+ << "Two"
+ << "Three"
+ << "Four"
+ << "Five")
+ << -1 // no sorting
+ << QString() // no filter
+ << 1 // position
+ << 3 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "One"
+ << "Five")
+ << (QStringList() // expectedSource
+ << "One"
+ << "Five");
+
+ QTest::newRow("remove one row in the middle [ascending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QString() // no filter
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "2"
+ << "4");
+
+ QTest::newRow("remove two rows in the middle [ascending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QString() // no filter
+ << 2 // position
+ << 2 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "2");
+
+ QTest::newRow("remove two rows in the middle [descending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::DescendingOrder)
+ << QString() // no filter
+ << 2 // position
+ << 2 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "5"
+ << "4"
+ << "1")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "4");
+
+ QTest::newRow("remove one row in the middle [no sorting, filter=5|2|3]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << -1 // no sorting
+ << QString("5|2|3")
+ << 1 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "5"
+ << "3")
+ << (QStringList() // expectedSource
+ << "1"
+ << "5"
+ << "4"
+ << "3");
+
+ QTest::newRow("remove all [ascending sorting, no filter]")
+ << (QStringList()
+ << "1"
+ << "5"
+ << "2"
+ << "4"
+ << "3")
+ << static_cast<int>(Qt::AscendingOrder)
+ << QString() // no filter
+ << 0 // position
+ << 5 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << QStringList(); // expectedSource
+}
+
+void tst_QSortFilterProxyModel::removeRows()
+{
+ QFETCH(QStringList, initial);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, filter);
+ QFETCH(int, position);
+ QFETCH(int, count);
+ QFETCH(bool, success);
+ QFETCH(QStringList, expectedProxy);
+ QFETCH(QStringList, expectedSource);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ // prepare model
+ foreach (QString s, initial)
+ model.appendRow(new QStandardItem(s));
+
+ if (sortOrder != -1)
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ if (!filter.isEmpty())
+ proxy.setFilterRegExp(QRegExp(filter));
+
+ // remove the rows
+ QCOMPARE(proxy.removeRows(position, count, QModelIndex()), success);
+ QCOMPARE(model.rowCount(QModelIndex()), expectedSource.count());
+ QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxy.count());
+
+ // make sure the model is correct after remove
+ for (int row = 0; row < model.rowCount(QModelIndex()); ++row)
+ QCOMPARE(model.item(row)->text(), expectedSource.at(row));
+
+ // make sure the proxy is correct after remove
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expectedProxy.at(row));
+ }
+}
+
+class MyFilteredColumnProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ MyFilteredColumnProxyModel(QObject *parent = 0)
+ : QSortFilterProxyModel(parent) { }
+protected:
+ bool filterAcceptsColumn(int sourceColumn, const QModelIndex &) const
+ {
+ QString key = sourceModel()->headerData(sourceColumn, Qt::Horizontal).toString();
+ return key.contains(filterRegExp());
+ }
+};
+
+void tst_QSortFilterProxyModel::removeColumns_data()
+{
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<int>("position");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<bool>("success");
+ QTest::addColumn<QStringList>("expectedProxy");
+ QTest::addColumn<QStringList>("expectedSource");
+
+ QTest::newRow("remove one column in the middle [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove one column in the end [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 4 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "3"
+ << "4")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4");
+
+ QTest::newRow("remove one column past the end [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 5 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove column -1 [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << -1 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove all columns [no filter]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString() // no filter
+ << 0 // position
+ << 5 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << QStringList(); // expectedSource
+
+ QTest::newRow("remove one column in the middle [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 1 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove one column in the end [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 2 // position
+ << 1 // count
+ << true // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "3")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4");
+
+ QTest::newRow("remove one column past the end [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 3 // position
+ << 1 // count
+ << false // success
+ << (QStringList() // expectedProxy
+ << "1"
+ << "3"
+ << "5")
+ << (QStringList() // expectedSource
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5");
+
+ QTest::newRow("remove all columns [filter=1|3|5]")
+ << (QStringList()
+ << "1"
+ << "2"
+ << "3"
+ << "4"
+ << "5")
+ << QString("1|3|5")
+ << 0 // position
+ << 3 // count
+ << true // success
+ << QStringList() // expectedProxy
+ << (QStringList() // expectedSource
+ << "2"
+ << "4");
+}
+
+void tst_QSortFilterProxyModel::removeColumns()
+{
+ QFETCH(QStringList, initial);
+ QFETCH(QString, filter);
+ QFETCH(int, position);
+ QFETCH(int, count);
+ QFETCH(bool, success);
+ QFETCH(QStringList, expectedProxy);
+ QFETCH(QStringList, expectedSource);
+
+ QStandardItemModel model;
+ MyFilteredColumnProxyModel proxy;
+ proxy.setSourceModel(&model);
+ if (!filter.isEmpty())
+ proxy.setFilterRegExp(QRegExp(filter));
+
+ // prepare model
+ model.setHorizontalHeaderLabels(initial);
+
+ // remove the columns
+ QCOMPARE(proxy.removeColumns(position, count, QModelIndex()), success);
+ QCOMPARE(model.columnCount(QModelIndex()), expectedSource.count());
+ QCOMPARE(proxy.columnCount(QModelIndex()), expectedProxy.count());
+
+ // make sure the model is correct after remove
+ for (int col = 0; col < model.columnCount(QModelIndex()); ++col)
+ QCOMPARE(model.horizontalHeaderItem(col)->text(), expectedSource.at(col));
+
+ // make sure the proxy is correct after remove
+ for (int col = 0; col < proxy.columnCount(QModelIndex()); ++col) {
+ QCOMPARE(proxy.headerData(col, Qt::Horizontal, Qt::DisplayRole).toString(),
+ expectedProxy.at(col));
+ }
+}
+
+
+void tst_QSortFilterProxyModel::filterColumns_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<bool>("data");
+
+ QTest::newRow("all") << "a"
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima")
+ << true;
+
+ QTest::newRow("some") << "lie"
+ << (QStringList()
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel")
+ << true;
+
+ QTest::newRow("nothing") << "zoo"
+ << (QStringList()
+ << "foxtrot"
+ << "uniform"
+ << "alpha"
+ << "golf")
+ << false;
+}
+
+void tst_QSortFilterProxyModel::filterColumns()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, initial);
+ QFETCH(bool, data);
+ // prepare model
+ m_model->setColumnCount(initial.count());
+ m_model->setRowCount(1);
+ QCOMPARE(m_model->columnCount(QModelIndex()), initial.count());
+ QCOMPARE(m_model->rowCount(QModelIndex()), 1);
+ // set data
+ QCOMPARE(m_model->rowCount(QModelIndex()), 1);
+ for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) {
+ QModelIndex index = m_model->index(0, col, QModelIndex());
+ m_model->setData(index, initial.at(col), Qt::DisplayRole);
+ }
+ m_proxy->setFilterRegExp(pattern);
+ m_proxy->setFilterKeyColumn(-1);
+ // make sure the model is unchanged
+ for (int col = 0; col < m_model->columnCount(QModelIndex()); ++col) {
+ QModelIndex index = m_model->index(0, col, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(col));
+ }
+ // make sure the proxy is filtered
+ QModelIndex index = m_proxy->index(0, 0, QModelIndex());
+ QCOMPARE(index.isValid(), data);
+}
+
+void tst_QSortFilterProxyModel::filter_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+ QTest::newRow("flat") << "e"
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "bravo"
+ << "lima"
+ << "charlie"
+ << "juliet"
+ << "tango"
+ << "hotel"
+ << "uniform"
+ << "alpha"
+ << "echo"
+ << "golf"
+ << "quebec"
+ << "foxtrot"
+ << "india"
+ << "romeo"
+ << "november"
+ << "oskar"
+ << "zulu"
+ << "kilo"
+ << "whiskey"
+ << "mike"
+ << "papa"
+ << "sierra"
+ << "xray"
+ << "viktor")
+ << (QStringList()
+ << "delta"
+ << "yankee"
+ << "charlie"
+ << "juliet"
+ << "hotel"
+ << "echo"
+ << "quebec"
+ << "romeo"
+ << "november"
+ << "whiskey"
+ << "mike"
+ << "sierra");
+}
+
+void tst_QSortFilterProxyModel::filter()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ // prepare model
+ QVERIFY(m_model->insertRows(0, initial.count(), QModelIndex()));
+ QCOMPARE(m_model->rowCount(QModelIndex()), initial.count());
+ // set data
+ QCOMPARE(m_model->columnCount(QModelIndex()), 1);
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ m_model->setData(index, initial.at(row), Qt::DisplayRole);
+ }
+ m_proxy->setFilterRegExp(pattern);
+ // make sure the proxy is unfiltered
+ QCOMPARE(m_proxy->columnCount(QModelIndex()), 1);
+ QCOMPARE(m_proxy->rowCount(QModelIndex()), expected.count());
+ // make sure the model is unchanged
+ for (int row = 0; row < m_model->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_model->index(row, 0, QModelIndex());
+ QCOMPARE(m_model->data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+ // make sure the proxy is filtered
+ for (int row = 0; row < m_proxy->rowCount(QModelIndex()); ++row) {
+ QModelIndex index = m_proxy->index(row, 0, QModelIndex());
+ QCOMPARE(m_proxy->data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+void tst_QSortFilterProxyModel::filterHierarchy_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QStringList>("initial");
+ QTest::addColumn<QStringList>("expected");
+
+ QTest::newRow("flat") << ".*oo"
+ << (QStringList()
+ << "foo" << "boo" << "baz" << "moo" << "laa" << "haa")
+ << (QStringList()
+ << "foo" << "boo" << "moo");
+
+ QTest::newRow("simple hierarchy") << "b.*z"
+ << (QStringList() << "baz" << "<" << "boz" << "<" << "moo" << ">" << ">")
+ << (QStringList() << "baz" << "<" << "boz" << ">");
+}
+
+void tst_QSortFilterProxyModel::filterHierarchy()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QStringList, initial);
+ QFETCH(QStringList, expected);
+ buildHierarchy(initial, m_model);
+ m_proxy->setFilterRegExp(pattern);
+ checkHierarchy(initial, m_model);
+ checkHierarchy(expected, m_proxy);
+}
+
+void tst_QSortFilterProxyModel::buildHierarchy(const QStringList &l, QAbstractItemModel *m)
+{
+ int ind = 0;
+ int row = 0;
+ QStack<int> row_stack;
+ QModelIndex parent;
+ QStack<QModelIndex> parent_stack;
+ for (int i = 0; i < l.count(); ++i) {
+ QString token = l.at(i);
+ if (token == "<") { // start table
+ ++ind;
+ parent_stack.push(parent);
+ row_stack.push(row);
+ parent = m->index(row - 1, 0, parent);
+ row = 0;
+ QVERIFY(m->insertColumns(0, 1, parent)); // add column
+ } else if (token == ">") { // end table
+ --ind;
+ parent = parent_stack.pop();
+ row = row_stack.pop();
+ } else { // append row
+ QVERIFY(m->insertRows(row, 1, parent));
+ QModelIndex index = m->index(row, 0, parent);
+ QVERIFY(index.isValid());
+ m->setData(index, token, Qt::DisplayRole);
+ ++row;
+ }
+ }
+}
+
+void tst_QSortFilterProxyModel::checkHierarchy(const QStringList &l, const QAbstractItemModel *m)
+{
+ int row = 0;
+ int indent = 0;
+ QStack<int> row_stack;
+ QModelIndex parent;
+ QStack<QModelIndex> parent_stack;
+ for (int i = 0; i < l.count(); ++i) {
+ QString token = l.at(i);
+ if (token == "<") { // start table
+ ++indent;
+ parent_stack.push(parent);
+ row_stack.push(row);
+ parent = m->index(row - 1, 0, parent);
+ QVERIFY(parent.isValid());
+ row = 0;
+ } else if (token == ">") { // end table
+ --indent;
+ parent = parent_stack.pop();
+ row = row_stack.pop();
+ } else { // compare row
+ QModelIndex index = m->index(row, 0, parent);
+ QVERIFY(index.isValid());
+ QString str = m->data(index, Qt::DisplayRole).toString();
+ QCOMPARE(str, token);
+ ++row;
+ }
+ }
+}
+
+
+
+class TestModel: public QAbstractTableModel
+{
+public:
+ int rowCount(const QModelIndex &) const { return 10000; }
+ int columnCount(const QModelIndex &) const { return 1; }
+ QVariant data(const QModelIndex &index, int role) const
+ {
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ return QString::number(index.row());
+ }
+};
+
+void tst_QSortFilterProxyModel::filterTable()
+{
+ TestModel model;
+ QSortFilterProxyModel filter;
+ filter.setSourceModel(&model);
+ filter.setFilterRegExp("9");
+
+ for (int i = 0; i < filter.rowCount(); ++i)
+ QVERIFY(filter.data(filter.index(i, 0)).toString().contains("9"));
+}
+
+void tst_QSortFilterProxyModel::insertAfterSelect()
+{
+ QStandardItemModel model(10, 2);
+ for (int i = 0; i<10;i++)
+ model.setData(model.index(i, 0), QVariant(i));
+ QSortFilterProxyModel filter;
+ filter.setSourceModel(&model);
+ QTreeView view;
+ view.setModel(&filter);
+ view.show();
+ QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex()));
+ QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model());
+ QVERIFY(firstIndex.isValid());
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ QPoint p(itemOffset, 1);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
+ model.insertRows(5, 1, QModelIndex());
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection
+}
+
+void tst_QSortFilterProxyModel::removeAfterSelect()
+{
+ QStandardItemModel model(10, 2);
+ for (int i = 0; i<10;i++)
+ model.setData(model.index(i, 0), QVariant(i));
+ QSortFilterProxyModel filter;
+ filter.setSourceModel(&model);
+ QTreeView view;
+ view.setModel(&filter);
+ view.show();
+ QModelIndex firstIndex = filter.mapFromSource(model.index(0, 0, QModelIndex()));
+ QCOMPARE(firstIndex.model(), (const QAbstractItemModel *)view.model());
+ QVERIFY(firstIndex.isValid());
+ int itemOffset = view.visualRect(firstIndex).width() / 2;
+ QPoint p(itemOffset, 1);
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, p);
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0);
+ model.removeRows(5, 1, QModelIndex());
+ QVERIFY(view.selectionModel()->selectedIndexes().size() > 0); // Should still have a selection
+}
+
+void tst_QSortFilterProxyModel::filterCurrent()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), QString("AAA"));
+ model.setData(model.index(1, 0), QString("BBB"));
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QTreeView view;
+
+ view.show();
+ view.setModel(&proxy);
+ QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)));
+
+ view.setCurrentIndex(proxy.index(0, 0));
+ QCOMPARE(spy.count(), 1);
+ proxy.setFilterRegExp(QRegExp("^B"));
+ QCOMPARE(spy.count(), 2);
+}
+
+void tst_QSortFilterProxyModel::changeSourceLayout()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), QString("b"));
+ model.setData(model.index(1, 0), QString("a"));
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QList<QPersistentModelIndex> persistentSourceIndexes;
+ QList<QPersistentModelIndex> persistentProxyIndexes;
+ for (int row = 0; row < model.rowCount(); ++row) {
+ persistentSourceIndexes.append(model.index(row, 0));
+ persistentProxyIndexes.append(proxy.index(row, 0));
+ }
+
+ // change layout of source model
+ model.sort(0, Qt::AscendingOrder);
+
+ for (int row = 0; row < model.rowCount(); ++row) {
+ QCOMPARE(persistentProxyIndexes.at(row).row(),
+ persistentSourceIndexes.at(row).row());
+ }
+}
+
+void tst_QSortFilterProxyModel::removeSourceRows_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("start");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<IntPairList>("expectedRemovedProxyIntervals");
+ QTest::addColumn<QStringList>("expectedProxyItems");
+
+ QTest::newRow("remove one, no sorting")
+ << (QStringList() << "a" << "b") // sourceItems
+ << 0 // start
+ << 1 // count
+ << -1 // sortOrder (no sorting)
+ << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b") // expectedProxyItems
+ ;
+ QTest::newRow("remove one, ascending sort (same order)")
+ << (QStringList() << "a" << "b") // sourceItems
+ << 0 // start
+ << 1 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b") // expectedProxyItems
+ ;
+ QTest::newRow("remove one, ascending sort (reverse order)")
+ << (QStringList() << "b" << "a") // sourceItems
+ << 0 // start
+ << 1 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(1, 1)) // expectedRemovedIntervals
+ << (QStringList() << "a") // expectedProxyItems
+ ;
+ QTest::newRow("remove two, multiple proxy intervals")
+ << (QStringList() << "c" << "d" << "a" << "b") // sourceItems
+ << 1 // start
+ << 2 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(3, 3) << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b" << "c") // expectedProxyItems
+ ;
+ QTest::newRow("remove three, multiple proxy intervals")
+ << (QStringList() << "b" << "d" << "f" << "a" << "c" << "e") // sourceItems
+ << 3 // start
+ << 3 // count
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (IntPairList() << IntPair(4, 4) << IntPair(2, 2) << IntPair(0, 0)) // expectedRemovedIntervals
+ << (QStringList() << "b" << "d" << "f") // expectedProxyItems
+ ;
+ QTest::newRow("remove all, single proxy intervals")
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
+ << 0 // start
+ << 6 // count
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << (IntPairList() << IntPair(0, 5)) // expectedRemovedIntervals
+ << QStringList() // expectedProxyItems
+ ;
+}
+
+// Check that correct proxy model rows are removed when rows are removed
+// from the source model
+void tst_QSortFilterProxyModel::removeSourceRows()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, start);
+ QFETCH(int, count);
+ QFETCH(int, sortOrder);
+ QFETCH(IntPairList, expectedRemovedProxyIntervals);
+ QFETCH(QStringList, expectedProxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex sindex = model.index(i, 0, QModelIndex());
+ model.setData(sindex, sourceItems.at(i), Qt::DisplayRole);
+ QModelIndex pindex = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(pindex, Qt::DisplayRole), model.data(sindex, Qt::DisplayRole));
+ }
+
+ if (sortOrder != -1)
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+ QSignalSpy aboutToRemoveSpy(&proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)));
+ QSignalSpy aboutToInsertSpy(&proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)));
+
+ model.removeRows(start, count, QModelIndex());
+
+ QCOMPARE(aboutToRemoveSpy.count(), expectedRemovedProxyIntervals.count());
+ for (int i = 0; i < aboutToRemoveSpy.count(); ++i) {
+ QList<QVariant> args = aboutToRemoveSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second);
+ }
+ QCOMPARE(removeSpy.count(), expectedRemovedProxyIntervals.count());
+ for (int i = 0; i < removeSpy.count(); ++i) {
+ QList<QVariant> args = removeSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), expectedRemovedProxyIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), expectedRemovedProxyIntervals.at(i).second);
+ }
+
+ QCOMPARE(insertSpy.count(), 0);
+ QCOMPARE(aboutToInsertSpy.count(), 0);
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), expectedProxyItems.count());
+ for (int i = 0; i < expectedProxyItems.count(); ++i) {
+ QModelIndex pindex = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(pindex, Qt::DisplayRole).toString(), expectedProxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::insertSourceRows_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("start");
+ QTest::addColumn<QStringList>("newItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QStringList>("proxyItems");
+
+ QTest::newRow("insert (1)")
+ << (QStringList() << "c" << "b") // sourceItems
+ << 1 // start
+ << (QStringList() << "a") // newItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << (QStringList() << "a" << "b" << "c") // proxyItems
+ ;
+
+ QTest::newRow("insert (2)")
+ << (QStringList() << "d" << "b" << "c") // sourceItems
+ << 3 // start
+ << (QStringList() << "a") // newItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << (QStringList() << "d" << "c" << "b" << "a") // proxyItems
+ ;
+}
+
+// Check that rows are inserted at correct position in proxy model when
+// rows are inserted into the source model
+void tst_QSortFilterProxyModel::insertSourceRows()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, start);
+ QFETCH(QStringList, newItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QStringList, proxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(true);
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ model.insertRows(start, newItems.size(), QModelIndex());
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count());
+ for (int i = 0; i < newItems.count(); ++i) {
+ QModelIndex index = model.index(start + i, 0, QModelIndex());
+ model.setData(index, newItems.at(i), Qt::DisplayRole);
+ }
+
+ for (int i = 0; i < proxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::changeFilter_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("initialFilter");
+ QTest::addColumn<IntPairList>("initialRemoveIntervals");
+ QTest::addColumn<QStringList>("initialProxyItems");
+ QTest::addColumn<QString>("finalFilter");
+ QTest::addColumn<IntPairList>("finalRemoveIntervals");
+ QTest::addColumn<IntPairList>("insertIntervals");
+ QTest::addColumn<QStringList>("finalProxyItems");
+
+ QTest::newRow("filter (1)")
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|b|c" // initialFilter
+ << (IntPairList() << IntPair(3, 5)) // initialRemoveIntervals
+ << (QStringList() << "a" << "b" << "c") // initialProxyItems
+ << "b|d|f" // finalFilter
+ << (IntPairList() << IntPair(2, 2) << IntPair(0, 0)) // finalRemoveIntervals
+ << (IntPairList() << IntPair(1, 2)) // insertIntervals
+ << (QStringList() << "b" << "d" << "f") // finalProxyItems
+ ;
+
+ QTest::newRow("filter (2)")
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|c|e" // initialFilter
+ << (IntPairList() << IntPair(5, 5) << IntPair(3, 3) << IntPair(1, 1)) // initialRemoveIntervals
+ << (QStringList() << "a" << "c" << "e") // initialProxyItems
+ << "" // finalFilter
+ << IntPairList() // finalRemoveIntervals
+ << (IntPairList() << IntPair(3, 3) << IntPair(2, 2) << IntPair(1, 1)) // insertIntervals
+ << (QStringList() << "a" << "b" << "c" << "d" << "e" << "f") // finalProxyItems
+ ;
+
+ QTest::newRow("filter (3)")
+ << (QStringList() << "a" << "b" << "c") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a" // initialFilter
+ << (IntPairList() << IntPair(1, 2)) // initialRemoveIntervals
+ << (QStringList() << "a") // initialProxyItems
+ << "a" // finalFilter
+ << IntPairList() // finalRemoveIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "a") // finalProxyItems
+ ;
+}
+
+// Check that rows are added/removed when filter changes
+void tst_QSortFilterProxyModel::changeFilter()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, initialFilter);
+ QFETCH(IntPairList, initialRemoveIntervals);
+ QFETCH(QStringList, initialProxyItems);
+ QFETCH(QString, finalFilter);
+ QFETCH(IntPairList, finalRemoveIntervals);
+ QFETCH(IntPairList, insertIntervals);
+ QFETCH(QStringList, finalProxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ QSignalSpy initialRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy initialInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+
+ proxy.setFilterRegExp(initialFilter);
+
+ QCOMPARE(initialRemoveSpy.count(), initialRemoveIntervals.count());
+ QCOMPARE(initialInsertSpy.count(), 0);
+ for (int i = 0; i < initialRemoveSpy.count(); ++i) {
+ QList<QVariant> args = initialRemoveSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), initialRemoveIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), initialRemoveIntervals.at(i).second);
+ }
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), initialProxyItems.count());
+ for (int i = 0; i < initialProxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initialProxyItems.at(i));
+ }
+
+ QSignalSpy finalRemoveSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy finalInsertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+
+ proxy.setFilterRegExp(finalFilter);
+
+ QCOMPARE(finalRemoveSpy.count(), finalRemoveIntervals.count());
+ for (int i = 0; i < finalRemoveSpy.count(); ++i) {
+ QList<QVariant> args = finalRemoveSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), finalRemoveIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), finalRemoveIntervals.at(i).second);
+ }
+
+#ifdef Q_OS_IRIX
+ QEXPECT_FAIL("filter (2)", "Not reliable on IRIX", Abort);
+#endif
+ QCOMPARE(finalInsertSpy.count(), insertIntervals.count());
+ for (int i = 0; i < finalInsertSpy.count(); ++i) {
+ QList<QVariant> args = finalInsertSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second);
+ }
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), finalProxyItems.count());
+ for (int i = 0; i < finalProxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), finalProxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::changeSourceData_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<bool>("dynamic");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<QString>("newValue");
+ QTest::addColumn<IntPairList>("removeIntervals");
+ QTest::addColumn<IntPairList>("insertIntervals");
+ QTest::addColumn<QStringList>("proxyItems");
+
+ QTest::newRow("changeSourceData (1)")
+ << (QStringList() << "c" << "b" << "a") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << true // dynamic
+ << 2 // row
+ << "z" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "b" << "c" << "z") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (2)")
+ << (QStringList() << "b" << "c" << "z") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "" // filter
+ << true // dynamic
+ << 1 // row
+ << "a" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "z" << "b" << "a") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (3)")
+ << (QStringList() << "a" << "b") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "" // filter
+ << true // dynamic
+ << 0 // row
+ << "a" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "b" << "a") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (4)")
+ << (QStringList() << "a" << "b" << "c" << "d") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|c" // filter
+ << true // dynamic
+ << 1 // row
+ << "x" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "a" << "c") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (5)")
+ << (QStringList() << "a" << "b" << "c" << "d") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|c|x" // filter
+ << true // dynamic
+ << 1 // row
+ << "x" // newValue
+ << IntPairList() // removeIntervals
+ << (IntPairList() << IntPair(2, 2)) // insertIntervals
+ << (QStringList() << "a" << "c" << "x") // proxyItems
+ ;
+
+ QTest::newRow("changeSourceData (6)")
+ << (QStringList() << "c" << "b" << "a") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << false // dynamic
+ << 2 // row
+ << "x" // newValue
+ << IntPairList() // removeIntervals
+ << IntPairList() // insertIntervals
+ << (QStringList() << "x" << "b" << "c") // proxyItems
+ ;
+}
+
+void tst_QSortFilterProxyModel::changeSourceData()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, filter);
+ QFETCH(bool, dynamic);
+ QFETCH(int, row);
+ QFETCH(QString, newValue);
+ QFETCH(IntPairList, removeIntervals);
+ QFETCH(IntPairList, insertIntervals);
+ QFETCH(QStringList, proxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setDynamicSortFilter(dynamic);
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ (void)proxy.rowCount(QModelIndex()); // force mapping
+
+ proxy.setFilterRegExp(filter);
+
+ QSignalSpy removeSpy(&proxy, SIGNAL(rowsRemoved(QModelIndex, int, int)));
+ QSignalSpy insertSpy(&proxy, SIGNAL(rowsInserted(QModelIndex, int, int)));
+
+ {
+ QModelIndex index = model.index(row, 0, QModelIndex());
+ model.setData(index, newValue, Qt::DisplayRole);
+ }
+
+ QCOMPARE(removeSpy.count(), removeIntervals.count());
+ for (int i = 0; i < removeSpy.count(); ++i) {
+ QList<QVariant> args = removeSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), removeIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), removeIntervals.at(i).second);
+ }
+
+ QCOMPARE(insertSpy.count(), insertIntervals.count());
+ for (int i = 0; i < insertSpy.count(); ++i) {
+ QList<QVariant> args = insertSpy.at(i);
+ QVERIFY(args.at(1).type() == QVariant::Int);
+ QVERIFY(args.at(2).type() == QVariant::Int);
+ QCOMPARE(args.at(1).toInt(), insertIntervals.at(i).first);
+ QCOMPARE(args.at(2).toInt(), insertIntervals.at(i).second);
+ }
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), proxyItems.count());
+ for (int i = 0; i < proxyItems.count(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), proxyItems.at(i));
+ }
+}
+
+void tst_QSortFilterProxyModel::sortFilterRole()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+
+ QList<QPair<QVariant, QVariant> > sourceItems;
+ sourceItems = QList<QPair<QVariant, QVariant> >()
+ << QPair<QVariant, QVariant>("b", 3)
+ << QPair<QVariant, QVariant>("c", 2)
+ << QPair<QVariant, QVariant>("a", 1);
+
+ QList<int> orderedItems;
+ orderedItems = QList<int>()
+ << 2 << 1;
+
+ model.insertRows(0, sourceItems.count());
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i).first, Qt::DisplayRole);
+ model.setData(index, sourceItems.at(i).second, Qt::UserRole);
+ }
+
+ proxy.setFilterRegExp("2");
+ QCOMPARE(proxy.rowCount(), 0); // Qt::DisplayRole is default role
+
+ proxy.setFilterRole(Qt::UserRole);
+ QCOMPARE(proxy.rowCount(), 1);
+
+ proxy.setFilterRole(Qt::DisplayRole);
+ QCOMPARE(proxy.rowCount(), 0);
+
+ proxy.setFilterRegExp("1|2|3");
+ QCOMPARE(proxy.rowCount(), 0);
+
+ proxy.setFilterRole(Qt::UserRole);
+ QCOMPARE(proxy.rowCount(), 3);
+
+ proxy.sort(0, Qt::AscendingOrder);
+ QCOMPARE(proxy.rowCount(), 3);
+
+ proxy.setSortRole(Qt::UserRole);
+ proxy.setFilterRole(Qt::DisplayRole);
+ proxy.setFilterRegExp("a|c");
+ QCOMPARE(proxy.rowCount(), orderedItems.count());
+ for (int i = 0; i < proxy.rowCount(); ++i) {
+ QModelIndex index = proxy.index(i, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole), sourceItems.at(orderedItems.at(i)).first);
+ }
+}
+
+void tst_QSortFilterProxyModel::selectionFilteredOut()
+{
+ QStandardItemModel model(2, 1);
+ model.setData(model.index(0, 0), QString("AAA"));
+ model.setData(model.index(1, 0), QString("BBB"));
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QTreeView view;
+
+ view.show();
+ view.setModel(&proxy);
+ QSignalSpy spy(view.selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)));
+
+ view.setCurrentIndex(proxy.index(0, 0));
+ QCOMPARE(spy.count(), 1);
+ proxy.setFilterRegExp(QRegExp("^B"));
+ QCOMPARE(spy.count(), 2);
+}
+
+void tst_QSortFilterProxyModel::match_data()
+{
+ QTest::addColumn<QStringList>("sourceItems");
+ QTest::addColumn<int>("sortOrder");
+ QTest::addColumn<QString>("filter");
+ QTest::addColumn<int>("proxyStartRow");
+ QTest::addColumn<QString>("what");
+ QTest::addColumn<int>("matchFlags");
+ QTest::addColumn<IntList>("expectedProxyItems");
+ QTest::newRow("1")
+ << (QStringList() << "a") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << 0 // proxyStartRow
+ << "a" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 0); // expectedProxyItems
+ QTest::newRow("2")
+ << (QStringList() << "a" << "b") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << 0 // proxyStartRow
+ << "b" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 1); // expectedProxyItems
+ QTest::newRow("3")
+ << (QStringList() << "a" << "b") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "" // filter
+ << 0 // proxyStartRow
+ << "a" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 1); // expectedProxyItems
+ QTest::newRow("4")
+ << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "" // filter
+ << 1 // proxyStartRow
+ << "a" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << IntList(); // expectedProxyItems
+ QTest::newRow("5")
+ << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
+ << static_cast<int>(Qt::AscendingOrder) // sortOrder
+ << "a|b" // filter
+ << 0 // proxyStartRow
+ << "c" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << IntList(); // expectedProxyItems
+ QTest::newRow("6")
+ << (QStringList() << "b" << "d" << "a" << "c") // sourceItems
+ << static_cast<int>(Qt::DescendingOrder) // sortOrder
+ << "a|b" // filter
+ << 0 // proxyStartRow
+ << "b" // what
+ << static_cast<int>(Qt::MatchExactly) // matchFlags
+ << (IntList() << 0); // expectedProxyItems
+}
+
+void tst_QSortFilterProxyModel::match()
+{
+ QFETCH(QStringList, sourceItems);
+ QFETCH(int, sortOrder);
+ QFETCH(QString, filter);
+ QFETCH(int, proxyStartRow);
+ QFETCH(QString, what);
+ QFETCH(int, matchFlags);
+ QFETCH(IntList, expectedProxyItems);
+
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+
+ proxy.setSourceModel(&model);
+ model.insertColumns(0, 1);
+ model.insertRows(0, sourceItems.count());
+
+ for (int i = 0; i < sourceItems.count(); ++i) {
+ QModelIndex index = model.index(i, 0, QModelIndex());
+ model.setData(index, sourceItems.at(i), Qt::DisplayRole);
+ }
+
+ proxy.sort(0, static_cast<Qt::SortOrder>(sortOrder));
+ proxy.setFilterRegExp(filter);
+
+ QModelIndex startIndex = proxy.index(proxyStartRow, 0);
+ QModelIndexList indexes = proxy.match(startIndex, Qt::DisplayRole, what,
+ expectedProxyItems.count(),
+ Qt::MatchFlags(matchFlags));
+ QCOMPARE(indexes.count(), expectedProxyItems.count());
+ for (int i = 0; i < indexes.count(); ++i)
+ QCOMPARE(indexes.at(i).row(), expectedProxyItems.at(i));
+}
+
+void tst_QSortFilterProxyModel::insertIntoChildrenlessItem()
+{
+ QStandardItemModel model;
+ QStandardItem *itemA = new QStandardItem("a");
+ model.appendRow(itemA);
+ QStandardItem *itemB = new QStandardItem("b");
+ model.appendRow(itemB);
+ QStandardItem *itemC = new QStandardItem("c");
+ model.appendRow(itemC);
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QSignalSpy colsInsertedSpy(&proxy, SIGNAL(columnsInserted(const QModelIndex&, int, int)));
+ QSignalSpy rowsInsertedSpy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
+
+ (void)proxy.rowCount(QModelIndex()); // force mapping of "a", "b", "c"
+ QCOMPARE(colsInsertedSpy.count(), 0);
+ QCOMPARE(rowsInsertedSpy.count(), 0);
+
+ // now add a child to itemB ==> should get insert notification from the proxy
+ itemB->appendRow(new QStandardItem("a.0"));
+ QCOMPARE(colsInsertedSpy.count(), 1);
+ QCOMPARE(rowsInsertedSpy.count(), 1);
+
+ QVariantList args = colsInsertedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index()));
+ QCOMPARE(qvariant_cast<int>(args.at(1)), 0);
+ QCOMPARE(qvariant_cast<int>(args.at(2)), 0);
+
+ args = rowsInsertedSpy.takeFirst();
+ QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), proxy.mapFromSource(itemB->index()));
+ QCOMPARE(qvariant_cast<int>(args.at(1)), 0);
+ QCOMPARE(qvariant_cast<int>(args.at(2)), 0);
+}
+
+void tst_QSortFilterProxyModel::invalidateMappedChildren()
+{
+ QStandardItemModel model;
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QStandardItem *itemA = new QStandardItem("a");
+ model.appendRow(itemA);
+ QStandardItem *itemB = new QStandardItem("b");
+ itemA->appendRow(itemB);
+
+ QStandardItem *itemC = new QStandardItem("c");
+ itemB->appendRow(itemC);
+ itemC->appendRow(new QStandardItem("d"));
+
+ // force mappings
+ (void)proxy.hasChildren(QModelIndex());
+ (void)proxy.hasChildren(proxy.mapFromSource(itemA->index()));
+ (void)proxy.hasChildren(proxy.mapFromSource(itemB->index()));
+ (void)proxy.hasChildren(proxy.mapFromSource(itemC->index()));
+
+ itemB->removeRow(0); // should invalidate mapping of itemC
+ itemC = new QStandardItem("c");
+ itemA->appendRow(itemC);
+ itemC->appendRow(new QStandardItem("d"));
+
+ itemA->removeRow(1); // should invalidate mapping of itemC
+ itemC = new QStandardItem("c");
+ itemB->appendRow(itemC);
+ itemC->appendRow(new QStandardItem("d"));
+
+ QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemA->index())), 1);
+ QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemB->index())), 1);
+ QCOMPARE(proxy.rowCount(proxy.mapFromSource(itemC->index())), 1);
+}
+
+class EvenOddFilterModel : public QSortFilterProxyModel
+{
+public:
+ virtual bool filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const
+ {
+ if (srcParent.isValid())
+ return (srcParent.row() % 2) ^ !(srcRow % 2);
+ return (srcRow % 2);
+ }
+};
+
+void tst_QSortFilterProxyModel::insertRowIntoFilteredParent()
+{
+ QStandardItemModel model;
+ EvenOddFilterModel proxy;
+ proxy.setSourceModel(&model);
+
+ QSignalSpy spy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
+
+ QStandardItem *itemA = new QStandardItem();
+ model.appendRow(itemA); // A will be filtered
+ QStandardItem *itemB = new QStandardItem();
+ itemA->appendRow(itemB);
+
+ QCOMPARE(spy.count(), 0);
+
+ itemA->removeRow(0);
+
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_QSortFilterProxyModel::filterOutParentAndFilterInChild()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ proxy.setFilterRegExp("A|B");
+ QStandardItem *itemA = new QStandardItem("A");
+ model.appendRow(itemA); // not filtered
+ QStandardItem *itemB = new QStandardItem("B");
+ itemA->appendRow(itemB); // not filtered
+ QStandardItem *itemC = new QStandardItem("C");
+ itemA->appendRow(itemC); // filtered
+
+ QSignalSpy removedSpy(&proxy, SIGNAL(rowsRemoved(const QModelIndex&, int, int)));
+ QSignalSpy insertedSpy(&proxy, SIGNAL(rowsInserted(const QModelIndex&, int, int)));
+
+ proxy.setFilterRegExp("C"); // A and B will be filtered out, C filtered in
+
+ // we should now have been notified that the subtree represented by itemA has been removed
+ QCOMPARE(removedSpy.count(), 1);
+ // we should NOT get any inserts; itemC should be filtered because its parent (itemA) is
+ QCOMPARE(insertedSpy.count(), 0);
+}
+
+void tst_QSortFilterProxyModel::sourceInsertRows()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ model.insertColumns(0, 1, QModelIndex());
+ model.insertRows(0, 2, QModelIndex());
+
+ {
+ QModelIndex parent = model.index(0, 0, QModelIndex());
+ model.insertColumns(0, 1, parent);
+ model.insertRows(0, 1, parent);
+ }
+
+ {
+ QModelIndex parent = model.index(1, 0, QModelIndex());
+ model.insertColumns(0, 1, parent);
+ model.insertRows(0, 1, parent);
+ }
+
+ model.insertRows(0, 1, QModelIndex());
+ model.insertRows(0, 1, QModelIndex());
+
+ QVERIFY(true); // if you got here without asserting, it's all good
+}
+
+void tst_QSortFilterProxyModel::sourceModelDeletion()
+{
+
+ QSortFilterProxyModel proxyModel;
+ {
+ QStandardItemModel model;
+ proxyModel.setSourceModel(&model);
+ QCOMPARE(proxyModel.sourceModel(), static_cast<QAbstractItemModel*>(&model));
+ }
+ QCOMPARE(proxyModel.sourceModel(), static_cast<QAbstractItemModel*>(0));
+
+}
+
+void tst_QSortFilterProxyModel::sortColumnTracking1()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ model.insertColumns(0, 10);
+ model.insertRows(0, 10);
+
+ proxyModel.sort(1);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.insertColumn(8);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.removeColumn(8);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.insertColumn(2);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.removeColumn(2);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.insertColumn(1);
+ QCOMPARE(proxyModel.sortColumn(), 2);
+
+ model.removeColumn(1);
+ QCOMPARE(proxyModel.sortColumn(), 1);
+
+ model.removeColumn(1);
+ QCOMPARE(proxyModel.sortColumn(), -1);
+}
+
+void tst_QSortFilterProxyModel::sortColumnTracking2()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setDynamicSortFilter(true);
+ proxyModel.setSourceModel(&model);
+
+ proxyModel.sort(0);
+ QCOMPARE(proxyModel.sortColumn(), 0);
+
+ QList<QStandardItem *> items;
+ QStringList strings;
+ strings << "foo" << "bar" << "some" << "others" << "item" << "aa" << "zz";
+ foreach (QString s, strings)
+ items << new QStandardItem(s);
+
+ model.insertColumn(0,items);
+ QCOMPARE(proxyModel.sortColumn(), 0);
+ QCOMPARE(proxyModel.data(proxyModel.index(0,0)).toString(),QString::fromLatin1("aa"));
+ QCOMPARE(proxyModel.data(proxyModel.index(strings.count()-1,0)).toString(),QString::fromLatin1("zz"));
+}
+
+void tst_QSortFilterProxyModel::sortStable()
+{
+ QStandardItemModel* model = new QStandardItemModel(5, 2);
+ for (int r=0; r<5; r++) {
+ for (int c=0; c<2; c++) {
+ QStandardItem* item = new QStandardItem(
+ QString("Row:%0, Column:%1").arg(r).arg(c) );
+ for( int i=0; i<3; i++ ) {
+ QStandardItem* child = new QStandardItem(
+ QString("Item %0").arg(i) );
+ item->appendRow( child );
+ }
+ model->setItem(r, c, item);
+ }
+ }
+ model->setHorizontalHeaderItem( 0, new QStandardItem( "Name" ));
+ model->setHorizontalHeaderItem( 1, new QStandardItem( "Value" ) );
+
+
+ QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(model);
+ filterModel->setSourceModel(model);
+
+ QTreeView *view = new QTreeView;
+ view->setModel(filterModel);
+ QModelIndex firstRoot = filterModel->index(0,0);
+ view->expand(firstRoot);
+ view->setSortingEnabled(true);
+
+ view->model()->sort(1, Qt::DescendingOrder);
+ QVariant lastItemData =filterModel->index(2,0, firstRoot).data();
+ view->model()->sort(1, Qt::DescendingOrder);
+ QCOMPARE(lastItemData, filterModel->index(2,0, firstRoot).data());
+}
+
+void tst_QSortFilterProxyModel::task236755_hiddenColumns()
+{
+ class MyStandardItemModel : public QStandardItemModel
+ {
+ public:
+ MyStandardItemModel() : QStandardItemModel(0,5) {}
+ void reset()
+ { QStandardItemModel::reset(); }
+ friend class tst_QSortFilterProxyModel;
+ } model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+
+ QTableView view;
+ view.setModel(&proxy);
+
+ view.hideColumn(0);
+
+ QVERIFY(view.isColumnHidden(0));
+ model.blockSignals(true);
+ model.setRowCount(1);
+ model.blockSignals(false);
+ model.reset();
+
+ //in the initial task this would be false because resetting
+ //model would also reset the hidden columns
+ QVERIFY(view.isColumnHidden(0));
+}
+
+void tst_QSortFilterProxyModel::task247867_insertRowsSort()
+{
+ QStandardItemModel model(2,2);
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(&model);
+
+ proxyModel.sort(0);
+ QCOMPARE(proxyModel.sortColumn(), 0);
+
+ model.insertColumns(0, 3, model.index(0,0));
+ QCOMPARE(proxyModel.sortColumn(), 0);
+
+ model.removeColumns(0, 3, model.index(0,0));
+ QCOMPARE(proxyModel.sortColumn(), 0);
+}
+
+void tst_QSortFilterProxyModel::task248868_staticSorting()
+{
+ QStandardItemModel model(0, 1);
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ proxy.setDynamicSortFilter(false);
+ QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" ");
+
+ // prepare model
+ QStandardItem *root = model.invisibleRootItem ();
+ QList<QStandardItem *> items;
+ for (int i = 0; i < initial.count(); ++i) {
+ items.append(new QStandardItem(initial.at(i)));
+ }
+ root->insertRows(0, items);
+ QCOMPARE(model.rowCount(QModelIndex()), initial.count());
+ QCOMPARE(model.columnCount(QModelIndex()), 1);
+
+ // make sure the proxy is unsorted
+ QCOMPARE(proxy.columnCount(QModelIndex()), 1);
+ QCOMPARE(proxy.rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ // sort
+ proxy.sort(0);
+
+ QStringList expected = initial;
+ expected.sort();
+ // make sure the proxy is sorted
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ //update one item.
+ model.setItem(0, 0, new QStandardItem("girafe"));
+
+ // make sure the proxy is updated but not sorted
+ expected.replaceInStrings("bateau", "girafe");
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ // sort again
+ proxy.sort(0);
+ expected.sort();
+
+ // make sure the proxy is sorted
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+}
+
+void tst_QSortFilterProxyModel::task248868_dynamicSorting()
+{
+ QStringListModel model1;
+ const QStringList initial = QString("bateau avion dragon hirondelle flamme camion elephant").split(" ");
+ model1.setStringList(initial);
+ QSortFilterProxyModel proxy1;
+ proxy1.sort(0);
+ proxy1.setSourceModel(&model1);
+
+ QCOMPARE(proxy1.columnCount(QModelIndex()), 1);
+ //the model should not be sorted because sorting has not been set to dynamic yet.
+ QCOMPARE(proxy1.rowCount(QModelIndex()), initial.count());
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), initial.at(row));
+ }
+
+ proxy1.setDynamicSortFilter(true);
+
+ //now the model should be sorted.
+ QStringList expected = initial;
+ expected.sort();
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ QStringList initial2 = initial;
+ initial2.replaceInStrings("bateau", "girafe");
+ model1.setStringList(initial2); //this will cause a reset
+
+ QStringList expected2 = initial2;
+ expected2.sort();
+
+ //now the model should still be sorted.
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected2.at(row));
+ }
+
+ QStringListModel model2(initial);
+ proxy1.setSourceModel(&model2);
+
+ //the model should again be sorted
+ for (int row = 0; row < proxy1.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy1.index(row, 0, QModelIndex());
+ QCOMPARE(proxy1.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+
+ //set up the sorting before seting the model up
+ QSortFilterProxyModel proxy2;
+ proxy2.setDynamicSortFilter(true);
+ proxy2.sort(0);
+ proxy2.setSourceModel(&model2);
+ for (int row = 0; row < proxy2.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy2.index(row, 0, QModelIndex());
+ QCOMPARE(proxy2.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+class QtTestModel: public QAbstractItemModel
+{
+ public:
+ QtTestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
+ rows(_rows), cols(_cols), wrongIndex(false) { }
+
+ bool canFetchMore(const QModelIndex &idx) const {
+ return !fetched.contains(idx);
+ }
+
+ void fetchMore(const QModelIndex &idx) {
+ if (fetched.contains(idx))
+ return;
+ beginInsertRows(idx, 0, rows-1);
+ fetched.insert(idx);
+ endInsertRows();
+ }
+
+ bool hasChildren(const QModelIndex & = QModelIndex()) const {
+ return true;
+ }
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const {
+ return fetched.contains(parent) ? rows : 0;
+ }
+ int columnCount(const QModelIndex& parent = QModelIndex()) const {
+ Q_UNUSED(parent);
+ return cols;
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
+ {
+ if (row < 0 || column < 0 || column >= cols || row >= rows) {
+ return QModelIndex();
+ }
+ QModelIndex i = createIndex(row, column, int(parent.internalId() + 1));
+ parentHash[i] = parent;
+ return i;
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ if (!parentHash.contains(index))
+ return QModelIndex();
+ return parentHash[index];
+ }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (!idx.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) {
+ wrongIndex = true;
+ qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
+ idx.internalPointer());
+ }
+ return QString("[%1,%2]").arg(idx.row()).arg(idx.column());
+ }
+ return QVariant();
+ }
+
+ QSet<QModelIndex> fetched;
+ int rows, cols;
+ mutable bool wrongIndex;
+ mutable QMap<QModelIndex,QModelIndex> parentHash;
+};
+
+void tst_QSortFilterProxyModel::task250023_fetchMore()
+{
+ QtTestModel model(10,10);
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ QVERIFY(proxy.canFetchMore(QModelIndex()));
+ QVERIFY(proxy.hasChildren());
+ while (proxy.canFetchMore(QModelIndex()))
+ proxy.fetchMore(QModelIndex());
+ QCOMPARE(proxy.rowCount(), 10);
+ QCOMPARE(proxy.columnCount(), 10);
+
+ QModelIndex idx = proxy.index(1,1);
+ QVERIFY(idx.isValid());
+ QVERIFY(proxy.canFetchMore(idx));
+ QVERIFY(proxy.hasChildren(idx));
+ while (proxy.canFetchMore(idx))
+ proxy.fetchMore(idx);
+ QCOMPARE(proxy.rowCount(idx), 10);
+ QCOMPARE(proxy.columnCount(idx), 10);
+}
+
+void tst_QSortFilterProxyModel::task251296_hiddenChildren()
+{
+ QStandardItemModel model;
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&model);
+ proxy.setDynamicSortFilter(true);
+
+ QStandardItem *itemA = new QStandardItem("A VISIBLE");
+ model.appendRow(itemA);
+ QStandardItem *itemB = new QStandardItem("B VISIBLE");
+ itemA->appendRow(itemB);
+ QStandardItem *itemC = new QStandardItem("C");
+ itemA->appendRow(itemC);
+ proxy.setFilterRegExp("VISIBLE");
+
+ QCOMPARE(proxy.rowCount(QModelIndex()) , 1);
+ QPersistentModelIndex indexA = proxy.index(0,0);
+ QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("A VISIBLE"));
+
+ QCOMPARE(proxy.rowCount(indexA) , 1);
+ QPersistentModelIndex indexB = proxy.index(0, 0, indexA);
+ QCOMPARE(proxy.data(indexB).toString(), QString::fromLatin1("B VISIBLE"));
+
+ itemA->setText("A");
+ QCOMPARE(proxy.rowCount(QModelIndex()), 0);
+ QVERIFY(!indexA.isValid());
+ QVERIFY(!indexB.isValid());
+
+ itemB->setText("B");
+ itemA->setText("A VISIBLE");
+ itemC->setText("C VISIBLE");
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), 1);
+ indexA = proxy.index(0,0);
+ QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("A VISIBLE"));
+
+ QCOMPARE(proxy.rowCount(indexA) , 1);
+ QModelIndex indexC = proxy.index(0, 0, indexA);
+ QCOMPARE(proxy.data(indexC).toString(), QString::fromLatin1("C VISIBLE"));
+
+ proxy.setFilterRegExp("C");
+ QCOMPARE(proxy.rowCount(QModelIndex()), 0);
+ itemC->setText("invisible");
+ itemA->setText("AC");
+
+ QCOMPARE(proxy.rowCount(QModelIndex()), 1);
+ indexA = proxy.index(0,0);
+ QCOMPARE(proxy.data(indexA).toString(), QString::fromLatin1("AC"));
+ QCOMPARE(proxy.rowCount(indexA) , 0);
+}
+
+void tst_QSortFilterProxyModel::task252507_mapFromToSource()
+{
+ QtTestModel source(10,10);
+ source.fetchMore(QModelIndex());
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&source);
+ QCOMPARE(proxy.mapFromSource(source.index(5, 4)), proxy.index(5, 4));
+ QCOMPARE(proxy.mapToSource(proxy.index(3, 2)), source.index(3, 2));
+ QCOMPARE(proxy.mapFromSource(QModelIndex()), QModelIndex());
+ QCOMPARE(proxy.mapToSource(QModelIndex()), QModelIndex());
+
+#ifdef QT_NO_DEBUG //if Qt is compiled in debug mode, this will assert
+ QTest::ignoreMessage(QtWarningMsg, "QSortFilterProxyModel: index from wrong model passed to mapToSource ");
+ QCOMPARE(proxy.mapToSource(source.index(2, 3)), QModelIndex());
+ QTest::ignoreMessage(QtWarningMsg, "QSortFilterProxyModel: index from wrong model passed to mapFromSource ");
+ QCOMPARE(proxy.mapFromSource(proxy.index(6, 2)), QModelIndex());
+#endif
+}
+
+static QStandardItem *addEntry(QStandardItem* pParent, const QString &description)
+{
+ QStandardItem* pItem = new QStandardItem(description);
+ pParent->appendRow(pItem);
+ return pItem;
+}
+
+
+void tst_QSortFilterProxyModel::task255652_removeRowsRecursive()
+{
+ QStandardItemModel pModel;
+ QStandardItem *pItem1 = new QStandardItem("root");
+ pModel.appendRow(pItem1);
+ QList<QStandardItem *> items;
+
+ QStandardItem *pItem11 = addEntry(pItem1,"Sub-heading");
+ items << pItem11;
+ QStandardItem *pItem111 = addEntry(pItem11,"A");
+ items << pItem111;
+ items << addEntry(pItem111,"A1");
+ items << addEntry(pItem111,"A2");
+ QStandardItem *pItem112 = addEntry(pItem11,"B");
+ items << pItem112;
+ items << addEntry(pItem112,"B1");
+ items << addEntry(pItem112,"B2");
+ QStandardItem *pItem1123 = addEntry(pItem112,"B3");
+ items << pItem1123;
+ items << addEntry(pItem1123,"B3-");
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel(&pModel);
+
+ QList<QPersistentModelIndex> sourceIndexes;
+ QList<QPersistentModelIndex> proxyIndexes;
+ foreach (QStandardItem *item, items) {
+ QModelIndex idx = item->index();
+ sourceIndexes << idx;
+ proxyIndexes << proxy.mapFromSource(idx);
+ }
+
+ foreach (const QPersistentModelIndex &pidx, sourceIndexes)
+ QVERIFY(pidx.isValid());
+ foreach (const QPersistentModelIndex &pidx, proxyIndexes)
+ QVERIFY(pidx.isValid());
+
+ QList<QStandardItem*> itemRow = pItem1->takeRow(0);
+
+ QCOMPARE(itemRow.count(), 1);
+ QCOMPARE(itemRow.first(), pItem11);
+
+ foreach (const QPersistentModelIndex &pidx, sourceIndexes)
+ QVERIFY(!pidx.isValid());
+ foreach (const QPersistentModelIndex &pidx, proxyIndexes)
+ QVERIFY(!pidx.isValid());
+
+ delete pItem11;
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_6205_doubleProxySelectionSetSourceModel()
+{
+ QStandardItemModel *model1 = new QStandardItemModel;
+ QStandardItem *parentItem = model1->invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("model1 item %0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+
+ QStandardItemModel *model2 = new QStandardItemModel;
+ QStandardItem *parentItem2 = model2->invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("model2 item %0").arg(i));
+ parentItem2->appendRow(item);
+ parentItem2 = item;
+ }
+
+ QSortFilterProxyModel *toggleProxy = new QSortFilterProxyModel;
+ toggleProxy->setSourceModel(model1);
+
+ QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel;
+ proxyModel->setSourceModel(toggleProxy);
+
+ QModelIndex mi = proxyModel->index(0, 0, proxyModel->index(0, 0, proxyModel->index(0, 0)));
+ QItemSelectionModel ism(proxyModel);
+ ism.select(mi, QItemSelectionModel::Select);
+ QModelIndexList mil = ism.selectedIndexes();
+ QCOMPARE(mil.count(), 1);
+ QCOMPARE(mil.first(), mi);
+
+ toggleProxy->setSourceModel(model2);
+ // No crash, it's good news!
+ QVERIFY(ism.selection().isEmpty());
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_7537_appearsAndSort()
+{
+ class PModel : public QSortFilterProxyModel
+ {
+ public:
+ PModel() : mVisible(false) {};
+ protected:
+ bool filterAcceptsRow(int, const QModelIndex &) const
+ {
+ return mVisible;
+ }
+
+ public:
+ void updateXX()
+ {
+ mVisible = true;
+ invalidate();
+ }
+ private:
+ bool mVisible;
+ } proxyModel;
+
+
+ QStringListModel sourceModel;
+ QStringList list;
+ list << "b" << "a" << "c";
+ sourceModel.setStringList(list);
+
+ proxyModel.setSourceModel(&sourceModel);
+ proxyModel.setDynamicSortFilter(true);
+ proxyModel.sort(0, Qt::AscendingOrder);
+
+ QApplication::processEvents();
+ QCOMPARE(sourceModel.rowCount(), 3);
+ QCOMPARE(proxyModel.rowCount(), 0); //all rows are hidden at first;
+
+ QSignalSpy spyAbout1(&proxyModel, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy spyChanged1(&proxyModel, SIGNAL(layoutChanged()));
+
+ //introducing secondProxyModel to test the layoutChange when many items appears at once
+ QSortFilterProxyModel secondProxyModel;
+ secondProxyModel.setSourceModel(&proxyModel);
+ secondProxyModel.setDynamicSortFilter(true);
+ secondProxyModel.sort(0, Qt::DescendingOrder);
+ QCOMPARE(secondProxyModel.rowCount(), 0); //all rows are hidden at first;
+ QSignalSpy spyAbout2(&secondProxyModel, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy spyChanged2(&secondProxyModel, SIGNAL(layoutChanged()));
+
+ proxyModel.updateXX();
+ QApplication::processEvents();
+ //now rows should be visible, and sorted
+ QCOMPARE(proxyModel.rowCount(), 3);
+ QCOMPARE(proxyModel.data(proxyModel.index(0,0), Qt::DisplayRole).toString(), QString::fromLatin1("a"));
+ QCOMPARE(proxyModel.data(proxyModel.index(1,0), Qt::DisplayRole).toString(), QString::fromLatin1("b"));
+ QCOMPARE(proxyModel.data(proxyModel.index(2,0), Qt::DisplayRole).toString(), QString::fromLatin1("c"));
+
+ //now rows should be visible, and sorted
+ QCOMPARE(secondProxyModel.rowCount(), 3);
+ QCOMPARE(secondProxyModel.data(secondProxyModel.index(0,0), Qt::DisplayRole).toString(), QString::fromLatin1("c"));
+ QCOMPARE(secondProxyModel.data(secondProxyModel.index(1,0), Qt::DisplayRole).toString(), QString::fromLatin1("b"));
+ QCOMPARE(secondProxyModel.data(secondProxyModel.index(2,0), Qt::DisplayRole).toString(), QString::fromLatin1("a"));
+
+ QCOMPARE(spyAbout1.count(), 1);
+ QCOMPARE(spyChanged1.count(), 1);
+ QCOMPARE(spyAbout2.count(), 1);
+ QCOMPARE(spyChanged2.count(), 1);
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_7716_unnecessaryDynamicSorting()
+{
+ QStringListModel model;
+ const QStringList initial = QString("bravo charlie delta echo").split(" ");
+ model.setStringList(initial);
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(false);
+ proxy.setSourceModel(&model);
+ proxy.sort(Qt::AscendingOrder);
+
+ //append two rows
+ int maxrows = proxy.rowCount(QModelIndex());
+ model.insertRows(maxrows, 2);
+ model.setData(model.index(maxrows, 0), QString("alpha"));
+ model.setData(model.index(maxrows + 1, 0), QString("fondue"));
+
+ //append new items to the initial string list and compare with model
+ QStringList expected = initial;
+ expected << QString("alpha") << QString("fondue");
+
+ //if bug 7716 is present, new rows were prepended, when they should have been appended
+ for (int row = 0; row < proxy.rowCount(QModelIndex()); ++row) {
+ QModelIndex index = proxy.index(row, 0, QModelIndex());
+ QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expected.at(row));
+ }
+}
+
+class SelectionProxyModel : QAbstractProxyModel
+{
+ Q_OBJECT
+public:
+ SelectionProxyModel()
+ : QAbstractProxyModel(), selectionModel(0)
+ {
+ }
+
+ QModelIndex mapFromSource(QModelIndex const&) const
+ { return QModelIndex(); }
+
+ QModelIndex mapToSource(QModelIndex const&) const
+ { return QModelIndex(); }
+
+ QModelIndex index(int, int, const QModelIndex&) const
+ { return QModelIndex(); }
+
+ QModelIndex parent(const QModelIndex&) const
+ { return QModelIndex(); }
+
+ int rowCount(const QModelIndex&) const
+ { return 0; }
+
+ int columnCount(const QModelIndex&) const
+ { return 0; }
+
+ void setSourceModel( QAbstractItemModel *sourceModel )
+ {
+ beginResetModel();
+ disconnect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()) );
+ QAbstractProxyModel::setSourceModel( sourceModel );
+ connect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset()) );
+ endResetModel();
+ }
+
+ void setSelectionModel( QItemSelectionModel *_selectionModel )
+ {
+ selectionModel = _selectionModel;
+ }
+
+private slots:
+ void sourceModelAboutToBeReset()
+ {
+ QVERIFY( selectionModel->selectedIndexes().size() == 1 );
+ beginResetModel();
+ }
+
+ void sourceModelReset()
+ {
+ endResetModel();
+ }
+
+private:
+ QItemSelectionModel *selectionModel;
+
+};
+
+void tst_QSortFilterProxyModel::testMultipleProxiesWithSelection()
+{
+ QStringListModel model;
+ const QStringList initial = QString("bravo charlie delta echo").split(" ");
+ model.setStringList(initial);
+
+ QSortFilterProxyModel proxy;
+ proxy.setSourceModel( &model );
+
+ SelectionProxyModel proxy1;
+ QSortFilterProxyModel proxy2;
+
+ // Note that the order here matters. The order of the sourceAboutToBeReset
+ // exposes the bug in QSortFilterProxyModel.
+ proxy2.setSourceModel( &proxy );
+ proxy1.setSourceModel( &proxy );
+
+ QItemSelectionModel selectionModel(&proxy2);
+ proxy1.setSelectionModel( &selectionModel );
+
+ selectionModel.select( proxy2.index( 0, 0 ), QItemSelectionModel::Select );
+
+ // trick the proxy into emitting begin/end reset signals.
+ proxy.setSourceModel(0);
+
+}
+
+static bool isValid(const QItemSelection &selection) {
+ foreach(const QItemSelectionRange &range, selection)
+ if (!range.isValid())
+ return false;
+ return true;
+}
+
+void tst_QSortFilterProxyModel::mapSelectionFromSource()
+{
+ QStringListModel model;
+ const QStringList initial = QString("bravo charlie delta echo").split(" ");
+ model.setStringList(initial);
+
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(true);
+ proxy.setFilterRegExp("d.*");
+ proxy.setSourceModel(&model);
+
+ // Only "delta" remains.
+ QVERIFY(proxy.rowCount() == 1);
+
+ QItemSelection selection;
+ QModelIndex charlie = model.index(1, 0);
+ selection.append(QItemSelectionRange(charlie, charlie));
+ QModelIndex delta = model.index(2, 0);
+ selection.append(QItemSelectionRange(delta, delta));
+ QModelIndex echo = model.index(3, 0);
+ selection.append(QItemSelectionRange(echo, echo));
+
+ QVERIFY(isValid(selection));
+
+ QItemSelection proxiedSelection = proxy.mapSelectionFromSource(selection);
+
+ // Only "delta" is in the mapped result.
+ QVERIFY(proxiedSelection.size() == 1);
+ QVERIFY(isValid(proxiedSelection));
+}
+
+class Model10287 : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ Model10287(QObject *parent = 0)
+ : QStandardItemModel(0, 1, parent)
+ {
+ parentItem = new QStandardItem("parent");
+ parentItem->setData(false, Qt::UserRole);
+ appendRow(parentItem);
+
+ childItem = new QStandardItem("child");
+ childItem->setData(true, Qt::UserRole);
+ parentItem->appendRow(childItem);
+
+ childItem2 = new QStandardItem("child2");
+ childItem2->setData(true, Qt::UserRole);
+ parentItem->appendRow(childItem2);
+ }
+
+ void removeChild()
+ {
+ childItem2->setData(false, Qt::UserRole);
+ parentItem->removeRow(0);
+ }
+
+private:
+ QStandardItem *parentItem, *childItem, *childItem2;
+};
+
+class Proxy10287 : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ Proxy10287(QAbstractItemModel *model, QObject *parent = 0)
+ : QSortFilterProxyModel(parent)
+ {
+ setSourceModel(model);
+ setDynamicSortFilter(true);
+ }
+
+protected:
+ virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+ {
+ // Filter based on UserRole in model
+ QModelIndex i = sourceModel()->index(source_row, 0, source_parent);
+ return i.data(Qt::UserRole).toBool();
+ }
+};
+
+void tst_QSortFilterProxyModel::taskQTBUG_10287_unnecessaryMapCreation()
+{
+ Model10287 m;
+ Proxy10287 p(&m);
+ m.removeChild();
+ // No assert failure, it passes.
+}
+
+class FilteredColumnProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ FilteredColumnProxyModel(QObject *parent = 0)
+ : QSortFilterProxyModel(parent)
+ {
+
+ }
+
+protected:
+ bool filterAcceptsColumn(int column, const QModelIndex & /* source_parent */) const
+ {
+ return column % 2 != 0;
+ }
+};
+
+void tst_QSortFilterProxyModel::filteredColumns()
+{
+ DynamicTreeModel *model = new DynamicTreeModel(this);
+
+ FilteredColumnProxyModel *proxy = new FilteredColumnProxyModel(this);
+ proxy->setSourceModel(model);
+
+ new ModelTest(proxy, this);
+
+ ModelInsertCommand *insertCommand = new ModelInsertCommand(model, this);
+ insertCommand->setNumCols(2);
+ insertCommand->setStartRow(0);
+ insertCommand->setEndRow(0);
+ // Parent is QModelIndex()
+ insertCommand->doCommand();
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate_data()
+{
+ QTest::addColumn<int>("test");
+ QTest::addColumn<bool>("works");
+
+ QTest::newRow("nothing") << 0 << false;
+ QTest::newRow("reset") << 1 << true;
+ QTest::newRow("invalidate") << 2 << true;
+ QTest::newRow("invalidate_filter") << 3 << true;
+}
+
+void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate()
+{
+ QFETCH(int, test);
+ QFETCH(bool, works);
+
+ struct Proxy : QSortFilterProxyModel {
+ QString pattern;
+ virtual bool filterAcceptsRow(int source_row, const QModelIndex&) const {
+ return sourceModel()->data(sourceModel()->index(source_row, 0)).toString().contains(pattern);
+ }
+ void notifyChange(int test) {
+ switch (test) {
+ case 0: break;
+ case 1: reset(); break;
+ case 2: invalidate(); break;
+ case 3: invalidateFilter(); break;
+ }
+ }
+ };
+
+ QStringListModel sourceModel(QStringList() << "Poisson" << "Vache" << "Brebis"
+ << "Elephant" << "Cochon" << "Serpent"
+ << "Mouton" << "Ecureuil" << "Mouche");
+ Proxy proxy;
+ proxy.pattern = QString::fromLatin1("n");
+ proxy.setSourceModel(&sourceModel);
+
+ QCOMPARE(proxy.rowCount(), 5);
+ for (int i = 0; i < proxy.rowCount(); i++) {
+ QVERIFY(proxy.data(proxy.index(i,0)).toString().contains('n'));
+ }
+
+ proxy.pattern = QString::fromLatin1("o");
+ proxy.notifyChange(test);
+
+ QCOMPARE(proxy.rowCount(), works ? 4 : 5);
+ bool ok = true;
+ for (int i = 0; i < proxy.rowCount(); i++) {
+ if (!proxy.data(proxy.index(i,0)).toString().contains('o'))
+ ok = false;
+ }
+ QCOMPARE(ok, works);
+}
+
+Q_DECLARE_METATYPE(QList<QPersistentModelIndex>)
+
+void tst_QSortFilterProxyModel::testParentLayoutChanged()
+{
+ 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);
+ }
+ {
+ QStandardItem *item = new QStandardItem(QString("item 1%0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+ }
+
+ QSortFilterProxyModel proxy;
+ proxy.sort(0, Qt::AscendingOrder);
+ proxy.setDynamicSortFilter(true);
+
+ proxy.setSourceModel(&model);
+ proxy.setObjectName("proxy");
+
+ // When Proxy1 emits layoutChanged(QList<QPersistentModelIndex>) this
+ // one will too, with mapped indexes.
+ QSortFilterProxyModel proxy2;
+ proxy2.sort(0, Qt::AscendingOrder);
+ proxy2.setDynamicSortFilter(true);
+
+ proxy2.setSourceModel(&proxy);
+ proxy2.setObjectName("proxy2");
+
+ qRegisterMetaType<QList<QPersistentModelIndex> >();
+
+ QSignalSpy dataChangedSpy(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
+
+ // Verify that the no-arg signal is still emitted.
+ QSignalSpy layoutAboutToBeChangedSpy(&proxy, SIGNAL(layoutAboutToBeChanged()));
+ QSignalSpy layoutChangedSpy(&proxy, SIGNAL(layoutChanged()));
+
+ QSignalSpy parentsAboutToBeChangedSpy(&proxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy parentsChangedSpy(&proxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+
+ QSignalSpy proxy2ParentsAboutToBeChangedSpy(&proxy2, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy proxy2ParentsChangedSpy(&proxy2, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+
+ QStandardItem *item = model.invisibleRootItem()->child(1)->child(1);
+
+ // Ensure mapped:
+ proxy.mapFromSource(model.indexFromItem(item));
+
+ item->setData("Changed");
+
+ QCOMPARE(dataChangedSpy.size(), 1);
+ QCOMPARE(layoutAboutToBeChangedSpy.size(), 1);
+ QCOMPARE(layoutChangedSpy.size(), 1);
+ QCOMPARE(parentsAboutToBeChangedSpy.size(), 1);
+ QCOMPARE(parentsChangedSpy.size(), 1);
+ QCOMPARE(proxy2ParentsAboutToBeChangedSpy.size(), 1);
+ QCOMPARE(proxy2ParentsChangedSpy.size(), 1);
+
+ QVariantList beforeSignal = parentsAboutToBeChangedSpy.first();
+ QVariantList afterSignal = parentsChangedSpy.first();
+
+ QCOMPARE(beforeSignal.size(), 1);
+ QCOMPARE(afterSignal.size(), 1);
+
+ QList<QPersistentModelIndex> beforeParents = beforeSignal.first().value<QList<QPersistentModelIndex> >();
+ QList<QPersistentModelIndex> afterParents = afterSignal.first().value<QList<QPersistentModelIndex> >();
+
+ QCOMPARE(beforeParents.size(), 1);
+ QCOMPARE(afterParents.size(), 1);
+
+ QVERIFY(beforeParents.first().isValid());
+ QVERIFY(beforeParents.first() == afterParents.first());
+
+ QVERIFY(beforeParents.first() == proxy.mapFromSource(model.indexFromItem(model.invisibleRootItem()->child(1))));
+
+ QList<QPersistentModelIndex> proxy2BeforeList = proxy2ParentsAboutToBeChangedSpy.first().first().value<QList<QPersistentModelIndex> >();
+ QList<QPersistentModelIndex> proxy2AfterList = proxy2ParentsChangedSpy.first().first().value<QList<QPersistentModelIndex> >();
+
+ QCOMPARE(proxy2BeforeList.size(), beforeParents.size());
+ QCOMPARE(proxy2AfterList.size(), afterParents.size());
+ foreach (const QPersistentModelIndex &idx, proxy2BeforeList)
+ QVERIFY(beforeParents.contains(proxy2.mapToSource(idx)));
+ foreach (const QPersistentModelIndex &idx, proxy2AfterList)
+ QVERIFY(afterParents.contains(proxy2.mapToSource(idx)));
+
+}
+
+class SignalArgumentChecker : public QObject
+{
+ Q_OBJECT
+public:
+ SignalArgumentChecker(QAbstractItemModel *model, QAbstractProxyModel *proxy, QObject *parent = 0)
+ : QObject(parent), m_model(model), m_proxy(proxy)
+ {
+ connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ connect(proxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)), SLOT(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ connect(proxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)), SLOT(layoutChanged(QList<QPersistentModelIndex>)));
+ }
+
+private slots:
+ void rowsAboutToBeMoved(const QModelIndex &source, int, int, const QModelIndex &destination, int)
+ {
+ m_p1PersistentBefore = source;
+ m_p2PersistentBefore = destination;
+ m_p2FirstProxyChild = m_proxy->index(0, 0, m_proxy->mapFromSource(destination));
+ }
+
+ void rowsMoved(const QModelIndex &source, int, int, const QModelIndex &destination, int)
+ {
+ m_p1PersistentAfter = source;
+ m_p2PersistentAfter = destination;
+ }
+
+ void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents)
+ {
+ QVERIFY(m_p1PersistentBefore.isValid());
+ QVERIFY(m_p2PersistentBefore.isValid());
+ QCOMPARE(parents.size(), 2);
+ QVERIFY(parents.first() != parents.at(1));
+ QVERIFY(parents.contains(m_proxy->mapFromSource(m_p1PersistentBefore)));
+ QVERIFY(parents.contains(m_proxy->mapFromSource(m_p2PersistentBefore)));
+ }
+
+ void layoutChanged(const QList<QPersistentModelIndex> &parents)
+ {
+ QVERIFY(m_p1PersistentAfter.isValid());
+ QVERIFY(m_p2PersistentAfter.isValid());
+ QCOMPARE(parents.size(), 2);
+ QVERIFY(parents.first() != parents.at(1));
+ QVERIFY(parents.contains(m_proxy->mapFromSource(m_p1PersistentAfter)));
+ QVERIFY(parents.contains(m_proxy->mapFromSource(m_p2PersistentAfter)));
+
+ // In the source model, the rows were moved to row 1 in the parent.
+ // m_p2FirstProxyChild was created with row 0 in the proxy.
+ // The moved rows in the proxy do not appear at row 1 because of sorting.
+ // Sorting causes them to appear at row 0 instead, pushing what used to
+ // be row 0 in the proxy down by two rows.
+ QCOMPARE(m_p2FirstProxyChild.row(), 2);
+ }
+
+private:
+ QAbstractItemModel *m_model;
+ QAbstractProxyModel *m_proxy;
+ QPersistentModelIndex m_p1PersistentBefore;
+ QPersistentModelIndex m_p2PersistentBefore;
+ QPersistentModelIndex m_p1PersistentAfter;
+ QPersistentModelIndex m_p2PersistentAfter;
+
+ QPersistentModelIndex m_p2FirstProxyChild;
+};
+
+void tst_QSortFilterProxyModel::moveSourceRows()
+{
+ qRegisterMetaType<QList<QPersistentModelIndex> >();
+
+ DynamicTreeModel model;
+
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setAncestorRowNumbers(QList<int>() << 2);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+ {
+ ModelInsertCommand insertCommand(&model);
+ insertCommand.setAncestorRowNumbers(QList<int>() << 5);
+ insertCommand.setStartRow(0);
+ insertCommand.setEndRow(9);
+ insertCommand.doCommand();
+ }
+
+ QSortFilterProxyModel proxy;
+ proxy.setDynamicSortFilter(true);
+ proxy.sort(0, Qt::AscendingOrder);
+
+ // We need to check the arguments at emission time
+ SignalArgumentChecker checker(&model, &proxy);
+
+ proxy.setSourceModel(&model);
+
+ QSortFilterProxyModel filterProxy;
+ filterProxy.setDynamicSortFilter(true);
+ filterProxy.sort(0, Qt::AscendingOrder);
+ filterProxy.setSourceModel(&proxy);
+ filterProxy.setFilterRegExp("6"); // One of the parents
+
+ QSortFilterProxyModel filterBothProxy;
+ filterBothProxy.setDynamicSortFilter(true);
+ filterBothProxy.sort(0, Qt::AscendingOrder);
+ filterBothProxy.setSourceModel(&proxy);
+ filterBothProxy.setFilterRegExp("5"); // The parents are 6 and 3. This filters both out.
+
+ QSignalSpy modelBeforeSpy(&model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy modelAfterSpy(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy proxyBeforeMoveSpy(m_proxy, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy proxyAfterMoveSpy(m_proxy, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QSignalSpy proxyBeforeParentLayoutSpy(&proxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy proxyAfterParentLayoutSpy(&proxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy filterBeforeParentLayoutSpy(&filterProxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy filterAfterParentLayoutSpy(&filterProxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy filterBothBeforeParentLayoutSpy(&filterBothProxy, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy filterBothAfterParentLayoutSpy(&filterBothProxy, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+
+ {
+ ModelMoveCommand moveCommand(&model, 0);
+ moveCommand.setAncestorRowNumbers(QList<int>() << 2);
+ moveCommand.setDestAncestors(QList<int>() << 5);
+ moveCommand.setStartRow(3);
+ moveCommand.setEndRow(4);
+ moveCommand.setDestRow(1);
+ moveCommand.doCommand();
+ }
+
+ // Proxy notifies layout change
+ QCOMPARE(modelBeforeSpy.size(), 1);
+ QCOMPARE(proxyBeforeParentLayoutSpy.size(), 1);
+ QCOMPARE(modelAfterSpy.size(), 1);
+ QCOMPARE(proxyAfterParentLayoutSpy.size(), 1);
+
+ // But it doesn't notify a move.
+ QCOMPARE(proxyBeforeMoveSpy.size(), 0);
+ QCOMPARE(proxyAfterMoveSpy.size(), 0);
+
+ QCOMPARE(filterBeforeParentLayoutSpy.size(), 1);
+ QCOMPARE(filterAfterParentLayoutSpy.size(), 1);
+
+ QList<QPersistentModelIndex> filterBeforeParents = filterBeforeParentLayoutSpy.first().first().value<QList<QPersistentModelIndex> >();
+ QList<QPersistentModelIndex> filterAfterParents = filterAfterParentLayoutSpy.first().first().value<QList<QPersistentModelIndex> >();
+
+ QCOMPARE(filterBeforeParents.size(), 1);
+ QCOMPARE(filterAfterParents.size(), 1);
+
+ QCOMPARE(filterBothBeforeParentLayoutSpy.size(), 0);
+ QCOMPARE(filterBothAfterParentLayoutSpy.size(), 0);
+}
+
+QTEST_MAIN(tst_QSortFilterProxyModel)
+#include "tst_qsortfilterproxymodel.moc"
diff --git a/tests/auto/corelib/itemmodels/qstringlistmodel/.gitignore b/tests/auto/corelib/itemmodels/qstringlistmodel/.gitignore
new file mode 100644
index 0000000000..9c14561e3c
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qstringlistmodel/.gitignore
@@ -0,0 +1 @@
+tst_qstringlistmodel
diff --git a/tests/auto/corelib/itemmodels/qstringlistmodel/qmodellistener.h b/tests/auto/corelib/itemmodels/qstringlistmodel/qmodellistener.h
new file mode 100644
index 0000000000..f3ed3c1793
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qstringlistmodel/qmodellistener.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QObject>
+#include <QModelIndex>
+#include <qdebug.h>
+
+
+QT_FORWARD_DECLARE_CLASS(QStringListModel)
+
+class QModelListener : public QObject
+{
+ Q_OBJECT
+public:
+ QModelListener(QStringList *pAboutToStringlist, QStringList *pExpectedStringlist, QStringListModel *pModel)
+ {
+ setTestData(pAboutToStringlist, pExpectedStringlist, pModel);
+ }
+ virtual ~QModelListener() { }
+
+ void setTestData(QStringList *pAboutToStringlist, QStringList *pExpectedStringlist, QStringListModel *pModel)
+ {
+ m_pAboutToStringlist = pAboutToStringlist;
+ m_pExpectedStringlist = pExpectedStringlist;
+ m_pModel = pModel;
+ }
+
+private:
+ QStringList *m_pAboutToStringlist;
+ QStringList *m_pExpectedStringlist;
+ QStringListModel *m_pModel;
+
+public slots:
+ void rowsAboutToBeRemovedOrInserted(const QModelIndex & parent, int start, int end );
+ void rowsRemovedOrInserted(const QModelIndex & parent, int start, int end );
+
+};
+
diff --git a/tests/auto/corelib/itemmodels/qstringlistmodel/qstringlistmodel.pro b/tests/auto/corelib/itemmodels/qstringlistmodel/qstringlistmodel.pro
new file mode 100644
index 0000000000..ecdd30cae2
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qstringlistmodel/qstringlistmodel.pro
@@ -0,0 +1,9 @@
+CONFIG += testcase
+TARGET = tst_qstringlistmodel
+QT += widgets testlib
+HEADERS += qmodellistener.h
+
+SOURCES += tst_qstringlistmodel.cpp
+
+
+
diff --git a/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp b/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp
new file mode 100644
index 0000000000..c8afe5dd75
--- /dev/null
+++ b/tests/auto/corelib/itemmodels/qstringlistmodel/tst_qstringlistmodel.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <qabstractitemmodel.h>
+#include <qapplication.h>
+#include <qmap.h>
+#include <qstringlistmodel.h>
+#include <qstringlist.h>
+#include <qlistview.h>
+#include "qmodellistener.h"
+#include <qstringlistmodel.h>
+
+void QModelListener::rowsAboutToBeRemovedOrInserted(const QModelIndex & parent, int start, int end )
+{
+ int i;
+ for (i = 0; start + i <= end; i++)
+ {
+ QModelIndex mIndex = m_pModel->index(start + i, 0, parent);
+ QVariant var = m_pModel->data(mIndex, Qt::DisplayRole);
+ QString str = var.toString();
+
+ QCOMPARE(str, m_pAboutToStringlist->at(i));
+ }
+}
+
+void QModelListener::rowsRemovedOrInserted(const QModelIndex & parent, int , int)
+{
+ int i;
+ // Can the rows that *are* removed be iterated now ?
+
+ // What about rowsAboutToBeInserted - what will the indices be?
+ // will insertRow() overwrite existing, or insert (and conseq. grow the model?)
+ // What will the item then contain? empty data?
+
+ // RemoveColumn. Does that also fire the rowsRemoved-family signals?
+
+ for (i = 0; i < m_pExpectedStringlist->size(); i++)
+ {
+ QModelIndex mIndex = m_pModel->index(i, 0, parent);
+ QVariant var = m_pModel->data(mIndex, Qt::DisplayRole);
+ QString str = var.toString();
+
+ //qDebug() << "index: " << i << " start: " << start << "end: " << end;
+ QCOMPARE(str, m_pExpectedStringlist->at(i));
+ }
+}
+
+
+class tst_QStringListModel : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ tst_QStringListModel();
+ virtual ~tst_QStringListModel();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+private slots:
+
+ void rowsAboutToBeRemoved_rowsRemoved();
+ void rowsAboutToBeRemoved_rowsRemoved_data();
+
+ void rowsAboutToBeInserted_rowsInserted();
+ void rowsAboutToBeInserted_rowsInserted_data();
+};
+
+
+tst_QStringListModel::tst_QStringListModel()
+
+{
+}
+
+tst_QStringListModel::~tst_QStringListModel()
+{
+}
+
+void tst_QStringListModel::initTestCase()
+{
+}
+
+void tst_QStringListModel::cleanupTestCase()
+{
+}
+
+void tst_QStringListModel::init()
+{
+}
+
+void tst_QStringListModel::cleanup()
+{
+}
+
+/*
+ tests
+*/
+
+
+void tst_QStringListModel::rowsAboutToBeRemoved_rowsRemoved_data()
+{
+ QTest::addColumn<QStringList>("input");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<QStringList>("aboutto");
+ QTest::addColumn<QStringList>("res");
+
+ QStringList strings0; strings0 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto0; aboutto0 << "Two" << "Three";
+ QStringList res0; res0 << "One" << "Four" << "Five";
+ QTest::newRow( "data0" ) << strings0 << 1 << 2 << aboutto0 << res0;
+
+ QStringList strings1; strings1 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto1; aboutto1 << "One" << "Two";
+ QStringList res1; res1 << "Three" << "Four" << "Five";
+ QTest::newRow( "data1" ) << strings1 << 0 << 2 << aboutto1 << res1;
+
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three";
+ QTest::newRow( "data2" ) << strings2 << 3 << 2 << aboutto2 << res2;
+
+ QStringList strings3; strings3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto3; aboutto3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res3;
+ QTest::newRow( "data3" ) << strings3 << 0 << 5 << aboutto3 << res3;
+
+ /* Not sure if this is a valid test */
+ QStringList strings4; strings4 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto4; aboutto4 << "Five" << "";
+ QStringList res4; res4 << "One" << "Two" << "Three" << "Four";
+ QTest::newRow( "data4" ) << strings4 << 4 << 2 << aboutto4 << res4;
+
+ /*
+ * Keep this, template to add more data
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data2" ) << strings2 << 0 << 5 << aboutto2 << res2;
+*/
+
+}
+
+void tst_QStringListModel::rowsAboutToBeRemoved_rowsRemoved()
+{
+ QFETCH(QStringList, input);
+ QFETCH(int, row);
+ QFETCH(int, count);
+ QFETCH(QStringList, aboutto);
+ QFETCH(QStringList, res);
+
+ QStringListModel *model = new QStringListModel(input);
+ QModelListener *pListener = new QModelListener(&aboutto, &res, model);
+ pListener->connect(model, SIGNAL( rowsAboutToBeRemoved(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsAboutToBeRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ pListener->connect(model, SIGNAL( rowsRemoved(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ model->removeRows(row,count);
+ // At this point, control goes to our connected slots inn this order:
+ // 1. rowsAboutToBeRemovedOrInserted
+ // 2. rowsRemovedOrInserted
+ // Control returns here
+
+ delete pListener;
+ delete model;
+
+}
+
+void tst_QStringListModel::rowsAboutToBeInserted_rowsInserted_data()
+{
+ QTest::addColumn<QStringList>("input");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<QStringList>("aboutto");
+ QTest::addColumn<QStringList>("res");
+
+ QStringList strings0; strings0 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto0; aboutto0 << "Two" << "Three";
+ QStringList res0; res0 << "One" << "" << "" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data0" ) << strings0 << 1 << 2 << aboutto0 << res0;
+
+ QStringList strings1; strings1 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto1; aboutto1 << "One" << "Two";
+ QStringList res1; res1 << "" << "" << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data1" ) << strings1 << 0 << 2 << aboutto1 << res1;
+
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three" << "" << "" << "Four" << "Five";
+ QTest::newRow( "data2" ) << strings2 << 3 << 2 << aboutto2 << res2;
+
+ QStringList strings3; strings3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto3; aboutto3 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res3; res3 << "" << "" << "" << "" << "" << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data3" ) << strings3 << 0 << 5 << aboutto3 << res3;
+
+ /*
+ * Keep this, template to add more data
+ QStringList strings2; strings2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList aboutto2; aboutto2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QStringList res2; res2 << "One" << "Two" << "Three" << "Four" << "Five";
+ QTest::newRow( "data2" ) << strings2 << 0 << 5 << aboutto2 << res2;
+*/
+
+}
+
+void tst_QStringListModel::rowsAboutToBeInserted_rowsInserted()
+{
+ QFETCH(QStringList, input);
+ QFETCH(int, row);
+ QFETCH(int, count);
+ QFETCH(QStringList, aboutto);
+ QFETCH(QStringList, res);
+
+ QStringListModel *model = new QStringListModel(input);
+ QModelListener *pListener = new QModelListener(&aboutto, &res, model);
+ connect(model, SIGNAL( rowsAboutToBeInserted(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsAboutToBeRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ connect(model, SIGNAL( rowsInserted(const QModelIndex & , int , int )),
+ pListener, SLOT( rowsRemovedOrInserted(const QModelIndex & , int , int )) );
+
+ model->insertRows(row,count);
+ // At this point, control goes to our connected slots inn this order:
+ // 1. rowsAboutToBeRemovedOrInserted
+ // 2. rowsRemovedOrInserted
+ // Control returns here
+
+ delete pListener;
+ delete model;
+
+}
+
+
+QTEST_MAIN(tst_QStringListModel)
+#include "tst_qstringlistmodel.moc"
+