/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** 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 http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include class CustomTreeWidget : public QTreeWidget { Q_OBJECT public: QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const { return QTreeWidget::indexFromItem(item, column); } QMimeData * mimeData(const QList 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(); 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(), (QTreeWidgetItem *)0); // 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(), (QTreeWidgetItem *)0); } typedef QList IntList; typedef QList ListIntList; Q_DECLARE_METATYPE(Qt::Orientation) typedef QTreeWidgetItem TreeItem; typedef QList TreeItemList; Q_DECLARE_METATYPE(QTreeWidgetItem*) Q_DECLARE_METATYPE(TreeItemList) tst_QTreeWidget::tst_QTreeWidget(): testWidget(0) { } tst_QTreeWidget::~tst_QTreeWidget() { } void tst_QTreeWidget::initTestCase() { qMetaTypeId(); qMetaTypeId(); qRegisterMetaType("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 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), static_cast(0)); QCOMPARE(tree.indexOfTopLevelItem(ti), i); QCOMPARE(ti->parent(), static_cast(0)); 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(100000, tops); // ### fixme QCOMPARE(tree.topLevelItemCount(), count + 10); } } void tst_QTreeWidget::currentItem_data() { QTest::addColumn("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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(), static_cast(0)); } void tst_QTreeWidget::editItem_data() { QTest::addColumn("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(); 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(args.at(0)), item); QCOMPARE(qvariant_cast(args.at(1)), col); } else { QVERIFY(!(item->flags() & Qt::ItemIsEditable)); } } } } void tst_QTreeWidget::takeItem_data() { QTest::addColumn("index"); QTest::addColumn("topLevel"); QTest::addColumn("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, (QTreeWidgetItem *)0); 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, (QTreeWidgetItem *)0); 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("childCount"); QTest::addColumn("removeAt"); QTest::newRow("10 remove 3") << 10 << 3; } void tst_QTreeWidget::removeChild() { QFETCH(int, childCount); QFETCH(int, removeAt); QTreeWidgetItem *root = new QTreeWidgetItem; for (int i = 0; i < childCount; ++i) new QTreeWidgetItem(root, QStringList(QString::number(i))); QCOMPARE(root->childCount(), childCount); for (int j = 0; j < childCount; ++j) QCOMPARE(root->child(j)->text(0), QString::number(j)); QTreeWidgetItem *remove = root->child(removeAt); root->removeChild(remove); 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)); } delete root; } 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("topLevel"); QTest::addColumn("children"); QTest::addColumn("closeTopLevel"); QTest::addColumn("selectedItems"); QTest::addColumn("hiddenItems"); QTest::addColumn("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; tsetText(0, topS); for (int c=0; csetText(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; itopLevelItemCount(); ++i) { if (closeTopLevel) testWidget->collapseItem(testWidget->topLevelItem(i)); else testWidget->expandItem(testWidget->topLevelItem(i)); } // check selectedItems QList 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; ttopLevelItemCount(); ++t) { QTreeWidgetItem *top = testWidget->topLevelItem(t); if (testWidget->isItemSelected(top) && !testWidget->isItemHidden(top)) QVERIFY(sel.contains(top)); for (int c=0; cchildCount(); ++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(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("column"); QTest::addColumn("topLevelIndex"); QTest::addColumn("childIndex"); QTest::addColumn("topLevelText"); QTest::addColumn("childText"); QTest::addColumn("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("topLevelIndex"); QTest::addColumn("topLevelCount"); QTest::addColumn("childIndex"); QTest::addColumn("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("column"); QTest::addColumn("topLevelText"); QTest::addColumn("childText"); QTest::addColumn("pattern"); QTest::addColumn("resultCount"); QTest::addColumn("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 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 items = testWidget->findItems("400", Qt::MatchExactly|Qt::MatchRecursive, 1); QCOMPARE(items.count(), 1); } void tst_QTreeWidget::sortItems_data() { QTest::addColumn("column"); QTest::addColumn("order"); QTest::addColumn("topLevelText"); QTest::addColumn("childText"); QTest::addColumn("topLevelResult"); QTest::addColumn("childResult"); QTest::addColumn("expectedTopRows"); QTest::addColumn("expectedChildRows"); QTest::newRow("ascending order") << 0 << static_cast(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(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 tops; for (int r = 0; r < model->rowCount(QModelIndex()); ++r) { QPersistentModelIndex p = model->index(r, 0, QModelIndex()); tops << p; } QList 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(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("topLevelCount"); QTest::addColumn("childCount"); QTest::addColumn("grandChildCount"); QTest::addColumn("deleteTopLevelCount"); QTest::addColumn("deleteChildCount"); QTest::addColumn("deleteGrandChildCount"); QTest::addColumn("expectedTopLevelCount"); QTest::addColumn("expectedChildCount"); QTest::addColumn("expectedGrandChildCount"); QTest::addColumn("persistentRow"); QTest::addColumn("persistentColumn"); QTest::addColumn("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("text"); QTest::addColumn("toolTip"); QTest::addColumn("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("initialText"); QTest::addColumn("insertText"); QTest::addColumn("insertTopLevelIndex"); QTest::addColumn("expectedTopLevelIndex"); QTest::addColumn("insertChildIndex"); QTest::addColumn("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 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 *bar; QTreeWidgetItem *search; for (int i=0; i<2; ++i) { 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) { QTreeWidgetItem *yo = new QTreeWidgetItem(foo); yo->setText(0, foo->text(0) + QString::number(k)); search = yo; } } } testWidget->setHeaderLabels(QStringList() << "foo"); testWidget->scrollToItem(search); QCOMPARE(search->text(0), QLatin1String("111")); bar = search->parent(); QVERIFY(testWidget->isItemExpanded(bar)); bar = bar->parent(); QVERIFY(testWidget->isItemExpanded(bar)); } // 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(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 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 taken = item->takeChildren(); QCOMPARE(taken, children); QCOMPARE(item->childCount(), 0); for (int i = 0; i < taken.count(); ++i) { QCOMPARE(taken.at(i)->parent(), static_cast(0)); QCOMPARE(taken.at(i)->treeWidget(), static_cast(0)); 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()); QCOMPARE(item->childCount(), count); } // add many at a time const int count = 10; for (int i = 0; i < 100; i += count) { QList 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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(args.at(0)), item); QCOMPARE(qvariant_cast(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(item->data(j, Qt::DisplayRole)), text); QCOMPARE(qvariant_cast(item->data(j, Qt::DecorationRole)), icon); QCOMPARE(qvariant_cast(item->data(j, Qt::ToolTipRole)), toolTip); QCOMPARE(qvariant_cast(item->data(j, Qt::StatusTipRole)), statusTip); QCOMPARE(qvariant_cast(item->data(j, Qt::WhatsThisRole)), whatsThis); QCOMPARE(qvariant_cast(item->data(j, Qt::SizeHintRole)), sizeHint); QCOMPARE(qvariant_cast(item->data(j, Qt::FontRole)), font); QCOMPARE(qvariant_cast(item->data(j, Qt::TextAlignmentRole)), int(textAlignment)); QCOMPARE(qvariant_cast(item->data(j, Qt::BackgroundColorRole)), QBrush(backgroundColor)); QCOMPARE(qvariant_cast(item->data(j, Qt::BackgroundRole)), QBrush(backgroundColor)); QCOMPARE(qvariant_cast(item->data(j, Qt::TextColorRole)), textColor); QCOMPARE(qvariant_cast(item->data(j, Qt::CheckStateRole)), int(checkState)); item->setBackground(j, pixmap); QCOMPARE(item->background(j).texture(), pixmap); QCOMPARE(qvariant_cast(item->data(j, Qt::BackgroundRole)).texture(), pixmap); args = itemChangedSpy.takeFirst(); QCOMPARE(qvariant_cast(args.at(0)), item); QCOMPARE(qvariant_cast(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; } } void tst_QTreeWidget::itemData() { QTreeWidget widget; QTreeWidgetItem item(&widget); widget.setColumnCount(2); item.setFlags(item.flags() | Qt::ItemIsEditable); item.setData(0, Qt::DisplayRole, QString("0")); item.setData(0, Qt::CheckStateRole, Qt::PartiallyChecked); item.setData(0, Qt::UserRole + 0, QString("1")); item.setData(0, Qt::UserRole + 1, QString("2")); item.setData(0, Qt::UserRole + 2, QString("3")); item.setData(0, Qt::UserRole + 3, QString("4")); QMap flags = widget.model()->itemData(widget.model()->index(0, 0)); QCOMPARE(flags.count(), 6); QCOMPARE(flags[Qt::UserRole + 0].toString(), QString("1")); flags = widget.model()->itemData(widget.model()->index(0, 1)); QCOMPARE(flags.count(), 0); } void tst_QTreeWidget::enableDisable() { QTreeWidgetItem *itm = new QTreeWidgetItem(); for (int i = 0; i < 10; ++i) new QTreeWidgetItem(itm); // 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); QTest::qWait(100); QCOMPARE(testWidget->headerItem(), headerItem); QCOMPARE(headerItem->treeWidget(), static_cast(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(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(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(); QVERIFY(editor != 0); tree.closePersistentEditor(item, col); } } } } } void tst_QTreeWidget::insertItemsWithSorting_data() { QTest::addColumn("sortOrder"); QTest::addColumn("initialItems"); QTest::addColumn("insertItems"); QTest::addColumn("expectedItems"); QTest::addColumn("expectedRows"); QTest::newRow("() + (a) = (a)") << static_cast(Qt::AscendingOrder) << QStringList() << (QStringList() << "a") << (QStringList() << "a") << IntList(); QTest::newRow("() + (c, b, a) = (a, b, c)") << static_cast(Qt::AscendingOrder) << QStringList() << (QStringList() << "c" << "b" << "a") << (QStringList() << "a" << "b" << "c") << IntList(); QTest::newRow("() + (a, b, c) = (c, b, a)") << static_cast(Qt::DescendingOrder) << QStringList() << (QStringList() << "a" << "b" << "c") << (QStringList() << "c" << "b" << "a") << IntList(); QTest::newRow("(a) + (b) = (a, b)") << static_cast(Qt::AscendingOrder) << QStringList("a") << (QStringList() << "b") << (QStringList() << "a" << "b") << (IntList() << 0); QTest::newRow("(a) + (b) = (b, a)") << static_cast(Qt::DescendingOrder) << QStringList("a") << (QStringList() << "b") << (QStringList() << "b" << "a") << (IntList() << 1); QTest::newRow("(a, c, b) + (d) = (a, b, c, d)") << static_cast(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(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(Qt::AscendingOrder) << QStringList() << ascendingItems << ascendingItems << IntList(); QTest::newRow("(sorted items) + () = (sorted items)") << static_cast(Qt::AscendingOrder) << ascendingItems << QStringList() << ascendingItems << ascendingRows; QTest::newRow("() + (ascending items) = (reverse items)") << static_cast(Qt::DescendingOrder) << QStringList() << ascendingItems << reverseItems << IntList(); QTest::newRow("(reverse items) + () = (ascending items)") << static_cast(Qt::AscendingOrder) << reverseItems << QStringList() << ascendingItems << ascendingRows; QTest::newRow("(reverse items) + () = (reverse items)") << static_cast(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(sortOrder)); for (int i = 0; i < initialItems.count(); ++i) w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i))); QAbstractItemModel *model = w.model(); QList 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 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 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("parentText"); QTest::addColumn("childText"); QTest::addColumn("parentResult"); QTest::addColumn("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 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(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 parents; for (int i = 0; i < model->rowCount(QModelIndex()); ++i) { QPersistentModelIndex parent = model->index(i, 0, QModelIndex()); parents << parent; } QList 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("sortOrder"); QTest::addColumn("initialItems"); QTest::addColumn("itemIndex"); QTest::addColumn("newValue"); QTest::addColumn("expectedItems"); QTest::addColumn("expectedRows"); QTest::addColumn("reorderingExpected"); QTest::newRow("change a to b in (a)") << static_cast(Qt::AscendingOrder) << (QStringList() << "a") << 0 << "b" << (QStringList() << "b") << (IntList() << 0) << false; QTest::newRow("change a to b in (a, c)") << static_cast(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(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(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(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(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(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(sortOrder)); for (int i = 0; i < initialItems.count(); ++i) w.addTopLevelItem(new QTreeWidgetItem(QStringList() << initialItems.at(i))); QAbstractItemModel *model = w.model(); QList 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("sortOrder"); QTest::addColumn("initialItems"); QTest::addColumn("itemIndex"); QTest::addColumn("newValue"); QTest::addColumn("expectedItems"); QTest::addColumn("expectedRows"); QTest::addColumn("reorderingExpected"); QTest::addColumn("forceChange"); QTest::newRow("change a to c in (a, c, c, c, e)") << static_cast(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(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(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(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(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(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(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(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(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(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(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(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(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(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(sortOrder)); for (int i = 0; i < initialItems.count(); ++i) w.addTopLevelItem(new StableItem(QStringList() << initialItems.at(i))); QAbstractItemModel *model = w.model(); QList 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(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("sortOrder"); QTest::addColumn("itemTexts"); QTest::addColumn >("expectedIndexes"); QTest::newRow("three ascending") << int(Qt::AscendingOrder) << (QStringList() << "A" << "B" << "C") << (QList() << 0 << 1 << 2); QTest::newRow("three descending") << int(Qt::DescendingOrder) << (QStringList() << "A" << "B" << "C") << (QList() << 2 << 1 << 0); } void tst_QTreeWidget::sortedIndexOfChild() { QFETCH(int, sortOrder); QFETCH(QStringList, itemTexts); QFETCH(QList, expectedIndexes); QTreeWidget tw; QList 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; 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 children; children.append(new QTreeWidgetItem()); children.append(new QTreeWidgetItem()); children.append(new QTreeWidgetItem()); i1 = top->takeChild(0); 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); children = top->takeChildren(); QCOMPARE(children.at(0)->isDisabled(), false); QCOMPARE(children.at(1)->isDisabled(), false); QCOMPARE(children.at(1)->isDisabled(), false); } void tst_QTreeWidget::removeSelectedItem() { 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); 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); delete w; } 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 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() { QTreeWidget *tw = new QTreeWidget(); tw->setIconSize(QSize(50, 50)); tw->setColumnCount(6); for (int i=0; i<10; ++i) { QTreeWidgetItem *it = new QTreeWidgetItem(tw); for (int j=0; jcolumnCount() - 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(); QTest::qWait(50); 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()); QTest::qWait(200); 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(); QTest::qWait(200); QTreeWidgetItem item(&treeWidget); class MyWidget : public QWidget { virtual QSize sizeHint() const { return QSize(200,100); } } w; treeWidget.setItemWidget(&item, 0, &w); QTest::qWait(200); QCOMPARE(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 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().width(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(); QStringList strList; strList << "variable1" << "0"; QTreeWidgetItem *item = new QTreeWidgetItem(strList); treeWidget.insertTopLevelItem(0, item); QTest::qWait(50); QTRY_VERIFY(delegate.numPaints > 0); delegate.numPaints = 0; item->setText(1, "42"); QApplication::processEvents(); 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(); QTreeWidgetItem *item = new QTreeWidgetItem(QStringList("Hello")); treeWidget.insertTopLevelItem(0, item); QTest::qWait(50); QTRY_VERIFY(delegate.numPaints > 0); delegate.numPaints = 0; delegate.expectChildren = true; item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); QApplication::processEvents(); QTRY_COMPARE(delegate.numPaints, 1); delegate.numPaints = 0; delegate.expectChildren = false; item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); QApplication::processEvents(); QTRY_COMPARE(delegate.numPaints, 1); delegate.numPaints = 0; delegate.expectChildren = true; new QTreeWidgetItem(item); QApplication::processEvents(); QTRY_COMPARE(delegate.numPaints, 1); delegate.numPaints = 0; delegate.expectChildren = false; item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); QApplication::processEvents(); 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)) QSKIP("Wayland: 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() << Q_NULLPTR); QVERIFY(!md); } QTEST_MAIN(tst_QTreeWidget) #include "tst_qtreewidget.moc"