1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QApplication> |
31 | #include <QHeaderView> |
32 | #include <QLineEdit> |
33 | #include <QScrollBar> |
34 | #include <QSignalSpy> |
35 | #include <QStyledItemDelegate> |
36 | #include <QTreeWidget> |
37 | #include <QTreeWidgetItemIterator> |
38 | #include <QTest> |
39 | |
40 | class tst_QTreeWidget : public QObject |
41 | { |
42 | Q_OBJECT |
43 | |
44 | public: |
45 | tst_QTreeWidget() = default; |
46 | |
47 | public slots: |
48 | void initTestCase(); |
49 | void cleanupTestCase(); |
50 | void init(); |
51 | void cleanup(); |
52 | |
53 | private slots: |
54 | void getSetCheck(); |
55 | void addTopLevelItem(); |
56 | void currentItem_data(); |
57 | void currentItem(); |
58 | void editItem_data(); |
59 | void editItem(); |
60 | void takeItem_data(); |
61 | void takeItem(); |
62 | void removeChild_data(); |
63 | void removeChild(); |
64 | void setItemHidden(); |
65 | void setItemHidden2(); |
66 | void selectedItems_data(); |
67 | void selectedItems(); |
68 | void itemAssignment(); |
69 | void clone_data(); |
70 | void clone(); |
71 | void expand_data(); |
72 | void expand(); |
73 | void checkState_data(); |
74 | void checkState(); |
75 | void findItems_data(); |
76 | void findItems(); |
77 | void findItemsInColumn(); |
78 | void sortItems_data(); |
79 | void sortItems(); |
80 | void deleteItems_data(); |
81 | void deleteItems(); |
82 | void itemAboveOrBelow(); |
83 | void itemStreaming_data(); |
84 | void itemStreaming(); |
85 | void insertTopLevelItems_data(); |
86 | void insertTopLevelItems(); |
87 | void keyboardNavigation(); |
88 | void keyboardNavigationWithHidden(); |
89 | void scrollToItem(); |
90 | void setSortingEnabled(); |
91 | void match(); |
92 | void columnCount(); |
93 | void setHeaderLabels(); |
94 | void setHeaderItem(); |
95 | void itemWidget_data(); |
96 | void itemWidget(); |
97 | void insertItemsWithSorting_data(); |
98 | void insertItemsWithSorting(); |
99 | void insertExpandedItemsWithSorting_data(); |
100 | void insertExpandedItemsWithSorting(); |
101 | void changeDataWithSorting_data(); |
102 | void changeDataWithSorting(); |
103 | void changeDataWithStableSorting_data(); |
104 | void changeDataWithStableSorting(); |
105 | void sizeHint_data(); |
106 | void sizeHint(); |
107 | |
108 | void sortedIndexOfChild_data(); |
109 | void sortedIndexOfChild(); |
110 | void defaultRowSizes(); |
111 | |
112 | void task191552_rtl(); |
113 | void task203673_selection(); |
114 | void rootItemFlags(); |
115 | void task218661_setHeaderData(); |
116 | void task245280_sortChildren(); |
117 | void task253109_itemHeight(); |
118 | |
119 | void nonEditableTristate(); |
120 | |
121 | // QTreeWidgetItem |
122 | void itemOperatorLessThan(); |
123 | void addChild(); |
124 | void setData(); |
125 | void enableDisable(); |
126 | |
127 | void expandAndCallapse(); |
128 | void itemData(); |
129 | void setDisabled(); |
130 | void setSpanned(); |
131 | void removeSelectedItem(); |
132 | void removeCurrentItem(); |
133 | void removeCurrentItem_task186451(); |
134 | void randomExpand(); |
135 | void crashTest(); |
136 | void sortAndSelect(); |
137 | |
138 | void task206367_duplication(); |
139 | void selectionOrder(); |
140 | |
141 | void setSelectionModel(); |
142 | void task217309(); |
143 | void setCurrentItemExpandsParent(); |
144 | void task239150_editorWidth(); |
145 | void setTextUpdate(); |
146 | void taskQTBUG2844_visualItemRect(); |
147 | void setChildIndicatorPolicy(); |
148 | |
149 | void taskQTBUG_34717_collapseAtBottom(); |
150 | void task20345_sortChildren(); |
151 | void getMimeDataWithInvalidItem(); |
152 | void testVisualItemRect(); |
153 | void reparentHiddenItem(); |
154 | void persistentChildIndex(); |
155 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) |
156 | void clearItemData(); |
157 | #endif |
158 | |
159 | public slots: |
160 | void itemSelectionChanged(); |
161 | void emitDataChanged(); |
162 | |
163 | public: |
164 | class PublicTreeWidget : public QTreeWidget |
165 | { |
166 | public: |
167 | using QTreeWidget::indexFromItem; |
168 | using QTreeWidget::mimeData; |
169 | using QTreeWidget::sizeHintForColumn; |
170 | void deleteCurrent() { delete currentItem(); } |
171 | }; |
172 | |
173 | class PublicTreeItem : public QTreeWidgetItem |
174 | { |
175 | public: |
176 | using QTreeWidgetItem::QTreeWidgetItem; |
177 | using QTreeWidgetItem::emitDataChanged; |
178 | }; |
179 | |
180 | private: |
181 | PublicTreeWidget *testWidget = nullptr; |
182 | }; |
183 | |
184 | // Testing get/set functions |
185 | void tst_QTreeWidget::getSetCheck() |
186 | { |
187 | QTreeWidget obj1; |
188 | // int QTreeWidget::columnCount() |
189 | // void QTreeWidget::setColumnCount(int) |
190 | obj1.setColumnCount(0); |
191 | QCOMPARE(obj1.columnCount(), 0); |
192 | |
193 | obj1.setColumnCount(std::numeric_limits<int>::min()); |
194 | QCOMPARE(obj1.columnCount(), 0); |
195 | |
196 | //obj1.setColumnCount(INT_MAX); |
197 | //QCOMPARE(obj1.columnCount(), INT_MAX); |
198 | // Since setColumnCount allocates memory, there is no way this will succeed |
199 | |
200 | obj1.setColumnCount(100); |
201 | QCOMPARE(obj1.columnCount(), 100); |
202 | |
203 | // QTreeWidgetItem * QTreeWidget::headerItem() |
204 | // void QTreeWidget::setHeaderItem(QTreeWidgetItem *) |
205 | QTreeWidgetItem *var2 = new QTreeWidgetItem(); |
206 | obj1.setHeaderItem(var2); |
207 | QCOMPARE(obj1.headerItem(), var2); |
208 | |
209 | obj1.setHeaderItem(nullptr); |
210 | // QCOMPARE(obj1.headerItem(), nullptr); |
211 | |
212 | // QTreeWidgetItem * QTreeWidget::currentItem() |
213 | // void QTreeWidget::setCurrentItem(QTreeWidgetItem *) |
214 | QTreeWidgetItem *var3 = new QTreeWidgetItem(&obj1); |
215 | obj1.setCurrentItem(var3); |
216 | QCOMPARE(obj1.currentItem(), var3); |
217 | |
218 | obj1.setCurrentItem(nullptr); |
219 | QCOMPARE(obj1.currentItem(), nullptr); |
220 | } |
221 | |
222 | using IntList = QVector<int>; |
223 | using ListIntList = QVector<IntList>; |
224 | using PersistentModelIndexVec = QVector<QPersistentModelIndex>; |
225 | using TreeItem = QTreeWidgetItem; |
226 | using TreeItemList = QVector<TreeItem*>; |
227 | |
228 | Q_DECLARE_METATYPE(Qt::Orientation) |
229 | Q_DECLARE_METATYPE(QTreeWidgetItem*) |
230 | Q_DECLARE_METATYPE(TreeItemList) |
231 | |
232 | void tst_QTreeWidget::initTestCase() |
233 | { |
234 | qMetaTypeId<Qt::Orientation>(); |
235 | qRegisterMetaType<QTreeWidgetItem*>(typeName: "QTreeWidgetItem*" ); |
236 | qRegisterMetaType<QList<QPersistentModelIndex>>(typeName: "QList<QPersistentModelIndex>" ); |
237 | qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(typeName: "QAbstractItemModel::LayoutChangeHint" ); |
238 | |
239 | testWidget = new PublicTreeWidget(); |
240 | testWidget->show(); |
241 | QVERIFY(QTest::qWaitForWindowExposed(testWidget)); |
242 | } |
243 | |
244 | void tst_QTreeWidget::cleanupTestCase() |
245 | { |
246 | testWidget->hide(); |
247 | delete testWidget; |
248 | } |
249 | |
250 | void tst_QTreeWidget::init() |
251 | { |
252 | testWidget->clear(); |
253 | testWidget->setColumnCount(2); |
254 | } |
255 | |
256 | void tst_QTreeWidget::cleanup() |
257 | { |
258 | } |
259 | |
260 | TreeItem *operator<<(TreeItem *parent, const TreeItemList &children) |
261 | { |
262 | for (TreeItem *child : children) |
263 | parent->addChild(child); |
264 | return parent; |
265 | } |
266 | |
267 | static void populate(QTreeWidget *widget, const TreeItemList &topLevelItems, |
268 | TreeItem * = nullptr) |
269 | { |
270 | widget->clear(); |
271 | widget->setHeaderItem(headerItem); |
272 | for (TreeItem *item : topLevelItems) |
273 | widget->addTopLevelItem(item); |
274 | } |
275 | |
276 | void tst_QTreeWidget::addTopLevelItem() |
277 | { |
278 | QTreeWidget tree; |
279 | QCOMPARE(tree.topLevelItemCount(), 0); |
280 | |
281 | // try to add 0 |
282 | tree.addTopLevelItem(item: nullptr); |
283 | QCOMPARE(tree.topLevelItemCount(), 0); |
284 | QCOMPARE(tree.indexOfTopLevelItem(nullptr), -1); |
285 | |
286 | // add one at a time |
287 | QList<TreeItem *> tops; |
288 | for (int i = 0; i < 10; ++i) { |
289 | TreeItem *ti = new TreeItem(); |
290 | QCOMPARE(tree.indexOfTopLevelItem(ti), -1); |
291 | tree.addTopLevelItem(item: ti); |
292 | QCOMPARE(tree.topLevelItemCount(), i+1); |
293 | QCOMPARE(tree.topLevelItem(i), ti); |
294 | QCOMPARE(tree.topLevelItem(-1), nullptr); |
295 | QCOMPARE(tree.indexOfTopLevelItem(ti), i); |
296 | QCOMPARE(ti->parent(), nullptr); |
297 | tree.addTopLevelItem(item: ti); |
298 | QCOMPARE(tree.topLevelItemCount(), i+1); |
299 | tops.append(t: ti); |
300 | } |
301 | |
302 | // delete one at a time |
303 | while (!tops.isEmpty()) { |
304 | TreeItem *ti = tops.takeFirst(); |
305 | delete ti; |
306 | QCOMPARE(tree.topLevelItemCount(), tops.count()); |
307 | for (int i = 0; i < tops.count(); ++i) |
308 | QCOMPARE(tree.topLevelItem(i), tops.at(i)); |
309 | } |
310 | |
311 | // add none |
312 | { |
313 | int count = tree.topLevelItemCount(); |
314 | tree.addTopLevelItems(items: tops); |
315 | QCOMPARE(tree.topLevelItemCount(), count); |
316 | } |
317 | |
318 | // add many at a time |
319 | { |
320 | const int count = 10; |
321 | for (int i = 0; i < 100; i += count) { |
322 | tops.clear(); |
323 | for (int j = 0; j < count; ++j) |
324 | tops << new TreeItem(QStringList(QString::number(j))); |
325 | tree.addTopLevelItems(items: tops); |
326 | QCOMPARE(tree.topLevelItemCount(), count + i); |
327 | for (int j = 0; j < count; ++j) |
328 | QCOMPARE(tree.topLevelItem(i+j), tops.at(j)); |
329 | |
330 | tree.addTopLevelItems(items: tops); |
331 | QCOMPARE(tree.topLevelItemCount(), count + i); |
332 | } |
333 | } |
334 | |
335 | // insert |
336 | { |
337 | tops.clear(); |
338 | for (int i = 0; i < 10; ++i) |
339 | tops << new TreeItem(); |
340 | int count = tree.topLevelItemCount(); |
341 | tree.insertTopLevelItems(index: count, items: tops); |
342 | QCOMPARE(tree.topLevelItemCount(), count + 10); |
343 | } |
344 | |
345 | // invalid insert |
346 | { |
347 | tops.clear(); |
348 | for (int i = 0; i < 10; ++i) |
349 | tops << new TreeItem(); |
350 | int count = tree.topLevelItemCount(); |
351 | tree.insertTopLevelItems(index: 100000, items: tops); // should be a no-op |
352 | QCOMPARE(tree.topLevelItemCount(), count); |
353 | } |
354 | } |
355 | |
356 | void tst_QTreeWidget::currentItem_data() |
357 | { |
358 | QTest::addColumn<TreeItemList>(name: "topLevelItems" ); |
359 | |
360 | QTest::newRow(dataTag: "only top-level items, 2 columns" ) |
361 | << (TreeItemList() |
362 | << new TreeItem({"a" , "b" }) |
363 | << new TreeItem({"c" , "d" })); |
364 | TreeItemList lst; |
365 | lst << (new TreeItem({"a" , "b" }) |
366 | << (TreeItemList() |
367 | << new TreeItem({"c" , "d" }) |
368 | << new TreeItem({"c" , "d" }) |
369 | ) |
370 | ) |
371 | << (new TreeItem({"e" , "f" }) |
372 | << (TreeItemList() |
373 | << new TreeItem({"g" , "h" }) |
374 | << new TreeItem({"g" , "h" }) |
375 | ) |
376 | ); |
377 | QTest::newRow(dataTag: "hierarchy, 2 columns" ) << lst; |
378 | } |
379 | |
380 | void tst_QTreeWidget::currentItem() |
381 | { |
382 | QFETCH(TreeItemList, topLevelItems); |
383 | |
384 | QTreeWidget tree; |
385 | tree.show(); |
386 | populate(widget: &tree, topLevelItems, headerItem: new TreeItem({"1" , "2" })); |
387 | QTreeWidgetItem *previous = nullptr; |
388 | for (int x = 0; x < 2; ++x) { |
389 | tree.setSelectionBehavior(x ? QAbstractItemView::SelectItems |
390 | : QAbstractItemView::SelectRows); |
391 | QSignalSpy currentItemChangedSpy( |
392 | &tree, &QTreeWidget::currentItemChanged); |
393 | QSignalSpy itemSelectionChangedSpy( |
394 | &tree, &QTreeWidget::itemSelectionChanged); |
395 | |
396 | QTreeWidgetItemIterator it(&tree); |
397 | // do all items |
398 | while (QTreeWidgetItem *item = (*it++)) { |
399 | tree.setCurrentItem(item); |
400 | QCOMPARE(tree.currentItem(), item); |
401 | |
402 | QCOMPARE(currentItemChangedSpy.count(), 1); |
403 | QVariantList args = currentItemChangedSpy.takeFirst(); |
404 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
405 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(1)), previous); |
406 | |
407 | QCOMPARE(itemSelectionChangedSpy.count(), 1); |
408 | itemSelectionChangedSpy.clear(); |
409 | |
410 | previous = item; |
411 | // do all columns |
412 | for (int col = 0; col < item->columnCount(); ++col) { |
413 | tree.setCurrentItem(item, column: col); |
414 | QCOMPARE(tree.currentItem(), item); |
415 | QCOMPARE(tree.currentColumn(), col); |
416 | |
417 | if (!currentItemChangedSpy.isEmpty()) { |
418 | // ### we get a currentItemChanged() when what really |
419 | // changed was just currentColumn(). Should it be like this? |
420 | QCOMPARE(currentItemChangedSpy.count(), 1); |
421 | QVariantList args = currentItemChangedSpy.takeFirst(); |
422 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
423 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(1)), item); |
424 | if (tree.selectionBehavior() == QAbstractItemView::SelectItems) { |
425 | QCOMPARE(itemSelectionChangedSpy.count(), 1); |
426 | itemSelectionChangedSpy.clear(); |
427 | } else { |
428 | QCOMPARE(itemSelectionChangedSpy.count(), 0); |
429 | } |
430 | } |
431 | } |
432 | } |
433 | } |
434 | |
435 | // can't set the headerItem to be the current item |
436 | tree.setCurrentItem(tree.headerItem()); |
437 | QCOMPARE(tree.currentItem(), nullptr); |
438 | } |
439 | |
440 | void tst_QTreeWidget::editItem_data() |
441 | { |
442 | QTest::addColumn<TreeItemList>(name: "topLevelItems" ); |
443 | |
444 | { |
445 | TreeItemList list; |
446 | for (int i = 0; i < 10; i++) { |
447 | TreeItem *item = new TreeItem(QStringList() << "col1" << "col2" ); |
448 | if ((i & 1) == 0) |
449 | item->setFlags(item->flags() | Qt::ItemIsEditable); |
450 | else |
451 | item->setFlags(item->flags() & ~Qt::ItemIsEditable); |
452 | list << item; |
453 | } |
454 | QTest::newRow(dataTag: "2 columns, only even items editable" ) |
455 | << list; |
456 | } |
457 | } |
458 | |
459 | void tst_QTreeWidget::editItem() |
460 | { |
461 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
462 | QSKIP("Wayland: This fails. Figure out why." ); |
463 | |
464 | QFETCH(TreeItemList, topLevelItems); |
465 | |
466 | QTreeWidget tree; |
467 | populate(widget: &tree, topLevelItems, headerItem: new TreeItem(QStringList() << "1" << "2" )); |
468 | tree.show(); |
469 | QVERIFY(QTest::qWaitForWindowActive(&tree)); |
470 | |
471 | QSignalSpy itemChangedSpy(&tree, &QTreeWidget::itemChanged); |
472 | |
473 | QTreeWidgetItemIterator it(&tree); |
474 | while (QTreeWidgetItem *item = (*it++)) { |
475 | for (int col = 0; col < item->columnCount(); ++col) { |
476 | if (!(item->flags() & Qt::ItemIsEditable)) |
477 | QTest::ignoreMessage(type: QtWarningMsg, message: "edit: editing failed" ); |
478 | tree.editItem(item, column: col); |
479 | QCoreApplication::processEvents(); |
480 | QCoreApplication::processEvents(); |
481 | QLineEdit *editor = tree.findChild<QLineEdit*>(); |
482 | if (editor) { |
483 | QVERIFY(item->flags() & Qt::ItemIsEditable); |
484 | QCOMPARE(editor->selectedText(), editor->text()); |
485 | QTest::keyClick(widget: editor, key: Qt::Key_A); |
486 | QTest::keyClick(widget: editor, key: Qt::Key_Enter); |
487 | QCoreApplication::processEvents(); |
488 | QCOMPARE(itemChangedSpy.count(), 1); |
489 | QVariantList args = itemChangedSpy.takeFirst(); |
490 | QCOMPARE(qvariant_cast<QTreeWidgetItem *>(args.at(0)), item); |
491 | QCOMPARE(qvariant_cast<int>(args.at(1)), col); |
492 | } else { |
493 | QVERIFY(!(item->flags() & Qt::ItemIsEditable)); |
494 | } |
495 | } |
496 | } |
497 | } |
498 | |
499 | void tst_QTreeWidget::takeItem_data() |
500 | { |
501 | QTest::addColumn<int>(name: "index" ); |
502 | QTest::addColumn<bool>(name: "topLevel" ); |
503 | QTest::addColumn<bool>(name: "outOfBounds" ); |
504 | |
505 | QTest::newRow(dataTag: "First, topLevel" ) << 0 << true << false; |
506 | QTest::newRow(dataTag: "Last, topLevel" ) << 2 << true << false; |
507 | QTest::newRow(dataTag: "Middle, topLevel" ) << 1 << true << false; |
508 | QTest::newRow(dataTag: "Out of bounds, toplevel, (index: -1)" ) << -1 << true << true; |
509 | QTest::newRow(dataTag: "Out of bounds, toplevel, (index: 3)" ) << 3 << true << true; |
510 | |
511 | QTest::newRow(dataTag: "First, child of topLevel" ) << 0 << false << false; |
512 | QTest::newRow(dataTag: "Last, child of topLevel" ) << 2 << false << false; |
513 | QTest::newRow(dataTag: "Middle, child of topLevel" ) << 1 << false << false; |
514 | QTest::newRow(dataTag: "Out of bounds, child of toplevel, (index: -1)" ) << -1 << false << true; |
515 | QTest::newRow(dataTag: "Out of bounds, child of toplevel, (index: 3)" ) << 3 << false << true; |
516 | } |
517 | |
518 | void tst_QTreeWidget::takeItem() |
519 | { |
520 | QFETCH(int, index); |
521 | QFETCH(bool, topLevel); |
522 | QFETCH(bool, outOfBounds); |
523 | |
524 | for (int i = 0; i < 3; ++i) { |
525 | QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); |
526 | top->setText(column: 0, QStringLiteral("top" ) + QString::number(i)); |
527 | for (int j = 0; j < 3; ++j) { |
528 | QTreeWidgetItem *child = new QTreeWidgetItem(top); |
529 | child->setText(column: 0, QStringLiteral("child" ) + QString::number(j)); |
530 | } |
531 | } |
532 | |
533 | QCOMPARE(testWidget->topLevelItemCount(), 3); |
534 | QCOMPARE(testWidget->topLevelItem(0)->childCount(), 3); |
535 | |
536 | if (topLevel) { |
537 | int count = testWidget->topLevelItemCount(); |
538 | QTreeWidgetItem *item = testWidget->takeTopLevelItem(index); |
539 | if (outOfBounds) { |
540 | QCOMPARE(item, nullptr); |
541 | QCOMPARE(count, testWidget->topLevelItemCount()); |
542 | } else { |
543 | QCOMPARE(item->text(0), QStringLiteral("top" ) + QString::number(index)); |
544 | QCOMPARE(count-1, testWidget->topLevelItemCount()); |
545 | delete item; |
546 | } |
547 | } else { |
548 | int count = testWidget->topLevelItem(index: 0)->childCount(); |
549 | QTreeWidgetItem *item = testWidget->topLevelItem(index: 0)->takeChild(index); |
550 | if (outOfBounds) { |
551 | QCOMPARE(item, nullptr); |
552 | QCOMPARE(count, testWidget->topLevelItem(0)->childCount()); |
553 | } else { |
554 | QCOMPARE(item->text(0), QStringLiteral("child" ) + QString::number(index)); |
555 | QCOMPARE(count-1, testWidget->topLevelItem(0)->childCount()); |
556 | delete item; |
557 | } |
558 | } |
559 | } |
560 | |
561 | void tst_QTreeWidget::removeChild_data() |
562 | { |
563 | QTest::addColumn<int>(name: "childCount" ); |
564 | QTest::addColumn<int>(name: "removeAt" ); |
565 | |
566 | QTest::newRow(dataTag: "10 remove 3" ) << 10 << 3; |
567 | } |
568 | |
569 | void tst_QTreeWidget::removeChild() |
570 | { |
571 | QFETCH(int, childCount); |
572 | QFETCH(int, removeAt); |
573 | |
574 | const QScopedPointer<QTreeWidgetItem> root(new QTreeWidgetItem); |
575 | for (int i = 0; i < childCount; ++i) |
576 | new QTreeWidgetItem(root.data(), QStringList(QString::number(i))); |
577 | |
578 | QCOMPARE(root->childCount(), childCount); |
579 | for (int j = 0; j < childCount; ++j) |
580 | QCOMPARE(root->child(j)->text(0), QString::number(j)); |
581 | |
582 | const QScopedPointer<QTreeWidgetItem> remove(root->child(index: removeAt)); |
583 | root->removeChild(child: remove.data()); |
584 | |
585 | QCOMPARE(root->childCount(), childCount - 1); |
586 | for (int k = 0; k < childCount; ++k) { |
587 | if (k == removeAt) |
588 | QCOMPARE(remove->text(0), QString::number(k)); |
589 | else if (k < removeAt) |
590 | QCOMPARE(root->child(k)->text(0), QString::number(k)); |
591 | else if (k > removeAt) |
592 | QCOMPARE(root->child(k - 1)->text(0), QString::number(k)); |
593 | } |
594 | } |
595 | |
596 | void tst_QTreeWidget::setItemHidden() |
597 | { |
598 | QTreeWidgetItem *parent = new QTreeWidgetItem(testWidget); |
599 | parent->setText(column: 0, atext: "parent" ); |
600 | QTreeWidgetItem *child = new QTreeWidgetItem(parent); |
601 | child->setText(column: 0, atext: "child" ); |
602 | QVERIFY(child->parent()); |
603 | |
604 | testWidget->expandItem(item: parent); |
605 | testWidget->scrollToItem(item: child); |
606 | |
607 | QVERIFY(testWidget->visualItemRect(parent).isValid() |
608 | && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(parent))); |
609 | QVERIFY(testWidget->visualItemRect(child).isValid() |
610 | && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(child))); |
611 | |
612 | QVERIFY(!parent->isHidden()); |
613 | QVERIFY(!child->isHidden()); |
614 | |
615 | parent->setHidden(true); |
616 | |
617 | QVERIFY(!(testWidget->visualItemRect(parent).isValid() |
618 | && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(parent)))); |
619 | QVERIFY(!(testWidget->visualItemRect(child).isValid() |
620 | && testWidget->viewport()->rect().intersects(testWidget->visualItemRect(child)))); |
621 | |
622 | QVERIFY(parent->isHidden()); |
623 | QVERIFY(!child->isHidden()); |
624 | |
625 | // From task 78670 (This caused an core dump) |
626 | // Check if we can set an item visible if it already is visible. |
627 | parent->setHidden(false); |
628 | parent->setHidden(false); |
629 | QVERIFY(!parent->isHidden()); |
630 | |
631 | |
632 | // hide, hide and then unhide. |
633 | parent->setHidden(true); |
634 | parent->setHidden(true); |
635 | parent->setHidden(false); |
636 | QVERIFY(!parent->isHidden()); |
637 | } |
638 | |
639 | |
640 | void tst_QTreeWidget::setItemHidden2() |
641 | { |
642 | // From Task 78587 |
643 | const QStringList hl({"ID" , "Desc" }); |
644 | testWidget->setColumnCount(hl.count()); |
645 | testWidget->setHeaderLabels(hl); |
646 | testWidget->setSortingEnabled(true); |
647 | |
648 | QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); |
649 | top->setText(column: 0, atext: "ItemList" ); |
650 | for (int i = 1; i <= 4; i++) { |
651 | auto leaf = new QTreeWidgetItem(top); |
652 | leaf->setText(column: 0, atext: QString::number(i)); |
653 | leaf->setText(column: 1, QStringLiteral("Item %1" ).arg(a: i)); |
654 | } |
655 | |
656 | if (testWidget->topLevelItemCount() > 0) { |
657 | top = testWidget->topLevelItem(index: 0); |
658 | top->setExpanded(true); |
659 | } |
660 | |
661 | if (testWidget->topLevelItemCount() > 0) { |
662 | top = testWidget->topLevelItem(index: 0); |
663 | for (int i = 0; i < top->childCount(); i++) { |
664 | auto leaf = top->child(index: i); |
665 | if (leaf->text(column: 0).toInt() % 2 == 0) { |
666 | if (!leaf->isHidden()) |
667 | leaf->setHidden(true); |
668 | } |
669 | } |
670 | } |
671 | } |
672 | |
673 | |
674 | void tst_QTreeWidget::selectedItems_data() |
675 | { |
676 | QTest::addColumn<int>(name: "topLevel" ); |
677 | QTest::addColumn<int>(name: "children" ); |
678 | QTest::addColumn<bool>(name: "closeTopLevel" ); |
679 | QTest::addColumn<ListIntList>(name: "selectedItems" ); |
680 | QTest::addColumn<ListIntList>(name: "hiddenItems" ); |
681 | QTest::addColumn<ListIntList>(name: "expectedItems" ); |
682 | |
683 | ListIntList selectedItems; |
684 | ListIntList hiddenItems; |
685 | ListIntList expectedItems; |
686 | |
687 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
688 | selectedItems |
689 | << (IntList() |
690 | << 0); |
691 | expectedItems |
692 | << (IntList() << 0); |
693 | QTest::newRow(dataTag: "2 top with 2 children, closed, top0 selected, no hidden" ) |
694 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
695 | |
696 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
697 | selectedItems |
698 | << (IntList() |
699 | << 0 << 0); |
700 | expectedItems |
701 | << (IntList() << 0 << 0); |
702 | QTest::newRow(dataTag: "2 top with 2 children, closed, top0child0 selected, no hidden" ) |
703 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
704 | |
705 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
706 | selectedItems |
707 | << (IntList() |
708 | << 0 << 0); |
709 | expectedItems |
710 | << (IntList() |
711 | << 0 << 0); |
712 | QTest::newRow(dataTag: "2 top with 2 children, open, top0child0 selected, no hidden" ) |
713 | << 2 << 2 << false << selectedItems << hiddenItems << expectedItems; |
714 | |
715 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
716 | selectedItems << (IntList() << 0); |
717 | hiddenItems << (IntList() << 0); |
718 | QTest::newRow(dataTag: "2 top with 2 children, closed, top0 selected, top0 hidden" ) |
719 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
720 | |
721 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
722 | selectedItems << (IntList() << 0 << 0); |
723 | hiddenItems << (IntList() << 0); |
724 | expectedItems << (IntList() << 0 << 0); |
725 | QTest::newRow(dataTag: "2 top with 2 children, closed, top0child0 selected, top0 hidden" ) |
726 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
727 | |
728 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
729 | selectedItems |
730 | << (IntList() << 0) |
731 | << (IntList() << 0 << 0) |
732 | << (IntList() << 0 << 1) |
733 | << (IntList() << 1) |
734 | << (IntList() << 1 << 0) |
735 | << (IntList() << 1 << 1); |
736 | expectedItems |
737 | << (IntList() << 0) |
738 | << (IntList() << 0 << 0) |
739 | << (IntList() << 0 << 1) |
740 | << (IntList() << 1) |
741 | << (IntList() << 1 << 0) |
742 | << (IntList() << 1 << 1); |
743 | QTest::newRow(dataTag: "2 top with 2 children, closed, all selected, no hidden" ) |
744 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
745 | |
746 | |
747 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
748 | selectedItems |
749 | << (IntList() << 0) |
750 | << (IntList() << 0 << 0) |
751 | << (IntList() << 0 << 1) |
752 | << (IntList() << 1) |
753 | << (IntList() << 1 << 0) |
754 | << (IntList() << 1 << 1); |
755 | hiddenItems |
756 | << (IntList() << 0); |
757 | expectedItems |
758 | //<< (IntList() << 0) |
759 | << (IntList() << 0 << 0) |
760 | << (IntList() << 0 << 1) |
761 | << (IntList() << 1) |
762 | << (IntList() << 1 << 0) |
763 | << (IntList() << 1 << 1); |
764 | QTest::newRow(dataTag: "2 top with 2 children, closed, all selected, top0 hidden" ) |
765 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
766 | |
767 | selectedItems.clear(); hiddenItems.clear(); expectedItems.clear(); |
768 | selectedItems |
769 | << (IntList() << 0) |
770 | << (IntList() << 0 << 0) |
771 | << (IntList() << 0 << 1) |
772 | << (IntList() << 1) |
773 | << (IntList() << 1 << 0) |
774 | << (IntList() << 1 << 1); |
775 | hiddenItems |
776 | << (IntList() << 0 << 1) |
777 | << (IntList() << 1); |
778 | expectedItems |
779 | << (IntList() << 0) |
780 | << (IntList() << 0 << 0) |
781 | //<< (IntList() << 0 << 1) |
782 | //<< (IntList() << 1) |
783 | << (IntList() << 1 << 0) |
784 | << (IntList() << 1 << 1); |
785 | |
786 | QTest::newRow(dataTag: "2 top with 2 children, closed, all selected, top0child1 and top1" ) |
787 | << 2 << 2 << true << selectedItems << hiddenItems << expectedItems; |
788 | |
789 | } |
790 | |
791 | void tst_QTreeWidget::selectedItems() |
792 | { |
793 | QFETCH(int, topLevel); |
794 | QFETCH(int, children); |
795 | QFETCH(bool, closeTopLevel); |
796 | QFETCH(const ListIntList, selectedItems); |
797 | QFETCH(const ListIntList, hiddenItems); |
798 | QFETCH(const ListIntList, expectedItems); |
799 | |
800 | // create items |
801 | for (int t = 0; t < topLevel; ++t) { |
802 | QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); |
803 | const QString topS = QLatin1String("top" ) + QString::number(t); |
804 | top->setText(column: 0, atext: topS); |
805 | for (int c = 0; c < children; ++c) { |
806 | QTreeWidgetItem *child = new QTreeWidgetItem(top); |
807 | child->setText(column: 0, atext: topS + QLatin1String("child" ) + QString::number(c)); |
808 | } |
809 | } |
810 | |
811 | // set selected |
812 | for (const auto &itemPath : selectedItems) { |
813 | QTreeWidgetItem *item = nullptr; |
814 | for (int index : itemPath) { |
815 | if (!item) |
816 | item = testWidget->topLevelItem(index); |
817 | else |
818 | item = item->child(index); |
819 | } |
820 | item->setSelected(true); |
821 | } |
822 | |
823 | // hide rows |
824 | for (const auto &itemPath : hiddenItems) { |
825 | QTreeWidgetItem *item = nullptr; |
826 | for (int index : itemPath) { |
827 | if (!item) |
828 | item = testWidget->topLevelItem(index); |
829 | else |
830 | item = item->child(index); |
831 | } |
832 | item->setHidden(true); |
833 | } |
834 | |
835 | // open/close toplevel |
836 | for (int i = 0; i < testWidget->topLevelItemCount(); ++i) { |
837 | if (closeTopLevel) |
838 | testWidget->collapseItem(item: testWidget->topLevelItem(index: i)); |
839 | else |
840 | testWidget->expandItem(item: testWidget->topLevelItem(index: i)); |
841 | } |
842 | |
843 | // check selectedItems |
844 | const auto sel = testWidget->selectedItems(); |
845 | QCOMPARE(sel.count(), expectedItems.count()); |
846 | for (const auto &itemPath : expectedItems) { |
847 | QTreeWidgetItem *item = nullptr; |
848 | for (int index : itemPath) { |
849 | if (!item) |
850 | item = testWidget->topLevelItem(index); |
851 | else |
852 | item = item->child(index); |
853 | } |
854 | if (item) |
855 | QVERIFY(sel.contains(item)); |
856 | } |
857 | |
858 | // compare isSelected |
859 | for (int t = 0; t < testWidget->topLevelItemCount(); ++t) { |
860 | QTreeWidgetItem *top = testWidget->topLevelItem(index: t); |
861 | if (top->isSelected() && !top->isHidden()) |
862 | QVERIFY(sel.contains(top)); |
863 | for (int c = 0; c < top->childCount(); ++c) { |
864 | QTreeWidgetItem *child = top->child(index: c); |
865 | if (child->isSelected() && !child->isHidden()) |
866 | QVERIFY(sel.contains(child)); |
867 | } |
868 | } |
869 | |
870 | #if QT_DEPRECATED_SINCE(5, 13) |
871 | QT_WARNING_PUSH |
872 | QT_WARNING_DISABLE_DEPRECATED |
873 | // Possible to select null without crashing? |
874 | testWidget->setItemSelected(item: nullptr, select: true); |
875 | QVERIFY(!testWidget->isItemSelected(nullptr)); |
876 | QT_WARNING_POP |
877 | #endif |
878 | |
879 | // unselect |
880 | for (const auto &itemPath : selectedItems) { |
881 | QTreeWidgetItem *item = nullptr; |
882 | for (int index : itemPath) { |
883 | if (!item) |
884 | item = testWidget->topLevelItem(index); |
885 | else |
886 | item = item->child(index); |
887 | } |
888 | item->setSelected(false); |
889 | } |
890 | QCOMPARE(testWidget->selectedItems().count(), 0); |
891 | } |
892 | |
893 | void tst_QTreeWidget::itemAssignment() |
894 | { |
895 | // create item with children and parent but not insert in the view |
896 | QTreeWidgetItem grandParent; |
897 | QTreeWidgetItem *parent = new QTreeWidgetItem(&grandParent); |
898 | parent->setText(column: 0, atext: "foo" ); |
899 | parent->setText(column: 1, atext: "bar" ); |
900 | for (int i = 0; i < 5; ++i) { |
901 | QTreeWidgetItem *child = new QTreeWidgetItem(parent); |
902 | child->setText(column: 0, atext: "bingo" ); |
903 | child->setText(column: 1, atext: "bango" ); |
904 | } |
905 | QCOMPARE(parent->parent(), &grandParent); |
906 | QVERIFY(!parent->treeWidget()); |
907 | QCOMPARE(parent->columnCount(), 2); |
908 | QCOMPARE(parent->text(0), QString("foo" )); |
909 | QCOMPARE(parent->childCount(), 5); |
910 | QCOMPARE(parent->child(0)->parent(), parent); |
911 | |
912 | // create item which is inserted in the widget |
913 | QTreeWidgetItem item(testWidget); |
914 | item.setText(column: 0, atext: "baz" ); |
915 | QVERIFY(!item.parent()); |
916 | QCOMPARE(item.treeWidget(), testWidget); |
917 | QCOMPARE(item.columnCount(), 1); |
918 | QCOMPARE(item.text(0), QString("baz" )); |
919 | QCOMPARE(item.childCount(), 0); |
920 | |
921 | // assign and test |
922 | *parent = item; |
923 | QCOMPARE(parent->parent(), &grandParent); |
924 | QVERIFY(!parent->treeWidget()); |
925 | QCOMPARE(parent->columnCount(), 1); |
926 | QCOMPARE(parent->text(0), QString("baz" )); |
927 | QCOMPARE(parent->childCount(), 5); |
928 | QCOMPARE(parent->child(0)->parent(), parent); |
929 | } |
930 | |
931 | void tst_QTreeWidget::clone_data() |
932 | { |
933 | QTest::addColumn<int>(name: "column" ); |
934 | QTest::addColumn<int>(name: "topLevelIndex" ); |
935 | QTest::addColumn<int>(name: "childIndex" ); |
936 | QTest::addColumn<QStringList>(name: "topLevelText" ); |
937 | QTest::addColumn<QStringList>(name: "childText" ); |
938 | QTest::addColumn<bool>(name: "cloneChild" ); |
939 | |
940 | QTest::newRow(dataTag: "clone parent with child" ) << 0 << 0 << 0 |
941 | << (QStringList() << "some text" ) |
942 | << (QStringList() << "more text" ) |
943 | << false; |
944 | |
945 | QTest::newRow(dataTag: "clone child" ) << 0 << 0 << 0 |
946 | << (QStringList() << "some text" ) |
947 | << (QStringList() << "more text" ) |
948 | << true; |
949 | } |
950 | |
951 | void tst_QTreeWidget::clone() |
952 | { |
953 | QFETCH(int, column); |
954 | QFETCH(int, topLevelIndex); |
955 | QFETCH(int, childIndex); |
956 | QFETCH(const QStringList, topLevelText); |
957 | QFETCH(const QStringList, childText); |
958 | QFETCH(bool, cloneChild); |
959 | |
960 | for (const QString &tl : topLevelText) { |
961 | QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); |
962 | item->setText(column, atext: tl); |
963 | for (const QString &cl : childText) { |
964 | QTreeWidgetItem *child = new QTreeWidgetItem(item); |
965 | child->setText(column, atext: cl); |
966 | } |
967 | } |
968 | |
969 | QTreeWidgetItem *original = testWidget->topLevelItem(index: topLevelIndex); |
970 | QTreeWidgetItem *copy = original->clone(); |
971 | QCOMPARE(copy->text(column), original->text(column)); |
972 | QCOMPARE(copy->childCount(), original->childCount()); |
973 | QVERIFY(!copy->parent()); |
974 | QVERIFY(!copy->treeWidget()); |
975 | |
976 | QTreeWidgetItem *originalChild = original->child(index: childIndex); |
977 | QTreeWidgetItem *copiedChild = cloneChild ? originalChild->clone() : copy->child(index: childIndex); |
978 | QVERIFY(copiedChild != originalChild); |
979 | QCOMPARE(copiedChild->text(column), originalChild->text(column)); |
980 | QCOMPARE(copiedChild->childCount(), originalChild->childCount()); |
981 | QCOMPARE(copiedChild->parent(), cloneChild ? nullptr : copy); |
982 | QVERIFY(!copiedChild->treeWidget()); |
983 | if (cloneChild) |
984 | delete copiedChild; |
985 | delete copy; |
986 | } |
987 | |
988 | void tst_QTreeWidget::expand_data() |
989 | { |
990 | QTest::addColumn<int>(name: "topLevelIndex" ); |
991 | QTest::addColumn<int>(name: "topLevelCount" ); |
992 | QTest::addColumn<int>(name: "childIndex" ); |
993 | QTest::addColumn<int>(name: "childCount" ); |
994 | |
995 | QTest::newRow(dataTag: "the only test data for now" ) << 0 << 1 << 0 << 1; |
996 | } |
997 | |
998 | void tst_QTreeWidget::expand() |
999 | { |
1000 | QFETCH(int, topLevelIndex); |
1001 | QFETCH(int, topLevelCount); |
1002 | QFETCH(int, childIndex); |
1003 | QFETCH(int, childCount); |
1004 | |
1005 | for (int i = 0; i < topLevelCount; ++i) { |
1006 | QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); |
1007 | for (int j = 0; j < childCount; ++j) |
1008 | new QTreeWidgetItem(item); |
1009 | } |
1010 | |
1011 | QTreeWidgetItem *topLevelItem = testWidget->topLevelItem(index: topLevelIndex); |
1012 | QTreeWidgetItem *childItem = topLevelItem->child(index: childIndex); |
1013 | |
1014 | QVERIFY(!topLevelItem->isExpanded()); |
1015 | topLevelItem->setExpanded(true); |
1016 | QVERIFY(topLevelItem->isExpanded()); |
1017 | |
1018 | QVERIFY(!childItem->isExpanded()); |
1019 | childItem->setExpanded(true); |
1020 | QVERIFY(childItem->isExpanded()); |
1021 | |
1022 | QVERIFY(topLevelItem->isExpanded()); |
1023 | topLevelItem->setExpanded(false); |
1024 | QVERIFY(!topLevelItem->isExpanded()); |
1025 | |
1026 | QVERIFY(childItem->isExpanded()); |
1027 | childItem->setExpanded(false); |
1028 | QVERIFY(!childItem->isExpanded()); |
1029 | } |
1030 | |
1031 | void tst_QTreeWidget::checkState_data() |
1032 | { |
1033 | } |
1034 | |
1035 | void tst_QTreeWidget::checkState() |
1036 | { |
1037 | QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); |
1038 | item->setCheckState(column: 0, state: Qt::Unchecked); |
1039 | QTreeWidgetItem *firstChild = new QTreeWidgetItem(item); |
1040 | firstChild->setCheckState(column: 0, state: Qt::Unchecked); |
1041 | QTreeWidgetItem *seccondChild = new QTreeWidgetItem(item); |
1042 | seccondChild->setCheckState(column: 0, state: Qt::Unchecked); |
1043 | |
1044 | QCOMPARE(item->checkState(0), Qt::Unchecked); |
1045 | QCOMPARE(firstChild->checkState(0), Qt::Unchecked); |
1046 | QCOMPARE(seccondChild->checkState(0), Qt::Unchecked); |
1047 | |
1048 | firstChild->setCheckState(column: 0, state: Qt::Checked); |
1049 | QCOMPARE(item->checkState(0), Qt::Unchecked); |
1050 | QCOMPARE(firstChild->checkState(0), Qt::Checked); |
1051 | QCOMPARE(seccondChild->checkState(0), Qt::Unchecked); |
1052 | |
1053 | item->setFlags(item->flags()|Qt::ItemIsAutoTristate); |
1054 | QCOMPARE(item->checkState(0), Qt::PartiallyChecked); |
1055 | QCOMPARE(firstChild->checkState(0), Qt::Checked); |
1056 | QCOMPARE(seccondChild->checkState(0), Qt::Unchecked); |
1057 | |
1058 | seccondChild->setCheckState(column: 0, state: Qt::Checked); |
1059 | QCOMPARE(item->checkState(0), Qt::Checked); |
1060 | QCOMPARE(firstChild->checkState(0), Qt::Checked); |
1061 | QCOMPARE(seccondChild->checkState(0), Qt::Checked); |
1062 | |
1063 | firstChild->setCheckState(column: 0, state: Qt::Unchecked); |
1064 | seccondChild->setCheckState(column: 0, state: Qt::Unchecked); |
1065 | QCOMPARE(item->checkState(0), Qt::Unchecked); |
1066 | QCOMPARE(firstChild->checkState(0), Qt::Unchecked); |
1067 | QCOMPARE(seccondChild->checkState(0), Qt::Unchecked); |
1068 | |
1069 | // Can't force the state to PartiallyChecked; state comes from children |
1070 | item->setCheckState(column: 0, state: Qt::PartiallyChecked); |
1071 | QCOMPARE(item->checkState(0), Qt::Unchecked); |
1072 | QCOMPARE(firstChild->checkState(0), Qt::Unchecked); |
1073 | QCOMPARE(seccondChild->checkState(0), Qt::Unchecked); |
1074 | } |
1075 | |
1076 | void tst_QTreeWidget::findItems_data() |
1077 | { |
1078 | QTest::addColumn<int>(name: "column" ); |
1079 | QTest::addColumn<QStringList>(name: "topLevelText" ); |
1080 | QTest::addColumn<QStringList>(name: "childText" ); |
1081 | QTest::addColumn<QString>(name: "pattern" ); |
1082 | QTest::addColumn<int>(name: "resultCount" ); |
1083 | QTest::addColumn<QStringList>(name: "resultText" ); |
1084 | |
1085 | QTest::newRow(dataTag: "find in toplevel" ) |
1086 | << 0 |
1087 | << (QStringList() << "This is a text" << "This is another" << "This is the one" ) |
1088 | << (QStringList() << "A child" << "This is not the one" << "And yet another child" ) |
1089 | << "This is the one" |
1090 | << 1 |
1091 | << (QStringList() << "This is the one" ); |
1092 | |
1093 | QTest::newRow(dataTag: "find child" ) |
1094 | << 0 |
1095 | << (QStringList() << "This is a text" << "This is another" << "This is the one" ) |
1096 | << (QStringList() << "A child" << "This is not the one" << "And yet another child" ) |
1097 | << "A child" |
1098 | << 3 // once for each branch |
1099 | << (QStringList() << "A child" ); |
1100 | |
1101 | } |
1102 | |
1103 | void tst_QTreeWidget::findItems() |
1104 | { |
1105 | QFETCH(int, column); |
1106 | QFETCH(const QStringList, topLevelText); |
1107 | QFETCH(const QStringList, childText); |
1108 | QFETCH(QString, pattern); |
1109 | QFETCH(int, resultCount); |
1110 | QFETCH(const QStringList, resultText); |
1111 | |
1112 | for (const QString &tl : topLevelText) { |
1113 | QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); |
1114 | item->setText(column, atext: tl); |
1115 | for (const QString &cl : childText) { |
1116 | QTreeWidgetItem *child = new QTreeWidgetItem(item); |
1117 | child->setText(column, atext: cl); |
1118 | } |
1119 | } |
1120 | |
1121 | QList<QTreeWidgetItem*> result = testWidget->findItems(text: pattern, |
1122 | flags: Qt::MatchExactly|Qt::MatchRecursive); |
1123 | QCOMPARE(result.count(), resultCount); |
1124 | |
1125 | for (int k = 0; k < result.count() && k < resultText.count(); ++k) |
1126 | QCOMPARE(result.at(k)->text(column), resultText.at(k)); |
1127 | } |
1128 | |
1129 | void tst_QTreeWidget::findItemsInColumn() |
1130 | { |
1131 | // Create 5 root items. |
1132 | for (int i = 0; i < 5; i++) |
1133 | new QTreeWidgetItem(testWidget, QStringList() << QString::number(i)); |
1134 | |
1135 | // Create a child with two columns for each root item. |
1136 | for (int i = 0; i < 5; i++) { |
1137 | QTreeWidgetItem * const parent = testWidget->topLevelItem(index: i); |
1138 | new QTreeWidgetItem(parent, QStringList() << QString::number(i * 10) << QString::number(i * 100)); |
1139 | } |
1140 | |
1141 | // Recursively search column one for 400. |
1142 | QList<QTreeWidgetItem*> items = testWidget->findItems(text: "400" , flags: Qt::MatchExactly|Qt::MatchRecursive, column: 1); |
1143 | QCOMPARE(items.count(), 1); |
1144 | } |
1145 | |
1146 | void tst_QTreeWidget::sortItems_data() |
1147 | { |
1148 | QTest::addColumn<int>(name: "column" ); |
1149 | QTest::addColumn<Qt::SortOrder>(name: "order" ); |
1150 | QTest::addColumn<QStringList>(name: "topLevelText" ); |
1151 | QTest::addColumn<QStringList>(name: "childText" ); |
1152 | QTest::addColumn<QStringList>(name: "topLevelResult" ); |
1153 | QTest::addColumn<QStringList>(name: "childResult" ); |
1154 | QTest::addColumn<IntList>(name: "expectedTopRows" ); |
1155 | QTest::addColumn<IntList>(name: "expectedChildRows" ); |
1156 | |
1157 | QTest::newRow(dataTag: "ascending order" ) |
1158 | << 0 |
1159 | << Qt::AscendingOrder |
1160 | << (QStringList() << "c" << "d" << "a" << "b" ) |
1161 | << (QStringList() << "e" << "h" << "g" << "f" ) |
1162 | << (QStringList() << "a" << "b" << "c" << "d" ) |
1163 | << (QStringList() << "e" << "f" << "g" << "h" ) |
1164 | << (IntList() << 2 << 3 << 0 << 1) |
1165 | << (IntList() << 0 << 3 << 2 << 1); |
1166 | |
1167 | QTest::newRow(dataTag: "descending order" ) |
1168 | << 0 |
1169 | << Qt::DescendingOrder |
1170 | << (QStringList() << "c" << "d" << "a" << "b" ) |
1171 | << (QStringList() << "e" << "h" << "g" << "f" ) |
1172 | << (QStringList() << "d" << "c" << "b" << "a" ) |
1173 | << (QStringList() << "h" << "g" << "f" << "e" ) |
1174 | << (IntList() << 1 << 0 << 3 << 2) |
1175 | << (IntList() << 3 << 0 << 1 << 2); |
1176 | } |
1177 | |
1178 | void tst_QTreeWidget::sortItems() |
1179 | { |
1180 | QFETCH(int, column); |
1181 | QFETCH(Qt::SortOrder, order); |
1182 | QFETCH(QStringList, topLevelText); |
1183 | QFETCH(QStringList, childText); |
1184 | QFETCH(QStringList, topLevelResult); |
1185 | QFETCH(QStringList, childResult); |
1186 | QFETCH(IntList, expectedTopRows); |
1187 | QFETCH(IntList, expectedChildRows); |
1188 | testWidget->setSortingEnabled(false); |
1189 | |
1190 | for (const QString &tl : topLevelText) { |
1191 | QTreeWidgetItem *item = new QTreeWidgetItem(testWidget); |
1192 | item->setText(column, atext: tl); |
1193 | for (const QString &cl : childText) { |
1194 | QTreeWidgetItem *child = new QTreeWidgetItem(item); |
1195 | child->setText(column, atext: cl); |
1196 | } |
1197 | } |
1198 | |
1199 | QAbstractItemModel *model = testWidget->model(); |
1200 | PersistentModelIndexVec tops; |
1201 | for (int r = 0; r < model->rowCount(parent: QModelIndex()); ++r) |
1202 | tops.push_back(t: model->index(row: r, column: 0, parent: QModelIndex())); |
1203 | PersistentModelIndexVec children; |
1204 | for (int s = 0; s < model->rowCount(parent: tops.constFirst()); ++s) |
1205 | children.push_back(t: model->index(row: s, column: 0, parent: tops.constFirst())); |
1206 | |
1207 | testWidget->sortItems(column, order); |
1208 | QCOMPARE(testWidget->sortColumn(), column); |
1209 | |
1210 | for (int k = 0; k < topLevelResult.count(); ++k) { |
1211 | QTreeWidgetItem *item = testWidget->topLevelItem(index: k); |
1212 | QCOMPARE(item->text(column), topLevelResult.at(k)); |
1213 | for (int l = 0; l < childResult.count(); ++l) |
1214 | QCOMPARE(item->child(l)->text(column), childResult.at(l)); |
1215 | } |
1216 | |
1217 | for (int m = 0; m < tops.count(); ++m) |
1218 | QCOMPARE(tops.at(m).row(), expectedTopRows.at(m)); |
1219 | for (int n = 0; n < children.count(); ++n) |
1220 | QCOMPARE(children.at(n).row(), expectedChildRows.at(n)); |
1221 | } |
1222 | |
1223 | void tst_QTreeWidget::deleteItems_data() |
1224 | { |
1225 | QTest::addColumn<int>(name: "topLevelCount" ); |
1226 | QTest::addColumn<int>(name: "childCount" ); |
1227 | QTest::addColumn<int>(name: "grandChildCount" ); |
1228 | |
1229 | QTest::addColumn<int>(name: "deleteTopLevelCount" ); |
1230 | QTest::addColumn<int>(name: "deleteChildCount" ); |
1231 | QTest::addColumn<int>(name: "deleteGrandChildCount" ); |
1232 | |
1233 | QTest::addColumn<int>(name: "expectedTopLevelCount" ); |
1234 | QTest::addColumn<int>(name: "expectedChildCount" ); |
1235 | QTest::addColumn<int>(name: "expectedGrandChildCount" ); |
1236 | |
1237 | QTest::addColumn<int>(name: "persistentRow" ); |
1238 | QTest::addColumn<int>(name: "persistentColumn" ); |
1239 | QTest::addColumn<bool>(name: "persistentIsValid" ); |
1240 | |
1241 | QTest::newRow(dataTag: "start with 10, delete 1" ) |
1242 | << 10 << 10 << 10 |
1243 | << 1 << 1 << 1 |
1244 | << 9 << 9 << 9 |
1245 | << 0 << 0 << false; |
1246 | QTest::newRow(dataTag: "start with 10, delete 5" ) |
1247 | << 10 << 10 << 10 |
1248 | << 5 << 5 << 5 |
1249 | << 5 << 5 << 5 |
1250 | << 0 << 0 << false; |
1251 | QTest::newRow(dataTag: "mixed" ) |
1252 | << 10 << 13 << 7 |
1253 | << 3 << 7 << 4 |
1254 | << 7 << 6 << 3 |
1255 | << 0 << 0 << false; |
1256 | QTest::newRow(dataTag: "all" ) |
1257 | << 10 << 10 << 10 |
1258 | << 10 << 10 << 10 |
1259 | << 0 << 0 << 0 |
1260 | << 0 << 0 << false; |
1261 | } |
1262 | |
1263 | void tst_QTreeWidget::deleteItems() |
1264 | { |
1265 | QFETCH(int, topLevelCount); |
1266 | QFETCH(int, childCount); |
1267 | QFETCH(int, grandChildCount); |
1268 | |
1269 | QFETCH(int, deleteTopLevelCount); |
1270 | QFETCH(int, deleteChildCount); |
1271 | QFETCH(int, deleteGrandChildCount); |
1272 | |
1273 | QFETCH(int, expectedTopLevelCount); |
1274 | QFETCH(int, expectedChildCount); |
1275 | QFETCH(int, expectedGrandChildCount); |
1276 | |
1277 | QFETCH(int, persistentRow); |
1278 | QFETCH(int, persistentColumn); |
1279 | QFETCH(bool, persistentIsValid); |
1280 | |
1281 | for (int i = 0; i < topLevelCount; ++i) { |
1282 | QTreeWidgetItem *top = new QTreeWidgetItem(testWidget); |
1283 | for (int j = 0; j < childCount; ++j) { |
1284 | QTreeWidgetItem *child = new QTreeWidgetItem(top); |
1285 | for (int k = 0; k < grandChildCount; ++k) { |
1286 | new QTreeWidgetItem(child); |
1287 | } |
1288 | } |
1289 | } |
1290 | |
1291 | QPersistentModelIndex persistent = testWidget->model()->index(row: persistentRow, |
1292 | column: persistentColumn); |
1293 | QVERIFY(persistent.isValid()); |
1294 | |
1295 | QTreeWidgetItem *top = testWidget->topLevelItem(index: 0); |
1296 | QTreeWidgetItem *child = top->child(index: 0); |
1297 | |
1298 | for (int n = 0; n < deleteGrandChildCount; ++n) |
1299 | delete child->child(index: 0); |
1300 | QCOMPARE(child->childCount(), expectedGrandChildCount); |
1301 | |
1302 | for (int m = 0; m < deleteChildCount; ++m) |
1303 | delete top->child(index: 0); |
1304 | QCOMPARE(top->childCount(), expectedChildCount); |
1305 | |
1306 | for (int l = 0; l < deleteTopLevelCount; ++l) |
1307 | delete testWidget->topLevelItem(index: 0); |
1308 | QCOMPARE(testWidget->topLevelItemCount(), expectedTopLevelCount); |
1309 | |
1310 | QCOMPARE(persistent.isValid(), persistentIsValid); |
1311 | } |
1312 | |
1313 | |
1314 | void tst_QTreeWidget::itemAboveOrBelow() |
1315 | { |
1316 | QTreeWidget tw; |
1317 | tw.setColumnCount(1); |
1318 | QTreeWidgetItem *twi = new QTreeWidgetItem(&tw, QStringList() << "Test" ); |
1319 | QTreeWidgetItem *twi2 = new QTreeWidgetItem(&tw, QStringList() << "Test 2" ); |
1320 | QTreeWidgetItem *twi3 = new QTreeWidgetItem(&tw, QStringList() << "Test 3" ); |
1321 | tw.show(); |
1322 | QCOMPARE(tw.itemAbove(twi2), twi); |
1323 | QCOMPARE(tw.itemBelow(twi2), twi3); |
1324 | } |
1325 | |
1326 | void tst_QTreeWidget::itemStreaming_data() |
1327 | { |
1328 | QTest::addColumn<QString>(name: "text" ); |
1329 | QTest::addColumn<QString>(name: "toolTip" ); |
1330 | QTest::addColumn<int>(name: "column" ); |
1331 | |
1332 | QTest::newRow(dataTag: "Data" ) << "item text" << "tool tip text" << 0; |
1333 | } |
1334 | |
1335 | void tst_QTreeWidget::itemStreaming() |
1336 | { |
1337 | QFETCH(QString, text); |
1338 | QFETCH(QString, toolTip); |
1339 | QFETCH(int, column); |
1340 | |
1341 | QTreeWidgetItem item(testWidget); |
1342 | QCOMPARE(item.text(column), QString()); |
1343 | QCOMPARE(item.toolTip(column), QString()); |
1344 | |
1345 | item.setText(column, atext: text); |
1346 | item.setToolTip(column, atoolTip: toolTip); |
1347 | QCOMPARE(item.text(column), text); |
1348 | QCOMPARE(item.toolTip(column), toolTip); |
1349 | |
1350 | QByteArray buffer; |
1351 | QDataStream out(&buffer, QIODevice::WriteOnly); |
1352 | out << item; |
1353 | |
1354 | QTreeWidgetItem item2(testWidget); |
1355 | QCOMPARE(item2.text(column), QString()); |
1356 | QCOMPARE(item2.toolTip(column), QString()); |
1357 | |
1358 | QVERIFY(!buffer.isEmpty()); |
1359 | |
1360 | QDataStream in(&buffer, QIODevice::ReadOnly); |
1361 | in >> item2; |
1362 | QCOMPARE(item2.text(column), text); |
1363 | QCOMPARE(item2.toolTip(column), toolTip); |
1364 | } |
1365 | |
1366 | void tst_QTreeWidget::insertTopLevelItems_data() |
1367 | { |
1368 | QTest::addColumn<QStringList>(name: "initialText" ); |
1369 | QTest::addColumn<QStringList>(name: "insertText" ); |
1370 | QTest::addColumn<int>(name: "insertTopLevelIndex" ); |
1371 | QTest::addColumn<int>(name: "expectedTopLevelIndex" ); |
1372 | QTest::addColumn<int>(name: "insertChildIndex" ); |
1373 | QTest::addColumn<int>(name: "expectedChildIndex" ); |
1374 | |
1375 | const QStringList initial{ "foo" , "bar" }; |
1376 | const QStringList insert{ "baz" }; |
1377 | |
1378 | QTest::newRow(dataTag: "Insert at count" ) << initial << insert |
1379 | << initial.count() << initial.count() |
1380 | << initial.count() << initial.count(); |
1381 | QTest::newRow(dataTag: "Insert in the middle" ) << initial << insert |
1382 | << (initial.count() / 2) << (initial.count() / 2) |
1383 | << (initial.count() / 2) << (initial.count() / 2); |
1384 | QTest::newRow(dataTag: "Insert less than 0" ) << initial << insert |
1385 | << -1 << -1 |
1386 | << -1 << -1; |
1387 | QTest::newRow(dataTag: "Insert beyond count" ) << initial << insert |
1388 | << initial.count() + 1 << -1 |
1389 | << initial.count() + 1 << -1; |
1390 | } |
1391 | |
1392 | void tst_QTreeWidget::insertTopLevelItems() |
1393 | { |
1394 | QFETCH(QStringList, initialText); |
1395 | QFETCH(QStringList, insertText); |
1396 | QFETCH(int, insertTopLevelIndex); |
1397 | QFETCH(int, expectedTopLevelIndex); |
1398 | QFETCH(int, insertChildIndex); |
1399 | QFETCH(int, expectedChildIndex); |
1400 | testWidget->setSortingEnabled(false); |
1401 | |
1402 | { // insert the initial items |
1403 | QCOMPARE(testWidget->topLevelItemCount(), 0); |
1404 | for (int i = 0; i < initialText.count(); ++i) { |
1405 | QTreeWidgetItem *top = new QTreeWidgetItem(QStringList(initialText.at(i))); |
1406 | testWidget->addTopLevelItem(item: top); |
1407 | QCOMPARE(testWidget->indexOfTopLevelItem(top), i); |
1408 | } |
1409 | QCOMPARE(testWidget->topLevelItemCount(), initialText.count()); |
1410 | } |
1411 | |
1412 | { // test adding children |
1413 | QTreeWidgetItem *topLevel = testWidget->topLevelItem(index: 0); |
1414 | for (int i = 0; i < initialText.count(); ++i) |
1415 | topLevel->addChild(child: new QTreeWidgetItem(QStringList(initialText.at(i)))); |
1416 | QCOMPARE(topLevel->childCount(), initialText.count()); |
1417 | } |
1418 | |
1419 | { // test adding more top level items |
1420 | QTreeWidgetItem *topsy = new QTreeWidgetItem(QStringList(insertText.at(i: 0))); |
1421 | testWidget->insertTopLevelItem(index: insertTopLevelIndex, item: topsy); |
1422 | if (expectedTopLevelIndex == -1) { |
1423 | QCOMPARE(testWidget->topLevelItemCount(), initialText.count()); |
1424 | delete topsy; |
1425 | } else { |
1426 | QTreeWidgetItem *item = testWidget->topLevelItem(index: expectedTopLevelIndex); |
1427 | QVERIFY(item != nullptr); |
1428 | QCOMPARE(item->text(0), insertText.at(0)); |
1429 | QCOMPARE(testWidget->indexOfTopLevelItem(item), expectedTopLevelIndex); |
1430 | } |
1431 | } |
1432 | |
1433 | { // test adding more children |
1434 | QTreeWidgetItem *topLevel = testWidget->topLevelItem(index: 0); |
1435 | QVERIFY(topLevel != nullptr); |
1436 | QTreeWidgetItem *child = new QTreeWidgetItem(QStringList(insertText.at(i: 0))); |
1437 | topLevel->insertChild(index: insertChildIndex, child); |
1438 | if (expectedChildIndex == -1) { |
1439 | QCOMPARE(topLevel->childCount(), initialText.count()); |
1440 | delete child; |
1441 | } else { |
1442 | QTreeWidgetItem *item = topLevel->child(index: expectedChildIndex); |
1443 | QVERIFY(item != nullptr); |
1444 | QCOMPARE(item->text(0), insertText.at(0)); |
1445 | } |
1446 | } |
1447 | } |
1448 | |
1449 | static void fillTreeWidget(QTreeWidgetItem *parent, int rows) |
1450 | { |
1451 | const int columns = parent->treeWidget()->columnCount(); |
1452 | for (int r = 0; r < rows; ++r) { |
1453 | const QString prefix = QLatin1String("[r:" ) + QString::number(r) + QLatin1String(",c:" ); |
1454 | QTreeWidgetItem *w = new QTreeWidgetItem(parent); |
1455 | for (int c = 0; c < columns; ++c) |
1456 | w->setText(column: c, atext: prefix + QString::number(c) + QLatin1Char(']')); |
1457 | fillTreeWidget(parent: w, rows: rows - r - 1); |
1458 | } |
1459 | } |
1460 | |
1461 | static void fillTreeWidget(QTreeWidget *tree, int rows) |
1462 | { |
1463 | for (int r = 0; r < rows; ++r) { |
1464 | QTreeWidgetItem *w = new QTreeWidgetItem(); |
1465 | const QString prefix = QLatin1String("[r:" ) + QString::number(r) + QLatin1String(",c:" ); |
1466 | for (int c = 0; c < tree->columnCount(); ++c) |
1467 | w->setText(column: c, atext: prefix + QString::number(c) + QLatin1Char(']')); |
1468 | tree->insertTopLevelItem(index: r, item: w); |
1469 | fillTreeWidget(parent: w, rows: rows - r - 1); |
1470 | } |
1471 | } |
1472 | |
1473 | void tst_QTreeWidget::keyboardNavigation() |
1474 | { |
1475 | int rows = 8; |
1476 | |
1477 | fillTreeWidget(tree: testWidget, rows); |
1478 | |
1479 | const QVector<Qt::Key> keymoves { |
1480 | Qt::Key_Down, Qt::Key_Right, Qt::Key_Left, |
1481 | Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, |
1482 | Qt::Key_Right, |
1483 | Qt::Key_Up, Qt::Key_Left, Qt::Key_Left, |
1484 | Qt::Key_Up, Qt::Key_Down, Qt::Key_Up, Qt::Key_Up, |
1485 | Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, |
1486 | Qt::Key_Down, Qt::Key_Right, Qt::Key_Down, Qt::Key_Down, |
1487 | Qt::Key_Down, Qt::Key_Right, Qt::Key_Down, Qt::Key_Down, |
1488 | Qt::Key_Left, Qt::Key_Left, Qt::Key_Up, Qt::Key_Down, |
1489 | Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Left, |
1490 | Qt::Key_Down, Qt::Key_Right, Qt::Key_Right, Qt::Key_Right, |
1491 | Qt::Key_Left, Qt::Key_Left, Qt::Key_Right, Qt::Key_Left |
1492 | }; |
1493 | |
1494 | int row = 0; |
1495 | QTreeWidgetItem *item = testWidget->topLevelItem(index: 0); |
1496 | testWidget->setCurrentItem(item); |
1497 | QCOMPARE(testWidget->currentItem(), item); |
1498 | QCoreApplication::processEvents(); |
1499 | |
1500 | QScrollBar *scrollBar = testWidget->horizontalScrollBar(); |
1501 | for (const Qt::Key key : keymoves) { |
1502 | int valueBeforeClick = scrollBar->value(); |
1503 | const bool checkScroll = (valueBeforeClick >= scrollBar->singleStep()); |
1504 | QTest::keyClick(widget: testWidget, key); |
1505 | QCoreApplication::processEvents(); |
1506 | |
1507 | switch (key) { |
1508 | case Qt::Key_Up: |
1509 | if (row > 0) { |
1510 | if (item->parent()) |
1511 | item = item->parent()->child(index: row - 1); |
1512 | else |
1513 | item = testWidget->topLevelItem(index: row - 1); |
1514 | row -= 1; |
1515 | } else if (item->parent()) { |
1516 | item = item->parent(); |
1517 | row = item->parent() ? item->parent()->indexOfChild(achild: item) : testWidget->indexOfTopLevelItem(item); |
1518 | } |
1519 | break; |
1520 | case Qt::Key_Down: |
1521 | if (item->isExpanded()) { |
1522 | row = 0; |
1523 | item = item->child(index: row); |
1524 | } else { |
1525 | row = qMin(a: rows - 1, b: row + 1); |
1526 | if (item->parent()) |
1527 | item = item->parent()->child(index: row); |
1528 | else |
1529 | item = testWidget->topLevelItem(index: row); |
1530 | } |
1531 | break; |
1532 | case Qt::Key_Left: |
1533 | if (checkScroll) { |
1534 | QVERIFY(item->isExpanded()); |
1535 | QCOMPARE(scrollBar->value(), valueBeforeClick - scrollBar->singleStep()); |
1536 | } |
1537 | // windows style right will walk to the parent |
1538 | if (testWidget->currentItem() != item) { |
1539 | QCOMPARE(testWidget->currentItem(), item->parent()); |
1540 | item = testWidget->currentItem(); |
1541 | row = item->parent() ? item->parent()->indexOfChild(achild: item) : testWidget->indexOfTopLevelItem(item);; |
1542 | } |
1543 | break; |
1544 | case Qt::Key_Right: |
1545 | if (checkScroll) |
1546 | QCOMPARE(scrollBar->value(), valueBeforeClick + scrollBar->singleStep()); |
1547 | // windows style right will walk to the first child |
1548 | if (testWidget->currentItem() != item) { |
1549 | QCOMPARE(testWidget->currentItem()->parent(), item); |
1550 | row = item->indexOfChild(achild: testWidget->currentItem()); |
1551 | item = testWidget->currentItem(); |
1552 | QCOMPARE(row, 0); |
1553 | } |
1554 | break; |
1555 | default: |
1556 | QVERIFY(false); |
1557 | } |
1558 | |
1559 | QTreeWidgetItem *current = testWidget->currentItem(); |
1560 | QCOMPARE(current->text(0), QLatin1String("[r:" ) + QString::number(row) + QLatin1String(",c:0]" )); |
1561 | if (current->parent()) |
1562 | QCOMPARE(current->parent()->indexOfChild(current), row); |
1563 | else |
1564 | QCOMPARE(testWidget->indexOfTopLevelItem(current), row); |
1565 | } |
1566 | } |
1567 | |
1568 | void tst_QTreeWidget::keyboardNavigationWithHidden() |
1569 | { |
1570 | QTreeWidget tw; |
1571 | for (int i = 0; i < 1000; ++i) |
1572 | tw.addTopLevelItem(item: new QTreeWidgetItem({QString::number(i), QStringLiteral("second col" )})); |
1573 | // QTBUG-34832 - when first/last item is hidden, |
1574 | // Key_PageUp/Down/Home/End will not work as expected. |
1575 | tw.topLevelItem(index: 0)->setHidden(true); |
1576 | tw.topLevelItem(index: tw.model()->rowCount() - 1)->setHidden(true); |
1577 | // PageUp |
1578 | tw.setCurrentIndex(tw.model()->index(row: 2, column: 0)); |
1579 | QCOMPARE(tw.currentIndex(), tw.model()->index(2, 0)); |
1580 | QTest::keyClick(widget: tw.viewport(), key: Qt::Key_PageUp); |
1581 | QCOMPARE(tw.currentIndex(), tw.model()->index(1, 0)); |
1582 | // PageDown |
1583 | tw.setCurrentIndex(tw.model()->index(row: tw.model()->rowCount() - 3, column: 0)); |
1584 | QCOMPARE(tw.currentIndex(), tw.model()->index(tw.model()->rowCount() - 3, 0)); |
1585 | QTest::keyClick(widget: tw.viewport(), key: Qt::Key_PageDown); |
1586 | QCOMPARE(tw.currentIndex(), tw.model()->index(tw.model()->rowCount() - 2, 0)); |
1587 | // Key_Home |
1588 | QTest::keyClick(widget: tw.viewport(), key: Qt::Key_Home); |
1589 | QCOMPARE(tw.currentIndex(), tw.model()->index(1, 0)); |
1590 | // Key_End |
1591 | QTest::keyClick(widget: tw.viewport(), key: Qt::Key_End); |
1592 | QCOMPARE(tw.currentIndex(), tw.model()->index(tw.model()->rowCount() - 2, 0)); |
1593 | } |
1594 | |
1595 | void tst_QTreeWidget::scrollToItem() |
1596 | { |
1597 | // Check if all parent nodes of the item found are expanded. |
1598 | // Reported in task #78761 |
1599 | QTreeWidgetItem *search = nullptr; |
1600 | for (int i = 0; i < 2; ++i) { |
1601 | QTreeWidgetItem *bar = new QTreeWidgetItem(testWidget); |
1602 | bar->setText(column: 0, atext: QString::number(i)); |
1603 | |
1604 | for (int j = 0; j < 2; ++j) { |
1605 | QTreeWidgetItem *foo = new QTreeWidgetItem(bar); |
1606 | foo->setText(column: 0, atext: bar->text(column: 0) + QString::number(j)); |
1607 | |
1608 | for (int k = 0; k < 2; ++k) { |
1609 | search = new QTreeWidgetItem(foo); |
1610 | search->setText(column: 0, atext: foo->text(column: 0) + QString::number(k)); |
1611 | } |
1612 | } |
1613 | } |
1614 | |
1615 | testWidget->setHeaderLabels(QStringList() << "foo" ); |
1616 | testWidget->scrollToItem(item: search); |
1617 | QCOMPARE(search->text(0), QLatin1String("111" )); |
1618 | |
1619 | QTreeWidgetItem *par = search->parent(); |
1620 | QVERIFY(par->isExpanded()); |
1621 | par = par->parent(); |
1622 | QVERIFY(par->isExpanded()); |
1623 | } |
1624 | |
1625 | // From task #85413 |
1626 | void tst_QTreeWidget::setSortingEnabled() |
1627 | { |
1628 | const QStringList hl{ "ID" }; |
1629 | testWidget->setColumnCount(hl.count()); |
1630 | testWidget->setHeaderLabels(hl); |
1631 | |
1632 | QTreeWidgetItem *item1 = new QTreeWidgetItem(testWidget); |
1633 | QTreeWidgetItem *item2 = new QTreeWidgetItem(testWidget); |
1634 | |
1635 | testWidget->setSortingEnabled(true); |
1636 | QCOMPARE(testWidget->isSortingEnabled(), true); |
1637 | QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown()); |
1638 | QCOMPARE(testWidget->topLevelItem(0), item1); |
1639 | QCOMPARE(testWidget->topLevelItem(1), item2); |
1640 | |
1641 | // Make sure we do it twice |
1642 | testWidget->setSortingEnabled(true); |
1643 | QCOMPARE(testWidget->isSortingEnabled(), true); |
1644 | QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown()); |
1645 | |
1646 | testWidget->setSortingEnabled(false); |
1647 | QCOMPARE(testWidget->isSortingEnabled(), false); |
1648 | QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown()); |
1649 | |
1650 | testWidget->setSortingEnabled(false); |
1651 | QCOMPARE(testWidget->isSortingEnabled(), false); |
1652 | QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown()); |
1653 | |
1654 | // And back again so that we make sure that we test the transition from false to true |
1655 | testWidget->setSortingEnabled(true); |
1656 | QCOMPARE(testWidget->isSortingEnabled(), true); |
1657 | QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown()); |
1658 | |
1659 | testWidget->setSortingEnabled(true); |
1660 | QCOMPARE(testWidget->isSortingEnabled(), true); |
1661 | QCOMPARE(testWidget->isSortingEnabled(), testWidget->header()->isSortIndicatorShown()); |
1662 | |
1663 | testWidget->setSortingEnabled(false); |
1664 | } |
1665 | |
1666 | void tst_QTreeWidget::addChild() |
1667 | { |
1668 | QTreeWidget tree; |
1669 | for (int x = 0; x < 2; ++x) { |
1670 | QTreeWidget *view = x ? &tree : static_cast<QTreeWidget*>(nullptr); |
1671 | QTreeWidgetItem *item = new QTreeWidgetItem(view); |
1672 | QCOMPARE(item->childCount(), 0); |
1673 | |
1674 | // try to add 0 |
1675 | item->addChild(child: nullptr); |
1676 | QCOMPARE(item->childCount(), 0); |
1677 | QCOMPARE(item->indexOfChild(nullptr), -1); |
1678 | |
1679 | // add one at a time |
1680 | QList<QTreeWidgetItem*> children; |
1681 | for (int i = 0; i < 10; ++i) { |
1682 | QTreeWidgetItem *child = new QTreeWidgetItem(); |
1683 | item->addChild(child); |
1684 | QCOMPARE(item->childCount(), i+1); |
1685 | QCOMPARE(item->child(i), child); |
1686 | QCOMPARE(item->indexOfChild(child), i); |
1687 | QCOMPARE(child->parent(), item); |
1688 | QCOMPARE(child->treeWidget(), view); |
1689 | item->addChild(child); |
1690 | QCOMPARE(item->childCount(), i+1); |
1691 | children.append(t: child); |
1692 | } |
1693 | |
1694 | // take them all |
1695 | QList<QTreeWidgetItem*> taken = item->takeChildren(); |
1696 | QCOMPARE(taken, children); |
1697 | QCOMPARE(item->childCount(), 0); |
1698 | for (int i = 0; i < taken.count(); ++i) { |
1699 | QCOMPARE(taken.at(i)->parent(), nullptr); |
1700 | QCOMPARE(taken.at(i)->treeWidget(), nullptr); |
1701 | item->addChild(child: taken.at(i)); // re-add |
1702 | } |
1703 | |
1704 | // delete one at a time |
1705 | while (!children.isEmpty()) { |
1706 | QTreeWidgetItem *ti = children.takeFirst(); |
1707 | delete ti; |
1708 | QCOMPARE(item->childCount(), children.count()); |
1709 | for (int i = 0; i < children.count(); ++i) |
1710 | QCOMPARE(item->child(i), children.at(i)); |
1711 | } |
1712 | |
1713 | // add none |
1714 | { |
1715 | int count = item->childCount(); |
1716 | item->addChildren(children: QList<QTreeWidgetItem*>()); |
1717 | QCOMPARE(item->childCount(), count); |
1718 | } |
1719 | |
1720 | // add many at a time |
1721 | const int count = 10; |
1722 | for (int i = 0; i < 100; i += count) { |
1723 | QList<QTreeWidgetItem*> list; |
1724 | for (int j = 0; j < count; ++j) |
1725 | list << new QTreeWidgetItem(QStringList(QString::number(j))); |
1726 | item->addChildren(children: list); |
1727 | QCOMPARE(item->childCount(), count + i); |
1728 | for (int j = 0; j < count; ++j) { |
1729 | QCOMPARE(item->child(i+j), list.at(j)); |
1730 | QCOMPARE(item->child(i+j)->parent(), item); |
1731 | } |
1732 | |
1733 | item->addChildren(children: list); |
1734 | QCOMPARE(item->childCount(), count + i); |
1735 | } |
1736 | |
1737 | if (!view) |
1738 | delete item; |
1739 | } |
1740 | } |
1741 | |
1742 | void tst_QTreeWidget::setData() |
1743 | { |
1744 | { |
1745 | QTreeWidgetItem * = new QTreeWidgetItem(); |
1746 | headerItem->setText(column: 0, atext: "Item1" ); |
1747 | testWidget->setHeaderItem(headerItem); |
1748 | |
1749 | QSignalSpy ( |
1750 | testWidget->model(), &QAbstractItemModel::headerDataChanged); |
1751 | QSignalSpy dataChangedSpy( |
1752 | testWidget->model(), &QAbstractItemModel::dataChanged); |
1753 | QSignalSpy itemChangedSpy( |
1754 | testWidget, &QTreeWidget::itemChanged); |
1755 | headerItem->setText(column: 0, atext: "test" ); |
1756 | QCOMPARE(dataChangedSpy.count(), 0); |
1757 | QCOMPARE(headerDataChangedSpy.count(), 1); |
1758 | QCOMPARE(itemChangedSpy.count(), 0); // no itemChanged() signal for header item |
1759 | |
1760 | headerItem->setData(column: -1, role: -1, value: QVariant()); |
1761 | } |
1762 | |
1763 | { |
1764 | QSignalSpy itemChangedSpy( |
1765 | testWidget, &QTreeWidget::itemChanged); |
1766 | QTreeWidgetItem *item = new QTreeWidgetItem(); |
1767 | testWidget->addTopLevelItem(item); |
1768 | for (int x = 0; x < 2; ++x) { |
1769 | for (int i = 1; i <= 2; ++i) { |
1770 | for (int j = 0; j < 5; ++j) { |
1771 | QVariantList args; |
1772 | const QString iS = QString::number(i); |
1773 | const QString text = QLatin1String("text " ) + iS; |
1774 | item->setText(column: j, atext: text); |
1775 | QCOMPARE(item->text(j), text); |
1776 | QCOMPARE(itemChangedSpy.count(), 1); |
1777 | args = itemChangedSpy.takeFirst(); |
1778 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1779 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1780 | item->setText(column: j, atext: text); |
1781 | QCOMPARE(itemChangedSpy.count(), 0); |
1782 | |
1783 | QPixmap pixmap(32, 32); |
1784 | pixmap.fill(fillColor: (i == 1) ? Qt::red : Qt::green); |
1785 | QIcon icon(pixmap); |
1786 | item->setIcon(column: j, aicon: icon); |
1787 | QCOMPARE(item->icon(j), icon); |
1788 | QCOMPARE(itemChangedSpy.count(), 1); |
1789 | args = itemChangedSpy.takeFirst(); |
1790 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1791 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1792 | item->setIcon(column: j, aicon: icon); |
1793 | QCOMPARE(itemChangedSpy.count(), 0); |
1794 | |
1795 | const QString toolTip = QLatin1String("toolTip " ) + iS; |
1796 | item->setToolTip(column: j, atoolTip: toolTip); |
1797 | QCOMPARE(item->toolTip(j), toolTip); |
1798 | QCOMPARE(itemChangedSpy.count(), 1); |
1799 | args = itemChangedSpy.takeFirst(); |
1800 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1801 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1802 | item->setToolTip(column: j, atoolTip: toolTip); |
1803 | QCOMPARE(itemChangedSpy.count(), 0); |
1804 | |
1805 | const QString statusTip = QLatin1String("statusTip " ) + iS; |
1806 | item->setStatusTip(column: j, astatusTip: statusTip); |
1807 | QCOMPARE(item->statusTip(j), statusTip); |
1808 | QCOMPARE(itemChangedSpy.count(), 1); |
1809 | args = itemChangedSpy.takeFirst(); |
1810 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1811 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1812 | item->setStatusTip(column: j, astatusTip: statusTip); |
1813 | QCOMPARE(itemChangedSpy.count(), 0); |
1814 | |
1815 | const QString whatsThis = QLatin1String("whatsThis " ) + iS; |
1816 | item->setWhatsThis(column: j, awhatsThis: whatsThis); |
1817 | QCOMPARE(item->whatsThis(j), whatsThis); |
1818 | QCOMPARE(itemChangedSpy.count(), 1); |
1819 | args = itemChangedSpy.takeFirst(); |
1820 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1821 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1822 | item->setWhatsThis(column: j, awhatsThis: whatsThis); |
1823 | QCOMPARE(itemChangedSpy.count(), 0); |
1824 | |
1825 | QSize sizeHint(64*i, 48*i); |
1826 | item->setSizeHint(column: j, size: sizeHint); |
1827 | QCOMPARE(item->sizeHint(j), sizeHint); |
1828 | QCOMPARE(itemChangedSpy.count(), 1); |
1829 | args = itemChangedSpy.takeFirst(); |
1830 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1831 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1832 | item->setSizeHint(column: j, size: sizeHint); |
1833 | QCOMPARE(itemChangedSpy.count(), 0); |
1834 | |
1835 | QFont font; |
1836 | item->setFont(column: j, afont: font); |
1837 | QCOMPARE(item->font(j), font); |
1838 | QCOMPARE(itemChangedSpy.count(), 1); |
1839 | args = itemChangedSpy.takeFirst(); |
1840 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1841 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1842 | item->setFont(column: j, afont: font); |
1843 | QCOMPARE(itemChangedSpy.count(), 0); |
1844 | |
1845 | Qt::Alignment textAlignment((i == 1) |
1846 | ? Qt::AlignLeft|Qt::AlignVCenter |
1847 | : Qt::AlignRight); |
1848 | item->setTextAlignment(column: j, alignment: textAlignment); |
1849 | QCOMPARE(item->textAlignment(j), int(textAlignment)); |
1850 | QCOMPARE(itemChangedSpy.count(), 1); |
1851 | args = itemChangedSpy.takeFirst(); |
1852 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1853 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1854 | item->setTextAlignment(column: j, alignment: textAlignment); |
1855 | QCOMPARE(itemChangedSpy.count(), 0); |
1856 | |
1857 | QColor backgroundColor((i == 1) ? Qt::blue : Qt::yellow); |
1858 | item->setBackground(column: j, brush: backgroundColor); |
1859 | QCOMPARE(item->background(j).color(), backgroundColor); |
1860 | QCOMPARE(itemChangedSpy.count(), 1); |
1861 | args = itemChangedSpy.takeFirst(); |
1862 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1863 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1864 | item->setBackground(column: j, brush: backgroundColor); |
1865 | QCOMPARE(itemChangedSpy.count(), 0); |
1866 | |
1867 | const QColor foregroundColor((i == 1) ? Qt::green : Qt::cyan); |
1868 | item->setForeground(column: j, brush: foregroundColor); |
1869 | QCOMPARE(item->foreground(j), foregroundColor); |
1870 | QCOMPARE(itemChangedSpy.count(), 1); |
1871 | args = itemChangedSpy.takeFirst(); |
1872 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1873 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1874 | item->setForeground(column: j, brush: foregroundColor); |
1875 | QCOMPARE(itemChangedSpy.count(), 0); |
1876 | |
1877 | Qt::CheckState checkState((i == 1) ? Qt::PartiallyChecked : Qt::Checked); |
1878 | item->setCheckState(column: j, state: checkState); |
1879 | QCOMPARE(item->checkState(j), checkState); |
1880 | QCOMPARE(itemChangedSpy.count(), 1); |
1881 | args = itemChangedSpy.takeFirst(); |
1882 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1883 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1884 | item->setCheckState(column: j, state: checkState); |
1885 | QCOMPARE(itemChangedSpy.count(), 0); |
1886 | |
1887 | QCOMPARE(item->text(j), text); |
1888 | QCOMPARE(item->icon(j), icon); |
1889 | QCOMPARE(item->toolTip(j), toolTip); |
1890 | QCOMPARE(item->statusTip(j), statusTip); |
1891 | QCOMPARE(item->whatsThis(j), whatsThis); |
1892 | QCOMPARE(item->sizeHint(j), sizeHint); |
1893 | QCOMPARE(item->font(j), font); |
1894 | QCOMPARE(item->textAlignment(j), int(textAlignment)); |
1895 | QCOMPARE(item->background(j).color(), backgroundColor); |
1896 | QCOMPARE(item->foreground(j), foregroundColor); |
1897 | QCOMPARE(item->checkState(j), checkState); |
1898 | |
1899 | QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::DisplayRole)), text); |
1900 | QCOMPARE(qvariant_cast<QIcon>(item->data(j, Qt::DecorationRole)), icon); |
1901 | QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::ToolTipRole)), toolTip); |
1902 | QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::StatusTipRole)), statusTip); |
1903 | QCOMPARE(qvariant_cast<QString>(item->data(j, Qt::WhatsThisRole)), whatsThis); |
1904 | QCOMPARE(qvariant_cast<QSize>(item->data(j, Qt::SizeHintRole)), sizeHint); |
1905 | QCOMPARE(qvariant_cast<QFont>(item->data(j, Qt::FontRole)), font); |
1906 | QCOMPARE(qvariant_cast<int>(item->data(j, Qt::TextAlignmentRole)), int(textAlignment)); |
1907 | QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundRole)), QBrush(backgroundColor)); |
1908 | QCOMPARE(qvariant_cast<QColor>(item->data(j, Qt::ForegroundRole)), foregroundColor); |
1909 | QCOMPARE(qvariant_cast<int>(item->data(j, Qt::CheckStateRole)), int(checkState)); |
1910 | |
1911 | item->setBackground(column: j, brush: pixmap); |
1912 | QCOMPARE(item->background(j).texture(), pixmap); |
1913 | QCOMPARE(qvariant_cast<QBrush>(item->data(j, Qt::BackgroundRole)).texture(), pixmap); |
1914 | args = itemChangedSpy.takeFirst(); |
1915 | QCOMPARE(qvariant_cast<QTreeWidgetItem*>(args.at(0)), item); |
1916 | QCOMPARE(qvariant_cast<int>(args.at(1)), j); |
1917 | item->setBackground(column: j, brush: pixmap); |
1918 | QCOMPARE(itemChangedSpy.count(), 0); |
1919 | |
1920 | item->setData(column: j, role: Qt::DisplayRole, value: QVariant()); |
1921 | item->setData(column: j, role: Qt::DecorationRole, value: QVariant()); |
1922 | item->setData(column: j, role: Qt::ToolTipRole, value: QVariant()); |
1923 | item->setData(column: j, role: Qt::StatusTipRole, value: QVariant()); |
1924 | item->setData(column: j, role: Qt::WhatsThisRole, value: QVariant()); |
1925 | item->setData(column: j, role: Qt::SizeHintRole, value: QVariant()); |
1926 | item->setData(column: j, role: Qt::FontRole, value: QVariant()); |
1927 | item->setData(column: j, role: Qt::TextAlignmentRole, value: QVariant()); |
1928 | item->setData(column: j, role: Qt::BackgroundRole, value: QVariant()); |
1929 | item->setData(column: j, role: Qt::ForegroundRole, value: QVariant()); |
1930 | item->setData(column: j, role: Qt::CheckStateRole, value: QVariant()); |
1931 | QCOMPARE(itemChangedSpy.count(), 11); |
1932 | itemChangedSpy.clear(); |
1933 | |
1934 | QCOMPARE(item->data(j, Qt::DisplayRole).toString(), QString()); |
1935 | QCOMPARE(item->data(j, Qt::DecorationRole), QVariant()); |
1936 | QCOMPARE(item->data(j, Qt::ToolTipRole), QVariant()); |
1937 | QCOMPARE(item->data(j, Qt::StatusTipRole), QVariant()); |
1938 | QCOMPARE(item->data(j, Qt::WhatsThisRole), QVariant()); |
1939 | QCOMPARE(item->data(j, Qt::SizeHintRole), QVariant()); |
1940 | QCOMPARE(item->data(j, Qt::FontRole), QVariant()); |
1941 | QCOMPARE(item->data(j, Qt::TextAlignmentRole), QVariant()); |
1942 | QCOMPARE(item->data(j, Qt::BackgroundRole), QVariant()); |
1943 | QCOMPARE(item->data(j, Qt::ForegroundRole), QVariant()); |
1944 | QCOMPARE(item->data(j, Qt::CheckStateRole), QVariant()); |
1945 | } |
1946 | } |
1947 | } |
1948 | |
1949 | // ### add more data types here |
1950 | |
1951 | item->setData(column: 0, role: Qt::DisplayRole, value: 5); |
1952 | QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::Int); |
1953 | |
1954 | item->setData(column: 0, role: Qt::DisplayRole, value: "test" ); |
1955 | QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::String); |
1956 | |
1957 | item->setData(column: 0, role: Qt::DisplayRole, value: 0.4); |
1958 | QCOMPARE(item->data(0, Qt::DisplayRole).type(), QVariant::Double); |
1959 | |
1960 | delete item; |
1961 | } |
1962 | } |
1963 | |
1964 | class QTreeWidgetDataChanged : public QTreeWidget |
1965 | { |
1966 | Q_OBJECT |
1967 | public: |
1968 | using QTreeWidget::QTreeWidget; |
1969 | |
1970 | void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) override |
1971 | { |
1972 | QTreeWidget::dataChanged(topLeft, bottomRight, roles); |
1973 | currentRoles = roles; |
1974 | } |
1975 | QVector<int> currentRoles; |
1976 | }; |
1977 | |
1978 | void tst_QTreeWidget::itemData() |
1979 | { |
1980 | QTreeWidgetDataChanged widget; |
1981 | QTreeWidgetItem item(&widget); |
1982 | widget.setColumnCount(2); |
1983 | item.setFlags(item.flags() | Qt::ItemIsEditable); |
1984 | item.setData(column: 0, role: Qt::DisplayRole, value: QString("0" )); |
1985 | QCOMPARE(widget.currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); |
1986 | item.setData(column: 0, role: Qt::CheckStateRole, value: Qt::PartiallyChecked); |
1987 | QCOMPARE(widget.currentRoles, QVector<int>{Qt::CheckStateRole}); |
1988 | for (int i = 0; i < 4; ++i) { |
1989 | item.setData(column: 0, role: Qt::UserRole + i, value: QString::number(i + 1)); |
1990 | QCOMPARE(widget.currentRoles, QVector<int>{Qt::UserRole + i}); |
1991 | } |
1992 | QMap<int, QVariant> flags = widget.model()->itemData(index: widget.model()->index(row: 0, column: 0)); |
1993 | QCOMPARE(flags.count(), 6); |
1994 | for (int i = 0; i < 4; ++i) |
1995 | QCOMPARE(flags[Qt::UserRole + i].toString(), QString::number(i + 1)); |
1996 | flags = widget.model()->itemData(index: widget.model()->index(row: 0, column: 1)); |
1997 | QCOMPARE(flags.count(), 0); |
1998 | |
1999 | item.setBackground(column: 0, brush: QBrush(Qt::red)); |
2000 | item.setForeground(column: 0, brush: QBrush(Qt::green)); |
2001 | item.setSizeHint(column: 0, size: QSize(10, 10)); |
2002 | QCOMPARE(item.data(0, Qt::BackgroundRole), QVariant(QBrush(Qt::red))); |
2003 | QCOMPARE(item.data(0, Qt::ForegroundRole), QVariant(QBrush(Qt::green))); |
2004 | QCOMPARE(item.data(0, Qt::SizeHintRole), QVariant(QSize(10, 10))); |
2005 | // an empty brush should result in a QVariant() |
2006 | item.setBackground(column: 0, brush: QBrush()); |
2007 | item.setForeground(column: 0, brush: QBrush()); |
2008 | item.setSizeHint(column: 0, size: QSize()); |
2009 | QCOMPARE(item.data(0, Qt::BackgroundRole), QVariant()); |
2010 | QCOMPARE(item.data(0, Qt::ForegroundRole), QVariant()); |
2011 | QCOMPARE(item.data(0, Qt::SizeHintRole), QVariant()); |
2012 | } |
2013 | |
2014 | void tst_QTreeWidget::enableDisable() |
2015 | { |
2016 | const QScopedPointer<QTreeWidgetItem> itm(new QTreeWidgetItem); |
2017 | for (int i = 0; i < 10; ++i) |
2018 | new QTreeWidgetItem(itm.data()); |
2019 | |
2020 | // make sure all items are enabled |
2021 | QVERIFY(itm->flags() & Qt::ItemIsEnabled); |
2022 | for (int j = 0; j < itm->childCount(); ++j) |
2023 | QVERIFY(itm->child(j)->flags() & Qt::ItemIsEnabled); |
2024 | |
2025 | // disable root and make sure they are all disabled |
2026 | itm->setFlags(itm->flags() & ~Qt::ItemIsEnabled); |
2027 | QVERIFY(!(itm->flags() & Qt::ItemIsEnabled)); |
2028 | for (int k = 0; k < itm->childCount(); ++k) |
2029 | QVERIFY(!(itm->child(k)->flags() & Qt::ItemIsEnabled)); |
2030 | |
2031 | // disable a child and make sure they are all still disabled |
2032 | itm->child(index: 5)->setFlags(itm->child(index: 5)->flags() & ~Qt::ItemIsEnabled); |
2033 | QVERIFY(!(itm->flags() & Qt::ItemIsEnabled)); |
2034 | for (int l = 0; l < itm->childCount(); ++l) |
2035 | QVERIFY(!(itm->child(l)->flags() & Qt::ItemIsEnabled)); |
2036 | |
2037 | // enable root and make sure all items except one are enabled |
2038 | itm->setFlags(itm->flags() | Qt::ItemIsEnabled); |
2039 | QVERIFY(itm->flags() & Qt::ItemIsEnabled); |
2040 | for (int m = 0; m < itm->childCount(); ++m) |
2041 | if (m == 5) |
2042 | QVERIFY(!(itm->child(m)->flags() & Qt::ItemIsEnabled)); |
2043 | else |
2044 | QVERIFY(itm->child(m)->flags() & Qt::ItemIsEnabled); |
2045 | } |
2046 | |
2047 | void tst_QTreeWidget::match() |
2048 | { |
2049 | QTreeWidget tree; |
2050 | QModelIndexList list = tree.model()->match(start: QModelIndex(), role: Qt::DisplayRole, value: QString()); |
2051 | |
2052 | QVERIFY(list.isEmpty()); |
2053 | } |
2054 | |
2055 | void tst_QTreeWidget::columnCount() |
2056 | { |
2057 | int columnCountBefore = testWidget->columnCount(); |
2058 | testWidget->setColumnCount(-1); |
2059 | QCOMPARE(testWidget->columnCount(), columnCountBefore); |
2060 | } |
2061 | |
2062 | void tst_QTreeWidget::() |
2063 | { |
2064 | 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(sep: QLatin1Char(',')); |
2065 | testWidget->setHeaderLabels(list); |
2066 | QCOMPARE(testWidget->header()->count(), list.count()); |
2067 | } |
2068 | |
2069 | void tst_QTreeWidget::() |
2070 | { |
2071 | testWidget->setHeaderItem(nullptr); |
2072 | QTreeWidgetItem * = new QTreeWidgetItem(); |
2073 | |
2074 | testWidget->setColumnCount(0); |
2075 | QCOMPARE(testWidget->header()->count(), 0); |
2076 | QCOMPARE(testWidget->columnCount(), 0); |
2077 | |
2078 | headerItem->setText(column: 0, atext: "0" ); |
2079 | headerItem->setText(column: 1, atext: "1" ); |
2080 | testWidget->setHeaderItem(headerItem); |
2081 | QCOMPARE(testWidget->headerItem(), headerItem); |
2082 | QCOMPARE(headerItem->treeWidget(), static_cast<QTreeWidget *>(testWidget)); |
2083 | |
2084 | QCOMPARE(testWidget->header()->count(), 2); |
2085 | QCOMPARE(testWidget->columnCount(), 2); |
2086 | |
2087 | headerItem->setText(column: 2, atext: "2" ); |
2088 | QCOMPARE(testWidget->header()->count(), 3); |
2089 | QCOMPARE(testWidget->columnCount(), 3); |
2090 | |
2091 | delete headerItem; |
2092 | testWidget->setColumnCount(3); |
2093 | testWidget->setColumnCount(5); |
2094 | QCOMPARE(testWidget->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), QString("1" )); |
2095 | QCOMPARE(testWidget->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), QString("2" )); |
2096 | QCOMPARE(testWidget->model()->headerData(2, Qt::Horizontal, Qt::DisplayRole).toString(), QString("3" )); |
2097 | QCOMPARE(testWidget->model()->headerData(3, Qt::Horizontal, Qt::DisplayRole).toString(), QString("4" )); |
2098 | QCOMPARE(testWidget->model()->headerData(4, Qt::Horizontal, Qt::DisplayRole).toString(), QString("5" )); |
2099 | |
2100 | headerItem = new QTreeWidgetItem(); |
2101 | testWidget->setHeaderItem(headerItem); |
2102 | testWidget->model()->insertColumns(column: 0, count: 5, parent: QModelIndex()); |
2103 | QCOMPARE(testWidget->model()->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), QString("1" )); |
2104 | QCOMPARE(testWidget->model()->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), QString("2" )); |
2105 | QCOMPARE(testWidget->model()->headerData(2, Qt::Horizontal, Qt::DisplayRole).toString(), QString("3" )); |
2106 | QCOMPARE(testWidget->model()->headerData(3, Qt::Horizontal, Qt::DisplayRole).toString(), QString("4" )); |
2107 | QCOMPARE(testWidget->model()->headerData(4, Qt::Horizontal, Qt::DisplayRole).toString(), QString("5" )); |
2108 | } |
2109 | |
2110 | void tst_QTreeWidget::itemWidget_data() |
2111 | { |
2112 | editItem_data(); |
2113 | } |
2114 | |
2115 | void tst_QTreeWidget::itemWidget() |
2116 | { |
2117 | QFETCH(TreeItemList, topLevelItems); |
2118 | |
2119 | QTreeWidget tree; |
2120 | populate(widget: &tree, topLevelItems, headerItem: new TreeItem({"1" , "2" })); |
2121 | tree.show(); |
2122 | |
2123 | for (int x = 0; x < 2; ++x) { |
2124 | QTreeWidgetItemIterator it(&tree); |
2125 | while (QTreeWidgetItem *item = (*it++)) { |
2126 | for (int col = 0; col < item->columnCount(); ++col) { |
2127 | if (x == 0) { |
2128 | QCOMPARE(tree.itemWidget(item, col), nullptr); |
2129 | QWidget *editor = new QLineEdit(); |
2130 | tree.setItemWidget(item, column: col, widget: editor); |
2131 | QCOMPARE(tree.itemWidget(item, col), editor); |
2132 | tree.removeItemWidget(item, column: col); |
2133 | QCOMPARE(tree.itemWidget(item, col), nullptr); |
2134 | } else { |
2135 | // ### should you really be able to open a persistent |
2136 | // editor for an item that isn't editable?? |
2137 | tree.openPersistentEditor(item, column: col); |
2138 | QWidget *editor = tree.findChild<QLineEdit*>(); |
2139 | QVERIFY(editor != nullptr); |
2140 | tree.closePersistentEditor(item, column: col); |
2141 | } |
2142 | } |
2143 | } |
2144 | } |
2145 | } |
2146 | |
2147 | void tst_QTreeWidget::insertItemsWithSorting_data() |
2148 | { |
2149 | QTest::addColumn<Qt::SortOrder>(name: "sortOrder" ); |
2150 | QTest::addColumn<QStringList>(name: "initialItems" ); |
2151 | QTest::addColumn<QStringList>(name: "insertItems" ); |
2152 | QTest::addColumn<QStringList>(name: "expectedItems" ); |
2153 | QTest::addColumn<IntList>(name: "expectedRows" ); |
2154 | |
2155 | QTest::newRow(dataTag: "() + (a) = (a)" ) |
2156 | << Qt::AscendingOrder |
2157 | << QStringList() |
2158 | << (QStringList() << "a" ) |
2159 | << (QStringList() << "a" ) |
2160 | << IntList(); |
2161 | QTest::newRow(dataTag: "() + (c, b, a) = (a, b, c)" ) |
2162 | << Qt::AscendingOrder |
2163 | << QStringList() |
2164 | << (QStringList() << "c" << "b" << "a" ) |
2165 | << (QStringList() << "a" << "b" << "c" ) |
2166 | << IntList(); |
2167 | QTest::newRow(dataTag: "() + (a, b, c) = (c, b, a)" ) |
2168 | << Qt::DescendingOrder |
2169 | << QStringList() |
2170 | << (QStringList() << "a" << "b" << "c" ) |
2171 | << (QStringList() << "c" << "b" << "a" ) |
2172 | << IntList(); |
2173 | QTest::newRow(dataTag: "(a) + (b) = (a, b)" ) |
2174 | << Qt::AscendingOrder |
2175 | << QStringList("a" ) |
2176 | << (QStringList() << "b" ) |
2177 | << (QStringList() << "a" << "b" ) |
2178 | << (IntList() << 0); |
2179 | QTest::newRow(dataTag: "(a) + (b) = (b, a)" ) |
2180 | << Qt::DescendingOrder |
2181 | << QStringList("a" ) |
2182 | << (QStringList() << "b" ) |
2183 | << (QStringList() << "b" << "a" ) |
2184 | << (IntList() << 1); |
2185 | QTest::newRow(dataTag: "(a, c, b) + (d) = (a, b, c, d)" ) |
2186 | << Qt::AscendingOrder |
2187 | << (QStringList() << "a" << "c" << "b" ) |
2188 | << (QStringList() << "d" ) |
2189 | << (QStringList() << "a" << "b" << "c" << "d" ) |
2190 | << (IntList() << 0 << 1 << 2); |
2191 | QTest::newRow(dataTag: "(b, c, a) + (d) = (d, c, b, a)" ) |
2192 | << Qt::DescendingOrder |
2193 | << (QStringList() << "b" << "c" << "a" ) |
2194 | << (QStringList() << "d" ) |
2195 | << (QStringList() << "d" << "c" << "b" << "a" ) |
2196 | << (IntList() << 1 << 2 << 3); |
2197 | { |
2198 | IntList ascendingRows; |
2199 | IntList reverseRows; |
2200 | QStringList ascendingItems; |
2201 | QStringList reverseItems; |
2202 | for (char i = 'a'; i <= 'z'; ++i) { |
2203 | ascendingItems << QString(1, QLatin1Char(i)); |
2204 | reverseItems << QString(1, QLatin1Char('z' - i + 'a')); |
2205 | ascendingRows << i - 'a'; |
2206 | reverseRows << 'z' - i + 'a'; |
2207 | } |
2208 | QTest::newRow(dataTag: "() + (sorted items) = (sorted items)" ) |
2209 | << Qt::AscendingOrder |
2210 | << QStringList() |
2211 | << ascendingItems |
2212 | << ascendingItems |
2213 | << IntList(); |
2214 | QTest::newRow(dataTag: "(sorted items) + () = (sorted items)" ) |
2215 | << Qt::AscendingOrder |
2216 | << ascendingItems |
2217 | << QStringList() |
2218 | << ascendingItems |
2219 | << ascendingRows; |
2220 | QTest::newRow(dataTag: "() + (ascending items) = (reverse items)" ) |
2221 | << Qt::DescendingOrder |
2222 | << QStringList() |
2223 | << ascendingItems |
2224 | << reverseItems |
2225 | << IntList(); |
2226 | QTest::newRow(dataTag: "(reverse items) + () = (ascending items)" ) |
2227 | << Qt::AscendingOrder |
2228 | << reverseItems |
2229 | << QStringList() |
2230 | << ascendingItems |
2231 | << ascendingRows; |
2232 | QTest::newRow(dataTag: "(reverse items) + () = (reverse items)" ) |
2233 | << Qt::DescendingOrder |
2234 | << reverseItems |
2235 | << QStringList() |
2236 | << reverseItems |
2237 | << ascendingRows; |
2238 | } |
2239 | } |
2240 | |
2241 | void tst_QTreeWidget::insertItemsWithSorting() |
2242 | { |
2243 | QFETCH(Qt::SortOrder, sortOrder); |
2244 | QFETCH(const QStringList, initialItems); |
2245 | QFETCH(const QStringList, insertItems); |
2246 | QFETCH(const QStringList, expectedItems); |
2247 | QFETCH(IntList, expectedRows); |
2248 | |
2249 | for (int method = 0; method < 5; ++method) { |
2250 | QTreeWidget w; |
2251 | w.setSortingEnabled(true); |
2252 | w.sortItems(column: 0, order: sortOrder); |
2253 | for (const QString &initialItem : initialItems) |
2254 | w.addTopLevelItem(item: new QTreeWidgetItem({initialItem})); |
2255 | |
2256 | QAbstractItemModel *model = w.model(); |
2257 | PersistentModelIndexVec persistent; |
2258 | for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) |
2259 | persistent << model->index(row: j, column: 0, parent: QModelIndex()); |
2260 | |
2261 | switch (method) { |
2262 | case 0: |
2263 | // insert using item constructor |
2264 | for (const QString &txt : insertItems) |
2265 | new QTreeWidgetItem(&w, { txt }); |
2266 | break; |
2267 | case 1: |
2268 | { |
2269 | // insert using insertTopLevelItems() |
2270 | QList<QTreeWidgetItem*> lst; |
2271 | for (const QString &txt : insertItems) |
2272 | lst << new QTreeWidgetItem({ txt }); |
2273 | w.insertTopLevelItems(index: 0, items: lst); |
2274 | break; |
2275 | } |
2276 | case 2: |
2277 | // insert using insertTopLevelItem() |
2278 | for (const QString &txt : insertItems) |
2279 | w.insertTopLevelItem(index: 0, item: new QTreeWidgetItem({ txt })); |
2280 | break; |
2281 | case 3: |
2282 | { |
2283 | // insert using addTopLevelItems() |
2284 | QList<QTreeWidgetItem*> lst; |
2285 | for (const QString &txt : insertItems) |
2286 | lst << new QTreeWidgetItem({ txt }); |
2287 | w.addTopLevelItems(items: lst); |
2288 | break; |
2289 | } |
2290 | case 4: |
2291 | // insert using addTopLevelItem() |
2292 | for (const QString &txt : insertItems) |
2293 | w.addTopLevelItem(item: new QTreeWidgetItem({ txt })); |
2294 | break; |
2295 | } |
2296 | QCOMPARE(w.topLevelItemCount(), expectedItems.count()); |
2297 | for (int i = 0; i < w.topLevelItemCount(); ++i) |
2298 | QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i)); |
2299 | |
2300 | for (int k = 0; k < persistent.count(); ++k) |
2301 | QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); |
2302 | } |
2303 | } |
2304 | |
2305 | void tst_QTreeWidget::insertExpandedItemsWithSorting_data() |
2306 | { |
2307 | QTest::addColumn<QStringList>(name: "parentTexts" ); |
2308 | QTest::addColumn<QStringList>(name: "childTexts" ); |
2309 | QTest::addColumn<QStringList>(name: "parentResult" ); |
2310 | QTest::addColumn<QStringList>(name: "childResult" ); |
2311 | QTest::newRow(dataTag: "test 1" ) |
2312 | << (QStringList() << "c" << "d" << "a" << "b" ) |
2313 | << (QStringList() << "e" << "h" << "g" << "f" ) |
2314 | << (QStringList() << "d" << "c" << "b" << "a" ) |
2315 | << (QStringList() << "h" << "g" << "f" << "e" ); |
2316 | } |
2317 | |
2318 | // From Task 134978 |
2319 | void tst_QTreeWidget::insertExpandedItemsWithSorting() |
2320 | { |
2321 | QFETCH(const QStringList, parentTexts); |
2322 | QFETCH(const QStringList, childTexts); |
2323 | QFETCH(const QStringList, parentResult); |
2324 | QFETCH(const QStringList, childResult); |
2325 | |
2326 | // create a tree with autosorting enabled |
2327 | PublicTreeWidget tree; |
2328 | tree.setSortingEnabled(true); |
2329 | |
2330 | // insert expanded items in unsorted order |
2331 | QVector<QTreeWidgetItem *> items; |
2332 | for (const QString &text : parentTexts) { |
2333 | QTreeWidgetItem *parent = new QTreeWidgetItem(&tree, {text}); |
2334 | parent->setExpanded(true); |
2335 | QVERIFY(parent->isExpanded()); |
2336 | items << parent; |
2337 | for (const QString &text : childTexts) { |
2338 | QTreeWidgetItem *child = new QTreeWidgetItem(parent, {text}); |
2339 | items << child; |
2340 | } |
2341 | QCOMPARE(parent->childCount(), childTexts.count()); |
2342 | QVERIFY(parent->isExpanded()); |
2343 | } |
2344 | QCOMPARE(tree.model()->rowCount(), parentTexts.count()); |
2345 | |
2346 | // verify that the items are still expanded |
2347 | for (const QTreeWidgetItem *item : qAsConst(t&: items)) { |
2348 | if (item->childCount() > 0) |
2349 | QVERIFY(item->isExpanded()); |
2350 | QModelIndex idx = tree.indexFromItem(item); |
2351 | QVERIFY(idx.isValid()); |
2352 | //QRect rect = tree.visualRect(idx); |
2353 | //QVERIFY(rect.isValid()); |
2354 | // ### it is not guarantied that the index is in the viewport |
2355 | } |
2356 | |
2357 | // verify that the tree is sorted |
2358 | QAbstractItemModel *model = tree.model(); |
2359 | PersistentModelIndexVec parents; |
2360 | for (int i = 0; i < model->rowCount(parent: QModelIndex()); ++i) |
2361 | parents.push_back(t: model->index(row: i, column: 0, parent: QModelIndex())); |
2362 | PersistentModelIndexVec children; |
2363 | for (int i = 0; i < model->rowCount(parent: parents.constFirst()); ++i) |
2364 | children.push_back(t: model->index(row: i, column: 0, parent: parents.constFirst())); |
2365 | for (int i = 0; i < parentResult.count(); ++i) { |
2366 | QTreeWidgetItem *item = tree.topLevelItem(index: i); |
2367 | QCOMPARE(item->text(0), parentResult.at(i)); |
2368 | for (int j = 0; j < childResult.count(); ++j) |
2369 | QCOMPARE(item->child(j)->text(0), childResult.at(j)); |
2370 | } |
2371 | } |
2372 | |
2373 | void tst_QTreeWidget::changeDataWithSorting_data() |
2374 | { |
2375 | QTest::addColumn<Qt::SortOrder>(name: "sortOrder" ); |
2376 | QTest::addColumn<QStringList>(name: "initialItems" ); |
2377 | QTest::addColumn<int>(name: "itemIndex" ); |
2378 | QTest::addColumn<QString>(name: "newValue" ); |
2379 | QTest::addColumn<QStringList>(name: "expectedItems" ); |
2380 | QTest::addColumn<IntList>(name: "expectedRows" ); |
2381 | QTest::addColumn<bool>(name: "reorderingExpected" ); |
2382 | |
2383 | QTest::newRow(dataTag: "change a to b in (a)" ) |
2384 | << Qt::AscendingOrder |
2385 | << (QStringList() << "a" ) |
2386 | << 0 << "b" |
2387 | << (QStringList() << "b" ) |
2388 | << (IntList() << 0) |
2389 | << false; |
2390 | QTest::newRow(dataTag: "change a to b in (a, c)" ) |
2391 | << Qt::AscendingOrder |
2392 | << (QStringList() << "a" << "c" ) |
2393 | << 0 << "b" |
2394 | << (QStringList() << "b" << "c" ) |
2395 | << (IntList() << 0 << 1) |
2396 | << false; |
2397 | QTest::newRow(dataTag: "change a to c in (a, b)" ) |
2398 | << Qt::AscendingOrder |
2399 | << (QStringList() << "a" << "b" ) |
2400 | << 0 << "c" |
2401 | << (QStringList() << "b" << "c" ) |
2402 | << (IntList() << 1 << 0) |
2403 | << true; |
2404 | QTest::newRow(dataTag: "change c to a in (c, b)" ) |
2405 | << Qt::DescendingOrder |
2406 | << (QStringList() << "c" << "b" ) |
2407 | << 0 << "a" |
2408 | << (QStringList() << "b" << "a" ) |
2409 | << (IntList() << 1 << 0) |
2410 | << true; |
2411 | QTest::newRow(dataTag: "change e to i in (a, c, e, g)" ) |
2412 | << Qt::AscendingOrder |
2413 | << (QStringList() << "a" << "c" << "e" << "g" ) |
2414 | << 2 << "i" |
2415 | << (QStringList() << "a" << "c" << "g" << "i" ) |
2416 | << (IntList() << 0 << 1 << 3 << 2) |
2417 | << true; |
2418 | QTest::newRow(dataTag: "change e to a in (c, e, g, i)" ) |
2419 | << Qt::AscendingOrder |
2420 | << (QStringList() << "c" << "e" << "g" << "i" ) |
2421 | << 1 << "a" |
2422 | << (QStringList() << "a" << "c" << "g" << "i" ) |
2423 | << (IntList() << 1 << 0 << 2 << 3) |
2424 | << true; |
2425 | QTest::newRow(dataTag: "change e to f in (c, e, g, i)" ) |
2426 | << Qt::AscendingOrder |
2427 | << (QStringList() << "c" << "e" << "g" << "i" ) |
2428 | << 1 << "f" |
2429 | << (QStringList() << "c" << "f" << "g" << "i" ) |
2430 | << (IntList() << 0 << 1 << 2 << 3) |
2431 | << false; |
2432 | } |
2433 | |
2434 | void tst_QTreeWidget::changeDataWithSorting() |
2435 | { |
2436 | QFETCH(Qt::SortOrder, sortOrder); |
2437 | QFETCH(const QStringList, initialItems); |
2438 | QFETCH(int, itemIndex); |
2439 | QFETCH(const QString, newValue); |
2440 | QFETCH(const QStringList, expectedItems); |
2441 | QFETCH(const IntList, expectedRows); |
2442 | QFETCH(bool, reorderingExpected); |
2443 | |
2444 | QTreeWidget w; |
2445 | w.setSortingEnabled(true); |
2446 | w.sortItems(column: 0, order: sortOrder); |
2447 | for (const QString &str : initialItems) |
2448 | w.addTopLevelItem(item: new QTreeWidgetItem({ str })); |
2449 | |
2450 | QAbstractItemModel *model = w.model(); |
2451 | PersistentModelIndexVec persistent; |
2452 | for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) |
2453 | persistent << model->index(row: j, column: 0, parent: QModelIndex()); |
2454 | |
2455 | QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged); |
2456 | QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged); |
2457 | |
2458 | QTreeWidgetItem *item = w.topLevelItem(index: itemIndex); |
2459 | item->setText(column: 0, atext: newValue); |
2460 | for (int i = 0; i < expectedItems.count(); ++i) { |
2461 | QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i)); |
2462 | for (const QPersistentModelIndex &p : qAsConst(t&: persistent)) { |
2463 | if (p.row() == i) // the same toplevel row |
2464 | QCOMPARE(p.internalPointer(), static_cast<void *>(w.topLevelItem(i))); |
2465 | } |
2466 | } |
2467 | |
2468 | for (int k = 0; k < persistent.count(); ++k) |
2469 | QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); |
2470 | |
2471 | QCOMPARE(dataChangedSpy.count(), 1); |
2472 | QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0); |
2473 | } |
2474 | |
2475 | void tst_QTreeWidget::changeDataWithStableSorting_data() |
2476 | { |
2477 | QTest::addColumn<Qt::SortOrder>(name: "sortOrder" ); |
2478 | QTest::addColumn<QStringList>(name: "initialItems" ); |
2479 | QTest::addColumn<int>(name: "itemIndex" ); |
2480 | QTest::addColumn<QString>(name: "newValue" ); |
2481 | QTest::addColumn<QStringList>(name: "expectedItems" ); |
2482 | QTest::addColumn<IntList>(name: "expectedRows" ); |
2483 | QTest::addColumn<bool>(name: "reorderingExpected" ); |
2484 | QTest::addColumn<bool>(name: "forceChange" ); |
2485 | |
2486 | QTest::newRow(dataTag: "change a to c in (a, c, c, c, e)" ) |
2487 | << Qt::AscendingOrder |
2488 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2489 | << 0 << "c" |
2490 | << (QStringList() << "c" << "c" << "c" << "c" << "e" ) |
2491 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2492 | << false |
2493 | << false; |
2494 | QTest::newRow(dataTag: "change e to c in (a, c, c, c, e)" ) |
2495 | << Qt::AscendingOrder |
2496 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2497 | << 4 << "c" |
2498 | << (QStringList() << "a" << "c" << "c" << "c" << "c" ) |
2499 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2500 | << false |
2501 | << false; |
2502 | QTest::newRow(dataTag: "change 1st c to c in (a, c, c, c, e)" ) |
2503 | << Qt::AscendingOrder |
2504 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2505 | << 1 << "c" |
2506 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2507 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2508 | << false |
2509 | << true; |
2510 | QTest::newRow(dataTag: "change 2nd c to c in (a, c, c, c, e)" ) |
2511 | << Qt::AscendingOrder |
2512 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2513 | << 2 << "c" |
2514 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2515 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2516 | << false |
2517 | << true; |
2518 | QTest::newRow(dataTag: "change 3rd c to c in (a, c, c, c, e)" ) |
2519 | << Qt::AscendingOrder |
2520 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2521 | << 3 << "c" |
2522 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2523 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2524 | << false |
2525 | << true; |
2526 | QTest::newRow(dataTag: "change 1st c to c in (e, c, c, c, a)" ) |
2527 | << Qt::DescendingOrder |
2528 | << (QStringList() << "e" << "c" << "c" << "c" << "a" ) |
2529 | << 1 << "c" |
2530 | << (QStringList() << "e" << "c" << "c" << "c" << "a" ) |
2531 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2532 | << false |
2533 | << true; |
2534 | QTest::newRow(dataTag: "change 2nd c to c in (e, c, c, c, a)" ) |
2535 | << Qt::DescendingOrder |
2536 | << (QStringList() << "e" << "c" << "c" << "c" << "a" ) |
2537 | << 2 << "c" |
2538 | << (QStringList() << "e" << "c" << "c" << "c" << "a" ) |
2539 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2540 | << false |
2541 | << true; |
2542 | QTest::newRow(dataTag: "change 3rd c to c in (e, c, c, c, a)" ) |
2543 | << Qt::DescendingOrder |
2544 | << (QStringList() << "e" << "c" << "c" << "c" << "a" ) |
2545 | << 3 << "c" |
2546 | << (QStringList() << "e" << "c" << "c" << "c" << "a" ) |
2547 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2548 | << false |
2549 | << true; |
2550 | QTest::newRow(dataTag: "change 1st c to b in (a, c, c, c, e)" ) |
2551 | << Qt::AscendingOrder |
2552 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2553 | << 1 << "b" |
2554 | << (QStringList() << "a" << "b" << "c" << "c" << "e" ) |
2555 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2556 | << false |
2557 | << false; |
2558 | QTest::newRow(dataTag: "change 2nd c to b in (a, c, c, c, e)" ) |
2559 | << Qt::AscendingOrder |
2560 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2561 | << 2 << "b" |
2562 | << (QStringList() << "a" << "b" << "c" << "c" << "e" ) |
2563 | << (IntList() << 0 << 2 << 1 << 3 << 4) |
2564 | << true |
2565 | << false; |
2566 | QTest::newRow(dataTag: "change 3rd c to b in (a, c, c, c, e)" ) |
2567 | << Qt::AscendingOrder |
2568 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2569 | << 3 << "b" |
2570 | << (QStringList() << "a" << "b" << "c" << "c" << "e" ) |
2571 | << (IntList() << 0 << 2 << 3 << 1 << 4) |
2572 | << true |
2573 | << false; |
2574 | QTest::newRow(dataTag: "change 1st c to d in (a, c, c, c, e)" ) |
2575 | << Qt::AscendingOrder |
2576 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2577 | << 1 << "d" |
2578 | << (QStringList() << "a" << "c" << "c" << "d" << "e" ) |
2579 | << (IntList() << 0 << 3 << 1 << 2 << 4) |
2580 | << true |
2581 | << false; |
2582 | QTest::newRow(dataTag: "change 2nd c to d in (a, c, c, c, e)" ) |
2583 | << Qt::AscendingOrder |
2584 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2585 | << 2 << "d" |
2586 | << (QStringList() << "a" << "c" << "c" << "d" << "e" ) |
2587 | << (IntList() << 0 << 1 << 3 << 2 << 4) |
2588 | << true |
2589 | << false; |
2590 | QTest::newRow(dataTag: "change 3rd c to d in (a, c, c, c, e)" ) |
2591 | << Qt::AscendingOrder |
2592 | << (QStringList() << "a" << "c" << "c" << "c" << "e" ) |
2593 | << 3 << "d" |
2594 | << (QStringList() << "a" << "c" << "c" << "d" << "e" ) |
2595 | << (IntList() << 0 << 1 << 2 << 3 << 4) |
2596 | << false |
2597 | << false; |
2598 | } |
2599 | |
2600 | void tst_QTreeWidget::changeDataWithStableSorting() |
2601 | { |
2602 | QFETCH(Qt::SortOrder, sortOrder); |
2603 | QFETCH(const QStringList, initialItems); |
2604 | QFETCH(int, itemIndex); |
2605 | QFETCH(const QString, newValue); |
2606 | QFETCH(const QStringList, expectedItems); |
2607 | QFETCH(const IntList, expectedRows); |
2608 | QFETCH(bool, reorderingExpected); |
2609 | QFETCH(bool, forceChange); |
2610 | |
2611 | QTreeWidget w; |
2612 | w.setSortingEnabled(true); |
2613 | w.sortItems(column: 0, order: sortOrder); |
2614 | for (const QString &str : initialItems) |
2615 | w.addTopLevelItem(item: new PublicTreeItem({ str })); |
2616 | |
2617 | QAbstractItemModel *model = w.model(); |
2618 | PersistentModelIndexVec persistent; |
2619 | for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) |
2620 | persistent << model->index(row: j, column: 0, parent: QModelIndex()); |
2621 | |
2622 | QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged); |
2623 | QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged); |
2624 | |
2625 | auto *item = static_cast<PublicTreeItem *>(w.topLevelItem(index: itemIndex)); |
2626 | item->setText(column: 0, atext: newValue); |
2627 | if (forceChange) |
2628 | item->emitDataChanged(); |
2629 | for (int i = 0; i < expectedItems.count(); ++i) { |
2630 | QCOMPARE(w.topLevelItem(i)->text(0), expectedItems.at(i)); |
2631 | for (const QPersistentModelIndex &p : qAsConst(t&: persistent)) { |
2632 | if (p.row() == i) // the same toplevel row |
2633 | QCOMPARE(p.internalPointer(), static_cast<void *>(w.topLevelItem(i))); |
2634 | } |
2635 | } |
2636 | |
2637 | for (int k = 0; k < persistent.count(); ++k) |
2638 | QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); |
2639 | |
2640 | QCOMPARE(dataChangedSpy.count(), 1); |
2641 | QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0); |
2642 | } |
2643 | |
2644 | void tst_QTreeWidget::sizeHint_data() |
2645 | { |
2646 | QTest::addColumn<Qt::ScrollBarPolicy>(name: "scrollBarPolicy" ); |
2647 | QTest::addColumn<QSize>(name: "viewSize" ); |
2648 | QTest::newRow(dataTag: "ScrollBarAlwaysOn" ) << Qt::ScrollBarAlwaysOn << QSize(); |
2649 | QTest::newRow(dataTag: "ScrollBarAlwaysOff" ) << Qt::ScrollBarAlwaysOff << QSize(); |
2650 | // make sure the scrollbars are shown by resizing the view to 40x40 |
2651 | QTest::newRow(dataTag: "ScrollBarAsNeeded (40x40)" ) << Qt::ScrollBarAsNeeded << QSize(40, 40); |
2652 | QTest::newRow(dataTag: "ScrollBarAsNeeded (1000x1000)" ) << Qt::ScrollBarAsNeeded << QSize(1000, 1000); |
2653 | } |
2654 | |
2655 | void tst_QTreeWidget::sizeHint() |
2656 | { |
2657 | QFETCH(Qt::ScrollBarPolicy, scrollBarPolicy); |
2658 | QFETCH(QSize, viewSize); |
2659 | |
2660 | QTreeWidget view; |
2661 | view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); |
2662 | view.setVerticalScrollBarPolicy(scrollBarPolicy); |
2663 | view.setHorizontalScrollBarPolicy(scrollBarPolicy); |
2664 | view.setColumnCount(2); |
2665 | for (int i = 0 ; i < view.columnCount(); ++i) |
2666 | view.addTopLevelItem(item: new QTreeWidgetItem(QStringList{"foo" ,"bar" })); |
2667 | |
2668 | view.show(); |
2669 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2670 | |
2671 | if (viewSize.isValid()) { |
2672 | view.resize(viewSize); |
2673 | view.setColumnWidth(column: 0, width: 100); |
2674 | QTRY_COMPARE(view.size(), viewSize); |
2675 | } |
2676 | |
2677 | auto sizeHint = view.sizeHint(); |
2678 | view.hide(); |
2679 | QCOMPARE(view.sizeHint(), sizeHint); |
2680 | |
2681 | view.header()->hide(); |
2682 | view.show(); |
2683 | sizeHint = view.sizeHint(); |
2684 | view.hide(); |
2685 | QCOMPARE(view.sizeHint(), sizeHint); |
2686 | } |
2687 | |
2688 | void tst_QTreeWidget::itemOperatorLessThan() |
2689 | { |
2690 | QTreeWidget tw; |
2691 | tw.setColumnCount(2); |
2692 | { |
2693 | QTreeWidgetItem item1(&tw); |
2694 | QTreeWidgetItem item2(&tw); |
2695 | QCOMPARE(item1 < item2, false); |
2696 | item1.setText(column: 1, atext: "a" ); |
2697 | item2.setText(column: 1, atext: "b" ); |
2698 | QCOMPARE(item1 < item2, false); |
2699 | item1.setText(column: 0, atext: "a" ); |
2700 | item2.setText(column: 0, atext: "b" ); |
2701 | QCOMPARE(item1 < item2, true); |
2702 | tw.sortItems(column: 1, order: Qt::AscendingOrder); |
2703 | item1.setText(column: 0, atext: "b" ); |
2704 | item2.setText(column: 0, atext: "a" ); |
2705 | QCOMPARE(item1 < item2, true); |
2706 | tw.sortItems(column: 0, order: Qt::AscendingOrder); |
2707 | item1.setData(column: 0, role: Qt::DisplayRole, value: 11); |
2708 | item2.setData(column: 0, role: Qt::DisplayRole, value: 2); |
2709 | QCOMPARE(item1 < item2, false); |
2710 | } |
2711 | } |
2712 | |
2713 | void tst_QTreeWidget::sortedIndexOfChild_data() |
2714 | { |
2715 | QTest::addColumn<Qt::SortOrder>(name: "sortOrder" ); |
2716 | QTest::addColumn<QStringList>(name: "itemTexts" ); |
2717 | QTest::addColumn<IntList>(name: "expectedIndexes" ); |
2718 | |
2719 | QTest::newRow(dataTag: "three ascending" ) |
2720 | << Qt::AscendingOrder |
2721 | << (QStringList{"A" , "B" , "C" }) |
2722 | << (IntList{0, 1, 2}); |
2723 | |
2724 | |
2725 | QTest::newRow(dataTag: "three descending" ) |
2726 | << Qt::DescendingOrder |
2727 | << (QStringList{"A" , "B" , "C" }) |
2728 | << (IntList{2, 1, 0}); |
2729 | } |
2730 | |
2731 | void tst_QTreeWidget::sortedIndexOfChild() |
2732 | { |
2733 | QFETCH(Qt::SortOrder, sortOrder); |
2734 | QFETCH(const QStringList, itemTexts); |
2735 | QFETCH(const IntList, expectedIndexes); |
2736 | |
2737 | QTreeWidget tw; |
2738 | QVector<QTreeWidgetItem *> itms; |
2739 | auto *top = new QTreeWidgetItem(&tw, {"top" }); |
2740 | |
2741 | for (const QString &str : itemTexts) |
2742 | itms << new QTreeWidgetItem(top, {str}); |
2743 | |
2744 | tw.sortItems(column: 0, order: sortOrder); |
2745 | tw.expandAll(); |
2746 | |
2747 | QCOMPARE(itms.count(), expectedIndexes.count()); |
2748 | for (int j = 0; j < expectedIndexes.count(); ++j) |
2749 | QCOMPARE(top->indexOfChild(itms.at(j)), expectedIndexes.at(j)); |
2750 | } |
2751 | |
2752 | void tst_QTreeWidget::expandAndCallapse() |
2753 | { |
2754 | QTreeWidget tw; |
2755 | QTreeWidgetItem *top = new QTreeWidgetItem(&tw, QStringList() << "top" ); |
2756 | QTreeWidgetItem *p = nullptr; |
2757 | for (int i = 0; i < 10; ++i) { |
2758 | p = new QTreeWidgetItem(top, QStringList(QString::number(i))); |
2759 | for (int j = 0; j < 10; ++j) |
2760 | new QTreeWidgetItem(p, QStringList(QString::number(j))); |
2761 | } |
2762 | QSignalSpy spy0(&tw, &QTreeWidget::itemExpanded); |
2763 | QSignalSpy spy1(&tw, &QTreeWidget::itemCollapsed); |
2764 | |
2765 | |
2766 | tw.expandItem(item: p); |
2767 | tw.collapseItem(item: p); |
2768 | tw.expandItem(item: p); |
2769 | tw.expandItem(item: top); |
2770 | tw.collapseItem(item: top); |
2771 | tw.collapseItem(item: top); |
2772 | |
2773 | QCOMPARE(spy0.count(), 3); |
2774 | QCOMPARE(spy1.count(), 2); |
2775 | } |
2776 | |
2777 | void tst_QTreeWidget::setDisabled() |
2778 | { |
2779 | QTreeWidget w; |
2780 | QTreeWidgetItem *i1 = new QTreeWidgetItem(); |
2781 | QTreeWidgetItem *i2 = new QTreeWidgetItem(i1); |
2782 | QTreeWidgetItem *i3 = new QTreeWidgetItem(i1); |
2783 | |
2784 | QTreeWidgetItem *top = new QTreeWidgetItem(&w); |
2785 | top->setDisabled(true); |
2786 | top->addChild(child: i1); |
2787 | QCOMPARE(i1->isDisabled(), true); |
2788 | QCOMPARE(i2->isDisabled(), true); |
2789 | QCOMPARE(i3->isDisabled(), true); |
2790 | |
2791 | i1 = top->takeChild(index: 0); |
2792 | QCOMPARE(i1->isDisabled(), false); |
2793 | QCOMPARE(i2->isDisabled(), false); |
2794 | QCOMPARE(i3->isDisabled(), false); |
2795 | |
2796 | top->addChild(child: i1); |
2797 | QCOMPARE(i1->isDisabled(), true); |
2798 | QCOMPARE(i2->isDisabled(), true); |
2799 | QCOMPARE(i3->isDisabled(), true); |
2800 | |
2801 | top->setDisabled(false); |
2802 | QCOMPARE(i1->isDisabled(), false); |
2803 | QCOMPARE(i2->isDisabled(), false); |
2804 | QCOMPARE(i3->isDisabled(), false); |
2805 | |
2806 | |
2807 | |
2808 | QList<QTreeWidgetItem*> children; |
2809 | children.append(t: new QTreeWidgetItem()); |
2810 | children.append(t: new QTreeWidgetItem()); |
2811 | children.append(t: new QTreeWidgetItem()); |
2812 | { |
2813 | const QScopedPointer<QTreeWidgetItem> taken(top->takeChild(index: 0)); |
2814 | QCOMPARE(taken.data(), i1); |
2815 | } |
2816 | |
2817 | top->addChildren(children); |
2818 | QCOMPARE(top->child(0)->isDisabled(), false); |
2819 | QCOMPARE(top->child(1)->isDisabled(), false); |
2820 | QCOMPARE(top->child(1)->isDisabled(), false); |
2821 | |
2822 | top->setDisabled(true); |
2823 | QCOMPARE(top->child(0)->isDisabled(), true); |
2824 | QCOMPARE(top->child(1)->isDisabled(), true); |
2825 | QCOMPARE(top->child(1)->isDisabled(), true); |
2826 | |
2827 | struct Deleter { |
2828 | QList<QTreeWidgetItem *> items; |
2829 | explicit Deleter(QList<QTreeWidgetItem *> items) : items(std::move(items)) {} |
2830 | ~Deleter() { qDeleteAll(c: items); } |
2831 | }; |
2832 | |
2833 | const Deleter takenChildren(top->takeChildren()); |
2834 | QCOMPARE(takenChildren.items[0]->isDisabled(), false); |
2835 | QCOMPARE(takenChildren.items[1]->isDisabled(), false); |
2836 | QCOMPARE(takenChildren.items[1]->isDisabled(), false); |
2837 | } |
2838 | |
2839 | void tst_QTreeWidget::setSpanned() |
2840 | { |
2841 | QTreeWidget w; |
2842 | QTreeWidgetItem *i1 = new QTreeWidgetItem(); |
2843 | QScopedPointer<QTreeWidgetItem> i2(new QTreeWidgetItem()); |
2844 | |
2845 | QTreeWidgetItem *top = new QTreeWidgetItem(&w); |
2846 | top->addChild(child: i1); |
2847 | |
2848 | top->setFirstColumnSpanned(true); |
2849 | QCOMPARE(top->isFirstColumnSpanned(), true); |
2850 | QCOMPARE(i1->isFirstColumnSpanned(), false); |
2851 | QCOMPARE(i2->isFirstColumnSpanned(), false); |
2852 | |
2853 | top->setFirstColumnSpanned(false); |
2854 | i1->setFirstColumnSpanned(true); |
2855 | i2->setFirstColumnSpanned(true); |
2856 | QCOMPARE(top->isFirstColumnSpanned(), false); |
2857 | QCOMPARE(i1->isFirstColumnSpanned(), true); |
2858 | QCOMPARE(i2->isFirstColumnSpanned(), false); |
2859 | } |
2860 | |
2861 | void tst_QTreeWidget::removeSelectedItem() |
2862 | { |
2863 | const QScopedPointer <QTreeWidget> w(new QTreeWidget); |
2864 | w->setSortingEnabled(true); |
2865 | |
2866 | QTreeWidgetItem *first = new QTreeWidgetItem(); |
2867 | first->setText(column: 0, atext: QLatin1String("D" )); |
2868 | w->addTopLevelItem(item: first); |
2869 | |
2870 | QTreeWidgetItem *itm = new QTreeWidgetItem(); |
2871 | itm->setText(column: 0, atext: QLatin1String("D" )); |
2872 | w->addTopLevelItem(item: itm); |
2873 | |
2874 | itm = new QTreeWidgetItem(); |
2875 | itm->setText(column: 0, atext: QLatin1String("C" )); |
2876 | w->addTopLevelItem(item: itm); |
2877 | itm->setSelected(true); |
2878 | |
2879 | itm = new QTreeWidgetItem(); |
2880 | itm->setText(column: 0, atext: QLatin1String("A" )); |
2881 | w->addTopLevelItem(item: itm); |
2882 | |
2883 | //w->show(); |
2884 | |
2885 | QItemSelectionModel *selModel = w->selectionModel(); |
2886 | QCOMPARE(selModel->hasSelection(), true); |
2887 | QCOMPARE(selModel->selectedRows().count(), 1); |
2888 | |
2889 | const QScopedPointer<QTreeWidgetItem> taken(w->takeTopLevelItem(index: 2)); |
2890 | QCOMPARE(taken->text(0), QLatin1String("C" )); |
2891 | |
2892 | QCOMPARE(selModel->hasSelection(), false); |
2893 | QCOMPARE(selModel->selectedRows().count(), 0); |
2894 | QItemSelection sel = selModel->selection(); |
2895 | QCOMPARE(selModel->isSelected(w->model()->index(0,0)), false); |
2896 | } |
2897 | |
2898 | void tst_QTreeWidget::removeCurrentItem() |
2899 | { |
2900 | PublicTreeWidget widget; |
2901 | connect(sender: widget.selectionModel(), |
2902 | signal: &QItemSelectionModel::currentChanged, |
2903 | receiver: &widget, slot: &PublicTreeWidget::clear); |
2904 | QTreeWidgetItem *item = new QTreeWidgetItem(&widget); |
2905 | widget.setCurrentItem(item); |
2906 | widget.deleteCurrent(); |
2907 | } |
2908 | |
2909 | void tst_QTreeWidget::removeCurrentItem_task186451() |
2910 | { |
2911 | PublicTreeWidget widget; |
2912 | QTreeWidgetItem *item = new QTreeWidgetItem(&widget, {"1" }); |
2913 | QTreeWidgetItem *item2 = new QTreeWidgetItem(&widget, {"2" }); |
2914 | widget.setCurrentItem(item); |
2915 | widget.deleteCurrent(); |
2916 | |
2917 | QVERIFY(item2->isSelected()); |
2918 | QCOMPARE(item2, widget.currentItem()); |
2919 | } |
2920 | |
2921 | void tst_QTreeWidget::randomExpand() |
2922 | { |
2923 | QTreeWidget tree; |
2924 | QTreeWidgetItem *item1 = new QTreeWidgetItem(&tree); |
2925 | QTreeWidgetItem *item3 = new QTreeWidgetItem(&tree, item1); |
2926 | new QTreeWidgetItem(item1); |
2927 | new QTreeWidgetItem(item3); |
2928 | |
2929 | tree.expandAll(); |
2930 | |
2931 | /* |
2932 | item1 |
2933 | \- item2 |
2934 | item3 |
2935 | \- item4 |
2936 | */ |
2937 | |
2938 | for (int i = 0; i < 100; i++) { |
2939 | auto newItem1 = new QTreeWidgetItem(&tree, item1); |
2940 | newItem1->setExpanded(true); |
2941 | QCOMPARE(newItem1->isExpanded(), true); |
2942 | |
2943 | QTreeWidgetItem *x = new QTreeWidgetItem(); |
2944 | QCOMPARE(newItem1->isExpanded(), true); |
2945 | newItem1->addChild(child: x); |
2946 | |
2947 | QCOMPARE(newItem1->isExpanded(), true); |
2948 | } |
2949 | } |
2950 | |
2951 | void tst_QTreeWidget::crashTest() |
2952 | { |
2953 | QTreeWidget tree; |
2954 | tree.setColumnCount(1); |
2955 | tree.show(); |
2956 | |
2957 | QTreeWidgetItem *item1 = new QTreeWidgetItem(&tree); |
2958 | item1->setText(column: 0, atext: "item1" ); |
2959 | item1->setExpanded(true); |
2960 | QTreeWidgetItem *item2 = new QTreeWidgetItem(item1); |
2961 | item2->setText(column: 0, atext: "item2" ); |
2962 | |
2963 | QTreeWidgetItem *item3 = new QTreeWidgetItem(&tree, item1); |
2964 | item3->setText(column: 0, atext: "item3" ); |
2965 | item3->setExpanded(true); |
2966 | QTreeWidgetItem *item4 = new QTreeWidgetItem(item3); |
2967 | item4->setText(column: 0, atext: "item4" ); |
2968 | |
2969 | QTreeWidgetItem *item5 = new QTreeWidgetItem(&tree, item3); |
2970 | item5->setText(column: 0, atext: "item5" ); |
2971 | item5->setExpanded(true); |
2972 | QTreeWidgetItem *item6 = new QTreeWidgetItem(item5); |
2973 | item6->setText(column: 0, atext: "item6" ); |
2974 | |
2975 | for (int i = 0; i < 1000; i++) { |
2976 | QTreeWidgetItem *newItem1 = new QTreeWidgetItem(&tree, item1); |
2977 | newItem1->setText(column: 0, atext: "newItem" ); |
2978 | QTreeWidgetItem *newItem2 = new QTreeWidgetItem(newItem1); |
2979 | newItem2->setText(column: 0, atext: "subItem1" ); |
2980 | QTreeWidgetItem *newItem3 = new QTreeWidgetItem(newItem1, newItem2); |
2981 | newItem3->setText(column: 0, atext: "subItem2" ); |
2982 | delete item3; |
2983 | item3 = newItem1; |
2984 | } |
2985 | QCoreApplication::processEvents(); |
2986 | } |
2987 | |
2988 | class CrashWidget : public QTreeWidget |
2989 | { |
2990 | public: |
2991 | CrashWidget(QWidget *parent = nullptr) : QTreeWidget(parent) |
2992 | { |
2993 | setSortingEnabled(true); |
2994 | timerId = startTimer(interval: 10); |
2995 | } |
2996 | int i = 0; |
2997 | protected: |
2998 | void timerEvent(QTimerEvent * event) override |
2999 | { |
3000 | if (event->timerId() == timerId) { |
3001 | auto newItem = new QTreeWidgetItem({QString::number(i++)}); |
3002 | m_list.append(t: newItem); |
3003 | insertTopLevelItem(index: 0, item: newItem); |
3004 | while (m_list.count() > 10) |
3005 | delete m_list.takeFirst(); |
3006 | } |
3007 | QTreeWidget::timerEvent(event); |
3008 | } |
3009 | private: |
3010 | int timerId; |
3011 | QVector<QTreeWidgetItem*> m_list; |
3012 | }; |
3013 | |
3014 | void tst_QTreeWidget::sortAndSelect() |
3015 | { |
3016 | CrashWidget w; |
3017 | w.resize(w: 1, h: 1); |
3018 | w.show(); |
3019 | while (w.i < 100) { |
3020 | QApplication::processEvents(); |
3021 | if (w.i & 16) { |
3022 | QPoint pt = w.viewport()->rect().center(); |
3023 | QTest::mouseClick(widget: w.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: pt); |
3024 | } |
3025 | } |
3026 | QVERIFY(true); |
3027 | } |
3028 | |
3029 | void tst_QTreeWidget::defaultRowSizes() |
3030 | { |
3031 | const QScopedPointer<QTreeWidget> tw(new QTreeWidget); |
3032 | tw->setIconSize(QSize(50, 50)); |
3033 | tw->setColumnCount(6); |
3034 | for (int i = 0; i < 10; ++i) { |
3035 | auto it = new QTreeWidgetItem(tw.data()); |
3036 | for (int j = 0; j < tw->columnCount() - 1; ++j) |
3037 | it->setText(column: j, atext: "This is a test" ); |
3038 | auto sp = static_cast<QStyle::StandardPixmap>(i + QStyle::SP_TitleBarMenuButton); |
3039 | QPixmap icon = tw->style()->standardPixmap(standardPixmap: sp); |
3040 | |
3041 | if (icon.isNull()) |
3042 | QSKIP("No pixmap found on current style, skipping this test." ); |
3043 | it->setIcon(column: tw->columnCount() - 1, |
3044 | aicon: icon.scaled(s: tw->iconSize())); |
3045 | } |
3046 | tw->resize(w: 100,h: 100); |
3047 | tw->show(); |
3048 | QApplication::processEvents(); |
3049 | |
3050 | QRect visualRect = tw->visualItemRect(item: tw->topLevelItem(index: 0)); |
3051 | QVERIFY(visualRect.height() >= 50); |
3052 | } |
3053 | |
3054 | void tst_QTreeWidget::task191552_rtl() |
3055 | { |
3056 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
3057 | QSKIP("Wayland: This fails. Figure out why." ); |
3058 | |
3059 | Qt::LayoutDirection oldDir = QGuiApplication::layoutDirection(); |
3060 | QGuiApplication::setLayoutDirection(Qt::RightToLeft); |
3061 | |
3062 | QTreeWidget tw; |
3063 | tw.setColumnCount(1); |
3064 | QTreeWidgetItem *item = new QTreeWidgetItem(&tw); |
3065 | item->setText(column: 0, atext: "item 1" ); |
3066 | item->setCheckState(column: 0, state: Qt::Checked); |
3067 | QCOMPARE(item->checkState(0), Qt::Checked); |
3068 | tw.show(); |
3069 | QVERIFY(QTest::qWaitForWindowActive(&tw)); |
3070 | QStyleOptionViewItem opt; |
3071 | opt.initFrom(w: &tw); |
3072 | opt.rect = tw.visualItemRect(item); |
3073 | // mimic QStyledItemDelegate::initStyleOption logic |
3074 | opt.features = QStyleOptionViewItem::HasDisplay | QStyleOptionViewItem::HasCheckIndicator; |
3075 | opt.checkState = Qt::Checked; |
3076 | opt.widget = &tw; |
3077 | const QRect checkRect = tw.style()->subElementRect(subElement: QStyle::SE_ItemViewItemCheckIndicator, option: &opt, widget: &tw); |
3078 | QTest::mouseClick(widget: tw.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: checkRect.center()); |
3079 | QCOMPARE(item->checkState(0), Qt::Unchecked); |
3080 | |
3081 | QGuiApplication::setLayoutDirection(oldDir); |
3082 | } |
3083 | |
3084 | void tst_QTreeWidget::task203673_selection() |
3085 | { |
3086 | //we try to change the selection by rightclick + ctrl |
3087 | //it should do anything when using ExtendedSelection |
3088 | |
3089 | QTreeWidget tw; |
3090 | tw.setColumnCount(1); |
3091 | QTreeWidgetItem *item1 = new QTreeWidgetItem(&tw); |
3092 | item1->setText(column: 0, atext: "item 1" ); |
3093 | tw.setSelectionMode(QTreeView::ExtendedSelection); |
3094 | |
3095 | QPoint center = tw.visualItemRect(item: item1).center(); |
3096 | QCOMPARE(item1->isSelected(), false); |
3097 | |
3098 | QTest::mouseClick(widget: tw.viewport(), button: Qt::RightButton, stateKey: Qt::ControlModifier, pos: center); |
3099 | QCOMPARE(item1->isSelected(), false); |
3100 | |
3101 | QTest::mouseClick(widget: tw.viewport(), button: Qt::LeftButton, stateKey: Qt::ControlModifier, pos: center); |
3102 | QCOMPARE(item1->isSelected(), true); |
3103 | |
3104 | QTest::mouseClick(widget: tw.viewport(), button: Qt::RightButton, stateKey: Qt::ControlModifier, pos: center); |
3105 | QCOMPARE(item1->isSelected(), true); //it shouldn't change |
3106 | |
3107 | QTest::mouseClick(widget: tw.viewport(), button: Qt::LeftButton, stateKey: Qt::ControlModifier, pos: center); |
3108 | QCOMPARE(item1->isSelected(), false); |
3109 | } |
3110 | |
3111 | |
3112 | void tst_QTreeWidget::rootItemFlags() |
3113 | { |
3114 | QTreeWidget tw; |
3115 | tw.setColumnCount(1); |
3116 | QTreeWidgetItem *item = new QTreeWidgetItem(&tw); |
3117 | item->setText(column: 0, atext: "item 1" ); |
3118 | |
3119 | QVERIFY(tw.invisibleRootItem()->flags() & Qt::ItemIsDropEnabled); |
3120 | |
3121 | tw.invisibleRootItem()->setFlags(tw.invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled); |
3122 | |
3123 | QVERIFY(!(tw.invisibleRootItem()->flags() & Qt::ItemIsDropEnabled)); |
3124 | } |
3125 | |
3126 | void tst_QTreeWidget::() |
3127 | { |
3128 | //We check that setting header data out of bounds returns false |
3129 | //and doesn't increase the size of the model |
3130 | QTreeWidget tw; |
3131 | tw.setColumnCount(1); |
3132 | QCOMPARE(tw.columnCount(), 1); |
3133 | |
3134 | QCOMPARE(tw.model()->setHeaderData(99999, Qt::Horizontal, QVariant()), false); |
3135 | |
3136 | QCOMPARE(tw.columnCount(), 1); |
3137 | } |
3138 | |
3139 | void tst_QTreeWidget::task245280_sortChildren() |
3140 | { |
3141 | QTreeWidget tw; |
3142 | tw.setColumnCount(2); |
3143 | |
3144 | QTreeWidgetItem top(&tw); |
3145 | top.setText(column: 0,atext: "Col 0" ); |
3146 | top.setText(column: 1,atext: "Col 1" ); |
3147 | QTreeWidgetItem item1(&top); |
3148 | item1.setText(column: 0,atext: "X" ); |
3149 | item1.setText(column: 1,atext: "0" ); |
3150 | QTreeWidgetItem item2(&top); |
3151 | item2.setText(column: 0,atext: "A" ); |
3152 | item2.setText(column: 1,atext: "4" ); |
3153 | QTreeWidgetItem item3(&top); |
3154 | item3.setText(column: 0,atext: "E" ); |
3155 | item3.setText(column: 1,atext: "1" ); |
3156 | QTreeWidgetItem item4(&top); |
3157 | item4.setText(column: 0,atext: "Z" ); |
3158 | item4.setText(column: 1,atext: "3" ); |
3159 | QTreeWidgetItem item5(&top); |
3160 | item5.setText(column: 0,atext: "U" ); |
3161 | item5.setText(column: 1,atext: "2" ); |
3162 | tw.expandAll(); |
3163 | tw.show(); |
3164 | top.sortChildren(column: 1,order: Qt::AscendingOrder); |
3165 | |
3166 | for (int i = 0; i < top.childCount(); ++i) |
3167 | QCOMPARE(top.child(i)->text(1), QString::number(i)); |
3168 | } |
3169 | |
3170 | void tst_QTreeWidget::task253109_itemHeight() |
3171 | { |
3172 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
3173 | QSKIP("Wayland: This fails. Figure out why." ); |
3174 | |
3175 | QTreeWidget treeWidget; |
3176 | treeWidget.setColumnCount(1); |
3177 | treeWidget.show(); |
3178 | QVERIFY(QTest::qWaitForWindowActive(&treeWidget)); |
3179 | |
3180 | QTreeWidgetItem item(&treeWidget); |
3181 | class MyWidget : public QWidget |
3182 | { |
3183 | QSize sizeHint() const override { return QSize(200, 100); } |
3184 | } w; |
3185 | treeWidget.setItemWidget(item: &item, column: 0, widget: &w); |
3186 | |
3187 | QTRY_COMPARE(w.geometry(), treeWidget.visualItemRect(&item)); |
3188 | } |
3189 | |
3190 | void tst_QTreeWidget::task206367_duplication() |
3191 | { |
3192 | QWidget topLevel; |
3193 | // Explicitly set the font size because it is dpi dependent on some platforms |
3194 | QFont font; |
3195 | font.setPixelSize(40); |
3196 | topLevel.setFont(font); |
3197 | QTreeWidget treeWidget(&topLevel); |
3198 | topLevel.show(); |
3199 | treeWidget.resize(w: 200, h: 200); |
3200 | treeWidget.setHeaderHidden(true); |
3201 | |
3202 | treeWidget.setSortingEnabled(true); |
3203 | QTreeWidgetItem* rootItem = new QTreeWidgetItem(&treeWidget, QStringList("root" )); |
3204 | for (int nFile = 0; nFile < 2; nFile++ ) { |
3205 | QTreeWidgetItem* itemFile = new QTreeWidgetItem(rootItem, {QString::number(nFile)}); |
3206 | for (int nRecord = 0; nRecord < 2; nRecord++) |
3207 | new QTreeWidgetItem(itemFile, {QString::number(nRecord)}); |
3208 | itemFile->setExpanded(true); |
3209 | } |
3210 | rootItem->setExpanded(true); |
3211 | |
3212 | //there should be enough room for 2x2 items. If there is a scrollbar, it means the items are duplicated |
3213 | QTRY_VERIFY(!treeWidget.verticalScrollBar()->isVisible()); |
3214 | } |
3215 | |
3216 | void tst_QTreeWidget::itemSelectionChanged() |
3217 | { |
3218 | QVERIFY(testWidget); |
3219 | if (testWidget->topLevelItem(index: 0)) |
3220 | QVERIFY(testWidget->topLevelItem(0)->isSelected()); |
3221 | } |
3222 | |
3223 | void tst_QTreeWidget::selectionOrder() |
3224 | { |
3225 | testWidget->setColumnCount(1); |
3226 | QList<QTreeWidgetItem *> items; |
3227 | for (int i = 0; i < 10; ++i) { |
3228 | items.append(t: new QTreeWidgetItem(static_cast<QTreeWidget *>(nullptr), |
3229 | {QStringLiteral("item: %1" ).arg(a: i)})); |
3230 | } |
3231 | testWidget->insertTopLevelItems(index: 0, items); |
3232 | |
3233 | QModelIndex idx = testWidget->indexFromItem(item: items.at(i: 0)); |
3234 | connect(sender: testWidget, signal: &QTreeWidget::itemSelectionChanged, |
3235 | receiver: this, slot: &tst_QTreeWidget::itemSelectionChanged); |
3236 | testWidget->selectionModel()->select(index: idx, command: QItemSelectionModel::SelectCurrent); |
3237 | disconnect(sender: testWidget, signal: &QTreeWidget::itemSelectionChanged, |
3238 | receiver: this, slot: &tst_QTreeWidget::itemSelectionChanged); |
3239 | } |
3240 | |
3241 | void tst_QTreeWidget::setSelectionModel() |
3242 | { |
3243 | QTreeWidget tree; |
3244 | for(int i = 0; i < 3; ++i) |
3245 | new QTreeWidgetItem(&tree, QStringList(QString::number(i))); |
3246 | QItemSelectionModel selection(tree.model()); |
3247 | selection.select(index: tree.model()->index(row: 1, column: 0), command: QItemSelectionModel::Select); |
3248 | tree.setSelectionModel(&selection); |
3249 | QCOMPARE(tree.topLevelItem(1)->isSelected(), true); |
3250 | } |
3251 | |
3252 | void tst_QTreeWidget::task217309() |
3253 | { |
3254 | QTreeWidgetItem item; |
3255 | item.setFlags(item.flags() | Qt::ItemIsAutoTristate); |
3256 | QTreeWidgetItem subitem1; |
3257 | subitem1.setFlags(subitem1.flags() | Qt::ItemIsAutoTristate); |
3258 | QTreeWidgetItem subitem2; |
3259 | subitem2.setFlags(subitem2.flags() | Qt::ItemIsAutoTristate); |
3260 | item.addChild(child: &subitem1); |
3261 | item.addChild(child: &subitem2); |
3262 | subitem1.setCheckState(column: 0, state: Qt::Checked); |
3263 | subitem2.setCheckState(column: 0, state: Qt::Unchecked); |
3264 | |
3265 | QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::PartiallyChecked); |
3266 | |
3267 | subitem2.setCheckState(column: 0, state: Qt::PartiallyChecked); |
3268 | QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::PartiallyChecked); |
3269 | |
3270 | subitem2.setCheckState(column: 0, state: Qt::Checked); |
3271 | QVERIFY(item.data(0, Qt::CheckStateRole) == Qt::Checked); |
3272 | } |
3273 | |
3274 | void tst_QTreeWidget::nonEditableTristate() |
3275 | { |
3276 | // A tree with checkable items, the parent is tristate |
3277 | QTreeWidget tree; |
3278 | QTreeWidgetItem *item = new QTreeWidgetItem; |
3279 | tree.insertTopLevelItem(index: 0, item); |
3280 | item->setFlags(item->flags() | Qt::ItemIsAutoTristate); |
3281 | item->setCheckState(column: 0, state: Qt::Unchecked); |
3282 | QTreeWidgetItem *subitem1 = new QTreeWidgetItem(item); |
3283 | subitem1->setCheckState(column: 0, state: Qt::Unchecked); |
3284 | QTreeWidgetItem *subitem2 = new QTreeWidgetItem(item); |
3285 | subitem2->setCheckState(column: 0, state: Qt::Unchecked); |
3286 | QCOMPARE(int(item->checkState(0)), int(Qt::Unchecked)); |
3287 | tree.show(); |
3288 | QVERIFY(QTest::qWaitForWindowExposed(&tree)); |
3289 | |
3290 | // Test clicking on the parent item, it should become Checked (not PartiallyChecked) |
3291 | QStyleOptionViewItem option; |
3292 | option.rect = tree.visualRect(index: tree.model()->index(row: 0, column: 0)); |
3293 | option.state |= QStyle::State_Enabled; |
3294 | option.features |= QStyleOptionViewItem::HasCheckIndicator | QStyleOptionViewItem::HasDisplay; |
3295 | option.checkState = item->checkState(column: 0); |
3296 | |
3297 | auto appStyle = QApplication::style(); |
3298 | const int checkMargin = appStyle->pixelMetric( |
3299 | metric: QStyle::PM_FocusFrameHMargin, option: nullptr, widget: nullptr) + 1; |
3300 | QPoint pos = appStyle->subElementRect( |
3301 | subElement: QStyle::SE_ItemViewItemCheckIndicator, option: &option, widget: nullptr).center(); |
3302 | pos.rx() += checkMargin; |
3303 | QTest::mouseClick(widget: tree.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos); |
3304 | QCOMPARE(item->checkState(0), Qt::Checked); |
3305 | |
3306 | // Click again, it should become Unchecked. |
3307 | QTest::mouseClick(widget: tree.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos); |
3308 | QCOMPARE(item->checkState(0), Qt::Unchecked); |
3309 | } |
3310 | |
3311 | void tst_QTreeWidget::emitDataChanged() |
3312 | { |
3313 | QTreeWidget tree; |
3314 | QSignalSpy spy(&tree, &QTreeWidget::itemChanged); |
3315 | auto item = new PublicTreeItem; |
3316 | tree.insertTopLevelItem(index: 0, item); |
3317 | item->emitDataChanged(); |
3318 | QCOMPARE(spy.count(), 1); |
3319 | } |
3320 | |
3321 | void tst_QTreeWidget::setCurrentItemExpandsParent() |
3322 | { |
3323 | QTreeWidget w; |
3324 | w.setColumnCount(1); |
3325 | QTreeWidgetItem *i1 = new QTreeWidgetItem(&w, {"parent" }); |
3326 | QTreeWidgetItem *i2 = new QTreeWidgetItem(i1, {"child" }); |
3327 | QVERIFY(!i2->isExpanded()); |
3328 | QVERIFY(!w.currentItem()); |
3329 | w.setCurrentItem(i2); |
3330 | QVERIFY(!i2->isExpanded()); |
3331 | QCOMPARE(w.currentItem(), i2); |
3332 | } |
3333 | |
3334 | void tst_QTreeWidget::task239150_editorWidth() |
3335 | { |
3336 | //we check that an item with no text will get an editor with a correct size |
3337 | QTreeWidget tree; |
3338 | |
3339 | QStyleOptionFrame opt; |
3340 | opt.init(w: &tree); |
3341 | const int minWidth = tree.style()->sizeFromContents(ct: QStyle::CT_LineEdit, opt: &opt, contentsSize: QSize(0, 0). |
3342 | expandedTo(otherSize: QApplication::globalStrut()), w: nullptr).width(); |
3343 | |
3344 | { |
3345 | QTreeWidgetItem item; |
3346 | item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); |
3347 | tree.addTopLevelItem(item: &item); |
3348 | QVERIFY(tree.itemWidget(&item, 0) == nullptr); |
3349 | tree.editItem(item: &item); |
3350 | QVERIFY(tree.itemWidget(&item, 0)); |
3351 | QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth); |
3352 | } |
3353 | |
3354 | //now let's test it with an item with a lot of text |
3355 | { |
3356 | QTreeWidgetItem item; |
3357 | item.setText(column: 0, atext: "foooooooooooooooooooooooo" ); |
3358 | item.setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); |
3359 | tree.addTopLevelItem(item: &item); |
3360 | QVERIFY(tree.itemWidget(&item, 0) == nullptr); |
3361 | tree.editItem(item: &item); |
3362 | QVERIFY(tree.itemWidget(&item, 0)); |
3363 | QVERIFY(tree.itemWidget(&item, 0)->width() >= minWidth + tree.fontMetrics().horizontalAdvance(item.text(0))); |
3364 | } |
3365 | } |
3366 | |
3367 | |
3368 | |
3369 | void tst_QTreeWidget::setTextUpdate() |
3370 | { |
3371 | QTreeWidget treeWidget; |
3372 | treeWidget.setColumnCount(2); |
3373 | |
3374 | class MyItemDelegate : public QStyledItemDelegate |
3375 | { |
3376 | public: |
3377 | using QStyledItemDelegate::QStyledItemDelegate; |
3378 | void paint(QPainter *painter, const QStyleOptionViewItem &option, |
3379 | const QModelIndex &index) const override |
3380 | { |
3381 | numPaints++; |
3382 | QStyledItemDelegate::paint(painter, option, index); |
3383 | } |
3384 | |
3385 | mutable int numPaints = 0; |
3386 | } delegate; |
3387 | |
3388 | treeWidget.setItemDelegate(&delegate); |
3389 | treeWidget.show(); |
3390 | QVERIFY(QTest::qWaitForWindowExposed(&treeWidget)); |
3391 | QTreeWidgetItem *item = new QTreeWidgetItem({ "variable1" , "0" }); |
3392 | treeWidget.insertTopLevelItem(index: 0, item); |
3393 | QTRY_VERIFY(delegate.numPaints > 0); |
3394 | delegate.numPaints = 0; |
3395 | |
3396 | item->setText(column: 1, atext: "42" ); |
3397 | QTRY_VERIFY(delegate.numPaints > 0); |
3398 | } |
3399 | |
3400 | void tst_QTreeWidget::taskQTBUG2844_visualItemRect() |
3401 | { |
3402 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
3403 | QSKIP("Wayland: This fails. Figure out why." ); |
3404 | |
3405 | PublicTreeWidget tree; |
3406 | tree.resize(w: 150, h: 100); |
3407 | tree.setColumnCount(3); |
3408 | QTreeWidgetItem item(&tree); |
3409 | |
3410 | QRect rectCol0 = tree.visualRect(index: tree.indexFromItem(item: &item, column: 0)); |
3411 | QRect rectCol1 = tree.visualRect(index: tree.indexFromItem(item: &item, column: 1)); |
3412 | QRect rectCol2 = tree.visualRect(index: tree.indexFromItem(item: &item, column: 2)); |
3413 | |
3414 | QCOMPARE(tree.visualItemRect(&item), rectCol0 | rectCol2); |
3415 | tree.setColumnHidden(column: 2, hide: true); |
3416 | QCOMPARE(tree.visualItemRect(&item), rectCol0 | rectCol1); |
3417 | } |
3418 | |
3419 | void tst_QTreeWidget::setChildIndicatorPolicy() |
3420 | { |
3421 | QTreeWidget treeWidget; |
3422 | treeWidget.setColumnCount(1); |
3423 | |
3424 | class MyItemDelegate : public QStyledItemDelegate |
3425 | { |
3426 | public: |
3427 | using QStyledItemDelegate::QStyledItemDelegate; |
3428 | void paint(QPainter *painter, |
3429 | const QStyleOptionViewItem &option, |
3430 | const QModelIndex &index) const override |
3431 | { |
3432 | numPaints++; |
3433 | QCOMPARE(!(option.state & QStyle::State_Children), !expectChildren); |
3434 | QStyledItemDelegate::paint(painter, option, index); |
3435 | } |
3436 | mutable int numPaints = 0; |
3437 | bool expectChildren = false; |
3438 | } delegate; |
3439 | |
3440 | treeWidget.setItemDelegate(&delegate); |
3441 | treeWidget.show(); |
3442 | QVERIFY(QTest::qWaitForWindowExposed(&treeWidget)); |
3443 | QCoreApplication::processEvents(); // Process all queued paint events |
3444 | |
3445 | QTreeWidgetItem *item = new QTreeWidgetItem(QStringList("Hello" )); |
3446 | treeWidget.insertTopLevelItem(index: 0, item); |
3447 | QTRY_VERIFY(delegate.numPaints > 0); |
3448 | |
3449 | delegate.numPaints = 0; |
3450 | delegate.expectChildren = true; |
3451 | item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); |
3452 | QTRY_COMPARE(delegate.numPaints, 1); |
3453 | |
3454 | delegate.numPaints = 0; |
3455 | delegate.expectChildren = false; |
3456 | item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); |
3457 | QTRY_COMPARE(delegate.numPaints, 1); |
3458 | |
3459 | delegate.numPaints = 0; |
3460 | delegate.expectChildren = true; |
3461 | new QTreeWidgetItem(item); |
3462 | QTRY_COMPARE(delegate.numPaints, 1); |
3463 | |
3464 | delegate.numPaints = 0; |
3465 | delegate.expectChildren = false; |
3466 | item->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); |
3467 | QTRY_COMPARE(delegate.numPaints, 1); |
3468 | } |
3469 | |
3470 | // From QTBUG_34717 (QTreeWidget crashes when scrolling to the end |
3471 | // of an expanded tree, then collapse all) |
3472 | // The test passes simply if it doesn't crash. |
3473 | void tst_QTreeWidget::taskQTBUG_34717_collapseAtBottom() |
3474 | { |
3475 | PublicTreeWidget treeWidget; |
3476 | treeWidget.header()->setSectionResizeMode(QHeaderView::ResizeToContents); |
3477 | treeWidget.setColumnCount(2); |
3478 | QTreeWidgetItem *mainItem = new QTreeWidgetItem(&treeWidget, { "Root" }); |
3479 | for (int i = 0; i < 200; ++i) { |
3480 | QTreeWidgetItem *item = new QTreeWidgetItem(mainItem, { "Item" }); |
3481 | new QTreeWidgetItem(item, { "Child" , "1" }); |
3482 | new QTreeWidgetItem(item, { "Child" , "2" }); |
3483 | new QTreeWidgetItem(item, { "Child" , "3" }); |
3484 | } |
3485 | treeWidget.show(); |
3486 | treeWidget.expandAll(); |
3487 | treeWidget.scrollToBottom(); |
3488 | treeWidget.collapseAll(); |
3489 | |
3490 | treeWidget.setAnimated(true); |
3491 | treeWidget.expandAll(); |
3492 | treeWidget.scrollToBottom(); |
3493 | mainItem->setExpanded(false); |
3494 | |
3495 | QVERIFY(treeWidget.sizeHintForColumn(1) >= 0); |
3496 | } |
3497 | |
3498 | void tst_QTreeWidget::task20345_sortChildren() |
3499 | { |
3500 | if (!QGuiApplication::platformName().compare(other: QLatin1String("wayland" ), cs: Qt::CaseInsensitive) |
3501 | || !QGuiApplication::platformName().compare(other: QLatin1String("winrt" ), cs: Qt::CaseInsensitive)) |
3502 | QSKIP("Wayland/WinRT: This causes a crash triggered by setVisible(false)" ); |
3503 | |
3504 | // This test case is considered successful if it is executed (no crash in sorting) |
3505 | QTreeWidget tw; |
3506 | tw.setColumnCount(3); |
3507 | tw.headerItem()->setText(column: 0, atext: "Col 0" ); |
3508 | tw.headerItem()->setText(column: 1, atext: "Col 1" ); |
3509 | tw.header()->setSortIndicator(logicalIndex: 0, order: Qt::AscendingOrder); |
3510 | tw.setSortingEnabled(true); |
3511 | tw.show(); |
3512 | |
3513 | auto rootItem = new QTreeWidgetItem(&tw, QStringList("a" )); |
3514 | auto childItem = new QTreeWidgetItem(rootItem); |
3515 | childItem->setText(column: 1, atext: "3" ); |
3516 | childItem = new QTreeWidgetItem(rootItem); |
3517 | childItem->setText(column: 1, atext: "1" ); |
3518 | childItem = new QTreeWidgetItem(rootItem); |
3519 | childItem->setText(column: 1, atext: "2" ); |
3520 | |
3521 | tw.setCurrentItem(tw.topLevelItem(index: 0)); |
3522 | |
3523 | QTreeWidgetItem *curItem = tw.currentItem(); |
3524 | int childCount = curItem->childCount() + 1; |
3525 | |
3526 | QTreeWidgetItem *newItem = new QTreeWidgetItem(curItem); |
3527 | newItem->setText(column: 1, atext: QString::number(childCount)); |
3528 | rootItem->sortChildren(column: 1, order: Qt::AscendingOrder); |
3529 | QVERIFY(1); |
3530 | } |
3531 | |
3532 | void tst_QTreeWidget::getMimeDataWithInvalidItem() |
3533 | { |
3534 | PublicTreeWidget w; |
3535 | QTest::ignoreMessage(type: QtWarningMsg, message: "QTreeWidget::mimeData: Null-item passed" ); |
3536 | QMimeData *md = w.mimeData(items: QList<QTreeWidgetItem*>() << nullptr); |
3537 | QVERIFY(!md); |
3538 | } |
3539 | |
3540 | // visualItemRect returned a wrong rect when the columns were moved |
3541 | // (-> logical index != visual index). see QTBUG-28733 |
3542 | void tst_QTreeWidget::testVisualItemRect() |
3543 | { |
3544 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
3545 | QSKIP("Wayland: This fails. Figure out why." ); |
3546 | |
3547 | QTreeWidget tw; |
3548 | tw.setColumnCount(2); |
3549 | QTreeWidgetItem *item = new QTreeWidgetItem(&tw); |
3550 | item->setText(column: 0, atext: "text 0" ); |
3551 | item->setText(column: 1, atext: "text 1" ); |
3552 | |
3553 | static const int sectionSize = 30; |
3554 | tw.header()->setStretchLastSection(false); |
3555 | tw.header()->setMinimumSectionSize(sectionSize); |
3556 | tw.header()->resizeSection(logicalIndex: 0, size: sectionSize); |
3557 | tw.header()->resizeSection(logicalIndex: 1, size: sectionSize); |
3558 | tw.setRootIsDecorated(false); |
3559 | tw.show(); |
3560 | QVERIFY(QTest::qWaitForWindowExposed(&tw)); |
3561 | |
3562 | QRect r = tw.visualItemRect(item); |
3563 | QCOMPARE(r.width(), sectionSize * 2); // 2 columns |
3564 | tw.header()->moveSection(from: 1, to: 0); |
3565 | r = tw.visualItemRect(item); |
3566 | QCOMPARE(r.width(), sectionSize * 2); // 2 columns |
3567 | tw.hideColumn(column: 0); |
3568 | r = tw.visualItemRect(item); |
3569 | QCOMPARE(r.width(), sectionSize); |
3570 | } |
3571 | |
3572 | void tst_QTreeWidget::reparentHiddenItem() |
3573 | { |
3574 | QTreeWidgetItem *parent = new QTreeWidgetItem(testWidget); |
3575 | parent->setText(column: 0, atext: "parent" ); |
3576 | QTreeWidgetItem *otherParent = new QTreeWidgetItem(testWidget); |
3577 | otherParent->setText(column: 0, atext: "other parent" ); |
3578 | QTreeWidgetItem *child = new QTreeWidgetItem(parent); |
3579 | child->setText(column: 0, atext: "child" ); |
3580 | QTreeWidgetItem *grandChild = new QTreeWidgetItem(child); |
3581 | grandChild->setText(column: 0, atext: "grandchild" ); |
3582 | QVERIFY(child->parent()); |
3583 | QVERIFY(grandChild->parent()); |
3584 | |
3585 | testWidget->expandItem(item: parent); |
3586 | testWidget->expandItem(item: otherParent); |
3587 | testWidget->expandItem(item: child); |
3588 | |
3589 | QVERIFY(!parent->isHidden()); |
3590 | QVERIFY(!child->isHidden()); |
3591 | QVERIFY(!grandChild->isHidden()); |
3592 | |
3593 | grandChild->setHidden(true); |
3594 | |
3595 | QVERIFY(grandChild->isHidden()); |
3596 | parent->removeChild(child); |
3597 | otherParent->addChild(child); |
3598 | QVERIFY(grandChild->isHidden()); |
3599 | } |
3600 | |
3601 | void tst_QTreeWidget::persistentChildIndex() // QTBUG-90030 |
3602 | { |
3603 | QTreeWidget tree; |
3604 | QTreeWidgetItem *toplevel = new QTreeWidgetItem(QStringList{QStringLiteral("toplevel" )}); |
3605 | tree.addTopLevelItem(item: toplevel); |
3606 | QModelIndex firstIndex = tree.model()->index(row: 0, column: 0); |
3607 | QTreeWidgetItem *child1 = new QTreeWidgetItem(QStringList{QStringLiteral("child1" )}); |
3608 | QTreeWidgetItem *child2 = new QTreeWidgetItem(QStringList{QStringLiteral("child2" )}); |
3609 | toplevel->addChildren(children: {child1, child2}); |
3610 | QPersistentModelIndex persistentIdx = tree.model()->index(row: 1, column: 0, parent: firstIndex); |
3611 | QCOMPARE(persistentIdx.data().toString(), QStringLiteral("child2" )); |
3612 | tree.model()->removeRows(row: 0, count: 1, parent: firstIndex); |
3613 | QCOMPARE(persistentIdx.data().toString(), QStringLiteral("child2" )); |
3614 | } |
3615 | |
3616 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) |
3617 | void tst_QTreeWidget::clearItemData() |
3618 | { |
3619 | QTreeWidget tree; |
3620 | QAbstractItemModel* model = tree.model(); |
3621 | QVERIFY(model->insertColumn(0)); |
3622 | QVERIFY(model->insertRow(0)); |
3623 | const QModelIndex parentIdx = model->index(0, 0); |
3624 | QVERIFY(model->insertColumn(0, parentIdx)); |
3625 | QVERIFY(model->insertRow(0, parentIdx)); |
3626 | const QModelIndex childIdx = model->index(0, 0, parentIdx); |
3627 | model->setData(parentIdx, QStringLiteral("parent" )); |
3628 | model->setData(parentIdx, QStringLiteral("parent" ), Qt::UserRole); |
3629 | model->setData(childIdx, QStringLiteral("child" )); |
3630 | QSignalSpy dataChangeSpy(model, &QAbstractItemModel::dataChanged); |
3631 | QVERIFY(dataChangeSpy.isValid()); |
3632 | QVERIFY(!model->clearItemData(QModelIndex())); |
3633 | QCOMPARE(dataChangeSpy.size(), 0); |
3634 | QVERIFY(model->clearItemData(parentIdx)); |
3635 | QVERIFY(!model->data(parentIdx).isValid()); |
3636 | QVERIFY(!model->data(parentIdx, Qt::UserRole).isValid()); |
3637 | QCOMPARE(dataChangeSpy.size(), 1); |
3638 | QList<QVariant> dataChangeArgs = dataChangeSpy.takeFirst(); |
3639 | QCOMPARE(dataChangeArgs.at(0).value<QModelIndex>(), parentIdx); |
3640 | QCOMPARE(dataChangeArgs.at(1).value<QModelIndex>(), parentIdx); |
3641 | QVERIFY(dataChangeArgs.at(2).value<QVector<int>>().isEmpty()); |
3642 | QVERIFY(model->clearItemData(parentIdx)); |
3643 | QCOMPARE(dataChangeSpy.size(), 0); |
3644 | QVERIFY(model->clearItemData(childIdx)); |
3645 | QVERIFY(!model->data(childIdx).isValid()); |
3646 | QCOMPARE(dataChangeSpy.size(), 1); |
3647 | dataChangeArgs = dataChangeSpy.takeFirst(); |
3648 | QCOMPARE(dataChangeArgs.at(0).value<QModelIndex>(), childIdx); |
3649 | QCOMPARE(dataChangeArgs.at(1).value<QModelIndex>(), childIdx); |
3650 | QVERIFY(dataChangeArgs.at(2).value<QVector<int>>().isEmpty()); |
3651 | } |
3652 | #endif |
3653 | |
3654 | QTEST_MAIN(tst_QTreeWidget) |
3655 | #include "tst_qtreewidget.moc" |
3656 | |