Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QtTest/private/qpropertytesthelper_p.h>
#include <QSignalSpy>
#include <QtGui/QtGui>
#include <algorithm>
Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlag)
Q_DECLARE_METATYPE(Qt::SortOrder)
class tst_QItemSelectionModel : public QObject
{
Q_OBJECT
public:
tst_QItemSelectionModel();
public slots:
void initTestCase();
void cleanupTestCase();
void init();
private slots:
void compareCompiles();
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 rowIntersectsSelection1();
void rowIntersectsSelection2();
void rowIntersectsSelection3();
void unselectable();
void selectedIndexes();
void layoutChanged();
void merge_data();
void merge();
void isRowSelected();
void isColumnSelected();
void childrenDeselectionSignal();
#if QT_CONFIG(proxymodel)
void layoutChangedWithAllSelected1();
void layoutChangedWithAllSelected2();
#endif
void layoutChangedTreeSelection();
void deselectRemovedMiddleRange();
void setModel();
void bindableModel();
void testDifferentModels();
void testValidRangesInSelectionsAfterReset();
void testChainedSelectionClear();
void testClearCurrentIndex();
void QTBUG48402_data();
void QTBUG48402();
void QTBUG58851_data();
#if QT_CONFIG(proxymodel)
void QTBUG58851();
#endif
void QTBUG18001_data();
void QTBUG18001();
void QTBUG93305();
void testSignalsDisconnection();
void destroyModel();
private:
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
QAbstractItemModel *model;
QItemSelectionModel *selection;
};
QT_BEGIN_NAMESPACE
QDataStream &operator<<(QDataStream &, const QModelIndex &);
QDataStream &operator>>(QDataStream &, QModelIndex &);
QDataStream &operator<<(QDataStream &, const QModelIndexList &);
QDataStream &operator>>(QDataStream &, QModelIndexList &);
typedef QList<int> IntList;
using IntPair = std::pair<int, int>;
typedef QList<IntPair> PairList;
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 override
{ return QModelIndex(); }
QModelIndex parent(const QModelIndex&) const override
{ return QModelIndex(); }
int rowCount(const QModelIndex & = QModelIndex()) const override
{ return 0; }
int columnCount(const QModelIndex & = QModelIndex()) const override
{ return 0; }
QVariant data(const QModelIndex &, int = Qt::DisplayRole) const override
{ return QVariant(); }
bool hasChildren(const QModelIndex &) const override
{ 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.size();
for (int i=0; i<input.size(); ++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;
}
QT_END_NAMESPACE
tst_QItemSelectionModel::tst_QItemSelectionModel()
: model(0), selection(0)
{
}
/*
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::compareCompiles()
{
QTestPrivate::testEqualityOperatorsCompile<QItemSelectionRange>();
}
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.size(); ++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().size(), 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().size(), 0);
QVERIFY(selection->hasSelection()==false);
QModelIndex index=model->index(1, 1, QModelIndex());
// populate selectionmodel
selection->select(index, QItemSelectionModel::Toggle);
QCOMPARE(selection->selectedIndexes().size(), 1);
QVERIFY(selection->hasSelection()==true);
selection->select(index, QItemSelectionModel::Toggle);
QCOMPARE(selection->selectedIndexes().size(), 0);
QVERIFY(selection->hasSelection()==false);
// populate selectionmodel with rows
selection->select(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
QCOMPARE(selection->selectedIndexes().size(), model->columnCount());
QVERIFY(selection->hasSelection()==true);
selection->select(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
QCOMPARE(selection->selectedIndexes().size(), 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;
}
{
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.size(); ++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());
// test that the number of indices are as expected
QVERIFY2(selectedList.size() == expectedList.size(),
QString("expected indices: %1 actual indices: %2")
.arg(expectedList.size())
.arg(selectedList.size()).toLatin1());
// test existence of each index
for (int i=0; i<expectedList.size(); ++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.size(); ++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.size(); ++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.size(); ++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(const 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.size(); ++i) {
if (indexList.size() == commandList.size()) {
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.size() > 1)
model->insertRows(insertRows.at(0), insertRows.at(1), QModelIndex());
if (insertColumns.size() > 1)
model->insertColumns(insertColumns.at(0), insertColumns.at(1), QModelIndex());
if (deleteRows.size() > 1)
model->removeRows(deleteRows.at(0), deleteRows.at(1), QModelIndex());
if (deleteColumns.size() > 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.size(), expectedList.size());
for (const auto &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() { beginResetModel(); endResetModel(); }
};
void tst_QItemSelectionModel::resetModel()
{
MyStandardItemModel model(20, 20);
QItemSelectionModel *selectionModel = new QItemSelectionModel(&model);
QSignalSpy spy(selectionModel, &QItemSelectionModel::selectionChanged);
QVERIFY(spy.isValid());
selectionModel->select(QItemSelection(model.index(0, 0), model.index(5, 5)), QItemSelectionModel::Select);
QCOMPARE(spy.size(), 1);
model.reset();
QVERIFY(selectionModel->selection().isEmpty());
QVERIFY(!selectionModel->hasSelection());
selectionModel->select(QItemSelection(model.index(0, 0), model.index(5, 5)), QItemSelectionModel::Select);
QCOMPARE(spy.size(), 2);
QCOMPARE(spy.at(1).size(), 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, &QItemSelectionModel::selectionChanged);
QVERIFY(spy.isValid());
QModelIndex tl = model.index(selectTop, selectLeft);
QModelIndex br = model.index(selectBottom, selectRight);
selections.select(QItemSelection(tl, br), QItemSelectionModel::ClearAndSelect);
QCOMPARE(spy.size(), 1);
QVERIFY(selections.isSelected(tl));
QVERIFY(selections.isSelected(br));
QVERIFY(selections.hasSelection());
model.removeRows(removeTop, removeBottom - removeTop + 1);
QCOMPARE(spy.size(), 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, &QItemSelectionModel::selectionChanged);
QVERIFY(spy.isValid());
QModelIndex tl = model.index(selectTop, selectLeft);
QModelIndex br = model.index(selectBottom, selectRight);
selections.select(QItemSelection(tl, br), QItemSelectionModel::ClearAndSelect);
QCOMPARE(spy.size(), 1);
QVERIFY(selections.isSelected(tl));
QVERIFY(selections.isSelected(br));
QVERIFY(selections.hasSelection());
model.removeColumns(removeLeft, removeRight - removeLeft + 1);
QCOMPARE(spy.size(), 2);
tl = model.index(expectedTop, expectedLeft);
br = model.index(expectedBottom, expectedRight);
QVERIFY(selections.isSelected(tl));
QVERIFY(selections.isSelected(br));
}
typedef QList<IntList> IntListList;
using IntPairPair = std::pair<IntPair, IntPair>;
typedef QList<IntPairPair> IntPairPairList;
void tst_QItemSelectionModel::modelLayoutChanged_data()
{
QTest::addColumn<IntListList>("items");
QTest::addColumn<IntPairPairList>("initialSelectedRanges");
QTest::addColumn<Qt::SortOrder>("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)))
<< 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)))
<< 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)))
<< 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)))
<< 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(const IntPairPairList, initialSelectedRanges);
QFETCH(Qt::SortOrder, sortOrder);
QFETCH(int, sortColumn);
QFETCH(IntPairPairList, expectedSelectedRanges);
MyStandardItemModel model(items.at(0).size(), items.size());
// 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);
for (const auto &range : initialSelectedRanges) {
const auto &tl = range.first;
const auto &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, sortOrder);
// verify that selection is as expected
QItemSelection selection = selectionModel.selection();
QCOMPARE(selection.size(), expectedSelectedRanges.size());
QCOMPARE(selectionModel.hasSelection(), !expectedSelectedRanges.isEmpty());
for (int i = 0; i < expectedSelectedRanges.size(); ++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.size(); ++i)
selectionModel.select(model.index(selectRows.at(i), 0),
QItemSelectionModel::Select
|QItemSelectionModel::Rows);
for (int j = 0; j < selectRows.size(); ++j)
QVERIFY(selectionModel.isRowSelected(expectedRows.at(j), QModelIndex()));
for (int k = 0; k < selectRows.size(); ++k)
QVERIFY(!selectionModel.isRowSelected(unexpectedRows.at(k), QModelIndex()));
QModelIndexList selectedRowIndexes = selectionModel.selectedRows(column);
QCOMPARE(selectedRowIndexes.size(), expectedRows.size());
std::sort(selectedRowIndexes.begin(), selectedRowIndexes.end());
for (int l = 0; l < selectedRowIndexes.size(); ++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.size(); ++i)
selectionModel.select(model.index(0, selectColumns.at(i)),
QItemSelectionModel::Select
|QItemSelectionModel::Columns);
for (int j = 0; j < selectColumns.size(); ++j)
QVERIFY(selectionModel.isColumnSelected(expectedColumns.at(j), QModelIndex()));
for (int k = 0; k < selectColumns.size(); ++k)
QVERIFY(!selectionModel.isColumnSelected(unexpectedColumns.at(k), QModelIndex()));
QModelIndexList selectedColumnIndexes = selectionModel.selectedColumns(row);
QCOMPARE(selectedColumnIndexes.size(), expectedColumns.size());
std::sort(selectedColumnIndexes.begin(), selectedColumnIndexes.end());
for (int l = 0; l < selectedColumnIndexes.size(); ++l) {
QCOMPARE(selectedColumnIndexes.at(l).column(), expectedColumns.at(l));
QCOMPARE(selectedColumnIndexes.at(l).row(), row);
}
}
void tst_QItemSelectionModel::setCurrentIndex()
{
// Build up a simple tree
QScopedPointer<QStandardItemModel> treemodel(new QStandardItemModel(0, 1));
treemodel->insertRow(0, new QStandardItem(1));
treemodel->insertRow(1, new QStandardItem(2));
QItemSelectionModel selectionModel(treemodel.data());
selectionModel.setCurrentIndex(
treemodel->index(0, 0, treemodel->index(0, 0)),
QItemSelectionModel::SelectCurrent);
QSignalSpy currentSpy(&selectionModel, &QItemSelectionModel::currentChanged);
QSignalSpy rowSpy(&selectionModel, &QItemSelectionModel::currentRowChanged);
QSignalSpy columnSpy(&selectionModel, &QItemSelectionModel::currentColumnChanged);
QVERIFY(currentSpy.isValid());
QVERIFY(rowSpy.isValid());
QVERIFY(columnSpy.isValid());
// 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.size(), 1);
QCOMPARE(rowSpy.size(), 1);
QCOMPARE(columnSpy.size(), 1);
// Select another row in the same parent
selectionModel.setCurrentIndex(
treemodel->index(1, 0, treemodel->index(1, 0)),
QItemSelectionModel::SelectCurrent);
QCOMPARE(currentSpy.size(), 2);
QCOMPARE(rowSpy.size(), 2);
QCOMPARE(columnSpy.size(), 1);
}
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::rowIntersectsSelection1()
{
QStandardItemModel model;
model.setItem(0, 0, new QStandardItem("foo"));
QItemSelectionModel selectionModel(&model);
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()));
QStandardItemModel model2;
model2.setItem(0, 0, new QStandardItem("foo"));
QVERIFY(!selectionModel.rowIntersectsSelection(0, model2.index(0, 0, QModelIndex())));
QVERIFY(!selectionModel.columnIntersectsSelection(0, model2.index(0, 0, QModelIndex())));
}
void tst_QItemSelectionModel::rowIntersectsSelection2()
{
QStandardItemModel m;
for (int i=0; i<8; ++i) {
const QString text = QLatin1String("Item number ") + QString::number(i);
for (int j=0; j<8; ++j) {
QStandardItem *item = new QStandardItem(text);
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::rowIntersectsSelection3()
{
QStandardItemModel model;
QStandardItem *parentItem = model.invisibleRootItem();
for (int i = 0; i < 4; ++i) {
QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
parentItem->appendRow(item);
parentItem = item;
}
QItemSelectionModel selectionModel(&model);
selectionModel.select(model.index(0, 0, model.index(0, 0)), QItemSelectionModel::Select);
QModelIndex parent;
QVERIFY(!selectionModel.rowIntersectsSelection(0, parent));
QVERIFY(!selectionModel.columnIntersectsSelection(0, parent));
parent = model.index(0, 0, parent);
QVERIFY(selectionModel.rowIntersectsSelection(0, parent));
QVERIFY(selectionModel.columnIntersectsSelection(0, parent));
parent = model.index(0, 0, parent);
QVERIFY(!selectionModel.rowIntersectsSelection(0, parent));
QVERIFY(!selectionModel.columnIntersectsSelection(0, parent));
parent = model.index(0, 0, parent);
QVERIFY(!selectionModel.rowIntersectsSelection(0, parent));
QVERIFY(!selectionModel.columnIntersectsSelection(0, parent));
}
void tst_QItemSelectionModel::unselectable()
{
QStandardItemModel model;
QStandardItem *parentItem = model.invisibleRootItem();
for (int i = 0; i < 10; ++i) {
QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
parentItem->appendRow(item);
}
QItemSelectionModel selectionModel(&model);
selectionModel.select(QItemSelection(model.index(0, 0), model.index(9, 0)), QItemSelectionModel::Select);
QCOMPARE(selectionModel.selectedIndexes().size(), 10);
QCOMPARE(selectionModel.selectedRows().size(), 10);
QVERIFY(selectionModel.hasSelection());
for (int j = 0; j < 10; ++j)
model.item(j)->setFlags({ });
QVERIFY(!selectionModel.hasSelection());
QCOMPARE(selectionModel.selectedIndexes().size(), 0);
QCOMPARE(selectionModel.selectedRows().size(), 0);
}
void tst_QItemSelectionModel::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().size(), 1);
QCOMPARE(selectionModel.selectedIndexes().size(), model.columnCount());
}
class QtTestTableModel: public QAbstractTableModel
{
Q_OBJECT
public:
QtTestTableModel(int rows = 0, int columns = 0, QObject *parent = nullptr)
: QAbstractTableModel(parent)
, row_count(rows)
, column_count(columns)
{
}
int rowCount(const QModelIndex& = QModelIndex()) const override { return row_count; }
int columnCount(const QModelIndex& = QModelIndex()) const override { return column_count; }
bool isEditable(const QModelIndex &) const { return true; }
QVariant data(const QModelIndex &idx, int role) const override
{
if (role == Qt::DisplayRole || role == Qt::EditRole)
return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',')
+ QString::number(idx.column()) + QLatin1Char(']');
return QVariant();
}
int row_count;
int column_count;
friend class tst_QItemSelectionModel;
};
void tst_QItemSelectionModel::layoutChanged()
{
QtTestTableModel model(1,1);
QItemSelectionModel selectionModel(&model);
selectionModel.select(model.index(0,0), QItemSelectionModel::Select);
QCOMPARE(selectionModel.selectedIndexes().size() , 1);
emit model.layoutAboutToBeChanged();
model.row_count = 5;
emit model.layoutChanged();
//The selection should not change.
QCOMPARE(selectionModel.selectedIndexes().size() , 1);
QCOMPARE(selectionModel.selectedIndexes().first() , model.index(0,0));
}
void tst_QItemSelectionModel::merge_data()
{
QTest::addColumn<QItemSelection>("init");
QTest::addColumn<QItemSelection>("other");
QTest::addColumn<QItemSelectionModel::SelectionFlag>("command");
QTest::addColumn<QItemSelection>("result");
QTest::newRow("Simple select")
<< QItemSelection()
<< QItemSelection(model->index(2, 1) , model->index(3, 4))
<< 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))
<< 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))
<< QItemSelectionModel::Toggle
<< QItemSelection();
QTest::newRow("Simple Toggle select")
<< QItemSelection()
<< QItemSelection(model->index(2, 1) , model->index(3, 4))
<< 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))
<< 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))
<< 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))
<< QItemSelectionModel::Toggle
<< r1;
}
void tst_QItemSelectionModel::merge()
{
QFETCH(QItemSelection, init);
QFETCH(QItemSelection, other);
QFETCH(QItemSelectionModel::SelectionFlag, command);
QFETCH(QItemSelection, result);
init.merge(other, command);
auto verify = [](const QModelIndexList &a, const QItemSelection &b)
{
for (const QModelIndex &idx : a)
QVERIFY(b.contains(idx));
};
verify(init.indexes(), result);
verify(result.indexes(), init);
}
void tst_QItemSelectionModel::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().size(), 1);
QVERIFY(sel.isRowSelected(0));
QVERIFY(!sel.isRowSelected(1));
// check Toggle branch in isRowSelected()
sel.select(QItemSelection(model.index(0, 0), model.index(0, 1)), QItemSelectionModel::Toggle);
QVERIFY(!sel.isRowSelected(0));
QVERIFY(!sel.isRowSelected(1));
sel.select(QItemSelection(model.index(0, 0), model.index(0, 1)), QItemSelectionModel::Toggle);
QVERIFY(sel.isRowSelected(0));
QVERIFY(!sel.isRowSelected(1));
// check Deselect branch in isRowSelected()
sel.select(QItemSelection(model.index(0, 0), model.index(0, 1)), QItemSelectionModel::Deselect);
QVERIFY(!sel.isRowSelected(0));
QVERIFY(!sel.isRowSelected(1));
}
void tst_QItemSelectionModel::isColumnSelected()
{
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(1, 0)), QItemSelectionModel::Select);
QCOMPARE(sel.selectedIndexes().size(), 1);
QVERIFY(sel.isColumnSelected(0));
QVERIFY(!sel.isColumnSelected(1));
// check Toggle branch in isColumnSelected()
sel.select(QItemSelection(model.index(0, 0), model.index(1, 0)), QItemSelectionModel::Toggle);
QVERIFY(!sel.isColumnSelected(0));
QVERIFY(!sel.isColumnSelected(1));
sel.select(QItemSelection(model.index(0, 0), model.index(1, 0)), QItemSelectionModel::Toggle);
QVERIFY(sel.isColumnSelected(0));
QVERIFY(!sel.isColumnSelected(1));
// check Deselect branch in isColumnSelected()
sel.select(QItemSelection(model.index(0, 0), model.index(1, 0)), QItemSelectionModel::Deselect);
QVERIFY(!sel.isColumnSelected(0));
QVERIFY(!sel.isColumnSelected(1));
}
void tst_QItemSelectionModel::childrenDeselectionSignal()
{
QStandardItemModel model;
QStandardItem *parentItem = model.invisibleRootItem();
for (int i = 0; i < 4; ++i) {
QStandardItem *item = new QStandardItem(QLatin1String("item ") + QString::number(i));
parentItem->appendRow(item);
parentItem = item;
}
QModelIndex root = model.index(0,0);
QModelIndex par = model.index(0, 0, root);
QModelIndex sel = model.index(0, 0, par);
QItemSelectionModel selectionModel(&model);
selectionModel.select(sel, QItemSelectionModel::SelectCurrent);
QSignalSpy deselectSpy(&selectionModel, &QItemSelectionModel::selectionChanged);
QVERIFY(deselectSpy.isValid());
model.removeRows(0, 1, root);
QCOMPARE(deselectSpy.size(), 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(QLatin1String("item ") + QString::number(i));
parentItem->appendRow(item);
}
for (int i = 0; i < 2; ++i) {
parentItem = model.invisibleRootItem()->child(i, 0);
const QString prefix = QLatin1String("item ") + QString::number(i) + QLatin1Char('.');
for (int j = 0; j < 2; ++j) {
QStandardItem *item = new QStandardItem(prefix + QString::number(j));
parentItem->appendRow(item);
}
}
sel = model.index(0, 0, model.index(0, 0));
selectionModel.select(sel, QItemSelectionModel::Select);
QModelIndex sel2 = model.index(0, 0, model.index(1, 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));
QCOMPARE(deselectSpy.size(), 1);
QVERIFY(!selectionModel.selection().contains(sel));
QVERIFY(selectionModel.selection().contains(sel2));
}
#if QT_CONFIG(proxymodel)
void tst_QItemSelectionModel::layoutChangedWithAllSelected1()
{
QStringListModel model( QStringList() << "foo" << "bar" << "foo2");
QSortFilterProxyModel proxy;
proxy.setSourceModel(&model);
QItemSelectionModel selection(&proxy);
QCOMPARE(model.rowCount(), 3);
QCOMPARE(proxy.rowCount(), 3);
proxy.setFilterRegularExpression(QRegularExpression("f"));
QCOMPARE(proxy.rowCount(), 2);
const QList<QPersistentModelIndex> 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().size(), indexList.size());
for (const auto &index : indexList)
QVERIFY(selection.isSelected(index));
proxy.setFilterRegularExpression(QRegularExpression());
QCOMPARE(proxy.rowCount(), 3);
//let's check the selection hasn't changed
QCOMPARE(selection.selectedIndexes().size(), indexList.size());
for (const auto &index : indexList)
QVERIFY(selection.isSelected(index));
}
// Same as layoutChangedWithAllSelected1, but with a slightly bigger model.
// This test is a regression test for QTBUG-5671.
void tst_QItemSelectionModel::layoutChangedWithAllSelected2()
{
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 override
{
return !filtering || !( source_row & 1 );
}
};
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, QLatin1String("Column ") + QString::number(i));
for (unsigned int r = 0; r < cNumRows; r++) {
const QString prefix = QLatin1String("r:") + QString::number(r) + QLatin1String("/c:");
for (unsigned int c = 0; c < cNumCols; c++)
model.setData(model.index(r, c, QModelIndex()), prefix + QString::number(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);
const auto selIndexes = selection.selectedIndexes();
const QList<QPersistentModelIndex> indexList(selIndexes.begin(), selIndexes.end());
proxy.filtering = false;
proxy.invalidate();
QCOMPARE(proxy.rowCount(), int(cNumRows));
//let's check the selection hasn't changed
QCOMPARE(selection.selectedIndexes().size(), indexList.size());
for (const auto &index : indexList)
QVERIFY(selection.isSelected(index));
}
#endif
// This test is a regression test for QTBUG-2804.
void tst_QItemSelectionModel::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.size(), 4);
model.sort(0); //this will provoke a relayout
QCOMPARE(selModel.selectedIndexes().size(), 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)
{
const auto deselIndexes = deselected.indexes();
for (const auto &index : deselIndexes) {
QVERIFY(!m_itemSelectionModel->selection().contains(index));
}
QCOMPARE(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);
QCOMPARE(selModel.selection().size(), 1);
RemovalObserver ro(&selModel);
QSignalSpy spy(&selModel, &QItemSelectionModel::selectionChanged);
QVERIFY(spy.isValid());
bool ok = model.removeRows(4, 2);
QVERIFY(ok);
QCOMPARE(spy.size(), 1);
}
void tst_QItemSelectionModel::setModel()
{
QItemSelectionModel sel;
QVERIFY(!sel.model());
QSignalSpy modelChangedSpy(&sel, SIGNAL(modelChanged(QAbstractItemModel*)));
QStringListModel model(QStringList() << "Blah" << "Blah" << "Blah");
sel.setModel(&model);
QCOMPARE(sel.model(), &model);
QCOMPARE(modelChangedSpy.size(), 1);
sel.select(model.index(0), QItemSelectionModel::Select);
QVERIFY(!sel.selection().isEmpty());
sel.setModel(0);
QVERIFY(sel.selection().isEmpty());
}
void tst_QItemSelectionModel::bindableModel()
{
QItemSelectionModel sel;
QVERIFY(!sel.model());
std::unique_ptr<QStringListModel> firstModel(
new QStringListModel(QStringList { "Some", "random", "content" }));
std::unique_ptr<QStringListModel> changedModel(
new QStringListModel(QStringList { "Other", "random", "content" }));
QTestPrivate::testReadWritePropertyBasics<QItemSelectionModel, QAbstractItemModel *>(
sel, firstModel.get(), changedModel.get(), "model");
if (QTest::currentTestFailed()) {
qDebug("Failed property test for QItemSelectionModel::model");
return;
}
// check that model is set to nullptr when the object pointed to is deleted:
sel.setModel(firstModel.get());
firstModel.reset();
QCOMPARE(sel.model(), nullptr);
}
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 = nullptr)
: 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)
{
for (const auto &range : selected)
QVERIFY(range.isValid());
for (const auto &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 = nullptr)
: QItemSelectionModel(model, parent), m_target(target)
{
}
void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override
{
QItemSelectionModel::select(selection, command);
m_target->select(selection, command);
}
using QItemSelectionModel::select;
void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) override
{
QItemSelectionModel::setCurrentIndex(index, command);
m_target->setCurrentIndex(index, command);
}
void clearCurrentIndex() override
{
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();
QCOMPARE(selectedIndexes.size(), duplicatedIndexes.size());
QCOMPARE(selectedIndexes.size(), 1);
QVERIFY(selectedIndexes.first() == model.index(0, 0));
}
duplicate.clearSelection();
{
QModelIndexList selectedIndexes = selectionModel.selection().indexes();
QModelIndexList duplicatedIndexes = duplicate.selection().indexes();
QCOMPARE(selectedIndexes.size(), duplicatedIndexes.size());
QCOMPARE(selectedIndexes.size(), 0);
}
duplicate.setCurrentIndex(model.index(0, 0), QItemSelectionModel::NoUpdate);
QCOMPARE(selectionModel.currentIndex(), duplicate.currentIndex());
duplicate.clearCurrentIndex();
QVERIFY(!duplicate.currentIndex().isValid());
QCOMPARE(selectionModel.currentIndex(), duplicate.currentIndex());
}
void tst_QItemSelectionModel::testClearCurrentIndex()
{
QStringListModel model(QStringList() << "Apples" << "Pears");
QItemSelectionModel selectionModel(&model, 0);
QSignalSpy currentIndexSpy(&selectionModel, &QItemSelectionModel::currentChanged);
QVERIFY(currentIndexSpy.isValid());
QModelIndex firstIndex = model.index(0, 0);
QVERIFY(firstIndex.isValid());
selectionModel.setCurrentIndex(firstIndex, QItemSelectionModel::NoUpdate);
QCOMPARE(selectionModel.currentIndex(), firstIndex);
QCOMPARE(currentIndexSpy.size(), 1);
selectionModel.clearCurrentIndex();
QCOMPARE(selectionModel.currentIndex(), QModelIndex());
QCOMPARE(currentIndexSpy.size(), 2);
}
void tst_QItemSelectionModel::QTBUG48402_data()
{
QTest::addColumn<int>("rows");
QTest::addColumn<int>("columns");
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>("deselectTop");
QTest::addColumn<int>("deselectLeft");
QTest::addColumn<int>("deselectBottom");
QTest::addColumn<int>("deselectRight");
QTest::newRow("4x4 top intersection")
<< 4 << 4
<< 0 << 2 << 1 << 3
<< 1 << 1
<< 1 << 2 << 1 << 3;
QTest::newRow("4x4 bottom intersection")
<< 4 << 4
<< 0 << 2 << 1 << 3
<< 0 << 0
<< 0 << 2 << 0 << 3;
QTest::newRow("4x4 middle intersection")
<< 4 << 4
<< 0 << 2 << 2 << 3
<< 1 << 1
<< 1 << 2 << 1 << 3;
QTest::newRow("4x4 full inclusion")
<< 4 << 4
<< 0 << 2 << 1 << 3
<< 0 << 1
<< 0 << 2 << 1 << 3;
}
class QTBUG48402_helper : public QObject
{
Q_OBJECT
public:
QModelIndex tl;
QModelIndex br;
public slots:
void changed(const QItemSelection &, const QItemSelection &deselected)
{
tl = deselected.first().topLeft();
br = deselected.first().bottomRight();
}
};
void tst_QItemSelectionModel::QTBUG48402()
{
QFETCH(int, rows);
QFETCH(int, columns);
QFETCH(int, selectTop);
QFETCH(int, selectLeft);
QFETCH(int, selectBottom);
QFETCH(int, selectRight);
QFETCH(int, removeTop);
QFETCH(int, removeBottom);
QFETCH(int, deselectTop);
QFETCH(int, deselectLeft);
QFETCH(int, deselectBottom);
QFETCH(int, deselectRight);
MyStandardItemModel model(rows, columns);
QItemSelectionModel selections(&model);
QModelIndex stl = model.index(selectTop, selectLeft);
QModelIndex sbr = model.index(selectBottom, selectRight);
QModelIndex dtl = model.index(deselectTop, deselectLeft);
QModelIndex dbr = model.index(deselectBottom, deselectRight);
selections.select(QItemSelection(stl, sbr), QItemSelectionModel::ClearAndSelect);
QTBUG48402_helper helper;
helper.connect(&selections, &QItemSelectionModel::selectionChanged, &helper, &QTBUG48402_helper::changed);
QVERIFY(selections.isSelected(stl));
QVERIFY(selections.isSelected(sbr));
QVERIFY(selections.hasSelection());
model.removeRows(removeTop, removeBottom - removeTop + 1);
QCOMPARE(QItemSelectionRange(helper.tl, helper.br), QItemSelectionRange(dtl, dbr));
QT_TEST_EQUALITY_OPS(QItemSelectionRange(helper.tl, helper.br), QItemSelectionRange(dtl, dbr), true);
QT_TEST_EQUALITY_OPS(QItemSelectionRange(), QItemSelectionRange(), true);
QT_TEST_EQUALITY_OPS(QItemSelectionRange(helper.tl, helper.br), QItemSelectionRange(), false);
}
void tst_QItemSelectionModel::QTBUG58851_data()
{
using IntPair = std::pair<int, int>;
using IntPairList = QList<IntPair>;
using IntPairPair = std::pair<IntPair, IntPair>;
using IntPairPairList = QList<IntPairPair>;
QTest::addColumn<IntPairPairList>("rangesToSelect");
QTest::addColumn<IntPairList>("expectedSelectedIndexesPairs");
QTest::newRow("Single index in > 0 column")
<< (IntPairPairList() << IntPairPair(IntPair(0, 1), IntPair(0, 1)))
<< (IntPairList() << IntPair(0, 1));
QTest::newRow("Rectangle in > 0 column")
<< (IntPairPairList() << IntPairPair(IntPair(0, 1), IntPair(1, 2)))
<< (IntPairList() << IntPair(0, 1) << IntPair(0, 2) << IntPair(1, 1) << IntPair(1, 2));
QTest::newRow("Diagonal in > 0 column")
<< (IntPairPairList()
<< IntPairPair(IntPair(0, 1), IntPair(0, 1))
<< IntPairPair(IntPair(1, 2), IntPair(1, 2))
<< IntPairPair(IntPair(2, 3), IntPair(2, 3)))
<< (IntPairList()
<< IntPair(0, 1)
<< IntPair(1, 2)
<< IntPair(2, 3));
}
#if QT_CONFIG(proxymodel)
void tst_QItemSelectionModel::QTBUG58851()
{
using IntPair = std::pair<int, int>;
using IntPairList = QList<IntPair>;
using IntPairPair = std::pair<IntPair, IntPair>;
using IntPairPairList = QList<IntPairPair>;
QFETCH(IntPairPairList, rangesToSelect);
QFETCH(IntPairList, expectedSelectedIndexesPairs);
QStandardItemModel model(4, 4);
for (int row = 0; row < model.rowCount(); ++row) {
for (int column = 0; column < model.columnCount(); ++column) {
QStandardItem *item = new QStandardItem(QString("%0%1").arg(row).arg(column));
model.setItem(row, column, item);
}
}
QSortFilterProxyModel proxy;
proxy.setSourceModel(&model);
proxy.setSortRole(Qt::DisplayRole);
std::vector<QPersistentModelIndex> expectedSelectedIndexes;
for (const IntPair &index : expectedSelectedIndexesPairs)
expectedSelectedIndexes.emplace_back(proxy.index(index.first, index.second));
QItemSelectionModel selections(&proxy);
for (const IntPairPair &range : rangesToSelect) {
const IntPair &tl = range.first;
const IntPair &br = range.second;
selections.select(QItemSelection(proxy.index(tl.first, tl.second),
proxy.index(br.first, br.second)),
QItemSelectionModel::Select);
}
for (const QPersistentModelIndex &i : expectedSelectedIndexes) {
QVERIFY(selections.isSelected(i));
}
proxy.sort(1, Qt::DescendingOrder);
QCOMPARE(selections.selectedIndexes().size(), (int)expectedSelectedIndexes.size());
for (const QPersistentModelIndex &i : expectedSelectedIndexes) {
QVERIFY(selections.isSelected(i));
}
}
#endif
void tst_QItemSelectionModel::QTBUG18001_data()
{
using IntPair = std::pair<int, int>;
using IntPairList = QList<IntPair>;
using IntList = QList<int>;
using BoolList = QList<bool>;
QTest::addColumn<IntPairList>("indexesToSelect");
QTest::addColumn<IntList>("selectionCommands");
QTest::addColumn<BoolList>("expectedSelectedRows");
QTest::addColumn<BoolList>("expectedSelectedColums");
int colSelect = QItemSelectionModel::Select | QItemSelectionModel::Columns;
int rowSelect = QItemSelectionModel::Select | QItemSelectionModel::Rows;
QTest::newRow("Select column 1")
<< IntPairList { {0, 1} }
<< IntList{ colSelect }
<< BoolList{ false, false, false, false, false }
<< BoolList{ false, true, false, false, false };
QTest::newRow("Select row 1")
<< IntPairList { {1, 0} }
<< IntList{ rowSelect }
<< BoolList{ false, true, false, false, false }
<< BoolList{ false, false, false, false, false };
QTest::newRow("Select column 1+2, row 1+2")
<< IntPairList { {0, 1}, {0, 2}, {1, 0}, {2, 0} }
<< IntList{ colSelect, colSelect, rowSelect, rowSelect }
<< BoolList{ false, true, true, false, false }
<< BoolList{ false, true, true, false, false };
QTest::newRow("Select row 1+2, col 1+2")
<< IntPairList { {1, 0}, {2, 0}, {0, 1}, {0, 2} }
<< IntList{ rowSelect, rowSelect, colSelect, colSelect }
<< BoolList{ false, true, true, false, false }
<< BoolList{ false, true, true, false, false };
}
void tst_QItemSelectionModel::QTBUG18001()
{
using IntPair = std::pair<int, int>;
using IntPairList = QList<IntPair>;
using IntList = QList<int>;
using BoolList = QList<bool>;
QFETCH(IntPairList, indexesToSelect);
QFETCH(IntList, selectionCommands);
QFETCH(BoolList, expectedSelectedRows);
QFETCH(BoolList, expectedSelectedColums);
QStandardItemModel model(5, 5);
for (int row = 0; row < model.rowCount(); ++row) {
for (int column = 0; column < model.columnCount(); ++column) {
QStandardItem *item = new QStandardItem(QString("%0x%1").arg(row).arg(column));
model.setItem(row, column, item);
const bool oddRow = row % 2;
const bool oddCol = column % 2;
if (oddRow == oddCol)
item->setSelectable(false);
}
}
QItemSelectionModel selectionModel(&model);
for (int i = 0; i < indexesToSelect.size(); ++i) {
QModelIndex idx = model.index( indexesToSelect.at(i).first, indexesToSelect.at(i).second );
selectionModel.select(idx, QItemSelectionModel::SelectionFlag(selectionCommands.at(i)));
}
for (int i = 0; i < expectedSelectedRows.size(); ++i) {
const bool expected = expectedSelectedRows.at(i);
const bool actual = selectionModel.isRowSelected(i, QModelIndex());
QByteArray description = QByteArray("Row ") + QByteArray::number(i)
+ " Expected " + QByteArray::number(expected)
+ " Actual " + QByteArray::number(actual);
QVERIFY2(expected == actual, description.data());
}
for (int i = 0; i < expectedSelectedColums.size(); ++i) {
const bool expected = expectedSelectedColums.at(i);
const bool actual = selectionModel.isColumnSelected(i, QModelIndex());
QByteArray description = QByteArray("Col ") + QByteArray::number(i)
+ " Expected " + QByteArray::number(expected)
+ " Actual " + QByteArray::number(actual);
QVERIFY2(expected == actual, description.data());
}
}
void tst_QItemSelectionModel::QTBUG93305()
{
// make sure the model is sane (5x5)
QCOMPARE(model->rowCount(QModelIndex()), 5);
QCOMPARE(model->columnCount(QModelIndex()), 5);
QSignalSpy spy(selection, &QItemSelectionModel::selectionChanged);
// select in row 1
QModelIndex index = model->index(1, 0, QModelIndex());
selection->select(index, QItemSelectionModel::ClearAndSelect);
QVERIFY(selection->hasSelection());
QCOMPARE(spy.size(), 1);
// removing row 0 does not change which cells are selected, but it
// does change the row number of the selected cells. Thus it changes
// what selectedIndexes() returns.
// The property selectedIndexes() has selectionChanged() as its
// NOTIFY signal, so selectionChanged() should be emitted.
// delete row 0
model->removeRows(0, 1, QModelIndex());
QVERIFY(selection->hasSelection());
QCOMPARE(spy.size(), 2);
// inserting a row before the first row again does not change which cells
// are selected, but does change the row number of the selected cells.
// This changes what selectedIndexes() returns and should thus trigger
// a selectionChanged() signal
// insert row 0 again
model->insertRows(0, 1, QModelIndex());
QVERIFY(selection->hasSelection());
QCOMPARE(spy.size(), 3);
// test for inserting multiple (6) rows
model->insertRows(0, 6, QModelIndex());
QVERIFY(selection->hasSelection());
QCOMPARE(spy.size(), 4);
}
static void (*oldMessageHandler)(QtMsgType, const QMessageLogContext&, const QString&);
static bool signalError = false;
// detect disconnect warning:
// qt.core.qobject.connect: QObject::disconnect: No such signal
void tst_QItemSelectionModel::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
Q_ASSERT(oldMessageHandler);
if (type == QtWarningMsg
&& QString(context.category) == "qt.core.qobject.connect"
&& msg.contains("No such")) {
signalError = true;
}
return oldMessageHandler(type, context, msg);
}
void tst_QItemSelectionModel::testSignalsDisconnection()
{
oldMessageHandler = qInstallMessageHandler(messageHandler);
auto resetMessageHandler = qScopeGuard([] { qInstallMessageHandler(oldMessageHandler); });
auto *newModel = new QStandardItemModel(model);
selection->setModel(newModel);
QSignalSpy spy(newModel, &QObject::destroyed);
delete newModel;
QTRY_COMPARE(spy.count(), 1);
qDebug() << spy;
selection->setModel(nullptr);
QVERIFY(!signalError);
}
void tst_QItemSelectionModel::destroyModel()
{
auto itemModel = std::make_unique<QStandardItemModel>(5, 5);
auto selectionModel = std::make_unique<QItemSelectionModel>();
selectionModel->setModel(itemModel.get());
selectionModel->select(itemModel->index(0, 0), QItemSelectionModel::Select);
QVERIFY(!selectionModel->selection().isEmpty());
selectionModel->setCurrentIndex(itemModel->index(1, 0), QItemSelectionModel::Select);
QVERIFY(selectionModel->currentIndex().isValid());
QTest::failOnWarning();
itemModel.reset();
QVERIFY(!selectionModel->currentIndex().isValid());
QVERIFY(selectionModel->selection().isEmpty());
}
QTEST_MAIN(tst_QItemSelectionModel)
#include "tst_qitemselectionmodel.moc"