qt6windows7/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp

1912 lines
65 KiB
C++
Raw Normal View History

2023-10-30 06:33:08 +08:00
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QHeaderView>
#include <QLineEdit>
#include <QMimeData>
#include <QSignalSpy>
#include <QTableWidget>
#include <QTest>
class QObjectTableItem : public QObject, public QTableWidgetItem
{
Q_OBJECT
};
class tst_QTableWidget : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
private slots:
void initTestCase();
void init();
void getSetCheck();
void selectionRange();
void clear();
void clearContents();
void rowCount();
void columnCount();
void itemAssignment();
void item_data();
void item();
void takeItem_data();
void takeItem();
void selectedItems_data();
void selectedItems();
void selectedSpannedCells_data();
void selectedSpannedCells();
void removeRow_data();
void removeRow();
void removeColumn_data();
void removeColumn();
void insertRow_data();
void insertRow();
void insertColumn_data();
void insertColumn();
void itemStreaming_data();
void itemStreaming();
void itemOwnership();
void sortItems_data();
void sortItems();
void setItemWithSorting_data();
void setItemWithSorting();
void itemData();
void setItemData();
void cellWidget();
void cellWidgetGeometry();
void sizeHint_data();
void sizeHint();
void task231094();
void task219380_removeLastRow();
void task262056_sortDuplicate();
void itemWithHeaderItems();
void checkHeaderItemFlagsConflict();
void mimeData();
void selectedRowAfterSorting();
void search();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void clearItemData();
#endif
void createPersistentOnLayoutAboutToBeChanged();
void createPersistentOnLayoutAboutToBeChangedAutoSort();
private:
std::unique_ptr<QTableWidget> testWidget;
};
using IntPair = QPair<int, int>;
using IntList = QList<int>;
using IntIntList = QList<IntPair>;
Q_DECLARE_METATYPE(QTableWidgetSelectionRange)
// Testing get/set functions
void tst_QTableWidget::getSetCheck()
{
QTableWidget obj1;
// int QTableWidget::rowCount()
// void QTableWidget::setRowCount(int)
obj1.setRowCount(0);
QCOMPARE(0, obj1.rowCount());
obj1.setRowCount(INT_MIN);
QCOMPARE(0, obj1.rowCount()); // Row count can never be negative
// obj1.setRowCount(INT_MAX);
// QCOMPARE(INT_MAX, obj1.rowCount());
obj1.setRowCount(100);
QCOMPARE(100, obj1.rowCount());
// int QTableWidget::columnCount()
// void QTableWidget::setColumnCount(int)
obj1.setColumnCount(0);
QCOMPARE(0, obj1.columnCount());
obj1.setColumnCount(INT_MIN);
QCOMPARE(0, obj1.columnCount()); // Column count can never be negative
obj1.setColumnCount(1000);
QCOMPARE(1000, obj1.columnCount());
// obj1.setColumnCount(INT_MAX);
// QCOMPARE(INT_MAX, obj1.columnCount());
// QTableWidgetItem * QTableWidget::currentItem()
// void QTableWidget::setCurrentItem(QTableWidgetItem *)
QTableWidgetItem *var3 = new QTableWidgetItem("0,0");
obj1.setItem(0, 0, var3);
obj1.setItem(1, 1, new QTableWidgetItem("1,1"));
obj1.setItem(2, 2, new QTableWidgetItem("2,2"));
obj1.setItem(3, 3, new QTableWidgetItem("3,3"));
obj1.setCurrentItem(var3);
QCOMPARE(var3, obj1.currentItem());
obj1.setCurrentItem(nullptr);
QCOMPARE(obj1.currentItem(), nullptr);
obj1.setItem(0, 0, nullptr);
QCOMPARE(obj1.item(0, 0), nullptr);
// const QTableWidgetItem * QTableWidget::itemPrototype()
// void QTableWidget::setItemPrototype(const QTableWidgetItem *)
const QTableWidgetItem *var4 = new QTableWidgetItem;
obj1.setItemPrototype(var4);
QCOMPARE(var4, obj1.itemPrototype());
obj1.setItemPrototype(nullptr);
QCOMPARE(obj1.itemPrototype(), nullptr);
}
void tst_QTableWidget::selectionRange()
{
QTableWidgetSelectionRange defaultSelection;
QTableWidgetSelectionRange selection(1, 2, 3, 4);
QTableWidgetSelectionRange copy(selection);
QCOMPARE(copy, selection);
QVERIFY(copy != defaultSelection);
defaultSelection = copy;
QCOMPARE(defaultSelection, copy);
}
void tst_QTableWidget::initTestCase()
{
testWidget.reset(new QTableWidget);
testWidget->show();
QApplication::setKeyboardInputInterval(100);
}
void tst_QTableWidget::init()
{
testWidget->clear();
testWidget->setRowCount(5);
testWidget->setColumnCount(5);
for (int row = 0; row < testWidget->rowCount(); ++row)
testWidget->showRow(row);
for (int column = 0; column < testWidget->columnCount(); ++column)
testWidget->showColumn(column);
}
void tst_QTableWidget::clearContents()
{
QTableWidgetItem *item = new QTableWidgetItem("test");
testWidget->setHorizontalHeaderItem(0, item);
QCOMPARE(testWidget->horizontalHeaderItem(0), item);
testWidget->clearContents();
QCOMPARE(testWidget->horizontalHeaderItem(0), item);
}
void tst_QTableWidget::clear()
{
QTableWidgetItem *item = new QTableWidgetItem("foo");
testWidget->setItem(0, 0, item);
item->setSelected(true);
QVERIFY(testWidget->item(0, 0) == item);
QVERIFY(item->isSelected());
QPointer<QObjectTableItem> bla = new QObjectTableItem();
testWidget->setItem(1, 1, bla);
testWidget->clear();
QVERIFY(bla.isNull());
QVERIFY(!testWidget->item(0,0));
QVERIFY(!testWidget->selectedRanges().size());
QVERIFY(!testWidget->selectedItems().size());
}
void tst_QTableWidget::rowCount()
{
int rowCountBefore = 5;
int rowCountAfter = 10;
int rowCount = testWidget->rowCount();
QCOMPARE(rowCount, rowCountBefore);
testWidget->setRowCount(rowCountAfter);
rowCount = testWidget->rowCount();
QCOMPARE(rowCount, rowCountAfter);
QPersistentModelIndex index(testWidget->model()->index(rowCountAfter - 1, 0,
testWidget->rootIndex()));
QCOMPARE(index.row(), rowCountAfter - 1);
QCOMPARE(index.column(), 0);
QVERIFY(index.isValid());
testWidget->setRowCount(rowCountBefore);
QCOMPARE(index.row(), -1);
QCOMPARE(index.column(), -1);
QVERIFY(!index.isValid());
rowCountBefore = testWidget->rowCount();
testWidget->setRowCount(-1);
QCOMPARE(testWidget->rowCount(), rowCountBefore);
}
void tst_QTableWidget::columnCount()
{
int columnCountBefore = 5;
int columnCountAfter = 10;
int columnCount = testWidget->columnCount();
QCOMPARE(columnCount, columnCountBefore);
testWidget->setColumnCount(columnCountAfter);
columnCount = testWidget->columnCount();
QCOMPARE(columnCount, columnCountAfter);
QPersistentModelIndex index(testWidget->model()->index(0, columnCountAfter - 1,
testWidget->rootIndex()));
QCOMPARE(index.row(), 0);
QCOMPARE(index.column(), columnCountAfter - 1);
QVERIFY(index.isValid());
testWidget->setColumnCount(columnCountBefore);
QCOMPARE(index.row(), -1);
QCOMPARE(index.column(), -1);
QVERIFY(!index.isValid());
columnCountBefore = testWidget->columnCount();
testWidget->setColumnCount(-1);
QCOMPARE(testWidget->columnCount(), columnCountBefore);
}
void tst_QTableWidget::itemAssignment()
{
QTableWidgetItem itemInWidget("inWidget");
testWidget->setItem(0, 0, &itemInWidget);
itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsUserTristate);
QTableWidgetItem itemOutsideWidget("outsideWidget");
QVERIFY(itemInWidget.tableWidget());
QCOMPARE(itemInWidget.text(), QString("inWidget"));
QVERIFY(itemInWidget.flags() & Qt::ItemIsUserTristate);
QVERIFY(!itemOutsideWidget.tableWidget());
QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget"));
QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsUserTristate));
itemOutsideWidget = itemInWidget;
QVERIFY(!itemOutsideWidget.tableWidget());
QCOMPARE(itemOutsideWidget.text(), QString("inWidget"));
QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsUserTristate);
}
void tst_QTableWidget::item_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("row");
QTest::addColumn<int>("column");
QTest::addColumn<bool>("expectItem");
QTest::newRow("0x0 take [0,0]") << 0 << 0 << 0 << 0 << false;
QTest::newRow("0x0 take [4,4]") << 0 << 0 << 4 << 4 << false;
QTest::newRow("4x4 take [0,0]") << 4 << 4 << 0 << 0 << true;
QTest::newRow("4x4 take [4,4]") << 4 << 4 << 4 << 4 << false;
QTest::newRow("4x4 take [2,2]") << 4 << 4 << 2 << 2 << true;
}
void tst_QTableWidget::item()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, row);
QFETCH(int, column);
QFETCH(bool, expectItem);
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c)));
}
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c));
}
QTableWidgetItem *item = testWidget->item(row, column);
QCOMPARE(!!item, expectItem);
if (expectItem)
QCOMPARE(item->text(), QString::number(row * column + column));
}
void tst_QTableWidget::takeItem_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("row");
QTest::addColumn<int>("column");
QTest::addColumn<bool>("expectItem");
QTest::newRow("0x0 take [0,0]") << 0 << 0 << 0 << 0 << false;
QTest::newRow("0x0 take [4,4]") << 0 << 0 << 4 << 4 << false;
QTest::newRow("4x4 take [0,0]") << 4 << 4 << 0 << 0 << true;
QTest::newRow("4x4 take [4,4]") << 4 << 4 << 4 << 4 << false;
QTest::newRow("4x4 take [2,2]") << 4 << 4 << 2 << 2 << true;
}
void tst_QTableWidget::takeItem()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, row);
QFETCH(int, column);
QFETCH(bool, expectItem);
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c)));
}
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c));
}
QSignalSpy spy(testWidget.get(), &QTableWidget::cellChanged);
QTableWidgetItem *item = testWidget->takeItem(row, column);
QCOMPARE(!!item, expectItem);
if (expectItem) {
QCOMPARE(item->text(), QString::number(row * column + column));
delete item;
QTRY_COMPARE(spy.size(), 1);
const QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(arguments.size(), 2);
QCOMPARE(arguments.at(0).toInt(), row);
QCOMPARE(arguments.at(1).toInt(), column);
}
QVERIFY(!testWidget->takeItem(row, column));
}
void tst_QTableWidget::selectedItems_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<IntIntList>("createItems");
QTest::addColumn<IntList>("hiddenRows");
QTest::addColumn<IntList>("hiddenColumns");
QTest::addColumn<QTableWidgetSelectionRange>("selectionRange");
QTest::addColumn<IntIntList>("expectedItems");
QTest::newRow("3x3 empty cells, no hidden rows/columns, none selected")
<< 3 << 3
<< IntIntList()
<< IntList()
<< IntList()
<< QTableWidgetSelectionRange()
<< IntIntList();
QTest::newRow("3x3 empty cells,no hidden rows/columnms, all selected")
<< 3 << 3
<< IntIntList()
<< IntList()
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< IntIntList();
QTest::newRow("3x3 (1,1) exists, no hidden rows/columnms, all selected")
<< 3 << 3
<< (IntIntList() << IntPair(1,1))
<< IntList()
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< (IntIntList() << IntPair(1,1));
QTest::newRow("3x3 (1,1) exists, row 1 hidden, all selected")
<< 3 << 3
<< (IntIntList() << IntPair(1,1))
<< (IntList() << 1)
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< IntIntList();
QTest::newRow("3x3 (1,1) exists, column 1 hidden, all selected")
<< 3 << 3
<< (IntIntList() << IntPair(1,1))
<< IntList()
<< (IntList() << 1)
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< IntIntList();
QTest::newRow("3x3 all exists, no hidden rows/columns, all selected")
<< 3 << 3
<< (IntIntList()
<< IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
<< IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
<< IntPair(2,0) << IntPair(2,1) << IntPair(2,2))
<< IntList()
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< (IntIntList()
<< IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
<< IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
<< IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
QTest::newRow("3x3 all exists, row 1 hidden, all selected")
<< 3 << 3
<< (IntIntList()
<< IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
<< IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
<< IntPair(2,0) << IntPair(2,1) << IntPair(2,2))
<< (IntList() << 1)
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< (IntIntList()
<< IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
<< IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
QTest::newRow("3x3 all exists, column 1 hidden, all selected")
<< 3 << 3
<< (IntIntList()
<< IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
<< IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
<< IntPair(2,0) << IntPair(2,1) << IntPair(2,2))
<< IntList()
<< (IntList() << 1)
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< (IntIntList()
<< IntPair(0,0) << IntPair(0,2)
<< IntPair(1,0) << IntPair(1,2)
<< IntPair(2,0) << IntPair(2,2));
QTest::newRow("3x3 none exists, no hidden rows/columns, all selected")
<< 3 << 3
<< IntIntList()
<< IntList()
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< IntIntList();
// << (IntIntList()
// << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
// << IntPair(1,0) << IntPair(1,1) << IntPair(1,2)
// << IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
QTest::newRow("3x3 none exists, row 1 hidden, all selected, filling empty cells")
<< 3 << 3
<< IntIntList()
<< (IntList() << 1)
<< IntList()
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< IntIntList();
// << (IntIntList()
// << IntPair(0,0) << IntPair(0,1) << IntPair(0,2)
// << IntPair(2,0) << IntPair(2,1) << IntPair(2,2));
QTest::newRow("3x3 none exists, column 1 hidden, all selected")
<< 3 << 3
<< IntIntList()
<< IntList()
<< (IntList() << 1)
<< QTableWidgetSelectionRange(0, 0, 2, 2)
<< IntIntList();
// << (IntIntList()
// << IntPair(0,0) << IntPair(0,2)
// << IntPair(1,0) << IntPair(1,2)
// << IntPair(2,0) << IntPair(2,2));
}
void tst_QTableWidget::selectedItems()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(const IntIntList, createItems);
QFETCH(const IntList, hiddenRows);
QFETCH(const IntList, hiddenColumns);
QFETCH(const QTableWidgetSelectionRange, selectionRange);
QFETCH(const IntIntList, expectedItems);
// set dimensions and test they are ok
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
// create and set items
for (const auto &intPair : createItems) {
testWidget->setItem(intPair.first, intPair.second,
new QTableWidgetItem(QString("Item %1 %2")
.arg(intPair.first).arg(intPair.second)));
}
// hide rows/columns
for (int row : hiddenRows)
testWidget->setRowHidden(row, true);
for (int column : hiddenColumns)
testWidget->setColumnHidden(column, true);
// make sure we don't have any previous selections hanging around
QVERIFY(!testWidget->selectedRanges().size());
QVERIFY(!testWidget->selectedItems().size());
// select range and check that it is set correctly
testWidget->setRangeSelected(selectionRange, true);
if (selectionRange.topRow() >= 0) {
QCOMPARE(testWidget->selectedRanges().size(), 1);
QCOMPARE(testWidget->selectedRanges().at(0).topRow(), selectionRange.topRow());
QCOMPARE(testWidget->selectedRanges().at(0).bottomRow(), selectionRange.bottomRow());
QCOMPARE(testWidget->selectedRanges().at(0).leftColumn(), selectionRange.leftColumn());
QCOMPARE(testWidget->selectedRanges().at(0).rightColumn(), selectionRange.rightColumn());
} else {
QCOMPARE(testWidget->selectedRanges().size(), 0);
}
// check that the correct number of items and the expected items are there
const QList<QTableWidgetItem *> selectedItems = testWidget->selectedItems();
QCOMPARE(selectedItems.size(), expectedItems.size());
for (const auto &intPair : expectedItems)
QVERIFY(selectedItems.contains(testWidget->item(intPair.first, intPair.second)));
// check that setItemSelected agrees with selectedItems
for (int row = 0; row < testWidget->rowCount(); ++row) {
if (hiddenRows.contains(row))
continue;
for (int column = 0; column < testWidget->columnCount(); ++column) {
if (hiddenColumns.contains(column))
continue;
QTableWidgetItem *item = testWidget->item(row, column);
if (item && item->isSelected())
QVERIFY(selectedItems.contains(item));
}
}
}
void tst_QTableWidget::selectedSpannedCells_data()
{
QTest::addColumn<QRect>("spannedCells"); // in cells, not pixels
QTest::addColumn<QPoint>("selectionStartCell");
QTest::addColumn<QPoint>("selectionEndCell");
QTest::addColumn<int>("expectedSelectionRangeCount");
QTest::addColumn<QTableWidgetSelectionRange>("expectedFirstSelectionRange");
QTest::newRow("merge 2 cells in column, select adjacent left")
<< QRect(1, 2, 1, 2) << QPoint(0, 1) << QPoint(0, 3)
<< 1 << QTableWidgetSelectionRange(1, 0, 3, 0);
QTest::newRow("merge 2 cells in column, select those and one more")
<< QRect(1, 2, 1, 2) << QPoint(1, 1) << QPoint(1, 3)
<< 3 << QTableWidgetSelectionRange(1, 1, 1, 1);
QTest::newRow("merge 2 cells in column, select rows above")
<< QRect(1, 2, 1, 2) << QPoint(0, 0) << QPoint(3, 1)
<< 1 << QTableWidgetSelectionRange(0, 0, 1, 3);
QTest::newRow("merge 4 cells in column, select adjacent right")
<< QRect(1, 0, 1, 4) << QPoint(2, 0) << QPoint(3, 3)
<< 1 << QTableWidgetSelectionRange(0, 2, 3, 3);
QTest::newRow("merge 3 cells in row, select those and one more")
<< QRect(0, 1, 3, 1) << QPoint(0, 1) << QPoint(3, 1)
<< 4 << QTableWidgetSelectionRange(1, 0, 1, 0);
QTest::newRow("merge 3 cells in row, select adjacent to right")
<< QRect(0, 1, 3, 1) << QPoint(3, 0) << QPoint(3, 2)
<< 1 << QTableWidgetSelectionRange(0, 3, 2, 3);
QTest::newRow("merge 3 cells in row, select adjacent above")
<< QRect(0, 2, 3, 2) << QPoint(0, 1) << QPoint(2, 1)
<< 1 << QTableWidgetSelectionRange(1, 0, 1, 2);
}
void tst_QTableWidget::selectedSpannedCells() // QTBUG-255
{
QFETCH(QRect, spannedCells);
QFETCH(QPoint, selectionStartCell);
QFETCH(QPoint, selectionEndCell);
QFETCH(int, expectedSelectionRangeCount);
QFETCH(const QTableWidgetSelectionRange, expectedFirstSelectionRange);
QTableWidget testWidget(4, 4);
testWidget.resize(600, 200);
testWidget.show();
// create and set items
for (int c = 0; c < 4; ++c) {
for (int r = 0; r < 4; ++r)
testWidget.setItem(r, c, new QTableWidgetItem(QString("Item %1 %2").arg(c).arg(r)));
}
// merge some cells
testWidget.setSpan(spannedCells.top(), spannedCells.left(), spannedCells.height(), spannedCells.width());
// click one cell and shift-click another, to select a range
QTest::mouseClick(testWidget.viewport(), Qt::LeftButton, Qt::NoModifier,
testWidget.visualRect(testWidget.model()->index(selectionStartCell.y(), selectionStartCell.x())).center());
QTest::mouseClick(testWidget.viewport(), Qt::LeftButton, Qt::ShiftModifier,
testWidget.visualRect(testWidget.model()->index(selectionEndCell.y(), selectionEndCell.x())).center());
auto ranges = testWidget.selectedRanges();
QCOMPARE(ranges.size(), expectedSelectionRangeCount);
QCOMPARE(ranges.first(), expectedFirstSelectionRange);
}
void tst_QTableWidget::removeRow_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("row");
QTest::addColumn<int>("expectedRowCount");
QTest::addColumn<int>("expectedColumnCount");
QTest::newRow("Empty") << 0 << 0 << 0 << 0 << 0;
QTest::newRow("1x1:0") << 1 << 1 << 0 << 0 << 1;
QTest::newRow("3x3:0") << 3 << 3 << 0 << 2 << 3;
QTest::newRow("3x3:1") << 3 << 3 << 1 << 2 << 3;
QTest::newRow("3x3:2") << 3 << 3 << 2 << 2 << 3;
}
void tst_QTableWidget::removeRow()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, row);
QFETCH(int, expectedRowCount);
QFETCH(int, expectedColumnCount);
// set dimensions and test they are ok
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
// fill table with items
for (int r = 0; r < rowCount; ++r) {
const QString rRow = QString::number(r) + QLatin1Char(':');
for (int c = 0; c < columnCount; ++c) {
testWidget->setItem(r, c,
new QTableWidgetItem(rRow + QString::number(c)));
}
}
// remove and compare the results
testWidget->removeRow(row);
QCOMPARE(testWidget->rowCount(), expectedRowCount);
QCOMPARE(testWidget->columnCount(), expectedColumnCount);
// check if the correct items were removed
for (int r = 0; r < expectedRowCount; ++r) {
const QString rRow = QString::number(r < row ? r : r + 1) +
QLatin1Char(':');
for (int c = 0; c < expectedColumnCount; ++c) {
if (r < row)
QCOMPARE(testWidget->item(r, c)->text(),
rRow + QString::number(c));
else
QCOMPARE(testWidget->item(r, c)->text(),
rRow + QString::number(c));
}
}
}
void tst_QTableWidget::removeColumn_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("column");
QTest::addColumn<int>("expectedRowCount");
QTest::addColumn<int>("expectedColumnCount");
QTest::newRow("Empty") << 0 << 0 << 0 << 0 << 0;
QTest::newRow("1x1:0") << 1 << 1 << 0 << 1 << 0;
QTest::newRow("3x3:0") << 3 << 3 << 0 << 3 << 2;
QTest::newRow("3x3:1") << 3 << 3 << 1 << 3 << 2;
QTest::newRow("3x3:2") << 3 << 3 << 2 << 3 << 2;
}
void tst_QTableWidget::removeColumn()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, column);
QFETCH(int, expectedRowCount);
QFETCH(int, expectedColumnCount);
// set dimensions and test they are ok
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
// fill table with items
for (int r = 0; r < rowCount; ++r) {
const QString rStr = QString::number(r) + QLatin1Char(':');
for (int c = 0; c < columnCount; ++c) {
testWidget->setItem(r, c,
new QTableWidgetItem(
rStr + QString::number(c)));
}
}
// remove and compare the results
testWidget->removeColumn(column);
QCOMPARE(testWidget->rowCount(), expectedRowCount);
QCOMPARE(testWidget->columnCount(), expectedColumnCount);
// check if the correct items were removed
for (int r = 0; r < expectedRowCount; ++r) {
const QString rStr = QString::number(r) + QLatin1Char(':');
for (int c = 0; c < expectedColumnCount; ++c) {
if (c < column)
QCOMPARE(testWidget->item(r, c)->text(),
rStr + QString::number(c));
else
QCOMPARE(testWidget->item(r, c)->text(),
rStr + QString::number(c + 1));
}
}
}
void tst_QTableWidget::insertRow_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("row");
QTest::addColumn<int>("expectedRowCount");
QTest::addColumn<int>("expectedColumnCount");
QTest::newRow("Empty") << 0 << 0 << 0 << 1 << 0;
QTest::newRow("1x1:0") << 1 << 1 << 0 << 2 << 1;
QTest::newRow("3x3:-1") << 3 << 3 << -1 << 3 << 3;
QTest::newRow("3x3:0") << 3 << 3 << 0 << 4 << 3;
QTest::newRow("3x3:1") << 3 << 3 << 1 << 4 << 3;
QTest::newRow("3x3:2") << 3 << 3 << 2 << 4 << 3;
QTest::newRow("3x3:3") << 3 << 3 << 3 << 4 << 3;
QTest::newRow("3x3:4") << 3 << 3 << 4 << 3 << 3;
}
void tst_QTableWidget::insertRow()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, row);
QFETCH(int, expectedRowCount);
QFETCH(int, expectedColumnCount);
// set dimensions and test they are ok
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
// insert and compare the results
testWidget->insertRow(row);
QCOMPARE(testWidget->rowCount(), expectedRowCount);
QCOMPARE(testWidget->columnCount(), expectedColumnCount);
}
void tst_QTableWidget::insertColumn_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("column");
QTest::addColumn<int>("expectedRowCount");
QTest::addColumn<int>("expectedColumnCount");
QTest::newRow("Empty") << 0 << 0 << 0 << 0 << 1;
QTest::newRow("1x1:0") << 1 << 1 << 0 << 1 << 2;
QTest::newRow("3x3:-1") << 3 << 3 << -1 << 3 << 3;
QTest::newRow("3x3:0") << 3 << 3 << 0 << 3 << 4;
QTest::newRow("3x3:1") << 3 << 3 << 1 << 3 << 4;
QTest::newRow("3x3:2") << 3 << 3 << 2 << 3 << 4;
QTest::newRow("3x3:3") << 3 << 3 << 3 << 3 << 4;
QTest::newRow("3x3:4") << 3 << 3 << 4 << 3 << 3;
}
void tst_QTableWidget::insertColumn()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, column);
QFETCH(int, expectedRowCount);
QFETCH(int, expectedColumnCount);
// set dimensions and test they are ok
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
// insert and compare the results
testWidget->insertColumn(column);
QCOMPARE(testWidget->rowCount(), expectedRowCount);
QCOMPARE(testWidget->columnCount(), expectedColumnCount);
}
void tst_QTableWidget::itemStreaming_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<QString>("toolTip");
QTest::newRow("Data") << "item text" << "tool tip text";
}
void tst_QTableWidget::itemStreaming()
{
QFETCH(QString, text);
QFETCH(QString, toolTip);
QTableWidgetItem item;
QCOMPARE(item.text(), QString());
QCOMPARE(item.toolTip(), QString());
item.setText(text);
item.setToolTip(toolTip);
QCOMPARE(item.text(), text);
QCOMPARE(item.toolTip(), toolTip);
QByteArray buffer;
QDataStream out(&buffer, QIODevice::WriteOnly);
out << item;
QTableWidgetItem item2;
QCOMPARE(item2.text(), QString());
QCOMPARE(item2.toolTip(), QString());
QVERIFY(!buffer.isEmpty());
QDataStream in(&buffer, QIODevice::ReadOnly);
in >> item2;
QCOMPARE(item2.text(), text);
QCOMPARE(item2.toolTip(), toolTip);
}
void tst_QTableWidget::itemOwnership()
{
QPointer<QObjectTableItem> item;
QPointer<QObjectTableItem> headerItem;
//delete from outside
item = new QObjectTableItem();
testWidget->setItem(0, 0, item);
delete item;
QCOMPARE(testWidget->item(0, 0), nullptr);
//delete vertical headeritem from outside
headerItem = new QObjectTableItem();
testWidget->setVerticalHeaderItem(0, headerItem);
delete headerItem;
QCOMPARE(testWidget->verticalHeaderItem(0), nullptr);
//delete horizontal headeritem from outside
headerItem = new QObjectTableItem();
testWidget->setHorizontalHeaderItem(0, headerItem);
delete headerItem;
QCOMPARE(testWidget->horizontalHeaderItem(0), nullptr);
//setItem
item = new QObjectTableItem();
testWidget->setItem(0, 0, item);
testWidget->setItem(0, 0, new QTableWidgetItem());
QVERIFY(item.isNull());
//setHorizontalHeaderItem
headerItem = new QObjectTableItem();
testWidget->setHorizontalHeaderItem(0, headerItem);
testWidget->setHorizontalHeaderItem(0, new QTableWidgetItem());
QVERIFY(headerItem.isNull());
//setVerticalHeaderItem
headerItem = new QObjectTableItem();
testWidget->setVerticalHeaderItem(0, headerItem);
testWidget->setVerticalHeaderItem(0, new QTableWidgetItem());
QVERIFY(headerItem.isNull());
//takeItem
item = new QObjectTableItem();
testWidget->setItem(0, 0, item);
testWidget->takeItem(0, 0);
QVERIFY(!item.isNull());
delete item;
// removeRow
item = new QObjectTableItem();
headerItem = new QObjectTableItem();
testWidget->setItem(0, 0, item);
testWidget->setVerticalHeaderItem(0, headerItem);
testWidget->removeRow(0);
QVERIFY(item.isNull());
QVERIFY(headerItem.isNull());
// removeColumn
item = new QObjectTableItem();
headerItem = new QObjectTableItem();
testWidget->setItem(0, 0, item);
testWidget->setHorizontalHeaderItem(0, headerItem);
testWidget->removeColumn(0);
QVERIFY(item.isNull());
QVERIFY(headerItem.isNull());
// clear
item = new QObjectTableItem();
testWidget->setItem(0, 0, item);
testWidget->clear();
QVERIFY(item.isNull());
}
void tst_QTableWidget::sortItems_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<Qt::SortOrder>("sortOrder");
QTest::addColumn<int>("sortColumn");
QTest::addColumn<QStringList>("initial");
QTest::addColumn<QStringList>("expected");
QTest::addColumn<IntList>("rows");
QTest::addColumn<IntList>("initialHidden");
QTest::addColumn<IntList>("expectedHidden");
QTest::newRow("ascending")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "1" << "b" << "7" << "3" << "u")
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "1" << "b" << "7" << "3" << "u"
<< "2" << "c" << "9" << "y" << "8"
<< "3" << "d" << "k" << "o" << "6")
<< (IntList() << 0 << 3 << 2 << 1)
<< IntList()
<< IntList();
QTest::newRow("descending")
<< 4 << 5
<< Qt::DescendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "1" << "b" << "7" << "3" << "u")
<< (QStringList()
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "1" << "b" << "7" << "3" << "u"
<< "0" << "a" << "o" << "8" << "k")
<< (IntList() << 3 << 0 << 1 << 2)
<< IntList()
<< IntList();
QTest::newRow("empty table")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (QStringList()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< IntList()
<< IntList()
<< IntList();
QTest::newRow("half-empty table")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << QString() << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (QStringList()
<< "0" << QString() << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (IntList() << 0 << 2 << 1)
<< IntList()
<< IntList();
QTest::newRow("empty column, should not sort.")
<< 4 << 5
<< Qt::AscendingOrder
<< 3
<< (QStringList()
<< "0" << QString() << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (QStringList()
<< "0" << QString() << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< IntList()
<< IntList()
<< IntList();
QTest::newRow("descending with null cell, the null cell should be placed at the bottom")
<< 4 << 5
<< Qt::DescendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (QStringList()
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "0" << "a" << "o" << "8" << "k"
<< QString() << "b" << "7" << "3" << "u")
<< (IntList() << 2 << 0 << 1)
<< IntList()
<< IntList();
QTest::newRow("ascending with null cell, the null cell should be placed at the bottom")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "2" << "c" << "9" << "y" << "8"
<< "3" << "d" << "k" << "o" << "6"
<< QString() << "b" << "7" << "3" << "u")
<< (IntList() << 0 << 2 << 1)
<< IntList()
<< IntList();
QTest::newRow("ascending with null cells, the null cells should be placed at the bottom")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "3" << "d" << "k" << "o" << "6"
<< "0" << "a" << "o" << "8" << "k"
<< QString() << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< QString() << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (IntList() << 1 << 0)
<< IntList()
<< IntList();
QTest::newRow("ascending... Check a bug in PersistentIndexes")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "3" << "c" << "9" << "y" << "8"
<< "2" << "b" << "7" << "3" << "u"
<< "4" << "d" << "k" << "o" << "6"
<< "1" << "a" << "o" << "8" << "k")
<< (QStringList()
<< "1" << "a" << "o" << "8" << "k"
<< "2" << "b" << "7" << "3" << "u"
<< "3" << "c" << "9" << "y" << "8"
<< "4" << "d" << "k" << "o" << "6")
<< (IntList() << 2 << 1 << 3 << 0)
<< IntList()
<< IntList();
QTest::newRow("ascending with some null cells inbetween")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< QString() << "a" << "o" << "8" << "k"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "d" << "k" << "o" << "6"
<< "1" << "b" << "7" << "3" << "u")
<< (QStringList()
<< "1" << "b" << "7" << "3" << "u"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "a" << "o" << "8" << "k"
<< QString() << "d" << "k" << "o" << "6")
<< (IntList() << 1 << 0)
<< IntList()
<< IntList();
QTest::newRow("ascending hidden")
<< 4 << 5
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "1" << "b" << "7" << "3" << "u")
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "1" << "b" << "7" << "3" << "u"
<< "2" << "c" << "9" << "y" << "8"
<< "3" << "d" << "k" << "o" << "6")
<< (IntList() << 0 << 3 << 2 << 1)
<< (IntList() << 0 << 2)
<< (IntList() << 0 << 2);
QTest::newRow("descending hidden")
<< 4 << 5
<< Qt::DescendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "1" << "b" << "7" << "3" << "u")
<< (QStringList()
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "1" << "b" << "7" << "3" << "u"
<< "0" << "a" << "o" << "8" << "k")
<< (IntList() << 3 << 0 << 1 << 2)
<< (IntList() << 0 << 2)
<< (IntList() << 3 << 1);
}
void tst_QTableWidget::sortItems()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(Qt::SortOrder, sortOrder);
QFETCH(int, sortColumn);
QFETCH(QStringList, initial);
QFETCH(QStringList, expected);
QFETCH(IntList, rows);
QFETCH(IntList, initialHidden);
QFETCH(IntList, expectedHidden);
testWidget->setRowCount(rowCount);
testWidget->setColumnCount(columnCount);
QAbstractItemModel *model = testWidget->model();
QList<QPersistentModelIndex> persistent;
int ti = 0;
for (int r = 0; r < rowCount; ++r) {
for (int c = 0; c < columnCount; ++c) {
QString str = initial.at(ti++);
if (!str.isEmpty()) {
testWidget->setItem(r, c, new QTableWidgetItem(str));
}
}
if (testWidget->item(r, sortColumn))
persistent << model->index(r, sortColumn, QModelIndex());
}
for (int h = 0; h < initialHidden.size(); ++h)
testWidget->hideRow(initialHidden.at(h));
QCOMPARE(testWidget->verticalHeader()->hiddenSectionCount(), initialHidden.size());
testWidget->sortItems(sortColumn, sortOrder);
int te = 0;
for (int i = 0; i < rows.size(); ++i) {
for (int j = 0; j < columnCount; ++j) {
QString value;
QTableWidgetItem *itm = testWidget->item(i, j);
if (itm) {
value = itm->text();
}
QCOMPARE(value, expected.at(te++));
}
QCOMPARE(persistent.at(i).row(), rows.at(i));
//qDebug() << "persistent" << persistent.at(i).row()
// << "expected" << rows.at(i);
}
for (int k = 0; k < expectedHidden.size(); ++k)
QVERIFY(testWidget->isRowHidden(expectedHidden.at(k)));
}
void tst_QTableWidget::setItemWithSorting_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<Qt::SortOrder>("sortOrder");
QTest::addColumn<int>("sortColumn");
QTest::addColumn<QStringList>("initialValues");
QTest::addColumn<int>("row");
QTest::addColumn<int>("column");
QTest::addColumn<QString>("newValue");
QTest::addColumn<QStringList>("expectedValues");
QTest::addColumn<IntList>("expectedRows");
QTest::addColumn<bool>("reorderingExpected");
QTest::newRow("2x1 no change (ascending)")
<< 2 << 1
<< Qt::AscendingOrder << 0
<< (QStringList() << "0" << "1")
<< 1 << 0 << "2"
<< (QStringList() << "0" << "2")
<< (IntList() << 0 << 1)
<< false;
QTest::newRow("2x1 no change (descending)")
<< 2 << 1
<< Qt::DescendingOrder << 0
<< (QStringList() << "1" << "0")
<< 0 << 0 << "2"
<< (QStringList() << "2" << "0")
<< (IntList() << 0 << 1)
<< false;
QTest::newRow("2x1 reorder (ascending)")
<< 2 << 1
<< Qt::AscendingOrder << 0
<< (QStringList() << "0" << "1")
<< 0 << 0 << "2"
<< (QStringList() << "1" << "2")
<< (IntList() << 1 << 0)
<< true;
QTest::newRow("2x1 reorder (descending)")
<< 2 << 1
<< Qt::DescendingOrder << 0
<< (QStringList() << "1" << "0")
<< 1 << 0 << "2"
<< (QStringList() << "2" << "1")
<< (IntList() << 1 << 0)
<< true;
QTest::newRow("2x2 no change (ascending)")
<< 2 << 2
<< Qt::AscendingOrder << 0
<< (QStringList()
<< "0" << "00"
<< "1" << "11")
<< 1 << 0 << "2"
<< (QStringList()
<< "0" << "00"
<< "2" << "11")
<< (IntList() << 0 << 1)
<< false;
QTest::newRow("2x2 reorder (ascending)")
<< 2 << 2
<< Qt::AscendingOrder << 0
<< (QStringList()
<< "0" << "00"
<< "1" << "11")
<< 0 << 0 << "2"
<< (QStringList()
<< "1" << "11"
<< "2" << "00")
<< (IntList() << 1 << 0)
<< true;
QTest::newRow("2x2 reorder (ascending, sortColumn = 1)")
<< 2 << 2
<< Qt::AscendingOrder << 1
<< (QStringList()
<< "00" << "0"
<< "11" << "1")
<< 0 << 1 << "2"
<< (QStringList()
<< "11" << "1"
<< "00" << "2")
<< (IntList() << 1 << 0)
<< true;
QTest::newRow("2x2 no change (column != sortColumn)")
<< 2 << 2
<< Qt::AscendingOrder << 1
<< (QStringList()
<< "00" << "0"
<< "11" << "1")
<< 0 << 0 << "22"
<< (QStringList()
<< "22" << "0"
<< "11" << "1")
<< (IntList() << 0 << 1)
<< false;
QTest::newRow("8x4 reorder (ascending, sortColumn = 3)")
<< 8 << 4
<< Qt::AscendingOrder << 3
<< (QStringList()
<< "q" << "v" << "u" << "0"
<< "e" << "j" << "i" << "10"
<< "h" << "d" << "c" << "12"
<< "k" << "g" << "f" << "14"
<< "w" << "y" << "x" << "2"
<< "t" << "s" << "o" << "4"
<< "z" << "p" << "r" << "6"
<< "n" << "m" << "l" << "8")
<< 2 << 3 << "5"
<< (QStringList()
<< "q" << "v" << "u" << "0"
<< "e" << "j" << "i" << "10"
<< "k" << "g" << "f" << "14"
<< "w" << "y" << "x" << "2"
<< "t" << "s" << "o" << "4"
<< "h" << "d" << "c" << "5"
<< "z" << "p" << "r" << "6"
<< "n" << "m" << "l" << "8")
<< (IntList() << 0 << 1 << 5 << 2 << 3 << 4 << 6 << 7)
<< true;
}
void tst_QTableWidget::setItemWithSorting()
{
static int dummy1 = qRegisterMetaType<QList<QPersistentModelIndex>>();
static int dummy2 = qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>();
Q_UNUSED(dummy1);
Q_UNUSED(dummy2);
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(Qt::SortOrder, sortOrder);
QFETCH(int, sortColumn);
QFETCH(QStringList, initialValues);
QFETCH(int, row);
QFETCH(int, column);
QFETCH(QString, newValue);
QFETCH(QStringList, expectedValues);
QFETCH(IntList, expectedRows);
QFETCH(bool, reorderingExpected);
for (int i = 0; i < 2; ++i) {
QTableWidget w(rowCount, columnCount);
QAbstractItemModel *model = w.model();
QList<QPersistentModelIndex> persistent;
int ti = 0;
for (int r = 0; r < rowCount; ++r) {
for (int c = 0; c < columnCount; ++c) {
QString str = initialValues.at(ti++);
w.setItem(r, c, new QTableWidgetItem(str));
}
persistent << model->index(r, sortColumn);
}
w.sortItems(sortColumn, sortOrder);
w.setSortingEnabled(true);
QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged);
QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged);
if (i == 0) {
// set a new item
QTableWidgetItem *item = new QTableWidgetItem(newValue);
w.setItem(row, column, item);
} else {
// change the data of existing item
QTableWidgetItem *item = w.item(row, column);
item->setText(newValue);
}
ti = 0;
for (int r = 0; r < rowCount; ++r) {
for (int c = 0; c < columnCount; ++c) {
QString str = expectedValues.at(ti++);
QCOMPARE(w.item(r, c)->text(), str);
}
}
for (int k = 0; k < persistent.size(); ++k) {
QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
int i = (persistent.at(k).row() * columnCount) + sortColumn;
QCOMPARE(persistent.at(k).data().toString(), expectedValues.at(i));
}
if (i == 0)
QCOMPARE(dataChangedSpy.size(), reorderingExpected ? 0 : 1);
else
QCOMPARE(dataChangedSpy.size(), 1);
QCOMPARE(layoutChangedSpy.size(), reorderingExpected ? 1 : 0);
}
}
class QTableWidgetDataChanged : public QTableWidget
{
Q_OBJECT
public:
using QTableWidget::QTableWidget;
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QList<int> &roles) override
{
QTableWidget::dataChanged(topLeft, bottomRight, roles);
currentRoles = roles;
}
QList<int> currentRoles;
};
void tst_QTableWidget::itemData()
{
QTableWidgetDataChanged widget(2, 2);
widget.setItem(0, 0, new QTableWidgetItem);
QTableWidgetItem *item = widget.item(0, 0);
QVERIFY(item);
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setData(Qt::DisplayRole, QString("0"));
QCOMPARE(widget.currentRoles, QList<int>({ Qt::DisplayRole, Qt::EditRole }));
item->setData(Qt::CheckStateRole, Qt::PartiallyChecked);
QCOMPARE(widget.currentRoles, QList<int> { Qt::CheckStateRole });
for (int i = 0; i < 4; ++i)
{
item->setData(Qt::UserRole + i, QString::number(i + 1));
QCOMPARE(widget.currentRoles, QList<int> { Qt::UserRole + i });
}
QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0));
QCOMPARE(flags.size(), 6);
for (int i = 0; i < 4; ++i)
QCOMPARE(flags[Qt::UserRole + i].toString(), QString::number(i + 1));
}
void tst_QTableWidget::setItemData()
{
QTableWidgetDataChanged table(10, 10);
table.setSortingEnabled(false);
QSignalSpy dataChangedSpy(table.model(), &QAbstractItemModel::dataChanged);
QTableWidgetItem *item = new QTableWidgetItem;
table.setItem(0, 0, item);
QCOMPARE(dataChangedSpy.size(), 1);
QModelIndex idx = qvariant_cast<QModelIndex>(dataChangedSpy.takeFirst().at(0));
QMap<int, QVariant> data;
data.insert(Qt::DisplayRole, QLatin1String("Display"));
data.insert(Qt::ToolTipRole, QLatin1String("ToolTip"));
table.model()->setItemData(idx, data);
QCOMPARE(table.currentRoles, QList<int>({ Qt::DisplayRole, Qt::EditRole, Qt::ToolTipRole }));
QCOMPARE(table.model()->data(idx, Qt::DisplayRole).toString(), QLatin1String("Display"));
QCOMPARE(table.model()->data(idx, Qt::EditRole).toString(), QLatin1String("Display"));
QCOMPARE(table.model()->data(idx, Qt::ToolTipRole).toString(), QLatin1String("ToolTip"));
QCOMPARE(dataChangedSpy.size(), 1);
QCOMPARE(idx, qvariant_cast<QModelIndex>(dataChangedSpy.first().at(0)));
QCOMPARE(idx, qvariant_cast<QModelIndex>(dataChangedSpy.first().at(1)));
const auto roles = qvariant_cast<QList<int>>(dataChangedSpy.first().at(2));
QCOMPARE(roles.size(), 3);
QVERIFY(roles.contains(Qt::DisplayRole));
QVERIFY(roles.contains(Qt::EditRole));
QVERIFY(roles.contains(Qt::ToolTipRole));
dataChangedSpy.clear();
table.model()->setItemData(idx, data);
QCOMPARE(dataChangedSpy.size(), 0);
data.clear();
data.insert(Qt::DisplayRole, QLatin1String("dizplaye"));
table.model()->setItemData(idx, data);
QCOMPARE(table.model()->data(idx, Qt::DisplayRole).toString(), QLatin1String("dizplaye"));
QCOMPARE(dataChangedSpy.size(), 1);
QCOMPARE(QList<int>({ Qt::DisplayRole, Qt::EditRole }),
qvariant_cast<QList<int>>(dataChangedSpy.first().at(2)));
item->setBackground(QBrush(Qt::red));
item->setForeground(QBrush(Qt::green));
item->setSizeHint(QSize(10, 10));
QCOMPARE(item->data(Qt::BackgroundRole), QVariant(QBrush(Qt::red)));
QCOMPARE(item->data(Qt::ForegroundRole), QVariant(QBrush(Qt::green)));
QCOMPARE(item->data(Qt::SizeHintRole), QVariant(QSize(10, 10)));
// an empty brush should result in a QVariant()
item->setBackground(QBrush());
item->setForeground(QBrush());
item->setSizeHint(QSize());
QCOMPARE(item->data(Qt::BackgroundRole), QVariant());
QCOMPARE(item->data(Qt::ForegroundRole), QVariant());
QCOMPARE(item->data(Qt::SizeHintRole), QVariant());
}
void tst_QTableWidget::cellWidget()
{
QTableWidget table(10, 10);
QWidget widget;
QCOMPARE(table.cellWidget(5, 5), nullptr);
table.setCellWidget(5, 5, &widget);
QCOMPARE(table.cellWidget(5, 5), &widget);
table.removeCellWidget(5, 5);
QCOMPARE(table.cellWidget(5, 5), nullptr);
}
void tst_QTableWidget::cellWidgetGeometry()
{
QTableWidget tw(3,2);
tw.show();
// make sure the next row added is not completely visibile
tw.resize(300, tw.rowHeight(0) * 3 + tw.rowHeight(0) / 2);
QVERIFY(QTest::qWaitForWindowExposed(&tw));
tw.scrollToBottom();
tw.setRowCount(tw.rowCount() + 1);
auto item = new QTableWidgetItem("Hello");
tw.setItem(0,0,item);
auto le = new QLineEdit("world");
tw.setCellWidget(0,1,le);
// process delayedPendingLayout triggered by setting the row count
tw.doItemsLayout();
// so y pos is 0 for the first row
tw.scrollToTop();
// check if updateEditorGeometries has set the correct y pos for the editors
QCOMPARE(tw.visualItemRect(item).top(), le->geometry().top());
}
void tst_QTableWidget::sizeHint_data()
{
QTest::addColumn<Qt::ScrollBarPolicy>("scrollBarPolicy");
QTest::addColumn<QSize>("viewSize");
QTest::newRow("ScrollBarAlwaysOn") << Qt::ScrollBarAlwaysOn << QSize();
QTest::newRow("ScrollBarAlwaysOff") << Qt::ScrollBarAlwaysOff << QSize();
// make sure the scrollbars are shown by resizing the view to 40x40
QTest::newRow("ScrollBarAsNeeded (40x40)") << Qt::ScrollBarAsNeeded << QSize(40, 40);
QTest::newRow("ScrollBarAsNeeded (1000x1000)") << Qt::ScrollBarAsNeeded << QSize(1000, 1000);
}
void tst_QTableWidget::sizeHint()
{
QFETCH(Qt::ScrollBarPolicy, scrollBarPolicy);
QFETCH(QSize, viewSize);
QTableWidget view(2, 2);
view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
view.setVerticalScrollBarPolicy(scrollBarPolicy);
view.setHorizontalScrollBarPolicy(scrollBarPolicy);
for (int r = 0 ; r < view.rowCount(); ++r) {
const QString rStr = QString::number(r) + QLatin1Char('/');
for (int c = 0 ; c < view.columnCount(); ++c)
view.setItem(r, c, new QTableWidgetItem(rStr + QString::number(c)));
}
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
if (viewSize.isValid()) {
view.resize(viewSize);
view.setColumnWidth(0, 100);
view.setRowHeight(0, 100);
QTRY_COMPARE(view.size(), viewSize);
}
auto sizeHint = view.sizeHint();
view.hide();
QCOMPARE(view.sizeHint(), sizeHint);
view.horizontalHeader()->hide();
view.show();
sizeHint = view.sizeHint();
view.hide();
QCOMPARE(view.sizeHint(), sizeHint);
view.verticalHeader()->hide();
view.show();
sizeHint = view.sizeHint();
view.hide();
QCOMPARE(view.sizeHint(), sizeHint);
}
void tst_QTableWidget::task231094()
{
QTableWidget tw(5, 3);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 5; y++) {
QTableWidgetItem *twi = new QTableWidgetItem(QLatin1String("1"));
if (y == 1)
twi->setFlags(Qt::ItemIsEnabled);
else
twi->setFlags({});
tw.setItem(y, x, twi);
}
}
tw.setCurrentCell(1, 1);
QCOMPARE(tw.currentRow(), 1);
QCOMPARE(tw.currentColumn(), 1);
//this would provoke a end-less loop
QTest::keyClick(&tw, '1');
//all the items are disabled: the current item shouldn't have changed
QCOMPARE(tw.currentRow(), 1);
QCOMPARE(tw.currentColumn(), 1);
}
void tst_QTableWidget::task219380_removeLastRow()
{
testWidget->setColumnCount(1);
testWidget->setRowCount(20);
QTableWidgetItem item;
testWidget->setItem(18, 0, &item); //we put the item in the second last row
testWidget->openPersistentEditor(&item);
testWidget->scrollToBottom();
testWidget->removeRow(19); //we remove the last row
//we make sure the editor is at the cell position
QTRY_COMPARE(testWidget->cellWidget(18, 0)->geometry(), testWidget->visualItemRect(&item));
}
void tst_QTableWidget::task262056_sortDuplicate()
{
testWidget->setColumnCount(2);
testWidget->setRowCount(8);
testWidget->setSortingEnabled(true);
const QStringList items({"AAA", "BBB", "CCC", "CCC", "DDD",
"EEE", "FFF", "GGG"});
for (int i = 0; i < 8; i++ ) {
QTableWidgetItem *twi = new QTableWidgetItem(items.at(i));
testWidget->setItem(i, 0, twi);
testWidget->setItem(i, 1, new QTableWidgetItem(QLatin1String("item ") + QString::number(i)));
}
testWidget->sortItems(0, Qt::AscendingOrder);
QSignalSpy layoutChangedSpy(testWidget->model(), &QAbstractItemModel::layoutChanged);
testWidget->item(3,0)->setBackground(Qt::red);
QCOMPARE(layoutChangedSpy.size(),0);
}
void tst_QTableWidget::itemWithHeaderItems()
{
// Need a separate testcase for this because the tst_QTableWidget::item testcase
// does creates QTableWidgetItems for each available cell in the table. We're testing
// the case of not all available cells having a QTableWidgetItem set.
QTableWidget table(2, 1);
QTableWidgetItem *item0_0 = new QTableWidgetItem(QTableWidgetItem::UserType);
table.setItem(0, 0, item0_0);
QTableWidgetItem *item1_0 = new QTableWidgetItem(QTableWidgetItem::UserType);
table.setItem(1, 0, item1_0);
QCOMPARE(table.item(0, 1), nullptr);
}
void tst_QTableWidget::checkHeaderItemFlagsConflict()
{
// QTBUG-113209
// Check that setting header item doesn't set Qt::ItemNeverHasChildren
// Chech that header items do not emit itemChanged.
QTableWidget table(1, 1);
QSignalSpy itemChangeSpy(&table, &QTableWidget::itemChanged);
QVERIFY(itemChangeSpy.isValid());
QTableWidgetItem *item = new QTableWidgetItem("Initial");
table.setHorizontalHeaderItem(0, item);
QVERIFY(!(item->flags() & Qt::ItemNeverHasChildren));
item->setData(Qt::DisplayRole, "updated");
QCOMPARE(itemChangeSpy.size(), 0);
}
class TestTableWidget : public QTableWidget
{
Q_OBJECT
public:
using QTableWidget::QTableWidget;
using QTableWidget::mimeData;
using QTableWidget::indexFromItem;
using QTableWidget::keyPressEvent;
};
void tst_QTableWidget::mimeData()
{
TestTableWidget table(10, 10);
for (int x = 0; x < 10; ++x) {
for (int y = 0; y < 10; ++y) {
QTableWidgetItem *item = new QTableWidgetItem(QStringLiteral("123"));
table.setItem(y, x, item);
}
}
QList<QTableWidgetItem *> tableWidgetItemList;
QModelIndexList modelIndexList;
// do these checks more than once to ensure that the "cached indexes" work as expected
QVERIFY(!table.mimeData(tableWidgetItemList));
QVERIFY(!table.model()->mimeData(modelIndexList));
QVERIFY(!table.model()->mimeData(modelIndexList));
QVERIFY(!table.mimeData(tableWidgetItemList));
tableWidgetItemList << table.item(1, 1);
modelIndexList << table.indexFromItem(table.item(1, 1));
QMimeData *data;
QVERIFY((data = table.mimeData(tableWidgetItemList)));
delete data;
QVERIFY((data = table.model()->mimeData(modelIndexList)));
delete data;
QVERIFY((data = table.model()->mimeData(modelIndexList)));
delete data;
QVERIFY((data = table.mimeData(tableWidgetItemList)));
delete data;
// check the saved data is actually the same
QMimeData *data2;
data = table.mimeData(tableWidgetItemList);
data2 = table.model()->mimeData(modelIndexList);
const QString format = QStringLiteral("application/x-qabstractitemmodeldatalist");
QVERIFY(data->hasFormat(format));
QVERIFY(data2->hasFormat(format));
QCOMPARE(data->data(format), data2->data(format));
delete data;
delete data2;
}
void tst_QTableWidget::selectedRowAfterSorting()
{
TestTableWidget table(3,3);
table.setSelectionBehavior(QAbstractItemView::SelectRows);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++)
table.setItem(r, c, new QTableWidgetItem(QStringLiteral("0")));
}
QHeaderView *localHorizontalHeader = table.horizontalHeader();
localHorizontalHeader->setSortIndicator(1,Qt::DescendingOrder);
table.setProperty("sortingEnabled",true);
table.selectRow(1);
table.item(1,1)->setText("9");
QCOMPARE(table.selectedItems().size(),3);
const auto selectedItems = table.selectedItems();
for (QTableWidgetItem *item : selectedItems)
QCOMPARE(item->row(), 0);
}
void tst_QTableWidget::search()
{
auto createItem = [](const QString &txt)
{
auto item = new QTableWidgetItem(txt);
item->setFlags(item->flags().setFlag(Qt::ItemIsEditable, false));
return item;
};
struct KeyPress {
Qt::Key key;
QString text;
};
auto checkSeries = [](TestTableWidget &tw, const QList<QPair<KeyPress, int>> &series) {
for (const auto &p : series) {
QKeyEvent e(QEvent::KeyPress, p.first.key, Qt::NoModifier, p.first.text);
tw.keyPressEvent(&e);
QVERIFY(tw.selectionModel()->isSelected(tw.model()->index(p.second, 0)));
}
};
TestTableWidget tw(5, 1);
tw.setItem(0, 0, createItem("12"));
tw.setItem(1, 0, createItem("123"));
tw.setItem(2, 0, createItem("123 4"));
tw.setItem(3, 0, createItem("123 5"));
tw.setItem(4, 0, createItem(" "));
tw.show();
KeyPress evSpace{Qt::Key_Space, " "};
KeyPress ev1{Qt::Key_1, "1"};
KeyPress ev2{Qt::Key_2, "2"};
KeyPress ev3{Qt::Key_3, "3"};
KeyPress ev4{Qt::Key_4, "4"};
KeyPress ev5{Qt::Key_5, "5"};
checkSeries(tw, {{evSpace, 4}, {ev1, 4}});
QTest::qWait(QApplication::keyboardInputInterval() * 2);
checkSeries(tw, {{ev1, 0}, {ev2, 0}, {ev3, 1}, {evSpace, 2}, {ev5, 3}});
QTest::qWait(QApplication::keyboardInputInterval() * 2);
checkSeries(tw, {{ev1, 0}, {ev2, 0}, {ev3, 1}, {evSpace, 2}, {ev4, 2}});
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void tst_QTableWidget::clearItemData()
{
QTableWidget table(3, 3);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++)
table.setItem(r, c, new QTableWidgetItem(QStringLiteral("0")));
}
QSignalSpy dataChangeSpy(table.model(), &QAbstractItemModel::dataChanged);
QVERIFY(dataChangeSpy.isValid());
QVERIFY(!table.model()->clearItemData(QModelIndex()));
QCOMPARE(dataChangeSpy.size(), 0);
QVERIFY(table.model()->clearItemData(table.model()->index(0, 0)));
QVERIFY(!table.model()->index(0, 0).data().isValid());
QCOMPARE(dataChangeSpy.size(), 1);
const QList<QVariant> dataChangeArgs = dataChangeSpy.takeFirst();
QCOMPARE(dataChangeArgs.at(0).value<QModelIndex>(), table.model()->index(0, 0));
QCOMPARE(dataChangeArgs.at(1).value<QModelIndex>(), table.model()->index(0, 0));
QVERIFY(dataChangeArgs.at(2).value<QList<int>>().isEmpty());
QVERIFY(table.model()->clearItemData(table.model()->index(0, 0)));
QCOMPARE(dataChangeSpy.size(), 0);
}
#endif
void tst_QTableWidget::createPersistentOnLayoutAboutToBeChanged() // QTBUG-93466
{
QTableWidget widget;
widget.model()->insertColumn(0);
QCOMPARE(widget.model()->columnCount(), 1);
widget.model()->insertRows(0, 3);
for (int row = 0; row < 3; ++row)
widget.model()->setData(widget.model()->index(row, 0), row);
QList<QPersistentModelIndex> idxList;
QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged);
QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged);
connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){
idxList.clear();
for (int row = 0; row < 3; ++row)
idxList << QPersistentModelIndex(widget.model()->index(row, 0));
});
connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){
QCOMPARE(idxList.size(), 3);
QCOMPARE(idxList.at(0).row(), 1);
QCOMPARE(idxList.at(0).column(), 0);
QCOMPARE(idxList.at(0).data().toInt(), 0);
QCOMPARE(idxList.at(1).row(), 0);
QCOMPARE(idxList.at(1).column(), 0);
QCOMPARE(idxList.at(1).data().toInt(), -1);
QCOMPARE(idxList.at(2).row(), 2);
QCOMPARE(idxList.at(2).column(), 0);
QCOMPARE(idxList.at(2).data().toInt(), 2);
});
widget.model()->setData(widget.model()->index(1, 0), -1);
widget.model()->sort(0);
QCOMPARE(layoutAboutToBeChangedSpy.size(), 1);
QCOMPARE(layoutChangedSpy.size(), 1);
}
void tst_QTableWidget::createPersistentOnLayoutAboutToBeChangedAutoSort() // QTBUG-93466
{
QTableWidget widget;
widget.model()->insertColumn(0);
QCOMPARE(widget.model()->columnCount(), 1);
widget.model()->insertRows(0, 3);
for (int row = 0; row < 3; ++row)
widget.model()->setData(widget.model()->index(row, 0), row);
widget.sortByColumn(0, Qt::AscendingOrder);
widget.setSortingEnabled(true);
QList<QPersistentModelIndex> idxList;
QSignalSpy layoutAboutToBeChangedSpy(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged);
QSignalSpy layoutChangedSpy(widget.model(), &QAbstractItemModel::layoutChanged);
connect(widget.model(), &QAbstractItemModel::layoutAboutToBeChanged, this, [&idxList, &widget](){
idxList.clear();
for (int row = 0; row < 3; ++row)
idxList << QPersistentModelIndex(widget.model()->index(row, 0));
});
connect(widget.model(), &QAbstractItemModel::layoutChanged, this, [&idxList](){
QCOMPARE(idxList.size(), 3);
QCOMPARE(idxList.at(0).row(), 1);
QCOMPARE(idxList.at(0).column(), 0);
QCOMPARE(idxList.at(0).data().toInt(), 0);
QCOMPARE(idxList.at(1).row(), 0);
QCOMPARE(idxList.at(1).column(), 0);
QCOMPARE(idxList.at(1).data().toInt(), -1);
QCOMPARE(idxList.at(2).row(), 2);
QCOMPARE(idxList.at(2).column(), 0);
QCOMPARE(idxList.at(2).data().toInt(), 2);
});
widget.model()->setData(widget.model()->index(1, 0), -1);
QCOMPARE(layoutAboutToBeChangedSpy.size(), 1);
QCOMPARE(layoutChangedSpy.size(), 1);
}
QTEST_MAIN(tst_QTableWidget)
#include "tst_qtablewidget.moc"