qt5base-lts/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp
Tor Arne Vestbø 68511d41d5 qWaitFor: Prevent being stuck in QCoreApplication::processEvents
When using the overload of QCoreApplication::processEvents that takes a
maxtime argument, the function will keep processing events until there
are no more events, or until it times out.

The problem is that the function doesn't distinguish between events that
were on the event queue when the function was called, and events generated
by processing events as part of its own execution. If for example a widget
calls update() in its paintEvent, the function will spin for the entire
duration of maxtime.

That doesn't work for qWaitFor, where we need to check the predicate
between each pass, so we use the overload of processEvents that doesn't
take a maxtime. That's fine, as we have our own timeout logic.

Change-Id: I9738d7d0187c36d4a5ddfcd3fd075b0bd84583c4
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
2019-01-09 18:10:54 +00:00

3535 lines
124 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qtreewidget.h>
#include <qtreewidgetitemiterator.h>
#include <qapplication.h>
#include <qeventloop.h>
#include <qdebug.h>
#include <qheaderview.h>
#include <qlineedit.h>
#include <QScrollBar>
#include <QStyledItemDelegate>
class CustomTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const
{ return QTreeWidget::indexFromItem(item, column); }
QMimeData * mimeData(const QList<QTreeWidgetItem*> items) const
{ return QTreeWidget::mimeData(items); }
};
class tst_QTreeWidget : public QObject
{
Q_OBJECT
public:
tst_QTreeWidget();
~tst_QTreeWidget();
public slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
private slots:
void getSetCheck();
void addTopLevelItem();
void currentItem_data();
void currentItem();
void editItem_data();
void editItem();
void takeItem_data();
void takeItem();
void removeChild_data();
void removeChild();
void setItemHidden();
void setItemHidden2();
void selectedItems_data();
void selectedItems();
void itemAssignment();
void clone_data();
void clone();
void expand_data();
void expand();
void checkState_data();
void checkState();
void findItems_data();
void findItems();
void findItemsInColumn();
void sortItems_data();
void sortItems();
void deleteItems_data();
void deleteItems();
void itemAboveOrBelow();
void itemStreaming_data();
void itemStreaming();
void insertTopLevelItems_data();
void insertTopLevelItems();
void keyboardNavigation();
void scrollToItem();
void setSortingEnabled();
void match();
void columnCount();
void setHeaderLabels();
void setHeaderItem();
void itemWidget_data();
void itemWidget();
void insertItemsWithSorting_data();
void insertItemsWithSorting();
void insertExpandedItemsWithSorting_data();
void insertExpandedItemsWithSorting();
void changeDataWithSorting_data();
void changeDataWithSorting();
void changeDataWithStableSorting_data();
void changeDataWithStableSorting();
void sortedIndexOfChild_data();
void sortedIndexOfChild();
void defaultRowSizes();
void task191552_rtl();
void task203673_selection();
void rootItemFlags();
void task218661_setHeaderData();
void task245280_sortChildren();
void task253109_itemHeight();
void nonEditableTristate();
// QTreeWidgetItem
void itemOperatorLessThan();
void addChild();
void setData();
void enableDisable();
void expandAndCallapse();
void itemData();
void setDisabled();
void removeSelectedItem();
void removeCurrentItem();
void removeCurrentItem_task186451();
void randomExpand();
void crashTest();
void sortAndSelect();
void task206367_duplication();
void selectionOrder();
void setSelectionModel();
void task217309();
void setCurrentItemExpandsParent();
void task239150_editorWidth();
void setTextUpdate();
void taskQTBUG2844_visualItemRect();
void setChildIndicatorPolicy();
void taskQTBUG_34717_collapseAtBottom();
void task20345_sortChildren();
void getMimeDataWithInvalidItem();
void testVisualItemRect();
void reparentHiddenItem();
public slots:
void itemSelectionChanged();
void emitDataChanged();
private:
CustomTreeWidget *testWidget;
};
// Testing get/set functions
void tst_QTreeWidget::getSetCheck()
{
QTreeWidget obj1;
// int QTreeWidget::columnCount()
// void QTreeWidget::setColumnCount(int)
obj1.setColumnCount(0);
QCOMPARE(obj1.columnCount(), 0);
obj1.setColumnCount(INT_MIN);
QCOMPARE(obj1.columnCount(), 0);
//obj1.setColumnCount(INT_MAX);
//QCOMPARE(obj1.columnCount(), INT_MAX);
// Since setColumnCount allocates memory, there is no way this will succeed
obj1.setColumnCount(100);
QCOMPARE(obj1.columnCount(), 100);
// QTreeWidgetItem * QTreeWidget::headerItem()
// void QTreeWidget::setHeaderItem(QTreeWidgetItem *)
QTreeWidgetItem *var2 = new QTreeWidgetItem();
obj1.setHeaderItem(var2);
QCOMPARE(obj1.headerItem(), var2);
obj1.setHeaderItem((QTreeWidgetItem *)0);
// QCOMPARE(obj1.headerItem(), nullptr);
// QTreeWidgetItem * QTreeWidget::currentItem()
// void QTreeWidget::setCurrentItem(QTreeWidgetItem *)
QTreeWidgetItem *var3 = new QTreeWidgetItem(&obj1);
obj1.setCurrentItem(var3);
QCOMPARE(obj1.currentItem(), var3);
obj1.setCurrentItem((QTreeWidgetItem *)0);
QCOMPARE(obj1.currentItem(), nullptr);
}
typedef QList<int> IntList;
typedef QList<IntList> ListIntList;
Q_DECLARE_METATYPE(Qt::Orientation)
typedef QTreeWidgetItem TreeItem;
typedef QList<TreeItem*> TreeItemList;
Q_DECLARE_METATYPE(QTreeWidgetItem*)
Q_DECLARE_METATYPE(TreeItemList)
tst_QTreeWidget::tst_QTreeWidget(): testWidget(0)
{
}
tst_QTreeWidget::~tst_QTreeWidget()
{
}
void tst_QTreeWidget::initTestCase()
{
qMetaTypeId<QModelIndex>();
qMetaTypeId<Qt::Orientation>();
qRegisterMetaType<QTreeWidgetItem*>("QTreeWidgetItem*");
testWidget = new CustomTreeWidget();
testWidget->show();
QVERIFY(QTest::qWaitForWindowExposed(testWidget));
}
void tst_QTreeWidget::cleanupTestCase()
{
testWidget->hide();
delete testWidget;
}
void tst_QTreeWidget::init()
{
testWidget->clear();
testWidget->setColumnCount(2);
}
void tst_QTreeWidget::cleanup()
{
}
TreeItem *operator<<(TreeItem *parent, const TreeItemList &children) {
for (int i = 0; i < children.count(); ++i)
parent->addChild(children.at(i));
return parent;
}
static void populate(QTreeWidget *widget, const TreeItemList &topLevelItems,
TreeItem *headerItem = 0)
{
widget->clear();
widget->setHeaderItem(headerItem);
foreach (TreeItem *item, topLevelItems)
widget->addTopLevelItem(item);
}
void tst_QTreeWidget::addTopLevelItem()
{
QTreeWidget tree;
QCOMPARE(tree.topLevelItemCount(), 0);
// try to add 0
tree.addTopLevelItem(0);
QCOMPARE(tree.topLevelItemCount(), 0);
QCOMPARE(tree.indexOfTopLevelItem(0), -1);
// add one at a time
QList<TreeItem*> tops;
for (int i = 0; i < 10; ++i) {
TreeItem *ti = new TreeItem();
QCOMPARE(tree.indexOfTopLevelItem(ti), -1);
tree.addTopLevelItem(ti);
QCOMPARE(tree.topLevelItemCount(), i+1);
QCOMPARE(tree.topLevelItem(i), ti);
QCOMPARE(tree.topLevelItem(-1), nullptr);
QCOMPARE(tree.indexOfTopLevelItem(ti), i);
QCOMPARE(ti->parent(), nullptr);
tree.addTopLevelItem(ti);
QCOMPARE(tree.topLevelItemCount(), i+1);
tops.append(ti);
}
// delete one at a time
while (!tops.isEmpty()) {
TreeItem *ti = tops.takeFirst();
delete ti;
QCOMPARE(tree.topLevelItemCount(), tops.count());
for (int i = 0; i < tops.count(); ++i)
QCOMPARE(tree.topLevelItem(i), tops.at(i));
}
// add none
{
int count = tree.topLevelItemCount();
tree.addTopLevelItems(tops);
QCOMPARE(tree.topLevelItemCount(), count);
}
// add many at a time
{
const int count = 10;
for (int i = 0; i < 100; i += count) {
tops.clear();
for (int j = 0; j < count; ++j)
tops << new TreeItem(QStringList(QString::number(j)));
tree.addTopLevelItems(tops);
QCOMPARE(tree.topLevelItemCount(), count + i);
for (int j = 0; j < count; ++j)
QCOMPARE(tree.topLevelItem(i+j), tops.at(j));
tree.addTopLevelItems(tops);
QCOMPARE(tree.topLevelItemCount(), count + i);
}
}
// insert
{
tops.clear();
for (int i = 0; i < 10; ++i)
tops << new TreeItem();
int count = tree.topLevelItemCount();
tree.insertTopLevelItems(count, tops);
QCOMPARE(tree.topLevelItemCount(), count + 10);
}
// invalid insert
{
tops.clear();
for (int i = 0; i < 10; ++i)
tops << new TreeItem();
int count = tree.topLevelItemCount();
tree.insertTopLevelItems(100000, tops); // should be a no-op
QCOMPARE(tree.topLevelItemCount(), count);
}
}
void tst_QTreeWidget::currentItem_data()
{
QTest::addColumn<TreeItemList>("topLevelItems");
QTest::newRow("only top-level items, 2 columns")
<< (TreeItemList()
<< new TreeItem(QStringList() << "a" << "b")
<< new TreeItem(QStringList() << "c" << "d"));
TreeItemList lst;
lst << (new TreeItem(QStringList() << "a" << "b")
<< (TreeItemList()
<< new TreeItem(QStringList() << "c" << "d")
<< new TreeItem(QStringList() << "c" << "d")
)
)
<< (new TreeItem(QStringList() << "e" << "f")
<< (TreeItemList()
<< new TreeItem(QStringList() << "g" << "h")
<< new TreeItem(QStringList() << "g" << "h")
)
);
QTest::newRow("hierarchy, 2 columns") << lst;
}
void tst_QTreeWidget::currentItem()
{
QFETCH(TreeItemList, topLevelItems);
QTreeWidget tree;
tree.show();
populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2"));
QTreeWidgetItem *previous = 0;
for (int x = 0; x < 2; ++x) {
tree.setSelectionBehavior(x ? QAbstractItemView::SelectItems
: QAbstractItemView::SelectRows);
QSignalSpy currentItemChangedSpy(
&tree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
QSignalSpy itemSelectionChangedSpy(
&tree, SIGNAL(itemSelectionChanged()));
QTreeWidgetItemIterator it(&tree);
// do all items
while (QTreeWidgetItem *item = (*it++)) {
tree.setCurrentItem(item);
QCOMPARE(tree.currentItem(), item);
QCOMPARE(currentItemChangedSpy.count(), 1);
QVariantList args = currentItemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(1)), previous);
QCOMPARE(itemSelectionChangedSpy.count(), 1);
itemSelectionChangedSpy.clear();
previous = item;
// do all columns
for (int col = 0; col < item->columnCount(); ++col) {
tree.setCurrentItem(item, col);
QCOMPARE(tree.currentItem(), item);
QCOMPARE(tree.currentColumn(), col);
if (!currentItemChangedSpy.isEmpty()) {
// ### we get a currentItemChanged() when what really
// changed was just currentColumn(). Should it be like this?
QCOMPARE(currentItemChangedSpy.count(), 1);
QVariantList args = currentItemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(1)), item);
if (tree.selectionBehavior() == QAbstractItemView::SelectItems) {
QCOMPARE(itemSelectionChangedSpy.count(), 1);
itemSelectionChangedSpy.clear();
} else {
QCOMPARE(itemSelectionChangedSpy.count(), 0);
}
}
}
}
}
// can't set the headerItem to be the current item
tree.setCurrentItem(tree.headerItem());
QCOMPARE(tree.currentItem(), nullptr);
}
void tst_QTreeWidget::editItem_data()
{
QTest::addColumn<TreeItemList>("topLevelItems");
{
TreeItemList list;
for (int i = 0; i < 10; i++) {
TreeItem *item = new TreeItem(QStringList() << "col1" << "col2");
if ((i & 1) == 0)
item->setFlags(item->flags() | Qt::ItemIsEditable);
else
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
list << item;
}
QTest::newRow("2 columns, only even items editable")
<< list;
}
}
void tst_QTreeWidget::editItem()
{
QFETCH(TreeItemList, topLevelItems);
QTreeWidget tree;
populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2"));
tree.show();
QVERIFY(QTest::qWaitForWindowActive(&tree));
QSignalSpy itemChangedSpy(
&tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
QTreeWidgetItemIterator it(&tree);
while (QTreeWidgetItem *item = (*it++)) {
for (int col = 0; col < item->columnCount(); ++col) {
if (!(item->flags() & Qt::ItemIsEditable))
QTest::ignoreMessage(QtWarningMsg, "edit: editing failed");
tree.editItem(item, col);
QApplication::instance()->processEvents();
QApplication::instance()->processEvents();
QLineEdit *editor = tree.findChild<QLineEdit*>();
if (editor) {
QVERIFY(item->flags() & Qt::ItemIsEditable);
QCOMPARE(editor->selectedText(), editor->text());
QTest::keyClick(editor, Qt::Key_A);
QTest::keyClick(editor, Qt::Key_Enter);
QApplication::instance()->processEvents();
QCOMPARE(itemChangedSpy.count(), 1);
QVariantList args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), col);
} else {
QVERIFY(!(item->flags() & Qt::ItemIsEditable));
}
}
}
}
void tst_QTreeWidget::takeItem_data()
{
QTest::addColumn<int>("index");
QTest::addColumn<bool>("topLevel");
QTest::addColumn<bool>("outOfBounds");
QTest::newRow("First, topLevel") << 0 << true << false;
QTest::newRow("Last, topLevel") << 2 << true << false;
QTest::newRow("Middle, topLevel") << 1 << true << false;
QTest::newRow("Out of bounds, toplevel, (index: -1)") << -1 << true << true;
QTest::newRow("Out of bounds, toplevel, (index: 3)") << 3 << true << true;
QTest::newRow("First, child of topLevel") << 0 << false << false;
QTest::newRow("Last, child of topLevel") << 2 << false << false;
QTest::newRow("Middle, child of topLevel") << 1 << false << false;
QTest::newRow("Out of bounds, child of toplevel, (index: -1)") << -1 << false << true;
QTest::newRow("Out of bounds, child of toplevel, (index: 3)") << 3 << false << true;
}
void tst_QTreeWidget::takeItem()
{
QFETCH(int, index);
QFETCH(bool, topLevel);
QFETCH(bool, outOfBounds);
for (int i=0; i<3; ++i) {
QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
top->setText(0, QStringLiteral("top") + QString::number(i));
for (int j=0; j<3; ++j) {
QTreeWidgetItem *child = new QTreeWidgetItem(top);
child->setText(0, QStringLiteral("child") + QString::number(j));
}
}
QCOMPARE(testWidget->topLevelItemCount(), 3);
QCOMPARE(testWidget->topLevelItem(0)->childCount(), 3);
if (topLevel) {
int count = testWidget->topLevelItemCount();
QTreeWidgetItem *item = testWidget->takeTopLevelItem(index);
if (outOfBounds) {
QCOMPARE(item, nullptr);
QCOMPARE(count, testWidget->topLevelItemCount());
} else {
QCOMPARE(item->text(0), QStringLiteral("top") + QString::number(index));
QCOMPARE(count-1, testWidget->topLevelItemCount());
delete item;
}
} else {
int count = testWidget->topLevelItem(0)->childCount();
QTreeWidgetItem *item = testWidget->topLevelItem(0)->takeChild(index);
if (outOfBounds) {
QCOMPARE(item, nullptr);
QCOMPARE(count, testWidget->topLevelItem(0)->childCount());
} else {
QCOMPARE(item->text(0), QStringLiteral("child") + QString::number(index));
QCOMPARE(count-1, testWidget->topLevelItem(0)->childCount());
delete item;
}
}
}
void tst_QTreeWidget::removeChild_data()
{
QTest::addColumn<int>("childCount");
QTest::addColumn<int>("removeAt");
QTest::newRow("10 remove 3") << 10 << 3;
}
void tst_QTreeWidget::removeChild()
{
QFETCH(int, childCount);
QFETCH(int, removeAt);
const QScopedPointer<QTreeWidgetItem> root(new QTreeWidgetItem);
for (int i = 0; i < childCount; ++i)
new QTreeWidgetItem(root.data(), QStringList(QString::number(i)));
QCOMPARE(root->childCount(), childCount);
for (int j = 0; j < childCount; ++j)
QCOMPARE(root->child(j)->text(0), QString::number(j));
const QScopedPointer<QTreeWidgetItem> remove(root->child(removeAt));
root->removeChild(remove.data());
QCOMPARE(root->childCount(), childCount - 1);
for (int k = 0; k < childCount; ++k) {
if (k == removeAt)
QCOMPARE(remove->text(0), QString::number(k));
else if (k < removeAt)
QCOMPARE(root->child(k)->text(0), QString::number(k));
else if (k > removeAt)
QCOMPARE(root->child(k - 1)->text(0), QString::number(k));
}
}
void tst_QTreeWidget::setItemHidden()
{
QTreeWidgetItem *parent = new QTreeWidgetItem(testWidget);
parent->setText(0, "parent");
QTreeWidgetItem *child = new QTreeWidgetItem(parent);
child->setText(0, "child");
QVERIFY(child->parent());
testWidget->expandItem(parent);
testWidget->scrollToItem(child);
QVERIFY(testWidget->visualItemRect(parent).isValid()
&& testWidget->viewport()->rect().intersects(testWidget->visualItemRect(parent)));
QVERIFY(testWidget->visualItemRect(child).isValid()
&& testWidget->viewport()->rect().intersects(testWidget->visualItemRect(child)));
QVERIFY(!testWidget->isItemHidden(parent));
QVERIFY(!testWidget->isItemHidden(child));
testWidget->setItemHidden(parent, true);
QVERIFY(!(testWidget->visualItemRect(parent).isValid()
&& testWidget->viewport()->rect().intersects(testWidget->visualItemRect(parent))));
QVERIFY(!(testWidget->visualItemRect(child).isValid()
&& testWidget->viewport()->rect().intersects(testWidget->visualItemRect(child))));
QVERIFY(testWidget->isItemHidden(parent));
QVERIFY(!testWidget->isItemHidden(child));
// From task 78670 (This caused an core dump)
// Check if we can set an item visible if it already is visible.
testWidget->setItemHidden(parent, false);
testWidget->setItemHidden(parent, false);
QVERIFY(!testWidget->isItemHidden(parent));
// hide, hide and then unhide.
testWidget->setItemHidden(parent, true);
testWidget->setItemHidden(parent, true);
testWidget->setItemHidden(parent, false);
QVERIFY(!testWidget->isItemHidden(parent));
}
void tst_QTreeWidget::setItemHidden2()
{
// From Task 78587
QStringList hl;
hl << "ID" << "Desc";
testWidget->setColumnCount(hl.count());
testWidget->setHeaderLabels(hl);
testWidget->setSortingEnabled(true);
QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
QTreeWidgetItem *leaf = 0;
top->setText(0, "ItemList");
for (int i = 1; i <= 4; i++) {
leaf = new QTreeWidgetItem(top);
leaf->setText(0, QString::asprintf("%d", i));
leaf->setText(1, QString::asprintf("Item %d", i));
}
if (testWidget->topLevelItemCount() > 0) {
top = testWidget->topLevelItem(0);
testWidget->setItemExpanded(top, true);
}
if (testWidget->topLevelItemCount() > 0) {
top = testWidget->topLevelItem(0);
for (int i = 0; i < top->childCount(); i++) {
leaf = top->child(i);
if (leaf->text(0).toInt() % 2 == 0) {
if (!testWidget->isItemHidden(leaf)) {
testWidget->setItemHidden(leaf, true);
}
}
}
}
}
void tst_QTreeWidget::selectedItems_data()
{
QTest::addColumn<int>("topLevel");
QTest::addColumn<int>("children");
QTest::addColumn<bool>("closeTopLevel");
QTest::addColumn<ListIntList>("selectedItems");
QTest::addColumn<ListIntList>("hiddenItems");
QTest::addColumn<ListIntList>("expectedItems");
ListIntList selectedItems;
ListIntList hiddenItems;
ListIntList expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems
<< (IntList()
<< 0);
expectedItems
<< (IntList() << 0);
QTest::newRow("2 top with 2 children, closed, top0 selected, no hidden")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems
<< (IntList()
<< 0 << 0);
expectedItems
<< (IntList() << 0 << 0);
QTest::newRow("2 top with 2 children, closed, top0child0 selected, no hidden")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems
<< (IntList()
<< 0 << 0);
expectedItems
<< (IntList()
<< 0 << 0);
QTest::newRow("2 top with 2 children, open, top0child0 selected, no hidden")
<< 2 << 2 << false << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems << (IntList() << 0);
hiddenItems << (IntList() << 0);
QTest::newRow("2 top with 2 children, closed, top0 selected, top0 hidden")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems << (IntList() << 0 << 0);
hiddenItems << (IntList() << 0);
expectedItems << (IntList() << 0 << 0);
QTest::newRow("2 top with 2 children, closed, top0child0 selected, top0 hidden")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems
<< (IntList() << 0)
<< (IntList() << 0 << 0)
<< (IntList() << 0 << 1)
<< (IntList() << 1)
<< (IntList() << 1 << 0)
<< (IntList() << 1 << 1);
expectedItems
<< (IntList() << 0)
<< (IntList() << 0 << 0)
<< (IntList() << 0 << 1)
<< (IntList() << 1)
<< (IntList() << 1 << 0)
<< (IntList() << 1 << 1);
QTest::newRow("2 top with 2 children, closed, all selected, no hidden")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems
<< (IntList() << 0)
<< (IntList() << 0 << 0)
<< (IntList() << 0 << 1)
<< (IntList() << 1)
<< (IntList() << 1 << 0)
<< (IntList() << 1 << 1);
hiddenItems
<< (IntList() << 0);
expectedItems
//<< (IntList() << 0)
<< (IntList() << 0 << 0)
<< (IntList() << 0 << 1)
<< (IntList() << 1)
<< (IntList() << 1 << 0)
<< (IntList() << 1 << 1);
QTest::newRow("2 top with 2 children, closed, all selected, top0 hidden")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
selectedItems.clear(); hiddenItems.clear(); expectedItems.clear();
selectedItems
<< (IntList() << 0)
<< (IntList() << 0 << 0)
<< (IntList() << 0 << 1)
<< (IntList() << 1)
<< (IntList() << 1 << 0)
<< (IntList() << 1 << 1);
hiddenItems
<< (IntList() << 0 << 1)
<< (IntList() << 1);
expectedItems
<< (IntList() << 0)
<< (IntList() << 0 << 0)
//<< (IntList() << 0 << 1)
//<< (IntList() << 1)
<< (IntList() << 1 << 0)
<< (IntList() << 1 << 1);
QTest::newRow("2 top with 2 children, closed, all selected, top0child1 and top1")
<< 2 << 2 << true << selectedItems << hiddenItems << expectedItems;
}
void tst_QTreeWidget::selectedItems()
{
QFETCH(int, topLevel);
QFETCH(int, children);
QFETCH(bool, closeTopLevel);
QFETCH(ListIntList, selectedItems);
QFETCH(ListIntList, hiddenItems);
QFETCH(ListIntList, expectedItems);
// create items
for (int t=0; t<topLevel; ++t) {
QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
const QString topS = QLatin1String("top") + QString::number(t);
top->setText(0, topS);
for (int c=0; c<children; ++c) {
QTreeWidgetItem *child = new QTreeWidgetItem(top);
child->setText(0, topS + QLatin1String("child") + QString::number(c));
}
}
// set selected
foreach (IntList itemPath, selectedItems) {
QTreeWidgetItem *item = 0;
foreach(int index, itemPath) {
if (!item)
item = testWidget->topLevelItem(index);
else
item = item->child(index);
}
testWidget->setItemSelected(item, true);
}
// hide rows
foreach (IntList itemPath, hiddenItems) {
QTreeWidgetItem *item = 0;
foreach(int index, itemPath) {
if (!item)
item = testWidget->topLevelItem(index);
else
item = item->child(index);
}
testWidget->setItemHidden(item, true);
}
// open/close toplevel
for (int i=0; i<testWidget->topLevelItemCount(); ++i) {
if (closeTopLevel)
testWidget->collapseItem(testWidget->topLevelItem(i));
else
testWidget->expandItem(testWidget->topLevelItem(i));
}
// check selectedItems
QList<QTreeWidgetItem*> sel = testWidget->selectedItems();
QCOMPARE(sel.count(), expectedItems.count());
foreach (IntList itemPath, expectedItems) {
QTreeWidgetItem *item = 0;
foreach(int index, itemPath) {
if (!item)
item = testWidget->topLevelItem(index);
else
item = item->child(index);
}
if (item)
QVERIFY(sel.contains(item));
}
// compare isSelected
for (int t=0; t<testWidget->topLevelItemCount(); ++t) {
QTreeWidgetItem *top = testWidget->topLevelItem(t);
if (testWidget->isItemSelected(top) && !testWidget->isItemHidden(top))
QVERIFY(sel.contains(top));
for (int c=0; c<top->childCount(); ++c) {
QTreeWidgetItem *child = top->child(c);
if (testWidget->isItemSelected(child) && !testWidget->isItemHidden(child))
QVERIFY(sel.contains(child));
}
}
// Possible to select null without crashing?
testWidget->setItemSelected(0, true);
QVERIFY(!testWidget->isItemSelected(0));
// unselect
foreach (IntList itemPath, selectedItems) {
QTreeWidgetItem *item = 0;
foreach(int index, itemPath) {
if (!item)
item = testWidget->topLevelItem(index);
else
item = item->child(index);
}
testWidget->setItemSelected(item, false);
}
QCOMPARE(testWidget->selectedItems().count(), 0);
}
void tst_QTreeWidget::itemAssignment()
{
// create item with children and parent but not insert in the view
QTreeWidgetItem grandParent;
QTreeWidgetItem *parent = new QTreeWidgetItem(&grandParent);
parent->setText(0, "foo");
parent->setText(1, "bar");
for (int i=0; i<5; ++i) {
QTreeWidgetItem *child = new QTreeWidgetItem(parent);
child->setText(0, "bingo");
child->setText(1, "bango");
}
QCOMPARE(parent->parent(), &grandParent);
QVERIFY(!parent->treeWidget());
QCOMPARE(parent->columnCount(), 2);
QCOMPARE(parent->text(0), QString("foo"));
QCOMPARE(parent->childCount(), 5);
QCOMPARE(parent->child(0)->parent(), parent);
// create item which is inserted in the widget
QTreeWidgetItem item(testWidget);
item.setText(0, "baz");
QVERIFY(!item.parent());
QCOMPARE(item.treeWidget(), static_cast<QTreeWidget *>(testWidget));
QCOMPARE(item.columnCount(), 1);
QCOMPARE(item.text(0), QString("baz"));
QCOMPARE(item.childCount(), 0);
// assign and test
*parent = item;
QCOMPARE(parent->parent(), &grandParent);
QVERIFY(!parent->treeWidget());
QCOMPARE(parent->columnCount(), 1);
QCOMPARE(parent->text(0), QString("baz"));
QCOMPARE(parent->childCount(), 5);
QCOMPARE(parent->child(0)->parent(), parent);
}
void tst_QTreeWidget::clone_data()
{
QTest::addColumn<int>("column");
QTest::addColumn<int>("topLevelIndex");
QTest::addColumn<int>("childIndex");
QTest::addColumn<QStringList>("topLevelText");
QTest::addColumn<QStringList>("childText");
QTest::addColumn<bool>("cloneChild");
QTest::newRow("clone parent with child") << 0 << 0 << 0
<< (QStringList() << "some text")
<< (QStringList() << "more text")
<< false;
QTest::newRow("clone child") << 0 << 0 << 0
<< (QStringList() << "some text")
<< (QStringList() << "more text")
<< true;
}
void tst_QTreeWidget::clone()
{
QFETCH(int, column);
QFETCH(int, topLevelIndex);
QFETCH(int, childIndex);
QFETCH(QStringList, topLevelText);
QFETCH(QStringList, childText);
QFETCH(bool, cloneChild);
for (int i = 0; i < topLevelText.count(); ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
item->setText(column, topLevelText.at(i));
for (int j = 0; j < childText.count(); ++j) {
QTreeWidgetItem *child = new QTreeWidgetItem(item);
child->setText(column, childText.at(j));
}
}
QTreeWidgetItem *original = testWidget->topLevelItem(topLevelIndex);
QTreeWidgetItem *copy = original->clone();
QCOMPARE(copy->text(column), original->text(column));
QCOMPARE(copy->childCount(), original->childCount());
QVERIFY(!copy->parent());
QVERIFY(!copy->treeWidget());
QTreeWidgetItem *originalChild = original->child(childIndex);
QTreeWidgetItem *copiedChild = cloneChild ? originalChild->clone() : copy->child(childIndex);
QVERIFY(copiedChild != originalChild);
QCOMPARE(copiedChild->text(column), originalChild->text(column));
QCOMPARE(copiedChild->childCount(), originalChild->childCount());
QCOMPARE(copiedChild->parent(), cloneChild ? 0 : copy);
QVERIFY(!copiedChild->treeWidget());
if (cloneChild)
delete copiedChild;
delete copy;
}
void tst_QTreeWidget::expand_data()
{
QTest::addColumn<int>("topLevelIndex");
QTest::addColumn<int>("topLevelCount");
QTest::addColumn<int>("childIndex");
QTest::addColumn<int>("childCount");
QTest::newRow("the only test data for now") << 0 << 1 << 0 << 1;
}
void tst_QTreeWidget::expand()
{
QFETCH(int, topLevelIndex);
QFETCH(int, topLevelCount);
QFETCH(int, childIndex);
QFETCH(int, childCount);
for (int i = 0; i < topLevelCount; ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
for (int j = 0; j < childCount; ++j)
new QTreeWidgetItem(item);
}
QTreeWidgetItem *topLevelItem = testWidget->topLevelItem(topLevelIndex);
QTreeWidgetItem *childItem = topLevelItem->child(childIndex);
QVERIFY(!testWidget->isItemExpanded(topLevelItem));
testWidget->setItemExpanded(topLevelItem, true);
QVERIFY(testWidget->isItemExpanded(topLevelItem));
QVERIFY(!testWidget->isItemExpanded(childItem));
testWidget->setItemExpanded(childItem, true);
QVERIFY(testWidget->isItemExpanded(childItem));
QVERIFY(testWidget->isItemExpanded(topLevelItem));
testWidget->setItemExpanded(topLevelItem, false);
QVERIFY(!testWidget->isItemExpanded(topLevelItem));
QVERIFY(testWidget->isItemExpanded(childItem));
testWidget->setItemExpanded(childItem, false);
QVERIFY(!testWidget->isItemExpanded(childItem));
}
void tst_QTreeWidget::checkState_data()
{
}
void tst_QTreeWidget::checkState()
{
QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
item->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *firstChild = new QTreeWidgetItem(item);
firstChild->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *seccondChild = new QTreeWidgetItem(item);
seccondChild->setCheckState(0, Qt::Unchecked);
QCOMPARE(item->checkState(0), Qt::Unchecked);
QCOMPARE(firstChild->checkState(0), Qt::Unchecked);
QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
firstChild->setCheckState(0, Qt::Checked);
QCOMPARE(item->checkState(0), Qt::Unchecked);
QCOMPARE(firstChild->checkState(0), Qt::Checked);
QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
item->setFlags(item->flags()|Qt::ItemIsAutoTristate);
QCOMPARE(item->checkState(0), Qt::PartiallyChecked);
QCOMPARE(firstChild->checkState(0), Qt::Checked);
QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
seccondChild->setCheckState(0, Qt::Checked);
QCOMPARE(item->checkState(0), Qt::Checked);
QCOMPARE(firstChild->checkState(0), Qt::Checked);
QCOMPARE(seccondChild->checkState(0), Qt::Checked);
firstChild->setCheckState(0, Qt::Unchecked);
seccondChild->setCheckState(0, Qt::Unchecked);
QCOMPARE(item->checkState(0), Qt::Unchecked);
QCOMPARE(firstChild->checkState(0), Qt::Unchecked);
QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
// Can't force the state to PartiallyChecked; state comes from children
item->setCheckState(0, Qt::PartiallyChecked);
QCOMPARE(item->checkState(0), Qt::Unchecked);
QCOMPARE(firstChild->checkState(0), Qt::Unchecked);
QCOMPARE(seccondChild->checkState(0), Qt::Unchecked);
}
void tst_QTreeWidget::findItems_data()
{
QTest::addColumn<int>("column");
QTest::addColumn<QStringList>("topLevelText");
QTest::addColumn<QStringList>("childText");
QTest::addColumn<QString>("pattern");
QTest::addColumn<int>("resultCount");
QTest::addColumn<QStringList>("resultText");
QTest::newRow("find in toplevel")
<< 0
<< (QStringList() << "This is a text" << "This is another" << "This is the one")
<< (QStringList() << "A child" << "This is not the one" << "And yet another child")
<< "This is the one"
<< 1
<< (QStringList() << "This is the one");
QTest::newRow("find child")
<< 0
<< (QStringList() << "This is a text" << "This is another" << "This is the one")
<< (QStringList() << "A child" << "This is not the one" << "And yet another child")
<< "A child"
<< 3 // once for each branch
<< (QStringList() << "A child");
}
void tst_QTreeWidget::findItems()
{
QFETCH(int, column);
QFETCH(QStringList, topLevelText);
QFETCH(QStringList, childText);
QFETCH(QString, pattern);
QFETCH(int, resultCount);
QFETCH(QStringList, resultText);
for (int i = 0; i < topLevelText.count(); ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
item->setText(column, topLevelText.at(i));
for (int j = 0; j < childText.count(); ++j) {
QTreeWidgetItem *child = new QTreeWidgetItem(item);
child->setText(column, childText.at(j));
}
}
QList<QTreeWidgetItem*> result = testWidget->findItems(pattern,
Qt::MatchExactly|Qt::MatchRecursive);
QCOMPARE(result.count(), resultCount);
for (int k = 0; k < result.count() && k < resultText.count(); ++k)
QCOMPARE(result.at(k)->text(column), resultText.at(k));
}
void tst_QTreeWidget::findItemsInColumn()
{
// Create 5 root items.
for (int i = 0; i < 5; i++)
new QTreeWidgetItem(testWidget, QStringList() << QString::number(i));
// Create a child with two columns for each root item.
for (int i = 0; i < 5; i++) {
QTreeWidgetItem * const parent = testWidget->topLevelItem(i);
new QTreeWidgetItem(parent, QStringList() << QString::number(i * 10) << QString::number(i * 100));
}
// Recursively search column one for 400.
QList<QTreeWidgetItem*> items = testWidget->findItems("400", Qt::MatchExactly|Qt::MatchRecursive, 1);
QCOMPARE(items.count(), 1);
}
void tst_QTreeWidget::sortItems_data()
{
QTest::addColumn<int>("column");
QTest::addColumn<int>("order");
QTest::addColumn<QStringList>("topLevelText");
QTest::addColumn<QStringList>("childText");
QTest::addColumn<QStringList>("topLevelResult");
QTest::addColumn<QStringList>("childResult");
QTest::addColumn<IntList>("expectedTopRows");
QTest::addColumn<IntList>("expectedChildRows");
QTest::newRow("ascending order")
<< 0
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "c" << "d" << "a" << "b")
<< (QStringList() << "e" << "h" << "g" << "f")
<< (QStringList() << "a" << "b" << "c" << "d")
<< (QStringList() << "e" << "f" << "g" << "h")
<< (IntList() << 2 << 3 << 0 << 1)
<< (IntList() << 0 << 3 << 2 << 1);
QTest::newRow("descending order")
<< 0
<< static_cast<int>(Qt::DescendingOrder)
<< (QStringList() << "c" << "d" << "a" << "b")
<< (QStringList() << "e" << "h" << "g" << "f")
<< (QStringList() << "d" << "c" << "b" << "a")
<< (QStringList() << "h" << "g" << "f" << "e")
<< (IntList() << 1 << 0 << 3 << 2)
<< (IntList() << 3 << 0 << 1 << 2);
}
void tst_QTreeWidget::sortItems()
{
QFETCH(int, column);
QFETCH(int, order);
QFETCH(QStringList, topLevelText);
QFETCH(QStringList, childText);
QFETCH(QStringList, topLevelResult);
QFETCH(QStringList, childResult);
QFETCH(IntList, expectedTopRows);
QFETCH(IntList, expectedChildRows);
testWidget->setSortingEnabled(false);
for (int i = 0; i < topLevelText.count(); ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem(testWidget);
item->setText(column, topLevelText.at(i));
for (int j = 0; j < childText.count(); ++j) {
QTreeWidgetItem *child = new QTreeWidgetItem(item);
child->setText(column, childText.at(j));
}
}
QAbstractItemModel *model = testWidget->model();
QList<QPersistentModelIndex> tops;
for (int r = 0; r < model->rowCount(QModelIndex()); ++r) {
QPersistentModelIndex p = model->index(r, 0, QModelIndex());
tops << p;
}
QList<QPersistentModelIndex> children;
for (int s = 0; s < model->rowCount(tops.first()); ++s) {
QPersistentModelIndex c = model->index(s, 0, tops.first());
children << c;
}
testWidget->sortItems(column, static_cast<Qt::SortOrder>(order));
QCOMPARE(testWidget->sortColumn(), column);
for (int k = 0; k < topLevelResult.count(); ++k) {
QTreeWidgetItem *item = testWidget->topLevelItem(k);
QCOMPARE(item->text(column), topLevelResult.at(k));
for (int l = 0; l < childResult.count(); ++l)
QCOMPARE(item->child(l)->text(column), childResult.at(l));
}
for (int m = 0; m < tops.count(); ++m)
QCOMPARE(tops.at(m).row(), expectedTopRows.at(m));
for (int n = 0; n < children.count(); ++n)
QCOMPARE(children.at(n).row(), expectedChildRows.at(n));
}
void tst_QTreeWidget::deleteItems_data()
{
QTest::addColumn<int>("topLevelCount");
QTest::addColumn<int>("childCount");
QTest::addColumn<int>("grandChildCount");
QTest::addColumn<int>("deleteTopLevelCount");
QTest::addColumn<int>("deleteChildCount");
QTest::addColumn<int>("deleteGrandChildCount");
QTest::addColumn<int>("expectedTopLevelCount");
QTest::addColumn<int>("expectedChildCount");
QTest::addColumn<int>("expectedGrandChildCount");
QTest::addColumn<int>("persistentRow");
QTest::addColumn<int>("persistentColumn");
QTest::addColumn<bool>("persistentIsValid");
QTest::newRow("start with 10, delete 1")
<< 10 << 10 << 10
<< 1 << 1 << 1
<< 9 << 9 << 9
<< 0 << 0 << false;
QTest::newRow("start with 10, delete 5")
<< 10 << 10 << 10
<< 5 << 5 << 5
<< 5 << 5 << 5
<< 0 << 0 << false;
QTest::newRow("mixed")
<< 10 << 13 << 7
<< 3 << 7 << 4
<< 7 << 6 << 3
<< 0 << 0 << false;
QTest::newRow("all")
<< 10 << 10 << 10
<< 10 << 10 << 10
<< 0 << 0 << 0
<< 0 << 0 << false;
}
void tst_QTreeWidget::deleteItems()
{
QFETCH(int, topLevelCount);
QFETCH(int, childCount);
QFETCH(int, grandChildCount);
QFETCH(int, deleteTopLevelCount);
QFETCH(int, deleteChildCount);
QFETCH(int, deleteGrandChildCount);
QFETCH(int, expectedTopLevelCount);
QFETCH(int, expectedChildCount);
QFETCH(int, expectedGrandChildCount);
QFETCH(int, persistentRow);
QFETCH(int, persistentColumn);
QFETCH(bool, persistentIsValid);
for (int i = 0; i < topLevelCount; ++i) {
QTreeWidgetItem *top = new QTreeWidgetItem(testWidget);
for (int j = 0; j < childCount; ++j) {
QTreeWidgetItem *child = new QTreeWidgetItem(top);
for (int k = 0; k < grandChildCount; ++k) {
new QTreeWidgetItem(child);
}
}
}
QPersistentModelIndex persistent = testWidget->model()->index(persistentRow,
persistentColumn);
QVERIFY(persistent.isValid());
QTreeWidgetItem *top = testWidget->topLevelItem(0);
QTreeWidgetItem *child = top->child(0);
for (int n = 0; n < deleteGrandChildCount; ++n)
delete child->child(0);
QCOMPARE(child->childCount(), expectedGrandChildCount);
for (int m = 0; m < deleteChildCount; ++m)
delete top->child(0);
QCOMPARE(top->childCount(), expectedChildCount);
for (int l = 0; l < deleteTopLevelCount; ++l)
delete testWidget->topLevelItem(0);
QCOMPARE(testWidget->topLevelItemCount(), expectedTopLevelCount);
QCOMPARE(persistent.isValid(), persistentIsValid);
}
void tst_QTreeWidget::itemAboveOrBelow()
{
QTreeWidget tw;
tw.setColumnCount(1);
QTreeWidgetItem *twi = new QTreeWidgetItem(&tw, QStringList() << "Test");
QTreeWidgetItem *twi2 = new QTreeWidgetItem(&tw, QStringList() << "Test 2");
QTreeWidgetItem *twi3 = new QTreeWidgetItem(&tw, QStringList() << "Test 3");
tw.show();
QCOMPARE(tw.itemAbove(twi2), twi);
QCOMPARE(tw.itemBelow(twi2), twi3);
}
void tst_QTreeWidget::itemStreaming_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<QString>("toolTip");
QTest::addColumn<int>("column");
QTest::newRow("Data") << "item text" << "tool tip text" << 0;
}
void tst_QTreeWidget::itemStreaming()
{
QFETCH(QString, text);
QFETCH(QString, toolTip);
QFETCH(int, column);
QTreeWidgetItem item(testWidget);
QCOMPARE(item.text(column), QString());
QCOMPARE(item.toolTip(column), QString());
item.setText(column, text);
item.setToolTip(column, toolTip);
QCOMPARE(item.text(column), text);
QCOMPARE(item.toolTip(column), toolTip);
QByteArray buffer;
QDataStream out(&buffer, QIODevice::WriteOnly);
out << item;
QTreeWidgetItem item2(testWidget);
QCOMPARE(item2.text(column), QString());
QCOMPARE(item2.toolTip(column), QString());
QVERIFY(!buffer.isEmpty());
QDataStream in(&buffer, QIODevice::ReadOnly);
in >> item2;
QCOMPARE(item2.text(column), text);
QCOMPARE(item2.toolTip(column), toolTip);
}
void tst_QTreeWidget::insertTopLevelItems_data()
{
QTest::addColumn<QStringList>("initialText");
QTest::addColumn<QStringList>("insertText");
QTest::addColumn<int>("insertTopLevelIndex");
QTest::addColumn<int>("expectedTopLevelIndex");
QTest::addColumn<int>("insertChildIndex");
QTest::addColumn<int>("expectedChildIndex");
QStringList initial = (QStringList() << "foo" << "bar");
QStringList insert = (QStringList() << "baz");
QTest::newRow("Insert at count") << initial << insert
<< initial.count() << initial.count()
<< initial.count() << initial.count();
QTest::newRow("Insert in the middle") << initial << insert
<< (initial.count() / 2) << (initial.count() / 2)
<< (initial.count() / 2) << (initial.count() / 2);
QTest::newRow("Insert less than 0") << initial << insert
<< -1 << -1
<< -1 << -1;
QTest::newRow("Insert beyond count") << initial << insert
<< initial.count() + 1 << -1
<< initial.count() + 1 << -1;
}
void tst_QTreeWidget::insertTopLevelItems()
{
QFETCH(QStringList, initialText);
QFETCH(QStringList, insertText);
QFETCH(int, insertTopLevelIndex);
QFETCH(int, expectedTopLevelIndex);
QFETCH(int, insertChildIndex);
QFETCH(int, expectedChildIndex);
testWidget->setSortingEnabled(false);
{ // insert the initial items
QCOMPARE(testWidget->topLevelItemCount(), 0);
for (int i = 0; i < initialText.count(); ++i) {
QTreeWidgetItem *top = new QTreeWidgetItem(QStringList(initialText.at(i)));
testWidget->addTopLevelItem(top);
QCOMPARE(testWidget->indexOfTopLevelItem(top), i);
}
QCOMPARE(testWidget->topLevelItemCount(), initialText.count());
}
{ // test adding children
QTreeWidgetItem *topLevel = testWidget->topLevelItem(0);
for (int i = 0; i < initialText.count(); ++i)
topLevel->addChild(new QTreeWidgetItem(QStringList(initialText.at(i))));
QCOMPARE(topLevel->childCount(), initialText.count());
}
{ // test adding more top level items
QTreeWidgetItem *topsy = new QTreeWidgetItem(QStringList(insertText.at(0)));
testWidget->insertTopLevelItem(insertTopLevelIndex, topsy);
if (expectedTopLevelIndex == -1) {
QCOMPARE(testWidget->topLevelItemCount(), initialText.count());
delete topsy;
} else {
QTreeWidgetItem *item = testWidget->topLevelItem(expectedTopLevelIndex);
QVERIFY(item != 0);
QCOMPARE(item->text(0), insertText.at(0));
QCOMPARE(testWidget->indexOfTopLevelItem(item), expectedTopLevelIndex);
}
}
{ // test adding more children
QTreeWidgetItem *topLevel = testWidget->topLevelItem(0);
QVERIFY(topLevel != 0);
QTreeWidgetItem *child = new QTreeWidgetItem(QStringList(insertText.at(0)));
topLevel->insertChild(insertChildIndex, child);
if (expectedChildIndex == -1) {
QCOMPARE(topLevel->childCount(), initialText.count());
delete child;
} else {
QTreeWidgetItem *item = topLevel->child(expectedChildIndex);
QVERIFY(item != 0);
QCOMPARE(item->text(0), insertText.at(0));
}
}
}
static void fillTreeWidget(QTreeWidgetItem *parent, int rows)
{
const int columns = parent->treeWidget()->columnCount();
for (int r = 0; r < rows; ++r) {
const QString prefix = QLatin1String("[r:") + QString::number(r) + QLatin1String(",c:");
QTreeWidgetItem *w = new QTreeWidgetItem(parent);
for (int c = 0; c < columns; ++c)
w->setText(c, prefix + QString::number(c) + QLatin1Char(']'));
fillTreeWidget(w, rows - r - 1);
}
}
static void fillTreeWidget(QTreeWidget *tree, int rows)
{
for (int r = 0; r < rows; ++r) {
QTreeWidgetItem *w = new QTreeWidgetItem();
const QString prefix = QLatin1String("[r:") + QString::number(r) + QLatin1String(",c:");
for (int c = 0; c < tree->columnCount(); ++c)
w->setText(c, prefix + QString::number(c) + QLatin1Char(']'));
tree->insertTopLevelItem(r, w);
fillTreeWidget(w, rows - r - 1);
}
}
void tst_QTreeWidget::keyboardNavigation()
{
int rows = 8;
fillTreeWidget(testWidget, rows);
QVector<Qt::Key> keymoves;
keymoves << Qt::Key_Down << Qt::Key_Right << Qt::Key_Left
<< Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down
<< Qt::Key_Right
<< Qt::Key_Up << Qt::Key_Left << Qt::Key_Left
<< Qt::Key_Up << Qt::Key_Down << Qt::Key_Up << Qt::Key_Up
<< Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Up
<< Qt::Key_Down << Qt::Key_Right << Qt::Key_Down << Qt::Key_Down
<< Qt::Key_Down << Qt::Key_Right << Qt::Key_Down << Qt::Key_Down
<< Qt::Key_Left << Qt::Key_Left << Qt::Key_Up << Qt::Key_Down
<< Qt::Key_Up << Qt::Key_Up << Qt::Key_Up << Qt::Key_Left
<< Qt::Key_Down << Qt::Key_Right << Qt::Key_Right << Qt::Key_Right
<< Qt::Key_Left << Qt::Key_Left << Qt::Key_Right << Qt::Key_Left;
int row = 0;
QTreeWidgetItem *item = testWidget->topLevelItem(0);
testWidget->setCurrentItem(item);
QCOMPARE(testWidget->currentItem(), item);
QApplication::instance()->processEvents();
QScrollBar *scrollBar = testWidget->horizontalScrollBar();
bool checkScroll = false;
for (int i = 0; i < keymoves.size(); ++i) {
Qt::Key key = keymoves.at(i);
int valueBeforeClick = scrollBar->value();
if (valueBeforeClick >= scrollBar->singleStep())
checkScroll = true;
else
checkScroll = false;
QTest::keyClick(testWidget, key);
QApplication::instance()->processEvents();
switch (key) {
case Qt::Key_Up:
if (row > 0) {
if (item->parent())
item = item->parent()->child(row - 1);
else
item = testWidget->topLevelItem(row - 1);
row -= 1;
} else if (item->parent()) {
item = item->parent();
row = item->parent() ? item->parent()->indexOfChild(item) : testWidget->indexOfTopLevelItem(item);
}
break;
case Qt::Key_Down:
if (testWidget->isItemExpanded(item)) {
row = 0;
item = item->child(row);
} else {
row = qMin(rows - 1, row + 1);
if (item->parent())
item = item->parent()->child(row);
else
item = testWidget->topLevelItem(row);
}
break;
case Qt::Key_Left:
if (checkScroll) {
QVERIFY(testWidget->isItemExpanded(item));
QCOMPARE(scrollBar->value(), valueBeforeClick - scrollBar->singleStep());
}
// windows style right will walk to the parent
if (testWidget->currentItem() != item) {
QCOMPARE(testWidget->currentItem(), item->parent());
item = testWidget->currentItem();
row = item->parent() ? item->parent()->indexOfChild(item) : testWidget->indexOfTopLevelItem(item);;
}
break;
case Qt::Key_Right:
if (checkScroll)
QCOMPARE(scrollBar->value(), valueBeforeClick + scrollBar->singleStep());
// windows style right will walk to the first child
if (testWidget->currentItem() != item) {
QCOMPARE(testWidget->currentItem()->parent(), item);
row = item->indexOfChild(testWidget->currentItem());
item = testWidget->currentItem();
QCOMPARE(row, 0);
}
break;
default:
QVERIFY(false);
}
QTreeWidgetItem *current = testWidget->currentItem();
QCOMPARE(current->text(0), QLatin1String("[r:") + QString::number(row) + QLatin1String(",c:0]"));
if (current->parent())
QCOMPARE(current->parent()->indexOfChild(current), row);
else
QCOMPARE(testWidget->indexOfTopLevelItem(current), row);
}
}
void tst_QTreeWidget::scrollToItem()
{
// Check if all parent nodes of the item found are expanded.
// Reported in task #78761
QTreeWidgetItem *search = nullptr;
for (int i=0; i<2; ++i) {
QTreeWidgetItem *bar = new QTreeWidgetItem(testWidget);
bar->setText(0, QString::number(i));
for (int j=0; j<2; ++j) {
QTreeWidgetItem *foo = new QTreeWidgetItem(bar);
foo->setText(0, bar->text(0) + QString::number(j));
for (int k=0; k<2; ++k) {
search = new QTreeWidgetItem(foo);
search->setText(0, foo->text(0) + QString::number(k));
}
}
}
testWidget->setHeaderLabels(QStringList() << "foo");
testWidget->scrollToItem(search);
QCOMPARE(search->text(0), QLatin1String("111"));
QTreeWidgetItem *par = search->parent();
QVERIFY(testWidget->isItemExpanded(par));
par = par->parent();
QVERIFY(testWidget->isItemExpanded(par));
}
// From task #85413
void tst_QTreeWidget::setSortingEnabled()
{
QStringList hl;
hl << "ID";
testWidget->setColumnCount(hl.count());
testWidget->setHeaderLabels(hl);
QTreeWidgetItem *item1 = new QTreeWidgetItem(testWidget);
QTreeWidgetItem *item2 = new QTreeWidgetItem(testWidget);
testWidget->setSortingEnabled(true);
QCOMPARE(testWidget->isSortingEnabled(), true);
QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
QCOMPARE(testWidget->topLevelItem(0), item1);
QCOMPARE(testWidget->topLevelItem(1), item2);
// Make sure we do it twice
testWidget->setSortingEnabled(true);
QCOMPARE(testWidget->isSortingEnabled(), true);
QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
testWidget->setSortingEnabled(false);
QCOMPARE(testWidget->isSortingEnabled(), false);
QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
testWidget->setSortingEnabled(false);
QCOMPARE(testWidget->isSortingEnabled(), false);
QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
// And back again so that we make sure that we test the transition from false to true
testWidget->setSortingEnabled(true);
QCOMPARE(testWidget->isSortingEnabled(), true);
QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
testWidget->setSortingEnabled(true);
QCOMPARE(testWidget->isSortingEnabled(), true);
QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown());
testWidget->setSortingEnabled(false);
}
void tst_QTreeWidget::addChild()
{
QTreeWidget tree;
for (int x = 0; x < 2; ++x) {
QTreeWidget *view = x ? &tree : static_cast<QTreeWidget*>(0);
QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)view);
QCOMPARE(item->childCount(), 0);
// try to add 0
item->addChild(0);
QCOMPARE(item->childCount(), 0);
QCOMPARE(item->indexOfChild(0), -1);
// add one at a time
QList<QTreeWidgetItem*> children;
for (int i = 0; i < 10; ++i) {
QTreeWidgetItem *child = new QTreeWidgetItem();
item->addChild(child);
QCOMPARE(item->childCount(), i+1);
QCOMPARE(item->child(i), child);
QCOMPARE(item->indexOfChild(child), i);
QCOMPARE(child->parent(), item);
QCOMPARE(child->treeWidget(), view);
item->addChild(child);
QCOMPARE(item->childCount(), i+1);
children.append(child);
}
// take them all
QList<QTreeWidgetItem*> taken = item->takeChildren();
QCOMPARE(taken, children);
QCOMPARE(item->childCount(), 0);
for (int i = 0; i < taken.count(); ++i) {
QCOMPARE(taken.at(i)->parent(), nullptr);
QCOMPARE(taken.at(i)->treeWidget(), nullptr);
item->addChild(taken.at(i)); // re-add
}
// delete one at a time
while (!children.isEmpty()) {
QTreeWidgetItem *ti = children.takeFirst();
delete ti;
QCOMPARE(item->childCount(), children.count());
for (int i = 0; i < children.count(); ++i)
QCOMPARE(item->child(i), children.at(i));
}
// add none
{
int count = item->childCount();
item->addChildren(QList<QTreeWidgetItem*>());
QCOMPARE(item->childCount(), count);
}
// add many at a time
const int count = 10;
for (int i = 0; i < 100; i += count) {
QList<QTreeWidgetItem*> list;
for (int j = 0; j < count; ++j)
list << new QTreeWidgetItem(QStringList(QString::number(j)));
item->addChildren(list);
QCOMPARE(item->childCount(), count + i);
for (int j = 0; j < count; ++j) {
QCOMPARE(item->child(i+j), list.at(j));
QCOMPARE(item->child(i+j)->parent(), item);
}
item->addChildren(list);
QCOMPARE(item->childCount(), count + i);
}
if (!view)
delete item;
}
}
void tst_QTreeWidget::setData()
{
{
QTreeWidgetItem *headerItem = new QTreeWidgetItem();
headerItem->setText(0, "Item1");
testWidget->setHeaderItem(headerItem);
QSignalSpy headerDataChangedSpy(
testWidget->model(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)));
QSignalSpy dataChangedSpy(
testWidget->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)));
QSignalSpy itemChangedSpy(
testWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
headerItem->setText(0, "test");
QCOMPARE(dataChangedSpy.count(), 0);
QCOMPARE(headerDataChangedSpy.count(), 1);
QCOMPARE(itemChangedSpy.count(), 0); // no itemChanged() signal for header item
headerItem->setData(-1, -1, QVariant());
}
{
QSignalSpy itemChangedSpy(
testWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
QTreeWidgetItem *item = new QTreeWidgetItem();
testWidget->addTopLevelItem(item);
for (int x = 0; x < 2; ++x) {
for (int i = 1; i <= 2; ++i) {
for (int j = 0; j < 5; ++j) {
QVariantList args;
const QString iS = QString::number(i);
const QString text = QLatin1String("text ") + iS;
item->setText(j, text);
QCOMPARE(item->text(j), text);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setText(j, text);
QCOMPARE(itemChangedSpy.count(), 0);
QPixmap pixmap(32, 32);
pixmap.fill((i == 1) ? Qt::red : Qt::green);
QIcon icon(pixmap);
item->setIcon(j, icon);
QCOMPARE(item->icon(j), icon);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setIcon(j, icon);
QCOMPARE(itemChangedSpy.count(), 0);
const QString toolTip = QLatin1String("toolTip ") + iS;
item->setToolTip(j, toolTip);
QCOMPARE(item->toolTip(j), toolTip);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setToolTip(j, toolTip);
QCOMPARE(itemChangedSpy.count(), 0);
const QString statusTip = QLatin1String("statusTip ") + iS;
item->setStatusTip(j, statusTip);
QCOMPARE(item->statusTip(j), statusTip);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setStatusTip(j, statusTip);
QCOMPARE(itemChangedSpy.count(), 0);
const QString whatsThis = QLatin1String("whatsThis ") + iS;
item->setWhatsThis(j, whatsThis);
QCOMPARE(item->whatsThis(j), whatsThis);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setWhatsThis(j, whatsThis);
QCOMPARE(itemChangedSpy.count(), 0);
QSize sizeHint(64*i, 48*i);
item->setSizeHint(j, sizeHint);
QCOMPARE(item->sizeHint(j), sizeHint);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setSizeHint(j, sizeHint);
QCOMPARE(itemChangedSpy.count(), 0);
QFont font;
item->setFont(j, font);
QCOMPARE(item->font(j), font);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setFont(j, font);
QCOMPARE(itemChangedSpy.count(), 0);
Qt::Alignment textAlignment((i == 1)
? Qt::AlignLeft|Qt::AlignVCenter
: Qt::AlignRight);
item->setTextAlignment(j, textAlignment);
QCOMPARE(item->textAlignment(j), int(textAlignment));
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setTextAlignment(j, textAlignment);
QCOMPARE(itemChangedSpy.count(), 0);
QColor backgroundColor((i == 1) ? Qt::blue : Qt::yellow);
item->setBackground(j, backgroundColor);
QCOMPARE(item->background(j).color(), backgroundColor);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setBackground(j, backgroundColor);
QCOMPARE(itemChangedSpy.count(), 0);
QColor textColor((i == 1) ? Qt::green : Qt::cyan);
item->setTextColor(j, textColor);
QCOMPARE(item->textColor(j), textColor);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setTextColor(j, textColor);
QCOMPARE(itemChangedSpy.count(), 0);
Qt::CheckState checkState((i == 1) ? Qt::PartiallyChecked : Qt::Checked);
item->setCheckState(j, checkState);
QCOMPARE(item->checkState(j), checkState);
QCOMPARE(itemChangedSpy.count(), 1);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setCheckState(j, checkState);
QCOMPARE(itemChangedSpy.count(), 0);
QCOMPARE(item->text(j), text);
QCOMPARE(item->icon(j), icon);
QCOMPARE(item->toolTip(j), toolTip);
QCOMPARE(item->statusTip(j), statusTip);
QCOMPARE(item->whatsThis(j), whatsThis);
QCOMPARE(item->sizeHint(j), sizeHint);
QCOMPARE(item->font(j), font);
QCOMPARE(item->textAlignment(j), int(textAlignment));
QCOMPARE(item->background(j).color(), backgroundColor);
QCOMPARE(item->textColor(j), textColor);
QCOMPARE(item->checkState(j), checkState);
QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::DisplayRole)), text);
QCOMPARE(qvariant_cast<QIcon>(item->data(j, Qt::DecorationRole)), icon);
QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::ToolTipRole)), toolTip);
QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::StatusTipRole)), statusTip);
QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::WhatsThisRole)), whatsThis);
QCOMPARE(qvariant_cast<QSize>(item->data(j, Qt::SizeHintRole)), sizeHint);
QCOMPARE(qvariant_cast<QFont>(item->data(j, Qt::FontRole)), font);
QCOMPARE(qvariant_cast<int>(item->data(j, Qt::TextAlignmentRole)), int(textAlignment));
QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundColorRole)), QBrush(backgroundColor));
QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundRole)), QBrush(backgroundColor));
QCOMPARE(qvariant_cast<QColor>(item->data(j, Qt::TextColorRole)), textColor);
QCOMPARE(qvariant_cast<int>(item->data(j, Qt::CheckStateRole)), int(checkState));
item->setBackground(j, pixmap);
QCOMPARE(item->background(j).texture(), pixmap);
QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundRole)).texture(), pixmap);
args = itemChangedSpy.takeFirst();
QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item);
QCOMPARE(qvariant_cast<int>(args.at(1)), j);
item->setBackground(j, pixmap);
QCOMPARE(itemChangedSpy.count(), 0);
item->setData(j, Qt::DisplayRole, QVariant());
item->setData(j, Qt::DecorationRole, QVariant());
item->setData(j, Qt::ToolTipRole, QVariant());
item->setData(j, Qt::StatusTipRole, QVariant());
item->setData(j, Qt::WhatsThisRole, QVariant());
item->setData(j, Qt::SizeHintRole, QVariant());
item->setData(j, Qt::FontRole, QVariant());
item->setData(j, Qt::TextAlignmentRole, QVariant());
item->setData(j, Qt::BackgroundColorRole, QVariant());
item->setData(j, Qt::TextColorRole, QVariant());
item->setData(j, Qt::CheckStateRole, QVariant());
QCOMPARE(itemChangedSpy.count(), 11);
itemChangedSpy.clear();
QCOMPARE(item->data(j, Qt::DisplayRole).toString(), QString());
QCOMPARE(item->data(j, Qt::DecorationRole), QVariant());
QCOMPARE(item->data(j, Qt::ToolTipRole), QVariant());
QCOMPARE(item->data(j, Qt::StatusTipRole), QVariant());
QCOMPARE(item->data(j, Qt::WhatsThisRole), QVariant());
QCOMPARE(item->data(j, Qt::SizeHintRole), QVariant());
QCOMPARE(item->data(j, Qt::FontRole), QVariant());
QCOMPARE(item->data(j, Qt::TextAlignmentRole), QVariant());
QCOMPARE(item->data(j, Qt::BackgroundColorRole), QVariant());
QCOMPARE(item->data(j, Qt::BackgroundRole), QVariant());
QCOMPARE(item->data(j, Qt::TextColorRole), QVariant());
QCOMPARE(item->data(j, Qt::CheckStateRole), QVariant());
}
}
}
// ### add more data types here
item->setData(0, Qt::DisplayRole, 5);
QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::Int);
item->setData(0, Qt::DisplayRole, "test");
QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::String);
item->setData(0, Qt::DisplayRole, 0.4);
QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::Double);
delete item;
}
}
class QTreeWidgetDataChanged : public QTreeWidget
{
Q_OBJECT
public:
using QTreeWidget::QTreeWidget;
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) override
{
QTreeWidget::dataChanged(topLeft, bottomRight, roles);
currentRoles = roles;
}
QVector<int> currentRoles;
};
void tst_QTreeWidget::itemData()
{
QTreeWidgetDataChanged widget;
QTreeWidgetItem item(&widget);
widget.setColumnCount(2);
item.setFlags(item.flags() | Qt::ItemIsEditable);
item.setData(0, Qt::DisplayRole, QString("0"));
QCOMPARE(widget.currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole}));
item.setData(0, Qt::CheckStateRole, Qt::PartiallyChecked);
QCOMPARE(widget.currentRoles, {Qt::CheckStateRole});
for (int i = 0; i < 4; ++i) {
item.setData(0, Qt::UserRole + i, QString::number(i + 1));
QCOMPARE(widget.currentRoles, {Qt::UserRole + i});
}
QMap<int, QVariant> flags = widget.model()->itemData(widget.model()->index(0, 0));
QCOMPARE(flags.count(), 6);
for (int i = 0; i < 4; ++i)
QCOMPARE(flags[Qt::UserRole + i].toString(), QString::number(i + 1));
flags = widget.model()->itemData(widget.model()->index(0, 1));
QCOMPARE(flags.count(), 0);
}
void tst_QTreeWidget::enableDisable()
{
const QScopedPointer<QTreeWidgetItem> itm(new QTreeWidgetItem);
for (int i = 0; i < 10; ++i)
new QTreeWidgetItem(itm.data());
// make sure all items are enabled
QVERIFY(itm->flags() & Qt::ItemIsEnabled);
for (int j = 0; j < itm->childCount(); ++j)
QVERIFY(itm->child(j)->flags() & Qt::ItemIsEnabled);
// disable root and make sure they are all disabled
itm->setFlags(itm->flags() & ~Qt::ItemIsEnabled);
QVERIFY(!(itm->flags() & Qt::ItemIsEnabled));
for (int k = 0; k < itm->childCount(); ++k)
QVERIFY(!(itm->child(k)->flags() & Qt::ItemIsEnabled));
// disable a child and make sure they are all still disabled
itm->child(5)->setFlags(itm->child(5)->flags() & ~Qt::ItemIsEnabled);
QVERIFY(!(itm->flags() & Qt::ItemIsEnabled));
for (int l = 0; l < itm->childCount(); ++l)
QVERIFY(!(itm->child(l)->flags() & Qt::ItemIsEnabled));
// enable root and make sure all items except one are enabled
itm->setFlags(itm->flags() | Qt::ItemIsEnabled);
QVERIFY(itm->flags() & Qt::ItemIsEnabled);
for (int m = 0; m < itm->childCount(); ++m)
if (m == 5)
QVERIFY(!(itm->child(m)->flags() & Qt::ItemIsEnabled));
else
QVERIFY(itm->child(m)->flags() & Qt::ItemIsEnabled);
}
void tst_QTreeWidget::match()
{
QTreeWidget tree;
QModelIndexList list = tree.model()->match(QModelIndex(), Qt::DisplayRole, QString());
QVERIFY(list.isEmpty());
}
void tst_QTreeWidget::columnCount()
{
int columnCountBefore = testWidget->columnCount();
testWidget->setColumnCount(-1);
QCOMPARE(testWidget->columnCount(), columnCountBefore);
}
void tst_QTreeWidget::setHeaderLabels()
{
QStringList list = QString("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z").split(QLatin1Char(','));
testWidget->setHeaderLabels(list);
QCOMPARE(testWidget->header()->count(), list.count());
}
void tst_QTreeWidget::setHeaderItem()
{
testWidget->setHeaderItem(0);
QTreeWidgetItem *headerItem = new QTreeWidgetItem();
testWidget->setColumnCount(0);
QCOMPARE(testWidget->header()->count(), 0);
QCOMPARE(testWidget->columnCount(), 0);
headerItem->setText(0, "0");
headerItem->setText(1, "1");
testWidget->setHeaderItem(headerItem);
QCOMPARE(testWidget->headerItem(), headerItem);
QCOMPARE(headerItem->treeWidget(), static_cast<QTreeWidget *>(testWidget));
QCOMPARE(testWidget->header()->count(), 2);
QCOMPARE(testWidget->columnCount(), 2);
headerItem->setText(2, "2");
QCOMPARE(testWidget->header()->count(), 3);
QCOMPARE(testWidget->columnCount(), 3);
delete headerItem;
testWidget->setColumnCount(3);
testWidget->setColumnCount(5);
QCOMPARE(testWidget->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), QString("1"));
QCOMPARE(testWidget->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), QString("2"));
QCOMPARE(testWidget->model()->headerData(2, Qt::Horizontal, Qt::DisplayRole).toString(), QString("3"));
QCOMPARE(testWidget->model()->headerData(3, Qt::Horizontal, Qt::DisplayRole).toString(), QString("4"));
QCOMPARE(testWidget->model()->headerData(4, Qt::Horizontal, Qt::DisplayRole).toString(), QString("5"));
headerItem = new QTreeWidgetItem();
testWidget->setHeaderItem(headerItem);
testWidget->model()->insertColumns(0, 5, QModelIndex());
QCOMPARE(testWidget->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), QString("1"));
QCOMPARE(testWidget->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), QString("2"));
QCOMPARE(testWidget->model()->headerData(2, Qt::Horizontal, Qt::DisplayRole).toString(), QString("3"));
QCOMPARE(testWidget->model()->headerData(3, Qt::Horizontal, Qt::DisplayRole).toString(), QString("4"));
QCOMPARE(testWidget->model()->headerData(4, Qt::Horizontal, Qt::DisplayRole).toString(), QString("5"));
}
void tst_QTreeWidget::itemWidget_data()
{
editItem_data();
}
void tst_QTreeWidget::itemWidget()
{
QFETCH(TreeItemList, topLevelItems);
QTreeWidget tree;
populate(&tree, topLevelItems, new TreeItem(QStringList() << "1" << "2"));
tree.show();
for (int x = 0; x < 2; ++x) {
QTreeWidgetItemIterator it(&tree);
while (QTreeWidgetItem *item = (*it++)) {
for (int col = 0; col < item->columnCount(); ++col) {
if (x == 0) {
QCOMPARE(tree.itemWidget(item, col), static_cast<QWidget*>(0));
QWidget *editor = new QLineEdit();
tree.setItemWidget(item, col, editor);
QCOMPARE(tree.itemWidget(item, col), editor);
tree.removeItemWidget(item, col);
QCOMPARE(tree.itemWidget(item, col), static_cast<QWidget*>(0));
} else {
// ### should you really be able to open a persistent
// editor for an item that isn't editable??
tree.openPersistentEditor(item, col);
QWidget *editor = tree.findChild<QLineEdit*>();
QVERIFY(editor != 0);
tree.closePersistentEditor(item, col);
}
}
}
}
}
void tst_QTreeWidget::insertItemsWithSorting_data()
{
QTest::addColumn<int>("sortOrder");
QTest::addColumn<QStringList>("initialItems");
QTest::addColumn<QStringList>("insertItems");
QTest::addColumn<QStringList>("expectedItems");
QTest::addColumn<IntList>("expectedRows");
QTest::newRow("() + (a) = (a)")
<< static_cast<int>(Qt::AscendingOrder)
<< QStringList()
<< (QStringList() << "a")
<< (QStringList() << "a")
<< IntList();
QTest::newRow("() + (c, b, a) = (a, b, c)")
<< static_cast<int>(Qt::AscendingOrder)
<< QStringList()
<< (QStringList() << "c" << "b" << "a")
<< (QStringList() << "a" << "b" << "c")
<< IntList();
QTest::newRow("() + (a, b, c) = (c, b, a)")
<< static_cast<int>(Qt::DescendingOrder)
<< QStringList()
<< (QStringList() << "a" << "b" << "c")
<< (QStringList() << "c" << "b" << "a")
<< IntList();
QTest::newRow("(a) + (b) = (a, b)")
<< static_cast<int>(Qt::AscendingOrder)
<< QStringList("a")
<< (QStringList() << "b")
<< (QStringList() << "a" << "b")
<< (IntList() << 0);
QTest::newRow("(a) + (b) = (b, a)")
<< static_cast<int>(Qt::DescendingOrder)
<< QStringList("a")
<< (QStringList() << "b")
<< (QStringList() << "b" << "a")
<< (IntList() << 1);
QTest::newRow("(a, c, b) + (d) = (a, b, c, d)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "b")
<< (QStringList() << "d")
<< (QStringList() << "a" << "b" << "c" << "d")
<< (IntList() << 0 << 1 << 2);
QTest::newRow("(b, c, a) + (d) = (d, c, b, a)")
<< static_cast<int>(Qt::DescendingOrder)
<< (QStringList() << "b" << "c" << "a")
<< (QStringList() << "d")
<< (QStringList() << "d" << "c" << "b" << "a")
<< (IntList() << 1 << 2 << 3);
{
IntList ascendingRows;
IntList reverseRows;
QStringList ascendingItems;
QStringList reverseItems;
for (int i = 'a'; i <= 'z'; ++i) {
ascendingItems << QString(1, QLatin1Char(i));
reverseItems << QString(1, QLatin1Char('z' - i + 'a'));
ascendingRows << i - 'a';
reverseRows << 'z' - i + 'a';
}
QTest::newRow("() + (sorted items) = (sorted items)")
<< static_cast<int>(Qt::AscendingOrder)
<< QStringList()
<< ascendingItems
<< ascendingItems
<< IntList();
QTest::newRow("(sorted items) + () = (sorted items)")
<< static_cast<int>(Qt::AscendingOrder)
<< ascendingItems
<< QStringList()
<< ascendingItems
<< ascendingRows;
QTest::newRow("() + (ascending items) = (reverse items)")
<< static_cast<int>(Qt::DescendingOrder)
<< QStringList()
<< ascendingItems
<< reverseItems
<< IntList();
QTest::newRow("(reverse items) + () = (ascending items)")
<< static_cast<int>(Qt::AscendingOrder)
<< reverseItems
<< QStringList()
<< ascendingItems
<< ascendingRows;
QTest::newRow("(reverse items) + () = (reverse items)")
<< static_cast<int>(Qt::DescendingOrder)
<< reverseItems
<< QStringList()
<< reverseItems
<< ascendingRows;
}
}
void tst_QTreeWidget::insertItemsWithSorting()
{
QFETCH(int, sortOrder);
QFETCH(QStringList, initialItems);
QFETCH(QStringList, insertItems);
QFETCH(QStringList, expectedItems);
QFETCH(IntList, expectedRows);
for (int method = 0; method < 5; ++method) {
QTreeWidget w;
w.setSortingEnabled(true);
w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder));
for (int i = 0; i < initialItems.count(); ++i)
w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i)));
QAbstractItemModel *model = w.model();
QList<QPersistentModelIndex> persistent;
for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
persistent << model->index(j, 0, QModelIndex());
switch (method) {
case 0:
// insert using item constructor
for (int i = 0; i < insertItems.size(); ++i)
new QTreeWidgetItem(&w, QStringList() << insertItems.at(i));
break;
case 1:
{
// insert using insertTopLevelItems()
QList<QTreeWidgetItem*> lst;
for (int i = 0; i < insertItems.size(); ++i)
lst << new QTreeWidgetItem(QStringList() << insertItems.at(i));
w.insertTopLevelItems(0, lst);
break;
}
case 2:
// insert using insertTopLevelItem()
for (int i = 0; i < insertItems.size(); ++i)
w.insertTopLevelItem(0, new QTreeWidgetItem(QStringList() << insertItems.at(i)));
break;
case 3:
{
// insert using addTopLevelItems()
QList<QTreeWidgetItem*> lst;
for (int i = 0; i < insertItems.size(); ++i)
lst << new QTreeWidgetItem(QStringList() << insertItems.at(i));
w.addTopLevelItems(lst);
break;
}
case 4:
// insert using addTopLevelItem()
for (int i = 0; i < insertItems.size(); ++i)
w.addTopLevelItem(new QTreeWidgetItem(QStringList() << insertItems.at(i)));
break;
}
QCOMPARE(w.topLevelItemCount(), expectedItems.count());
for (int i = 0; i < w.topLevelItemCount(); ++i)
QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i));
for (int k = 0; k < persistent.count(); ++k)
QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
}
}
void tst_QTreeWidget::insertExpandedItemsWithSorting_data()
{
QTest::addColumn<QStringList>("parentText");
QTest::addColumn<QStringList>("childText");
QTest::addColumn<QStringList>("parentResult");
QTest::addColumn<QStringList>("childResult");
QTest::newRow("test 1")
<< (QStringList() << "c" << "d" << "a" << "b")
<< (QStringList() << "e" << "h" << "g" << "f")
<< (QStringList() << "d" << "c" << "b" << "a")
<< (QStringList() << "h" << "g" << "f" << "e");
}
// From Task 134978
void tst_QTreeWidget::insertExpandedItemsWithSorting()
{
QFETCH(QStringList, parentText);
QFETCH(QStringList, childText);
QFETCH(QStringList, parentResult);
QFETCH(QStringList, childResult);
// create a tree with autosorting enabled
CustomTreeWidget tree;
tree.setSortingEnabled(true);
// insert expanded items in unsorted order
QList<QTreeWidgetItem *> items;
for (int i = 0; i < parentText.count(); ++i) {
QTreeWidgetItem *parent = new QTreeWidgetItem(&tree, QStringList(parentText.at(i)));
parent->setExpanded(true);
QVERIFY(parent->isExpanded());
items << parent;
for (int j = 0; j < childText.count(); ++j) {
QTreeWidgetItem *child = new QTreeWidgetItem(parent, QStringList(childText.at(j)));
items << child;
}
QCOMPARE(parent->childCount(), childText.count());
QVERIFY(parent->isExpanded());
}
QCOMPARE(tree.model()->rowCount(), parentText.count());
// verify that the items are still expanded
foreach (QTreeWidgetItem *item, items) {
if (item->childCount() > 0)
QVERIFY(item->isExpanded());
QModelIndex idx = tree.indexFromItem(const_cast<QTreeWidgetItem *>(item));
QVERIFY(idx.isValid());
//QRect rect = tree.visualRect(idx);
//QVERIFY(rect.isValid());
// ### it is not guarantied that the index is in the viewport
}
// verify that the tree is sorted
QAbstractItemModel *model = tree.model();
QList<QPersistentModelIndex> parents;
for (int i = 0; i < model->rowCount(QModelIndex()); ++i) {
QPersistentModelIndex parent = model->index(i, 0, QModelIndex());
parents << parent;
}
QList<QPersistentModelIndex> children;
for (int i = 0; i < model->rowCount(parents.first()); ++i) {
QPersistentModelIndex child = model->index(i, 0, parents.first());
children << child;
}
for (int i = 0; i < parentResult.count(); ++i) {
QTreeWidgetItem *item = tree.topLevelItem(i);
QCOMPARE(item->text(0), parentResult.at(i));
for (int j = 0; j < childResult.count(); ++j)
QCOMPARE(item->child(j)->text(0), childResult.at(j));
}
}
void tst_QTreeWidget::changeDataWithSorting_data()
{
QTest::addColumn<int>("sortOrder");
QTest::addColumn<QStringList>("initialItems");
QTest::addColumn<int>("itemIndex");
QTest::addColumn<QString>("newValue");
QTest::addColumn<QStringList>("expectedItems");
QTest::addColumn<IntList>("expectedRows");
QTest::addColumn<bool>("reorderingExpected");
QTest::newRow("change a to b in (a)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a")
<< 0 << "b"
<< (QStringList() << "b")
<< (IntList() << 0)
<< false;
QTest::newRow("change a to b in (a, c)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c")
<< 0 << "b"
<< (QStringList() << "b" << "c")
<< (IntList() << 0 << 1)
<< false;
QTest::newRow("change a to c in (a, b)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "b")
<< 0 << "c"
<< (QStringList() << "b" << "c")
<< (IntList() << 1 << 0)
<< true;
QTest::newRow("change c to a in (c, b)")
<< static_cast<int>(Qt::DescendingOrder)
<< (QStringList() << "c" << "b")
<< 0 << "a"
<< (QStringList() << "b" << "a")
<< (IntList() << 1 << 0)
<< true;
QTest::newRow("change e to i in (a, c, e, g)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "e" << "g")
<< 2 << "i"
<< (QStringList() << "a" << "c" << "g" << "i")
<< (IntList() << 0 << 1 << 3 << 2)
<< true;
QTest::newRow("change e to a in (c, e, g, i)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "c" << "e" << "g" << "i")
<< 1 << "a"
<< (QStringList() << "a" << "c" << "g" << "i")
<< (IntList() << 1 << 0 << 2 << 3)
<< true;
QTest::newRow("change e to f in (c, e, g, i)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "c" << "e" << "g" << "i")
<< 1 << "f"
<< (QStringList() << "c" << "f" << "g" << "i")
<< (IntList() << 0 << 1 << 2 << 3)
<< false;
}
void tst_QTreeWidget::changeDataWithSorting()
{
QFETCH(int, sortOrder);
QFETCH(QStringList, initialItems);
QFETCH(int, itemIndex);
QFETCH(QString, newValue);
QFETCH(QStringList, expectedItems);
QFETCH(IntList, expectedRows);
QFETCH(bool, reorderingExpected);
QTreeWidget w;
w.setSortingEnabled(true);
w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder));
for (int i = 0; i < initialItems.count(); ++i)
w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i)));
QAbstractItemModel *model = w.model();
QList<QPersistentModelIndex> persistent;
for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
persistent << model->index(j, 0, QModelIndex());
QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
QTreeWidgetItem *item = w.topLevelItem(itemIndex);
item->setText(0, newValue);
for (int i = 0; i < expectedItems.count(); ++i) {
QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i));
for (int j = 0; j < persistent.count(); ++j) {
if (persistent.at(j).row() == i) // the same toplevel row
QCOMPARE(persistent.at(j).internalPointer(), (void *)w.topLevelItem(i));
}
}
for (int k = 0; k < persistent.count(); ++k)
QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
QCOMPARE(dataChangedSpy.count(), 1);
QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0);
}
void tst_QTreeWidget::changeDataWithStableSorting_data()
{
QTest::addColumn<int>("sortOrder");
QTest::addColumn<QStringList>("initialItems");
QTest::addColumn<int>("itemIndex");
QTest::addColumn<QString>("newValue");
QTest::addColumn<QStringList>("expectedItems");
QTest::addColumn<IntList>("expectedRows");
QTest::addColumn<bool>("reorderingExpected");
QTest::addColumn<bool>("forceChange");
QTest::newRow("change a to c in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 0 << "c"
<< (QStringList() << "c" << "c" << "c" << "c" << "e")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< false;
QTest::newRow("change e to c in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 4 << "c"
<< (QStringList() << "a" << "c" << "c" << "c" << "c")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< false;
QTest::newRow("change 1st c to c in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 1 << "c"
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< true;
QTest::newRow("change 2nd c to c in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 2 << "c"
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< true;
QTest::newRow("change 3rd c to c in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 3 << "c"
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< true;
QTest::newRow("change 1st c to c in (e, c, c, c, a)")
<< static_cast<int>(Qt::DescendingOrder)
<< (QStringList() << "e" << "c" << "c" << "c" << "a")
<< 1 << "c"
<< (QStringList() << "e" << "c" << "c" << "c" << "a")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< true;
QTest::newRow("change 2nd c to c in (e, c, c, c, a)")
<< static_cast<int>(Qt::DescendingOrder)
<< (QStringList() << "e" << "c" << "c" << "c" << "a")
<< 2 << "c"
<< (QStringList() << "e" << "c" << "c" << "c" << "a")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< true;
QTest::newRow("change 3rd c to c in (e, c, c, c, a)")
<< static_cast<int>(Qt::DescendingOrder)
<< (QStringList() << "e" << "c" << "c" << "c" << "a")
<< 3 << "c"
<< (QStringList() << "e" << "c" << "c" << "c" << "a")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< true;
QTest::newRow("change 1st c to b in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 1 << "b"
<< (QStringList() << "a" << "b" << "c" << "c" << "e")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< false;
QTest::newRow("change 2nd c to b in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 2 << "b"
<< (QStringList() << "a" << "b" << "c" << "c" << "e")
<< (IntList() << 0 << 2 << 1 << 3 << 4)
<< true
<< false;
QTest::newRow("change 3rd c to b in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 3 << "b"
<< (QStringList() << "a" << "b" << "c" << "c" << "e")
<< (IntList() << 0 << 2 << 3 << 1 << 4)
<< true
<< false;
QTest::newRow("change 1st c to d in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 1 << "d"
<< (QStringList() << "a" << "c" << "c" << "d" << "e")
<< (IntList() << 0 << 3 << 1 << 2 << 4)
<< true
<< false;
QTest::newRow("change 2nd c to d in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 2 << "d"
<< (QStringList() << "a" << "c" << "c" << "d" << "e")
<< (IntList() << 0 << 1 << 3 << 2 << 4)
<< true
<< false;
QTest::newRow("change 3rd c to d in (a, c, c, c, e)")
<< static_cast<int>(Qt::AscendingOrder)
<< (QStringList() << "a" << "c" << "c" << "c" << "e")
<< 3 << "d"
<< (QStringList() << "a" << "c" << "c" << "d" << "e")
<< (IntList() << 0 << 1 << 2 << 3 << 4)
<< false
<< false;
}
void tst_QTreeWidget::changeDataWithStableSorting()
{
QFETCH(int, sortOrder);
QFETCH(QStringList, initialItems);
QFETCH(int, itemIndex);
QFETCH(QString, newValue);
QFETCH(QStringList, expectedItems);
QFETCH(IntList, expectedRows);
QFETCH(bool, reorderingExpected);
QFETCH(bool, forceChange);
class StableItem : public QTreeWidgetItem
{
public:
StableItem(const QStringList &strings) : QTreeWidgetItem(strings, QTreeWidgetItem::UserType) {}
void forceChangeData() {
emitDataChanged();
}
};
QTreeWidget w;
w.setSortingEnabled(true);
w.sortItems(0, static_cast<Qt::SortOrder>(sortOrder));
for (int i = 0; i < initialItems.count(); ++i)
w.addTopLevelItem(new StableItem(QStringList() << initialItems.at(i)));
QAbstractItemModel *model = w.model();
QList<QPersistentModelIndex> persistent;
for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
persistent << model->index(j, 0, QModelIndex());
QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
StableItem *item = static_cast<StableItem *>(w.topLevelItem(itemIndex));
item->setText(0, newValue);
if (forceChange)
item->forceChangeData();
for (int i = 0; i < expectedItems.count(); ++i) {
QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i));
for (int j = 0; j < persistent.count(); ++j) {
if (persistent.at(j).row() == i) // the same toplevel row
QCOMPARE(persistent.at(j).internalPointer(), (void *)w.topLevelItem(i));
}
}
for (int k = 0; k < persistent.count(); ++k)
QCOMPARE(persistent.at(k).row(), expectedRows.at(k));
QCOMPARE(dataChangedSpy.count(), 1);
QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0);
}
void tst_QTreeWidget::itemOperatorLessThan()
{
QTreeWidget tw;
tw.setColumnCount(2);
{
QTreeWidgetItem item1(&tw);
QTreeWidgetItem item2(&tw);
QCOMPARE(item1 < item2, false);
item1.setText(1, "a");
item2.setText(1, "b");
QCOMPARE(item1 < item2, false);
item1.setText(0, "a");
item2.setText(0, "b");
QCOMPARE(item1 < item2, true);
tw.sortItems(1, Qt::AscendingOrder);
item1.setText(0, "b");
item2.setText(0, "a");
QCOMPARE(item1 < item2, true);
tw.sortItems(0, Qt::AscendingOrder);
item1.setData(0, Qt::DisplayRole, 11);
item2.setData(0, Qt::DisplayRole, 2);
QCOMPARE(item1 < item2, false);
}
}
void tst_QTreeWidget::sortedIndexOfChild_data()
{
QTest::addColumn<int>("sortOrder");
QTest::addColumn<QStringList>("itemTexts");
QTest::addColumn<QList<int> >("expectedIndexes");
QTest::newRow("three ascending")
<< int(Qt::AscendingOrder)
<< (QStringList() << "A" << "B" << "C")
<< (QList<int>() << 0 << 1 << 2);
QTest::newRow("three descending")
<< int(Qt::DescendingOrder)
<< (QStringList() << "A" << "B" << "C")
<< (QList<int>() << 2 << 1 << 0);
}
void tst_QTreeWidget::sortedIndexOfChild()
{
QFETCH(int, sortOrder);
QFETCH(QStringList, itemTexts);
QFETCH(QList<int>, expectedIndexes);
QTreeWidget tw;
QList<QTreeWidgetItem*> itms;
QTreeWidgetItem *top = new QTreeWidgetItem(&tw, QStringList() << "top");
for (int i = 0; i < itemTexts.count(); ++i)
itms << new QTreeWidgetItem(top, QStringList() << itemTexts.at(i));
tw.sortItems(0, (Qt::SortOrder)sortOrder);
tw.expandAll();
QCOMPARE(itms.count(), expectedIndexes.count());
for (int j = 0; j < expectedIndexes.count(); ++j)
QCOMPARE(top->indexOfChild(itms.at(j)), expectedIndexes.at(j));
}
void tst_QTreeWidget::expandAndCallapse()
{
QTreeWidget tw;
QTreeWidgetItem *top = new QTreeWidgetItem(&tw, QStringList() << "top");
QTreeWidgetItem *p = nullptr;
for (int i = 0; i < 10; ++i) {
p = new QTreeWidgetItem(top, QStringList(QString::number(i)));
for (int j = 0; j < 10; ++j)
new QTreeWidgetItem(p, QStringList(QString::number(j)));
}
QSignalSpy spy0(&tw, SIGNAL(itemExpanded(QTreeWidgetItem*)));
QSignalSpy spy1(&tw, SIGNAL(itemCollapsed(QTreeWidgetItem*)));
tw.expandItem(p);
tw.collapseItem(p);
tw.expandItem(p);
tw.expandItem(top);
tw.collapseItem(top);
tw.collapseItem(top);
QCOMPARE(spy0.count(), 3);
QCOMPARE(spy1.count(), 2);
}
void tst_QTreeWidget::setDisabled()
{
QTreeWidget w;
QTreeWidgetItem *i1 = new QTreeWidgetItem();
QTreeWidgetItem *i2 = new QTreeWidgetItem(i1);
QTreeWidgetItem *i3 = new QTreeWidgetItem(i1);
QTreeWidgetItem *top = new QTreeWidgetItem(&w);
top->setDisabled(true);
top->addChild(i1);
QCOMPARE(i1->isDisabled(), true);
QCOMPARE(i2->isDisabled(), true);
QCOMPARE(i3->isDisabled(), true);
i1 = top->takeChild(0);
QCOMPARE(i1->isDisabled(), false);
QCOMPARE(i2->isDisabled(), false);
QCOMPARE(i3->isDisabled(), false);
top->addChild(i1);
QCOMPARE(i1->isDisabled(), true);
QCOMPARE(i2->isDisabled(), true);
QCOMPARE(i3->isDisabled(), true);
top->setDisabled(false);
QCOMPARE(i1->isDisabled(), false);
QCOMPARE(i2->isDisabled(), false);
QCOMPARE(i3->isDisabled(), false);
QList<QTreeWidgetItem*> children;
children.append(new QTreeWidgetItem());
children.append(new QTreeWidgetItem());
children.append(new QTreeWidgetItem());
{
const QScopedPointer<QTreeWidgetItem> taken(top->takeChild(0));
QCOMPARE(taken.data(), i1);
}
top->addChildren(children);
QCOMPARE(top->child(0)->isDisabled(), false);
QCOMPARE(top->child(1)->isDisabled(), false);
QCOMPARE(top->child(1)->isDisabled(), false);
top->setDisabled(true);
QCOMPARE(top->child(0)->isDisabled(), true);
QCOMPARE(top->child(1)->isDisabled(), true);
QCOMPARE(top->child(1)->isDisabled(), true);
struct Deleter {
QList<QTreeWidgetItem *> items;
explicit Deleter(QList<QTreeWidgetItem *> items) : items(std::move(items)) {}
~Deleter() { qDeleteAll(items); }
};
const Deleter takenChildren(top->takeChildren());
QCOMPARE(takenChildren.items[0]->isDisabled(), false);
QCOMPARE(takenChildren.items[1]->isDisabled(), false);
QCOMPARE(takenChildren.items[1]->isDisabled(), false);
}
void tst_QTreeWidget::removeSelectedItem()
{
const QScopedPointer <QTreeWidget> w(new QTreeWidget);
w->setSortingEnabled(true);
QTreeWidgetItem *first = new QTreeWidgetItem();
first->setText(0, QLatin1String("D"));
w->addTopLevelItem(first);
QTreeWidgetItem *itm = new QTreeWidgetItem();
itm->setText(0, QLatin1String("D"));
w->addTopLevelItem(itm);
itm = new QTreeWidgetItem();
itm->setText(0, QLatin1String("C"));
w->addTopLevelItem(itm);
itm->setSelected(true);
itm = new QTreeWidgetItem();
itm->setText(0, QLatin1String("A"));
w->addTopLevelItem(itm);
//w->show();
QItemSelectionModel *selModel = w->selectionModel();
QCOMPARE(selModel->hasSelection(), true);
QCOMPARE(selModel->selectedRows().count(), 1);
const QScopedPointer<QTreeWidgetItem> taken(w->takeTopLevelItem(2));
QCOMPARE(taken->text(0), QLatin1String("C"));
QCOMPARE(selModel->hasSelection(), false);
QCOMPARE(selModel->selectedRows().count(), 0);
QItemSelection sel = selModel->selection();
QCOMPARE(selModel->isSelected(w->model()->index(0,0)), false);
}
class AnotherTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
AnotherTreeWidget(QWidget *parent = 0) : QTreeWidget(parent) {}
void deleteCurrent() { if (currentItem()) delete currentItem(); }
};
void tst_QTreeWidget::removeCurrentItem()
{
AnotherTreeWidget widget;
QObject::connect(widget.selectionModel(),
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
&widget, SLOT(clear()));
QTreeWidgetItem *item = new QTreeWidgetItem(&widget);
widget.setCurrentItem(item);
widget.deleteCurrent();
}
void tst_QTreeWidget::removeCurrentItem_task186451()
{
AnotherTreeWidget widget;
QTreeWidgetItem *item = new QTreeWidgetItem(&widget, QStringList() << "1");
QTreeWidgetItem *item2 = new QTreeWidgetItem(&widget, QStringList() << "2");
widget.setCurrentItem(item);
widget.deleteCurrent();
QVERIFY(item2->isSelected());
QCOMPARE(item2, widget.currentItem());
}
class TreeWidget : QTreeWidget {
public:
QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const {
return QTreeWidget::indexFromItem(item, column);
}
QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const {
return QTreeWidget::itemFromIndex(index);
}
};
void tst_QTreeWidget::randomExpand()
{
QTreeWidget tree;
QTreeWidgetItem *item1 = new QTreeWidgetItem(&tree);
QTreeWidgetItem *item3 = new QTreeWidgetItem(&tree, item1);
new QTreeWidgetItem(item1);
new QTreeWidgetItem(item3);
tree.expandAll();
/*
item1
\- item2
item3
\- item4
*/
QTreeWidgetItem *newItem1 = 0;
for (int i = 0; i < 100; i++) {
newItem1 = new QTreeWidgetItem(&tree, item1);
tree.setItemExpanded(newItem1, true);
QCOMPARE(tree.isItemExpanded(newItem1), true);
QTreeWidgetItem *x = new QTreeWidgetItem();
QCOMPARE(tree.isItemExpanded(newItem1), true);
newItem1->addChild(x);
QCOMPARE(tree.isItemExpanded(newItem1), true);
}
}
void tst_QTreeWidget::crashTest()
{
QTreeWidget *tree = new QTreeWidget();
tree->setColumnCount(1);
tree->show();
QTreeWidgetItem *item1 = new QTreeWidgetItem(tree);
item1->setText(0, "item1");
tree->setItemExpanded(item1, true);
QTreeWidgetItem *item2 = new QTreeWidgetItem(item1);
item2->setText(0, "item2");
QTreeWidgetItem *item3 = new QTreeWidgetItem(tree, item1);
item3->setText(0, "item3");
tree->setItemExpanded(item3, true);
QTreeWidgetItem *item4 = new QTreeWidgetItem(item3);
item4->setText(0, "item4");
QTreeWidgetItem *item5 = new QTreeWidgetItem(tree, item3);
item5->setText(0, "item5");
tree->setItemExpanded(item5, true);
QTreeWidgetItem *item6 = new QTreeWidgetItem(item5);
item6->setText(0, "item6");
for (int i = 0; i < 1000; i++) {
QTreeWidgetItem *newItem1 = new QTreeWidgetItem(tree, item1);
newItem1->setText(0, "newItem");
QTreeWidgetItem *newItem2 = new QTreeWidgetItem(newItem1);
newItem2->setText(0, "subItem1");
QTreeWidgetItem *newItem3 = new QTreeWidgetItem(newItem1, newItem2);
newItem3->setText(0, "subItem2");
delete item3;
item3 = newItem1;
}
QApplication::instance()->processEvents();
delete tree;
}
class CrashWidget : public QTreeWidget
{
public:
CrashWidget(QWidget *parent = 0) : QTreeWidget(parent), i(0) {
setSortingEnabled(true);
timerId = startTimer(10);
}
int i;
protected:
void timerEvent(QTimerEvent * event) {
if (event->timerId() == timerId) {
QTreeWidgetItem *newItem = new QTreeWidgetItem((QStringList() << QString::number(i++)));
m_list.append(newItem);
insertTopLevelItem(0, newItem);
while (m_list.count() > 10)
delete m_list.takeFirst();
}
QTreeWidget::timerEvent(event);
}
private:
int timerId;
QList<QTreeWidgetItem*> m_list;
};
void tst_QTreeWidget::sortAndSelect()
{
CrashWidget w;
w.resize(1, 1);
w.show();
while (w.i < 100) {
QApplication::processEvents();
if (w.i & 16) {
QPoint pt = w.viewport()->rect().center();
QTest::mouseClick(w.viewport(), Qt::LeftButton, Qt::NoModifier, pt);
}
}
QVERIFY(true);
}
void tst_QTreeWidget::defaultRowSizes()
{
const QScopedPointer<QTreeWidget> tw(new QTreeWidget);
tw->setIconSize(QSize(50, 50));
tw->setColumnCount(6);
for (int i=0; i<10; ++i) {
auto it = new QTreeWidgetItem(tw.data());
for (int j=0; j<tw->columnCount() - 1; ++j) {
it->setText(j, "This is a test");
}
QPixmap icon = tw->style()->standardPixmap((QStyle::StandardPixmap)(i + QStyle::SP_TitleBarMenuButton));
if (icon.isNull())
QSKIP("No pixmap found on current style, skipping this test.");
it->setIcon(tw->columnCount() - 1,
icon.scaled(tw->iconSize()));
}
tw->resize(100,100);
tw->show();
QApplication::processEvents();
QRect visualRect = tw->visualItemRect(tw->topLevelItem(0));
QVERIFY(visualRect.height() >= 50);
}
void tst_QTreeWidget::task191552_rtl()
{
Qt::LayoutDirection oldDir = qApp->layoutDirection();
qApp->setLayoutDirection(Qt::RightToLeft);
QTreeWidget tw;
tw.setColumnCount(1);
QTreeWidgetItem *item = new QTreeWidgetItem(&tw);
item->setText(0, "item 1");
item->setCheckState(0, Qt::Checked);
QCOMPARE(item->checkState(0), Qt::Checked);
tw.show();
QVERIFY(QTest::qWaitForWindowActive(&tw));
QStyleOptionViewItem opt;
opt.initFrom(&tw);
opt.rect = tw.visualItemRect(item);
// mimic QStyledItemDelegate::initStyleOption logic
opt.features = QStyleOptionViewItem::HasDisplay | QStyleOptionViewItem::HasCheckIndicator;
opt.checkState = Qt::Checked;
opt.widget = &tw;
const QRect checkRect = tw.style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, &tw);
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::NoModifier, checkRect.center());
QCOMPARE(item->checkState(0), Qt::Unchecked);
qApp->setLayoutDirection(oldDir);
}
void tst_QTreeWidget::task203673_selection()
{
//we try to change the selection by rightclick + ctrl
//it should do anything when using ExtendedSelection
QTreeWidget tw;
tw.setColumnCount(1);
QTreeWidgetItem *item1 = new QTreeWidgetItem(&tw);
item1->setText(0, "item 1");
tw.setSelectionMode(QTreeView::ExtendedSelection);
QPoint center = tw.visualItemRect(item1).center();
QCOMPARE(item1->isSelected(), false);
QTest::mouseClick(tw.viewport(), Qt::RightButton, Qt::ControlModifier, center);
QCOMPARE(item1->isSelected(), false);
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::ControlModifier, center);
QCOMPARE(item1->isSelected(), true);
QTest::mouseClick(tw.viewport(), Qt::RightButton, Qt::ControlModifier, center);
QCOMPARE(item1->isSelected(), true); //it shouldn't change
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::ControlModifier, center);
QCOMPARE(item1->isSelected(), false);
}
void tst_QTreeWidget::rootItemFlags()
{
QTreeWidget tw;
tw.setColumnCount(1);
QTreeWidgetItem *item = new QTreeWidgetItem(&tw);
item->setText(0, "item 1");
QVERIFY(tw.invisibleRootItem()->flags() & Qt::ItemIsDropEnabled);
tw.invisibleRootItem()->setFlags(tw.invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled);
QVERIFY(!(tw.invisibleRootItem()->flags() & Qt::ItemIsDropEnabled));
}
void tst_QTreeWidget::task218661_setHeaderData()
{
//We check that setting header data out of bounds returns false
//and doesn't increase the size of the model
QTreeWidget tw;
tw.setColumnCount(1);
QCOMPARE(tw.columnCount(), 1);
QCOMPARE(tw.model()->setHeaderData(99999, Qt::Horizontal, QVariant()), false);
QCOMPARE(tw.columnCount(), 1);
}
void tst_QTreeWidget::task245280_sortChildren()
{
QTreeWidget tw;
tw.setColumnCount(2);
QTreeWidgetItem top(&tw);
top.setText(0,"Col 0");
top.setText(1,"Col 1");
QTreeWidgetItem item1(&top);
item1.setText(0,"X");
item1.setText(1,"0");
QTreeWidgetItem item2(&top);
item2.setText(0,"A");
item2.setText(1,"4");
QTreeWidgetItem item3(&top);
item3.setText(0,"E");
item3.setText(1,"1");
QTreeWidgetItem item4(&top);
item4.setText(0,"Z");
item4.setText(1,"3");
QTreeWidgetItem item5(&top);
item5.setText(0,"U");
item5.setText(1,"2");
tw.expandAll();
tw.show();
top.sortChildren(1,Qt::AscendingOrder);
for (int i = 0; i < top.childCount(); ++i)
QCOMPARE(top.child(i)->text(1), QString::number(i));
}
void tst_QTreeWidget::task253109_itemHeight()
{
QTreeWidget treeWidget;
treeWidget.setColumnCount(1);
treeWidget.show();
QVERIFY(QTest::qWaitForWindowActive(&treeWidget));
QTreeWidgetItem item(&treeWidget);
class MyWidget : public QWidget
{
virtual QSize sizeHint() const { return QSize(200,100); }
} w;
treeWidget.setItemWidget(&item, 0, &w);
QTRY_COMPARE(w.geometry(), treeWidget.visualItemRect(&item));
}
void tst_QTreeWidget::task206367_duplication()
{
QWidget topLevel;
// Explicitly set the font size because it is dpi dependent on some platforms
QFont font;
font.setPixelSize(40);
topLevel.setFont(font);
QTreeWidget treeWidget(&topLevel);
topLevel.show();
treeWidget.resize(200, 200);
treeWidget.setHeaderHidden(true);
treeWidget.setSortingEnabled(true);
QTreeWidgetItem* rootItem = new QTreeWidgetItem( &treeWidget, QStringList("root") );
for (int nFile = 0; nFile < 2; nFile++ ) {
QTreeWidgetItem* itemFile = new QTreeWidgetItem(rootItem, QStringList(QString::number(nFile)));
for (int nRecord = 0; nRecord < 2; nRecord++)
new QTreeWidgetItem(itemFile , QStringList(QString::number(nRecord)));
itemFile->setExpanded(true);
}
rootItem->setExpanded(true);
//there should be enough room for 2x2 items. If there is a scrollbar, it means the items are duplicated
QTRY_VERIFY(!treeWidget.verticalScrollBar()->isVisible());
}
void tst_QTreeWidget::itemSelectionChanged()
{
QVERIFY(testWidget);
if(testWidget->topLevelItem(0))
QVERIFY(testWidget->topLevelItem(0)->isSelected());
}
void tst_QTreeWidget::selectionOrder()
{
testWidget->setColumnCount(1);
QList<QTreeWidgetItem *> items;
for (int i = 0; i < 10; ++i)
items.append(new QTreeWidgetItem((QTreeWidget*)0, QStringList(QLatin1String("item: ") + QString::number(i))));
testWidget->insertTopLevelItems(0, items);
QModelIndex idx = testWidget->indexFromItem(items[0]);
connect(testWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
testWidget->selectionModel()->select(idx, QItemSelectionModel::SelectCurrent);
disconnect(testWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
}
void tst_QTreeWidget::setSelectionModel()
{
QTreeWidget tree;
for(int i = 0; i < 3; ++i)
new QTreeWidgetItem(&tree, QStringList(QString::number(i)));
QItemSelectionModel selection(tree.model());
selection.select(tree.model()->index(1,0), QItemSelectionModel::Select);
tree.setSelectionModel(&selection);
QCOMPARE(tree.topLevelItem(1)->isSelected(), true);
}
void tst_QTreeWidget::task217309()
{
QTreeWidgetItem item;
item.setFlags(item.flags() | Qt::ItemIsAutoTristate);
QTreeWidgetItem subitem1;
subitem1.setFlags(subitem1.flags() | Qt::ItemIsAutoTristate);
QTreeWidgetItem subitem2;
subitem2.setFlags(subitem2.flags() | Qt::ItemIsAutoTristate);
item.addChild(&subitem1);
item.addChild(&subitem2);
subitem1.setCheckState(0, Qt::Checked);
subitem2.setCheckState(0, Qt::Unchecked);
QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::PartiallyChecked);
subitem2.setCheckState(0, Qt::PartiallyChecked);
QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::PartiallyChecked);
subitem2.setCheckState(0, Qt::Checked);
QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::Checked);
}
void tst_QTreeWidget::nonEditableTristate()
{
// A tree with checkable items, the parent is tristate
QTreeWidget *tree = new QTreeWidget;
QTreeWidgetItem *item = new QTreeWidgetItem();
tree->insertTopLevelItem(0, item);
item->setFlags(item->flags() | Qt::ItemIsAutoTristate);
item->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subitem1 = new QTreeWidgetItem(item);
subitem1->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subitem2 = new QTreeWidgetItem(item);
subitem2->setCheckState(0, Qt::Unchecked);
QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked));
tree->show();
// Test clicking on the parent item, it should become Checked (not PartiallyChecked)
QStyleOptionViewItem option;
option.rect = tree->visualRect(tree->model()->index(0, 0));
option.state |= QStyle::State_Enabled;
option.features |= QStyleOptionViewItem::HasCheckIndicator | QStyleOptionViewItem::HasDisplay;
option.checkState = item->checkState(0);
const int checkMargin = qApp->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, 0) + 1;
QPoint pos = qApp->style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &option, 0).center() + QPoint(checkMargin, 0);
QTest::mouseClick(tree->viewport(), Qt::LeftButton, Qt::NoModifier, pos);
QCOMPARE(int(item->checkState(0)), int(Qt::Checked));
// Click again, it should become Unchecked.
QTest::mouseClick(tree->viewport(), Qt::LeftButton, Qt::NoModifier, pos);
QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked));
delete tree;
}
class TreeWidgetItem : public QTreeWidgetItem
{
public:
void _emitDataChanged() { emitDataChanged(); }
};
void tst_QTreeWidget::emitDataChanged()
{
QTreeWidget *tree = new QTreeWidget;
QSignalSpy spy(tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)));
TreeWidgetItem *item = new TreeWidgetItem();
tree->insertTopLevelItem(0, item);
item->_emitDataChanged();
QCOMPARE(spy.count(), 1);
}
void tst_QTreeWidget::setCurrentItemExpandsParent()
{
QTreeWidget w;
w.setColumnCount(1);
QTreeWidgetItem *i1 = new QTreeWidgetItem(&w, QStringList() << "parent");
QTreeWidgetItem *i2 = new QTreeWidgetItem(i1, QStringList() << "child");
QVERIFY(!i2->isExpanded());
QVERIFY(!w.currentItem());
w.setCurrentItem(i2);
QVERIFY(!i2->isExpanded());
QCOMPARE(w.currentItem(), i2);
}
void tst_QTreeWidget::task239150_editorWidth()
{
//we check that an item with no text will get an editor with a correct size
QTreeWidget tree;
QStyleOptionFrame opt;
opt.init(&tree);
const int minWidth = tree.style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(0, 0).
expandedTo(QApplication::globalStrut()), 0).width();
{
QTreeWidgetItem item;
item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
tree.addTopLevelItem(&item);
QVERIFY(tree.itemWidget(&item, 0) == 0);
tree.editItem(&item);
QVERIFY(tree.itemWidget(&item, 0));
QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth);
}
//now let's test it with an item with a lot of text
{
QTreeWidgetItem item;
item.setText(0, "foooooooooooooooooooooooo");
item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
tree.addTopLevelItem(&item);
QVERIFY(tree.itemWidget(&item, 0) == 0);
tree.editItem(&item);
QVERIFY(tree.itemWidget(&item, 0));
QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth + tree.fontMetrics().horizontalAdvance(item.text(0)));
}
}
void tst_QTreeWidget::setTextUpdate()
{
QTreeWidget treeWidget;
treeWidget.setColumnCount(2);
class MyItemDelegate : public QStyledItemDelegate
{
public:
MyItemDelegate() : numPaints(0) { }
void paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
numPaints++;
QStyledItemDelegate::paint(painter, option, index);
}
mutable int numPaints;
} delegate;
treeWidget.setItemDelegate(&delegate);
treeWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&treeWidget));
QStringList strList;
strList << "variable1" << "0";
QTreeWidgetItem *item = new QTreeWidgetItem(strList);
treeWidget.insertTopLevelItem(0, item);
QTRY_VERIFY(delegate.numPaints > 0);
delegate.numPaints = 0;
item->setText(1, "42");
QTRY_VERIFY(delegate.numPaints > 0);
}
void tst_QTreeWidget::taskQTBUG2844_visualItemRect()
{
CustomTreeWidget tree;
tree.resize(150, 100);
tree.setColumnCount(3);
QTreeWidgetItem item(&tree);
QRect rectCol0 = tree.visualRect(tree.indexFromItem(&item, 0));
QRect rectCol1 = tree.visualRect(tree.indexFromItem(&item, 1));
QRect rectCol2 = tree.visualRect(tree.indexFromItem(&item, 2));
QCOMPARE(tree.visualItemRect(&item), rectCol0 | rectCol2);
tree.setColumnHidden(2, true);
QCOMPARE(tree.visualItemRect(&item), rectCol0 | rectCol1);
}
void tst_QTreeWidget::setChildIndicatorPolicy()
{
QTreeWidget treeWidget;
treeWidget.setColumnCount(1);
class MyItemDelegate : public QStyledItemDelegate
{
public:
MyItemDelegate() : numPaints(0), expectChildren(false) { }
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
numPaints++;
QCOMPARE(!(option.state & QStyle::State_Children), !expectChildren);
QStyledItemDelegate::paint(painter, option, index);
}
mutable int numPaints;
bool expectChildren;
} delegate;
treeWidget.setItemDelegate(&delegate);
treeWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&treeWidget));
QCoreApplication::processEvents(); // Process all queued paint events
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList("Hello"));
treeWidget.insertTopLevelItem(0, item);
QTRY_VERIFY(delegate.numPaints > 0);
delegate.numPaints = 0;
delegate.expectChildren = true;
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
QTRY_COMPARE(delegate.numPaints, 1);
delegate.numPaints = 0;
delegate.expectChildren = false;
item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
QTRY_COMPARE(delegate.numPaints, 1);
delegate.numPaints = 0;
delegate.expectChildren = true;
new QTreeWidgetItem(item);
QTRY_COMPARE(delegate.numPaints, 1);
delegate.numPaints = 0;
delegate.expectChildren = false;
item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
QTRY_COMPARE(delegate.numPaints, 1);
}
// From QTBUG_34717 (QTreeWidget crashes when scrolling to the end
// of an expanded tree, then collapse all)
// The test passes simply if it doesn't crash.
void tst_QTreeWidget::taskQTBUG_34717_collapseAtBottom()
{
struct PublicTreeWidget: public QTreeWidget
{
inline int sizeHintForColumn(int column) const { return QTreeWidget::sizeHintForColumn(column); }
};
PublicTreeWidget treeWidget;
treeWidget.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
treeWidget.setColumnCount(2);
QTreeWidgetItem *mainItem = new QTreeWidgetItem(&treeWidget, QStringList() << "Root");
for (int i = 0; i < 200; ++i) {
QTreeWidgetItem *item = new QTreeWidgetItem(mainItem, QStringList(QString("Item")));
new QTreeWidgetItem(item, QStringList() << "Child" << "1");
new QTreeWidgetItem(item, QStringList() << "Child" << "2");
new QTreeWidgetItem(item, QStringList() << "Child" << "3");
}
treeWidget.show();
treeWidget.expandAll();
treeWidget.scrollToBottom();
treeWidget.collapseAll();
treeWidget.setAnimated(true);
treeWidget.expandAll();
treeWidget.scrollToBottom();
mainItem->setExpanded(false);
QVERIFY(treeWidget.sizeHintForColumn(1) >= 0);
}
void tst_QTreeWidget::task20345_sortChildren()
{
if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)
|| !QGuiApplication::platformName().compare(QLatin1String("winrt"), Qt::CaseInsensitive))
QSKIP("Wayland/WinRT: This causes a crash triggered by setVisible(false)");
// This test case is considered successful if it is executed (no crash in sorting)
QTreeWidget tw;
tw.setColumnCount(3);
tw.headerItem()->setText(0, "Col 0");
tw.headerItem()->setText(1, "Col 1");
tw.header()->setSortIndicator(0, Qt::AscendingOrder);
tw.setSortingEnabled(true);
tw.show();
QTreeWidgetItem *rootItem = 0;
QTreeWidgetItem *childItem = 0;
rootItem = new QTreeWidgetItem(&tw, QStringList("a"));
childItem = new QTreeWidgetItem(rootItem);
childItem->setText(1, "3");
childItem = new QTreeWidgetItem(rootItem);
childItem->setText(1, "1");
childItem = new QTreeWidgetItem(rootItem);
childItem->setText(1, "2");
tw.setCurrentItem(tw.topLevelItem(0));
QTreeWidgetItem * curItem = tw.currentItem();
int childCount = curItem->childCount() + 1;
QTreeWidgetItem * newItem = new QTreeWidgetItem(curItem);
newItem->setText(1, QString::number(childCount));
rootItem->sortChildren(1, Qt::AscendingOrder);
QVERIFY(1);
}
void tst_QTreeWidget::getMimeDataWithInvalidItem()
{
CustomTreeWidget w;
QTest::ignoreMessage(QtWarningMsg, "QTreeWidget::mimeData: Null-item passed");
QMimeData *md = w.mimeData(QList<QTreeWidgetItem*>() << nullptr);
QVERIFY(!md);
}
// visualItemRect returned a wrong rect when the columns were moved
// (-> logical index != visual index). see QTBUG-28733
void tst_QTreeWidget::testVisualItemRect()
{
QTreeWidget tw;
tw.setColumnCount(2);
QTreeWidgetItem *item = new QTreeWidgetItem(&tw);
item->setText(0, "text 0");
item->setText(1, "text 1");
static const int sectionSize = 30;
tw.header()->setStretchLastSection(false);
tw.header()->setMinimumSectionSize(sectionSize);
tw.header()->resizeSection(0, sectionSize);
tw.header()->resizeSection(1, sectionSize);
tw.setRootIsDecorated(false);
tw.show();
QVERIFY(QTest::qWaitForWindowExposed(&tw));
QRect r = tw.visualItemRect(item);
QCOMPARE(r.width(), sectionSize * 2); // 2 columns
tw.header()->moveSection(1, 0);
r = tw.visualItemRect(item);
QCOMPARE(r.width(), sectionSize * 2); // 2 columns
tw.hideColumn(0);
r = tw.visualItemRect(item);
QCOMPARE(r.width(), sectionSize);
}
void tst_QTreeWidget::reparentHiddenItem()
{
QTreeWidgetItem *parent = new QTreeWidgetItem(testWidget);
parent->setText(0, "parent");
QTreeWidgetItem *otherParent = new QTreeWidgetItem(testWidget);
otherParent->setText(0, "other parent");
QTreeWidgetItem *child = new QTreeWidgetItem(parent);
child->setText(0, "child");
QTreeWidgetItem *grandChild = new QTreeWidgetItem(child);
grandChild->setText(0, "grandchild");
QVERIFY(child->parent());
QVERIFY(grandChild->parent());
testWidget->expandItem(parent);
testWidget->expandItem(otherParent);
testWidget->expandItem(child);
QVERIFY(!parent->isHidden());
QVERIFY(!child->isHidden());
QVERIFY(!grandChild->isHidden());
grandChild->setHidden(true);
QVERIFY(grandChild->isHidden());
parent->removeChild(child);
otherParent->addChild(child);
QVERIFY(grandChild->isHidden());
}
QTEST_MAIN(tst_QTreeWidget)
#include "tst_qtreewidget.moc"