diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2012-06-26 17:30:57 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-06-29 22:42:19 +0200 |
commit | dba22bc03690eaa00a7757dd024d8953ec74b30c (patch) | |
tree | 3c5cfc060642467bed2b457f35996f86cbb48bc9 /tests/auto/gui | |
parent | f4f0c8b99b362822f85dd1859518e89d33e4bd3b (diff) |
Move QStandardItem/QStandardItemModel to QtGui
The dependencies on QFont, QBrush, QIcon are all in QtGui, so there's
little sense to still have these classes in QtWidgets.
This also copies and pastes a version of QWidgetItemData as
QStandardItemData inside qstandarditemmodel_p.h.
Change-Id: Ibafc5a30748e7ce0b54753309ae6dc4a797fc20e
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'tests/auto/gui')
8 files changed, 2814 insertions, 0 deletions
diff --git a/tests/auto/gui/gui.pro b/tests/auto/gui/gui.pro index 48fa2772f9..87aea70acb 100644 --- a/tests/auto/gui/gui.pro +++ b/tests/auto/gui/gui.pro @@ -7,3 +7,4 @@ SUBDIRS=\ qopengl \ text \ util \ + itemmodels \ diff --git a/tests/auto/gui/itemmodels/itemmodels.pro b/tests/auto/gui/itemmodels/itemmodels.pro new file mode 100644 index 0000000000..2e7fabfa7e --- /dev/null +++ b/tests/auto/gui/itemmodels/itemmodels.pro @@ -0,0 +1,4 @@ +TEMPLATE=subdirs +SUBDIRS= \ + qstandarditem \ + qstandarditemmodel \ diff --git a/tests/auto/gui/itemmodels/qstandarditem/.gitignore b/tests/auto/gui/itemmodels/qstandarditem/.gitignore new file mode 100644 index 0000000000..6da85cc6c8 --- /dev/null +++ b/tests/auto/gui/itemmodels/qstandarditem/.gitignore @@ -0,0 +1 @@ +tst_qstandarditem diff --git a/tests/auto/gui/itemmodels/qstandarditem/qstandarditem.pro b/tests/auto/gui/itemmodels/qstandarditem/qstandarditem.pro new file mode 100644 index 0000000000..282737ed7d --- /dev/null +++ b/tests/auto/gui/itemmodels/qstandarditem/qstandarditem.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +CONFIG += parallel_test +TARGET = tst_qstandarditem +QT += gui testlib +SOURCES += tst_qstandarditem.cpp + + diff --git a/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp b/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp new file mode 100644 index 0000000000..8ababf0ac4 --- /dev/null +++ b/tests/auto/gui/itemmodels/qstandarditem/tst_qstandarditem.cpp @@ -0,0 +1,1107 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qstandarditemmodel.h> + +class tst_QStandardItem : public QObject +{ + Q_OBJECT + +public: + tst_QStandardItem(); + virtual ~tst_QStandardItem(); + +public slots: + void init(); + void cleanup(); + +private slots: + void ctor(); + void textCtor(); + void iconTextCtor(); + void rowsColumnsCtor(); + void getSetData(); + void getSetFlags(); + void getSetRowAndColumnCount(); + void getSetChild_data(); + void getSetChild(); + void parent(); + void insertColumn_data(); + void insertColumn(); + void insertColumns_data(); + void insertColumns(); + void insertRow_data(); + void insertRow(); + void insertRows_data(); + void insertRows(); + void appendColumn_data(); + void appendColumn(); + void appendRow_data(); + void appendRow(); + void takeChild(); + void takeColumn_data(); + void takeColumn(); + void takeRow_data(); + void takeRow(); + void streamItem(); + void deleteItem(); + void clone(); + void sortChildren(); + void subclassing(); +}; + +tst_QStandardItem::tst_QStandardItem() +{ +} + +tst_QStandardItem::~tst_QStandardItem() +{ +} + +void tst_QStandardItem::init() +{ +} + +void tst_QStandardItem::cleanup() +{ +} + +void tst_QStandardItem::ctor() +{ + QStandardItem item; + QVERIFY(!item.hasChildren()); +} + +void tst_QStandardItem::textCtor() +{ + QLatin1String text("text"); + QStandardItem item(text); + QCOMPARE(item.text(), text); + QVERIFY(!item.hasChildren()); +} + +void tst_QStandardItem::iconTextCtor() +{ + QPixmap pixmap(32, 32); + pixmap.fill(Qt::red); + QIcon icon(pixmap); + QLatin1String text("text"); + QStandardItem item(icon, text); + QCOMPARE(item.icon(), icon); + QCOMPARE(item.text(), text); + QVERIFY(!item.hasChildren()); +} + +void tst_QStandardItem::rowsColumnsCtor() +{ + const int rows = 5; + const int columns = 12; + QStandardItem item(rows, columns); + QCOMPARE(item.rowCount(), rows); + QCOMPARE(item.columnCount(), columns); +} + +void tst_QStandardItem::getSetData() +{ + QStandardItem item; + for (int x = 0; x < 2; ++x) { + for (int i = 1; i <= 2; ++i) { + QString text = QString("text %0").arg(i); + item.setText(text); + QCOMPARE(item.text(), text); + + QPixmap pixmap(32, 32); + pixmap.fill((i == 1) ? Qt::red : Qt::green); + QIcon icon(pixmap); + item.setIcon(icon); + QCOMPARE(item.icon(), icon); + + QString toolTip = QString("toolTip %0").arg(i); + item.setToolTip(toolTip); + QCOMPARE(item.toolTip(), toolTip); + + QString statusTip = QString("statusTip %0").arg(i); + item.setStatusTip(statusTip); + QCOMPARE(item.statusTip(), statusTip); + + QString whatsThis = QString("whatsThis %0").arg(i); + item.setWhatsThis(whatsThis); + QCOMPARE(item.whatsThis(), whatsThis); + + QSize sizeHint(64*i, 48*i); + item.setSizeHint(sizeHint); + QCOMPARE(item.sizeHint(), sizeHint); + + QFont font; + item.setFont(font); + QCOMPARE(item.font(), font); + + Qt::Alignment textAlignment((i == 1) + ? Qt::AlignLeft|Qt::AlignVCenter + : Qt::AlignRight); + item.setTextAlignment(textAlignment); + QCOMPARE(item.textAlignment(), textAlignment); + + QColor backgroundColor((i == 1) ? Qt::blue : Qt::yellow); + item.setBackground(backgroundColor); + QCOMPARE(item.background().color(), backgroundColor); + + QColor textColor((i == i) ? Qt::green : Qt::cyan); + item.setForeground(textColor); + QCOMPARE(item.foreground().color(), textColor); + + Qt::CheckState checkState((i == 1) ? Qt::PartiallyChecked : Qt::Checked); + item.setCheckState(checkState); + QCOMPARE(item.checkState(), checkState); + + QString accessibleText = QString("accessibleText %0").arg(i); + item.setAccessibleText(accessibleText); + QCOMPARE(item.accessibleText(), accessibleText); + + QString accessibleDescription = QString("accessibleDescription %0").arg(i); + item.setAccessibleDescription(accessibleDescription); + QCOMPARE(item.accessibleDescription(), accessibleDescription); + + QCOMPARE(item.text(), text); + QCOMPARE(item.icon(), icon); + QCOMPARE(item.toolTip(), toolTip); + QCOMPARE(item.statusTip(), statusTip); + QCOMPARE(item.whatsThis(), whatsThis); + QCOMPARE(item.sizeHint(), sizeHint); + QCOMPARE(item.font(), font); + QCOMPARE(item.textAlignment(), textAlignment); + QCOMPARE(item.background().color(), backgroundColor); + QCOMPARE(item.foreground().color(), textColor); + QCOMPARE(item.checkState(), checkState); + QCOMPARE(item.accessibleText(), accessibleText); + QCOMPARE(item.accessibleDescription(), accessibleDescription); + + QCOMPARE(qvariant_cast<QString>(item.data(Qt::DisplayRole)), text); + QCOMPARE(qvariant_cast<QIcon>(item.data(Qt::DecorationRole)), icon); + QCOMPARE(qvariant_cast<QString>(item.data(Qt::ToolTipRole)), toolTip); + QCOMPARE(qvariant_cast<QString>(item.data(Qt::StatusTipRole)), statusTip); + QCOMPARE(qvariant_cast<QString>(item.data(Qt::WhatsThisRole)), whatsThis); + QCOMPARE(qvariant_cast<QSize>(item.data(Qt::SizeHintRole)), sizeHint); + QCOMPARE(qvariant_cast<QFont>(item.data(Qt::FontRole)), font); + QCOMPARE(qvariant_cast<int>(item.data(Qt::TextAlignmentRole)), int(textAlignment)); + QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::BackgroundColorRole)), QBrush(backgroundColor)); + QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::BackgroundRole)), QBrush(backgroundColor)); + QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::TextColorRole)), QBrush(textColor)); + QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::ForegroundRole)), QBrush(textColor)); + QCOMPARE(qvariant_cast<int>(item.data(Qt::CheckStateRole)), int(checkState)); + QCOMPARE(qvariant_cast<QString>(item.data(Qt::AccessibleTextRole)), accessibleText); + QCOMPARE(qvariant_cast<QString>(item.data(Qt::AccessibleDescriptionRole)), accessibleDescription); + + item.setBackground(pixmap); + QCOMPARE(item.background().texture(), pixmap); + QCOMPARE(qvariant_cast<QBrush>(item.data(Qt::BackgroundRole)).texture(), pixmap); + } + item.setData(QVariant(), Qt::DisplayRole); + item.setData(QVariant(), Qt::DecorationRole); + item.setData(QVariant(), Qt::ToolTipRole); + item.setData(QVariant(), Qt::StatusTipRole); + item.setData(QVariant(), Qt::WhatsThisRole); + item.setData(QVariant(), Qt::SizeHintRole); + item.setData(QVariant(), Qt::FontRole); + item.setData(QVariant(), Qt::TextAlignmentRole); + item.setData(QVariant(), Qt::BackgroundRole); + item.setData(QVariant(), Qt::ForegroundRole); + item.setData(QVariant(), Qt::CheckStateRole); + item.setData(QVariant(), Qt::AccessibleTextRole); + item.setData(QVariant(), Qt::AccessibleDescriptionRole); + + QCOMPARE(item.data(Qt::DisplayRole), QVariant()); + QCOMPARE(item.data(Qt::DecorationRole), QVariant()); + QCOMPARE(item.data(Qt::ToolTipRole), QVariant()); + QCOMPARE(item.data(Qt::StatusTipRole), QVariant()); + QCOMPARE(item.data(Qt::WhatsThisRole), QVariant()); + QCOMPARE(item.data(Qt::SizeHintRole), QVariant()); + QCOMPARE(item.data(Qt::FontRole), QVariant()); + QCOMPARE(item.data(Qt::TextAlignmentRole), QVariant()); + QCOMPARE(item.data(Qt::BackgroundColorRole), QVariant()); + QCOMPARE(item.data(Qt::BackgroundRole), QVariant()); + QCOMPARE(item.data(Qt::TextColorRole), QVariant()); + QCOMPARE(item.data(Qt::ForegroundRole), QVariant()); + QCOMPARE(item.data(Qt::CheckStateRole), QVariant()); + QCOMPARE(item.data(Qt::AccessibleTextRole), QVariant()); + QCOMPARE(item.data(Qt::AccessibleDescriptionRole), QVariant()); + } +} + +void tst_QStandardItem::getSetFlags() +{ + QStandardItem item; + item.setEnabled(true); + QVERIFY(item.isEnabled()); + QVERIFY(item.flags() & Qt::ItemIsEnabled); + item.setEditable(true); + QVERIFY(item.isEditable()); + QVERIFY(item.flags() & Qt::ItemIsEditable); + item.setSelectable(true); + QVERIFY(item.isSelectable()); + QVERIFY(item.flags() & Qt::ItemIsSelectable); + item.setCheckable(true); + QVERIFY(item.isCheckable()); + QCOMPARE(item.checkState(), Qt::Unchecked); + QVERIFY(item.flags() & Qt::ItemIsUserCheckable); + item.setTristate(true); + QVERIFY(item.isTristate()); + QVERIFY(item.flags() & Qt::ItemIsTristate); +#ifndef QT_NO_DRAGANDDROP + item.setDragEnabled(true); + QVERIFY(item.isDragEnabled()); + QVERIFY(item.flags() & Qt::ItemIsDragEnabled); + item.setDropEnabled(true); + QVERIFY(item.isDropEnabled()); + QVERIFY(item.flags() & Qt::ItemIsDropEnabled); +#endif + + QVERIFY(item.isEnabled()); + item.setEnabled(false); + QVERIFY(!item.isEnabled()); + QVERIFY(!(item.flags() & Qt::ItemIsEnabled)); + QVERIFY(item.isEditable()); + item.setEditable(false); + QVERIFY(!item.isEditable()); + QVERIFY(!(item.flags() & Qt::ItemIsEditable)); + QVERIFY(item.isSelectable()); + item.setSelectable(false); + QVERIFY(!item.isSelectable()); + QVERIFY(!(item.flags() & Qt::ItemIsSelectable)); + QVERIFY(item.isCheckable()); + item.setCheckable(false); + QVERIFY(!item.isCheckable()); + QVERIFY(!(item.flags() & Qt::ItemIsUserCheckable)); + QVERIFY(item.isTristate()); + item.setTristate(false); + QVERIFY(!item.isTristate()); + QVERIFY(!(item.flags() & Qt::ItemIsTristate)); +#ifndef QT_NO_DRAGANDDROP + QVERIFY(item.isDragEnabled()); + item.setDragEnabled(false); + QVERIFY(!item.isDragEnabled()); + QVERIFY(!(item.flags() & Qt::ItemIsDragEnabled)); + QVERIFY(item.isDropEnabled()); + item.setDropEnabled(false); + QVERIFY(!item.isDropEnabled()); + QVERIFY(!(item.flags() & Qt::ItemIsDropEnabled)); +#endif + + item.setCheckable(false); + item.setCheckState(Qt::Checked); + item.setCheckable(true); + QCOMPARE(item.checkState(), Qt::Checked); +} + +void tst_QStandardItem::getSetRowAndColumnCount() +{ + QStandardItem item; + + item.setRowCount(-1); + QCOMPARE(item.rowCount(), 0); + + item.setColumnCount(-1); + QCOMPARE(item.columnCount(), 0); + + item.setRowCount(1); + QCOMPARE(item.rowCount(), 1); + QCOMPARE(item.columnCount(), 0); + + item.setColumnCount(1); + QCOMPARE(item.columnCount(), 1); + QCOMPARE(item.rowCount(), 1); + + item.setColumnCount(10); + QCOMPARE(item.columnCount(), 10); + QCOMPARE(item.rowCount(), 1); + + item.setRowCount(20); + QCOMPARE(item.rowCount(), 20); + QCOMPARE(item.columnCount(), 10); + + item.setRowCount(-1); + QCOMPARE(item.rowCount(), 20); + + item.setColumnCount(-1); + QCOMPARE(item.columnCount(), 10); + + item.setColumnCount(0); + QCOMPARE(item.columnCount(), 0); + QCOMPARE(item.rowCount(), 20); + + item.setRowCount(0); + QCOMPARE(item.rowCount(), 0); +} + +void tst_QStandardItem::getSetChild_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("row"); + QTest::addColumn<int>("column"); + + QTest::newRow("0x0 children, child at (-1,-1)") << 0 << 0 << -1 << -1; + QTest::newRow("0x0 children, child at (0,0)") << 0 << 0 << 0 << 0; +} + +void tst_QStandardItem::getSetChild() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, row); + QFETCH(int, column); + + QStandardItem item(rows, columns); + bool shouldHaveChildren = (rows > 0) && (columns > 0); + QCOMPARE(item.hasChildren(), shouldHaveChildren); + QCOMPARE(item.child(row, column), static_cast<QStandardItem*>(0)); + + QStandardItem *child = new QStandardItem; + item.setChild(row, column, child); + if ((row >= 0) && (column >= 0)) { + QCOMPARE(item.rowCount(), qMax(rows, row + 1)); + QCOMPARE(item.columnCount(), qMax(columns, column + 1)); + + QCOMPARE(item.child(row, column), child); + QCOMPARE(child->row(), row); + QCOMPARE(child->column(), column); + + QStandardItem *anotherChild = new QStandardItem; + item.setChild(row, column, anotherChild); + QCOMPARE(item.child(row, column), anotherChild); + QCOMPARE(anotherChild->row(), row); + QCOMPARE(anotherChild->column(), column); + item.setChild(row, column, 0); + } else { + delete child; + } + QCOMPARE(item.child(row, column), static_cast<QStandardItem*>(0)); +} + +void tst_QStandardItem::parent() +{ + { + QStandardItem item; + QStandardItem *child = new QStandardItem; + QCOMPARE(child->parent(), static_cast<QStandardItem*>(0)); + item.setChild(0, 0, child); + QCOMPARE(child->parent(), &item); + + QStandardItem *childOfChild = new QStandardItem; + child->setChild(0, 0, childOfChild); + QCOMPARE(childOfChild->parent(), child); + } + + { + QStandardItemModel model; + QStandardItem *item = new QStandardItem; + model.appendRow(item); + // parent of a top-level item should be 0 + QCOMPARE(item->parent(), static_cast<QStandardItem*>(0)); + } +} + +void tst_QStandardItem::insertColumn_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("column"); + QTest::addColumn<int>("count"); + + QTest::newRow("insert 0 at -1 in 0x0") << 0 << 0 << -1 << 0; + QTest::newRow("insert 0 at 0 in 0x0") << 0 << 0 << 0 << 0; + QTest::newRow("insert 0 at 0 in 1x0") << 1 << 0 << 0 << 0; + QTest::newRow("insert 0 at 0 in 0x1") << 0 << 1 << 0 << 0; + QTest::newRow("insert 0 at 0 in 1x1") << 1 << 1 << 0 << 0; + QTest::newRow("insert 1 at -1 in 0x0") << 0 << 0 << -1 << 1; + QTest::newRow("insert 1 at 0 in 0x0") << 0 << 0 << 0 << 1; + QTest::newRow("insert 1 at 0 in 1x0") << 1 << 0 << 0 << 1; + QTest::newRow("insert 1 at 0 in 0x1") << 0 << 1 << 0 << 1; + QTest::newRow("insert 1 at 0 in 1x1") << 1 << 1 << 0 << 1; + QTest::newRow("insert 1 at 1 in 1x1") << 1 << 1 << 1 << 1; + QTest::newRow("insert 1 at 0 in 2x1") << 2 << 1 << 0 << 1; + QTest::newRow("insert 1 at 1 in 2x1") << 2 << 1 << 1 << 1; + QTest::newRow("insert 1 at 0 in 1x2") << 1 << 2 << 0 << 1; + QTest::newRow("insert 1 at 1 in 1x2") << 1 << 2 << 1 << 1; + QTest::newRow("insert 1 at 0 in 8x4") << 8 << 4 << 0 << 1; + QTest::newRow("insert 1 at 1 in 8x4") << 8 << 4 << 1 << 1; + QTest::newRow("insert 1 at 2 in 8x4") << 8 << 4 << 2 << 1; + QTest::newRow("insert 1 at 3 in 8x4") << 8 << 4 << 3 << 1; + QTest::newRow("insert 1 at 4 in 8x4") << 8 << 4 << 4 << 1; + QTest::newRow("insert 4 at 0 in 8x4") << 8 << 4 << 0 << 4; + QTest::newRow("insert 4 at 4 in 8x4") << 8 << 4 << 4 << 4; + QTest::newRow("insert 6 at 0 in 8x4") << 8 << 4 << 0 << 6; + QTest::newRow("insert 6 at 4 in 8x4") << 8 << 4 << 4 << 6; +} + +void tst_QStandardItem::insertColumn() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, column); + QFETCH(int, count); + + QStandardItem item(rows, columns); + + // make items for a new column + QList<QStandardItem*> columnItems; + for (int i = 0; i < count; ++i) + columnItems.append(new QStandardItem); + + item.insertColumn(column, columnItems); + + if (column >= 0) { + QCOMPARE(item.columnCount(), columns + 1); + QCOMPARE(item.rowCount(), qMax(rows, count)); + // check to make sure items were inserted in correct place + for (int i = 0; i < count; ++i) + QCOMPARE(item.child(i, column), columnItems.at(i)); + for (int i = count; i < item.rowCount(); ++i) + QCOMPARE(item.child(i, column), static_cast<QStandardItem*>(0)); + } else { + QCOMPARE(item.columnCount(), columns); + QCOMPARE(item.rowCount(), rows); + qDeleteAll(columnItems); + } +} + +void tst_QStandardItem::insertColumns_data() +{ +} + +void tst_QStandardItem::insertColumns() +{ +} + +void tst_QStandardItem::insertRow_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("row"); + QTest::addColumn<int>("count"); + + QTest::newRow("insert 0 at -1 in 0x0") << 0 << 0 << -1 << 0; + QTest::newRow("insert 0 at 0 in 0x0") << 0 << 0 << 0 << 0; + QTest::newRow("insert 0 at 0 in 1x0") << 1 << 0 << 0 << 0; + QTest::newRow("insert 0 at 0 in 0x1") << 0 << 1 << 0 << 0; + QTest::newRow("insert 0 at 0 in 1x1") << 1 << 1 << 0 << 0; + QTest::newRow("insert 1 at -1 in 0x0") << 0 << 0 << -1 << 1; + QTest::newRow("insert 1 at 0 in 0x0") << 0 << 0 << 0 << 1; + QTest::newRow("insert 1 at 0 in 1x0") << 1 << 0 << 0 << 1; + QTest::newRow("insert 1 at 0 in 0x1") << 0 << 1 << 0 << 1; + QTest::newRow("insert 1 at 0 in 1x1") << 1 << 1 << 0 << 1; + QTest::newRow("insert 1 at 1 in 1x1") << 1 << 1 << 1 << 1; + QTest::newRow("insert 1 at 0 in 2x1") << 2 << 1 << 0 << 1; + QTest::newRow("insert 1 at 1 in 2x1") << 2 << 1 << 1 << 1; + QTest::newRow("insert 1 at 0 in 1x2") << 1 << 2 << 0 << 1; + QTest::newRow("insert 1 at 1 in 1x2") << 1 << 2 << 1 << 1; + QTest::newRow("insert 1 at 0 in 4x8") << 4 << 8 << 0 << 1; + QTest::newRow("insert 1 at 1 in 4x8") << 4 << 8 << 1 << 1; + QTest::newRow("insert 1 at 2 in 4x8") << 4 << 8 << 2 << 1; + QTest::newRow("insert 1 at 3 in 4x8") << 4 << 8 << 3 << 1; + QTest::newRow("insert 1 at 4 in 4x8") << 4 << 8 << 4 << 1; + QTest::newRow("insert 4 at 0 in 4x8") << 4 << 8 << 0 << 4; + QTest::newRow("insert 4 at 4 in 4x8") << 4 << 8 << 4 << 4; + QTest::newRow("insert 6 at 0 in 4x8") << 4 << 8 << 0 << 6; + QTest::newRow("insert 6 at 4 in 4x8") << 4 << 8 << 4 << 6; +} + +void tst_QStandardItem::insertRow() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, row); + QFETCH(int, count); + + QStandardItem item(rows, columns); + + // make items for a new column + QList<QStandardItem*> rowItems; + for (int i = 0; i < count; ++i) + rowItems.append(new QStandardItem); + + item.insertRow(row, rowItems); + + if (row >= 0) { + QCOMPARE(item.columnCount(), qMax(columns, count)); + QCOMPARE(item.rowCount(), rows + 1); + // check to make sure items were inserted in correct place + for (int i = 0; i < count; ++i) + QCOMPARE(item.child(row, i), rowItems.at(i)); + for (int i = count; i < item.columnCount(); ++i) + QCOMPARE(item.child(row, i), static_cast<QStandardItem*>(0)); + } else { + QCOMPARE(item.columnCount(), columns); + QCOMPARE(item.rowCount(), rows); + qDeleteAll(rowItems); + } +} + +void tst_QStandardItem::insertRows_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("insertAt"); + QTest::addColumn<int>("insertCount"); + + QTest::newRow("insert {0,1} at 0 in 0x0") << 0 << 0 << 0 << 2; +} + +void tst_QStandardItem::insertRows() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, insertAt); + QFETCH(int, insertCount); + + QStandardItem item(rows, columns); + + QList<QStandardItem*> items; + for (int i = 0; i < insertCount; ++i) { + items.append(new QStandardItem()); + } + item.insertRows(insertAt, items); + + QCOMPARE(item.rowCount(), rows + insertCount); +} + +void tst_QStandardItem::appendColumn_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("count"); + + QTest::newRow("append 0 to 0x0") << 0 << 0 << 0; + QTest::newRow("append 1 to 0x0") << 0 << 0 << 1; + QTest::newRow("append 1 to 1x0") << 1 << 0 << 1; + QTest::newRow("append 1 to 0x1") << 0 << 1 << 1; + QTest::newRow("append 1 to 1x1") << 1 << 1 << 1; + QTest::newRow("append 1 to 2x0") << 2 << 0 << 1; + QTest::newRow("append 1 to 0x2") << 0 << 2 << 1; + QTest::newRow("append 1 to 2x1") << 2 << 1 << 1; + QTest::newRow("append 1 to 1x2") << 1 << 2 << 1; + QTest::newRow("append 1 to 2x2") << 2 << 2 << 1; + QTest::newRow("append 2 to 0x0") << 0 << 0 << 2; + QTest::newRow("append 2 to 1x0") << 1 << 0 << 2; + QTest::newRow("append 2 to 0x1") << 0 << 1 << 2; + QTest::newRow("append 2 to 1x1") << 1 << 1 << 2; + QTest::newRow("append 2 to 2x0") << 2 << 0 << 2; + QTest::newRow("append 2 to 0x2") << 0 << 2 << 2; + QTest::newRow("append 2 to 2x1") << 2 << 1 << 2; + QTest::newRow("append 2 to 1x2") << 1 << 2 << 2; + QTest::newRow("append 2 to 2x2") << 2 << 2 << 2; + QTest::newRow("append 3 to 2x1") << 2 << 1 << 3; + QTest::newRow("append 3 to 1x2") << 1 << 2 << 3; + QTest::newRow("append 3 to 2x2") << 2 << 2 << 3; + QTest::newRow("append 3 to 4x2") << 4 << 2 << 3; + QTest::newRow("append 3 to 2x4") << 2 << 4 << 3; + QTest::newRow("append 3 to 4x4") << 4 << 4 << 3; + QTest::newRow("append 7 to 4x2") << 4 << 2 << 7; + QTest::newRow("append 7 to 2x4") << 2 << 4 << 7; + QTest::newRow("append 7 to 4x4") << 4 << 4 << 7; +} + +void tst_QStandardItem::appendColumn() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, count); + + QStandardItem item(rows, columns); + QList<QStandardItem*> originalChildren; + // initialize children + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + QStandardItem *child = new QStandardItem; + originalChildren.append(child); + item.setChild(i, j, child); + } + } + + // make items for a new column + QList<QStandardItem*> columnItems; + for (int i = 0; i < count; ++i) + columnItems.append(new QStandardItem); + + item.appendColumn(columnItems); + + QCOMPARE(item.columnCount(), columns + 1); + QCOMPARE(item.rowCount(), qMax(rows, count)); + // check to make sure items were inserted in correct place + for (int i = 0; i < count; ++i) + QCOMPARE(item.child(i, columns), columnItems.at(i)); + for (int i = count; i < item.rowCount(); ++i) + QCOMPARE(item.child(i, columns), static_cast<QStandardItem*>(0)); + + // make sure original children remained unchanged + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) + QCOMPARE(item.child(i, j), originalChildren.at(i*columns+j)); + } +} + +void tst_QStandardItem::appendRow_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("count"); + + QTest::newRow("append 0 to 0x0") << 0 << 0 << 0; + QTest::newRow("append 1 to 0x0") << 0 << 0 << 1; + QTest::newRow("append 1 to 1x0") << 1 << 0 << 1; + QTest::newRow("append 1 to 0x1") << 0 << 1 << 1; + QTest::newRow("append 1 to 1x1") << 1 << 1 << 1; + QTest::newRow("append 1 to 2x0") << 2 << 0 << 1; + QTest::newRow("append 1 to 0x2") << 0 << 2 << 1; + QTest::newRow("append 1 to 2x1") << 2 << 1 << 1; + QTest::newRow("append 1 to 1x2") << 1 << 2 << 1; + QTest::newRow("append 1 to 2x2") << 2 << 2 << 1; + QTest::newRow("append 2 to 0x0") << 0 << 0 << 2; + QTest::newRow("append 2 to 1x0") << 1 << 0 << 2; + QTest::newRow("append 2 to 0x1") << 0 << 1 << 2; + QTest::newRow("append 2 to 1x1") << 1 << 1 << 2; + QTest::newRow("append 2 to 2x0") << 2 << 0 << 2; + QTest::newRow("append 2 to 0x2") << 0 << 2 << 2; + QTest::newRow("append 2 to 2x1") << 2 << 1 << 2; + QTest::newRow("append 2 to 1x2") << 1 << 2 << 2; + QTest::newRow("append 2 to 2x2") << 2 << 2 << 2; + QTest::newRow("append 3 to 2x1") << 2 << 1 << 3; + QTest::newRow("append 3 to 1x2") << 1 << 2 << 3; + QTest::newRow("append 3 to 2x2") << 2 << 2 << 3; + QTest::newRow("append 3 to 4x2") << 4 << 2 << 3; + QTest::newRow("append 3 to 2x4") << 2 << 4 << 3; + QTest::newRow("append 3 to 4x4") << 4 << 4 << 3; + QTest::newRow("append 7 to 4x2") << 4 << 2 << 7; + QTest::newRow("append 7 to 2x4") << 2 << 4 << 7; + QTest::newRow("append 7 to 4x4") << 4 << 4 << 7; +} + +void tst_QStandardItem::appendRow() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, count); + + QStandardItem item(rows, columns); + QList<QStandardItem*> originalChildren; + // initialize children + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + QStandardItem *child = new QStandardItem; + originalChildren.append(child); + item.setChild(i, j, child); + } + } + + // make items for a new row + QList<QStandardItem*> rowItems; + for (int i = 0; i < count; ++i) + rowItems.append(new QStandardItem); + + item.appendRow(rowItems); + + QCOMPARE(item.rowCount(), rows + 1); + QCOMPARE(item.columnCount(), qMax(columns, count)); + // check to make sure items were inserted in correct place + for (int i = 0; i < count; ++i) + QCOMPARE(item.child(rows, i), rowItems.at(i)); + for (int i = count; i < item.columnCount(); ++i) + QCOMPARE(item.child(rows, i), static_cast<QStandardItem*>(0)); + + // make sure original children remained unchanged + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) + QCOMPARE(item.child(i, j), originalChildren.at(i*columns+j)); + } +} + +void tst_QStandardItem::takeChild() +{ + QList<QStandardItem*> itemList; + for (int i = 0; i < 10; ++i) + itemList.append(new QStandardItem); + QStandardItem item; + item.appendColumn(itemList); + + for (int i = 0; i < item.rowCount(); ++i) { + QCOMPARE(item.takeChild(i), itemList.at(i)); + QCOMPARE(item.takeChild(0, 0), static_cast<QStandardItem*>(0)); + for (int j = i + 1; j < item.rowCount(); ++j) + QCOMPARE(item.child(j), itemList.at(j)); + } + qDeleteAll(itemList); +} + +void tst_QStandardItem::takeColumn_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("column"); + QTest::addColumn<bool>("expectSuccess"); + + QTest::newRow("take -1 from 0x0") << 0 << 0 << -1 << false; + QTest::newRow("take 0 from 0x0") << 0 << 0 << 0 << false; + QTest::newRow("take 0 from 1x0") << 1 << 0 << 0 << false; + QTest::newRow("take 0 from 0x1") << 0 << 1 << 0 << true; + QTest::newRow("take 1 from 0x1") << 0 << 1 << 1 << false; + QTest::newRow("take 0 from 1x1") << 1 << 1 << 0 << true; + QTest::newRow("take 1 from 1x1") << 0 << 1 << 1 << false; + QTest::newRow("take 0 from 4x1") << 4 << 1 << 0 << true; + QTest::newRow("take 1 from 4x1") << 4 << 1 << 1 << false; + QTest::newRow("take 0 from 4x8") << 4 << 8 << 0 << true; + QTest::newRow("take 7 from 4x8") << 4 << 8 << 7 << true; + QTest::newRow("take 8 from 4x8") << 4 << 8 << 8 << false; +} + +void tst_QStandardItem::takeColumn() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, column); + QFETCH(bool, expectSuccess); + + QStandardItem item(rows, columns); + QList<QStandardItem*> originalChildren; + // initialize children + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + QStandardItem *child = new QStandardItem; + originalChildren.append(child); + item.setChild(i, j, child); + } + } + + QList<QStandardItem *> taken = item.takeColumn(column); + if (expectSuccess) { + QCOMPARE(taken.count(), item.rowCount()); + QCOMPARE(item.columnCount(), columns - 1); + int index = column; + for (int i = 0; i < taken.count(); ++i) { + QCOMPARE(taken.at(i), originalChildren.takeAt(index)); + index += item.columnCount(); + } + index = 0; + for (int i = 0; i < item.rowCount(); ++i) { + for (int j = 0; j < item.columnCount(); ++j) { + QCOMPARE(item.child(i, j), originalChildren.at(index)); + ++index; + } + } + } else { + QVERIFY(taken.isEmpty()); + } + qDeleteAll(taken); +} + +void tst_QStandardItem::takeRow_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("row"); + QTest::addColumn<bool>("expectSuccess"); + + QTest::newRow("take -1 from 0x0") << 0 << 0 << -1 << false; + QTest::newRow("take 0 from 0x0") << 0 << 0 << 0 << false; + QTest::newRow("take 0 from 1x0") << 1 << 0 << 0 << true; + QTest::newRow("take 0 from 0x1") << 0 << 1 << 0 << false; + QTest::newRow("take 1 from 0x1") << 0 << 1 << 1 << false; + QTest::newRow("take 0 from 1x1") << 1 << 1 << 0 << true; + QTest::newRow("take 1 from 1x1") << 0 << 1 << 1 << false; + QTest::newRow("take 0 from 1x4") << 1 << 4 << 0 << true; + QTest::newRow("take 1 from 1x4") << 1 << 4 << 1 << false; + QTest::newRow("take 0 from 8x4") << 8 << 4 << 0 << true; + QTest::newRow("take 7 from 8x4") << 8 << 4 << 7 << true; + QTest::newRow("take 8 from 8x4") << 8 << 4 << 8 << false; +} + +void tst_QStandardItem::takeRow() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, row); + QFETCH(bool, expectSuccess); + + QStandardItem item(rows, columns); + QList<QStandardItem*> originalChildren; + // initialize children + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + QStandardItem *child = new QStandardItem; + originalChildren.append(child); + item.setChild(i, j, child); + } + } + + QList<QStandardItem *> taken = item.takeRow(row); + if (expectSuccess) { + QCOMPARE(taken.count(), item.columnCount()); + QCOMPARE(item.rowCount(), rows - 1); + int index = row * columns; + for (int i = 0; i < taken.count(); ++i) { + QCOMPARE(taken.at(i), originalChildren.takeAt(index)); + } + index = 0; + for (int i = 0; i < item.rowCount(); ++i) { + for (int j = 0; j < item.columnCount(); ++j) { + QCOMPARE(item.child(i, j), originalChildren.at(index)); + ++index; + } + } + } else { + QVERIFY(taken.isEmpty()); + } + qDeleteAll(taken); +} + +void tst_QStandardItem::streamItem() +{ + QStandardItem item; + + item.setText(QLatin1String("text")); + item.setToolTip(QLatin1String("toolTip")); + item.setStatusTip(QLatin1String("statusTip")); + item.setWhatsThis(QLatin1String("whatsThis")); + item.setSizeHint(QSize(64, 48)); + item.setFont(QFont()); + item.setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter); + item.setBackground(QColor(Qt::blue)); + item.setForeground(QColor(Qt::green)); + item.setCheckState(Qt::PartiallyChecked); + item.setAccessibleText(QLatin1String("accessibleText")); + item.setAccessibleDescription(QLatin1String("accessibleDescription")); + + QByteArray ba; + { + QDataStream ds(&ba, QIODevice::WriteOnly); + ds << item; + } + { + QStandardItem streamedItem; + QDataStream ds(&ba, QIODevice::ReadOnly); + ds >> streamedItem; + QCOMPARE(streamedItem.text(), item.text()); + QCOMPARE(streamedItem.toolTip(), item.toolTip()); + QCOMPARE(streamedItem.statusTip(), item.statusTip()); + QCOMPARE(streamedItem.whatsThis(), item.whatsThis()); + QCOMPARE(streamedItem.sizeHint(), item.sizeHint()); + QCOMPARE(streamedItem.font(), item.font()); + QCOMPARE(streamedItem.textAlignment(), item.textAlignment()); + QCOMPARE(streamedItem.background(), item.background()); + QCOMPARE(streamedItem.foreground(), item.foreground()); + QCOMPARE(streamedItem.checkState(), item.checkState()); + QCOMPARE(streamedItem.accessibleText(), item.accessibleText()); + QCOMPARE(streamedItem.accessibleDescription(), item.accessibleDescription()); + QCOMPARE(streamedItem.flags(), item.flags()); + } +} + +void tst_QStandardItem::deleteItem() +{ + QStandardItemModel model(4, 6); + // initialize items + for (int i = 0; i < model.rowCount(); ++i) { + for (int j = 0; j < model.columnCount(); ++j) { + QStandardItem *item = new QStandardItem(); + model.setItem(i, j, item); + } + } + // delete items + for (int i = 0; i < model.rowCount(); ++i) { + for (int j = 0; j < model.columnCount(); ++j) { + QStandardItem *item = model.item(i, j); + delete item; + QCOMPARE(model.item(i, j), static_cast<QStandardItem*>(0)); + } + } +} + +void tst_QStandardItem::clone() +{ + QStandardItem item; + item.setText(QLatin1String("text")); + item.setToolTip(QLatin1String("toolTip")); + item.setStatusTip(QLatin1String("statusTip")); + item.setWhatsThis(QLatin1String("whatsThis")); + item.setSizeHint(QSize(64, 48)); + item.setFont(QFont()); + item.setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter); + item.setBackground(QColor(Qt::blue)); + item.setForeground(QColor(Qt::green)); + item.setCheckState(Qt::PartiallyChecked); + item.setAccessibleText(QLatin1String("accessibleText")); + item.setAccessibleDescription(QLatin1String("accessibleDescription")); + item.setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); + + QStandardItem *clone = item.clone(); + QCOMPARE(clone->text(), item.text()); + QCOMPARE(clone->toolTip(), item.toolTip()); + QCOMPARE(clone->statusTip(), item.statusTip()); + QCOMPARE(clone->whatsThis(), item.whatsThis()); + QCOMPARE(clone->sizeHint(), item.sizeHint()); + QCOMPARE(clone->font(), item.font()); + QCOMPARE(clone->textAlignment(), item.textAlignment()); + QCOMPARE(clone->background(), item.background()); + QCOMPARE(clone->foreground(), item.foreground()); + QCOMPARE(clone->checkState(), item.checkState()); + QCOMPARE(clone->accessibleText(), item.accessibleText()); + QCOMPARE(clone->accessibleDescription(), item.accessibleDescription()); + QCOMPARE(clone->flags(), item.flags()); + QVERIFY(!(*clone < item)); + delete clone; +} + +void tst_QStandardItem::sortChildren() +{ + for (int x = 0; x < 2; ++x) { + QStandardItemModel *model = new QStandardItemModel; + QStandardItem *item = (x == 0) ? new QStandardItem : model->invisibleRootItem(); + QStandardItem *one = new QStandardItem; + one->appendRow(new QStandardItem(QLatin1String("a"))); + one->appendRow(new QStandardItem(QLatin1String("b"))); + one->appendRow(new QStandardItem(QLatin1String("c"))); + QStandardItem *two = new QStandardItem; + two->appendRow(new QStandardItem(QLatin1String("f"))); + two->appendRow(new QStandardItem(QLatin1String("d"))); + two->appendRow(new QStandardItem(QLatin1String("e"))); + item->appendRow(one); + item->appendRow(two); + + QSignalSpy layoutAboutToBeChangedSpy( + model, SIGNAL(layoutAboutToBeChanged())); + QSignalSpy layoutChangedSpy( + model, SIGNAL(layoutChanged())); + + one->sortChildren(0, Qt::DescendingOrder); + // verify sorted + QCOMPARE(one->child(0)->text(), QLatin1String("c")); + QCOMPARE(one->child(1)->text(), QLatin1String("b")); + QCOMPARE(one->child(2)->text(), QLatin1String("a")); + // verify siblings unaffected + QCOMPARE(two->child(0)->text(), QLatin1String("f")); + QCOMPARE(two->child(1)->text(), QLatin1String("d")); + QCOMPARE(two->child(2)->text(), QLatin1String("e")); + + two->sortChildren(0, Qt::AscendingOrder); + // verify sorted + QCOMPARE(two->child(0)->text(), QLatin1String("d")); + QCOMPARE(two->child(1)->text(), QLatin1String("e")); + QCOMPARE(two->child(2)->text(), QLatin1String("f")); + // verify siblings unaffected + QCOMPARE(one->child(0)->text(), QLatin1String("c")); + QCOMPARE(one->child(1)->text(), QLatin1String("b")); + QCOMPARE(one->child(2)->text(), QLatin1String("a")); + + item->sortChildren(0, Qt::AscendingOrder); + // verify everything sorted + QCOMPARE(one->child(0)->text(), QLatin1String("a")); + QCOMPARE(one->child(1)->text(), QLatin1String("b")); + QCOMPARE(one->child(2)->text(), QLatin1String("c")); + QCOMPARE(two->child(0)->text(), QLatin1String("d")); + QCOMPARE(two->child(1)->text(), QLatin1String("e")); + QCOMPARE(two->child(2)->text(), QLatin1String("f")); + + QCOMPARE(layoutAboutToBeChangedSpy.count(), (x == 0) ? 0 : 3); + QCOMPARE(layoutChangedSpy.count(), (x == 0) ? 0 : 3); + + if (x == 0) + delete item; + delete model; + } +} + +class CustomItem : public QStandardItem +{ +public: + CustomItem(const QString &text) : QStandardItem(text) { } + CustomItem() { } + virtual ~CustomItem() { } + + virtual int type() const { return QStandardItem::UserType + 1; } + + virtual QStandardItem *clone() const { return QStandardItem::clone(); } + + void emitDataChanged() { QStandardItem::emitDataChanged(); } + + virtual bool operator<(const QStandardItem &other) const { + return text().length() < other.text().length(); + } +}; + +Q_DECLARE_METATYPE(QStandardItem*) + +void tst_QStandardItem::subclassing() +{ + qMetaTypeId<QStandardItem*>(); + + CustomItem *item = new CustomItem; + QCOMPARE(item->type(), int(QStandardItem::UserType + 1)); + + item->setText(QString::fromLatin1("foo")); + QCOMPARE(item->text(), QString::fromLatin1("foo")); + + item->emitDataChanged(); // does nothing + + QStandardItemModel model; + model.appendRow(item); + + QSignalSpy itemChangedSpy(&model, SIGNAL(itemChanged(QStandardItem*))); + item->emitDataChanged(); + QCOMPARE(itemChangedSpy.count(), 1); + QCOMPARE(itemChangedSpy.at(0).count(), 1); + QCOMPARE(qvariant_cast<QStandardItem*>(itemChangedSpy.at(0).at(0)), (QStandardItem*)item); + + CustomItem *child0 = new CustomItem("cc"); + CustomItem *child1 = new CustomItem("bbb"); + CustomItem *child2 = new CustomItem("a"); + item->appendRow(child0); + item->appendRow(child1); + item->appendRow(child2); + item->sortChildren(0); + QCOMPARE(item->child(0), (QStandardItem*)child2); + QCOMPARE(item->child(1), (QStandardItem*)child0); + QCOMPARE(item->child(2), (QStandardItem*)child1); +} + +QTEST_MAIN(tst_QStandardItem) +#include "tst_qstandarditem.moc" diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/.gitignore b/tests/auto/gui/itemmodels/qstandarditemmodel/.gitignore new file mode 100644 index 0000000000..c218efce58 --- /dev/null +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/.gitignore @@ -0,0 +1 @@ +tst_qstandarditemmodel diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro b/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro new file mode 100644 index 0000000000..71ef4acb88 --- /dev/null +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/qstandarditemmodel.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +CONFIG += parallel_test +TARGET = tst_qstandarditemmodel + +QT += widgets widgets-private testlib +QT += core-private gui-private + +SOURCES += tst_qstandarditemmodel.cpp + + diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp new file mode 100644 index 0000000000..1c661f9060 --- /dev/null +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp @@ -0,0 +1,1683 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qstandarditemmodel.h> +#include <QTreeView> +#include <private/qtreeview_p.h> + +class tst_QStandardItemModel : public QObject +{ + Q_OBJECT + +public: + tst_QStandardItemModel(); + virtual ~tst_QStandardItemModel(); + + enum ModelChanged { + RowsAboutToBeInserted, + RowsInserted, + RowsAboutToBeRemoved, + RowsRemoved, + ColumnsAboutToBeInserted, + ColumnsInserted, + ColumnsAboutToBeRemoved, + ColumnsRemoved + }; + +public slots: + void init(); + void cleanup(); + +protected slots: + void checkAboutToBeRemoved(); + void checkRemoved(); + void updateRowAboutToBeRemoved(); + + void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last) + { modelChanged(RowsAboutToBeInserted, parent, first, last); } + void rowsInserted(const QModelIndex &parent, int first, int last) + { modelChanged(RowsInserted, parent, first, last); } + void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) + { modelChanged(RowsAboutToBeRemoved, parent, first, last); } + void rowsRemoved(const QModelIndex &parent, int first, int last) + { modelChanged(RowsRemoved, parent, first, last); } + void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last) + { modelChanged(ColumnsAboutToBeInserted, parent, first, last); } + void columnsInserted(const QModelIndex &parent, int first, int last) + { modelChanged(ColumnsInserted, parent, first, last); } + void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) + { modelChanged(ColumnsAboutToBeRemoved, parent, first, last); } + void columnsRemoved(const QModelIndex &parent, int first, int last) + { modelChanged(ColumnsRemoved, parent, first, last); } + + void modelChanged(ModelChanged change, const QModelIndex &parent, int first, int last); + +private slots: + void insertRow_data(); + void insertRow(); + void insertRows(); + void insertRowsItems(); + void insertRowInHierarcy(); + void insertColumn_data(); + void insertColumn(); + void insertColumns(); + void removeRows(); + void removeColumns(); + void setHeaderData(); + void persistentIndexes(); + void removingPersistentIndexes(); + void updatingPersistentIndexes(); + + void checkChildren(); + void data(); + void clear(); + void sort_data(); + void sort(); + void sortRole_data(); + void sortRole(); + void findItems(); + void getSetHeaderItem(); + void indexFromItem(); + void itemFromIndex(); + void getSetItemPrototype(); + void getSetItemData(); + void setHeaderLabels_data(); + void setHeaderLabels(); + void itemDataChanged(); + void takeHeaderItem(); + void useCase1(); + void useCase2(); + void useCase3(); + + void rootItemFlags(); + void treeDragAndDrop(); + void removeRowsAndColumns(); + + void itemRoleNames(); + +private: + QAbstractItemModel *m_model; + QPersistentModelIndex persistent; + QVector<QModelIndex> rcParent; + QVector<int> rcFirst; + QVector<int> rcLast; + + //return true if models have the same structure, and all child have the same text + bool compareModels(QStandardItemModel *model1, QStandardItemModel *model2); + //return true if models have the same structure, and all child have the same text + bool compareItems(QStandardItem *item1, QStandardItem *item2); +}; + +static const int defaultSize = 3; + +Q_DECLARE_METATYPE(QModelIndex) +Q_DECLARE_METATYPE(QStandardItem*) +Q_DECLARE_METATYPE(Qt::Orientation) +Q_DECLARE_METATYPE(QVariantList) + +tst_QStandardItemModel::tst_QStandardItemModel() : m_model(0), rcParent(8), rcFirst(8,0), rcLast(8,0) +{ +} + +tst_QStandardItemModel::~tst_QStandardItemModel() +{ +} + +/* + This test usually uses a model with a 3x3 table + --------------------------- + | 0,0 | 0,1 | 0,2 | + --------------------------- + | 1,0 | 1,1 | 1,2 | + --------------------------- + | 2,0 | 2,1 | 2,2 | + --------------------------- +*/ +void tst_QStandardItemModel::init() +{ + qRegisterMetaType<QModelIndex>("QModelIndex"); + qRegisterMetaType<QStandardItem*>("QStandardItem*"); + qRegisterMetaType<Qt::Orientation>("Qt::Orientation"); + + m_model = new QStandardItemModel(defaultSize, defaultSize); + connect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), + this, SLOT(rowsAboutToBeInserted(QModelIndex, int, int))); + connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(rowsInserted(QModelIndex, int, int))); + connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), + this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int))); + connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), + this, SLOT(rowsRemoved(QModelIndex, int, int))); + + connect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), + this, SLOT(columnsAboutToBeInserted(QModelIndex, int, int))); + connect(m_model, SIGNAL(columnsInserted(QModelIndex, int, int)), + this, SLOT(columnsInserted(QModelIndex, int, int))); + connect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + this, SLOT(columnsAboutToBeRemoved(QModelIndex, int, int))); + connect(m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)), + this, SLOT(columnsRemoved(QModelIndex, int, int))); + + rcFirst.fill(-1); + rcLast.fill(-1); +} + +void tst_QStandardItemModel::cleanup() +{ + disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), + this, SLOT(rowsAboutToBeInserted(QModelIndex, int, int))); + disconnect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(rowsInserted(QModelIndex, int, int))); + disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), + this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int))); + disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), + this, SLOT(rowsRemoved(QModelIndex, int, int))); + + disconnect(m_model, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), + this, SLOT(columnsAboutToBeInserted(QModelIndex, int, int))); + disconnect(m_model, SIGNAL(columnsInserted(QModelIndex, int, int)), + this, SLOT(columnsInserted(QModelIndex, int, int))); + disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + this, SLOT(columnsAboutToBeRemoved(QModelIndex, int, int))); + disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)), + this, SLOT(columnsRemoved(QModelIndex, int, int))); + delete m_model; + m_model = 0; +} + +void tst_QStandardItemModel::insertRow_data() +{ + QTest::addColumn<int>("insertRow"); + QTest::addColumn<int>("expectedRow"); + + QTest::newRow("Insert less then 0") << -1 << 0; + QTest::newRow("Insert at 0") << 0 << 0; + QTest::newRow("Insert beyond count") << defaultSize+1 << defaultSize; + QTest::newRow("Insert at count") << defaultSize << defaultSize; + QTest::newRow("Insert in the middle") << 1 << 1; +} + +void tst_QStandardItemModel::insertRow() +{ + QFETCH(int, insertRow); + QFETCH(int, expectedRow); + + QIcon icon; + // default all initial items to DisplayRole: "initalitem" + for (int r=0; r < m_model->rowCount(); ++r) { + for (int c=0; c < m_model->columnCount(); ++c) { + m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole); + } + } + + // check that inserts changes rowCount + QCOMPARE(m_model->rowCount(), defaultSize); + m_model->insertRow(insertRow); + if (insertRow >= 0 && insertRow <= defaultSize) { + QCOMPARE(m_model->rowCount(), defaultSize + 1); + + // check that signals were emitted with correct info + QCOMPARE(rcFirst[RowsAboutToBeInserted], expectedRow); + QCOMPARE(rcLast[RowsAboutToBeInserted], expectedRow); + QCOMPARE(rcFirst[RowsInserted], expectedRow); + QCOMPARE(rcLast[RowsInserted], expectedRow); + + //check that the inserted item has different DisplayRole than initial items + QVERIFY(m_model->data(m_model->index(expectedRow, 0), Qt::DisplayRole).toString() != "initialitem"); + } else { + // We inserted something outside the bounds, do nothing + QCOMPARE(m_model->rowCount(), defaultSize); + QCOMPARE(rcFirst[RowsAboutToBeInserted], -1); + QCOMPARE(rcLast[RowsAboutToBeInserted], -1); + QCOMPARE(rcFirst[RowsInserted], -1); + QCOMPARE(rcLast[RowsInserted], -1); + } +} + +void tst_QStandardItemModel::insertRows() +{ + int rowCount = m_model->rowCount(); + QCOMPARE(rowCount, defaultSize); + + // insert custom header label + QString headerLabel = "custom"; + m_model->setHeaderData(0, Qt::Vertical, headerLabel); + + // insert one row + m_model->insertRows(0, 1); + QCOMPARE(m_model->rowCount(), rowCount + 1); + rowCount = m_model->rowCount(); + + // check header data has moved + QCOMPARE(m_model->headerData(1, Qt::Vertical).toString(), headerLabel); + + // insert two rows + m_model->insertRows(0, 2); + QCOMPARE(m_model->rowCount(), rowCount + 2); + + // check header data has moved + QCOMPARE(m_model->headerData(3, Qt::Vertical).toString(), headerLabel); +} + +void tst_QStandardItemModel::insertRowsItems() +{ + int rowCount = m_model->rowCount(); + + QList<QStandardItem *> items; + QStandardItemModel *m = qobject_cast<QStandardItemModel*>(m_model); + QStandardItem *hiddenRoot = m->invisibleRootItem(); + for (int i = 0; i < 3; ++i) + items.append(new QStandardItem(QString("%1").arg(i + 10))); + hiddenRoot->appendRows(items); + QCOMPARE(m_model->rowCount(), rowCount + 3); + QCOMPARE(m_model->index(rowCount + 0, 0).data().toInt(), 10); + QCOMPARE(m_model->index(rowCount + 1, 0).data().toInt(), 11); + QCOMPARE(m_model->index(rowCount + 2, 0).data().toInt(), 12); + for (int i = rowCount; i < rowCount + 3; ++i) { + QVERIFY(m->item(i)); + QCOMPARE(static_cast<QAbstractItemModel *>(m->item(i)->model()), m_model); + } +} + +void tst_QStandardItemModel::insertRowInHierarcy() +{ + QVERIFY(m_model->insertRows(0, 1, QModelIndex())); + QVERIFY(m_model->insertColumns(0, 1, QModelIndex())); + QVERIFY(m_model->hasIndex(0, 0, QModelIndex())); + + QModelIndex parent = m_model->index(0, 0, QModelIndex()); + QVERIFY(parent.isValid()); + + QVERIFY(m_model->insertRows(0, 1, parent)); + QVERIFY(m_model->insertColumns(0, 1, parent)); + QVERIFY(m_model->hasIndex(0, 0, parent)); + + QModelIndex child = m_model->index(0, 0, parent); + QVERIFY(child.isValid()); +} + +void tst_QStandardItemModel::insertColumn_data() +{ + QTest::addColumn<int>("insertColumn"); + QTest::addColumn<int>("expectedColumn"); + + QTest::newRow("Insert less then 0") << -1 << 0; + QTest::newRow("Insert at 0") << 0 << 0; + QTest::newRow("Insert beyond count") << defaultSize+1 << defaultSize; + QTest::newRow("Insert at count") << defaultSize << defaultSize; + QTest::newRow("Insert in the middle") << 1 << 1; +} + +void tst_QStandardItemModel::insertColumn() +{ + QFETCH(int, insertColumn); + QFETCH(int, expectedColumn); + + // default all initial items to DisplayRole: "initalitem" + for (int r=0; r < m_model->rowCount(); ++r) { + for (int c=0; c < m_model->columnCount(); ++c) { + m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole); + } + } + + // check that inserts changes columnCount + QCOMPARE(m_model->columnCount(), defaultSize); + m_model->insertColumn(insertColumn); + if (insertColumn >= 0 && insertColumn <= defaultSize) { + QCOMPARE(m_model->columnCount(), defaultSize + 1); + // check that signals were emitted with correct info + QCOMPARE(rcFirst[ColumnsAboutToBeInserted], expectedColumn); + QCOMPARE(rcLast[ColumnsAboutToBeInserted], expectedColumn); + QCOMPARE(rcFirst[ColumnsInserted], expectedColumn); + QCOMPARE(rcLast[ColumnsInserted], expectedColumn); + + //check that the inserted item has different DisplayRole than initial items + QVERIFY(m_model->data(m_model->index(0, expectedColumn), Qt::DisplayRole).toString() != "initialitem"); + } else { + // We inserted something outside the bounds, do nothing + QCOMPARE(m_model->columnCount(), defaultSize); + QCOMPARE(rcFirst[ColumnsAboutToBeInserted], -1); + QCOMPARE(rcLast[ColumnsAboutToBeInserted], -1); + QCOMPARE(rcFirst[ColumnsInserted], -1); + QCOMPARE(rcLast[ColumnsInserted], -1); + } + +} + +void tst_QStandardItemModel::insertColumns() +{ + int columnCount = m_model->columnCount(); + QCOMPARE(columnCount, defaultSize); + + // insert custom header label + QString headerLabel = "custom"; + m_model->setHeaderData(0, Qt::Horizontal, headerLabel); + + // insert one column + m_model->insertColumns(0, 1); + QCOMPARE(m_model->columnCount(), columnCount + 1); + columnCount = m_model->columnCount(); + + // check header data has moved + QCOMPARE(m_model->headerData(1, Qt::Horizontal).toString(), headerLabel); + + // insert two columns + m_model->insertColumns(0, 2); + QCOMPARE(m_model->columnCount(), columnCount + 2); + + // check header data has moved + QCOMPARE(m_model->headerData(3, Qt::Horizontal).toString(), headerLabel); +} + +void tst_QStandardItemModel::removeRows() +{ + int rowCount = m_model->rowCount(); + QCOMPARE(rowCount, defaultSize); + + // insert custom header label + QString headerLabel = "custom"; + m_model->setHeaderData(rowCount - 1, Qt::Vertical, headerLabel); + + // remove one row + m_model->removeRows(0, 1); + QCOMPARE(m_model->rowCount(), rowCount - 1); + rowCount = m_model->rowCount(); + + // check header data has moved + QCOMPARE(m_model->headerData(rowCount - 1, Qt::Vertical).toString(), headerLabel); + + // remove two rows + m_model->removeRows(0, 2); + QCOMPARE(m_model->rowCount(), rowCount - 2); +} + +void tst_QStandardItemModel::removeColumns() +{ + int columnCount = m_model->columnCount(); + QCOMPARE(columnCount, defaultSize); + + // insert custom header label + QString headerLabel = "custom"; + m_model->setHeaderData(columnCount - 1, Qt::Horizontal, headerLabel); + + // remove one column + m_model->removeColumns(0, 1); + QCOMPARE(m_model->columnCount(), columnCount - 1); + columnCount = m_model->columnCount(); + + // check header data has moved + QCOMPARE(m_model->headerData(columnCount - 1, Qt::Horizontal).toString(), headerLabel); + + // remove two columns + m_model->removeColumns(0, 2); + QCOMPARE(m_model->columnCount(), columnCount - 2); +} + + +void tst_QStandardItemModel::setHeaderData() +{ + for (int x = 0; x < 2; ++x) { + bool vertical = (x == 0); + int count = vertical ? m_model->rowCount() : m_model->columnCount(); + QCOMPARE(count, defaultSize); + Qt::Orientation orient = vertical ? Qt::Vertical : Qt::Horizontal; + + // check default values are ok + for (int i = 0; i < count; ++i) + QCOMPARE(m_model->headerData(i, orient).toString(), QString::number(i + 1)); + + QSignalSpy headerDataChangedSpy( + m_model, SIGNAL(headerDataChanged(Qt::Orientation, int, int))); + QSignalSpy dataChangedSpy( + m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex))); + // insert custom values and check + for (int i = 0; i < count; ++i) { + QString customString = QString("custom") + QString::number(i); + QCOMPARE(m_model->setHeaderData(i, orient, customString), true); + QCOMPARE(headerDataChangedSpy.count(), 1); + QCOMPARE(dataChangedSpy.count(), 0); + QVariantList args = headerDataChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<Qt::Orientation>(args.at(0)), orient); + QCOMPARE(args.at(1).toInt(), i); + QCOMPARE(args.at(2).toInt(), i); + QCOMPARE(m_model->headerData(i, orient).toString(), customString); + QCOMPARE(m_model->setHeaderData(i, orient, customString), true); + QCOMPARE(headerDataChangedSpy.count(), 0); + QCOMPARE(dataChangedSpy.count(), 0); + } + + //check read from invalid sections + QVERIFY(!m_model->headerData(count, orient).isValid()); + QVERIFY(!m_model->headerData(-1, orient).isValid()); + //check write to invalid section + QCOMPARE(m_model->setHeaderData(count, orient, "foo"), false); + QCOMPARE(m_model->setHeaderData(-1, orient, "foo"), false); + QVERIFY(!m_model->headerData(count, orient).isValid()); + QVERIFY(!m_model->headerData(-1, orient).isValid()); + } +} + +void tst_QStandardItemModel::persistentIndexes() +{ + QCOMPARE(m_model->rowCount(), defaultSize); + QCOMPARE(m_model->columnCount(), defaultSize); + + // create a persisten index at 0,0 + QPersistentModelIndex persistentIndex(m_model->index(0, 0)); + + // verify it is ok and at the correct spot + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 0); + QCOMPARE(persistentIndex.column(), 0); + + // insert row and check that the persisten index has moved + QVERIFY(m_model->insertRow(0)); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 1); + QCOMPARE(persistentIndex.column(), 0); + + // insert row after the persisten index and see that it stays the same + QVERIFY(m_model->insertRow(m_model->rowCount())); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 1); + QCOMPARE(persistentIndex.column(), 0); + + // insert column and check that the persisten index has moved + QVERIFY(m_model->insertColumn(0)); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 1); + QCOMPARE(persistentIndex.column(), 1); + + // insert column after the persisten index and see that it stays the same + QVERIFY(m_model->insertColumn(m_model->columnCount())); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 1); + QCOMPARE(persistentIndex.column(), 1); + + // removes a row beyond the persistent index and see it stays the same + QVERIFY(m_model->removeRow(m_model->rowCount() - 1)); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 1); + QCOMPARE(persistentIndex.column(), 1); + + // removes a column beyond the persistent index and see it stays the same + QVERIFY(m_model->removeColumn(m_model->columnCount() - 1)); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 1); + QCOMPARE(persistentIndex.column(), 1); + + // removes a row before the persistent index and see it moves the same + QVERIFY(m_model->removeRow(0)); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 0); + QCOMPARE(persistentIndex.column(), 1); + + // removes a column before the persistent index and see it moves the same + QVERIFY(m_model->removeColumn(0)); + QVERIFY(persistentIndex.isValid()); + QCOMPARE(persistentIndex.row(), 0); + QCOMPARE(persistentIndex.column(), 0); + + // remove the row where the persistent index is, and see that it becomes invalid + QVERIFY(m_model->removeRow(0)); + QVERIFY(!persistentIndex.isValid()); + + // remove the row where the persistent index is, and see that it becomes invalid + persistentIndex = m_model->index(0, 0); + QVERIFY(persistentIndex.isValid()); + QVERIFY(m_model->removeColumn(0)); + QVERIFY(!persistentIndex.isValid()); +} + +void tst_QStandardItemModel::checkAboutToBeRemoved() +{ + QVERIFY(persistent.isValid()); +} + +void tst_QStandardItemModel::checkRemoved() +{ + QVERIFY(!persistent.isValid()); +} + +void tst_QStandardItemModel::removingPersistentIndexes() +{ + // add 10 rows and columns to model to make it big enough + QVERIFY(m_model->insertRows(0, 10)); + QVERIFY(m_model->insertColumns(0, 10)); + + QObject::connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(checkAboutToBeRemoved())); + QObject::connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(checkRemoved())); + QObject::connect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(checkAboutToBeRemoved())); + QObject::connect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), + this, SLOT(checkRemoved())); + + + // test removeRow + // add child table 3x3 to parent index(0, 0) + QVERIFY(m_model->insertRows(0, 3, m_model->index(0, 0))); + QVERIFY(m_model->insertColumns(0, 3, m_model->index(0, 0))); + + // set child to persistent and delete parent row + persistent = m_model->index(0, 0, m_model->index(0, 0)); + QVERIFY(persistent.isValid()); + QVERIFY(m_model->removeRow(0)); + + // set persistent to index(0, 0) and remove that row + persistent = m_model->index(0, 0); + QVERIFY(persistent.isValid()); + QVERIFY(m_model->removeRow(0)); + + + // test removeColumn + // add child table 3x3 to parent index (0, 0) + QVERIFY(m_model->insertRows(0, 3, m_model->index(0, 0))); + QVERIFY(m_model->insertColumns(0, 3, m_model->index(0, 0))); + + // set child to persistent and delete parent column + persistent = m_model->index(0, 0, m_model->index(0, 0)); + QVERIFY(persistent.isValid()); + QVERIFY(m_model->removeColumn(0)); + + // set persistent to index(0, 0) and remove that column + persistent = m_model->index(0, 0); + QVERIFY(persistent.isValid()); + QVERIFY(m_model->removeColumn(0)); + + + QObject::disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(checkAboutToBeRemoved())); + QObject::disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(checkRemoved())); + QObject::disconnect(m_model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(checkAboutToBeRemoved())); + QObject::disconnect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), + this, SLOT(checkRemoved())); +} + +void tst_QStandardItemModel::updateRowAboutToBeRemoved() +{ + QModelIndex idx = m_model->index(0, 0); + QVERIFY(idx.isValid()); + persistent = idx; +} + +void tst_QStandardItemModel::updatingPersistentIndexes() +{ + QObject::connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(updateRowAboutToBeRemoved())); + + persistent = m_model->index(1, 0); + QVERIFY(persistent.isValid()); + QVERIFY(m_model->removeRow(1)); + QVERIFY(persistent.isValid()); + QPersistentModelIndex tmp = m_model->index(0, 0); + QCOMPARE(persistent, tmp); + + QObject::disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), + this, SLOT(updateRowAboutToBeRemoved())); +} + +void tst_QStandardItemModel::modelChanged(ModelChanged change, const QModelIndex &parent, + int first, int last) +{ + rcParent[change] = parent; + rcFirst[change] = first; + rcLast[change] = last; +} + + +void tst_QStandardItemModel::checkChildren() +{ + QStandardItemModel model(0, 0); + QCOMPARE(model.rowCount(), 0); + QCOMPARE(model.columnCount(), 0); + QVERIFY(!model.hasChildren()); + + QVERIFY(model.insertRows(0, 1)); + QVERIFY(!model.hasChildren()); + QCOMPARE(model.rowCount(), 1); + QCOMPARE(model.columnCount(), 0); + + QVERIFY(model.insertColumns(0, 1)); + QVERIFY(model.hasChildren()); + QCOMPARE(model.rowCount(), 1); + QCOMPARE(model.columnCount(), 1); + + QModelIndex idx = model.index(0, 0); + QVERIFY(!model.hasChildren(idx)); + QCOMPARE(model.rowCount(idx), 0); + QCOMPARE(model.columnCount(idx), 0); + + QVERIFY(model.insertRows(0, 1, idx)); + QVERIFY(!model.hasChildren(idx)); + QCOMPARE(model.rowCount(idx), 1); + QCOMPARE(model.columnCount(idx), 0); + + QVERIFY(model.insertColumns(0, 1, idx)); + QVERIFY(model.hasChildren(idx)); + QCOMPARE(model.rowCount(idx), 1); + QCOMPARE(model.columnCount(idx), 1); + + QModelIndex idx2 = model.index(0, 0, idx); + QVERIFY(!model.hasChildren(idx2)); + QCOMPARE(model.rowCount(idx2), 0); + QCOMPARE(model.columnCount(idx2), 0); + + QVERIFY(model.removeRows(0, 1, idx)); + QVERIFY(model.hasChildren()); + QCOMPARE(model.rowCount(), 1); + QCOMPARE(model.columnCount(), 1); + QVERIFY(!model.hasChildren(idx)); + QCOMPARE(model.rowCount(idx), 0); + QCOMPARE(model.columnCount(idx), 1); + + QVERIFY(model.removeRows(0, 1)); + QVERIFY(!model.hasChildren()); + QCOMPARE(model.rowCount(), 0); + QCOMPARE(model.columnCount(), 1); +} + +void tst_QStandardItemModel::data() +{ + // bad args + m_model->setData(QModelIndex(), "bla", Qt::DisplayRole); + + QIcon icon; + for (int r=0; r < m_model->rowCount(); ++r) { + for (int c=0; c < m_model->columnCount(); ++c) { + m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole); + m_model->setData(m_model->index(r,c), "tooltip", Qt::ToolTipRole); + m_model->setData(m_model->index(r,c), icon, Qt::DecorationRole); + } + } + + QVERIFY(m_model->data(m_model->index(0, 0), Qt::DisplayRole).toString() == "initialitem"); + QVERIFY(m_model->data(m_model->index(0, 0), Qt::ToolTipRole).toString() == "tooltip"); + +} + +void tst_QStandardItemModel::clear() +{ + QStandardItemModel model; + model.insertColumns(0, 10); + model.insertRows(0, 10); + QCOMPARE(model.columnCount(), 10); + QCOMPARE(model.rowCount(), 10); + + QSignalSpy modelResetSpy(&model, SIGNAL(modelReset())); + QSignalSpy layoutChangedSpy(&model, SIGNAL(layoutChanged())); + QSignalSpy rowsRemovedSpy(&model, SIGNAL(rowsRemoved(QModelIndex, int, int))); + model.clear(); + + QCOMPARE(modelResetSpy.count(), 1); + QCOMPARE(layoutChangedSpy.count(), 0); + QCOMPARE(rowsRemovedSpy.count(), 0); + QCOMPARE(model.index(0, 0), QModelIndex()); + QCOMPARE(model.columnCount(), 0); + QCOMPARE(model.rowCount(), 0); + QCOMPARE(model.hasChildren(), false); +} + +void tst_QStandardItemModel::sort_data() +{ + QTest::addColumn<int>("sortOrder"); + QTest::addColumn<QStringList>("initial"); + QTest::addColumn<QStringList>("expected"); + + QTest::newRow("flat descending") << static_cast<int>(Qt::DescendingOrder) + << (QStringList() + << "delta" + << "yankee" + << "bravo" + << "lima" + << "charlie" + << "juliet" + << "tango" + << "hotel" + << "uniform" + << "alpha" + << "echo" + << "golf" + << "quebec" + << "foxtrot" + << "india" + << "romeo" + << "november" + << "oskar" + << "zulu" + << "kilo" + << "whiskey" + << "mike" + << "papa" + << "sierra" + << "xray" + << "viktor") + << (QStringList() + << "zulu" + << "yankee" + << "xray" + << "whiskey" + << "viktor" + << "uniform" + << "tango" + << "sierra" + << "romeo" + << "quebec" + << "papa" + << "oskar" + << "november" + << "mike" + << "lima" + << "kilo" + << "juliet" + << "india" + << "hotel" + << "golf" + << "foxtrot" + << "echo" + << "delta" + << "charlie" + << "bravo" + << "alpha"); + QTest::newRow("flat ascending") << static_cast<int>(Qt::AscendingOrder) + << (QStringList() + << "delta" + << "yankee" + << "bravo" + << "lima" + << "charlie" + << "juliet" + << "tango" + << "hotel" + << "uniform" + << "alpha" + << "echo" + << "golf" + << "quebec" + << "foxtrot" + << "india" + << "romeo" + << "november" + << "oskar" + << "zulu" + << "kilo" + << "whiskey" + << "mike" + << "papa" + << "sierra" + << "xray" + << "viktor") + << (QStringList() + << "alpha" + << "bravo" + << "charlie" + << "delta" + << "echo" + << "foxtrot" + << "golf" + << "hotel" + << "india" + << "juliet" + << "kilo" + << "lima" + << "mike" + << "november" + << "oskar" + << "papa" + << "quebec" + << "romeo" + << "sierra" + << "tango" + << "uniform" + << "viktor" + << "whiskey" + << "xray" + << "yankee" + << "zulu"); + QStringList list; + for (int i=1000; i < 2000; ++i) + list.append(QString("Number: %1").arg(i)); + QTest::newRow("large set ascending") << static_cast<int>(Qt::AscendingOrder) << list << list; +} + +void tst_QStandardItemModel::sort() +{ + QFETCH(int, sortOrder); + QFETCH(QStringList, initial); + QFETCH(QStringList, expected); + // prepare model + QStandardItemModel model; + QVERIFY(model.insertRows(0, initial.count(), QModelIndex())); + QCOMPARE(model.rowCount(QModelIndex()), initial.count()); + model.insertColumns(0, 1, QModelIndex()); + QCOMPARE(model.columnCount(QModelIndex()), 1); + for (int row = 0; row < model.rowCount(QModelIndex()); ++row) { + QModelIndex index = model.index(row, 0, QModelIndex()); + model.setData(index, initial.at(row), Qt::DisplayRole); + } + + QSignalSpy layoutAboutToBeChangedSpy( + &model, SIGNAL(layoutAboutToBeChanged())); + QSignalSpy layoutChangedSpy( + &model, SIGNAL(layoutChanged())); + + // sort + model.sort(0, static_cast<Qt::SortOrder>(sortOrder)); + + QCOMPARE(layoutAboutToBeChangedSpy.count(), 1); + QCOMPARE(layoutChangedSpy.count(), 1); + + // make sure the model is sorted + for (int row = 0; row < model.rowCount(QModelIndex()); ++row) { + QModelIndex index = model.index(row, 0, QModelIndex()); + QCOMPARE(model.data(index, Qt::DisplayRole).toString(), expected.at(row)); + } +} + +void tst_QStandardItemModel::sortRole_data() +{ + QTest::addColumn<QStringList>("initialText"); + QTest::addColumn<QVariantList>("initialData"); + QTest::addColumn<int>("sortRole"); + QTest::addColumn<int>("sortOrder"); + QTest::addColumn<QStringList>("expectedText"); + QTest::addColumn<QVariantList>("expectedData"); + + QTest::newRow("sort ascending with Qt::DisplayRole") + << (QStringList() << "b" << "a" << "c") + << (QVariantList() << 2 << 3 << 1) + << static_cast<int>(Qt::DisplayRole) + << static_cast<int>(Qt::AscendingOrder) + << (QStringList() << "a" << "b" << "c") + << (QVariantList() << 3 << 2 << 1); + QTest::newRow("sort ascending with Qt::UserRole") + << (QStringList() << "a" << "b" << "c") + << (QVariantList() << 3 << 2 << 1) + << static_cast<int>(Qt::UserRole) + << static_cast<int>(Qt::AscendingOrder) + << (QStringList() << "c" << "b" << "a") + << (QVariantList() << 1 << 2 << 3); +} + +void tst_QStandardItemModel::sortRole() +{ + QFETCH(QStringList, initialText); + QFETCH(QVariantList, initialData); + QFETCH(int, sortRole); + QFETCH(int, sortOrder); + QFETCH(QStringList, expectedText); + QFETCH(QVariantList, expectedData); + + QStandardItemModel model; + for (int i = 0; i < initialText.count(); ++i) { + QStandardItem *item = new QStandardItem; + item->setText(initialText.at(i)); + item->setData(initialData.at(i), Qt::UserRole); + model.appendRow(item); + } + model.setSortRole(sortRole); + model.sort(0, static_cast<Qt::SortOrder>(sortOrder)); + for (int i = 0; i < expectedText.count(); ++i) { + QStandardItem *item = model.item(i); + QCOMPARE(item->text(), expectedText.at(i)); + QCOMPARE(item->data(Qt::UserRole), expectedData.at(i)); + } +} + +void tst_QStandardItemModel::findItems() +{ + QStandardItemModel model; + model.appendRow(new QStandardItem(QLatin1String("foo"))); + model.appendRow(new QStandardItem(QLatin1String("bar"))); + model.item(1)->appendRow(new QStandardItem(QLatin1String("foo"))); + QList<QStandardItem*> matches; + matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly|Qt::MatchRecursive, 0); + QCOMPARE(matches.count(), 2); + matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly, 0); + QCOMPARE(matches.count(), 1); + matches = model.findItems(QLatin1String("food"), Qt::MatchExactly|Qt::MatchRecursive, 0); + QCOMPARE(matches.count(), 0); + matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly|Qt::MatchRecursive, -1); + QCOMPARE(matches.count(), 0); + matches = model.findItems(QLatin1String("foo"), Qt::MatchExactly|Qt::MatchRecursive, 1); + QCOMPARE(matches.count(), 0); +} + +void tst_QStandardItemModel::getSetHeaderItem() +{ + QStandardItemModel model; + + QCOMPARE(model.horizontalHeaderItem(0), static_cast<QStandardItem*>(0)); + QStandardItem *hheader = new QStandardItem(); + model.setHorizontalHeaderItem(0, hheader); + QCOMPARE(model.columnCount(), 1); + QCOMPARE(model.horizontalHeaderItem(0), hheader); + QCOMPARE(hheader->model(), &model); + model.setHorizontalHeaderItem(0, 0); + QCOMPARE(model.horizontalHeaderItem(0), static_cast<QStandardItem*>(0)); + + QCOMPARE(model.verticalHeaderItem(0), static_cast<QStandardItem*>(0)); + QStandardItem *vheader = new QStandardItem(); + model.setVerticalHeaderItem(0, vheader); + QCOMPARE(model.rowCount(), 1); + QCOMPARE(model.verticalHeaderItem(0), vheader); + QCOMPARE(vheader->model(), &model); + model.setVerticalHeaderItem(0, 0); + QCOMPARE(model.verticalHeaderItem(0), static_cast<QStandardItem*>(0)); +} + +void tst_QStandardItemModel::indexFromItem() +{ + QStandardItemModel model; + + QCOMPARE(model.indexFromItem(model.invisibleRootItem()), QModelIndex()); + + QStandardItem *item = new QStandardItem; + model.setItem(10, 20, item); + QCOMPARE(item->model(), &model); + QModelIndex itemIndex = model.indexFromItem(item); + QVERIFY(itemIndex.isValid()); + QCOMPARE(itemIndex.row(), 10); + QCOMPARE(itemIndex.column(), 20); + QCOMPARE(itemIndex.parent(), QModelIndex()); + QCOMPARE(itemIndex.model(), (const QAbstractItemModel*)(&model)); + + QStandardItem *child = new QStandardItem; + item->setChild(4, 2, child); + QModelIndex childIndex = model.indexFromItem(child); + QVERIFY(childIndex.isValid()); + QCOMPARE(childIndex.row(), 4); + QCOMPARE(childIndex.column(), 2); + QCOMPARE(childIndex.parent(), itemIndex); + + QStandardItem *dummy = new QStandardItem; + QModelIndex noSuchIndex = model.indexFromItem(dummy); + QVERIFY(!noSuchIndex.isValid()); + delete dummy; + + noSuchIndex = model.indexFromItem(0); + QVERIFY(!noSuchIndex.isValid()); +} + +void tst_QStandardItemModel::itemFromIndex() +{ + QStandardItemModel model; + + QCOMPARE(model.itemFromIndex(QModelIndex()), (QStandardItem*)0); + + QStandardItem *item = new QStandardItem; + model.setItem(10, 20, item); + QModelIndex itemIndex = model.index(10, 20, QModelIndex()); + QVERIFY(itemIndex.isValid()); + QCOMPARE(model.itemFromIndex(itemIndex), item); + + QStandardItem *child = new QStandardItem; + item->setChild(4, 2, child); + QModelIndex childIndex = model.index(4, 2, itemIndex); + QVERIFY(childIndex.isValid()); + QCOMPARE(model.itemFromIndex(childIndex), child); + + QModelIndex noSuchIndex = model.index(99, 99, itemIndex); + QVERIFY(!noSuchIndex.isValid()); +} + +class CustomItem : public QStandardItem +{ +public: + CustomItem() : QStandardItem() { } + ~CustomItem() { } + int type() const { + return UserType; + } + QStandardItem *clone() const { + return new CustomItem; + } +}; + +void tst_QStandardItemModel::getSetItemPrototype() +{ + QStandardItemModel model; + QCOMPARE(model.itemPrototype(), static_cast<const QStandardItem*>(0)); + + const CustomItem *proto = new CustomItem; + model.setItemPrototype(proto); + QCOMPARE(model.itemPrototype(), (const QStandardItem*)proto); + + model.setRowCount(1); + model.setColumnCount(1); + QModelIndex index = model.index(0, 0, QModelIndex()); + model.setData(index, "foo"); + QStandardItem *item = model.itemFromIndex(index); + QVERIFY(item != 0); + QCOMPARE(item->type(), static_cast<int>(QStandardItem::UserType)); + + model.setItemPrototype(0); + QCOMPARE(model.itemPrototype(), static_cast<const QStandardItem*>(0)); +} + +void tst_QStandardItemModel::getSetItemData() +{ + QMap<int, QVariant> roles; + QLatin1String text("text"); + roles.insert(Qt::DisplayRole, text); + QLatin1String statusTip("statusTip"); + roles.insert(Qt::StatusTipRole, statusTip); + QLatin1String toolTip("toolTip"); + roles.insert(Qt::ToolTipRole, toolTip); + QLatin1String whatsThis("whatsThis"); + roles.insert(Qt::WhatsThisRole, whatsThis); + QSize sizeHint(64, 48); + roles.insert(Qt::SizeHintRole, sizeHint); + QFont font; + roles.insert(Qt::FontRole, font); + Qt::Alignment textAlignment(Qt::AlignLeft|Qt::AlignVCenter); + roles.insert(Qt::TextAlignmentRole, int(textAlignment)); + QColor backgroundColor(Qt::blue); + roles.insert(Qt::BackgroundRole, backgroundColor); + QColor textColor(Qt::green); + roles.insert(Qt::TextColorRole, textColor); + Qt::CheckState checkState(Qt::PartiallyChecked); + roles.insert(Qt::CheckStateRole, int(checkState)); + QLatin1String accessibleText("accessibleText"); + roles.insert(Qt::AccessibleTextRole, accessibleText); + QLatin1String accessibleDescription("accessibleDescription"); + roles.insert(Qt::AccessibleDescriptionRole, accessibleDescription); + + QStandardItemModel model; + model.insertRows(0, 1); + model.insertColumns(0, 1); + QModelIndex idx = model.index(0, 0, QModelIndex()); + + QSignalSpy modelDataChangedSpy( + &model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&))); + QVERIFY(model.setItemData(idx, roles)); + QCOMPARE(modelDataChangedSpy.count(), 1); + QVERIFY(model.setItemData(idx, roles)); + QCOMPARE(modelDataChangedSpy.count(), 1); //it was already changed once + QCOMPARE(model.itemData(idx), roles); +} + +void tst_QStandardItemModel::setHeaderLabels_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<int>("orientation"); + QTest::addColumn<QStringList>("labels"); + QTest::addColumn<QStringList>("expectedLabels"); + + QTest::newRow("horizontal labels") + << 1 + << 4 + << int(Qt::Horizontal) + << (QStringList() << "a" << "b" << "c" << "d") + << (QStringList() << "a" << "b" << "c" << "d"); + QTest::newRow("vertical labels") + << 4 + << 1 + << int(Qt::Vertical) + << (QStringList() << "a" << "b" << "c" << "d") + << (QStringList() << "a" << "b" << "c" << "d"); + QTest::newRow("too few (horizontal)") + << 1 + << 4 + << int(Qt::Horizontal) + << (QStringList() << "a" << "b") + << (QStringList() << "a" << "b" << "3" << "4"); + QTest::newRow("too few (vertical)") + << 4 + << 1 + << int(Qt::Vertical) + << (QStringList() << "a" << "b") + << (QStringList() << "a" << "b" << "3" << "4"); + QTest::newRow("too many (horizontal)") + << 1 + << 2 + << int(Qt::Horizontal) + << (QStringList() << "a" << "b" << "c" << "d") + << (QStringList() << "a" << "b" << "c" << "d"); + QTest::newRow("too many (vertical)") + << 2 + << 1 + << int(Qt::Vertical) + << (QStringList() << "a" << "b" << "c" << "d") + << (QStringList() << "a" << "b" << "c" << "d"); +} + +void tst_QStandardItemModel::setHeaderLabels() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(int, orientation); + QFETCH(QStringList, labels); + QFETCH(QStringList, expectedLabels); + QStandardItemModel model(rows, columns); + QSignalSpy columnsInsertedSpy( + &model, SIGNAL(columnsInserted(QModelIndex,int,int))); + QSignalSpy rowsInsertedSpy( + &model, SIGNAL(rowsInserted(QModelIndex,int,int))); + if (orientation == Qt::Horizontal) + model.setHorizontalHeaderLabels(labels); + else + model.setVerticalHeaderLabels(labels); + for (int i = 0; i < expectedLabels.count(); ++i) + QCOMPARE(model.headerData(i, Qt::Orientation(orientation)).toString(), expectedLabels.at(i)); + QCOMPARE(columnsInsertedSpy.count(), + (orientation == Qt::Vertical) ? 0 : labels.count() > columns); + QCOMPARE(rowsInsertedSpy.count(), + (orientation == Qt::Horizontal) ? 0 : labels.count() > rows); +} + +void tst_QStandardItemModel::itemDataChanged() +{ + QStandardItemModel model(6, 4); + QStandardItem item; + QSignalSpy dataChangedSpy( + &model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &))); + QSignalSpy itemChangedSpy( + &model, SIGNAL(itemChanged(QStandardItem *))); + + model.setItem(0, &item); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(itemChangedSpy.count(), 1); + QModelIndex index = model.indexFromItem(&item); + QList<QVariant> args; + args = dataChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index); + QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index); + args = itemChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item); + + item.setData(QLatin1String("foo"), Qt::DisplayRole); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(itemChangedSpy.count(), 1); + args = dataChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index); + QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index); + args = itemChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item); + + item.setData(item.data(Qt::DisplayRole), Qt::DisplayRole); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(itemChangedSpy.count(), 0); + + item.setFlags(Qt::ItemIsEnabled); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(itemChangedSpy.count(), 1); + args = dataChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index); + QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index); + args = itemChangedSpy.takeFirst(); + QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item); + + item.setFlags(item.flags()); + QCOMPARE(dataChangedSpy.count(), 0); + QCOMPARE(itemChangedSpy.count(), 0); +} + +void tst_QStandardItemModel::takeHeaderItem() +{ + QStandardItemModel model; + // set header items + QStandardItem *hheader = new QStandardItem(); + model.setHorizontalHeaderItem(0, hheader); + QStandardItem *vheader = new QStandardItem(); + model.setVerticalHeaderItem(0, vheader); + // take header items + QCOMPARE(model.takeHorizontalHeaderItem(0), hheader); + QCOMPARE(model.takeVerticalHeaderItem(0), vheader); + QCOMPARE(hheader->model(), static_cast<QStandardItemModel*>(0)); + QCOMPARE(vheader->model(), static_cast<QStandardItemModel*>(0)); + QCOMPARE(model.takeHorizontalHeaderItem(0), static_cast<QStandardItem*>(0)); + QCOMPARE(model.takeVerticalHeaderItem(0), static_cast<QStandardItem*>(0)); + delete hheader; + delete vheader; +} + +void tst_QStandardItemModel::useCase1() +{ + const int rows = 5; + const int columns = 8; + QStandardItemModel model(rows, columns); + for (int i = 0; i < model.rowCount(); ++i) { + for (int j = 0; j < model.columnCount(); ++j) { + QCOMPARE(model.item(i, j), static_cast<QStandardItem*>(0)); + + QStandardItem *item = new QStandardItem(); + model.setItem(i, j, item); + QCOMPARE(item->row(), i); + QCOMPARE(item->column(), j); + QCOMPARE(item->model(), &model); + + QModelIndex index = model.indexFromItem(item); + QCOMPARE(index, model.index(i, j, QModelIndex())); + QStandardItem *sameItem = model.itemFromIndex(index); + QCOMPARE(sameItem, item); + } + } +} + +static void createChildren(QStandardItemModel *model, QStandardItem *parent, int level) +{ + if (level > 4) + return; + for (int i = 0; i < 4; ++i) { + QCOMPARE(parent->rowCount(), i); + parent->appendRow(QList<QStandardItem*>()); + for (int j = 0; j < parent->columnCount(); ++j) { + QStandardItem *item = new QStandardItem(); + parent->setChild(i, j, item); + QCOMPARE(item->row(), i); + QCOMPARE(item->column(), j); + + QModelIndex parentIndex = model->indexFromItem(parent); + QModelIndex index = model->indexFromItem(item); + QCOMPARE(index, model->index(i, j, parentIndex)); + QStandardItem *theItem = model->itemFromIndex(index); + QCOMPARE(theItem, item); + QStandardItem *theParent = model->itemFromIndex(parentIndex); + QCOMPARE(theParent, (level == 0) ? (QStandardItem*)0 : parent); + } + + { + QStandardItem *item = parent->child(i); + item->setColumnCount(parent->columnCount()); + createChildren(model, item, level + 1); + } + } +} + +void tst_QStandardItemModel::useCase2() +{ + QStandardItemModel model; + model.setColumnCount(2); + createChildren(&model, model.invisibleRootItem(), 0); +} + +void tst_QStandardItemModel::useCase3() +{ + // create the tree structure first + QStandardItem *childItem = 0; + for (int i = 0; i < 100; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + if (childItem) + item->appendRow(childItem); + childItem = item; + } + + // add to model as last step + QStandardItemModel model; + model.appendRow(childItem); + + // make sure each item has the correct model and parent + QStandardItem *parentItem = 0; + while (childItem) { + QCOMPARE(childItem->model(), &model); + QCOMPARE(childItem->parent(), parentItem); + parentItem = childItem; + childItem = childItem->child(0); + } + + // take the item, make sure model is set to 0, but that parents are the same + childItem = model.takeItem(0); + { + parentItem = 0; + QStandardItem *item = childItem; + while (item) { + QCOMPARE(item->model(), static_cast<QStandardItemModel*>(0)); + QCOMPARE(item->parent(), parentItem); + parentItem = item; + item = item->child(0); + } + } + delete childItem; +} + +void tst_QStandardItemModel::rootItemFlags() +{ + QStandardItemModel model(6, 4); + QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex())); + QCOMPARE(model.invisibleRootItem()->flags() , Qt::ItemIsDropEnabled); + + Qt::ItemFlags f = Qt::ItemIsDropEnabled | Qt::ItemIsEnabled; + model.invisibleRootItem()->setFlags(f); + QCOMPARE(model.invisibleRootItem()->flags() , f); + QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex())); + +#ifndef QT_NO_DRAGANDDROP + model.invisibleRootItem()->setDropEnabled(false); +#endif + QCOMPARE(model.invisibleRootItem()->flags() , Qt::ItemIsEnabled); + QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex())); +} + +bool tst_QStandardItemModel::compareModels(QStandardItemModel *model1, QStandardItemModel *model2) +{ + return compareItems(model1->invisibleRootItem(), model2->invisibleRootItem()); +} + +bool tst_QStandardItemModel::compareItems(QStandardItem *item1, QStandardItem *item2) +{ + if (!item1 && !item2) + return true; + if (!item1 || !item2) + return false; + if (item1->text() != item2->text()){ + qDebug() << item1->text() << item2->text(); + return false; + } + if (item1->rowCount() != item2->rowCount()) { + // qDebug() << "RowCount" << item1->text() << item1->rowCount() << item2->rowCount(); + return false; + } + if (item1->columnCount() != item2->columnCount()) { + // qDebug() << "ColumnCount" << item1->text() << item1->columnCount() << item2->columnCount(); + return false; + } + for (int row = 0; row < item1->columnCount(); row++) + for (int col = 0; col < item1->columnCount(); col++) { + + if (!compareItems(item1->child(row, col), item2->child(row, col))) + return false; + } + return true; +} + +static QStandardItem *itemFromText(QStandardItem *parent, const QString &text) +{ + QStandardItem *item = 0; + for(int i = 0; i < parent->columnCount(); i++) + for(int j = 0; j < parent->rowCount(); j++) { + + QStandardItem *child = parent->child(j, i); + + if(!child) + continue; + + if (child->text() == text) { + if (item) { + return 0; + } + item = child; + } + + QStandardItem *candidate = itemFromText(child, text); + if(candidate) { + if (item) { + return 0; + } + item = candidate; + } + } + return item; +} + +#ifdef QT_BUILD_INTERNAL +static QModelIndex indexFromText(QStandardItemModel *model, const QString &text) +{ + QStandardItem *item = itemFromText(model->invisibleRootItem(), text); + /*QVERIFY(item);*/ + return model->indexFromItem(item); +} + + +struct FriendlyTreeView : public QTreeView +{ + friend class tst_QStandardItemModel; + Q_DECLARE_PRIVATE(QTreeView) +}; +#endif + +void tst_QStandardItemModel::treeDragAndDrop() +{ +#ifdef QT_BUILD_INTERNAL + const int nRow = 5; + const int nCol = 3; + + QStandardItemModel model; + QStandardItemModel checkModel; + + for (int i = 0; i < nRow; ++i) { + QList<QStandardItem *> colItems1; + for (int c = 0 ; c < nCol; c ++) + colItems1 << new QStandardItem(QString("item %1 - %0").arg(c).arg(i)); + model.appendRow(colItems1); + + for (int j = 0; j < nRow; ++j) { + QList<QStandardItem *> colItems2; + for (int c = 0 ; c < nCol; c ++) + colItems2 << new QStandardItem(QString("item %1/%2 - %0").arg(c).arg(i).arg(j)); + colItems1.at(0)->appendRow(colItems2); + + for (int k = 0; k < nRow; ++k) { + QList<QStandardItem *> colItems3; + for (int c = 0 ; c < nCol; c ++) + colItems3 << new QStandardItem(QString("item %1/%2/%3 - %0").arg(c).arg(i).arg(j).arg(k)); + colItems2.at(0)->appendRow(colItems3); + } + } + } + + for (int i = 0; i < nRow; ++i) { + QList<QStandardItem *> colItems1; + for (int c = 0 ; c < nCol; c ++) + colItems1 << new QStandardItem(QString("item %1 - %0").arg(c).arg(i)); + checkModel.appendRow(colItems1); + + for (int j = 0; j < nRow; ++j) { + QList<QStandardItem *> colItems2; + for (int c = 0 ; c < nCol; c ++) + colItems2 << new QStandardItem(QString("item %1/%2 - %0").arg(c).arg(i).arg(j)); + colItems1.at(0)->appendRow(colItems2); + + for (int k = 0; k < nRow; ++k) { + QList<QStandardItem *> colItems3; + for (int c = 0 ; c < nCol; c ++) + colItems3 << new QStandardItem(QString("item %1/%2/%3 - %0").arg(c).arg(i).arg(j).arg(k)); + colItems2.at(0)->appendRow(colItems3); + } + } + } + + QVERIFY(compareModels(&model, &checkModel)); + + FriendlyTreeView view; + view.setModel(&model); + view.expandAll(); + view.show(); +#ifndef QT_NO_DRAGANDDROP + view.setDragDropMode(QAbstractItemView::InternalMove); +#endif + view.setSelectionMode(QAbstractItemView::ExtendedSelection); + + QItemSelectionModel *selection = view.selectionModel(); + + // + // step1 drag "item 1" and "item 2" into "item 4" + // + { + selection->clear(); + selection->select(QItemSelection(indexFromText(&model, QString("item 1 - 0")), + indexFromText(&model, QString("item 1 - %0").arg(nCol-1))), QItemSelectionModel::Select); + + selection->select(QItemSelection(indexFromText(&model, QString("item 2 - 0")), + indexFromText(&model, QString("item 2 - %0").arg(nCol-1))), QItemSelectionModel::Select); + + //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent + QModelIndexList indexes = view.selectedIndexes(); + QMimeData *data = model.mimeData(indexes); + if(model.dropMimeData(data, Qt::MoveAction, 0, 0, indexFromText(&model, "item 4 - 0"))) + view.d_func()->clearOrRemove(); + delete data; + + QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point + QStandardItem *item4 = itemFromText(checkModel.invisibleRootItem(), "item 4 - 0"); + item4->insertRow(0, checkModel.takeRow(1)); + item4->insertRow(1, checkModel.takeRow(1)); + QVERIFY(compareModels(&model, &checkModel)); + } + + // + // step2 drag "item 3" and "item 3/0" into "item 4" + // + { + selection->clear(); + selection->select(QItemSelection(indexFromText(&model, QString("item 3 - 0")), + indexFromText(&model, QString("item 3 - %0").arg(nCol-1))), QItemSelectionModel::Select); + + selection->select(QItemSelection(indexFromText(&model, QString("item 3/0 - 0")), + indexFromText(&model, QString("item 3/0 - %0").arg(nCol-1))), QItemSelectionModel::Select); + + //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent + QModelIndexList indexes = view.selectedIndexes(); + QMimeData *data = model.mimeData(indexes); + if(model.dropMimeData(data, Qt::MoveAction, 0, 0, indexFromText(&model, "item 4 - 0"))) + view.d_func()->clearOrRemove(); + delete data; + + QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point + QStandardItem *item4 = itemFromText(checkModel.invisibleRootItem(), "item 4 - 0"); + item4->insertRow(0, checkModel.takeRow(1)); + + QVERIFY(compareModels(&model, &checkModel)); + } + + // + // step2 drag "item 3" and "item 3/0/2" into "item 0/2" + // ( remember "item 3" is now the first child of "item 4") + // + { + selection->clear(); + selection->select(QItemSelection(indexFromText(&model, QString("item 3 - 0")), + indexFromText(&model, QString("item 3 - %0").arg(nCol-1))), QItemSelectionModel::Select); + + selection->select(QItemSelection(indexFromText(&model, QString("item 3/0/2 - 0")), + indexFromText(&model, QString("item 3/0/2 - %0").arg(nCol-1))), QItemSelectionModel::Select); + + //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent + QModelIndexList indexes = view.selectedIndexes(); + QMimeData *data = model.mimeData(indexes); + if(model.dropMimeData(data, Qt::MoveAction, 0, 0, indexFromText(&model, "item 0/2 - 0"))) + view.d_func()->clearOrRemove(); + delete data; + + QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point + QStandardItem *item02 = itemFromText(checkModel.invisibleRootItem(), "item 0/2 - 0"); + QStandardItem *item4 = itemFromText(checkModel.invisibleRootItem(), "item 4 - 0"); + item02->insertRow(0, item4->takeRow(0)); + + QVERIFY(compareModels(&model, &checkModel)); + } +#endif +} + +void tst_QStandardItemModel::removeRowsAndColumns() +{ +#define VERIFY_MODEL \ + for (int c = 0; c < col_list.count(); c++) \ + for (int r = 0; r < row_list.count(); r++) \ + QCOMPARE(model.item(r,c)->text() , row_list[r] + "x" + col_list[c]); + + QVector<QString> row_list = QString("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20").split(',').toVector(); + QVector<QString> col_list = row_list; + QStandardItemModel model; + for (int c = 0; c < col_list.count(); c++) + for (int r = 0; r < row_list.count(); r++) + model.setItem(r, c, new QStandardItem(row_list[r] + "x" + col_list[c])); + VERIFY_MODEL + + row_list.remove(3); + model.removeRow(3); + VERIFY_MODEL + + col_list.remove(5); + model.removeColumn(5); + VERIFY_MODEL + + row_list.remove(2, 5); + model.removeRows(2, 5); + VERIFY_MODEL + + col_list.remove(1, 6); + model.removeColumns(1, 6); + VERIFY_MODEL + + QList<QStandardItem *> row_taken = model.takeRow(6); + QCOMPARE(row_taken.count(), col_list.count()); + for (int c = 0; c < col_list.count(); c++) + QCOMPARE(row_taken[c]->text() , row_list[6] + "x" + col_list[c]); + row_list.remove(6); + VERIFY_MODEL + + QList<QStandardItem *> col_taken = model.takeColumn(10); + QCOMPARE(col_taken.count(), row_list.count()); + for (int r = 0; r < row_list.count(); r++) + QCOMPARE(col_taken[r]->text() , row_list[r] + "x" + col_list[10]); + col_list.remove(10); + VERIFY_MODEL +} + +void tst_QStandardItemModel::itemRoleNames() +{ + QVector<QString> row_list = QString("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20").split(',').toVector(); + QVector<QString> col_list = row_list; + QStandardItemModel model; + for (int c = 0; c < col_list.count(); c++) + for (int r = 0; r < row_list.count(); r++) + model.setItem(r, c, new QStandardItem(row_list[r] + "x" + col_list[c])); + VERIFY_MODEL + + QHash<int, QByteArray> newRoleNames; + newRoleNames.insert(Qt::DisplayRole, "Name"); + newRoleNames.insert(Qt::DecorationRole, "Avatar"); + model.setItemRoleNames(newRoleNames); + QCOMPARE(model.roleNames(), newRoleNames); + VERIFY_MODEL +} + + +QTEST_MAIN(tst_QStandardItemModel) +#include "tst_qstandarditemmodel.moc" |