1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtreewidget.h"
5
6#include <qheaderview.h>
7#include <qpainter.h>
8#include <qstack.h>
9#include <qdebug.h>
10#include <private/qtreewidget_p.h>
11#include <private/qwidgetitemdata_p.h>
12#include <private/qtreewidgetitemiterator_p.h>
13
14#include <QtCore/private/qduplicatetracker_p.h>
15
16#include <algorithm>
17
18QT_BEGIN_NAMESPACE
19
20class QTreeModelLessThan
21{
22public:
23 inline bool operator()(QTreeWidgetItem *i1, QTreeWidgetItem *i2) const
24 { return *i1 < *i2; }
25};
26
27class QTreeModelGreaterThan
28{
29public:
30 inline bool operator()(QTreeWidgetItem *i1, QTreeWidgetItem *i2) const
31 { return *i2 < *i1; }
32};
33
34/*
35 \class QTreeModel
36 \brief The QTreeModel class manages the items stored in a tree view.
37
38 \ingroup model-view
39 \inmodule QtWidgets
40
41*/
42
43/*!
44 \enum QTreeWidgetItem::ChildIndicatorPolicy
45 \since 4.3
46
47 \value ShowIndicator The controls for expanding and collapsing will be shown for this item even if there are no children.
48 \value DontShowIndicator The controls for expanding and collapsing will never be shown even if there are children. If the node is forced open the user will not be able to expand or collapse the item.
49 \value DontShowIndicatorWhenChildless The controls for expanding and collapsing will be shown if the item contains children.
50*/
51
52/*!
53 \fn void QTreeWidgetItem::setDisabled(bool disabled)
54 \since 4.3
55
56 Disables the item if \a disabled is true; otherwise enables the item.
57
58 \sa setFlags()
59*/
60
61/*!
62 \fn bool QTreeWidgetItem::isDisabled() const
63 \since 4.3
64
65 Returns \c true if the item is disabled; otherwise returns \c false.
66
67 \sa setFlags()
68*/
69
70/*!
71 \internal
72
73 Constructs a tree model with a \a parent object and the given
74 number of \a columns.
75*/
76
77QTreeModel::QTreeModel(int columns, QTreeWidget *parent)
78 : QAbstractItemModel(*new QTreeModelPrivate, parent),
79 rootItem(new QTreeWidgetItem),
80 headerItem(new QTreeWidgetItem)
81{
82 rootItem->view = parent;
83 rootItem->itemFlags = Qt::ItemIsDropEnabled;
84 headerItem->view = parent;
85 setColumnCount(columns);
86}
87
88/*!
89 \internal
90
91*/
92
93QTreeModel::QTreeModel(QTreeModelPrivate &dd, QTreeWidget *parent)
94 : QAbstractItemModel(dd, parent), rootItem(new QTreeWidgetItem), headerItem(new QTreeWidgetItem)
95{
96 rootItem->view = parent;
97 rootItem->itemFlags = Qt::ItemIsDropEnabled;
98 headerItem->view = parent;
99}
100
101/*!
102 \internal
103
104 Destroys this tree model.
105*/
106
107QTreeModel::~QTreeModel()
108{
109 clear();
110 headerItem->view = nullptr;
111 delete headerItem;
112 rootItem->view = nullptr;
113 delete rootItem;
114}
115
116/*!
117 \internal
118
119 Removes all items in the model.
120*/
121
122void QTreeModel::clear()
123{
124 SkipSorting skipSorting(this);
125 beginResetModel();
126 for (int i = 0; i < rootItem->childCount(); ++i) {
127 QTreeWidgetItem *item = rootItem->children.at(i);
128 item->par = nullptr;
129 item->view = nullptr;
130 delete item;
131 }
132 rootItem->children.clear();
133 sortPendingTimer.stop();
134 endResetModel();
135}
136
137/*!
138 \internal
139
140 Sets the number of \a columns in the tree model.
141*/
142
143void QTreeModel::setColumnCount(int columns)
144{
145 SkipSorting skipSorting(this);
146 if (columns < 0)
147 return;
148 if (!headerItem) {
149 headerItem = new QTreeWidgetItem();
150 headerItem->view = view();
151 }
152 int count = columnCount();
153 if (count == columns)
154 return;
155
156 if (columns < count) {
157 beginRemoveColumns(parent: QModelIndex(), first: columns, last: count - 1);
158 headerItem->values.resize(size: columns);
159 endRemoveColumns();
160 } else {
161 beginInsertColumns(parent: QModelIndex(), first: count, last: columns - 1);
162 headerItem->values.resize(size: columns);
163 for (int i = count; i < columns; ++i) {// insert data without emitting the dataChanged signal
164 headerItem->values[i].append(t: QWidgetItemData(Qt::DisplayRole, QString::number(i + 1)));
165 headerItem->d->display.append(t: QString::number(i + 1));
166 }
167 endInsertColumns();
168 }
169}
170
171/*!
172 \internal
173
174 Returns the tree view item corresponding to the \a index given.
175
176 \sa QModelIndex
177*/
178
179QTreeWidgetItem *QTreeModel::item(const QModelIndex &index) const
180{
181 if (!index.isValid())
182 return nullptr;
183 return static_cast<QTreeWidgetItem*>(index.internalPointer());
184}
185
186/*!
187 \internal
188
189 Returns the model index that refers to the
190 tree view \a item and \a column.
191*/
192
193QModelIndex QTreeModel::index(const QTreeWidgetItem *item, int column) const
194{
195 executePendingSort();
196
197 if (!item || (item == rootItem))
198 return QModelIndex();
199 const QTreeWidgetItem *par = item->parent();
200 QTreeWidgetItem *itm = const_cast<QTreeWidgetItem*>(item);
201 if (!par)
202 par = rootItem;
203 int row;
204 int guess = item->d->rowGuess;
205 if (guess >= 0
206 && par->children.size() > guess
207 && par->children.at(i: guess) == itm) {
208 row = guess;
209 } else {
210 row = par->children.lastIndexOf(t: itm);
211 itm->d->rowGuess = row;
212 }
213 return createIndex(arow: row, acolumn: column, adata: itm);
214}
215
216/*!
217 \internal
218 \reimp
219
220 Returns the model index with the given \a row,
221 \a column and \a parent.
222*/
223
224QModelIndex QTreeModel::index(int row, int column, const QModelIndex &parent) const
225{
226 executePendingSort();
227
228 int c = columnCount(parent);
229 if (row < 0 || column < 0 || column >= c)
230 return QModelIndex();
231
232 QTreeWidgetItem *parentItem = parent.isValid() ? item(index: parent) : rootItem;
233 if (parentItem && row < parentItem->childCount()) {
234 QTreeWidgetItem *itm = parentItem->child(index: row);
235 if (itm)
236 return createIndex(arow: row, acolumn: column, adata: itm);
237 return QModelIndex();
238 }
239
240 return QModelIndex();
241}
242
243/*!
244 \internal
245 \reimp
246
247 Returns the parent model index of the index given as
248 the \a child.
249*/
250
251QModelIndex QTreeModel::parent(const QModelIndex &child) const
252{
253 SkipSorting skipSorting(this); //The reason we don't sort here is that this might be called from a valid QPersistentModelIndex
254 //We don't want it to become suddenly invalid
255
256 if (!child.isValid())
257 return QModelIndex();
258 QTreeWidgetItem *itm = static_cast<QTreeWidgetItem *>(child.internalPointer());
259 if (!itm || itm == rootItem)
260 return QModelIndex();
261 QTreeWidgetItem *parent = itm->parent();
262 return index(item: parent, column: 0);
263}
264
265/*!
266 \internal
267 \reimp
268
269 Returns the number of rows in the \a parent model index.
270*/
271
272int QTreeModel::rowCount(const QModelIndex &parent) const
273{
274 if (!parent.isValid())
275 return rootItem->childCount();
276
277 QTreeWidgetItem *parentItem = item(index: parent);
278 if (parentItem)
279 return parentItem->childCount();
280 return 0;
281}
282
283/*!
284 \internal
285 \reimp
286
287 Returns the number of columns in the item referred to by
288 the given \a index.
289*/
290
291int QTreeModel::columnCount(const QModelIndex &index) const
292{
293 Q_UNUSED(index);
294 if (!headerItem)
295 return 0;
296 return headerItem->columnCount();
297}
298
299bool QTreeModel::hasChildren(const QModelIndex &parent) const
300{
301 if (!parent.isValid())
302 return (rootItem->childCount() > 0);
303
304 QTreeWidgetItem *itm = item(index: parent);
305 if (!itm)
306 return false;
307 switch (itm->d->policy) {
308 case QTreeWidgetItem::ShowIndicator:
309 return true;
310 case QTreeWidgetItem::DontShowIndicator:
311 return false;
312 case QTreeWidgetItem::DontShowIndicatorWhenChildless:
313 return (itm->childCount() > 0);
314 }
315 return false;
316}
317
318/*!
319 \internal
320 \reimp
321
322 Returns the data corresponding to the given model \a index
323 and \a role.
324*/
325
326QVariant QTreeModel::data(const QModelIndex &index, int role) const
327{
328 if (!index.isValid())
329 return QVariant();
330 QTreeWidgetItem *itm = item(index);
331 if (itm)
332 return itm->data(column: index.column(), role);
333 return QVariant();
334}
335
336/*!
337 \internal
338 \reimp
339
340 Sets the data for the item specified by the \a index and \a role
341 to that referred to by the \a value.
342
343 Returns \c true if successful; otherwise returns \c false.
344*/
345
346bool QTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
347{
348 if (!index.isValid())
349 return false;
350 QTreeWidgetItem *itm = item(index);
351 if (itm) {
352 itm->setData(column: index.column(), role, value);
353 return true;
354 }
355 return false;
356}
357
358bool QTreeModel::clearItemData(const QModelIndex &index)
359{
360 if (!checkIndex(index, options: CheckIndexOption::IndexIsValid))
361 return false;
362 QTreeWidgetItem *itm = item(index);
363 if (!itm)
364 return false;
365 const auto beginIter = itm->values.at(i: index.column()).cbegin();
366 const auto endIter = itm->values.at(i: index.column()).cend();
367 if (std::all_of(first: beginIter, last: endIter, pred: [](const QWidgetItemData& data) -> bool { return !data.value.isValid(); })
368 && !itm->d->display.at(i: index.column()).isValid()) {
369 return true; //it's already cleared
370 }
371 itm->d->display[index.column()] = QVariant();
372 itm->values[index.column()].clear();
373 emit dataChanged(topLeft: index, bottomRight: index, roles: QList<int> {});
374 return true;
375}
376
377QMap<int, QVariant> QTreeModel::itemData(const QModelIndex &index) const
378{
379 QMap<int, QVariant> roles;
380 QTreeWidgetItem *itm = item(index);
381 if (itm) {
382 int column = index.column();
383 if (column < itm->values.size()) {
384 for (int i = 0; i < itm->values.at(i: column).size(); ++i) {
385 roles.insert(key: itm->values.at(i: column).at(i).role,
386 value: itm->values.at(i: column).at(i).value);
387 }
388 }
389
390 // the two special cases
391 QVariant displayValue = itm->data(column, role: Qt::DisplayRole);
392 if (displayValue.isValid())
393 roles.insert(key: Qt::DisplayRole, value: displayValue);
394
395 QVariant checkValue = itm->data(column, role: Qt::CheckStateRole);
396 if (checkValue.isValid())
397 roles.insert(key: Qt::CheckStateRole, value: checkValue);
398 }
399 return roles;
400}
401
402/*!
403 \internal
404 \reimp
405*/
406bool QTreeModel::insertRows(int row, int count, const QModelIndex &parent)
407{
408 SkipSorting skipSorting(this);
409 if (count < 1 || row < 0 || row > rowCount(parent) || parent.column() > 0)
410 return false;
411
412 beginInsertRows(parent, first: row, last: row + count - 1);
413 QTreeWidgetItem *par = item(index: parent);
414 while (count > 0) {
415 QTreeWidgetItem *item = new QTreeWidgetItem();
416 item->view = view();
417 item->par = par;
418 if (par)
419 par->children.insert(i: row++, t: item);
420 else
421 rootItem->children.insert(i: row++, t: item);
422 --count;
423 }
424 endInsertRows();
425 return true;
426}
427
428/*!
429 \internal
430 \reimp
431*/
432bool QTreeModel::insertColumns(int column, int count, const QModelIndex &parent)
433{
434 SkipSorting skipSorting(this);
435 if (count < 1 || column < 0 || column > columnCount(index: parent) || parent.column() > 0 || !headerItem)
436 return false;
437
438 beginInsertColumns(parent, first: column, last: column + count - 1);
439
440 int oldCount = columnCount(index: parent);
441 column = qBound(min: 0, val: column, max: oldCount);
442 headerItem->values.resize(size: oldCount + count);
443 for (int i = oldCount; i < oldCount + count; ++i) {
444 headerItem->values[i].append(t: QWidgetItemData(Qt::DisplayRole, QString::number(i + 1)));
445 headerItem->d->display.append(t: QString::number(i + 1));
446 }
447
448 QStack<QTreeWidgetItem*> itemstack;
449 itemstack.push(t: 0);
450 while (!itemstack.isEmpty()) {
451 QTreeWidgetItem *par = itemstack.pop();
452 QList<QTreeWidgetItem*> children = par ? par->children : rootItem->children;
453 for (int row = 0; row < children.size(); ++row) {
454 QTreeWidgetItem *child = children.at(i: row);
455 if (child->children.size())
456 itemstack.push(t: child);
457 child->values.insert(i: column, n: count, t: QList<QWidgetItemData>());
458 }
459 }
460
461 endInsertColumns();
462 return true;
463}
464
465/*!
466 \internal
467 \reimp
468*/
469bool QTreeModel::removeRows(int row, int count, const QModelIndex &parent) {
470 if (count < 1 || row < 0 || (row + count) > rowCount(parent))
471 return false;
472 QTreeWidgetItem *parentItem = item(index: parent);
473 // if parentItem is valid, begin/end RemoveRows is handled by takeChild below
474 if (!parentItem)
475 beginRemoveRows(parent, first: row, last: row + count - 1);
476 for (int i = row + count - 1; i >= row; --i) {
477 QTreeWidgetItem *child = parentItem ? parentItem->takeChild(index: i) : rootItem->children.takeAt(i);
478 Q_ASSERT(child);
479 child->view = nullptr;
480 delete child;
481 }
482 if (!parentItem)
483 endRemoveRows();
484 return true;
485}
486
487/*!
488 \internal
489 \reimp
490
491 Returns the header data corresponding to the given header \a section,
492 \a orientation and data \a role.
493*/
494
495QVariant QTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
496{
497 if (orientation != Qt::Horizontal)
498 return QVariant();
499
500 if (headerItem)
501 return headerItem->data(column: section, role);
502 if (role == Qt::DisplayRole)
503 return QString::number(section + 1);
504 return QVariant();
505}
506
507/*!
508 \internal
509 \reimp
510
511 Sets the header data for the item specified by the header \a section,
512 \a orientation and data \a role to the given \a value.
513
514 Returns \c true if successful; otherwise returns \c false.
515*/
516
517bool QTreeModel::setHeaderData(int section, Qt::Orientation orientation,
518 const QVariant &value, int role)
519{
520 if (section < 0 || orientation != Qt::Horizontal || !headerItem || section >= columnCount())
521 return false;
522
523 headerItem->setData(column: section, role, value);
524 return true;
525}
526
527/*!
528 \reimp
529
530 Returns the flags for the item referred to the given \a index.
531
532*/
533
534Qt::ItemFlags QTreeModel::flags(const QModelIndex &index) const
535{
536 if (!index.isValid())
537 return rootItem->flags();
538 QTreeWidgetItem *itm = item(index);
539 Q_ASSERT(itm);
540 return itm->flags();
541}
542
543/*!
544 \internal
545
546 Sorts the entire tree in the model in the given \a order,
547 by the values in the given \a column.
548*/
549
550void QTreeModel::sort(int column, Qt::SortOrder order)
551{
552 SkipSorting skipSorting(this);
553 sortPendingTimer.stop();
554
555 if (column < 0 || column >= columnCount())
556 return;
557
558 //layoutAboutToBeChanged and layoutChanged will be called by sortChildren
559 rootItem->sortChildren(column, order, climb: true);
560}
561
562/*!
563 \internal
564*/
565void QTreeModel::ensureSorted(int column, Qt::SortOrder order,
566 int start, int end, const QModelIndex &parent)
567{
568 if (isChanging())
569 return;
570
571 sortPendingTimer.stop();
572
573 if (column < 0 || column >= columnCount())
574 return;
575
576 SkipSorting skipSorting(this);
577
578 QTreeWidgetItem *itm = item(index: parent);
579 if (!itm)
580 itm = rootItem;
581 QList<QTreeWidgetItem*> lst = itm->children;
582
583 int count = end - start + 1;
584 QList<QPair<QTreeWidgetItem *, int>> sorting(count);
585 for (int i = 0; i < count; ++i) {
586 sorting[i].first = lst.at(i: start + i);
587 sorting[i].second = start + i;
588 }
589
590 const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
591 std::stable_sort(first: sorting.begin(), last: sorting.end(), comp: compare);
592
593 QModelIndexList oldPersistentIndexes;
594 QModelIndexList newPersistentIndexes;
595 QList<QTreeWidgetItem*>::iterator lit = lst.begin();
596 bool changed = false;
597
598 for (int i = 0; i < count; ++i) {
599 int oldRow = sorting.at(i).second;
600
601 int tmpitepos = lit - lst.begin();
602 QTreeWidgetItem *item = lst.takeAt(i: oldRow);
603 if (tmpitepos > lst.size())
604 --tmpitepos;
605 lit = lst.begin() + tmpitepos;
606
607 lit = sortedInsertionIterator(begin: lit, end: lst.end(), order, item);
608 int newRow = qMax<qsizetype>(a: lit - lst.begin(), b: 0);
609
610 if ((newRow < oldRow) && !(*item < *lst.at(i: oldRow - 1)) && !(*lst.at(i: oldRow - 1) < *item ))
611 newRow = oldRow;
612
613 lit = lst.insert(before: lit, t: item);
614 if (newRow != oldRow) {
615 // we are going to change the persistent indexes, so we need to prepare
616 if (!changed) { // this will only happen once
617 changed = true;
618 emit layoutAboutToBeChanged(parents: {parent}, hint: QAbstractItemModel::VerticalSortHint); // the selection model needs to know
619 oldPersistentIndexes = persistentIndexList();
620 newPersistentIndexes = oldPersistentIndexes;
621 }
622 for (int j = i + 1; j < count; ++j) {
623 int otherRow = sorting.at(i: j).second;
624 if (oldRow < otherRow && newRow >= otherRow)
625 --sorting[j].second;
626 else if (oldRow > otherRow && newRow <= otherRow)
627 ++sorting[j].second;
628 }
629 for (int k = 0; k < newPersistentIndexes.size(); ++k) {
630 QModelIndex pi = newPersistentIndexes.at(i: k);
631 if (pi.parent() != parent)
632 continue;
633 int oldPersistentRow = pi.row();
634 int newPersistentRow = oldPersistentRow;
635 if (oldPersistentRow == oldRow)
636 newPersistentRow = newRow;
637 else if (oldRow < oldPersistentRow && newRow >= oldPersistentRow)
638 newPersistentRow = oldPersistentRow - 1;
639 else if (oldRow > oldPersistentRow && newRow <= oldPersistentRow)
640 newPersistentRow = oldPersistentRow + 1;
641 if (newPersistentRow != oldPersistentRow)
642 newPersistentIndexes[k] = createIndex(arow: newPersistentRow,
643 acolumn: pi.column(), adata: pi.internalPointer());
644 }
645 }
646 }
647
648 if (changed) {
649 itm->children = lst;
650 changePersistentIndexList(from: oldPersistentIndexes, to: newPersistentIndexes);
651 emit layoutChanged(parents: {parent}, hint: QAbstractItemModel::VerticalSortHint);
652 }
653}
654
655/*!
656 \internal
657
658 Returns \c true if the value of the \a left item is
659 less than the value of the \a right item.
660
661 Used by the sorting functions.
662*/
663
664bool QTreeModel::itemLessThan(const QPair<QTreeWidgetItem*,int> &left,
665 const QPair<QTreeWidgetItem*,int> &right)
666{
667 return *(left.first) < *(right.first);
668}
669
670/*!
671 \internal
672
673 Returns \c true if the value of the \a left item is
674 greater than the value of the \a right item.
675
676 Used by the sorting functions.
677*/
678
679bool QTreeModel::itemGreaterThan(const QPair<QTreeWidgetItem*,int> &left,
680 const QPair<QTreeWidgetItem*,int> &right)
681{
682 return *(right.first) < *(left.first);
683}
684
685/*!
686 \internal
687*/
688QList<QTreeWidgetItem*>::iterator QTreeModel::sortedInsertionIterator(
689 const QList<QTreeWidgetItem*>::iterator &begin,
690 const QList<QTreeWidgetItem*>::iterator &end,
691 Qt::SortOrder order, QTreeWidgetItem *item)
692{
693 if (order == Qt::AscendingOrder)
694 return std::lower_bound(first: begin, last: end, val: item, comp: QTreeModelLessThan());
695 return std::lower_bound(first: begin, last: end, val: item, comp: QTreeModelGreaterThan());
696}
697
698QStringList QTreeModel::mimeTypes() const
699{
700 auto v = view();
701 if (v)
702 return v->mimeTypes();
703 return {};
704}
705
706QMimeData *QTreeModel::internalMimeData() const
707{
708 return QAbstractItemModel::mimeData(indexes: cachedIndexes);
709}
710
711QMimeData *QTreeModel::mimeData(const QModelIndexList &indexes) const
712{
713 QList<QTreeWidgetItem *> items;
714 std::transform(first: indexes.begin(), last: indexes.end(), result: std::back_inserter(x&: items),
715 unary_op: [this](const QModelIndex &idx) -> QTreeWidgetItem * { return item(index: idx); });
716
717 // Ensure we only have one item as an item may have more than
718 // one index selected if there is more than one column
719 std::sort(first: items.begin(), last: items.end());
720 items.erase(abegin: std::unique(first: items.begin(), last: items.end()), aend: items.end());
721
722 // cachedIndexes is a little hack to avoid copying from QModelIndexList to
723 // QList<QTreeWidgetItem*> and back again in the view
724 cachedIndexes = indexes;
725 QMimeData *mimeData = view()->mimeData(items);
726 cachedIndexes.clear();
727 return mimeData;
728}
729
730bool QTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
731 int row, int column, const QModelIndex &parent)
732{
733 if (row == -1 && column == -1)
734 row = rowCount(parent); // append
735 return view()->dropMimeData(parent: item(index: parent), index: row, data, action);
736}
737
738Qt::DropActions QTreeModel::supportedDropActions() const
739{
740 return view()->supportedDropActions();
741}
742
743void QTreeModel::itemChanged(QTreeWidgetItem *item)
744{
745 SkipSorting skipSorting(this); //this is kind of wrong, but not doing this would kill performance
746 QModelIndex left = index(item, column: 0);
747 QModelIndex right = index(item, column: item->columnCount() - 1);
748 emit dataChanged(topLeft: left, bottomRight: right);
749}
750
751bool QTreeModel::isChanging() const
752{
753 Q_D(const QTreeModel);
754 return !d->changes.isEmpty();
755}
756
757/*!
758 \internal
759 Emits the dataChanged() signal for the given \a item.
760 if column is -1 then all columns have changed
761*/
762
763void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column, const QList<int> &roles)
764{
765 if (signalsBlocked())
766 return;
767
768 if (headerItem == item && column < item->columnCount()) {
769 if (column == -1)
770 emit headerDataChanged(orientation: Qt::Horizontal, first: 0, last: columnCount() - 1);
771 else
772 emit headerDataChanged(orientation: Qt::Horizontal, first: column, last: column);
773 return;
774 }
775
776 SkipSorting skipSorting(this); //This is a little bit wrong, but not doing it would kill performance
777
778 QModelIndex bottomRight, topLeft;
779 if (column == -1) {
780 topLeft = index(item, column: 0);
781 bottomRight = createIndex(arow: topLeft.row(), acolumn: columnCount() - 1, adata: item);
782 } else {
783 topLeft = index(item, column);
784 bottomRight = topLeft;
785 }
786 emit dataChanged(topLeft, bottomRight, roles);
787}
788
789void QTreeModel::beginInsertItems(QTreeWidgetItem *parent, int row, int count)
790{
791 QModelIndex par = index(item: parent, column: 0);
792 beginInsertRows(parent: par, first: row, last: row + count - 1);
793}
794
795void QTreeModel::endInsertItems()
796{
797 endInsertRows();
798}
799
800void QTreeModel::beginRemoveItems(QTreeWidgetItem *parent, int row, int count)
801{
802 Q_ASSERT(row >= 0);
803 Q_ASSERT(count > 0);
804 beginRemoveRows(parent: index(item: parent, column: 0), first: row, last: row + count - 1);
805 if (!parent)
806 parent = rootItem;
807 // now update the iterators
808 for (int i = 0; i < iterators.size(); ++i) {
809 for (int j = 0; j < count; j++) {
810 QTreeWidgetItem *c = parent->child(index: row + j);
811 iterators[i]->d_func()->ensureValidIterator(itemToBeRemoved: c);
812 }
813 }
814}
815
816void QTreeModel::endRemoveItems()
817{
818 endRemoveRows();
819}
820
821void QTreeModel::sortItems(QList<QTreeWidgetItem*> *items, int column, Qt::SortOrder order)
822{
823 // see QTreeViewItem::operator<
824 Q_UNUSED(column);
825 if (isChanging())
826 return;
827
828 // store the original order of indexes
829 QList<QPair<QTreeWidgetItem *, int>> sorting(items->size());
830 for (int i = 0; i < sorting.size(); ++i) {
831 sorting[i].first = items->at(i);
832 sorting[i].second = i;
833 }
834
835 // do the sorting
836 const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
837 std::stable_sort(first: sorting.begin(), last: sorting.end(), comp: compare);
838
839 QModelIndexList fromList;
840 QModelIndexList toList;
841 int colCount = columnCount();
842 for (int r = 0; r < sorting.size(); ++r) {
843 int oldRow = sorting.at(i: r).second;
844 if (oldRow == r)
845 continue;
846 QTreeWidgetItem *item = sorting.at(i: r).first;
847 items->replace(i: r, t: item);
848 for (int c = 0; c < colCount; ++c) {
849 QModelIndex from = createIndex(arow: oldRow, acolumn: c, adata: item);
850 if (static_cast<QAbstractItemModelPrivate *>(d_ptr.data())->persistent.indexes.contains(key: from)) {
851 QModelIndex to = createIndex(arow: r, acolumn: c, adata: item);
852 fromList << from;
853 toList << to;
854 }
855 }
856 }
857 changePersistentIndexList(from: fromList, to: toList);
858}
859
860void QTreeModel::timerEvent(QTimerEvent *ev)
861{
862 if (ev->timerId() == sortPendingTimer.timerId()) {
863 executePendingSort();
864 } else {
865 QAbstractItemModel::timerEvent(event: ev);
866 }
867}
868
869/*!
870 \class QTreeWidgetItem
871
872 \brief The QTreeWidgetItem class provides an item for use with the
873 QTreeWidget convenience class.
874
875 \ingroup model-view
876 \inmodule QtWidgets
877
878 Tree widget items are used to hold rows of information for tree widgets.
879 Rows usually contain several columns of data, each of which can contain
880 a text label and an icon.
881
882 The QTreeWidgetItem class is a convenience class that replaces the
883 QListViewItem class in Qt 3. It provides an item for use with
884 the QTreeWidget class.
885
886 Items are usually constructed with a parent that is either a QTreeWidget
887 (for top-level items) or a QTreeWidgetItem (for items on lower levels of
888 the tree). For example, the following code constructs a top-level item
889 to represent cities of the world, and adds a entry for Oslo as a child
890 item:
891
892 \snippet qtreewidget-using/mainwindow.cpp 3
893
894 Items can be added in a particular order by specifying the item they
895 follow when they are constructed:
896
897 \snippet qtreewidget-using/mainwindow.cpp 5
898
899 Each column in an item can have its own background brush which is set with
900 the setBackground() function. The current background brush can be
901 found with background().
902 The text label for each column can be rendered with its own font and brush.
903 These are specified with the setFont() and setForeground() functions,
904 and read with font() and foreground().
905
906 The main difference between top-level items and those in lower levels of
907 the tree is that a top-level item has no parent(). This information
908 can be used to tell the difference between items, and is useful to know
909 when inserting and removing items from the tree.
910 Children of an item can be removed with takeChild() and inserted at a
911 given index in the list of children with the insertChild() function.
912
913 By default, items are enabled, selectable, checkable, and can be the source
914 of a drag and drop operation.
915 Each item's flags can be changed by calling setFlags() with the appropriate
916 value (see \l{Qt::ItemFlags}). Checkable items can be checked and unchecked
917 with the setCheckState() function. The corresponding checkState() function
918 indicates whether the item is currently checked.
919
920 \section1 Subclassing
921
922 When subclassing QTreeWidgetItem to provide custom items, it is possible to
923 define new types for them so that they can be distinguished from standard
924 items. The constructors for subclasses that require this feature need to
925 call the base class constructor with a new type value equal to or greater
926 than \l UserType.
927
928 \sa QTreeWidget, QTreeWidgetItemIterator, {Model/View Programming},
929 QListWidgetItem, QTableWidgetItem
930*/
931
932/*!
933 \enum QTreeWidgetItem::ItemType
934
935 This enum describes the types that are used to describe tree widget items.
936
937 \value Type The default type for tree widget items.
938 \value UserType The minimum value for custom types. Values below UserType are
939 reserved by Qt.
940
941 You can define new user types in QTreeWidgetItem subclasses to ensure that
942 custom items are treated specially; for example, when items are sorted.
943
944 \sa type()
945*/
946
947/*!
948 \fn int QTreeWidgetItem::type() const
949
950 Returns the type passed to the QTreeWidgetItem constructor.
951*/
952
953/*!
954 \fn void QTreeWidgetItem::sortChildren(int column, Qt::SortOrder order)
955 \since 4.2
956
957 Sorts the children of the item using the given \a order,
958 by the values in the given \a column.
959
960 \note This function does nothing if the item is not associated with a
961 QTreeWidget.
962*/
963
964/*!
965 \fn QTreeWidget *QTreeWidgetItem::treeWidget() const
966
967 Returns the tree widget that contains the item.
968*/
969
970/*!
971 \fn void QTreeWidgetItem::setSelected(bool select)
972 \since 4.2
973
974 Sets the selected state of the item to \a select.
975
976 \sa isSelected()
977*/
978void QTreeWidgetItem::setSelected(bool select)
979{
980 const QTreeModel *model = treeModel();
981 if (!model || !view->selectionModel())
982 return;
983 const QModelIndex index = model->index(item: this, column: 0);
984 view->selectionModel()->select(index, command: (select ? QItemSelectionModel::Select
985 : QItemSelectionModel::Deselect)
986 | QItemSelectionModel::Rows);
987 d->selected = select;
988}
989
990/*!
991 \fn bool QTreeWidgetItem::isSelected() const
992 \since 4.2
993
994 Returns \c true if the item is selected, otherwise returns \c false.
995
996 \sa setSelected()
997*/
998bool QTreeWidgetItem::isSelected() const
999{
1000 return d->selected;
1001}
1002
1003/*!
1004 \fn void QTreeWidgetItem::setHidden(bool hide)
1005 \since 4.2
1006
1007 Hides the item if \a hide is true, otherwise shows the item.
1008 \note A call to this function has no effect if the item is not currently in a view. In particular,
1009 calling \c setHidden(true) on an item and only then adding it to a view will result in
1010 a visible item.
1011
1012 \sa isHidden()
1013*/
1014
1015void QTreeWidgetItem::setHidden(bool hide)
1016{
1017 const QTreeModel *model = treeModel();
1018 if (!model)
1019 return;
1020 if (this == model->headerItem) {
1021 view->header()->setHidden(hide);
1022 } else {
1023 const QModelIndex index = view->d_func()->index(item: this);
1024 view->setRowHidden(row: index.row(), parent: index.parent(), hide);
1025 }
1026 d->hidden = hide;
1027}
1028
1029/*!
1030 \fn bool QTreeWidgetItem::isHidden() const
1031 \since 4.2
1032
1033 Returns \c true if the item is hidden, otherwise returns \c false.
1034
1035 \sa setHidden()
1036*/
1037
1038bool QTreeWidgetItem::isHidden() const
1039{
1040 const QTreeModel *model = treeModel();
1041 if (!model)
1042 return false;
1043 if (this == model->headerItem)
1044 return view->header()->isHidden();
1045 if (view->d_func()->hiddenIndexes.isEmpty())
1046 return false;
1047 QTreeModel::SkipSorting skipSorting(model);
1048 return view->d_func()->isRowHidden(idx: view->d_func()->index(item: this));
1049}
1050
1051/*!
1052 \fn void QTreeWidgetItem::setExpanded(bool expand)
1053 \since 4.2
1054
1055 Expands the item if \a expand is true, otherwise collapses the item.
1056 \warning The QTreeWidgetItem must be added to the QTreeWidget before calling this function.
1057
1058 \sa isExpanded()
1059*/
1060void QTreeWidgetItem::setExpanded(bool expand)
1061{
1062 const QTreeModel *model = treeModel();
1063 if (!model)
1064 return;
1065 QTreeModel::SkipSorting skipSorting(model);
1066 view->setExpanded(index: view->d_func()->index(item: this), expand);
1067}
1068
1069/*!
1070 \fn bool QTreeWidgetItem::isExpanded() const
1071 \since 4.2
1072
1073 Returns \c true if the item is expanded, otherwise returns \c false.
1074
1075 \sa setExpanded()
1076*/
1077bool QTreeWidgetItem::isExpanded() const
1078{
1079 const QTreeModel *model = treeModel();
1080 if (!model)
1081 return false;
1082 QTreeModel::SkipSorting skipSorting(model);
1083 return view->isExpanded(index: view->d_func()->index(item: this));
1084}
1085
1086/*!
1087 \fn void QTreeWidgetItem::setFirstColumnSpanned(bool span)
1088 \since 4.3
1089
1090 Sets the first section to span all columns if \a span is true;
1091 otherwise all item sections are shown.
1092
1093 \sa isFirstColumnSpanned()
1094*/
1095void QTreeWidgetItem::setFirstColumnSpanned(bool span)
1096{
1097 const QTreeModel *model = treeModel();
1098 if (!model || this == model->headerItem)
1099 return; // We can't set the header items to spanning
1100 const QModelIndex index = model->index(item: this, column: 0);
1101 view->setFirstColumnSpanned(row: index.row(), parent: index.parent(), span);
1102}
1103
1104/*!
1105 \fn bool QTreeWidgetItem::isFirstColumnSpanned() const
1106 \since 4.3
1107
1108 Returns \c true if the item is spanning all the columns in a row; otherwise returns \c false.
1109
1110 \sa setFirstColumnSpanned()
1111*/
1112bool QTreeWidgetItem::isFirstColumnSpanned() const
1113{
1114 const QTreeModel *model = treeModel();
1115 if (!model || this == model->headerItem)
1116 return false;
1117 const QModelIndex index = model->index(item: this, column: 0);
1118 return view->isFirstColumnSpanned(row: index.row(), parent: index.parent());
1119}
1120
1121/*!
1122 \fn QString QTreeWidgetItem::text(int column) const
1123
1124 Returns the text in the specified \a column.
1125
1126 \sa setText()
1127*/
1128
1129/*!
1130 \fn void QTreeWidgetItem::setText(int column, const QString &text)
1131
1132 Sets the text to be displayed in the given \a column to the given \a text.
1133
1134 \sa text(), setFont(), setForeground()
1135*/
1136
1137/*!
1138 \fn QIcon QTreeWidgetItem::icon(int column) const
1139
1140 Returns the icon that is displayed in the specified \a column.
1141
1142 \sa setIcon(), {QAbstractItemView::iconSize}{iconSize}
1143*/
1144
1145/*!
1146 \fn void QTreeWidgetItem::setIcon(int column, const QIcon &icon)
1147
1148 Sets the icon to be displayed in the given \a column to \a icon.
1149
1150 \sa icon(), setText(), {QAbstractItemView::iconSize}{iconSize}
1151*/
1152
1153/*!
1154 \fn QString QTreeWidgetItem::statusTip(int column) const
1155
1156 Returns the status tip for the contents of the given \a column.
1157
1158 \sa setStatusTip()
1159*/
1160
1161/*!
1162 \fn void QTreeWidgetItem::setStatusTip(int column, const QString &statusTip)
1163
1164 Sets the status tip for the given \a column to the given \a statusTip.
1165 QTreeWidget mouse tracking needs to be enabled for this feature to work.
1166
1167 \sa statusTip(), setToolTip(), setWhatsThis()
1168*/
1169
1170/*!
1171 \fn QString QTreeWidgetItem::toolTip(int column) const
1172
1173 Returns the tool tip for the given \a column.
1174
1175 \sa setToolTip()
1176*/
1177
1178/*!
1179 \fn void QTreeWidgetItem::setToolTip(int column, const QString &toolTip)
1180
1181 Sets the tooltip for the given \a column to \a toolTip.
1182
1183 \sa toolTip(), setStatusTip(), setWhatsThis()
1184*/
1185
1186/*!
1187 \fn QString QTreeWidgetItem::whatsThis(int column) const
1188
1189 Returns the "What's This?" help for the contents of the given \a column.
1190
1191 \sa setWhatsThis()
1192*/
1193
1194/*!
1195 \fn void QTreeWidgetItem::setWhatsThis(int column, const QString &whatsThis)
1196
1197 Sets the "What's This?" help for the given \a column to \a whatsThis.
1198
1199 \sa whatsThis(), setStatusTip(), setToolTip()
1200*/
1201
1202/*!
1203 \fn QFont QTreeWidgetItem::font(int column) const
1204
1205 Returns the font used to render the text in the specified \a column.
1206
1207 \sa setFont()
1208*/
1209
1210/*!
1211 \fn void QTreeWidgetItem::setFont(int column, const QFont &font)
1212
1213 Sets the font used to display the text in the given \a column to the given
1214 \a font.
1215
1216 \sa font(), setText(), setForeground()
1217*/
1218
1219/*!
1220 \fn QBrush QTreeWidgetItem::background(int column) const
1221 \since 4.2
1222
1223 Returns the brush used to render the background of the specified \a column.
1224
1225 \sa foreground()
1226*/
1227
1228/*!
1229 \fn void QTreeWidgetItem::setBackground(int column, const QBrush &brush)
1230 \since 4.2
1231
1232 Sets the background brush of the label in the given \a column to the
1233 specified \a brush.
1234 Setting a default-constructed brush will let the view use the
1235 default color from the style.
1236
1237 \note If \l{Qt Style Sheets} are used on the same widget as setBackground(),
1238 style sheets will take precedence if the settings conflict.
1239
1240 \sa setForeground()
1241*/
1242
1243
1244/*!
1245 \fn QBrush QTreeWidgetItem::foreground(int column) const
1246 \since 4.2
1247
1248 Returns the brush used to render the foreground (e.g. text) of the
1249 specified \a column.
1250 Setting a default-constructed brush will let the view use the
1251 default color from the style.
1252
1253 \sa background()
1254*/
1255
1256/*!
1257 \fn void QTreeWidgetItem::setForeground(int column, const QBrush &brush)
1258 \since 4.2
1259
1260 Sets the foreground brush of the label in the given \a column to the
1261 specified \a brush.
1262
1263 \sa setBackground()
1264*/
1265
1266/*!
1267 \fn Qt::CheckState QTreeWidgetItem::checkState(int column) const
1268
1269 Returns the check state of the label in the given \a column.
1270
1271 \sa Qt::CheckState
1272*/
1273
1274/*!
1275 \fn void QTreeWidgetItem::setCheckState(int column, Qt::CheckState state)
1276
1277 Sets the item in the given \a column check state to be \a state.
1278
1279 \sa checkState()
1280*/
1281
1282/*!
1283 \fn QSize QTreeWidgetItem::sizeHint(int column) const
1284 \since 4.1
1285
1286 Returns the size hint set for the tree item in the given
1287 \a column (see \l{QSize}).
1288*/
1289
1290/*!
1291 \fn void QTreeWidgetItem::setSizeHint(int column, const QSize &size)
1292 \since 4.1
1293
1294 Sets the size hint for the tree item in the given \a column to be \a size.
1295 If no size hint is set or \a size is invalid, the item
1296 delegate will compute the size hint based on the item data.
1297*/
1298
1299/*!
1300 \fn QTreeWidgetItem *QTreeWidgetItem::parent() const
1301
1302 Returns the item's parent.
1303
1304 \sa child()
1305*/
1306
1307/*!
1308 \fn QTreeWidgetItem *QTreeWidgetItem::child(int index) const
1309
1310 Returns the item at the given \a index in the list of the item's children.
1311
1312 \sa parent()
1313*/
1314
1315/*!
1316 \fn int QTreeWidgetItem::childCount() const
1317
1318 Returns the number of child items.
1319*/
1320
1321/*!
1322 \fn int QTreeWidgetItem::columnCount() const
1323
1324 Returns the number of columns in the item.
1325*/
1326
1327/*!
1328 \if defined(qt7)
1329
1330 \fn Qt::Alignment QTreeWidgetItem::textAlignment(int column) const
1331
1332 Returns the text alignment for the label in the given \a column.
1333
1334 \else
1335
1336 \fn int QTreeWidgetItem::textAlignment(int column) const
1337
1338 Returns the text alignment for the label in the given \a column.
1339
1340 \note This function returns an int for historical reasons. It will
1341 be corrected to return Qt::Alignment in Qt 7.
1342
1343 \sa Qt::Alignment
1344
1345 \endif
1346*/
1347
1348/*!
1349 \obsolete [6.4] Use the overload that takes a Qt::Alignment argument.
1350
1351 \fn void QTreeWidgetItem::setTextAlignment(int column, int alignment)
1352
1353 Sets the text alignment for the label in the given \a column to
1354 the \a alignment specified.
1355
1356 \sa Qt::Alignment
1357*/
1358
1359/*!
1360 \since 6.4
1361
1362 \fn void QTreeWidgetItem::setTextAlignment(int column, Qt::Alignment alignment)
1363
1364 Sets the text alignment for the label in the given \a column to
1365 the \a alignment specified.
1366*/
1367
1368/*!
1369 \fn void QTreeWidgetItem::setTextAlignment(int column, Qt::AlignmentFlag alignment)
1370 \internal
1371*/
1372
1373/*!
1374 \fn int QTreeWidgetItem::indexOfChild(QTreeWidgetItem *child) const
1375
1376 Returns the index of the given \a child in the item's list of children.
1377*/
1378
1379/*!
1380 Constructs a tree widget item of the specified \a type. The item
1381 must be inserted into a tree widget.
1382
1383 \sa type()
1384*/
1385QTreeWidgetItem::QTreeWidgetItem(int type) : rtti(type), d(new QTreeWidgetItemPrivate(this)) { }
1386
1387/*!
1388 Constructs a tree widget item of the specified \a type. The item
1389 must be inserted into a tree widget.
1390 The given list of \a strings will be set as the item text for each
1391 column in the item.
1392
1393 \sa type()
1394*/
1395QTreeWidgetItem::QTreeWidgetItem(const QStringList &strings, int type)
1396 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1397{
1398 for (int i = 0; i < strings.size(); ++i)
1399 setText(column: i, atext: strings.at(i));
1400}
1401
1402/*!
1403 \fn QTreeWidgetItem::QTreeWidgetItem(QTreeWidget *parent, int type)
1404
1405 Constructs a tree widget item of the specified \a type and appends it
1406 to the items in the given \a parent.
1407
1408 \sa type()
1409*/
1410
1411QTreeWidgetItem::QTreeWidgetItem(QTreeWidget *treeview, int type)
1412 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1413{
1414 // do not set this->view here otherwise insertChild() will fail
1415 if (QTreeModel *model = treeModel(v: treeview)) {
1416 model->rootItem->addChild(child: this);
1417 values.reserve(asize: model->headerItem->columnCount());
1418 }
1419}
1420
1421/*!
1422 \fn QTreeWidgetItem::QTreeWidgetItem(QTreeWidget *parent, const QStringList &strings, int type)
1423
1424 Constructs a tree widget item of the specified \a type and appends it
1425 to the items in the given \a parent. The given list of \a strings will be set as
1426 the item text for each column in the item.
1427
1428 \sa type()
1429*/
1430
1431QTreeWidgetItem::QTreeWidgetItem(QTreeWidget *treeview, const QStringList &strings, int type)
1432 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1433{
1434 for (int i = 0; i < strings.size(); ++i)
1435 setText(column: i, atext: strings.at(i));
1436 // do not set this->view here otherwise insertChild() will fail
1437 if (QTreeModel *model = treeModel(v: treeview)) {
1438 model->rootItem->addChild(child: this);
1439 values.reserve(asize: model->headerItem->columnCount());
1440 }
1441}
1442
1443/*!
1444 \fn QTreeWidgetItem::QTreeWidgetItem(QTreeWidget *parent, QTreeWidgetItem *preceding, int type)
1445
1446 Constructs a tree widget item of the specified \a type and inserts it into
1447 the given \a parent after the \a preceding item.
1448
1449 \sa type()
1450*/
1451QTreeWidgetItem::QTreeWidgetItem(QTreeWidget *treeview, QTreeWidgetItem *after, int type)
1452 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1453{
1454 // do not set this->view here otherwise insertChild() will fail
1455 if (QTreeModel *model = treeModel(v: treeview)) {
1456 int i = model->rootItem->children.indexOf(t: after) + 1;
1457 model->rootItem->insertChild(index: i, child: this);
1458 values.reserve(asize: model->headerItem->columnCount());
1459 }
1460}
1461
1462/*!
1463 Constructs a tree widget item and append it to the given \a parent.
1464
1465 \sa type()
1466*/
1467QTreeWidgetItem::QTreeWidgetItem(QTreeWidgetItem *parent, int type)
1468 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1469{
1470 if (parent)
1471 parent->addChild(child: this);
1472}
1473
1474/*!
1475 Constructs a tree widget item and append it to the given \a parent.
1476 The given list of \a strings will be set as the item text for each column in the item.
1477
1478 \sa type()
1479*/
1480QTreeWidgetItem::QTreeWidgetItem(QTreeWidgetItem *parent, const QStringList &strings, int type)
1481 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1482{
1483 for (int i = 0; i < strings.size(); ++i)
1484 setText(column: i, atext: strings.at(i));
1485 if (parent)
1486 parent->addChild(child: this);
1487}
1488
1489/*!
1490 \fn QTreeWidgetItem::QTreeWidgetItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding, int type)
1491
1492 Constructs a tree widget item of the specified \a type that is inserted
1493 into the \a parent after the \a preceding child item.
1494
1495 \sa type()
1496*/
1497QTreeWidgetItem::QTreeWidgetItem(QTreeWidgetItem *parent, QTreeWidgetItem *after, int type)
1498 : rtti(type), d(new QTreeWidgetItemPrivate(this))
1499{
1500 if (parent) {
1501 int i = parent->children.indexOf(t: after) + 1;
1502 parent->insertChild(index: i, child: this);
1503 }
1504}
1505
1506/*!
1507 Destroys this tree widget item.
1508
1509 The item will be removed from \l{QTreeWidget}s to which it has
1510 been added. This makes it safe to delete an item at any time.
1511
1512*/
1513
1514QTreeWidgetItem::~QTreeWidgetItem()
1515{
1516 QTreeModel *model = treeModel();
1517 QTreeModel::SkipSorting skipSorting(model);
1518
1519 if (par) {
1520 int i = par->children.indexOf(t: this);
1521 if (i >= 0) {
1522 if (model) model->beginRemoveItems(parent: par, row: i, count: 1);
1523 // users _could_ do changes when connected to rowsAboutToBeRemoved,
1524 // so we check again to make sure 'i' is valid
1525 if (!par->children.isEmpty() && par->children.at(i) == this)
1526 par->children.takeAt(i);
1527 if (model) model->endRemoveItems();
1528 }
1529 } else if (model) {
1530 if (this == model->headerItem) {
1531 model->headerItem = nullptr;
1532 } else {
1533 int i = model->rootItem->children.indexOf(t: this);
1534 if (i >= 0) {
1535 model->beginRemoveItems(parent: nullptr, row: i, count: 1);
1536 // users _could_ do changes when connected to rowsAboutToBeRemoved,
1537 // so we check again to make sure 'i' is valid
1538 if (!model->rootItem->children.isEmpty() && model->rootItem->children.at(i) == this)
1539 model->rootItem->children.takeAt(i);
1540 model->endRemoveItems();
1541 }
1542 }
1543 }
1544 // at this point the persistent indexes for the children should also be invalidated
1545 // since we invalidated the parent
1546 for (int i = 0; i < children.size(); ++i) {
1547 QTreeWidgetItem *child = children.at(i);
1548 // make sure the child does not try to remove itself from our children list
1549 child->par = nullptr;
1550 // make sure the child does not try to remove itself from the top level list
1551 child->view = nullptr;
1552 delete child;
1553 }
1554
1555 children.clear();
1556 delete d;
1557}
1558
1559/*!
1560 Creates a deep copy of the item and of its children.
1561*/
1562QTreeWidgetItem *QTreeWidgetItem::clone() const
1563{
1564 QTreeWidgetItem *copy = nullptr;
1565
1566 QStack<const QTreeWidgetItem*> stack;
1567 QStack<QTreeWidgetItem*> parentStack;
1568 stack.push(t: this);
1569 parentStack.push(t: 0);
1570
1571 QTreeWidgetItem *root = nullptr;
1572 const QTreeWidgetItem *item = nullptr;
1573 QTreeWidgetItem *parent = nullptr;
1574 while (!stack.isEmpty()) {
1575 // get current item, and copied parent
1576 item = stack.pop();
1577 parent = parentStack.pop();
1578
1579 // copy item
1580 copy = new QTreeWidgetItem(*item);
1581 if (!root)
1582 root = copy;
1583
1584 // set parent and add to parents children list
1585 if (parent) {
1586 copy->par = parent;
1587 parent->children.insert(i: 0, t: copy);
1588 }
1589
1590 for (int i = 0; i < item->childCount(); ++i) {
1591 stack.push(t: item->child(index: i));
1592 parentStack.push(t: copy);
1593 }
1594 }
1595 return root;
1596}
1597
1598/*!
1599 Sets the item indicator \a policy. This policy decides when the
1600 tree branch expand/collapse indicator is shown.
1601 The default value is DontShowIndicatorWhenChildless.
1602
1603 \sa childIndicatorPolicy()
1604*/
1605void QTreeWidgetItem::setChildIndicatorPolicy(QTreeWidgetItem::ChildIndicatorPolicy policy)
1606{
1607 if (d->policy == policy)
1608 return;
1609 d->policy = policy;
1610
1611 if (!view)
1612 return;
1613
1614 view->scheduleDelayedItemsLayout();
1615}
1616
1617/*!
1618 Returns the item indicator policy. This policy decides when the
1619 tree branch expand/collapse indicator is shown.
1620
1621 \sa setChildIndicatorPolicy()
1622*/
1623QTreeWidgetItem::ChildIndicatorPolicy QTreeWidgetItem::childIndicatorPolicy() const
1624{
1625 return d->policy;
1626}
1627
1628/*!
1629 \fn void QTreeWidgetItem::setFlags(Qt::ItemFlags flags)
1630
1631 Sets the flags for the item to the given \a flags. These determine whether
1632 the item can be selected or modified. This is often used to disable an item.
1633
1634 \sa flags()
1635*/
1636void QTreeWidgetItem::setFlags(Qt::ItemFlags flags)
1637{
1638 const bool enable = (flags & Qt::ItemIsEnabled);
1639 const bool changedState = bool(itemFlags & Qt::ItemIsEnabled) != enable;
1640 const bool changedExplicit = d->disabled != !enable;
1641
1642 d->disabled = !enable;
1643
1644 if (enable && par && !(par->itemFlags & Qt::ItemIsEnabled)) // inherit from parent
1645 itemFlags = flags & ~Qt::ItemIsEnabled;
1646 else // this item is explicitly disabled or has no parent
1647 itemFlags = flags;
1648
1649 if (changedState && changedExplicit) { // if the propagate the change to the children
1650 QStack<QTreeWidgetItem*> parents;
1651 parents.push(t: this);
1652 while (!parents.isEmpty()) {
1653 QTreeWidgetItem *parent = parents.pop();
1654 for (int i = 0; i < parent->children.size(); ++i) {
1655 QTreeWidgetItem *child = parent->children.at(i);
1656 if (!child->d->disabled) { // if not explicitly disabled
1657 parents.push(t: child);
1658 if (enable)
1659 child->itemFlags = child->itemFlags | Qt::ItemIsEnabled;
1660 else
1661 child->itemFlags = child->itemFlags & ~Qt::ItemIsEnabled;
1662 child->itemChanged(); // ### we may want to optimize this
1663 }
1664 }
1665 }
1666 }
1667 itemChanged();
1668}
1669
1670void QTreeWidgetItemPrivate::updateHiddenStatus(QTreeWidgetItem *item, bool inserting)
1671{
1672 QTreeModel *model = item->treeModel();
1673 if (!model)
1674 return;
1675 QStack<QTreeWidgetItem *> parents;
1676 parents.push(t: item);
1677 while (!parents.isEmpty()) {
1678 QTreeWidgetItem *parent = parents.pop();
1679 if (parent->d->hidden) {
1680 const QModelIndex index = model->index(item: parent, column: 0);
1681 item->view->setRowHidden(row: index.row(), parent: index.parent(), hide: inserting);
1682 }
1683 for (int i = 0; i < parent->children.size(); ++i) {
1684 QTreeWidgetItem *child = parent->children.at(i);
1685 parents.push(t: child);
1686 }
1687 }
1688}
1689
1690void QTreeWidgetItemPrivate::propagateDisabled(QTreeWidgetItem *item)
1691{
1692 Q_ASSERT(item);
1693 const bool enable = item->par ? (item->par->itemFlags.testFlag(flag: Qt::ItemIsEnabled)) : true;
1694
1695 QStack<QTreeWidgetItem*> parents;
1696 parents.push(t: item);
1697 while (!parents.isEmpty()) {
1698 QTreeWidgetItem *parent = parents.pop();
1699 if (!parent->d->disabled) { // if not explicitly disabled
1700 Qt::ItemFlags oldFlags = parent->itemFlags;
1701 if (enable)
1702 parent->itemFlags = parent->itemFlags | Qt::ItemIsEnabled;
1703 else
1704 parent->itemFlags = parent->itemFlags & ~Qt::ItemIsEnabled;
1705 if (parent->itemFlags != oldFlags)
1706 parent->itemChanged();
1707 }
1708
1709 for (int i = 0; i < parent->children.size(); ++i) {
1710 QTreeWidgetItem *child = parent->children.at(i);
1711 parents.push(t: child);
1712 }
1713 }
1714}
1715/*!
1716 \fn Qt::ItemFlags QTreeWidgetItem::flags() const
1717
1718 Returns the flags used to describe the item. These determine whether
1719 the item can be checked, edited, and selected.
1720
1721 The default value for flags is
1722 Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
1723 Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled.
1724
1725 \sa setFlags()
1726*/
1727Qt::ItemFlags QTreeWidgetItem::flags() const
1728{
1729 return itemFlags;
1730}
1731
1732/*!
1733 Sets the value for the item's \a column and \a role to the given
1734 \a value.
1735
1736 The \a role describes the type of data specified by \a value, and is defined by
1737 the Qt::ItemDataRole enum.
1738
1739 \note The default implementation treats Qt::EditRole and Qt::DisplayRole as
1740 referring to the same data.
1741*/
1742void QTreeWidgetItem::setData(int column, int role, const QVariant &value)
1743{
1744 if (column < 0)
1745 return;
1746
1747 QTreeModel *model = treeModel();
1748 switch (role) {
1749 case Qt::EditRole:
1750 case Qt::DisplayRole: {
1751 if (values.size() <= column) {
1752 if (model && this == model->headerItem)
1753 model->setColumnCount(column + 1);
1754 else
1755 values.resize(size: column + 1);
1756 }
1757 if (d->display.size() <= column) {
1758 for (int i = d->display.size() - 1; i < column - 1; ++i)
1759 d->display.append(t: QVariant());
1760 d->display.append(t: value);
1761 } else if (d->display[column] != value) {
1762 d->display[column] = value;
1763 } else {
1764 return; // value is unchanged
1765 }
1766 } break;
1767 case Qt::CheckStateRole:
1768 if ((itemFlags & Qt::ItemIsAutoTristate) && value != Qt::PartiallyChecked) {
1769 for (int i = 0; i < children.size(); ++i) {
1770 QTreeWidgetItem *child = children.at(i);
1771 if (child->data(column, role).isValid()) {// has a CheckState
1772 Qt::ItemFlags f = itemFlags; // a little hack to avoid multiple dataChanged signals
1773 itemFlags &= ~Qt::ItemIsAutoTristate;
1774 child->setData(column, role, value);
1775 itemFlags = f;
1776 }
1777 }
1778 }
1779 Q_FALLTHROUGH();
1780 default:
1781 if (column < values.size()) {
1782 bool found = false;
1783 const QList<QWidgetItemData> column_values = values.at(i: column);
1784 for (int i = 0; i < column_values.size(); ++i) {
1785 if (column_values.at(i).role == role) {
1786 if (column_values.at(i).value == value)
1787 return; // value is unchanged
1788 values[column][i].value = value;
1789 found = true;
1790 break;
1791 }
1792 }
1793 if (!found)
1794 values[column].append(t: QWidgetItemData(role, value));
1795 } else {
1796 if (model && this == model->headerItem)
1797 model->setColumnCount(column + 1);
1798 else
1799 values.resize(size: column + 1);
1800 values[column].append(t: QWidgetItemData(role, value));
1801 }
1802 }
1803
1804 if (model) {
1805 const QList<int> roles((role == Qt::DisplayRole || role == Qt::EditRole)
1806 ? QList<int>({ Qt::DisplayRole, Qt::EditRole })
1807 : QList<int>({ role }));
1808 model->emitDataChanged(item: this, column, roles);
1809 if (role == Qt::CheckStateRole) {
1810 QTreeWidgetItem *p;
1811 for (p = par; p && (p->itemFlags & Qt::ItemIsAutoTristate); p = p->par)
1812 model->emitDataChanged(item: p, column, roles);
1813 }
1814 }
1815}
1816
1817/*!
1818 Returns the value for the item's \a column and \a role.
1819*/
1820QVariant QTreeWidgetItem::data(int column, int role) const
1821{
1822 switch (role) {
1823 case Qt::EditRole:
1824 case Qt::DisplayRole:
1825 if (column >= 0 && column < d->display.size())
1826 return d->display.at(i: column);
1827 break;
1828 case Qt::CheckStateRole:
1829 // special case for check state in tristate
1830 if (children.size() && (itemFlags & Qt::ItemIsAutoTristate))
1831 return childrenCheckState(column);
1832 Q_FALLTHROUGH();
1833 default:
1834 if (column >= 0 && column < values.size()) {
1835 const QList<QWidgetItemData> &column_values = values.at(i: column);
1836 for (const auto &column_value : column_values) {
1837 if (column_value.role == role)
1838 return column_value.value;
1839 }
1840 }
1841 }
1842 return QVariant();
1843}
1844
1845/*!
1846 Returns \c true if the text in the item is less than the text in the
1847 \a other item, otherwise returns \c false.
1848*/
1849
1850bool QTreeWidgetItem::operator<(const QTreeWidgetItem &other) const
1851{
1852 int column = view ? view->sortColumn() : 0;
1853 const QVariant v1 = data(column, role: Qt::DisplayRole);
1854 const QVariant v2 = other.data(column, role: Qt::DisplayRole);
1855 return QAbstractItemModelPrivate::variantLessThan(v1, v2);
1856}
1857
1858#ifndef QT_NO_DATASTREAM
1859
1860/*!
1861 Reads the item from stream \a in. This only reads data into a single item.
1862
1863 \sa write()
1864*/
1865void QTreeWidgetItem::read(QDataStream &in)
1866{
1867 // convert from streams written before we introduced display (4.2.0)
1868 if (in.version() < QDataStream::Qt_4_2) {
1869 d->display.clear();
1870 in >> values;
1871 // move the display value over to the display string list
1872 for (int column = 0; column < values.size(); ++column) {
1873 d->display << QVariant();
1874 for (int i = 0; i < values.at(i: column).size(); ++i) {
1875 if (values.at(i: column).at(i).role == Qt::DisplayRole) {
1876 d->display[column] = values.at(i: column).at(i).value;
1877 values[column].remove(i: i--);
1878 }
1879 }
1880 }
1881 } else {
1882 in >> values >> d->display;
1883 }
1884}
1885
1886/*!
1887 Writes the item to stream \a out. This only writes data from one single item.
1888
1889 \sa read()
1890*/
1891void QTreeWidgetItem::write(QDataStream &out) const
1892{
1893 out << values << d->display;
1894}
1895#endif // QT_NO_DATASTREAM
1896
1897/*!
1898 \since 4.1
1899
1900 Constructs a copy of \a other. Note that type() and treeWidget()
1901 are not copied.
1902
1903 This function is useful when reimplementing clone().
1904
1905 \sa data(), flags()
1906*/
1907QTreeWidgetItem::QTreeWidgetItem(const QTreeWidgetItem &other)
1908 : rtti(Type),
1909 values(other.values),
1910 d(new QTreeWidgetItemPrivate(this)),
1911 itemFlags(other.itemFlags)
1912{
1913 d->display = other.d->display;
1914}
1915
1916/*!
1917 Assigns \a other's data and flags to this item. Note that type()
1918 and treeWidget() are not copied.
1919
1920 This function is useful when reimplementing clone().
1921
1922 \sa data(), flags()
1923*/
1924QTreeWidgetItem &QTreeWidgetItem::operator=(const QTreeWidgetItem &other)
1925{
1926 values = other.values;
1927 d->display = other.d->display;
1928 d->policy = other.d->policy;
1929 itemFlags = other.itemFlags;
1930 return *this;
1931}
1932
1933/*!
1934 Appends the \a child item to the list of children.
1935
1936 \sa insertChild(), takeChild()
1937*/
1938void QTreeWidgetItem::addChild(QTreeWidgetItem *child)
1939{
1940 if (child) {
1941 insertChild(index: children.size(), child);
1942 child->d->rowGuess = children.size() - 1;
1943 }
1944}
1945
1946/*!
1947 Inserts the \a child item at \a index in the list of children.
1948
1949 If the child has already been inserted somewhere else it won't be inserted again.
1950*/
1951void QTreeWidgetItem::insertChild(int index, QTreeWidgetItem *child)
1952{
1953 if (index < 0 || index > children.size() || child == nullptr || child->view != nullptr || child->par != nullptr)
1954 return;
1955
1956 if (QTreeModel *model = treeModel()) {
1957 QTreeModel::SkipSorting skipSorting(model);
1958 if (model->rootItem == this)
1959 child->par = nullptr;
1960 else
1961 child->par = this;
1962 if (view->isSortingEnabled()) {
1963 // do a delayed sort instead
1964 if (!model->sortPendingTimer.isActive())
1965 model->sortPendingTimer.start(msec: 0, obj: model);
1966 }
1967 model->beginInsertItems(parent: this, row: index, count: 1);
1968 int cols = model->columnCount();
1969 QStack<QTreeWidgetItem*> stack;
1970 stack.push(t: child);
1971 while (!stack.isEmpty()) {
1972 QTreeWidgetItem *i = stack.pop();
1973 i->view = view;
1974 i->values.reserve(asize: cols);
1975 for (int c = 0; c < i->children.size(); ++c)
1976 stack.push(t: i->children.at(i: c));
1977 }
1978 children.insert(i: index, t: child);
1979 d->updateHiddenStatus(item: child, inserting: true);
1980 model->endInsertItems();
1981 } else {
1982 child->par = this;
1983 children.insert(i: index, t: child);
1984 }
1985 if (child->par)
1986 d->propagateDisabled(item: child);
1987}
1988
1989/*!
1990 Removes the given item indicated by \a child.
1991 The removed item will not be deleted.
1992*/
1993void QTreeWidgetItem::removeChild(QTreeWidgetItem *child)
1994{
1995 (void)takeChild(index: children.indexOf(t: child));
1996}
1997
1998/*!
1999 Removes the item at \a index and returns it, otherwise return 0.
2000*/
2001QTreeWidgetItem *QTreeWidgetItem::takeChild(int index)
2002{
2003 // we move this outside the check of the index to allow executing
2004 // pending sorts from inline functions, using this function (hack)
2005 QTreeModel *model = treeModel();
2006 if (model) {
2007 // This will trigger a layoutChanged signal, thus we might want to optimize
2008 // this function by not emitting the rowsRemoved signal etc to the view.
2009 // On the other hand we also need to make sure that the selectionmodel
2010 // is updated in case we take an item that is selected.
2011 model->skipPendingSort = false;
2012 model->executePendingSort();
2013 }
2014 if (index >= 0 && index < children.size()) {
2015 if (model) model->beginRemoveItems(parent: this, row: index, count: 1);
2016 d->updateHiddenStatus(item: children.at(i: index), inserting: false);
2017 QTreeWidgetItem *item = children.takeAt(i: index);
2018 item->par = nullptr;
2019 QStack<QTreeWidgetItem*> stack;
2020 stack.push(t: item);
2021 while (!stack.isEmpty()) {
2022 QTreeWidgetItem *i = stack.pop();
2023 i->view = nullptr;
2024 for (int c = 0; c < i->children.size(); ++c)
2025 stack.push(t: i->children.at(i: c));
2026 }
2027 d->propagateDisabled(item);
2028 if (model) model->endRemoveRows();
2029 return item;
2030 }
2031 return nullptr;
2032}
2033
2034/*!
2035 \since 4.1
2036
2037 Appends the given list of \a children to the item.
2038
2039 \sa insertChildren(), takeChildren()
2040*/
2041void QTreeWidgetItem::addChildren(const QList<QTreeWidgetItem*> &children)
2042{
2043 insertChildren(index: this->children.size(), children);
2044}
2045
2046/*!
2047 \since 4.1
2048
2049 Inserts the given list of \a children into the list of the item children at \a index .
2050
2051 Children that have already been inserted somewhere else won't be inserted.
2052*/
2053void QTreeWidgetItem::insertChildren(int index, const QList<QTreeWidgetItem*> &children)
2054{
2055 if (index < 0 || index > this->children.size() || children.isEmpty())
2056 return;
2057
2058 if (view && view->isSortingEnabled()) {
2059 for (int n = 0; n < children.size(); ++n)
2060 insertChild(index, child: children.at(i: n));
2061 return;
2062 }
2063 QTreeModel *model = treeModel();
2064 QStack<QTreeWidgetItem*> stack;
2065 QList<QTreeWidgetItem*> itemsToInsert;
2066 for (int n = 0; n < children.size(); ++n) {
2067 QTreeWidgetItem *child = children.at(i: n);
2068 if (child->view || child->par)
2069 continue;
2070 itemsToInsert.append(t: child);
2071 if (view && model) {
2072 if (child->childCount() == 0)
2073 child->view = view;
2074 else
2075 stack.push(t: child);
2076 }
2077 if (model && (model->rootItem == this))
2078 child->par = nullptr;
2079 else
2080 child->par = this;
2081 }
2082 if (!itemsToInsert.isEmpty()) {
2083 while (!stack.isEmpty()) {
2084 QTreeWidgetItem *i = stack.pop();
2085 i->view = view;
2086 for (int c = 0; c < i->children.size(); ++c)
2087 stack.push(t: i->children.at(i: c));
2088 }
2089 if (model) model->beginInsertItems(parent: this, row: index, count: itemsToInsert.size());
2090 for (int n = 0; n < itemsToInsert.size(); ++n) {
2091 QTreeWidgetItem *child = itemsToInsert.at(i: n);
2092 this->children.insert(i: index + n, t: child);
2093 if (child->par)
2094 d->propagateDisabled(item: child);
2095 d->updateHiddenStatus(item: child, inserting: true);
2096 }
2097 if (model) model->endInsertItems();
2098 }
2099}
2100
2101/*!
2102 \since 4.1
2103
2104 Removes the list of children and returns it, otherwise returns an empty list.
2105*/
2106QList<QTreeWidgetItem*> QTreeWidgetItem::takeChildren()
2107{
2108 QList<QTreeWidgetItem*> removed;
2109 if (children.size() > 0) {
2110 QTreeModel *model = treeModel();
2111 if (model) {
2112 // This will trigger a layoutChanged signal, thus we might want to optimize
2113 // this function by not emitting the rowsRemoved signal etc to the view.
2114 // On the other hand we also need to make sure that the selectionmodel
2115 // is updated in case we take an item that is selected.
2116 model->executePendingSort();
2117 }
2118 if (model) model->beginRemoveItems(parent: this, row: 0, count: children.size());
2119 for (int n = 0; n < children.size(); ++n) {
2120 QTreeWidgetItem *item = children.at(i: n);
2121 item->par = nullptr;
2122 QStack<QTreeWidgetItem*> stack;
2123 stack.push(t: item);
2124 while (!stack.isEmpty()) {
2125 QTreeWidgetItem *i = stack.pop();
2126 i->view = nullptr;
2127 for (int c = 0; c < i->children.size(); ++c)
2128 stack.push(t: i->children.at(i: c));
2129 }
2130 d->propagateDisabled(item);
2131 }
2132 removed = children;
2133 children.clear(); // detach
2134 if (model) model->endRemoveItems();
2135 }
2136 return removed;
2137}
2138
2139
2140void QTreeWidgetItemPrivate::sortChildren(int column, Qt::SortOrder order, bool climb)
2141{
2142 QTreeModel *model = q->treeModel();
2143 if (!model)
2144 return;
2145 model->sortItems(items: &q->children, column, order);
2146 if (climb) {
2147 QList<QTreeWidgetItem*>::iterator it = q->children.begin();
2148 for (; it != q->children.end(); ++it) {
2149 //here we call the private object's method to avoid emitting
2150 //the layoutAboutToBeChanged and layoutChanged signals
2151 (*it)->d->sortChildren(column, order, climb);
2152 }
2153 }
2154}
2155
2156/*!
2157 \internal
2158
2159 Sorts the children by the value in the given \a column, in the \a order
2160 specified. If \a climb is true, the items below each of the children will
2161 also be sorted.
2162*/
2163void QTreeWidgetItem::sortChildren(int column, Qt::SortOrder order, bool climb)
2164{
2165 QTreeModel *model = treeModel();
2166 if (!model)
2167 return;
2168 if (model->isChanging())
2169 return;
2170 QTreeModel::SkipSorting skipSorting(model);
2171 int oldSortColumn = view->d_func()->explicitSortColumn;
2172 view->d_func()->explicitSortColumn = column;
2173 emit model->layoutAboutToBeChanged(parents: {}, hint: QAbstractItemModel::VerticalSortHint);
2174 d->sortChildren(column, order, climb);
2175 emit model->layoutChanged(parents: {}, hint: QAbstractItemModel::VerticalSortHint);
2176 view->d_func()->explicitSortColumn = oldSortColumn;
2177}
2178
2179/*!
2180 \internal
2181
2182 Calculates the checked state of the item based on the checked state
2183 of its children. E.g. if all children checked => this item is also
2184 checked; if some children checked => this item is partially checked;
2185 if no children checked => this item is unchecked.
2186*/
2187QVariant QTreeWidgetItem::childrenCheckState(int column) const
2188{
2189 if (column < 0)
2190 return QVariant();
2191 bool checkedChildren = false;
2192 bool uncheckedChildren = false;
2193 for (const auto *child : children) {
2194 QVariant value = child->data(column, role: Qt::CheckStateRole);
2195 if (!value.isValid())
2196 return QVariant();
2197
2198 switch (static_cast<Qt::CheckState>(value.toInt()))
2199 {
2200 case Qt::Unchecked:
2201 uncheckedChildren = true;
2202 break;
2203 case Qt::Checked:
2204 checkedChildren = true;
2205 break;
2206 case Qt::PartiallyChecked:
2207 default:
2208 return Qt::PartiallyChecked;
2209 }
2210
2211 if (uncheckedChildren && checkedChildren)
2212 return Qt::PartiallyChecked;
2213 }
2214
2215 if (uncheckedChildren)
2216 return Qt::Unchecked;
2217 else if (checkedChildren)
2218 return Qt::Checked;
2219 else
2220 return QVariant(); // value was not defined
2221}
2222
2223/*!
2224 \since 4.5
2225
2226 Causes the model associated with this item to emit a
2227 \l{QAbstractItemModel::dataChanged()}{dataChanged}() signal for this
2228 item.
2229
2230 You normally only need to call this function if you have subclassed
2231 QTreeWidgetItem and reimplemented data() and/or setData().
2232
2233 \sa setData()
2234*/
2235void QTreeWidgetItem::emitDataChanged()
2236{
2237 itemChanged();
2238}
2239
2240/*!
2241 \internal
2242*/
2243void QTreeWidgetItem::itemChanged()
2244{
2245 if (QTreeModel *model = treeModel())
2246 model->itemChanged(item: this);
2247}
2248
2249/*!
2250 \internal
2251*/
2252void QTreeWidgetItem::executePendingSort() const
2253{
2254 if (QTreeModel *model = treeModel())
2255 model->executePendingSort();
2256}
2257
2258/*!
2259 \internal
2260 returns the QTreeModel if a view is set
2261*/
2262QTreeModel *QTreeWidgetItem::treeModel(QTreeWidget *v) const
2263{
2264 if (!v)
2265 v = view;
2266 return (v ? qobject_cast<QTreeModel*>(object: v->model()) : nullptr);
2267}
2268
2269
2270#ifndef QT_NO_DATASTREAM
2271/*!
2272 \relates QTreeWidgetItem
2273
2274 Writes the tree widget item \a item to stream \a out.
2275
2276 This operator uses QTreeWidgetItem::write().
2277
2278 \sa {Serializing Qt Data Types}
2279*/
2280QDataStream &operator<<(QDataStream &out, const QTreeWidgetItem &item)
2281{
2282 item.write(out);
2283 return out;
2284}
2285
2286/*!
2287 \relates QTreeWidgetItem
2288
2289 Reads a tree widget item from stream \a in into \a item.
2290
2291 This operator uses QTreeWidgetItem::read().
2292
2293 \sa {Serializing Qt Data Types}
2294*/
2295QDataStream &operator>>(QDataStream &in, QTreeWidgetItem &item)
2296{
2297 item.read(in);
2298 return in;
2299}
2300#endif // QT_NO_DATASTREAM
2301
2302
2303void QTreeWidgetPrivate::clearConnections()
2304{
2305 for (const QMetaObject::Connection &connection : connections)
2306 QObject::disconnect(connection);
2307}
2308
2309void QTreeWidgetPrivate::emitItemPressed(const QModelIndex &index)
2310{
2311 Q_Q(QTreeWidget);
2312 emit q->itemPressed(item: item(index), column: index.column());
2313}
2314
2315void QTreeWidgetPrivate::emitItemClicked(const QModelIndex &index)
2316{
2317 Q_Q(QTreeWidget);
2318 emit q->itemClicked(item: item(index), column: index.column());
2319}
2320
2321void QTreeWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index)
2322{
2323 Q_Q(QTreeWidget);
2324 emit q->itemDoubleClicked(item: item(index), column: index.column());
2325}
2326
2327void QTreeWidgetPrivate::emitItemActivated(const QModelIndex &index)
2328{
2329 Q_Q(QTreeWidget);
2330 emit q->itemActivated(item: item(index), column: index.column());
2331}
2332
2333void QTreeWidgetPrivate::emitItemEntered(const QModelIndex &index)
2334{
2335 Q_Q(QTreeWidget);
2336 emit q->itemEntered(item: item(index), column: index.column());
2337}
2338
2339void QTreeWidgetPrivate::emitItemChanged(const QModelIndex &index)
2340{
2341 Q_Q(QTreeWidget);
2342 QTreeWidgetItem *indexItem = item(index);
2343 if (indexItem)
2344 emit q->itemChanged(item: indexItem, column: index.column());
2345}
2346
2347void QTreeWidgetPrivate::emitItemExpanded(const QModelIndex &index)
2348{
2349 Q_Q(QTreeWidget);
2350 emit q->itemExpanded(item: item(index));
2351}
2352
2353void QTreeWidgetPrivate::emitItemCollapsed(const QModelIndex &index)
2354{
2355 Q_Q(QTreeWidget);
2356 emit q->itemCollapsed(item: item(index));
2357}
2358
2359void QTreeWidgetPrivate::emitCurrentItemChanged(const QModelIndex &current,
2360 const QModelIndex &previous)
2361{
2362 Q_Q(QTreeWidget);
2363 QTreeWidgetItem *currentItem = item(index: current);
2364 QTreeWidgetItem *previousItem = item(index: previous);
2365 emit q->currentItemChanged(current: currentItem, previous: previousItem);
2366}
2367
2368void QTreeWidgetPrivate::sort()
2369{
2370 if (sortingEnabled) {
2371 int column = header->sortIndicatorSection();
2372 Qt::SortOrder order = header->sortIndicatorOrder();
2373 treeModel()->sort(column, order);
2374 }
2375}
2376
2377void QTreeWidgetPrivate::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
2378{
2379 Q_Q(QTreeWidget);
2380 QModelIndexList indices = selected.indexes();
2381 int i;
2382 QTreeModel *m = treeModel();
2383 for (i = 0; i < indices.size(); ++i) {
2384 QTreeWidgetItem *item = m->item(index: indices.at(i));
2385 item->d->selected = true;
2386 }
2387
2388 indices = deselected.indexes();
2389 for (i = 0; i < indices.size(); ++i) {
2390 QTreeWidgetItem *item = m->item(index: indices.at(i));
2391 item->d->selected = false;
2392 }
2393
2394 emit q->itemSelectionChanged();
2395}
2396
2397void QTreeWidgetPrivate::dataChanged(const QModelIndex &topLeft,
2398 const QModelIndex &bottomRight)
2399{
2400 if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()
2401 && !treeModel()->sortPendingTimer.isActive()) {
2402 int column = header->sortIndicatorSection();
2403 if (column >= topLeft.column() && column <= bottomRight.column()) {
2404 Qt::SortOrder order = header->sortIndicatorOrder();
2405 treeModel()->ensureSorted(column, order, start: topLeft.row(),
2406 end: bottomRight.row(), parent: topLeft.parent());
2407 }
2408 }
2409}
2410
2411/*!
2412 \class QTreeWidget
2413
2414 \brief The QTreeWidget class provides a tree view that uses a predefined
2415 tree model.
2416
2417 \ingroup model-view
2418 \inmodule QtWidgets
2419
2420 \image fusion-treeview.png
2421
2422 The QTreeWidget class is a convenience class that provides a standard
2423 tree widget with a classic item-based interface similar to that used by
2424 the QListView class in Qt 3.
2425 This class is based on Qt's Model/View architecture and uses a default
2426 model to hold items, each of which is a QTreeWidgetItem.
2427
2428 Developers who do not need the flexibility of the Model/View framework
2429 can use this class to create simple hierarchical lists very easily. A more
2430 flexible approach involves combining a QTreeView with a standard item model.
2431 This allows the storage of data to be separated from its representation.
2432
2433 In its simplest form, a tree widget can be constructed in the following way:
2434
2435 \snippet code/src_gui_itemviews_qtreewidget.cpp 0
2436
2437 Before items can be added to the tree widget, the number of columns must
2438 be set with setColumnCount(). This allows each item to have one or more
2439 labels or other decorations. The number of columns in use can be found
2440 with the columnCount() function.
2441
2442 The tree can have a header that contains a section for each column in
2443 the widget. It is easiest to set up the labels for each section by
2444 supplying a list of strings with setHeaderLabels(), but a custom header
2445 can be constructed with a QTreeWidgetItem and inserted into the tree
2446 with the setHeaderItem() function.
2447
2448 The items in the tree can be sorted by column according to a predefined
2449 sort order. If sorting is enabled, the user can sort the items by clicking
2450 on a column header. Sorting can be enabled or disabled by calling
2451 \l{QTreeView::setSortingEnabled()}{setSortingEnabled()}. The
2452 \l{QTreeView::isSortingEnabled()}{isSortingEnabled()} function indicates
2453 whether sorting is enabled.
2454
2455 \sa QTreeWidgetItem, QTreeWidgetItemIterator, QTreeView,
2456 {Model/View Programming}
2457*/
2458
2459/*!
2460 \property QTreeWidget::columnCount
2461 \brief the number of columns displayed in the tree widget
2462
2463 By default, this property has a value of 1.
2464*/
2465
2466/*!
2467 \fn void QTreeWidget::itemActivated(QTreeWidgetItem *item, int column)
2468
2469 This signal is emitted when the user activates an item by single-
2470 or double-clicking (depending on the platform, i.e. on the
2471 QStyle::SH_ItemView_ActivateItemOnSingleClick style hint) or
2472 pressing a special key (e.g., \uicontrol Enter).
2473
2474 The specified \a item is the item that was clicked, or \nullptr if
2475 no item was clicked. The \a column is the item's column that was
2476 clicked, or -1 if no item was clicked.
2477*/
2478
2479/*!
2480 \fn void QTreeWidget::itemPressed(QTreeWidgetItem *item, int column)
2481
2482 This signal is emitted when the user presses a mouse button inside
2483 the widget.
2484
2485 The specified \a item is the item that was clicked, or \nullptr if
2486 no item was clicked. The \a column is the item's column that was
2487 clicked, or -1 if no item was clicked.
2488*/
2489
2490/*!
2491 \fn void QTreeWidget::itemClicked(QTreeWidgetItem *item, int column)
2492
2493 This signal is emitted when the user clicks inside the widget.
2494
2495 The specified \a item is the item that was clicked. The \a column is the
2496 item's column that was clicked. If no item was clicked, no signal will be
2497 emitted.
2498*/
2499
2500/*!
2501 \fn void QTreeWidget::itemDoubleClicked(QTreeWidgetItem *item, int column)
2502
2503 This signal is emitted when the user double clicks inside the
2504 widget.
2505
2506 The specified \a item is the item that was clicked, or \nullptr if
2507 no item was clicked. The \a column is the item's column that was
2508 clicked. If no item was double clicked, no signal will be emitted.
2509*/
2510
2511/*!
2512 \fn void QTreeWidget::itemExpanded(QTreeWidgetItem *item)
2513
2514 This signal is emitted when the specified \a item is expanded so that
2515 all of its children are displayed.
2516
2517 \sa QTreeWidgetItem::isExpanded(), itemCollapsed(), expandItem()
2518*/
2519
2520/*!
2521 \fn void QTreeWidget::itemCollapsed(QTreeWidgetItem *item)
2522
2523 This signal is emitted when the specified \a item is collapsed so that
2524 none of its children are displayed.
2525
2526 \note This signal will not be emitted if an item changes its state when
2527 collapseAll() is invoked.
2528
2529 \sa QTreeWidgetItem::isExpanded(), itemExpanded(), collapseItem()
2530*/
2531
2532/*!
2533 \fn void QTreeWidget::currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
2534
2535 This signal is emitted when the current item changes. The current
2536 item is specified by \a current, and this replaces the \a previous
2537 current item.
2538
2539 \sa setCurrentItem()
2540*/
2541
2542/*!
2543 \fn void QTreeWidget::itemSelectionChanged()
2544
2545 This signal is emitted when the selection changes in the tree widget.
2546 The current selection can be found with selectedItems().
2547*/
2548
2549/*!
2550 \fn void QTreeWidget::itemEntered(QTreeWidgetItem *item, int column)
2551
2552 This signal is emitted when the mouse cursor enters an \a item over the
2553 specified \a column.
2554 QTreeWidget mouse tracking needs to be enabled for this feature to work.
2555*/
2556
2557/*!
2558 \fn void QTreeWidget::itemChanged(QTreeWidgetItem *item, int column)
2559
2560 This signal is emitted when the contents of the \a column in the specified
2561 \a item changes.
2562*/
2563
2564/*!
2565 \since 4.3
2566
2567 \fn void QTreeWidget::removeItemWidget(QTreeWidgetItem *item, int column)
2568
2569 Removes the widget set in the given \a item in the given \a column.
2570
2571 \sa itemWidget(), setItemWidget()
2572*/
2573
2574/*!
2575 Constructs a tree widget with the given \a parent.
2576*/
2577QTreeWidget::QTreeWidget(QWidget *parent)
2578 : QTreeView(*new QTreeWidgetPrivate(), parent)
2579{
2580 Q_D(QTreeWidget);
2581 QTreeView::setModel(new QTreeModel(1, this));
2582 d->connections = {
2583 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::pressed,
2584 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemPressed),
2585 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::clicked,
2586 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemClicked),
2587 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::doubleClicked,
2588 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemDoubleClicked),
2589 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::activated,
2590 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemActivated),
2591 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::entered,
2592 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemEntered),
2593 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::expanded,
2594 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemExpanded),
2595 QObjectPrivate::connect(sender: this, signal: &QTreeWidget::collapsed,
2596 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemCollapsed),
2597 QObjectPrivate::connect(sender: model(), signal: &QAbstractItemModel::dataChanged,
2598 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitItemChanged),
2599 QObjectPrivate::connect(sender: model(), signal: &QAbstractItemModel::dataChanged,
2600 receiverPrivate: d, slot: &QTreeWidgetPrivate::dataChanged),
2601 QObjectPrivate::connect(sender: model(), signal: &QAbstractItemModel::columnsRemoved,
2602 receiverPrivate: d, slot: &QTreeWidgetPrivate::sort),
2603 QObjectPrivate::connect(sender: selectionModel(), signal: &QItemSelectionModel::currentChanged,
2604 receiverPrivate: d, slot: &QTreeWidgetPrivate::emitCurrentItemChanged),
2605 QObjectPrivate::connect(sender: selectionModel(), signal: &QItemSelectionModel::selectionChanged,
2606 receiverPrivate: d, slot: &QTreeWidgetPrivate::selectionChanged)
2607 };
2608 header()->setSectionsClickable(false);
2609}
2610
2611/*!
2612 Destroys the tree widget and all its items.
2613*/
2614
2615QTreeWidget::~QTreeWidget()
2616{
2617 Q_D(QTreeWidget);
2618 d->clearConnections();
2619}
2620
2621/*
2622 Returns the number of header columns in the view.
2623
2624 \sa sortColumn(), currentColumn(), topLevelItemCount()
2625*/
2626
2627int QTreeWidget::columnCount() const
2628{
2629 Q_D(const QTreeWidget);
2630 return d->model->columnCount();
2631}
2632
2633/*
2634 Sets the number of header \a columns in the tree widget.
2635*/
2636
2637void QTreeWidget::setColumnCount(int columns)
2638{
2639 Q_D(QTreeWidget);
2640 if (columns < 0)
2641 return;
2642 d->treeModel()->setColumnCount(columns);
2643}
2644
2645/*!
2646 \since 4.2
2647
2648 Returns the tree widget's invisible root item.
2649
2650 The invisible root item provides access to the tree widget's top-level items
2651 through the QTreeWidgetItem API, making it possible to write functions that
2652 can treat top-level items and their children in a uniform way; for example,
2653 recursive functions.
2654*/
2655
2656QTreeWidgetItem *QTreeWidget::invisibleRootItem() const
2657{
2658 Q_D(const QTreeWidget);
2659 return d->treeModel()->rootItem;
2660}
2661
2662/*!
2663 Returns the top level item at the given \a index, or \nullptr if the
2664 item does not exist.
2665
2666 \sa topLevelItemCount(), insertTopLevelItem()
2667*/
2668
2669QTreeWidgetItem *QTreeWidget::topLevelItem(int index) const
2670{
2671 Q_D(const QTreeWidget);
2672 return d->treeModel()->rootItem->child(index);
2673}
2674
2675/*!
2676 \property QTreeWidget::topLevelItemCount
2677 \brief the number of top-level items
2678
2679 By default, this property has a value of 0.
2680
2681 \sa columnCount(), currentItem()
2682*/
2683
2684int QTreeWidget::topLevelItemCount() const
2685{
2686 Q_D(const QTreeWidget);
2687 return d->treeModel()->rootItem->childCount();
2688}
2689
2690/*!
2691 Inserts the \a item at \a index in the top level in the view.
2692
2693 If the item has already been inserted somewhere else it won't be inserted.
2694
2695 \sa addTopLevelItem(), columnCount()
2696*/
2697
2698void QTreeWidget::insertTopLevelItem(int index, QTreeWidgetItem *item)
2699{
2700 Q_D(QTreeWidget);
2701 d->treeModel()->rootItem->insertChild(index, child: item);
2702}
2703
2704/*!
2705 \since 4.1
2706
2707 Appends the \a item as a top-level item in the widget.
2708
2709 \sa insertTopLevelItem()
2710*/
2711void QTreeWidget::addTopLevelItem(QTreeWidgetItem *item)
2712{
2713 insertTopLevelItem(index: topLevelItemCount(), item);
2714}
2715
2716/*!
2717 Removes the top-level item at the given \a index in the tree and
2718 returns it, otherwise returns \nullptr;
2719
2720 \sa insertTopLevelItem(), topLevelItem(), topLevelItemCount()
2721*/
2722
2723QTreeWidgetItem *QTreeWidget::takeTopLevelItem(int index)
2724{
2725 Q_D(QTreeWidget);
2726 return d->treeModel()->rootItem->takeChild(index);
2727}
2728
2729/*!
2730 Returns the index of the given top-level \a item, or -1 if the item
2731 cannot be found.
2732
2733 \sa sortItems(), topLevelItemCount()
2734 */
2735int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem *item) const
2736{
2737 Q_D(const QTreeWidget);
2738 d->treeModel()->executePendingSort();
2739 return d->treeModel()->rootItem->children.indexOf(t: item);
2740}
2741
2742/*!
2743 \since 4.1
2744
2745 Inserts the list of \a items at \a index in the top level in the view.
2746
2747 Items that have already been inserted somewhere else won't be inserted.
2748
2749 \sa addTopLevelItems()
2750*/
2751void QTreeWidget::insertTopLevelItems(int index, const QList<QTreeWidgetItem*> &items)
2752{
2753 Q_D(QTreeWidget);
2754 d->treeModel()->rootItem->insertChildren(index, children: items);
2755}
2756
2757/*!
2758 Appends the list of \a items as a top-level items in the widget.
2759
2760 \sa insertTopLevelItems()
2761*/
2762void QTreeWidget::addTopLevelItems(const QList<QTreeWidgetItem*> &items)
2763{
2764 insertTopLevelItems(index: topLevelItemCount(), items);
2765}
2766
2767/*!
2768 Returns the item used for the tree widget's header.
2769
2770 \sa setHeaderItem()
2771*/
2772
2773QTreeWidgetItem *QTreeWidget::headerItem() const
2774{
2775 Q_D(const QTreeWidget);
2776 return d->treeModel()->headerItem;
2777}
2778
2779/*!
2780 Sets the header \a item for the tree widget. The label for each column in
2781 the header is supplied by the corresponding label in the item.
2782
2783 The tree widget takes ownership of the item.
2784
2785 \sa headerItem(), setHeaderLabels()
2786*/
2787
2788void QTreeWidget::setHeaderItem(QTreeWidgetItem *item)
2789{
2790 Q_D(QTreeWidget);
2791 if (!item)
2792 return;
2793 item->view = this;
2794
2795 int oldCount = columnCount();
2796 if (oldCount < item->columnCount())
2797 d->treeModel()->beginInsertColumns(parent: QModelIndex(), first: oldCount, last: item->columnCount() - 1);
2798 else if (oldCount > item->columnCount())
2799 d->treeModel()->beginRemoveColumns(parent: QModelIndex(), first: item->columnCount(), last: oldCount - 1);
2800 delete d->treeModel()->headerItem;
2801 d->treeModel()->headerItem = item;
2802 if (oldCount < item->columnCount())
2803 d->treeModel()->endInsertColumns();
2804 else if (oldCount > item->columnCount())
2805 d->treeModel()->endRemoveColumns();
2806 d->treeModel()->headerDataChanged(orientation: Qt::Horizontal, first: 0, last: oldCount);
2807}
2808
2809
2810/*!
2811 Adds a column in the header for each item in the \a labels list, and sets
2812 the label for each column.
2813
2814 Note that setHeaderLabels() won't remove existing columns.
2815
2816 \sa setHeaderItem(), setHeaderLabel()
2817*/
2818void QTreeWidget::setHeaderLabels(const QStringList &labels)
2819{
2820 Q_D(QTreeWidget);
2821 if (columnCount() < labels.size())
2822 setColumnCount(labels.size());
2823 QTreeWidgetItem *item = d->treeModel()->headerItem;
2824 for (int i = 0; i < labels.size(); ++i)
2825 item->setText(column: i, atext: labels.at(i));
2826}
2827
2828/*!
2829 \fn void QTreeWidget::setHeaderLabel(const QString &label)
2830 \since 4.2
2831
2832 Same as setHeaderLabels(QStringList(\a label)).
2833*/
2834
2835/*!
2836 Returns the current item in the tree widget.
2837
2838 \sa setCurrentItem(), currentItemChanged()
2839*/
2840QTreeWidgetItem *QTreeWidget::currentItem() const
2841{
2842 Q_D(const QTreeWidget);
2843 return d->item(index: currentIndex());
2844}
2845
2846/*!
2847 \since 4.1
2848 Returns the current column in the tree widget.
2849
2850 \sa setCurrentItem(), columnCount()
2851*/
2852int QTreeWidget::currentColumn() const
2853{
2854 return currentIndex().column();
2855}
2856
2857/*!
2858 Sets the current \a item in the tree widget.
2859
2860 Unless the selection mode is \l{QAbstractItemView::}{NoSelection},
2861 the item is also selected.
2862
2863 \sa currentItem(), currentItemChanged()
2864*/
2865void QTreeWidget::setCurrentItem(QTreeWidgetItem *item)
2866{
2867 setCurrentItem(item, column: 0);
2868}
2869
2870/*!
2871 \since 4.1
2872 Sets the current \a item in the tree widget and the current column to \a column.
2873
2874 \sa currentItem()
2875*/
2876void QTreeWidget::setCurrentItem(QTreeWidgetItem *item, int column)
2877{
2878 Q_D(QTreeWidget);
2879 setCurrentIndex(d->index(item, column));
2880}
2881
2882/*!
2883 \since 4.4
2884 Sets the current \a item in the tree widget and the current column to \a column,
2885 using the given \a command.
2886
2887 \sa currentItem()
2888*/
2889void QTreeWidget::setCurrentItem(QTreeWidgetItem *item, int column,
2890 QItemSelectionModel::SelectionFlags command)
2891{
2892 Q_D(QTreeWidget);
2893 d->selectionModel->setCurrentIndex(index: d->index(item, column), command);
2894}
2895
2896
2897/*!
2898 Returns a pointer to the item at the coordinates \a p. The coordinates
2899 are relative to the tree widget's \l{QAbstractScrollArea::}{viewport()}.
2900
2901 \sa visualItemRect()
2902*/
2903QTreeWidgetItem *QTreeWidget::itemAt(const QPoint &p) const
2904{
2905 Q_D(const QTreeWidget);
2906 return d->item(index: indexAt(p));
2907}
2908
2909/*!
2910 \fn QTreeWidgetItem *QTreeWidget::itemAt(int x, int y) const
2911 \overload
2912
2913 Returns a pointer to the item at the coordinates (\a x, \a y). The coordinates
2914 are relative to the tree widget's \l{QAbstractScrollArea::}{viewport()}.
2915*/
2916
2917/*!
2918 Returns the rectangle on the viewport occupied by the item at \a item.
2919
2920 \sa itemAt()
2921*/
2922QRect QTreeWidget::visualItemRect(const QTreeWidgetItem *item) const
2923{
2924 Q_D(const QTreeWidget);
2925 //the visual rect for an item is across all columns. So we need to determine
2926 //what is the first and last column and get their visual index rects
2927 const QModelIndex base = d->index(item);
2928 const int firstVisiblesection = header()->logicalIndexAt(position: - header()->offset());
2929 const int lastVisibleSection = header()->logicalIndexAt(position: header()->length() - header()->offset() - 1);
2930 const QModelIndex first = base.sibling(arow: base.row(), acolumn: firstVisiblesection);
2931 const QModelIndex last = base.sibling(arow: base.row(), acolumn: lastVisibleSection);
2932 return visualRect(index: first) | visualRect(index: last);
2933}
2934
2935/*!
2936 \since 4.1
2937
2938 Returns the column used to sort the contents of the widget.
2939
2940 \sa sortItems()
2941*/
2942int QTreeWidget::sortColumn() const
2943{
2944 Q_D(const QTreeWidget);
2945 return (d->explicitSortColumn != -1
2946 ? d->explicitSortColumn
2947 : header()->sortIndicatorSection());
2948}
2949
2950/*!
2951 Sorts the items in the widget in the specified \a order by the values in
2952 the given \a column.
2953
2954 \sa sortColumn()
2955*/
2956
2957void QTreeWidget::sortItems(int column, Qt::SortOrder order)
2958{
2959 Q_D(QTreeWidget);
2960 header()->setSortIndicator(logicalIndex: column, order);
2961 d->model->sort(column, order);
2962}
2963
2964/*!
2965 Starts editing the \a item in the given \a column if it is editable.
2966*/
2967
2968void QTreeWidget::editItem(QTreeWidgetItem *item, int column)
2969{
2970 Q_D(QTreeWidget);
2971 edit(index: d->index(item, column));
2972}
2973
2974/*!
2975 Opens a persistent editor for the \a item in the given \a column.
2976
2977 \sa closePersistentEditor(), isPersistentEditorOpen()
2978*/
2979
2980void QTreeWidget::openPersistentEditor(QTreeWidgetItem *item, int column)
2981{
2982 Q_D(QTreeWidget);
2983 QAbstractItemView::openPersistentEditor(index: d->index(item, column));
2984}
2985
2986/*!
2987 Closes the persistent editor for the \a item in the given \a column.
2988
2989 This function has no effect if no persistent editor is open for this
2990 combination of item and column.
2991
2992 \sa openPersistentEditor(), isPersistentEditorOpen()
2993*/
2994
2995void QTreeWidget::closePersistentEditor(QTreeWidgetItem *item, int column)
2996{
2997 Q_D(QTreeWidget);
2998 QAbstractItemView::closePersistentEditor(index: d->index(item, column));
2999}
3000
3001/*!
3002 \since 5.10
3003
3004 Returns whether a persistent editor is open for item \a item in
3005 column \a column.
3006
3007 \sa openPersistentEditor(), closePersistentEditor()
3008*/
3009
3010bool QTreeWidget::isPersistentEditorOpen(QTreeWidgetItem *item, int column) const
3011{
3012 Q_D(const QTreeWidget);
3013 return QAbstractItemView::isPersistentEditorOpen(index: d->index(item, column));
3014}
3015
3016/*!
3017 \since 4.1
3018
3019 Returns the widget displayed in the cell specified by \a item and the given \a column.
3020
3021 \sa setItemWidget(), removeItemWidget()
3022*/
3023QWidget *QTreeWidget::itemWidget(QTreeWidgetItem *item, int column) const
3024{
3025 Q_D(const QTreeWidget);
3026 return QAbstractItemView::indexWidget(index: d->index(item, column));
3027}
3028
3029/*!
3030 \since 4.1
3031
3032 Sets the given \a widget to be displayed in the cell specified by the given
3033 \a item and \a column.
3034
3035 The given \a widget's \l {QWidget::}{autoFillBackground} property must be
3036 set to true, otherwise the widget's background will be transparent, showing
3037 both the model data and the tree widget item.
3038
3039 This function should only be used to display static content in the place of
3040 a tree widget item. If you want to display custom dynamic content or
3041 implement a custom editor widget, use QTreeView and subclass QStyledItemDelegate
3042 instead.
3043
3044 This function cannot be called before the item hierarchy has been set up,
3045 i.e., the QTreeWidgetItem that will hold \a widget must have been added to
3046 the view before \a widget is set.
3047
3048 \note The tree takes ownership of \a widget.
3049
3050 \sa itemWidget(), removeItemWidget(), {Delegate Classes}
3051*/
3052void QTreeWidget::setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget)
3053{
3054 Q_D(QTreeWidget);
3055 QAbstractItemView::setIndexWidget(index: d->index(item, column), widget);
3056}
3057
3058/*!
3059 Returns a list of all selected non-hidden items.
3060
3061 \sa itemSelectionChanged()
3062*/
3063QList<QTreeWidgetItem*> QTreeWidget::selectedItems() const
3064{
3065 Q_D(const QTreeWidget);
3066 const QModelIndexList indexes = selectionModel()->selectedIndexes();
3067 QList<QTreeWidgetItem*> items;
3068 items.reserve(asize: indexes.size());
3069 QDuplicateTracker<QTreeWidgetItem *> seen(indexes.size());
3070 for (const auto &index : indexes) {
3071 QTreeWidgetItem *item = d->item(index);
3072 if (item->isHidden() || seen.hasSeen(s: item))
3073 continue;
3074 items.append(t: item);
3075 }
3076 return items;
3077}
3078
3079/*!
3080 Returns a list of items that match the given \a text, using the given \a flags, in the given \a column.
3081*/
3082QList<QTreeWidgetItem*> QTreeWidget::findItems(const QString &text, Qt::MatchFlags flags, int column) const
3083{
3084 Q_D(const QTreeWidget);
3085 QModelIndexList indexes = d->model->match(start: model()->index(row: 0, column, parent: QModelIndex()),
3086 role: Qt::DisplayRole, value: text, hits: -1, flags);
3087 QList<QTreeWidgetItem*> items;
3088 const int indexesSize = indexes.size();
3089 items.reserve(asize: indexesSize);
3090 for (int i = 0; i < indexesSize; ++i)
3091 items.append(t: d->item(index: indexes.at(i)));
3092 return items;
3093}
3094
3095
3096/*!
3097 \since 4.3
3098
3099 Returns the item above the given \a item.
3100*/
3101QTreeWidgetItem *QTreeWidget::itemAbove(const QTreeWidgetItem *item) const
3102{
3103 Q_D(const QTreeWidget);
3104 if (item == d->treeModel()->headerItem)
3105 return nullptr;
3106 const QModelIndex index = d->index(item);
3107 const QModelIndex above = indexAbove(index);
3108 return d->item(index: above);
3109}
3110
3111/*!
3112 \since 4.3
3113
3114 Returns the item visually below the given \a item.
3115*/
3116QTreeWidgetItem *QTreeWidget::itemBelow(const QTreeWidgetItem *item) const
3117{
3118 Q_D(const QTreeWidget);
3119 if (item == d->treeModel()->headerItem)
3120 return nullptr;
3121 const QModelIndex index = d->index(item);
3122 const QModelIndex below = indexBelow(index);
3123 return d->item(index: below);
3124}
3125
3126/*!
3127 \reimp
3128 */
3129void QTreeWidget::setSelectionModel(QItemSelectionModel *selectionModel)
3130{
3131 Q_D(QTreeWidget);
3132 QTreeView::setSelectionModel(selectionModel);
3133 QItemSelection newSelection = selectionModel->selection();
3134 if (!newSelection.isEmpty())
3135 d->selectionChanged(selected: newSelection, deselected: QItemSelection());
3136}
3137
3138/*!
3139 Ensures that the \a item is visible, scrolling the view if necessary using
3140 the specified \a hint.
3141
3142 \sa currentItem(), itemAt(), topLevelItem()
3143*/
3144void QTreeWidget::scrollToItem(const QTreeWidgetItem *item, QAbstractItemView::ScrollHint hint)
3145{
3146 Q_D(QTreeWidget);
3147 QTreeView::scrollTo(index: d->index(item), hint);
3148}
3149
3150/*!
3151 Expands the \a item. This causes the tree containing the item's children
3152 to be expanded.
3153
3154 \sa collapseItem(), currentItem(), itemAt(), topLevelItem(), itemExpanded()
3155*/
3156void QTreeWidget::expandItem(const QTreeWidgetItem *item)
3157{
3158 Q_D(QTreeWidget);
3159 QTreeModel::SkipSorting skipSorting(d->treeModel());
3160 expand(index: d->index(item));
3161}
3162
3163/*!
3164 Closes the \a item. This causes the tree containing the item's children
3165 to be collapsed.
3166
3167 \sa expandItem(), currentItem(), itemAt(), topLevelItem()
3168*/
3169void QTreeWidget::collapseItem(const QTreeWidgetItem *item)
3170{
3171 Q_D(QTreeWidget);
3172 QTreeModel::SkipSorting skipSorting(d->treeModel());
3173 collapse(index: d->index(item));
3174}
3175
3176/*!
3177 Clears the tree widget by removing all of its items and selections.
3178
3179 \b{Note:} Since each item is removed from the tree widget before being
3180 deleted, the return value of QTreeWidgetItem::treeWidget() will be invalid
3181 when called from an item's destructor.
3182
3183 \sa takeTopLevelItem(), topLevelItemCount(), columnCount()
3184*/
3185void QTreeWidget::clear()
3186{
3187 Q_D(QTreeWidget);
3188 selectionModel()->clear();
3189 d->treeModel()->clear();
3190}
3191
3192/*!
3193 Returns a list of MIME types that can be used to describe a list of
3194 treewidget items.
3195
3196 \sa mimeData()
3197*/
3198QStringList QTreeWidget::mimeTypes() const
3199{
3200 return model()->QAbstractItemModel::mimeTypes();
3201}
3202
3203/*!
3204 Returns an object that contains a serialized description of the specified
3205 \a items. The format used to describe the items is obtained from the
3206 mimeTypes() function.
3207
3208 If the list of items is empty, \nullptr is returned rather than a
3209 serialized empty list.
3210*/
3211QMimeData *QTreeWidget::mimeData(const QList<QTreeWidgetItem *> &items) const
3212{
3213 Q_D(const QTreeWidget);
3214 if (d->treeModel()->cachedIndexes.isEmpty()) {
3215 QList<QModelIndex> indexes;
3216 for (const auto *item : items) {
3217 if (Q_UNLIKELY(!item)) {
3218 qWarning(msg: "QTreeWidget::mimeData: Null-item passed");
3219 return nullptr;
3220 }
3221
3222 for (int c = 0; c < item->values.size(); ++c) {
3223 const QModelIndex index = indexFromItem(item, column: c);
3224 if (Q_UNLIKELY(!index.isValid())) {
3225 qWarning() << "QTreeWidget::mimeData: No index associated with item :" << item;
3226 return nullptr;
3227 }
3228 indexes << index;
3229 }
3230 }
3231 return d->model->QAbstractItemModel::mimeData(indexes);
3232 }
3233 return d->treeModel()->internalMimeData();
3234}
3235
3236/*!
3237 Handles the \a data supplied by a drag and drop operation that ended with
3238 the given \a action in the \a index in the given \a parent item.
3239
3240 The default implementation returns \c true if the drop was
3241 successfully handled by decoding the mime data and inserting it
3242 into the model; otherwise it returns \c false.
3243
3244 \sa supportedDropActions()
3245*/
3246bool QTreeWidget::dropMimeData(QTreeWidgetItem *parent, int index,
3247 const QMimeData *data, Qt::DropAction action)
3248{
3249 QModelIndex idx;
3250 if (parent) idx = indexFromItem(item: parent);
3251 return model()->QAbstractItemModel::dropMimeData(data, action , row: index, column: 0, parent: idx);
3252}
3253
3254/*!
3255 Returns the drop actions supported by this view.
3256
3257 \sa Qt::DropActions
3258*/
3259Qt::DropActions QTreeWidget::supportedDropActions() const
3260{
3261 return model()->QAbstractItemModel::supportedDropActions() | Qt::MoveAction;
3262}
3263
3264/*!
3265 Returns the QModelIndex associated with the given \a item in the given \a column.
3266
3267 \note In Qt versions prior to 5.7, this function took a non-\c{const} \a item.
3268
3269 \sa itemFromIndex(), topLevelItem()
3270*/
3271QModelIndex QTreeWidget::indexFromItem(const QTreeWidgetItem *item, int column) const
3272{
3273 Q_D(const QTreeWidget);
3274 return d->index(item, column);
3275}
3276
3277/*!
3278 Returns a pointer to the QTreeWidgetItem associated with the given \a index.
3279
3280 \sa indexFromItem()
3281*/
3282QTreeWidgetItem *QTreeWidget::itemFromIndex(const QModelIndex &index) const
3283{
3284 Q_D(const QTreeWidget);
3285 return d->item(index);
3286}
3287
3288#if QT_CONFIG(draganddrop)
3289/*! \reimp */
3290void QTreeWidget::dropEvent(QDropEvent *event) {
3291 Q_D(QTreeWidget);
3292 if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
3293 dragDropMode() == QAbstractItemView::InternalMove)) {
3294 QModelIndex topIndex;
3295 int col = -1;
3296 int row = -1;
3297 // check whether a subclass has already accepted the event, ie. moved the data
3298 if (!event->isAccepted() && d->dropOn(event, row: &row, col: &col, index: &topIndex)) {
3299 const QList<QModelIndex> idxs = selectedIndexes();
3300 QList<QPersistentModelIndex> indexes;
3301 const int indexesCount = idxs.size();
3302 indexes.reserve(asize: indexesCount);
3303 for (const auto &idx : idxs)
3304 indexes.append(t: idx);
3305
3306 if (indexes.contains(t: topIndex))
3307 return;
3308
3309 // When removing items the drop location could shift
3310 QPersistentModelIndex dropRow = model()->index(row, column: col, parent: topIndex);
3311
3312 // Remove the items
3313 QList<QTreeWidgetItem *> taken;
3314 for (const auto &index : indexes) {
3315 QTreeWidgetItem *parent = itemFromIndex(index);
3316 if (!parent || !parent->parent()) {
3317 taken.append(t: takeTopLevelItem(index: index.row()));
3318 } else {
3319 taken.append(t: parent->parent()->takeChild(index: index.row()));
3320 }
3321 }
3322
3323 // insert them back in at their new positions
3324 for (int i = 0; i < indexes.size(); ++i) {
3325 // Either at a specific point or appended
3326 if (row == -1) {
3327 if (topIndex.isValid()) {
3328 QTreeWidgetItem *parent = itemFromIndex(index: topIndex);
3329 parent->insertChild(index: parent->childCount(), child: taken.takeFirst());
3330 } else {
3331 insertTopLevelItem(index: topLevelItemCount(), item: taken.takeFirst());
3332 }
3333 } else {
3334 int r = dropRow.row() >= 0 ? dropRow.row() : row;
3335 if (topIndex.isValid()) {
3336 QTreeWidgetItem *parent = itemFromIndex(index: topIndex);
3337 parent->insertChild(index: qMin(a: r, b: parent->childCount()), child: taken.takeFirst());
3338 } else {
3339 insertTopLevelItem(index: qMin(a: r, b: topLevelItemCount()), item: taken.takeFirst());
3340 }
3341 }
3342 }
3343
3344 event->accept();
3345 }
3346 // either we or a subclass accepted the move event, so assume that the data was
3347 // moved and that QAbstractItemView shouldn't remove the source when QDrag::exec returns
3348 if (event->isAccepted())
3349 d->dropEventMoved = true;
3350 }
3351
3352 QTreeView::dropEvent(event);
3353}
3354#endif
3355
3356/*!
3357 \reimp
3358*/
3359
3360void QTreeWidget::setModel(QAbstractItemModel * /*model*/)
3361{
3362 Q_ASSERT(!"QTreeWidget::setModel() - Changing the model of the QTreeWidget is not allowed.");
3363}
3364
3365/*!
3366 \reimp
3367*/
3368bool QTreeWidget::event(QEvent *e)
3369{
3370 Q_D(QTreeWidget);
3371 if (e->type() == QEvent::Polish)
3372 d->treeModel()->executePendingSort();
3373 return QTreeView::event(event: e);
3374}
3375
3376/*!
3377 see QTBUG-94546
3378*/
3379void QTreeModelPrivate::executePendingOperations() const
3380{
3381 q_func()->executePendingSort();
3382}
3383
3384QT_END_NAMESPACE
3385
3386#include "moc_qtreewidget.cpp"
3387#include "moc_qtreewidget_p.cpp"
3388

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/widgets/itemviews/qtreewidget.cpp