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