Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtreeview.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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#include "qtreeview.h"
4
5#include <qheaderview.h>
7#include <qapplication.h>
8#include <qscrollbar.h>
9#include <qpainter.h>
10#include <qstack.h>
11#include <qstyle.h>
12#include <qstyleoption.h>
13#include <qevent.h>
14#include <qpen.h>
15#include <qdebug.h>
16#include <QMetaMethod>
17#include <private/qscrollbar_p.h>
18#if QT_CONFIG(accessibility)
19#include <qaccessible.h>
20#endif
21
22#include <private/qapplication_p.h>
23#include <private/qtreeview_p.h>
24#include <private/qheaderview_p.h>
25
26#include <algorithm>
27
29
151 : QAbstractItemView(*new QTreeViewPrivate, parent)
152{
153 Q_D(QTreeView);
154 d->initialize();
155}
156
161 : QAbstractItemView(dd, parent)
162{
163 Q_D(QTreeView);
164 d->initialize();
165}
166
171{
172 Q_D(QTreeView);
173 d->clearConnections();
174}
175
180{
181 Q_D(QTreeView);
182 if (model == d->model)
183 return;
184 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
185 for (const QMetaObject::Connection &connection : d->modelConnections)
187 }
188
189 if (d->selectionModel) { // support row editing
190 QObject::disconnect(d->selectionmodelConnection);
191 }
192 d->viewItems.clear();
193 d->expandedIndexes.clear();
194 d->hiddenIndexes.clear();
195 d->geometryRecursionBlock = true; // do not update geometries due to signals from the headers
196 d->header->setModel(model);
197 d->geometryRecursionBlock = false;
199
200 if (d->model) {
201 // QAbstractItemView connects to a private slot
204 // do header layout after the tree
206 d->header->d_func(), &QAbstractItemViewPrivate::layoutChanged);
207
208 d->modelConnections = {
209 // QTreeView has a public slot for this
214 };
215 }
216 if (d->sortingEnabled)
217 d->sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
218}
219
224{
225 Q_D(QTreeView);
226 d->header->setRootIndex(index);
228}
229
234{
235 Q_D(QTreeView);
237 if (d->selectionModel) {
238 // support row editing
239 QObject::disconnect(d->selectionmodelConnection);
240 }
241
242 d->header->setSelectionModel(selectionModel);
244
245 if (d->selectionModel) {
246 // support row editing
247 d->selectionmodelConnection =
250 }
251}
252
259{
260 Q_D(const QTreeView);
261 return d->header;
262}
263
273{
274 Q_D(QTreeView);
275 if (header == d->header || !header)
276 return;
277 if (d->header && d->header->parent() == this)
278 delete d->header;
279 d->header = header;
280 d->header->setParent(this);
281 d->header->setFirstSectionMovable(false);
282
283 if (!d->header->model()) {
284 d->header->setModel(d->model);
285 if (d->selectionModel)
286 d->header->setSelectionModel(d->selectionModel);
287 }
288
289 d->headerConnections = {
300 };
301
302 setSortingEnabled(d->sortingEnabled);
303 d->updateGeometry();
304}
305
318{
319 Q_D(const QTreeView);
320 return d->autoExpandDelay;
321}
322
324{
325 Q_D(QTreeView);
326 d->autoExpandDelay = delay;
327}
328
343{
344 Q_D(const QTreeView);
345 return d->indent;
346}
347
349{
350 Q_D(QTreeView);
351 if (!d->customIndent || (i != d->indent)) {
352 d->indent = i;
353 d->customIndent = true;
354 d->viewport->update();
355 }
356}
357
359{
360 Q_D(QTreeView);
361 if (d->customIndent) {
362 d->updateIndentationFromStyle();
363 d->customIndent = false;
364 }
365}
366
379{
380 Q_D(const QTreeView);
381 return d->rootDecoration;
382}
383
385{
386 Q_D(QTreeView);
387 if (show != d->rootDecoration) {
388 d->rootDecoration = show;
389 d->viewport->update();
390 }
391}
392
410{
411 Q_D(const QTreeView);
412 return d->uniformRowHeights;
413}
414
416{
417 Q_D(QTreeView);
418 d->uniformRowHeights = uniform;
419}
420
432{
433 Q_D(const QTreeView);
434 return d->itemsExpandable;
435}
436
438{
439 Q_D(QTreeView);
440 d->itemsExpandable = enable;
441}
442
454{
455 Q_D(const QTreeView);
456 return d->expandsOnDoubleClick;
457}
458
460{
461 Q_D(QTreeView);
462 d->expandsOnDoubleClick = enable;
463}
464
469{
470 Q_D(const QTreeView);
471 return d->header->sectionViewportPosition(column);
472}
473
480{
481 Q_D(const QTreeView);
482 return d->header->sectionSize(column);
483}
484
493{
494 Q_D(QTreeView);
495 d->header->resizeSection(column, width);
496}
497
502int QTreeView::columnAt(int x) const
503{
504 Q_D(const QTreeView);
505 return d->header->logicalIndexAt(x);
506}
507
514{
515 Q_D(const QTreeView);
516 return d->header->isSectionHidden(column);
517}
518
525{
526 Q_D(QTreeView);
527 if (column < 0 || column >= d->header->count())
528 return;
529 d->header->setSectionHidden(column, hide);
530}
531
543{
544 Q_D(const QTreeView);
545 return d->header->isHidden();
546}
547
549{
550 Q_D(QTreeView);
551 d->header->setHidden(hide);
552}
553
560bool QTreeView::isRowHidden(int row, const QModelIndex &parent) const
561{
562 Q_D(const QTreeView);
563 if (!d->model)
564 return false;
565 return d->isRowHidden(d->model->index(row, 0, parent));
566}
567
573void QTreeView::setRowHidden(int row, const QModelIndex &parent, bool hide)
574{
575 Q_D(QTreeView);
576 if (!d->model)
577 return;
578 QModelIndex index = d->model->index(row, 0, parent);
579 if (!index.isValid())
580 return;
581
582 if (hide) {
583 d->hiddenIndexes.insert(index);
584 } else if (d->isPersistent(index)) { //if the index is not persistent, it cannot be in the set
585 d->hiddenIndexes.remove(index);
586 }
587
588 d->doDelayedItemsLayout();
589}
590
599bool QTreeView::isFirstColumnSpanned(int row, const QModelIndex &parent) const
600{
601 Q_D(const QTreeView);
602 if (d->spanningIndexes.isEmpty() || !d->model)
603 return false;
604 const QModelIndex index = d->model->index(row, 0, parent);
605 return d->spanningIndexes.contains(index);
606}
607
618{
619 Q_D(QTreeView);
620 if (!d->model)
621 return;
622 const QModelIndex index = d->model->index(row, 0, parent);
623 if (!index.isValid())
624 return;
625
626 if (span)
627 d->spanningIndexes.insert(index);
628 else
629 d->spanningIndexes.remove(index);
630
631 d->executePostedLayout();
632 int i = d->viewIndex(index);
633 if (i >= 0)
634 d->viewItems[i].spanning = span;
635
636 d->viewport->update();
637}
638
642void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
643 const QList<int> &roles)
644{
645 Q_D(QTreeView);
646
647 // if we are going to do a complete relayout anyway, there is no need to update
648 if (d->delayedPendingLayout)
649 return;
650
651 // refresh the height cache here; we don't really lose anything by getting the size hint,
652 // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway
653
654 bool sizeChanged = false;
655 int topViewIndex = d->viewIndex(topLeft);
656 if (topViewIndex == 0) {
657 int newDefaultItemHeight = indexRowSizeHint(topLeft);
658 sizeChanged = d->defaultItemHeight != newDefaultItemHeight;
659 d->defaultItemHeight = newDefaultItemHeight;
660 }
661
662 if (topViewIndex != -1) {
663 if (topLeft.row() == bottomRight.row()) {
664 int oldHeight = d->itemHeight(topViewIndex);
665 d->invalidateHeightCache(topViewIndex);
666 sizeChanged |= (oldHeight != d->itemHeight(topViewIndex));
667 if (topLeft.column() == 0)
668 d->viewItems[topViewIndex].hasChildren = d->hasVisibleChildren(topLeft);
669 } else {
670 int bottomViewIndex = d->viewIndex(bottomRight);
671 for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
672 int oldHeight = d->itemHeight(i);
673 d->invalidateHeightCache(i);
674 sizeChanged |= (oldHeight != d->itemHeight(i));
675 if (topLeft.column() == 0)
676 d->viewItems[i].hasChildren = d->hasVisibleChildren(d->viewItems.at(i).index);
677 }
678 }
679 }
680
681 if (sizeChanged) {
682 d->updateScrollBars();
683 d->viewport->update();
684 }
685 QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
686}
687
698{
699 Q_D(QTreeView);
700 if (d->header->isSectionHidden(column))
701 return;
702 d->header->hideSection(column);
704}
705
712{
713 Q_D(QTreeView);
714 if (!d->header->isSectionHidden(column))
715 return;
716 d->header->showSection(column);
718}
719
728{
729 Q_D(QTreeView);
730 if (!d->isIndexValid(index))
731 return;
732 if (index.flags() & Qt::ItemNeverHasChildren)
733 return;
734 if (d->isIndexExpanded(index))
735 return;
736 if (d->delayedPendingLayout) {
737 //A complete relayout is going to be performed, just store the expanded index, no need to layout.
738 if (d->storeExpanded(index))
740 return;
741 }
742
743 int i = d->viewIndex(index);
744 if (i != -1) { // is visible
745 d->expand(i, true);
746 if (!d->isAnimating()) {
748 d->viewport->update();
749 }
750 } else if (d->storeExpanded(index)) {
752 }
753}
754
763{
764 Q_D(QTreeView);
765 if (!d->isIndexValid(index))
766 return;
767 if (!d->isIndexExpanded(index))
768 return;
769 //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
770 d->delayedAutoScroll.stop();
771
772 if (d->delayedPendingLayout) {
773 //A complete relayout is going to be performed, just un-store the expanded index, no need to layout.
774 if (d->isPersistent(index) && d->expandedIndexes.remove(index))
776 return;
777 }
778 int i = d->viewIndex(index);
779 if (i != -1) { // is visible
780 d->collapse(i, true);
781 if (!d->isAnimating()) {
783 viewport()->update();
784 }
785 } else {
786 if (d->isPersistent(index) && d->expandedIndexes.remove(index))
788 }
789}
790
800{
801 Q_D(const QTreeView);
802 return d->isIndexExpanded(index);
803}
804
811void QTreeView::setExpanded(const QModelIndex &index, bool expanded)
812{
813 if (expanded)
814 this->expand(index);
815 else
816 this->collapse(index);
817}
818
836{
837 Q_D(QTreeView);
840 if (enable) {
841 //sortByColumn has to be called before we connect or set the sortingEnabled flag
842 // because otherwise it will not call sort on the model.
843 sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
844 d->sortHeaderConnection =
848 } else {
849 QObject::disconnect(d->sortHeaderConnection);
850 }
851 d->sortingEnabled = enable;
852}
853
855{
856 Q_D(const QTreeView);
857 return d->sortingEnabled;
858}
859
873void QTreeView::setAnimated(bool animate)
874{
875 Q_D(QTreeView);
876 d->animationsEnabled = animate;
877}
878
880{
881 Q_D(const QTreeView);
882 return d->animationsEnabled;
883}
884
897{
898 Q_D(QTreeView);
899 if (d->allColumnsShowFocus == enable)
900 return;
901 d->allColumnsShowFocus = enable;
902 d->viewport->update();
903}
904
906{
907 Q_D(const QTreeView);
908 return d->allColumnsShowFocus;
909}
910
925{
926 Q_D(QTreeView);
927 if (d->wrapItemText == on)
928 return;
929 d->wrapItemText = on;
930 d->doDelayedItemsLayout();
931}
932
934{
935 Q_D(const QTreeView);
936 return d->wrapItemText;
937}
938
949{
950 Q_D(QTreeView);
951 d->treePosition = index;
952 d->viewport->update();
953}
954
965{
966 Q_D(const QTreeView);
967 return d->treePosition;
968}
969
974{
975 Q_D(QTreeView);
976 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
977 return;
978
979 // Do a relayout nows, so that we can utilize viewItems
980 d->executePostedLayout();
981 if (d->viewItems.isEmpty())
982 return;
983
985 if (currentIndex().isValid())
987 else
988 start = d->viewItems.at(0).index;
989
990 bool skipRow = false;
991 bool keyboardTimeWasValid = d->keyboardInputTime.isValid();
992 qint64 keyboardInputTimeElapsed;
993 if (keyboardTimeWasValid)
994 keyboardInputTimeElapsed = d->keyboardInputTime.restart();
995 else
996 d->keyboardInputTime.start();
997 if (search.isEmpty() || !keyboardTimeWasValid
998 || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) {
999 d->keyboardInput = search;
1000 skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
1001 } else {
1002 d->keyboardInput += search;
1003 }
1004
1005 // special case for searches with same key like 'aaaaa'
1006 bool sameKey = false;
1007 if (d->keyboardInput.size() > 1) {
1008 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.size() - 1));
1009 sameKey = (c == d->keyboardInput.size());
1010 if (sameKey)
1011 skipRow = true;
1012 }
1013
1014 // skip if we are searching for the same key or a new search started
1015 if (skipRow) {
1016 if (indexBelow(start).isValid()) {
1018 } else {
1019 const int origCol = start.column();
1020 start = d->viewItems.at(0).index;
1021 if (origCol != start.column())
1022 start = start.sibling(start.row(), origCol);
1023 }
1024 }
1025
1026 int startIndex = d->viewIndex(start);
1027 if (startIndex <= -1)
1028 return;
1029
1030 int previousLevel = -1;
1031 int bestAbove = -1;
1032 int bestBelow = -1;
1033 QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput;
1034 for (int i = 0; i < d->viewItems.size(); ++i) {
1035 if ((int)d->viewItems.at(i).level > previousLevel) {
1036 QModelIndex searchFrom = d->viewItems.at(i).index;
1037 if (start.column() > 0)
1038 searchFrom = searchFrom.sibling(searchFrom.row(), start.column());
1039 if (searchFrom.parent() == start.parent())
1040 searchFrom = start;
1041 QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString);
1042 if (match.size()) {
1043 int hitIndex = d->viewIndex(match.at(0));
1044 if (hitIndex >= 0 && hitIndex < startIndex)
1045 bestAbove = bestAbove == -1 ? hitIndex : qMin(hitIndex, bestAbove);
1046 else if (hitIndex >= startIndex)
1047 bestBelow = bestBelow == -1 ? hitIndex : qMin(hitIndex, bestBelow);
1048 }
1049 }
1050 previousLevel = d->viewItems.at(i).level;
1051 }
1052
1054 if (bestBelow > -1)
1055 index = d->viewItems.at(bestBelow).index;
1056 else if (bestAbove > -1)
1057 index = d->viewItems.at(bestAbove).index;
1058
1059 if (start.column() > 0)
1060 index = index.sibling(index.row(), start.column());
1061
1062 if (index.isValid())
1064}
1065
1071{
1072 Q_D(const QTreeView);
1073 return d->visualRect(index, QTreeViewPrivate::SingleSection);
1074}
1075
1091{
1092 Q_Q(const QTreeView);
1093
1094 if (!isIndexValid(index))
1095 return QRect();
1096
1097 // Calculate the entire row's rectangle, even if one of the elements is hidden
1098 if (q->isIndexHidden(index) && rule != FullRow)
1099 return QRect();
1100
1102
1103 const int viewIndex = this->viewIndex(index);
1104 if (viewIndex < 0)
1105 return QRect();
1106
1107 const bool spanning = viewItems.at(viewIndex).spanning;
1108 const int column = index.column();
1109
1110 // if we have a spanning item, make the selection stretch from left to right
1111 int x = (spanning ? 0 : q->columnViewportPosition(column));
1112 int width = (spanning ? header->length() : q->columnWidth(column));
1113
1114 const bool addIndentation = isTreePosition(column) && (column > 0 || rule == SingleSection);
1115
1116 if (rule == FullRow) {
1117 x = 0;
1118 width = q->viewport()->width();
1119 } else if (addIndentation) {
1120 // calculate indentation
1121 const int indentation = indentationForItem(viewIndex);
1122 width -= indentation;
1123 if (!q->isRightToLeft())
1124 x += indentation;
1125 }
1126
1127 const int y = coordinateForItem(viewIndex);
1128 const int height = itemHeight(viewIndex);
1129
1130 return QRect(x, y, width, height);
1131}
1132
1142{
1143 Q_D(QTreeView);
1144
1145 if (!d->isIndexValid(index))
1146 return;
1147
1148 d->executePostedLayout();
1149 d->updateScrollBars();
1150
1151 // Expand all parents if the parent(s) of the node are not expanded.
1152 QModelIndex parent = index.parent();
1153 while (parent != d->root && parent.isValid() && state() == NoState && d->itemsExpandable) {
1154 if (!isExpanded(parent))
1155 expand(parent);
1156 parent = d->model->parent(parent);
1157 }
1158
1159 int item = d->viewIndex(index);
1160 if (item < 0)
1161 return;
1162
1163 QRect area = d->viewport->rect();
1164
1165 // vertical
1167 int top = verticalScrollBar()->value();
1168 int bottom = top + verticalScrollBar()->pageStep();
1169 if (hint == EnsureVisible && item >= top && item < bottom) {
1170 // nothing to do
1171 } else if (hint == PositionAtTop || (hint == EnsureVisible && item < top)) {
1172 verticalScrollBar()->setValue(item);
1173 } else { // PositionAtBottom or PositionAtCenter
1174 const int currentItemHeight = d->itemHeight(item);
1175 int y = (hint == PositionAtCenter
1176 //we center on the current item with a preference to the top item (ie. -1)
1177 ? area.height() / 2 + currentItemHeight - 1
1178 //otherwise we simply take the whole space
1179 : area.height());
1180 if (y > currentItemHeight) {
1181 while (item >= 0) {
1182 y -= d->itemHeight(item);
1183 if (y < 0) { //there is no more space left
1184 item++;
1185 break;
1186 }
1187 item--;
1188 }
1189 }
1190 verticalScrollBar()->setValue(item);
1191 }
1192 } else { // ScrollPerPixel
1194 d->coordinateForItem(item), // ### slow for items outside the view
1195 columnWidth(index.column()),
1196 d->itemHeight(item));
1197
1198 if (rect.isEmpty()) {
1199 // nothing to do
1200 } else if (hint == EnsureVisible && area.contains(rect)) {
1201 d->viewport->update(rect);
1202 // nothing to do
1203 } else {
1204 bool above = (hint == EnsureVisible
1205 && (rect.top() < area.top()
1206 || area.height() < rect.height()));
1207 bool below = (hint == EnsureVisible
1208 && rect.bottom() > area.bottom()
1209 && rect.height() < area.height());
1210
1211 int verticalValue = verticalScrollBar()->value();
1212 if (hint == PositionAtTop || above)
1213 verticalValue += rect.top();
1214 else if (hint == PositionAtBottom || below)
1215 verticalValue += rect.bottom() - area.height();
1216 else if (hint == PositionAtCenter)
1217 verticalValue += rect.top() - ((area.height() - rect.height()) / 2);
1218 verticalScrollBar()->setValue(verticalValue);
1219 }
1220 }
1221 // horizontal
1222 int viewportWidth = d->viewport->width();
1223 int horizontalOffset = d->header->offset();
1224 int horizontalPosition = d->header->sectionPosition(index.column());
1225 int cellWidth = d->header->sectionSize(index.column());
1226
1227 if (hint == PositionAtCenter) {
1228 horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
1229 } else {
1230 if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
1231 horizontalScrollBar()->setValue(horizontalPosition);
1232 else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
1233 horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
1234 }
1235}
1236
1241{
1242 Q_D(QTreeView);
1243 if (event->type() == QEvent::StyleChange) {
1244 if (!d->customIndent) {
1245 // QAbstractItemView calls this method in case of a style change,
1246 // so update the indentation here if it wasn't set manually.
1247 d->updateIndentationFromStyle();
1248 }
1249 }
1250 QAbstractItemView::changeEvent(event);
1251}
1252
1257{
1258 Q_D(QTreeView);
1259 if (event->timerId() == d->columnResizeTimerID) {
1261 killTimer(d->columnResizeTimerID);
1262 d->columnResizeTimerID = 0;
1263 QRect rect;
1264 int viewportHeight = d->viewport->height();
1265 int viewportWidth = d->viewport->width();
1266 for (int i = d->columnsToUpdate.size() - 1; i >= 0; --i) {
1267 int column = d->columnsToUpdate.at(i);
1269 if (isRightToLeft())
1270 rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
1271 else
1272 rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
1273 }
1274 d->viewport->update(rect.normalized());
1275 d->columnsToUpdate.clear();
1276 } else if (event->timerId() == d->openTimer.timerId()) {
1277 QPoint pos = d->viewport->mapFromGlobal(QCursor::pos());
1279 && d->viewport->rect().contains(pos)) {
1282 }
1283 d->openTimer.stop();
1284 }
1285
1287}
1288
1292#if QT_CONFIG(draganddrop)
1293void QTreeView::dragMoveEvent(QDragMoveEvent *event)
1294{
1295 Q_D(QTreeView);
1296 if (d->autoExpandDelay >= 0)
1297 d->openTimer.start(d->autoExpandDelay, this);
1298 QAbstractItemView::dragMoveEvent(event);
1299}
1300#endif
1301
1306{
1307 Q_D(QTreeView);
1308 switch (event->type()) {
1309 case QEvent::HoverEnter:
1310 case QEvent::HoverLeave:
1311 case QEvent::HoverMove: {
1312 QHoverEvent *he = static_cast<QHoverEvent*>(event);
1313 const int oldBranch = d->hoverBranch;
1314 d->hoverBranch = d->itemDecorationAt(he->position().toPoint());
1315 QModelIndex newIndex = indexAt(he->position().toPoint());
1316 if (d->hover != newIndex || d->hoverBranch != oldBranch) {
1317 // Update the whole hovered over row. No need to update the old hovered
1318 // row, that is taken care in superclass hover handling.
1319 viewport()->update(d->visualRect(newIndex, QTreeViewPrivate::FullRow));
1320 }
1321 break; }
1322 default:
1323 break;
1324 }
1326}
1327
1332{
1333 Q_D(QTreeView);
1334 d->executePostedLayout();
1336#if QT_CONFIG(animation)
1337 if (d->isAnimating()) {
1338 drawTree(&painter, event->region() - d->animatedOperation.rect());
1339 d->drawAnimatedOperation(&painter);
1340 } else
1341#endif // animation
1342 {
1343 drawTree(&painter, event->region());
1344#if QT_CONFIG(draganddrop)
1345 d->paintDropIndicator(&painter);
1346#endif
1347 }
1348}
1349
1351{
1352 int index = treePosition;
1353 if (index < 0)
1355 return index;
1356}
1357
1358void QTreeViewPrivate::paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItem *option, int y, int bottom) const
1359{
1360 Q_Q(const QTreeView);
1362 return;
1363 int rowHeight = defaultItemHeight;
1364 if (rowHeight <= 0) {
1365 rowHeight = itemDelegate->sizeHint(*option, QModelIndex()).height();
1366 if (rowHeight <= 0)
1367 return;
1368 }
1369 while (y <= bottom) {
1370 option->rect.setRect(0, y, viewport->width(), rowHeight);
1371 option->features.setFlag(QStyleOptionViewItem::Alternate, current & 1);
1372 ++current;
1373 q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, option, painter, q);
1374 y += rowHeight;
1375 }
1376}
1377
1379{
1380 Q_Q(QTreeView);
1381 // we want to handle mousePress in EditingState (persistent editors)
1384 || !viewport->rect().contains(pos))
1385 return true;
1386
1387 int i = itemDecorationAt(pos);
1388 if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) {
1389 if (viewItems.at(i).expanded)
1390 collapse(i, true);
1391 else
1392 expand(i, true);
1393 if (!isAnimating()) {
1394 q->updateGeometries();
1395 viewport->update();
1396 }
1397 return true;
1398 }
1399 return false;
1400}
1401
1403{
1404 //we need to clear the viewItems because it contains QModelIndexes to
1405 //the model currently being destroyed
1406 viewItems.clear();
1408}
1409
1410QRect QTreeViewPrivate::intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const
1411{
1412 const auto parentIdx = topLeft.parent();
1414 QRect updateRect;
1415 for (int r = topLeft.row(); r <= bottomRight.row(); ++r) {
1416 if (isRowHidden(model->index(r, 0, parentIdx)))
1417 continue;
1418 for (int c = topLeft.column(); c <= bottomRight.column(); ++c) {
1419 const QModelIndex idx(model->index(r, c, parentIdx));
1420 updateRect |= visualRect(idx, SingleSection);
1421 }
1422 }
1423 return rect.intersected(updateRect);
1424}
1425
1432{
1433 Q_ASSERT(r);
1434 Q_Q(const QTreeView);
1438 for (const QModelIndex &idx : indexes) {
1439 if (idx.column() > 0 && q->isFirstColumnSpanned(idx.row(), idx.parent()))
1440 continue;
1441 list << idx;
1442 }
1444}
1445
1446void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItem *option, const QModelIndex &current) const
1447{
1448 const int row = viewIndex(current); // get the index in viewItems[]
1452
1453 option->showDecorationSelected = (selectionBehavior & QTreeView::SelectRows)
1454 || option->showDecorationSelected;
1455
1456 QList<int>
1457 logicalIndices; // index = visual index of visible columns only. data = logical index.
1458 QList<QStyleOptionViewItem::ViewItemPosition>
1459 viewItemPosList; // vector of left/middle/end for each logicalIndex, visible columns
1460 // only.
1461 const bool spanning = viewItems.at(row).spanning;
1462 const int left = (spanning ? header->visualIndex(0) : 0);
1463 const int right = (spanning ? header->visualIndex(0) : header->count() - 1 );
1464 calcLogicalIndices(&logicalIndices, &viewItemPosList, left, right);
1465
1466 const int visualIndex = logicalIndices.indexOf(current.column());
1467 option->viewItemPosition = viewItemPosList.at(visualIndex);
1468}
1469
1470
1478void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
1479{
1480 Q_D(const QTreeView);
1481 // d->viewItems changes when posted layouts are executed in itemDecorationAt, so don't copy
1482 const QList<QTreeViewItem> &viewItems = d->viewItems;
1483
1484 QStyleOptionViewItem option;
1486 const QStyle::State state = option.state;
1487 d->current = 0;
1488
1489 if (viewItems.size() == 0 || d->header->count() == 0 || !d->itemDelegate) {
1490 d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
1491 return;
1492 }
1493
1494 int firstVisibleItemOffset = 0;
1495 const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset);
1496 if (firstVisibleItem < 0) {
1497 d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
1498 return;
1499 }
1500
1501 const int viewportWidth = d->viewport->width();
1502
1503 QPoint hoverPos = d->viewport->mapFromGlobal(QCursor::pos());
1504 d->hoverBranch = d->itemDecorationAt(hoverPos);
1505
1506 QList<int> drawn;
1507 bool multipleRects = (region.rectCount() > 1);
1508 for (const QRect &a : region) {
1509 const QRect area = (multipleRects
1510 ? QRect(0, a.y(), viewportWidth, a.height())
1511 : a);
1512 d->leftAndRight = d->startAndEndColumns(area);
1513
1514 int i = firstVisibleItem; // the first item at the top of the viewport
1515 int y = firstVisibleItemOffset; // we may only see part of the first item
1516
1517 // start at the top of the viewport and iterate down to the update area
1518 for (; i < viewItems.size(); ++i) {
1519 const int itemHeight = d->itemHeight(i);
1520 if (y + itemHeight > area.top())
1521 break;
1522 y += itemHeight;
1523 }
1524
1525 // paint the visible rows
1526 for (; i < viewItems.size() && y <= area.bottom(); ++i) {
1527 const QModelIndex &index = viewItems.at(i).index;
1528 const int itemHeight = d->itemHeight(i);
1529 option.rect = d->visualRect(index, QTreeViewPrivate::FullRow);
1530 option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None)
1531 | (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None)
1532 | (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None);
1533 d->current = i;
1534 d->spanning = viewItems.at(i).spanning;
1535 if (!multipleRects || !drawn.contains(i)) {
1536 drawRow(painter, option, viewItems.at(i).index);
1537 if (multipleRects) // even if the rect only intersects the item,
1538 drawn.append(i); // the entire item will be painted
1539 }
1540 y += itemHeight;
1541 }
1542
1543 if (y <= area.bottom()) {
1544 d->current = i;
1545 d->paintAlternatingRowColors(painter, &option, y, area.bottom());
1546 }
1547 }
1548}
1549
1551static inline bool ancestorOf(QObject *widget, QObject *other)
1552{
1553 for (QObject *parent = other; parent != nullptr; parent = parent->parent()) {
1554 if (parent == widget)
1555 return true;
1556 }
1557 return false;
1558}
1559
1561 QList<int> *logicalIndices, QList<QStyleOptionViewItem::ViewItemPosition> *itemPositions,
1562 int left, int right) const
1563{
1564 const int columnCount = header->count();
1565 /* 'left' and 'right' are the left-most and right-most visible visual indices.
1566 Compute the first visible logical indices before and after the left and right.
1567 We will use these values to determine the QStyleOptionViewItem::viewItemPosition. */
1568 int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1;
1569 for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) {
1570 int logicalIndex = header->logicalIndex(visualIndex);
1571 if (!header->isSectionHidden(logicalIndex)) {
1572 logicalIndexBeforeLeft = logicalIndex;
1573 break;
1574 }
1575 }
1576
1577 for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) {
1578 int logicalIndex = header->logicalIndex(visualIndex);
1579 if (!header->isSectionHidden(logicalIndex)) {
1580 if (visualIndex > right) {
1581 logicalIndexAfterRight = logicalIndex;
1582 break;
1583 }
1584 logicalIndices->append(logicalIndex);
1585 }
1586 }
1587
1588 itemPositions->resize(logicalIndices->size());
1589 for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices->size(); ++currentLogicalSection) {
1590 const int headerSection = logicalIndices->at(currentLogicalSection);
1591 // determine the viewItemPosition depending on the position of column 0
1592 int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices->size()
1593 ? logicalIndexAfterRight
1594 : logicalIndices->at(currentLogicalSection + 1);
1595 int prevLogicalSection = currentLogicalSection - 1 < 0
1596 ? logicalIndexBeforeLeft
1597 : logicalIndices->at(currentLogicalSection - 1);
1598 QStyleOptionViewItem::ViewItemPosition pos;
1599 if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
1600 || (headerSection == 0 && nextLogicalSection == -1) || spanning)
1601 pos = QStyleOptionViewItem::OnlyOne;
1602 else if (isTreePosition(headerSection) || (nextLogicalSection != 0 && prevLogicalSection == -1))
1603 pos = QStyleOptionViewItem::Beginning;
1604 else if (nextLogicalSection == 0 || nextLogicalSection == -1)
1605 pos = QStyleOptionViewItem::End;
1606 else
1607 pos = QStyleOptionViewItem::Middle;
1608 (*itemPositions)[currentLogicalSection] = pos;
1609 }
1610}
1611
1616int QTreeViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const
1617{
1618 Q_Q(const QTreeView);
1620 if (editor && persistent.contains(editor)) {
1621 hint = qMax(hint, editor->sizeHint().width());
1622 int min = editor->minimumSize().width();
1623 int max = editor->maximumSize().width();
1624 hint = qBound(min, hint, max);
1625 }
1626 int xhint = q->itemDelegateForIndex(index)->sizeHint(option, index).width();
1627 hint = qMax(hint, xhint + (isTreePosition(index.column()) ? indentationForItem(i) : 0));
1628 return hint;
1629}
1630
1638void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
1639 const QModelIndex &index) const
1640{
1641 Q_D(const QTreeView);
1642 QStyleOptionViewItem opt = option;
1643 const QPoint offset = d->scrollDelayOffset;
1644 const int y = option.rect.y() + offset.y();
1645 const QModelIndex parent = index.parent();
1646 const QHeaderView *header = d->header;
1647 const QModelIndex current = currentIndex();
1648 const QModelIndex hover = d->hover;
1649 const bool reverse = isRightToLeft();
1650 const QStyle::State state = opt.state;
1651 const bool spanning = d->spanning;
1652 const int left = (spanning ? header->visualIndex(0) : d->leftAndRight.first);
1653 const int right = (spanning ? header->visualIndex(0) : d->leftAndRight.second);
1654 const bool alternate = d->alternatingColors;
1655 const bool enabled = (state & QStyle::State_Enabled) != 0;
1656 const bool allColumnsShowFocus = d->allColumnsShowFocus;
1657
1658
1659 // when the row contains an index widget which has focus,
1660 // we want to paint the entire row as active
1661 bool indexWidgetHasFocus = false;
1662 if ((current.row() == index.row()) && !d->editorIndexHash.isEmpty()) {
1663 const int r = index.row();
1665 for (int c = 0; c < header->count(); ++c) {
1666 QModelIndex idx = d->model->index(r, c, parent);
1667 if (QWidget *editor = indexWidget(idx)) {
1668 if (ancestorOf(editor, fw)) {
1669 indexWidgetHasFocus = true;
1670 break;
1671 }
1672 }
1673 }
1674 }
1675
1676 const bool widgetHasFocus = hasFocus();
1677 bool currentRowHasFocus = false;
1678 if (allColumnsShowFocus && widgetHasFocus && current.isValid()) {
1679 // check if the focus index is before or after the visible columns
1680 const int r = index.row();
1681 for (int c = 0; c < left && !currentRowHasFocus; ++c) {
1682 QModelIndex idx = d->model->index(r, c, parent);
1683 currentRowHasFocus = (idx == current);
1684 }
1685 QModelIndex parent = d->model->parent(index);
1686 for (int c = right; c < header->count() && !currentRowHasFocus; ++c) {
1687 currentRowHasFocus = (d->model->index(r, c, parent) == current);
1688 }
1689 }
1690
1691 // ### special case: if we select entire rows, then we need to draw the
1692 // selection in the first column all the way to the second column, rather
1693 // than just around the item text. We abuse showDecorationSelected to
1694 // indicate this to the style. Below we will reset this value temporarily
1695 // to only respect the styleHint while we are rendering the decoration.
1696 opt.showDecorationSelected = (d->selectionBehavior & SelectRows)
1697 || option.showDecorationSelected;
1698
1699 int width, height = option.rect.height();
1700 int position;
1701 QModelIndex modelIndex;
1702 const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
1703 && index.parent() == hover.parent()
1704 && index.row() == hover.row();
1705
1706 QList<int> logicalIndices;
1707 QList<QStyleOptionViewItem::ViewItemPosition>
1708 viewItemPosList; // vector of left/middle/end for each logicalIndex
1709 d->calcLogicalIndices(&logicalIndices, &viewItemPosList, left, right);
1710
1711 for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices.size(); ++currentLogicalSection) {
1712 int headerSection = logicalIndices.at(currentLogicalSection);
1713 position = columnViewportPosition(headerSection) + offset.x();
1714 width = header->sectionSize(headerSection);
1715
1716 if (spanning) {
1717 int lastSection = header->logicalIndex(header->count() - 1);
1718 if (!reverse) {
1719 width = columnViewportPosition(lastSection) + header->sectionSize(lastSection) - position;
1720 } else {
1721 width += position - columnViewportPosition(lastSection);
1722 position = columnViewportPosition(lastSection);
1723 }
1724 }
1725
1726 modelIndex = d->model->index(index.row(), headerSection, parent);
1727 if (!modelIndex.isValid())
1728 continue;
1729 opt.state = state;
1730
1731 opt.viewItemPosition = viewItemPosList.at(currentLogicalSection);
1732
1733 // fake activeness when row editor has focus
1734 if (indexWidgetHasFocus)
1736
1737 if (d->selectionModel->isSelected(modelIndex))
1739 if (widgetHasFocus && (current == modelIndex)) {
1741 currentRowHasFocus = true;
1742 else
1744 }
1746 (hoverRow || modelIndex == hover)
1747 && (option.showDecorationSelected || d->hoverBranch == -1));
1748
1749 if (enabled) {
1751 if ((d->model->flags(modelIndex) & Qt::ItemIsEnabled) == 0) {
1752 opt.state &= ~QStyle::State_Enabled;
1753 cg = QPalette::Disabled;
1754 } else if (opt.state & QStyle::State_Active) {
1755 cg = QPalette::Active;
1756 } else {
1757 cg = QPalette::Inactive;
1758 }
1760 }
1761
1762 if (alternate) {
1763 opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1);
1764 }
1765
1766 /* Prior to Qt 4.3, the background of the branch (in selected state and
1767 alternate row color was provided by the view. For backward compatibility,
1768 this is now delegated to the style using PE_PanelItemViewRow which
1769 does the appropriate fill */
1770 if (d->isTreePosition(headerSection)) {
1771 const int i = d->indentationForItem(d->current);
1772 QRect branches(reverse ? position + width - i : position, y, i, height);
1773 const bool setClipRect = branches.width() > width;
1774 if (setClipRect) {
1775 painter->save();
1777 }
1778 // draw background for the branch (selection + alternate row)
1779 opt.rect = branches;
1780
1781 // We use showDecorationSelected both to store the style hint, and to indicate
1782 // that the entire row has to be selected (see overrides of the value if
1783 // selectionBehavior == SelectRow).
1784 // While we are only painting the background we don't care for the
1785 // selectionBehavior factor, so respect only the style value, and reset later.
1786 const bool oldShowDecorationSelected = opt.showDecorationSelected;
1787 opt.showDecorationSelected = style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected,
1788 &opt, this);
1789 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
1790
1791 // draw background of the item (only alternate row). rest of the background
1792 // is provided by the delegate
1793 QStyle::State oldState = opt.state;
1794 opt.state &= ~QStyle::State_Selected;
1795 opt.rect.setRect(reverse ? position : i + position, y, width - i, height);
1796 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
1797 opt.state = oldState;
1798 opt.showDecorationSelected = oldShowDecorationSelected;
1799
1800 if (d->indent != 0)
1801 drawBranches(painter, branches, index);
1802 if (setClipRect)
1803 painter->restore();
1804 } else {
1805 QStyle::State oldState = opt.state;
1806 opt.state &= ~QStyle::State_Selected;
1808 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
1809 opt.state = oldState;
1810 }
1811
1812 itemDelegateForIndex(modelIndex)->paint(painter, opt, modelIndex);
1813 }
1814
1815 if (currentRowHasFocus) {
1817 o.QStyleOption::operator=(option);
1821 o.backgroundColor = option.palette.color(cg, d->selectionModel->isSelected(index)
1823 int x = 0;
1824 if (!option.showDecorationSelected)
1825 x = header->sectionPosition(0) + d->indentationForItem(d->current);
1826 QRect focusRect(x - header->offset(), y, header->length() - x, height);
1827 o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), focusRect);
1828 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
1829 // if we show focus on all columns and the first section is moved,
1830 // we have to split the focus rect into two rects
1831 if (allColumnsShowFocus && !option.showDecorationSelected
1832 && header->sectionsMoved() && (header->visualIndex(0) != 0)) {
1833 QRect sectionRect(0, y, header->sectionPosition(0), height);
1834 o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), sectionRect);
1835 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
1836 }
1837 }
1838}
1839
1846 const QModelIndex &index) const
1847{
1848 Q_D(const QTreeView);
1849 const bool reverse = isRightToLeft();
1850 const int indent = d->indent;
1851 const int outer = d->rootDecoration ? 0 : 1;
1852 const int item = d->current;
1853 const QTreeViewItem &viewItem = d->viewItems.at(item);
1854 int level = viewItem.level;
1855 QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height());
1856
1857 QModelIndex parent = index.parent();
1858 QModelIndex current = parent;
1859 QModelIndex ancestor = current.parent();
1860
1861 QStyleOptionViewItem opt;
1863 QStyle::State extraFlags = QStyle::State_None;
1864 if (isEnabled())
1865 extraFlags |= QStyle::State_Enabled;
1866 if (hasFocus())
1867 extraFlags |= QStyle::State_Active;
1868 QPoint oldBO = painter->brushOrigin();
1871
1872 if (d->alternatingColors) {
1873 opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1);
1874 }
1875
1876 // When hovering over a row, pass State_Hover for painting the branch
1877 // indicators if it has the decoration (aka branch) selected.
1879 && opt.showDecorationSelected
1880 && index.parent() == d->hover.parent()
1881 && index.row() == d->hover.row();
1882
1883 if (d->selectionModel->isSelected(index))
1884 extraFlags |= QStyle::State_Selected;
1885
1886 if (level >= outer) {
1887 // start with the innermost branch
1888 primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent);
1889 opt.rect = primitive;
1890
1891 const bool expanded = viewItem.expanded;
1892 const bool children = viewItem.hasChildren;
1893 bool moreSiblings = viewItem.hasMoreSiblings;
1894
1895 opt.state = QStyle::State_Item | extraFlags
1896 | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None)
1899 opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch);
1900
1901 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
1902 }
1903 // then go out level by level
1904 for (--level; level >= outer; --level) { // we have already drawn the innermost branch
1905 primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent);
1906 opt.rect = primitive;
1907 opt.state = extraFlags;
1908 bool moreSiblings = false;
1909 if (d->hiddenIndexes.isEmpty()) {
1910 moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row());
1911 } else {
1912 int successor = item + viewItem.total + 1;
1913 while (successor < d->viewItems.size()
1914 && d->viewItems.at(successor).level >= uint(level)) {
1915 const QTreeViewItem &successorItem = d->viewItems.at(successor);
1916 if (successorItem.level == uint(level)) {
1917 moreSiblings = true;
1918 break;
1919 }
1920 successor += successorItem.total + 1;
1921 }
1922 }
1923 if (moreSiblings)
1925 opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch);
1926
1927 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
1928 current = ancestor;
1929 ancestor = current.parent();
1930 }
1931 painter->setBrushOrigin(oldBO);
1932}
1933
1938{
1939 Q_D(QTreeView);
1940 bool handled = false;
1941 if (style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, nullptr, this) == QEvent::MouseButtonPress)
1942 handled = d->expandOrCollapseItemAtPos(event->position().toPoint());
1943 if (!handled && d->itemDecorationAt(event->position().toPoint()) == -1)
1945 else
1946 d->pressedIndex = QModelIndex();
1947}
1948
1953{
1954 Q_D(QTreeView);
1955 if (d->itemDecorationAt(event->position().toPoint()) == -1) {
1957 } else {
1960 if (style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, nullptr, this) == QEvent::MouseButtonRelease)
1961 d->expandOrCollapseItemAtPos(event->position().toPoint());
1962 }
1963}
1964
1969{
1970 Q_D(QTreeView);
1971 if (state() != NoState || !d->viewport->rect().contains(event->position().toPoint()))
1972 return;
1973
1974 int i = d->itemDecorationAt(event->position().toPoint());
1975 if (i == -1) {
1976 i = d->itemAtCoordinate(event->position().toPoint().y());
1977 if (i == -1)
1978 return; // user clicked outside the items
1979
1980 const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index;
1981 const QPersistentModelIndex persistent = indexAt(event->position().toPoint());
1982
1983 if (d->pressedIndex != persistent) {
1985 return;
1986 }
1987
1988 // signal handlers may change the model
1989 emit doubleClicked(persistent);
1990
1991 if (!persistent.isValid())
1992 return;
1993
1994 if (edit(persistent, DoubleClicked, event) || state() != NoState)
1995 return; // the double click triggered editing
1996
1997 if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
1998 emit activated(persistent);
1999
2000 d->releaseFromDoubleClick = true;
2001 d->executePostedLayout(); // we need to make sure viewItems is updated
2002 if (d->itemsExpandable
2003 && d->expandsOnDoubleClick
2004 && d->hasVisibleChildren(persistent)) {
2005 if (!((i < d->viewItems.size()) && (d->viewItems.at(i).index == firstColumnIndex))) {
2006 // find the new index of the item
2007 for (i = 0; i < d->viewItems.size(); ++i) {
2008 if (d->viewItems.at(i).index == firstColumnIndex)
2009 break;
2010 }
2011 if (i == d->viewItems.size())
2012 return;
2013 }
2014 if (d->viewItems.at(i).expanded)
2015 d->collapse(i, true);
2016 else
2017 d->expand(i, true);
2019 viewport()->update();
2020 }
2021 }
2022}
2023
2028{
2029 Q_D(QTreeView);
2030 if (d->itemDecorationAt(event->position().toPoint()) == -1) // ### what about expanding/collapsing state ?
2032}
2033
2038{
2039 Q_D(QTreeView);
2040 QModelIndex current = currentIndex();
2041 //this is the management of the expansion
2042 if (d->isIndexValid(current) && d->model && d->itemsExpandable) {
2043 switch (event->key()) {
2044 case Qt::Key_Asterisk: {
2045 expandRecursively(current);
2046 break; }
2047 case Qt::Key_Plus:
2048 expand(current);
2049 break;
2050 case Qt::Key_Minus:
2051 collapse(current);
2052 break;
2053 }
2054 }
2055
2057}
2058
2063{
2064 Q_D(const QTreeView);
2065 d->executePostedLayout();
2066
2067 int visualIndex = d->itemAtCoordinate(point.y());
2068 QModelIndex idx = d->modelIndex(visualIndex);
2069 if (!idx.isValid())
2070 return QModelIndex();
2071
2072 if (d->viewItems.at(visualIndex).spanning)
2073 return idx;
2074
2075 int column = d->columnAt(point.x());
2076 if (column == idx.column())
2077 return idx;
2078 if (column < 0)
2079 return QModelIndex();
2080 return idx.sibling(idx.row(), column);
2081}
2082
2087{
2088 Q_D(const QTreeView);
2089 if (!d->isIndexValid(index))
2090 return QModelIndex();
2091 d->executePostedLayout();
2092 int i = d->viewIndex(index);
2093 if (--i < 0)
2094 return QModelIndex();
2095 const QModelIndex firstColumnIndex = d->viewItems.at(i).index;
2096 return firstColumnIndex.sibling(firstColumnIndex.row(), index.column());
2097}
2098
2103{
2104 Q_D(const QTreeView);
2105 if (!d->isIndexValid(index))
2106 return QModelIndex();
2107 d->executePostedLayout();
2108 int i = d->viewIndex(index);
2109 if (++i >= d->viewItems.size())
2110 return QModelIndex();
2111 const QModelIndex firstColumnIndex = d->viewItems.at(i).index;
2112 return firstColumnIndex.sibling(firstColumnIndex.row(), index.column());
2113}
2114
2121{
2122 Q_D(QTreeView);
2123 if (d->hasRemovedItems) {
2124 //clean the QSet that may contains old (and this invalid) indexes
2125 d->hasRemovedItems = false;
2126 QSet<QPersistentModelIndex>::iterator it = d->expandedIndexes.begin();
2127 while (it != d->expandedIndexes.end()) {
2128 if (!it->isValid())
2129 it = d->expandedIndexes.erase(it);
2130 else
2131 ++it;
2132 }
2133 it = d->hiddenIndexes.begin();
2134 while (it != d->hiddenIndexes.end()) {
2135 if (!it->isValid())
2136 it = d->hiddenIndexes.erase(it);
2137 else
2138 ++it;
2139 }
2140 }
2141 d->viewItems.clear(); // prepare for new layout
2142 QModelIndex parent = d->root;
2143 if (d->model->hasChildren(parent)) {
2144 d->layout(-1);
2145 }
2147 d->header->doItemsLayout();
2148 d->updateAccessibility();
2149}
2150
2155{
2156 Q_D(QTreeView);
2157 d->expandedIndexes.clear();
2158 d->hiddenIndexes.clear();
2159 d->spanningIndexes.clear();
2160 d->viewItems.clear();
2162}
2163
2173{
2174 Q_D(const QTreeView);
2175 return d->header->offset();
2176}
2177
2184{
2185 Q_D(const QTreeView);
2186 if (d->verticalScrollMode == QAbstractItemView::ScrollPerItem) {
2187 if (d->uniformRowHeights)
2188 return verticalScrollBar()->value() * d->defaultItemHeight;
2189 // If we are scrolling per item and have non-uniform row heights,
2190 // finding the vertical offset in pixels is going to be relatively slow.
2191 // ### find a faster way to do this
2192 d->executePostedLayout();
2193 int offset = 0;
2194 const int cnt = qMin(d->viewItems.size(), verticalScrollBar()->value());
2195 for (int i = 0; i < cnt; ++i)
2196 offset += d->itemHeight(i);
2197 return offset;
2198 }
2199 // scroll per pixel
2200 return verticalScrollBar()->value();
2201}
2202
2207QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
2208{
2209 Q_D(QTreeView);
2211
2212 d->executePostedLayout();
2213
2214 QModelIndex current = currentIndex();
2215 if (!current.isValid()) {
2216 int i = d->below(-1);
2217 int c = 0;
2218 while (c < d->header->count() && d->header->isSectionHidden(d->header->logicalIndex(c)))
2219 ++c;
2220 if (i < d->viewItems.size() && c < d->header->count()) {
2221 return d->modelIndex(i, d->header->logicalIndex(c));
2222 }
2223 return QModelIndex();
2224 }
2225
2226 const int vi = qMax(0, d->viewIndex(current));
2227
2228 if (isRightToLeft()) {
2229 if (cursorAction == MoveRight)
2230 cursorAction = MoveLeft;
2231 else if (cursorAction == MoveLeft)
2232 cursorAction = MoveRight;
2233 }
2234 switch (cursorAction) {
2235 case MoveNext:
2236 case MoveDown:
2237#ifdef QT_KEYPAD_NAVIGATION
2238 if (vi == d->viewItems.count()-1 && QApplicationPrivate::keypadNavigationEnabled())
2239 return d->model->index(0, current.column(), d->root);
2240#endif
2241 return d->modelIndex(d->below(vi), current.column());
2242 case MovePrevious:
2243 case MoveUp:
2244#ifdef QT_KEYPAD_NAVIGATION
2245 if (vi == 0 && QApplicationPrivate::keypadNavigationEnabled())
2246 return d->modelIndex(d->viewItems.count() - 1, current.column());
2247#endif
2248 return d->modelIndex(d->above(vi), current.column());
2249 case MoveLeft: {
2250 QScrollBar *sb = horizontalScrollBar();
2251 if (vi < d->viewItems.size() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum()) {
2252 d->collapse(vi, true);
2253 d->moveCursorUpdatedView = true;
2254 } else {
2255 bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, nullptr, this);
2256 if (descend) {
2257 QModelIndex par = current.parent();
2258 if (par.isValid() && par != rootIndex())
2259 return par;
2260 else
2261 descend = false;
2262 }
2263 if (!descend) {
2264 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
2265 int visualColumn = d->header->visualIndex(current.column()) - 1;
2266 while (visualColumn >= 0 && isColumnHidden(d->header->logicalIndex(visualColumn)))
2267 visualColumn--;
2268 int newColumn = d->header->logicalIndex(visualColumn);
2269 QModelIndex next = current.sibling(current.row(), newColumn);
2270 if (next.isValid())
2271 return next;
2272 }
2273
2274 int oldValue = sb->value();
2275 sb->setValue(sb->value() - sb->singleStep());
2276 if (oldValue != sb->value())
2277 d->moveCursorUpdatedView = true;
2278 }
2279
2280 }
2282 viewport()->update();
2283 break;
2284 }
2285 case MoveRight:
2286 if (vi < d->viewItems.size() && !d->viewItems.at(vi).expanded && d->itemsExpandable
2287 && d->hasVisibleChildren(d->viewItems.at(vi).index)) {
2288 d->expand(vi, true);
2289 d->moveCursorUpdatedView = true;
2290 } else {
2291 bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, nullptr, this);
2292 if (descend) {
2293 QModelIndex idx = d->modelIndex(d->below(vi));
2294 if (idx.parent() == current)
2295 return idx;
2296 else
2297 descend = false;
2298 }
2299 if (!descend) {
2300 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
2301 int visualColumn = d->header->visualIndex(current.column()) + 1;
2302 while (visualColumn < d->model->columnCount(current.parent()) && isColumnHidden(d->header->logicalIndex(visualColumn)))
2303 visualColumn++;
2304 const int newColumn = d->header->logicalIndex(visualColumn);
2305 const QModelIndex next = current.sibling(current.row(), newColumn);
2306 if (next.isValid())
2307 return next;
2308 }
2309
2310 //last restort: we change the scrollbar value
2311 QScrollBar *sb = horizontalScrollBar();
2312 int oldValue = sb->value();
2313 sb->setValue(sb->value() + sb->singleStep());
2314 if (oldValue != sb->value())
2315 d->moveCursorUpdatedView = true;
2316 }
2317 }
2319 viewport()->update();
2320 break;
2321 case MovePageUp:
2322 return d->modelIndex(d->pageUp(vi), current.column());
2323 case MovePageDown:
2324 return d->modelIndex(d->pageDown(vi), current.column());
2325 case MoveHome:
2326 return d->modelIndex(d->itemForKeyHome(), current.column());
2327 case MoveEnd:
2328 return d->modelIndex(d->itemForKeyEnd(), current.column());
2329 }
2330 return current;
2331}
2332
2339void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
2340{
2341 Q_D(QTreeView);
2342 if (!selectionModel() || rect.isNull())
2343 return;
2344
2345 d->executePostedLayout();
2346 QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right())
2347 : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom()));
2348 QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) :
2349 qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom()));
2350 QModelIndex topLeft = indexAt(tl);
2351 QModelIndex bottomRight = indexAt(br);
2352 if (!topLeft.isValid() && !bottomRight.isValid()) {
2353 if (command & QItemSelectionModel::Clear)
2354 selectionModel()->clear();
2355 return;
2356 }
2357 if (!topLeft.isValid() && !d->viewItems.isEmpty())
2358 topLeft = d->viewItems.constFirst().index;
2359 if (!bottomRight.isValid() && !d->viewItems.isEmpty()) {
2360 const int column = d->header->logicalIndex(d->header->count() - 1);
2361 const QModelIndex index = d->viewItems.constLast().index;
2362 bottomRight = index.sibling(index.row(), column);
2363 }
2364
2365 if (!d->isIndexEnabled(topLeft) || !d->isIndexEnabled(bottomRight))
2366 return;
2367
2368 d->select(topLeft, bottomRight, command);
2369}
2370
2379{
2380 Q_D(const QTreeView);
2381 if (selection.isEmpty())
2382 return QRegion();
2383
2384 QRegion selectionRegion;
2385 const QRect &viewportRect = d->viewport->rect();
2386 for (const auto &range : selection) {
2387 if (!range.isValid())
2388 continue;
2389 QModelIndex parent = range.parent();
2390 QModelIndex leftIndex = range.topLeft();
2391 int columnCount = d->model->columnCount(parent);
2392 while (leftIndex.isValid() && isIndexHidden(leftIndex)) {
2393 if (leftIndex.column() + 1 < columnCount)
2394 leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent);
2395 else
2396 leftIndex = QModelIndex();
2397 }
2398 if (!leftIndex.isValid())
2399 continue;
2400 const QRect leftRect = d->visualRect(leftIndex, QTreeViewPrivate::SingleSection);
2401 int top = leftRect.top();
2402 QModelIndex rightIndex = range.bottomRight();
2403 while (rightIndex.isValid() && isIndexHidden(rightIndex)) {
2404 if (rightIndex.column() - 1 >= 0)
2405 rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent);
2406 else
2407 rightIndex = QModelIndex();
2408 }
2409 if (!rightIndex.isValid())
2410 continue;
2411 const QRect rightRect = d->visualRect(rightIndex, QTreeViewPrivate::SingleSection);
2412 int bottom = rightRect.bottom();
2413 if (top > bottom)
2414 qSwap<int>(top, bottom);
2415 int height = bottom - top + 1;
2416 if (d->header->sectionsMoved()) {
2417 for (int c = range.left(); c <= range.right(); ++c) {
2418 const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height);
2419 if (viewportRect.intersects(rangeRect))
2420 selectionRegion += rangeRect;
2421 }
2422 } else {
2423 QRect combined = leftRect|rightRect;
2424 combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
2425 if (viewportRect.intersects(combined))
2426 selectionRegion += combined;
2427 }
2428 }
2429 return selectionRegion;
2430}
2431
2436{
2437 QModelIndexList viewSelected;
2438 QModelIndexList modelSelected;
2439 if (selectionModel())
2440 modelSelected = selectionModel()->selectedIndexes();
2441 for (int i = 0; i < modelSelected.size(); ++i) {
2442 // check that neither the parents nor the index is hidden before we add
2443 QModelIndex index = modelSelected.at(i);
2444 while (index.isValid() && !isIndexHidden(index))
2445 index = index.parent();
2446 if (index.isValid())
2447 continue;
2448 viewSelected.append(modelSelected.at(i));
2449 }
2450 return viewSelected;
2451}
2452
2457{
2458 Q_D(QTreeView);
2459
2460 d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
2461
2462 dx = isRightToLeft() ? -dx : dx;
2463 if (dx) {
2464 int oldOffset = d->header->offset();
2465 d->header->d_func()->setScrollOffset(horizontalScrollBar(), horizontalScrollMode());
2467 int newOffset = d->header->offset();
2468 dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
2469 }
2470 }
2471
2472 const int itemHeight = d->defaultItemHeight <= 0 ? sizeHintForRow(0) : d->defaultItemHeight;
2473 if (d->viewItems.isEmpty() || itemHeight == 0)
2474 return;
2475
2476 // guestimate the number of items in the viewport
2477 int viewCount = d->viewport->height() / itemHeight;
2478 int maxDeltaY = qMin(d->viewItems.size(), viewCount);
2479 // no need to do a lot of work if we are going to redraw the whole thing anyway
2480 if (qAbs(dy) > qAbs(maxDeltaY) && d->editorIndexHash.isEmpty()) {
2481 verticalScrollBar()->update();
2482 d->viewport->update();
2483 return;
2484 }
2485
2487 int currentScrollbarValue = verticalScrollBar()->value();
2488 int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy)
2489 int currentViewIndex = currentScrollbarValue; // the first visible item
2490 int previousViewIndex = previousScrollbarValue;
2491 dy = 0;
2492 if (previousViewIndex < currentViewIndex) { // scrolling down
2493 for (int i = previousViewIndex; i < currentViewIndex; ++i) {
2494 if (i < d->viewItems.size())
2495 dy -= d->itemHeight(i);
2496 }
2497 } else if (previousViewIndex > currentViewIndex) { // scrolling up
2498 for (int i = previousViewIndex - 1; i >= currentViewIndex; --i) {
2499 if (i < d->viewItems.size())
2500 dy += d->itemHeight(i);
2501 }
2502 }
2503 }
2504
2505 d->scrollContentsBy(dx, dy);
2506}
2507
2512{
2513 Q_D(QTreeView);
2515 d->viewport->update();
2516}
2517
2522{
2523 // do nothing
2524}
2525
2530void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
2531{
2532 Q_D(QTreeView);
2533 // if we are going to do a complete relayout anyway, there is no need to update
2534 if (d->delayedPendingLayout) {
2536 return;
2537 }
2538
2539 //don't add a hierarchy on a column != 0
2540 if (parent.column() != 0 && parent.isValid()) {
2542 return;
2543 }
2544
2545 const int parentRowCount = d->model->rowCount(parent);
2546 const int delta = end - start + 1;
2547 if (parent != d->root && !d->isIndexExpanded(parent) && parentRowCount > delta) {
2549 return;
2550 }
2551
2552 const int parentItem = d->viewIndex(parent);
2553 if (((parentItem != -1) && d->viewItems.at(parentItem).expanded)
2554 || (parent == d->root)) {
2555 d->doDelayedItemsLayout();
2556 } else if (parentItem != -1 && parentRowCount == delta) {
2557 // the parent just went from 0 children to more. update to re-paint the decoration
2558 d->viewItems[parentItem].hasChildren = true;
2559 viewport()->update();
2560 }
2562}
2563
2569{
2570 Q_D(QTreeView);
2572 d->viewItems.clear();
2573}
2574
2581void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
2582{
2583 Q_D(QTreeView);
2584 d->viewItems.clear();
2585 d->doDelayedItemsLayout();
2586 d->hasRemovedItems = true;
2587 d->rowsRemoved(parent, start, end);
2588}
2589
2594void QTreeView::columnCountChanged(int oldCount, int newCount)
2595{
2596 Q_D(QTreeView);
2597 if (oldCount == 0 && newCount > 0) {
2598 //if the first column has just been added we need to relayout.
2599 d->doDelayedItemsLayout();
2600 }
2601
2602 if (isVisible())
2604 viewport()->update();
2605}
2606
2613{
2614 Q_D(QTreeView);
2615 d->executePostedLayout();
2616 if (column < 0 || column >= d->header->count())
2617 return;
2619 int header = d->header->isHidden() ? 0 : d->header->sectionSizeHint(column);
2620 d->header->resizeSection(column, qMax(contents, header));
2621}
2622
2635{
2636 Q_D(QTreeView);
2637 if (column < -1)
2638 return;
2639 d->header->setSortIndicator(column, order);
2640 // If sorting is not enabled or has the same order as before, force to sort now
2641 // else sorting will be trigger through sortIndicatorChanged()
2642 if (!d->sortingEnabled ||
2643 (d->header->sortIndicatorSection() == column && d->header->sortIndicatorOrder() == order))
2644 d->model->sort(column, order);
2645}
2646
2651{
2652 Q_D(QTreeView);
2653 if (!selectionModel())
2654 return;
2655 SelectionMode mode = d->selectionMode;
2656 d->executePostedLayout(); //make sure we lay out the items
2657 if (mode != SingleSelection && mode != NoSelection && !d->viewItems.isEmpty()) {
2658 const QModelIndex &idx = d->viewItems.constLast().index;
2659 QModelIndex lastItemIndex = idx.sibling(idx.row(), d->model->columnCount(idx.parent()) - 1);
2660 d->select(d->viewItems.constFirst().index, lastItemIndex,
2663 }
2664}
2665
2670{
2671 Q_D(const QTreeView);
2672 d->executePostedLayout(); // Make sure that viewItems are up to date.
2673
2674 if (d->viewItems.size() == 0)
2676
2677 // Get rect for last item
2678 const QRect deepestRect = d->visualRect(d->viewItems.last().index,
2680
2681 if (!deepestRect.isValid())
2683
2684 QSize result = QSize(d->header->length(), deepestRect.bottom() + 1);
2685
2686 // add size for header
2687 result += QSize(0, d->header->isHidden() ? 0 : d->header->height());
2688
2689 return result;
2690}
2691
2705{
2706 Q_D(QTreeView);
2707 d->viewItems.clear();
2708 d->interruptDelayedItemsLayout();
2709 d->layout(-1, true);
2711 d->viewport->update();
2712 d->updateAccessibility();
2713}
2714
2731{
2732 Q_D(QTreeView);
2733
2734 if (depth < -1)
2735 return;
2736 // do layouting only once after expanding is done
2737 d->doDelayedItemsLayout();
2738 expand(index);
2739 if (depth == 0)
2740 return;
2741 QStack<QPair<QModelIndex, int>> parents;
2742 parents.push({index, 0});
2743 while (!parents.isEmpty()) {
2744 const QPair<QModelIndex, int> elem = parents.pop();
2745 const QModelIndex &parent = elem.first;
2746 const int curDepth = elem.second;
2747 const int rowCount = d->model->rowCount(parent);
2748 for (int row = 0; row < rowCount; ++row) {
2749 const QModelIndex child = d->model->index(row, 0, parent);
2750 if (!d->isIndexValid(child))
2751 break;
2752 if (depth == -1 || curDepth + 1 < depth)
2753 parents.push({child, curDepth + 1});
2754 if (d->isIndexExpanded(child))
2755 continue;
2756 if (d->storeExpanded(child))
2758 }
2759 }
2760}
2761
2770{
2771 Q_D(QTreeView);
2772 QSet<QPersistentModelIndex> old_expandedIndexes;
2773 old_expandedIndexes = d->expandedIndexes;
2774 d->expandedIndexes.clear();
2775 if (!signalsBlocked() && isSignalConnected(QMetaMethod::fromSignal(&QTreeView::collapsed))) {
2776 QSet<QPersistentModelIndex>::const_iterator i = old_expandedIndexes.constBegin();
2777 for (; i != old_expandedIndexes.constEnd(); ++i) {
2778 const QPersistentModelIndex &mi = (*i);
2779 if (mi.isValid() && !(mi.flags() & Qt::ItemNeverHasChildren))
2780 emit collapsed(mi);
2781 }
2782 }
2783 doItemsLayout();
2784}
2785
2796{
2797 Q_D(QTreeView);
2798 d->viewItems.clear();
2799 QSet<QPersistentModelIndex> old_expandedIndexes;
2800 old_expandedIndexes = d->expandedIndexes;
2801 d->expandedIndexes.clear();
2802 d->interruptDelayedItemsLayout();
2803 d->layout(-1);
2804 for (int i = 0; i < d->viewItems.size(); ++i) {
2805 if (d->viewItems.at(i).level <= (uint)depth) {
2806 d->viewItems[i].expanded = true;
2807 d->layout(i);
2808 d->storeExpanded(d->viewItems.at(i).index);
2809 }
2810 }
2811
2812 bool someSignalEnabled = isSignalConnected(QMetaMethod::fromSignal(&QTreeView::collapsed));
2813 someSignalEnabled |= isSignalConnected(QMetaMethod::fromSignal(&QTreeView::expanded));
2814
2815 if (!signalsBlocked() && someSignalEnabled) {
2816 // emit signals
2817 QSet<QPersistentModelIndex> collapsedIndexes = old_expandedIndexes - d->expandedIndexes;
2818 QSet<QPersistentModelIndex>::const_iterator i = collapsedIndexes.constBegin();
2819 for (; i != collapsedIndexes.constEnd(); ++i) {
2820 const QPersistentModelIndex &mi = (*i);
2821 if (mi.isValid() && !(mi.flags() & Qt::ItemNeverHasChildren))
2822 emit collapsed(mi);
2823 }
2824
2825 QSet<QPersistentModelIndex> expandedIndexs = d->expandedIndexes - old_expandedIndexes;
2826 i = expandedIndexs.constBegin();
2827 for (; i != expandedIndexs.constEnd(); ++i) {
2828 const QPersistentModelIndex &mi = (*i);
2829 if (mi.isValid() && !(mi.flags() & Qt::ItemNeverHasChildren))
2830 emit expanded(mi);
2831 }
2832 }
2833
2835 d->viewport->update();
2836 d->updateAccessibility();
2837}
2838
2846void QTreeView::columnResized(int column, int /* oldSize */, int /* newSize */)
2847{
2848 Q_D(QTreeView);
2849 d->columnsToUpdate.append(column);
2850 if (d->columnResizeTimerID == 0)
2851 d->columnResizeTimerID = startTimer(0);
2852}
2853
2858{
2859 Q_D(QTreeView);
2860 if (d->header) {
2861 if (d->geometryRecursionBlock)
2862 return;
2863 d->geometryRecursionBlock = true;
2864 int height = 0;
2865 if (!d->header->isHidden()) {
2866 height = qMax(d->header->minimumHeight(), d->header->sizeHint().height());
2867 height = qMin(height, d->header->maximumHeight());
2868 }
2869 setViewportMargins(0, height, 0, 0);
2870 QRect vg = d->viewport->geometry();
2871 QRect geometryRect(vg.left(), vg.top() - height, vg.width(), height);
2872 d->header->setGeometry(geometryRect);
2873 QMetaObject::invokeMethod(d->header, "updateGeometries");
2874 d->updateScrollBars();
2875 d->geometryRecursionBlock = false;
2876 }
2878}
2879
2895{
2896 Q_D(const QTreeView);
2897 d->executePostedLayout();
2898 if (d->viewItems.isEmpty())
2899 return -1;
2900 ensurePolished();
2901 int w = 0;
2902 QStyleOptionViewItem option;
2904 const QList<QTreeViewItem> viewItems = d->viewItems;
2905
2906 const int maximumProcessRows = d->header->resizeContentsPrecision(); // To avoid this to take forever.
2907
2908 int offset = 0;
2909 int start = d->firstVisibleItem(&offset);
2910 int end = d->lastVisibleItem(start, offset);
2911 if (start < 0 || end < 0 || end == viewItems.size() - 1) {
2912 end = viewItems.size() - 1;
2913 if (maximumProcessRows < 0) {
2914 start = 0;
2915 } else if (maximumProcessRows == 0) {
2916 start = qMax(0, end - 1);
2917 int remainingHeight = viewport()->height();
2918 while (start > 0 && remainingHeight > 0) {
2919 remainingHeight -= d->itemHeight(start);
2920 --start;
2921 }
2922 } else {
2923 start = qMax(0, end - maximumProcessRows);
2924 }
2925 }
2926
2927 int rowsProcessed = 0;
2928
2929 for (int i = start; i <= end; ++i) {
2930 if (viewItems.at(i).spanning)
2931 continue; // we have no good size hint
2932 QModelIndex index = viewItems.at(i).index;
2933 index = index.sibling(index.row(), column);
2934 w = d->widthHintForIndex(index, w, option, i);
2935 ++rowsProcessed;
2936 if (rowsProcessed == maximumProcessRows)
2937 break;
2938 }
2939
2940 --end;
2941 int actualBottom = viewItems.size() - 1;
2942
2943 if (maximumProcessRows == 0)
2944 rowsProcessed = 0; // skip the while loop
2945
2946 while (rowsProcessed != maximumProcessRows && (start > 0 || end < actualBottom)) {
2947 int idx = -1;
2948
2949 if ((rowsProcessed % 2 && start > 0) || end == actualBottom) {
2950 while (start > 0) {
2951 --start;
2952 if (viewItems.at(start).spanning)
2953 continue;
2954 idx = start;
2955 break;
2956 }
2957 } else {
2958 while (end < actualBottom) {
2959 ++end;
2960 if (viewItems.at(end).spanning)
2961 continue;
2962 idx = end;
2963 break;
2964 }
2965 }
2966 if (idx < 0)
2967 continue;
2968
2969 QModelIndex index = viewItems.at(idx).index;
2970 index = index.sibling(index.row(), column);
2971 w = d->widthHintForIndex(index, w, option, idx);
2972 ++rowsProcessed;
2973 }
2974 return w;
2975}
2976
2983{
2984 Q_D(const QTreeView);
2985 if (!d->isIndexValid(index) || !d->itemDelegate)
2986 return 0;
2987
2988 int start = -1;
2989 int end = -1;
2990 int indexRow = index.row();
2991 int count = d->header->count();
2992 bool emptyHeader = (count == 0);
2993 QModelIndex parent = index.parent();
2994
2995 if (count && isVisible()) {
2996 // If the sections have moved, we end up checking too many or too few
2997 start = d->header->visualIndexAt(0);
2998 } else {
2999 // If the header has not been laid out yet, we use the model directly
3000 count = d->model->columnCount(parent);
3001 }
3002
3003 if (isRightToLeft()) {
3004 start = (start == -1 ? count - 1 : start);
3005 end = 0;
3006 } else {
3007 start = (start == -1 ? 0 : start);
3008 end = count - 1;
3009 }
3010
3011 if (end < start)
3012 qSwap(end, start);
3013
3014 int height = -1;
3015 QStyleOptionViewItem option;
3017 // ### If we want word wrapping in the items,
3018 // ### we need to go through all the columns
3019 // ### and set the width of the column
3020
3021 // Hack to speed up the function
3022 option.rect.setWidth(-1);
3023
3024 for (int column = start; column <= end; ++column) {
3025 int logicalColumn = emptyHeader ? column : d->header->logicalIndex(column);
3026 if (d->header->isSectionHidden(logicalColumn))
3027 continue;
3028 QModelIndex idx = d->model->index(indexRow, logicalColumn, parent);
3029 if (idx.isValid()) {
3030 QWidget *editor = d->editorForIndex(idx).widget.data();
3031 if (editor && d->persistent.contains(editor)) {
3032 height = qMax(height, editor->sizeHint().height());
3033 int min = editor->minimumSize().height();
3034 int max = editor->maximumSize().height();
3035 height = qBound(min, height, max);
3036 }
3037 int hint = itemDelegateForIndex(idx)->sizeHint(option, idx).height();
3038 height = qMax(height, hint);
3039 }
3040 }
3041
3042 return height;
3043}
3044
3051{
3052 Q_D(const QTreeView);
3053 d->executePostedLayout();
3054 int i = d->viewIndex(index);
3055 if (i == -1)
3056 return 0;
3057 return d->itemHeight(i);
3058}
3059
3067
3072{
3073 return (isColumnHidden(index.column()) || isRowHidden(index.row(), index.parent()));
3074}
3075
3076/*
3077 private implementation
3078*/
3080{
3081 Q_Q(QTreeView);
3082
3084 updateStyledFrameWidths();
3085 q->setSelectionBehavior(QAbstractItemView::SelectRows);
3086 q->setSelectionMode(QAbstractItemView::SingleSelection);
3087 q->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
3088 q->setAttribute(Qt::WA_MacShowFocusRect);
3089
3094 q->setHeader(header);
3095#if QT_CONFIG(animation)
3096 animationsEnabled = q->style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, q) > 0;
3099 this, &QTreeViewPrivate::endAnimatedOperation);
3100#endif // animation
3101}
3102
3115
3116void QTreeViewPrivate::expand(int item, bool emitSignal)
3117{
3118 Q_Q(QTreeView);
3119
3120 if (item == -1 || viewItems.at(item).expanded)
3121 return;
3123 if (index.flags() & Qt::ItemNeverHasChildren)
3124 return;
3125
3126#if QT_CONFIG(animation)
3127 if (emitSignal && animationsEnabled)
3128 prepareAnimatedOperation(item, QVariantAnimation::Forward);
3129#endif // animation
3130 //if already animating, stateBeforeAnimation is set to the correct value
3135 viewItems[item].expanded = true;
3136 layout(item);
3137 q->setState(stateBeforeAnimation);
3138
3139 if (model->canFetchMore(index))
3141 if (emitSignal) {
3142 emit q->expanded(index);
3143#if QT_CONFIG(animation)
3145 beginAnimatedOperation();
3146#endif // animation
3147 }
3149}
3150
3152{
3153 viewItems.insert(pos, count, viewItem);
3155 for (int i = pos + count; i < viewItems.size(); i++)
3156 if (items[i].parentItem >= pos)
3157 items[i].parentItem += count;
3158}
3159
3161{
3164 for (int i = pos; i < viewItems.size(); i++)
3165 if (items[i].parentItem >= pos)
3166 items[i].parentItem -= count;
3167}
3168
3169#if 0
3170bool QTreeViewPrivate::checkViewItems() const
3171{
3172 for (int i = 0; i < viewItems.count(); ++i) {
3173 const QTreeViewItem &vi = viewItems.at(i);
3174 if (vi.parentItem == -1) {
3175 Q_ASSERT(!vi.index.parent().isValid() || vi.index.parent() == root);
3176 } else {
3178 }
3179 }
3180 return true;
3181}
3182#endif
3183
3184void QTreeViewPrivate::collapse(int item, bool emitSignal)
3185{
3186 Q_Q(QTreeView);
3187
3188 if (item == -1 || expandedIndexes.isEmpty())
3189 return;
3190
3191 //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
3193
3194 int total = viewItems.at(item).total;
3197 return; // if the index is not persistent, no chances it is expanded
3199 if (it == expandedIndexes.end() || viewItems.at(item).expanded == false)
3200 return; // nothing to do
3201
3202#if QT_CONFIG(animation)
3203 if (emitSignal && animationsEnabled)
3204 prepareAnimatedOperation(item, QVariantAnimation::Backward);
3205#endif // animation
3206
3207 //if already animating, stateBeforeAnimation is set to the correct value
3212 viewItems[item].expanded = false;
3213 int index = item;
3214 while (index > -1) {
3215 viewItems[index].total -= total;
3216 index = viewItems[index].parentItem;
3217 }
3218 removeViewItems(item + 1, total); // collapse
3219 q->setState(stateBeforeAnimation);
3220
3221 if (emitSignal) {
3222 emit q->collapsed(modelIndex);
3223#if QT_CONFIG(animation)
3225 beginAnimatedOperation();
3226#endif // animation
3227 }
3228}
3229
3230#if QT_CONFIG(animation)
3231void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction)
3232{
3233 animatedOperation.item = item;
3234 animatedOperation.viewport = viewport;
3235 animatedOperation.setDirection(direction);
3236
3238 QRect rect = viewport->rect();
3239 rect.setTop(top);
3241 const int limit = rect.height() * 2;
3242 int h = 0;
3243 int c = item + viewItems.at(item).total + 1;
3244 for (int i = item + 1; i < c && h < limit; ++i)
3245 h += itemHeight(i);
3246 rect.setHeight(h);
3247 animatedOperation.setEndValue(top + h);
3248 }
3249 animatedOperation.setStartValue(top);
3250 animatedOperation.before = renderTreeToPixmapForAnimation(rect);
3251}
3252
3253void QTreeViewPrivate::beginAnimatedOperation()
3254{
3255 Q_Q(QTreeView);
3256
3257 QRect rect = viewport->rect();
3258 rect.setTop(animatedOperation.top());
3259 if (animatedOperation.direction() == QVariantAnimation::Forward) {
3260 const int limit = rect.height() * 2;
3261 int h = 0;
3262 int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1;
3263 for (int i = animatedOperation.item + 1; i < c && h < limit; ++i)
3264 h += itemHeight(i);
3265 rect.setHeight(h);
3266 animatedOperation.setEndValue(animatedOperation.top() + h);
3267 }
3268
3269 if (!rect.isEmpty()) {
3270 animatedOperation.after = renderTreeToPixmapForAnimation(rect);
3271
3273 animatedOperation.start(); //let's start the animation
3274 }
3275}
3276
3277void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const
3278{
3279 const int start = animatedOperation.startValue().toInt(),
3280 end = animatedOperation.endValue().toInt(),
3281 current = animatedOperation.currentValue().toInt();
3282 bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward;
3283 const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after;
3284 painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height());
3285 const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before;
3287}
3288
3289QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) const
3290{
3291 Q_Q(const QTreeView);
3292 QPixmap pixmap(rect.size() * q->devicePixelRatio());
3293 pixmap.setDevicePixelRatio(q->devicePixelRatio());
3294 if (rect.size().isEmpty())
3295 return pixmap;
3296 pixmap.fill(Qt::transparent); //the base might not be opaque, and we don't want uninitialized pixels.
3298 painter.fillRect(QRect(QPoint(0,0), rect.size()), q->palette().base());
3299 painter.translate(0, -rect.top());
3300 q->drawTree(&painter, QRegion(rect));
3301 painter.end();
3302
3303 //and now let's render the editors the editors
3304 QStyleOptionViewItem option;
3305 q->initViewItemOption(&option);
3307 QWidget *editor = it.key();
3308 const QModelIndex &index = it.value();
3310 if (option.rect.isValid()) {
3311
3312 if (QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index))
3313 delegate->updateEditorGeometry(editor, option, index);
3314
3315 const QPoint pos = editor->pos();
3316 if (rect.contains(pos)) {
3317 editor->render(&pixmap, pos - rect.topLeft());
3318 //the animation uses pixmap to display the treeview's content
3319 //the editor is rendered on this pixmap and thus can (should) be hidden
3320 editor->hide();
3321 }
3322 }
3323 }
3324
3325
3326 return pixmap;
3327}
3328
3329void QTreeViewPrivate::endAnimatedOperation()
3330{
3331 Q_Q(QTreeView);
3332 q->setState(stateBeforeAnimation);
3333 q->updateGeometries();
3334 viewport->update();
3335}
3336#endif // animation
3337
3342
3344{
3345 if (start <= 0 && 0 <= end)
3346 viewItems.clear();
3348}
3349
3351{
3352 if (start <= 0 && 0 <= end)
3355}
3356
3358{
3359#if QT_CONFIG(accessibility)
3360 Q_Q(QTreeView);
3361 if (pendingAccessibilityUpdate) {
3362 pendingAccessibilityUpdate = false;
3363 if (QAccessible::isActive()) {
3364 QAccessibleTableModelChangeEvent event(q, QAccessibleTableModelChangeEvent::ModelReset);
3365 QAccessible::updateAccessibility(&event);
3366 }
3367 }
3368#endif
3369}
3370
3371
3379void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninitialized)
3380{
3381 Q_Q(QTreeView);
3383 QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
3384
3385 if (i>=0 && !parent.isValid()) {
3386 //modelIndex() should never return something invalid for the real items.
3387 //This can happen if columncount has been set to 0.
3388 //To avoid infinite loop we stop here.
3389 return;
3390 }
3391
3392#if QT_CONFIG(accessibility)
3393 // QAccessibleTree's rowCount implementation uses viewItems.size(), so
3394 // we need to invalidate any cached accessibility data structures if
3395 // that value changes during the run of this function.
3396 const auto resetModelIfNeeded = qScopeGuard([oldViewItemsSize = viewItems.size(), this]{
3397 pendingAccessibilityUpdate |= oldViewItemsSize != viewItems.size();
3398 });
3399#endif
3400
3401 int count = 0;
3402 if (model->hasChildren(parent)) {
3403 if (model->canFetchMore(parent)) {
3404 // fetchMore first, otherwise we might not yet have any data for sizeHintForRow
3405 model->fetchMore(parent);
3406 // guestimate the number of items in the viewport, and fetch as many as might fit
3407 const int itemHeight = defaultItemHeight <= 0 ? q->sizeHintForRow(0) : defaultItemHeight;
3408 const int viewCount = itemHeight ? viewport->height() / itemHeight : 0;
3409 int lastCount = -1;
3410 while ((count = model->rowCount(parent)) < viewCount &&
3411 count != lastCount && model->canFetchMore(parent)) {
3412 model->fetchMore(parent);
3413 lastCount = count;
3414 }
3415 } else {
3416 count = model->rowCount(parent);
3417 }
3418 }
3419
3420 bool expanding = true;
3421 if (i == -1) {
3422 if (uniformRowHeights) {
3423 QModelIndex index = model->index(0, 0, parent);
3424 defaultItemHeight = q->indexRowSizeHint(index);
3425 }
3427 afterIsUninitialized = true;
3428 } else if (viewItems[i].total != (uint)count) {
3429 if (!afterIsUninitialized)
3430 insertViewItems(i + 1, count, QTreeViewItem()); // expand
3431 else if (count > 0)
3433 } else {
3434 expanding = false;
3435 }
3436
3437 int first = i + 1;
3438 int level = (i >= 0 ? viewItems.at(i).level + 1 : 0);
3439 int hidden = 0;
3440 int last = 0;
3441 int children = 0;
3442 QTreeViewItem *item = nullptr;
3443 for (int j = first; j < first + count; ++j) {
3444 current = model->index(j - first, 0, parent);
3445 if (isRowHidden(current)) {
3446 ++hidden;
3447 last = j - hidden + children;
3448 } else {
3449 last = j - hidden + children;
3450 if (item)
3451 item->hasMoreSiblings = true;
3452 item = &viewItems[last];
3453 item->index = current;
3454 item->parentItem = i;
3455 item->level = level;
3456 item->height = 0;
3457 item->spanning = q->isFirstColumnSpanned(current.row(), parent);
3458 item->expanded = false;
3459 item->total = 0;
3460 item->hasMoreSiblings = false;
3461 if ((recursiveExpanding && !(current.flags() & Qt::ItemNeverHasChildren)) || isIndexExpanded(current)) {
3462 if (recursiveExpanding && storeExpanded(current) && !q->signalsBlocked())
3463 emit q->expanded(current);
3464 item->expanded = true;
3465 layout(last, recursiveExpanding, afterIsUninitialized);
3466 item = &viewItems[last];
3467 children += item->total;
3468 item->hasChildren = item->total > 0;
3469 last = j - hidden + children;
3470 } else {
3471 item->hasChildren = hasVisibleChildren(current);
3472 }
3473 }
3474 }
3475
3476 // remove hidden items
3477 if (hidden > 0) {
3478 if (!afterIsUninitialized)
3479 removeViewItems(last + 1, hidden);
3480 else
3481 viewItems.resize(viewItems.size() - hidden);
3482 }
3483
3484 if (!expanding)
3485 return; // nothing changed
3486
3487 while (i > -1) {
3488 viewItems[i].total += count - hidden;
3489 i = viewItems[i].parentItem;
3490 }
3491}
3492
3494{
3497 index--;
3498 if (index == -1)
3499 index = 0;
3501 index++;
3502 return index >= viewItems.size() ? 0 : index;
3503}
3504
3506{
3509 index++;
3510 if (index == -1 || index >= viewItems.size())
3511 index = viewItems.size() - 1;
3513 index--;
3514 return index == -1 ? viewItems.size() - 1 : index;
3515}
3516
3518{
3519 int index = 0;
3521 index++;
3522 return index >= viewItems.size() ? 0 : index;
3523}
3524
3526{
3527 int index = viewItems.size() - 1;
3529 index--;
3530 return index == -1 ? viewItems.size() - 1 : index;
3531}
3532
3534{
3535 if (item < 0 || item >= viewItems.size())
3536 return 0;
3537 int level = viewItems.at(item).level;
3538 if (rootDecoration)
3539 ++level;
3540 return level * indent;
3541}
3542
3544{
3547 return defaultItemHeight;
3548 if (viewItems.isEmpty())
3549 return 0;
3551 if (!index.isValid())
3552 return 0;
3553 int height = viewItems.at(item).height;
3554 if (height <= 0) {
3555 height = q_func()->indexRowSizeHint(index);
3556 viewItems[item].height = height;
3557 }
3558 return qMax(height, 0);
3559}
3560
3561
3567{
3570 return (item * defaultItemHeight) - vbar->value();
3571 // ### optimize (maybe do like QHeaderView by letting items have startposition)
3572 int y = 0;
3573 for (int i = 0; i < viewItems.size(); ++i) {
3574 if (i == item)
3575 return y - vbar->value();
3576 y += itemHeight(i);
3577 }
3578 } else { // ScrollPerItem
3579 int topViewItemIndex = vbar->value();
3581 return defaultItemHeight * (item - topViewItemIndex);
3582 if (item >= topViewItemIndex) {
3583 // search in the visible area first and continue down
3584 // ### slow if the item is not visible
3585 int viewItemCoordinate = 0;
3586 int viewItemIndex = topViewItemIndex;
3587 while (viewItemIndex < viewItems.size()) {
3588 if (viewItemIndex == item)
3589 return viewItemCoordinate;
3590 viewItemCoordinate += itemHeight(viewItemIndex);
3591 ++viewItemIndex;
3592 }
3593 // below the last item in the view
3594 Q_ASSERT(false);
3595 return viewItemCoordinate;
3596 } else {
3597 // search the area above the viewport (used for editor widgets)
3598 int viewItemCoordinate = 0;
3599 for (int viewItemIndex = topViewItemIndex; viewItemIndex > 0; --viewItemIndex) {
3600 if (viewItemIndex == item)
3601 return viewItemCoordinate;
3602 viewItemCoordinate -= itemHeight(viewItemIndex - 1);
3603 }
3604 return viewItemCoordinate;
3605 }
3606 }
3607 return 0;
3608}
3609
3617int QTreeViewPrivate::itemAtCoordinate(int coordinate) const
3618{
3619 const int itemCount = viewItems.size();
3620 if (itemCount == 0)
3621 return -1;
3623 return -1;
3625 if (uniformRowHeights) {
3626 const int viewItemIndex = (coordinate + vbar->value()) / defaultItemHeight;
3627 return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
3628 }
3629 // ### optimize
3630 int viewItemCoordinate = 0;
3631 const int contentsCoordinate = coordinate + vbar->value();
3632 for (int viewItemIndex = 0; viewItemIndex < viewItems.size(); ++viewItemIndex) {
3633 viewItemCoordinate += itemHeight(viewItemIndex);
3634 if (viewItemCoordinate > contentsCoordinate)
3635 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
3636 }
3637 } else { // ScrollPerItem
3638 int topViewItemIndex = vbar->value();
3639 if (uniformRowHeights) {
3640 if (coordinate < 0)
3641 coordinate -= defaultItemHeight - 1;
3642 const int viewItemIndex = topViewItemIndex + (coordinate / defaultItemHeight);
3643 return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
3644 }
3645 if (coordinate >= 0) {
3646 // the coordinate is in or below the viewport
3647 int viewItemCoordinate = 0;
3648 for (int viewItemIndex = topViewItemIndex; viewItemIndex < viewItems.size(); ++viewItemIndex) {
3649 viewItemCoordinate += itemHeight(viewItemIndex);
3650 if (viewItemCoordinate > coordinate)
3651 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
3652 }
3653 } else {
3654 // the coordinate is above the viewport
3655 int viewItemCoordinate = 0;
3656 for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) {
3657 if (viewItemCoordinate <= coordinate)
3658 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
3659 viewItemCoordinate -= itemHeight(viewItemIndex);
3660 }
3661 }
3662 }
3663 return -1;
3664}
3665
3667{
3668 if (!_index.isValid() || viewItems.isEmpty())
3669 return -1;
3670
3671 const int totalCount = viewItems.size();
3672 const QModelIndex index = _index.sibling(_index.row(), 0);
3673 const int row = index.row();
3674 const quintptr internalId = index.internalId();
3675
3676 // We start nearest to the lastViewedItem
3677 int localCount = qMin(lastViewedItem - 1, totalCount - lastViewedItem);
3678 for (int i = 0; i < localCount; ++i) {
3679 const QModelIndex &idx1 = viewItems.at(lastViewedItem + i).index;
3680 if (idx1.row() == row && idx1.internalId() == internalId) {
3682 return lastViewedItem;
3683 }
3684 const QModelIndex &idx2 = viewItems.at(lastViewedItem - i - 1).index;
3685 if (idx2.row() == row && idx2.internalId() == internalId) {
3687 return lastViewedItem;
3688 }
3689 }
3690
3691 for (int j = qMax(0, lastViewedItem + localCount); j < totalCount; ++j) {
3692 const QModelIndex &idx = viewItems.at(j).index;
3693 if (idx.row() == row && idx.internalId() == internalId) {
3694 lastViewedItem = j;
3695 return j;
3696 }
3697 }
3698 for (int j = qMin(totalCount, lastViewedItem - localCount) - 1; j >= 0; --j) {
3699 const QModelIndex &idx = viewItems.at(j).index;
3700 if (idx.row() == row && idx.internalId() == internalId) {
3701 lastViewedItem = j;
3702 return j;
3703 }
3704 }
3705
3706 // nothing found
3707 return -1;
3708}
3709
3711{
3712 if (i < 0 || i >= viewItems.size())
3713 return QModelIndex();
3714
3716 if (column)
3717 ret = ret.sibling(ret.row(), column);
3718 return ret;
3719}
3720
3722{
3723 const int value = vbar->value();
3725 if (offset)
3726 *offset = 0;
3727 return (value < 0 || value >= viewItems.size()) ? -1 : value;
3728 }
3729 // ScrollMode == ScrollPerPixel
3730 if (uniformRowHeights) {
3731 if (!defaultItemHeight)
3732 return -1;
3733
3734 if (offset)
3736 return value / defaultItemHeight;
3737 }
3738 int y = 0; // ### (maybe do like QHeaderView by letting items have startposition)
3739 for (int i = 0; i < viewItems.size(); ++i) {
3740 y += itemHeight(i); // the height value is cached
3741 if (y > value) {
3742 if (offset)
3743 *offset = y - value - itemHeight(i);
3744 return i;
3745 }
3746 }
3747 return -1;
3748}
3749
3750int QTreeViewPrivate::lastVisibleItem(int firstVisual, int offset) const
3751{
3752 if (firstVisual < 0 || offset < 0) {
3753 firstVisual = firstVisibleItem(&offset);
3754 if (firstVisual < 0)
3755 return -1;
3756 }
3757 int y = - offset;
3758 int value = viewport->height();
3759
3760 for (int i = firstVisual; i < viewItems.size(); ++i) {
3761 y += itemHeight(i); // the height value is cached
3762 if (y > value)
3763 return i;
3764 }
3765 return viewItems.size() - 1;
3766}
3767
3769{
3770 return header->logicalIndexAt(x);
3771}
3772
3774{
3775 Q_Q(QTreeView);
3776 QSize viewportSize = viewport->size();
3777 if (!viewportSize.isValid())
3778 viewportSize = QSize(0, 0);
3779
3781 if (viewItems.isEmpty()) {
3782 q->doItemsLayout();
3783 }
3784
3785 int itemsInViewport = 0;
3786 if (uniformRowHeights) {
3787 if (defaultItemHeight <= 0)
3788 itemsInViewport = viewItems.size();
3789 else
3790 itemsInViewport = viewportSize.height() / defaultItemHeight;
3791 } else {
3792 const int itemsCount = viewItems.size();
3793 const int viewportHeight = viewportSize.height();
3794 for (int height = 0, item = itemsCount - 1; item >= 0; --item) {
3796 if (height > viewportHeight)
3797 break;
3798 ++itemsInViewport;
3799 }
3800 }
3802 if (!viewItems.isEmpty())
3803 itemsInViewport = qMax(1, itemsInViewport);
3804 vbar->setRange(0, viewItems.size() - itemsInViewport);
3805 vbar->setPageStep(itemsInViewport);
3806 vbar->setSingleStep(1);
3807 } else { // scroll per pixel
3808 int contentsHeight = 0;
3809 if (uniformRowHeights) {
3810 contentsHeight = defaultItemHeight * viewItems.size();
3811 } else { // ### (maybe do like QHeaderView by letting items have startposition)
3812 for (int i = 0; i < viewItems.size(); ++i)
3813 contentsHeight += itemHeight(i);
3814 }
3815 vbar->setRange(0, contentsHeight - viewportSize.height());
3816 vbar->setPageStep(viewportSize.height());
3817 vbar->d_func()->itemviewChangeSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2));
3818 }
3819
3820 const int columnCount = header->count();
3821 const int viewportWidth = viewportSize.width();
3822 int columnsInViewport = 0;
3823 for (int width = 0, column = columnCount - 1; column >= 0; --column) {
3824 int logical = header->logicalIndex(column);
3825 width += header->sectionSize(logical);
3826 if (width > viewportWidth)
3827 break;
3828 ++columnsInViewport;
3829 }
3830 if (columnCount > 0)
3831 columnsInViewport = qMax(1, columnsInViewport);
3833 hbar->setRange(0, columnCount - columnsInViewport);
3834 hbar->setPageStep(columnsInViewport);
3835 hbar->setSingleStep(1);
3836 } else { // scroll per pixel
3837 const int horizontalLength = header->length();
3838 const QSize maxSize = q->maximumViewportSize();
3839 if (maxSize.width() >= horizontalLength && vbar->maximum() <= 0)
3840 viewportSize = maxSize;
3841 hbar->setPageStep(viewportSize.width());
3842 hbar->setRange(0, qMax(horizontalLength - viewportSize.width(), 0));
3843 hbar->d_func()->itemviewChangeSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2));
3844 }
3845}
3846
3848{
3849 Q_Q(const QTreeView);
3851 bool spanned = false;
3852 if (!spanningIndexes.isEmpty()) {
3853 const QModelIndex index = q->indexAt(pos);
3854 if (index.isValid())
3855 spanned = q->isFirstColumnSpanned(index.row(), index.parent());
3856 }
3857 const int column = spanned ? 0 : header->logicalIndexAt(pos.x());
3858 if (!isTreePosition(column))
3859 return -1; // no logical index at x
3860
3861 int viewItemIndex = itemAtCoordinate(pos.y());
3862 QRect returning = itemDecorationRect(modelIndex(viewItemIndex));
3863 if (!returning.contains(pos))
3864 return -1;
3865
3866 return viewItemIndex;
3867}
3868
3870{
3871 Q_Q(const QTreeView);
3872 if (!rootDecoration && index.parent() == root)
3873 return QRect(); // no decoration at root
3874
3875 int viewItemIndex = viewIndex(index);
3876 if (viewItemIndex < 0 || !hasVisibleChildren(viewItems.at(viewItemIndex).index))
3877 return QRect();
3878
3879 int itemIndentation = indentationForItem(viewItemIndex);
3882
3883 QRect rect;
3884 if (q->isRightToLeft())
3885 rect = QRect(position + size - itemIndentation, coordinateForItem(viewItemIndex),
3886 indent, itemHeight(viewItemIndex));
3887 else
3888 rect = QRect(position + itemIndentation - indent, coordinateForItem(viewItemIndex),
3889 indent, itemHeight(viewItemIndex));
3891 opt.initFrom(q);
3892 opt.rect = rect;
3893 return q->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, q);
3894}
3895
3896QList<QPair<int, int>> QTreeViewPrivate::columnRanges(const QModelIndex &topIndex,
3897 const QModelIndex &bottomIndex) const
3898{
3899 const int topVisual = header->visualIndex(topIndex.column()),
3900 bottomVisual = header->visualIndex(bottomIndex.column());
3901
3902 const int start = qMin(topVisual, bottomVisual);
3903 const int end = qMax(topVisual, bottomVisual);
3904
3905 QList<int> logicalIndexes;
3906
3907 //we iterate over the visual indexes to get the logical indexes
3908 for (int c = start; c <= end; c++) {
3909 const int logical = header->logicalIndex(c);
3910 if (!header->isSectionHidden(logical)) {
3911 logicalIndexes << logical;
3912 }
3913 }
3914 //let's sort the list
3915 std::sort(logicalIndexes.begin(), logicalIndexes.end());
3916
3917 QList<QPair<int, int>> ret;
3918 QPair<int, int> current;
3919 current.first = -2; // -1 is not enough because -1+1 = 0
3920 current.second = -2;
3921 for(int i = 0; i < logicalIndexes.size(); ++i) {
3922 const int logicalColumn = logicalIndexes.at(i);
3923 if (current.second + 1 != logicalColumn) {
3924 if (current.first != -2) {
3925 //let's save the current one
3926 ret += current;
3927 }
3928 //let's start a new one
3929 current.first = current.second = logicalColumn;
3930 } else {
3931 current.second++;
3932 }
3933 }
3934
3935 //let's get the last range
3936 if (current.first != -2) {
3937 ret += current;
3938 }
3939
3940 return ret;
3941}
3942
3943void QTreeViewPrivate::select(const QModelIndex &topIndex, const QModelIndex &bottomIndex,
3944 QItemSelectionModel::SelectionFlags command)
3945{
3946 Q_Q(QTreeView);
3948 const int top = viewIndex(topIndex),
3949 bottom = viewIndex(bottomIndex);
3950
3951 const QList<QPair<int, int>> colRanges = columnRanges(topIndex, bottomIndex);
3952 QList<QPair<int, int>>::const_iterator it;
3953 for (it = colRanges.begin(); it != colRanges.end(); ++it) {
3954 const int left = (*it).first,
3955 right = (*it).second;
3956
3957 QModelIndex previous;
3958 QItemSelectionRange currentRange;
3959 QStack<QItemSelectionRange> rangeStack;
3960 for (int i = top; i <= bottom; ++i) {
3962 QModelIndex parent = index.parent();
3963 QModelIndex previousParent = previous.parent();
3964 if (previous.isValid() && parent == previousParent) {
3965 // same parent
3966 if (qAbs(previous.row() - index.row()) > 1) {
3967 //a hole (hidden index inside a range) has been detected
3968 if (currentRange.isValid()) {
3969 selection.append(currentRange);
3970 }
3971 //let's start a new range
3972 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
3973 } else {
3974 QModelIndex tl = model->index(currentRange.top(), currentRange.left(),
3975 currentRange.parent());
3976 currentRange = QItemSelectionRange(tl, index.sibling(index.row(), right));
3977 }
3978 } else if (previous.isValid() && parent == model->index(previous.row(), 0, previousParent)) {
3979 // item is child of previous
3980 rangeStack.push(currentRange);
3981 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
3982 } else {
3983 if (currentRange.isValid())
3984 selection.append(currentRange);
3985 if (rangeStack.isEmpty()) {
3986 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
3987 } else {
3988 currentRange = rangeStack.pop();
3989 index = currentRange.bottomRight(); //let's resume the range
3990 --i; //we process again the current item
3991 }
3992 }
3993 previous = index;
3994 }
3995 if (currentRange.isValid())
3996 selection.append(currentRange);
3997 for (int i = 0; i < rangeStack.size(); ++i)
3998 selection.append(rangeStack.at(i));
3999 }
4000 q->selectionModel()->select(selection, command);
4001}
4002
4004{
4005 Q_Q(const QTreeView);
4006 int start = header->visualIndexAt(rect.left());
4007 int end = header->visualIndexAt(rect.right());
4008 if (q->isRightToLeft()) {
4009 start = (start == -1 ? header->count() - 1 : start);
4010 end = (end == -1 ? 0 : end);
4011 } else {
4012 start = (start == -1 ? 0 : start);
4013 end = (end == -1 ? header->count() - 1 : end);
4014 }
4015 return qMakePair(qMin(start, end), qMax(start, end));
4016}
4017
4019{
4020 Q_Q(const QTreeView);
4021 if (parent.flags() & Qt::ItemNeverHasChildren)
4022 return false;
4023 if (model->hasChildren(parent)) {
4024 if (hiddenIndexes.isEmpty())
4025 return true;
4026 if (q->isIndexHidden(parent))
4027 return false;
4028 int rowCount = model->rowCount(parent);
4029 for (int i = 0; i < rowCount; ++i) {
4030 if (!q->isRowHidden(i, parent))
4031 return true;
4032 }
4033 if (rowCount == 0)
4034 return true;
4035 }
4036 return false;
4037}
4038
4043
4045{
4046 Q_Q(const QTreeView);
4047
4048 // Note that this will include the header, even if its hidden.
4049 return (q->visualIndex(index) + (q->header() ? 1 : 0)) * index.model()->columnCount() + index.column();
4050}
4051
4053{
4054 Q_Q(const QTreeView);
4055 indent = q->style()->pixelMetric(QStyle::PM_TreeViewIndentation, nullptr, q);
4056}
4057
4061void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
4062{
4063 Q_D(QTreeView);
4064 QAbstractItemView::currentChanged(current, previous);
4065
4066 if (allColumnsShowFocus()) {
4067 if (previous.isValid())
4068 viewport()->update(d->visualRect(previous, QTreeViewPrivate::FullRow));
4069 if (current.isValid())
4070 viewport()->update(d->visualRect(current, QTreeViewPrivate::FullRow));
4071 }
4072#if QT_CONFIG(accessibility)
4073 if (QAccessible::isActive() && current.isValid() && hasFocus()) {
4074 Q_D(QTreeView);
4075
4076 QAccessibleEvent event(this, QAccessible::Focus);
4077 event.setChild(d->accessibleTree2Index(current));
4078 QAccessible::updateAccessibility(&event);
4079 }
4080#endif
4081}
4082
4087 const QItemSelection &deselected)
4088{
4089 QAbstractItemView::selectionChanged(selected, deselected);
4090#if QT_CONFIG(accessibility)
4091 if (QAccessible::isActive()) {
4092 Q_D(QTreeView);
4093
4094 // ### does not work properly for selection ranges.
4095 QModelIndex sel = selected.indexes().value(0);
4096 if (sel.isValid()) {
4097 int entry = d->accessibleTree2Index(sel);
4098 Q_ASSERT(entry >= 0);
4099 QAccessibleEvent event(this, QAccessible::SelectionAdd);
4100 event.setChild(entry);
4101 QAccessible::updateAccessibility(&event);
4102 }
4103 QModelIndex desel = deselected.indexes().value(0);
4104 if (desel.isValid()) {
4105 int entry = d->accessibleTree2Index(desel);
4106 Q_ASSERT(entry >= 0);
4107 QAccessibleEvent event(this, QAccessible::SelectionRemove);
4108 event.setChild(entry);
4109 QAccessible::updateAccessibility(&event);
4110 }
4111 }
4112#endif
4113}
4114
4115int QTreeView::visualIndex(const QModelIndex &index) const
4116{
4117 Q_D(const QTreeView);
4118 d->executePostedLayout();
4119 return d->viewIndex(index);
4120}
4121
4127{
4128 Q_D(QTreeView);
4129 if (!d->viewItems.isEmpty() && value == verticalScrollBar()->maximum()) {
4130 QModelIndex ret = d->viewItems.last().index;
4131 // Root index will be handled by base class implementation
4132 while (ret.isValid()) {
4133 if (isExpanded(ret) && d->model->canFetchMore(ret)) {
4134 d->model->fetchMore(ret);
4135 break;
4136 }
4137 ret = ret.parent();
4138 }
4139 }
4141}
4142
4144
4145#include "moc_qtreeview.cpp"
Direction
This enum describes the direction of the animation when in \l Running state.
void finished()
QAbstractAnimation emits this signal after the animation has stopped and has reached the end.
The QAbstractItemDelegate class is used to display and edit data items from a model.
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const =0
This pure abstract function must be reimplemented if you want to provide custom rendering.
static QAbstractItemModel * staticEmptyModel()
void modelAboutToBeReset(QPrivateSignal)
virtual Q_INVOKABLE bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Returns {true} if parent has any children; otherwise returns {false}.
virtual Q_INVOKABLE int rowCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of rows under the given parent.
virtual Q_INVOKABLE void fetchMore(const QModelIndex &parent)
Fetches any available data for the items with the parent specified by the parent index.
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
virtual Q_INVOKABLE bool canFetchMore(const QModelIndex &parent) const
Returns {true} if there is more data available for parent; otherwise returns {false}.
virtual Q_INVOKABLE int columnCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of columns for the children of the given parent.
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index.
void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been removed from the model.
virtual bool submit()
Lets the model know that it should submit cached information to permanent storage.
const QEditorInfo & editorForIndex(const QModelIndex &index) const
virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
void doDelayedItemsLayout(int delay=0)
virtual void rowsRemoved(const QModelIndex &parent, int start, int end)
QPointer< QAbstractItemDelegate > itemDelegate
QAbstractItemView::ScrollMode horizontalScrollMode
QAbstractItemView::State state
bool isPersistent(const QModelIndex &index) const
QAbstractItemView::State stateBeforeAnimation
QPersistentModelIndex root
virtual void columnsRemoved(const QModelIndex &parent, int start, int end)
virtual void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
bool isIndexValid(const QModelIndex &index) const
QWidget * editor(const QModelIndex &index, const QStyleOptionViewItem &options)
QAbstractItemView::SelectionBehavior selectionBehavior
QAbstractItemView::ScrollMode verticalScrollMode
The QAbstractItemView class provides the basic functionality for item view classes.
SelectionMode
This enum indicates how the view responds to user selections:
QWidget * indexWidget(const QModelIndex &index) const
void activated(const QModelIndex &index)
This signal is emitted when the item specified by index is activated by the user.
QAbstractItemModel * model() const
Returns the model that this view is presenting.
void setCurrentIndex(const QModelIndex &index)
Sets the current item to be the item at index.
void doubleClicked(const QModelIndex &index)
This signal is emitted when a mouse button is double-clicked.
virtual void setSelectionModel(QItemSelectionModel *selectionModel)
Sets the current selection model to the given selectionModel.
void timerEvent(QTimerEvent *event) override
This function is called with the given event when a timer event is sent to the widget.
ScrollMode verticalScrollMode
how the view scrolls its contents in the vertical direction
virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
This slot is called when the selection is changed.
State state() const
Returns the item view's state.
virtual void reset()
Reset the internal state of the view.
void mouseReleaseEvent(QMouseEvent *event) override
This function is called with the given event when a mouse button is released, after a mouse press eve...
virtual QAbstractItemDelegate * itemDelegateForIndex(const QModelIndex &index) const
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This slot is called when items with the given roles are changed in the model.
QModelIndex currentIndex() const
Returns the model index of the current item.
bool viewportEvent(QEvent *event) override
This function is used to handle tool tips, and What's This? mode, if the given event is a QEvent::Too...
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
This slot is called when rows are about to be removed.
virtual void setModel(QAbstractItemModel *model)
Sets the model for the view to present.
ScrollMode horizontalScrollMode
how the view scrolls its contents in the horizontal direction
virtual void setRootIndex(const QModelIndex &index)
Sets the root item to the item at the given index.
virtual void initViewItemOption(QStyleOptionViewItem *option) const
virtual void doItemsLayout()
void keyPressEvent(QKeyEvent *event) override
This function is called with the given event when a key event is sent to the widget.
QModelIndex rootIndex() const
Returns the model index of the model's root item.
CursorAction
This enum describes the different ways to navigate between items,.
virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous)
This slot is called when a new item becomes the current item.
ScrollHint
\value EnsureVisible Scroll to ensure that the item is visible.
void mousePressEvent(QMouseEvent *event) override
This function is called with the given event when a mouse button is pressed while the cursor is insid...
virtual void rowsInserted(const QModelIndex &parent, int start, int end)
This slot is called when rows are inserted.
virtual void updateEditorGeometries()
void setState(State state)
Sets the item view's state to the given state.
void mouseMoveEvent(QMouseEvent *event) override
This function is called with the given event when a mouse move event is sent to the widget.
QItemSelectionModel * selectionModel() const
Returns the current selection model.
virtual void verticalScrollbarValueChanged(int value)
virtual void updateGeometries()
SelectionBehavior selectionBehavior
which selection behavior the view uses
QSize viewportSizeHint() const override
virtual void horizontalScrollbarAction(int action)
virtual int sizeHintForRow(int row) const
Returns the height size hint for the specified row or -1 if there is no model.
static QWidget * focusWidget()
Returns the application widget that has the keyboard input focus, or \nullptr if no widget in this ap...
int keyboardInputInterval
the time limit in milliseconds that distinguishes a key press from two consecutive key presses
void stop()
Stops the timer.
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
\inmodule QtCore
Definition qcoreevent.h:45
@ StyleChange
Definition qcoreevent.h:136
@ MouseButtonPress
Definition qcoreevent.h:60
@ HoverLeave
Definition qcoreevent.h:176
@ HoverEnter
Definition qcoreevent.h:175
@ HoverMove
Definition qcoreevent.h:177
@ MouseButtonRelease
Definition qcoreevent.h:61
QGraphicsItem * parentItem() const
Returns a pointer to this item's parent item.
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1219
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1215
The QHeaderView class provides a header row or header column for item views.
Definition qheaderview.h:18
void geometriesChanged()
void setSortIndicatorShown(bool show)
int sectionPosition(int logicalIndex) const
Returns the section position of the given logicalIndex, or -1 if the section is hidden.
void setSectionsClickable(bool clickable)
Set \l sectionsClickable to clickable.
int sectionViewportPosition(int logicalIndex) const
Returns the section viewport position of the given logicalIndex.
bool isSectionHidden(int logicalIndex) const
Returns true if the section specified by logicalIndex is explicitly hidden from the user; otherwise r...
void sectionCountChanged(int oldCount, int newCount)
This signal is emitted when the number of sections changes, i.e., when sections are added or deleted.
void sectionResized(int logicalIndex, int oldSize, int newSize)
This signal is emitted when a section is resized.
int sectionSize(int logicalIndex) const
Returns the width (or height for vertical headers) of the given logicalIndex.
bool sectionsMoved() const
Returns true if sections in the header has been moved; otherwise returns false;.
void setStretchLastSection(bool stretch)
void sortIndicatorChanged(int logicalIndex, Qt::SortOrder order)
int logicalIndexAt(int position) const
Returns the section that covers the given position in the viewport.
void setDefaultAlignment(Qt::Alignment alignment)
int logicalIndex(int visualIndex) const
Returns the logicalIndex for the section at the given visualIndex position, or -1 if visualIndex < 0 ...
int length() const
Returns the length along the orientation of the header.
void sectionHandleDoubleClicked(int logicalIndex)
This signal is emitted when a section is double-clicked.
int visualIndexAt(int position) const
Returns the visual index of the section that covers the given position in the viewport.
void setFirstSectionMovable(bool movable)
int visualIndex(int logicalIndex) const
Returns the visual index position of the section specified by the given logicalIndex,...
int sectionSizeHint(int logicalIndex) const
Returns a suitable size hint for the section specified by logicalIndex.
void sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
This signal is emitted when a section is moved.
void setSectionsMovable(bool movable)
Sets \l sectionsMovable to movable.
int offset() const
Returns the offset of the header: this is the header's left-most (or top-most for vertical headers) v...
int count() const
Returns the number of sections in the header.
\inmodule QtGui
Definition qevent.h:246
QModelIndexList selectedIndexes
virtual void clear()
Clears the selection model.
void currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
This signal is emitted if the current item changes and its row is different to the row of the previou...
\inmodule QtCore
Q_CORE_EXPORT QModelIndexList indexes() const
Returns a list of model indexes that correspond to the selected items.
The QKeyEvent class describes a key event.
Definition qevent.h:424
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void remove(qsizetype i, qsizetype n=1)
Definition qlist.h:794
qsizetype count() const noexcept
Definition qlist.h:398
pointer data()
Definition qlist.h:431
void resize(qsizetype size)
Definition qlist.h:403
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
static QMetaMethod fromSignal(PointerToMemberFunction signal)
\inmodule QtCore Represents a handle to a signal-slot (or signal-functor) connection.
\inmodule QtCore
constexpr int row() const noexcept
Returns the row this model index refers to.
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
constexpr const QAbstractItemModel * model() const noexcept
Returns a pointer to the model containing the item that this index refers to.
Qt::ItemFlags flags() const
constexpr int column() const noexcept
Returns the column this model index refers to.
constexpr bool isValid() const noexcept
Returns {true} if this model index is valid; otherwise returns {false}.
QModelIndex sibling(int row, int column) const
Returns the sibling at row and column.
constexpr quintptr internalId() const noexcept
Returns a {quintptr} used by the model to associate the index with the internal data structure.
\inmodule QtGui
Definition qevent.h:196
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:328
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
The QPaintEvent class contains event parameters for paint events.
Definition qevent.h:486
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip region to the given rectangle using the given clip operation.
void setBrushOrigin(int x, int y)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpainter.h:698
void restore()
Restores the current painter state (pops a saved state off the stack).
void save()
Saves the current painter state (pushes the state onto a stack).
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
QPoint brushOrigin() const
Returns the currently set brush origin.
bool end()
Ends painting.
void translate(const QPointF &offset)
Translates the coordinate system by the given offset; i.e.
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
void setCurrentColorGroup(ColorGroup cg)
Set the palette's current color group to cg.
Definition qpalette.h:65
ColorGroup
\value Disabled \value Active \value Inactive \value Normal synonym for Active
Definition qpalette.h:49
@ Inactive
Definition qpalette.h:49
@ Disabled
Definition qpalette.h:49
@ Highlight
Definition qpalette.h:53
bool isValid() const
Returns {true} if this persistent model index is valid; otherwise returns {false}.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
T * data() const noexcept
Definition qpointer.h:73
\inmodule QtCore\reentrant
Definition qrect.h:30
bool intersects(const QRect &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e., there is at least one pixel...
Definition qrect.cpp:1069
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr void setRect(int x, int y, int w, int h) noexcept
Sets the coordinates of the rectangle's top-left corner to ({x}, {y}), and its size to the given widt...
Definition qrect.h:346
constexpr void setX(int x) noexcept
Sets the left edge of the rectangle to the given x coordinate.
Definition qrect.h:215
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr void setTop(int pos) noexcept
Sets the top edge of the rectangle to the given y coordinate.
Definition qrect.h:194
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
int rectCount() const noexcept
The QScrollBar widget provides a vertical or horizontal scroll bar.
Definition qscrollbar.h:20
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
bool isEmpty() const
Definition qset.h:52
void clear()
Definition qset.h:61
iterator erase(const_iterator i)
Definition qset.h:145
iterator find(const T &value)
Definition qset.h:159
bool contains(const T &value) const
Definition qset.h:71
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4833
ButtonFeatures features
\variable QStyleOption::palette
The QStyleOption class stores the parameters used by QStyle functions.
QStyle::State state
QPalette palette
void initFrom(const QWidget *w)
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ State_Sibling
Definition qstyle.h:88
@ State_MouseOver
Definition qstyle.h:80
@ State_Item
Definition qstyle.h:87
@ State_HasFocus
Definition qstyle.h:75
@ State_Active
Definition qstyle.h:83
@ State_Children
Definition qstyle.h:86
@ State_Open
Definition qstyle.h:85
@ State_KeyboardFocusChange
Definition qstyle.h:90
@ State_Enabled
Definition qstyle.h:67
@ State_Selected
Definition qstyle.h:82
@ State_None
Definition qstyle.h:66
@ SH_ItemView_PaintAlternatingRowColorsForEmptyArea
Definition qstyle.h:669
@ SH_ItemView_ArrowKeysNavigateIntoChildren
Definition qstyle.h:664
@ SH_Widget_Animation_Duration
Definition qstyle.h:700
@ SH_ListViewExpand_SelectMouseType
Definition qstyle.h:625
@ SH_ItemView_ActivateItemOnSingleClick
Definition qstyle.h:646
@ SH_ItemView_ShowDecorationSelected
Definition qstyle.h:645
@ PM_TreeViewIndentation
Definition qstyle.h:528
@ PE_PanelItemViewRow
Definition qstyle.h:154
@ PE_IndicatorBranch
Definition qstyle.h:128
@ PE_FrameFocusRect
Definition qstyle.h:106
@ SE_TreeViewDisclosureItem
Definition qstyle.h:279
\inmodule QtCore
Definition qcoreevent.h:366
void sortIndicatorChanged(int column, Qt::SortOrder order)
int itemForKeyEnd() const
QHeaderView * header
int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const
int accessibleTree2Index(const QModelIndex &index) const
bool isRowHidden(const QModelIndex &idx) const
int logicalIndexForTree() const
bool isItemHiddenOrDisabled(int i) const
QMetaObject::Connection animationConnection
int itemHeight(int item) const
void collapse(int item, bool emitSignal)
void calcLogicalIndices(QList< int > *logicalIndices, QList< QStyleOptionViewItem::ViewItemPosition > *itemPositions, int left, int right) const
void layout(int item, bool recusiveExpanding=false, bool afterIsUninitialized=false)
QMetaObject::Connection selectionmodelConnection
bool isIndexExpanded(const QModelIndex &idx) const
QModelIndex modelIndex(int i, int column=0) const
bool storeExpanded(const QPersistentModelIndex &idx)
QList< QPair< int, int > > columnRanges(const QModelIndex &topIndex, const QModelIndex &bottomIndex) const
void removeViewItems(int pos, int count)
bool isTreePosition(int logicalIndex) const
Definition qtreeview_p.h:69
QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override
int firstVisibleItem(int *offset=nullptr) const
QRect itemDecorationRect(const QModelIndex &index) const
void insertViewItems(int pos, int count, const QTreeViewItem &viewItem)
QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const override
\reimp
void columnsRemoved(const QModelIndex &, int, int) override
void select(const QModelIndex &start, const QModelIndex &stop, QItemSelectionModel::SelectionFlags command)
std::array< QMetaObject::Connection, 5 > headerConnections
void paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItem *option, int y, int bottom) const
QList< QTreeViewItem > viewItems
QRect visualRect(const QModelIndex &index) const override
int pageUp(int item) const
void columnsAboutToBeRemoved(const QModelIndex &, int, int) override
int viewIndex(const QModelIndex &index) const
int itemDecorationAt(const QPoint &pos) const
QMetaObject::Connection sortHeaderConnection
int pageDown(int item) const
QSet< QPersistentModelIndex > hiddenIndexes
int lastVisibleItem(int firstVisual=-1, int offset=-1) const
int columnAt(int x) const
int itemAtCoordinate(int coordinate) const
QSet< QPersistentModelIndex > spanningIndexes
void updateAccessibility()
std::array< QMetaObject::Connection, 2 > modelConnections
int itemForKeyHome() const
int indentationForItem(int item) const
void updateIndentationFromStyle()
QSet< QPersistentModelIndex > expandedIndexes
bool expandOrCollapseItemAtPos(const QPoint &pos)
void adjustViewOptionsForIndex(QStyleOptionViewItem *option, const QModelIndex &current) const override
void modelDestroyed() override
int coordinateForItem(int item) const
void expand(int item, bool emitSignal)
QPair< int, int > startAndEndColumns(const QRect &rect) const
bool hasVisibleChildren(const QModelIndex &parent) const
void modelAboutToBeReset()
The QTreeView class provides a default model/view implementation of a tree view.
Definition qtreeview.h:20
void setItemsExpandable(bool enable)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >()) override
\reimp
bool isSortingEnabled() const
bool isIndexHidden(const QModelIndex &index) const override
\reimp
void expand(const QModelIndex &index)
Expands the model item specified by the index.
bool itemsExpandable
whether the items are expandable by the user.
Definition qtreeview.h:26
QRegion visualRegionForSelection(const QItemSelection &selection) const override
Returns the rectangle from the viewport of the items in the given selection.
void setWordWrap(bool on)
void setSelectionModel(QItemSelectionModel *selectionModel) override
\reimp
bool isHeaderHidden() const
virtual void drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const
Draws the branches in the tree view on the same row as the model item index, using the painter given.
void collapse(const QModelIndex &index)
Collapses the model item specified by the index.
void setRootIndex(const QModelIndex &index) override
\reimp
void setModel(QAbstractItemModel *model) override
\reimp
QModelIndex indexBelow(const QModelIndex &index) const
Returns the model index of the item below index.
int indexRowSizeHint(const QModelIndex &index) const
Returns the size hint for the row indicated by index.
void reset() override
\reimp
void doItemsLayout() override
int rowHeight(const QModelIndex &index) const
bool isExpanded(const QModelIndex &index) const
Returns true if the model item index is expanded; otherwise returns false.
void changeEvent(QEvent *event) override
\reimp
QSize viewportSizeHint() const override
\reimp
int columnViewportPosition(int column) const
Returns the horizontal position of the column in the viewport.
void columnCountChanged(int oldCount, int newCount)
Informs the tree view that the number of columns in the tree view has changed from oldCount to newCou...
void setColumnHidden(int column, bool hide)
If hide is true the column is hidden, otherwise the column is shown.
QHeaderView * header() const
Returns the header for the tree view.
void setColumnWidth(int column, int width)
void keyPressEvent(QKeyEvent *event) override
\reimp
void collapseAll()
bool isAnimated() const
void setTreePosition(int logicalIndex)
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override
Informs the view that the rows from the start row to the end row inclusive are about to removed from ...
void setExpandsOnDoubleClick(bool enable)
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
Move the cursor in the way described by cursorAction, using the information provided by the button mo...
void verticalScrollbarValueChanged(int value) override
bool wordWrap
the item text word-wrapping policy
Definition qtreeview.h:30
int columnAt(int x) const
Returns the column in the tree view whose header covers the x coordinate given.
virtual void drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const
Draws the row in the tree view that contains the model item index, using the painter given.
void selectAll() override
\reimp
void setExpanded(const QModelIndex &index, bool expand)
Sets the item referred to by index to either collapse or expanded, depending on the value of expanded...
void updateGeometries() override
\reimp
void mousePressEvent(QMouseEvent *event) override
\reimp
void timerEvent(QTimerEvent *event) override
\reimp
~QTreeView()
Destroys the tree view.
QModelIndex indexAt(const QPoint &p) const override
\reimp
int sizeHintForColumn(int column) const override
Returns the size hint for the column's width or -1 if there is no model.
void setHeaderHidden(bool hide)
void currentChanged(const QModelIndex &current, const QModelIndex &previous) override
\reimp
void reexpand()
QModelIndex indexAbove(const QModelIndex &index) const
Returns the model index of the item above index.
bool viewportEvent(QEvent *event) override
\reimp
void drawTree(QPainter *painter, const QRegion &region) const
void columnMoved()
This slot is called whenever a column has been moved.
bool uniformRowHeights
whether all items in the treeview have the same height
Definition qtreeview.h:25
void expandToDepth(int depth)
void resetIndentation()
void setUniformRowHeights(bool uniform)
void showColumn(int column)
Shows the given column in the tree view.
void setHeader(QHeaderView *header)
Sets the header for the tree view, to the given header.
QTreeView(QWidget *parent=nullptr)
Constructs a tree view with a parent to represent a model's data.
void setRootIsDecorated(bool show)
void setIndentation(int i)
int indentation
indentation of the items in the tree view.
Definition qtreeview.h:23
void setAllColumnsShowFocus(bool enable)
void columnResized(int column, int oldSize, int newSize)
This function is called whenever {column}'s size is changed in the header.
void mouseReleaseEvent(QMouseEvent *event) override
\reimp
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) override
Applies the selection command to the items in or touched by the rectangle, rect.
bool allColumnsShowFocus
whether items should show keyboard focus using all columns
Definition qtreeview.h:29
void paintEvent(QPaintEvent *event) override
\reimp
void resizeColumnToContents(int column)
Resizes the column given to the size of its contents.
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override
\reimp
void setFirstColumnSpanned(int row, const QModelIndex &parent, bool span)
int autoExpandDelay
The delay time before items in a tree are opened during a drag and drop operation.
Definition qtreeview.h:22
void mouseDoubleClickEvent(QMouseEvent *event) override
\reimp
void setAutoExpandDelay(int delay)
QModelIndexList selectedIndexes() const override
\reimp
void keyboardSearch(const QString &search) override
\reimp
void collapsed(const QModelIndex &index)
This signal is emitted when the item specified by index is collapsed.
void mouseMoveEvent(QMouseEvent *event) override
\reimp
void sortByColumn(int column, Qt::SortOrder order)
bool isColumnHidden(int column) const
Returns true if the column is hidden; otherwise returns false.
void scrollTo(const QModelIndex &index, ScrollHint hint=EnsureVisible) override
Scroll the contents of the tree view until the given model item index is visible.
void rowsRemoved(const QModelIndex &parent, int first, int last)
bool rootIsDecorated
whether to show controls for expanding and collapsing top-level items
Definition qtreeview.h:24
bool expandsOnDoubleClick
whether the items can be expanded by double-clicking.
Definition qtreeview.h:32
void setRowHidden(int row, const QModelIndex &parent, bool hide)
If hide is true the row with the given parent is hidden, otherwise the row is shown.
bool isRowHidden(int row, const QModelIndex &parent) const
Returns true if the item in the given row of the parent is hidden; otherwise returns false.
QRect visualRect(const QModelIndex &index) const override
Returns the rectangle on the viewport occupied by the item at index.
int treePosition() const
int horizontalOffset() const override
Returns the horizontal offset of the items in the treeview.
void rowsInserted(const QModelIndex &parent, int start, int end) override
Informs the view that the rows from the start row to the end row inclusive have been inserted into th...
void setSortingEnabled(bool enable)
int columnWidth(int column) const
Returns the width of the column.
void hideColumn(int column)
Hides the column given.
bool isFirstColumnSpanned(int row, const QModelIndex &parent) const
void setAnimated(bool enable)
void expanded(const QModelIndex &index)
This signal is emitted when the item specified by index is expanded.
void expandAll()
int verticalOffset() const override
Returns the vertical offset of the items in the tree view.
void expandRecursively(const QModelIndex &index, int depth=-1)
void scrollContentsBy(int dx, int dy) override
Scrolls the contents of the tree view by (dx, dy).
void horizontalScrollbarAction(int action) override
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QSize minimumSize
the widget's minimum size
Definition qwidget.h:120
QSize maximumSize
the widget's maximum size in pixels
Definition qwidget.h:121
QPoint pos
the position of the widget within its parent widget
Definition qwidget.h:111
void hide()
Hides the widget.
Definition qwidget.cpp:8135
QSize sizeHint
the recommended size for the widget
Definition qwidget.h:148
void render(QPaintDevice *target, const QPoint &targetOffset=QPoint(), const QRegion &sourceRegion=QRegion(), RenderFlags renderFlags=RenderFlags(DrawWindowBackground|DrawChildren))
Definition qwidget.cpp:5092
EGLImageKHR int int EGLuint64KHR * modifiers
QOpenGLWidget * widget
[1]
QSet< QString >::iterator it
rect
[4]
direction
QStyleOptionButton opt
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ AlignVCenter
Definition qnamespace.h:155
@ AlignLeft
Definition qnamespace.h:144
@ WA_MacShowFocusRect
Definition qnamespace.h:359
@ Horizontal
Definition qnamespace.h:99
@ transparent
Definition qnamespace.h:47
@ DisplayRole
@ Key_Plus
Definition qnamespace.h:525
@ Key_Minus
Definition qnamespace.h:527
@ Key_Asterisk
Definition qnamespace.h:524
SortOrder
Definition qnamespace.h:121
@ UniqueConnection
@ ItemNeverHasChildren
@ ItemIsEnabled
QList< QItemViewPaintPair > QItemViewPaintPairs
DBusConnection const char * rule
DBusConnection * connection
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static int area(const QSize &s)
Definition qicon.cpp:153
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei range
GLint GLsizei width
GLint left
GLint GLint bottom
GLboolean enable
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLenum GLenum GLsizei void GLsizei void * column
struct _cl_event * event
const GLubyte * c
GLuint entry
GLint limit
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLenum GLenum GLsizei void GLsizei void void * span
GLuint64EXT * result
[6]
GLuint GLenum option
GLfixed GLfixed GLint GLint order
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define emit
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
static bool ancestorOf(QObject *widget, QObject *other)
size_t quintptr
Definition qtypes.h:167
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
QSqlQueryModel * model
[16]
view show()
[18] //! [19]
QList< int > list
[14]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QVBoxLayout * layout
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
view viewport() -> scroll(dx, dy, deviceRect)
edit hide()
edit isVisible()
QItemSelection * selection
[0]
QList< QTreeWidgetItem * > items
QLayoutItem * child
[0]
widget render & pixmap
QPainter painter(this)
[7]
QPointer< QWidget > widget
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
QModelIndex index
Definition qtreeview_p.h:36
uint hasMoreSiblings
Definition qtreeview_p.h:41