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 int left = std::numeric_limits<int>::max();
1416 int right = std::numeric_limits<int>::min();
1417 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
1418 const auto idxCol0 = model->index(row, 0, parentIdx);
1419 if (isRowHidden(idxCol0))
1420 continue;
1421 QRect rowRect;
1422 if (left != std::numeric_limits<int>::max()) {
1423 // we already know left and right boundary of the rect to update
1424 rowRect = visualRect(idxCol0, FullRow);
1425 if (!rowRect.intersects(rect))
1426 continue;
1427 rowRect = QRect(left, rowRect.top(), right, rowRect.bottom());
1428 } else if (!spanningIndexes.isEmpty() && spanningIndexes.contains(idxCol0)) {
1429 // isFirstColumnSpanned re-creates the child index so take a shortcut here
1430 // spans the whole row, therefore ask for FullRow instead for every cell
1431 rowRect = visualRect(idxCol0, FullRow);
1432 if (!rowRect.intersects(rect))
1433 continue;
1434 } else {
1435 for (int col = topLeft.column(); col <= bottomRight.column(); ++col) {
1436 if (header->isSectionHidden(col))
1437 continue;
1438 const QModelIndex idx(model->index(row, col, parentIdx));
1439 const QRect idxRect = visualRect(idx, SingleSection);
1440 if (idxRect.isNull())
1441 continue;
1442 // early exit when complete row is out of viewport
1443 if (idxRect.top() > rect.bottom() && idxRect.bottom() < rect.top())
1444 break;
1445 if (!idxRect.intersects(rect))
1446 continue;
1447 rowRect = rowRect.united(idxRect);
1448 if (rowRect.left() < rect.left() && rowRect.right() > rect.right())
1449 break;
1450 }
1451 left = std::min(left, rowRect.left());
1452 right = std::max(right, rowRect.right());
1453 }
1454 updateRect = updateRect.united(rowRect);
1455 if (updateRect.contains(rect)) // already full rect covered?
1456 break;
1457 }
1458 return rect.intersected(updateRect);
1459}
1460
1467{
1468 Q_ASSERT(r);
1469 Q_Q(const QTreeView);
1473 for (const QModelIndex &idx : indexes) {
1474 if (idx.column() > 0 && q->isFirstColumnSpanned(idx.row(), idx.parent()))
1475 continue;
1476 list << idx;
1477 }
1479}
1480
1481void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItem *option, const QModelIndex &current) const
1482{
1483 const int row = viewIndex(current); // get the index in viewItems[]
1487
1488 option->showDecorationSelected = (selectionBehavior & QTreeView::SelectRows)
1489 || option->showDecorationSelected;
1490
1491 QList<int>
1492 logicalIndices; // index = visual index of visible columns only. data = logical index.
1493 QList<QStyleOptionViewItem::ViewItemPosition>
1494 viewItemPosList; // vector of left/middle/end for each logicalIndex, visible columns
1495 // only.
1496 const bool spanning = viewItems.at(row).spanning;
1497 const int left = (spanning ? header->visualIndex(0) : 0);
1498 const int right = (spanning ? header->visualIndex(0) : header->count() - 1 );
1499 calcLogicalIndices(&logicalIndices, &viewItemPosList, left, right);
1500
1501 const int visualIndex = logicalIndices.indexOf(current.column());
1502 option->viewItemPosition = viewItemPosList.at(visualIndex);
1503}
1504
1505
1513void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
1514{
1515 Q_D(const QTreeView);
1516 // d->viewItems changes when posted layouts are executed in itemDecorationAt, so don't copy
1517 const QList<QTreeViewItem> &viewItems = d->viewItems;
1518
1519 QStyleOptionViewItem option;
1521 const QStyle::State state = option.state;
1522 d->current = 0;
1523
1524 if (viewItems.size() == 0 || d->header->count() == 0 || !d->itemDelegate) {
1525 d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
1526 return;
1527 }
1528
1529 int firstVisibleItemOffset = 0;
1530 const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset);
1531 if (firstVisibleItem < 0) {
1532 d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
1533 return;
1534 }
1535
1536 const int viewportWidth = d->viewport->width();
1537
1538 QPoint hoverPos = d->viewport->mapFromGlobal(QCursor::pos());
1539 d->hoverBranch = d->itemDecorationAt(hoverPos);
1540
1541 QList<int> drawn;
1542 bool multipleRects = (region.rectCount() > 1);
1543 for (const QRect &a : region) {
1544 const QRect area = (multipleRects
1545 ? QRect(0, a.y(), viewportWidth, a.height())
1546 : a);
1547 d->leftAndRight = d->startAndEndColumns(area);
1548
1549 int i = firstVisibleItem; // the first item at the top of the viewport
1550 int y = firstVisibleItemOffset; // we may only see part of the first item
1551
1552 // start at the top of the viewport and iterate down to the update area
1553 for (; i < viewItems.size(); ++i) {
1554 const int itemHeight = d->itemHeight(i);
1555 if (y + itemHeight > area.top())
1556 break;
1557 y += itemHeight;
1558 }
1559
1560 // paint the visible rows
1561 for (; i < viewItems.size() && y <= area.bottom(); ++i) {
1562 const QModelIndex &index = viewItems.at(i).index;
1563 const int itemHeight = d->itemHeight(i);
1564 option.rect = d->visualRect(index, QTreeViewPrivate::FullRow);
1565 option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None)
1566 | (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None)
1567 | (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None);
1568 d->current = i;
1569 d->spanning = viewItems.at(i).spanning;
1570 if (!multipleRects || !drawn.contains(i)) {
1571 drawRow(painter, option, viewItems.at(i).index);
1572 if (multipleRects) // even if the rect only intersects the item,
1573 drawn.append(i); // the entire item will be painted
1574 }
1575 y += itemHeight;
1576 }
1577
1578 if (y <= area.bottom()) {
1579 d->current = i;
1580 d->paintAlternatingRowColors(painter, &option, y, area.bottom());
1581 }
1582 }
1583}
1584
1586static inline bool ancestorOf(QObject *widget, QObject *other)
1587{
1588 for (QObject *parent = other; parent != nullptr; parent = parent->parent()) {
1589 if (parent == widget)
1590 return true;
1591 }
1592 return false;
1593}
1594
1596 QList<int> *logicalIndices, QList<QStyleOptionViewItem::ViewItemPosition> *itemPositions,
1597 int left, int right) const
1598{
1599 const int columnCount = header->count();
1600 /* 'left' and 'right' are the left-most and right-most visible visual indices.
1601 Compute the first visible logical indices before and after the left and right.
1602 We will use these values to determine the QStyleOptionViewItem::viewItemPosition. */
1603 int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1;
1604 for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) {
1605 int logicalIndex = header->logicalIndex(visualIndex);
1606 if (!header->isSectionHidden(logicalIndex)) {
1607 logicalIndexBeforeLeft = logicalIndex;
1608 break;
1609 }
1610 }
1611
1612 for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) {
1613 int logicalIndex = header->logicalIndex(visualIndex);
1614 if (!header->isSectionHidden(logicalIndex)) {
1615 if (visualIndex > right) {
1616 logicalIndexAfterRight = logicalIndex;
1617 break;
1618 }
1619 logicalIndices->append(logicalIndex);
1620 }
1621 }
1622
1623 itemPositions->resize(logicalIndices->size());
1624 for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices->size(); ++currentLogicalSection) {
1625 const int headerSection = logicalIndices->at(currentLogicalSection);
1626 // determine the viewItemPosition depending on the position of column 0
1627 int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices->size()
1628 ? logicalIndexAfterRight
1629 : logicalIndices->at(currentLogicalSection + 1);
1630 int prevLogicalSection = currentLogicalSection - 1 < 0
1631 ? logicalIndexBeforeLeft
1632 : logicalIndices->at(currentLogicalSection - 1);
1633 QStyleOptionViewItem::ViewItemPosition pos;
1634 if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
1635 || (headerSection == 0 && nextLogicalSection == -1) || spanning)
1636 pos = QStyleOptionViewItem::OnlyOne;
1637 else if (isTreePosition(headerSection) || (nextLogicalSection != 0 && prevLogicalSection == -1))
1638 pos = QStyleOptionViewItem::Beginning;
1639 else if (nextLogicalSection == 0 || nextLogicalSection == -1)
1640 pos = QStyleOptionViewItem::End;
1641 else
1642 pos = QStyleOptionViewItem::Middle;
1643 (*itemPositions)[currentLogicalSection] = pos;
1644 }
1645}
1646
1651int QTreeViewPrivate::widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const
1652{
1653 Q_Q(const QTreeView);
1655 if (editor && persistent.contains(editor)) {
1656 hint = qMax(hint, editor->sizeHint().width());
1657 int min = editor->minimumSize().width();
1658 int max = editor->maximumSize().width();
1659 hint = qBound(min, hint, max);
1660 }
1661 int xhint = q->itemDelegateForIndex(index)->sizeHint(option, index).width();
1662 hint = qMax(hint, xhint + (isTreePosition(index.column()) ? indentationForItem(i) : 0));
1663 return hint;
1664}
1665
1673void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
1674 const QModelIndex &index) const
1675{
1676 Q_D(const QTreeView);
1677 QStyleOptionViewItem opt = option;
1678 const QPoint offset = d->scrollDelayOffset;
1679 const int y = option.rect.y() + offset.y();
1680 const QModelIndex parent = index.parent();
1681 const QHeaderView *header = d->header;
1682 const QModelIndex current = currentIndex();
1683 const QModelIndex hover = d->hover;
1684 const bool reverse = isRightToLeft();
1685 const QStyle::State state = opt.state;
1686 const bool spanning = d->spanning;
1687 const int left = (spanning ? header->visualIndex(0) : d->leftAndRight.first);
1688 const int right = (spanning ? header->visualIndex(0) : d->leftAndRight.second);
1689 const bool alternate = d->alternatingColors;
1690 const bool enabled = (state & QStyle::State_Enabled) != 0;
1691 const bool allColumnsShowFocus = d->allColumnsShowFocus;
1692
1693
1694 // when the row contains an index widget which has focus,
1695 // we want to paint the entire row as active
1696 bool indexWidgetHasFocus = false;
1697 if ((current.row() == index.row()) && !d->editorIndexHash.isEmpty()) {
1698 const int r = index.row();
1700 for (int c = 0; c < header->count(); ++c) {
1701 QModelIndex idx = d->model->index(r, c, parent);
1702 if (QWidget *editor = indexWidget(idx)) {
1703 if (ancestorOf(editor, fw)) {
1704 indexWidgetHasFocus = true;
1705 break;
1706 }
1707 }
1708 }
1709 }
1710
1711 const bool widgetHasFocus = hasFocus();
1712 bool currentRowHasFocus = false;
1713 if (allColumnsShowFocus && widgetHasFocus && current.isValid()) {
1714 // check if the focus index is before or after the visible columns
1715 const int r = index.row();
1716 for (int c = 0; c < left && !currentRowHasFocus; ++c) {
1717 QModelIndex idx = d->model->index(r, c, parent);
1718 currentRowHasFocus = (idx == current);
1719 }
1720 QModelIndex parent = d->model->parent(index);
1721 for (int c = right; c < header->count() && !currentRowHasFocus; ++c) {
1722 currentRowHasFocus = (d->model->index(r, c, parent) == current);
1723 }
1724 }
1725
1726 // ### special case: if we select entire rows, then we need to draw the
1727 // selection in the first column all the way to the second column, rather
1728 // than just around the item text. We abuse showDecorationSelected to
1729 // indicate this to the style. Below we will reset this value temporarily
1730 // to only respect the styleHint while we are rendering the decoration.
1731 opt.showDecorationSelected = (d->selectionBehavior & SelectRows)
1732 || option.showDecorationSelected;
1733
1734 int width, height = option.rect.height();
1735 int position;
1736 QModelIndex modelIndex;
1737 const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
1738 && index.parent() == hover.parent()
1739 && index.row() == hover.row();
1740
1741 QList<int> logicalIndices;
1742 QList<QStyleOptionViewItem::ViewItemPosition>
1743 viewItemPosList; // vector of left/middle/end for each logicalIndex
1744 d->calcLogicalIndices(&logicalIndices, &viewItemPosList, left, right);
1745
1746 for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices.size(); ++currentLogicalSection) {
1747 int headerSection = logicalIndices.at(currentLogicalSection);
1748 position = columnViewportPosition(headerSection) + offset.x();
1749 width = header->sectionSize(headerSection);
1750
1751 if (spanning) {
1752 int lastSection = header->logicalIndex(header->count() - 1);
1753 if (!reverse) {
1754 width = columnViewportPosition(lastSection) + header->sectionSize(lastSection) - position;
1755 } else {
1756 width += position - columnViewportPosition(lastSection);
1757 position = columnViewportPosition(lastSection);
1758 }
1759 }
1760
1761 modelIndex = d->model->index(index.row(), headerSection, parent);
1762 if (!modelIndex.isValid())
1763 continue;
1764 opt.state = state;
1765
1766 opt.viewItemPosition = viewItemPosList.at(currentLogicalSection);
1767
1768 // fake activeness when row editor has focus
1769 if (indexWidgetHasFocus)
1771
1772 if (d->selectionModel->isSelected(modelIndex))
1774 if (widgetHasFocus && (current == modelIndex)) {
1776 currentRowHasFocus = true;
1777 else
1779 }
1781 (hoverRow || modelIndex == hover)
1782 && (option.showDecorationSelected || d->hoverBranch == -1));
1783
1784 if (enabled) {
1786 if ((d->model->flags(modelIndex) & Qt::ItemIsEnabled) == 0) {
1787 opt.state &= ~QStyle::State_Enabled;
1788 cg = QPalette::Disabled;
1789 } else if (opt.state & QStyle::State_Active) {
1790 cg = QPalette::Active;
1791 } else {
1792 cg = QPalette::Inactive;
1793 }
1795 }
1796
1797 if (alternate) {
1798 opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1);
1799 }
1800
1801 /* Prior to Qt 4.3, the background of the branch (in selected state and
1802 alternate row color was provided by the view. For backward compatibility,
1803 this is now delegated to the style using PE_PanelItemViewRow which
1804 does the appropriate fill */
1805 if (d->isTreePosition(headerSection)) {
1806 const int i = d->indentationForItem(d->current);
1807 QRect branches(reverse ? position + width - i : position, y, i, height);
1808 const bool setClipRect = branches.width() > width;
1809 if (setClipRect) {
1810 painter->save();
1812 }
1813 // draw background for the branch (selection + alternate row)
1814 opt.rect = branches;
1815
1816 // We use showDecorationSelected both to store the style hint, and to indicate
1817 // that the entire row has to be selected (see overrides of the value if
1818 // selectionBehavior == SelectRow).
1819 // While we are only painting the background we don't care for the
1820 // selectionBehavior factor, so respect only the style value, and reset later.
1821 const bool oldShowDecorationSelected = opt.showDecorationSelected;
1822 opt.showDecorationSelected = style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected,
1823 &opt, this);
1824 opt.features |= QStyleOptionViewItem::HasDecoration;
1825 opt.rect = branches;
1826 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
1827 opt.features &= ~QStyleOptionViewItem::HasDecoration;
1828
1829 // draw background of the item (only alternate row). rest of the background
1830 // is provided by the delegate
1831 QStyle::State oldState = opt.state;
1832 opt.state &= ~QStyle::State_Selected;
1833 opt.rect.setRect(reverse ? position : i + position, y, width - i, height);
1834 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
1835 opt.state = oldState;
1836 opt.showDecorationSelected = oldShowDecorationSelected;
1837
1838 if (d->indent != 0)
1839 drawBranches(painter, branches, index);
1840 if (setClipRect)
1841 painter->restore();
1842 } else {
1843 QStyle::State oldState = opt.state;
1844 opt.state &= ~QStyle::State_Selected;
1846 style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
1847 opt.state = oldState;
1848 }
1849
1850 itemDelegateForIndex(modelIndex)->paint(painter, opt, modelIndex);
1851 }
1852
1853 if (currentRowHasFocus) {
1855 o.QStyleOption::operator=(option);
1859 o.backgroundColor = option.palette.color(cg, d->selectionModel->isSelected(index)
1861 int x = 0;
1862 if (!option.showDecorationSelected)
1863 x = header->sectionPosition(0) + d->indentationForItem(d->current);
1864 QRect focusRect(x - header->offset(), y, header->length() - x, height);
1865 o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), focusRect);
1866 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
1867 // if we show focus on all columns and the first section is moved,
1868 // we have to split the focus rect into two rects
1869 if (allColumnsShowFocus && !option.showDecorationSelected
1870 && header->sectionsMoved() && (header->visualIndex(0) != 0)) {
1871 QRect sectionRect(0, y, header->sectionPosition(0), height);
1872 o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), sectionRect);
1873 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
1874 }
1875 }
1876}
1877
1884 const QModelIndex &index) const
1885{
1886 Q_D(const QTreeView);
1887 const bool reverse = isRightToLeft();
1888 const int indent = d->indent;
1889 const int outer = d->rootDecoration ? 0 : 1;
1890 const int item = d->current;
1891 const QTreeViewItem &viewItem = d->viewItems.at(item);
1892 int level = viewItem.level;
1893 QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height());
1894
1895 QModelIndex parent = index.parent();
1896 QModelIndex current = parent;
1897 QModelIndex ancestor = current.parent();
1898
1899 QStyleOptionViewItem opt;
1901 QStyle::State extraFlags = QStyle::State_None;
1902 if (isEnabled())
1903 extraFlags |= QStyle::State_Enabled;
1904 if (hasFocus())
1905 extraFlags |= QStyle::State_Active;
1906 QPoint oldBO = painter->brushOrigin();
1909
1910 if (d->alternatingColors) {
1911 opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1);
1912 }
1913
1914 // When hovering over a row, pass State_Hover for painting the branch
1915 // indicators if it has the decoration (aka branch) selected.
1917 && opt.showDecorationSelected
1918 && index.parent() == d->hover.parent()
1919 && index.row() == d->hover.row();
1920
1921 if (d->selectionModel->isSelected(index))
1922 extraFlags |= QStyle::State_Selected;
1923
1924 if (level >= outer) {
1925 // start with the innermost branch
1926 primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent);
1927 opt.rect = primitive;
1928
1929 const bool expanded = viewItem.expanded;
1930 const bool children = viewItem.hasChildren;
1931 bool moreSiblings = viewItem.hasMoreSiblings;
1932
1933 opt.state = QStyle::State_Item | extraFlags
1934 | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None)
1937 opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch);
1938
1939 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
1940 }
1941 // then go out level by level
1942 for (--level; level >= outer; --level) { // we have already drawn the innermost branch
1943 primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent);
1944 opt.rect = primitive;
1945 opt.state = extraFlags;
1946 bool moreSiblings = false;
1947 if (d->hiddenIndexes.isEmpty()) {
1948 moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row());
1949 } else {
1950 int successor = item + viewItem.total + 1;
1951 while (successor < d->viewItems.size()
1952 && d->viewItems.at(successor).level >= uint(level)) {
1953 const QTreeViewItem &successorItem = d->viewItems.at(successor);
1954 if (successorItem.level == uint(level)) {
1955 moreSiblings = true;
1956 break;
1957 }
1958 successor += successorItem.total + 1;
1959 }
1960 }
1961 if (moreSiblings)
1963 opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch);
1964
1965 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
1966 current = ancestor;
1967 ancestor = current.parent();
1968 }
1969 painter->setBrushOrigin(oldBO);
1970}
1971
1976{
1977 Q_D(QTreeView);
1978 bool handled = false;
1979 if (style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, nullptr, this) == QEvent::MouseButtonPress)
1980 handled = d->expandOrCollapseItemAtPos(event->position().toPoint());
1981 if (!handled && d->itemDecorationAt(event->position().toPoint()) == -1)
1983 else
1984 d->pressedIndex = QModelIndex();
1985}
1986
1991{
1992 Q_D(QTreeView);
1993 if (d->itemDecorationAt(event->position().toPoint()) == -1) {
1995 } else {
1998 if (style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, nullptr, this) == QEvent::MouseButtonRelease)
1999 d->expandOrCollapseItemAtPos(event->position().toPoint());
2000 }
2001}
2002
2007{
2008 Q_D(QTreeView);
2009 if (state() != NoState || !d->viewport->rect().contains(event->position().toPoint()))
2010 return;
2011
2012 int i = d->itemDecorationAt(event->position().toPoint());
2013 if (i == -1) {
2014 i = d->itemAtCoordinate(event->position().toPoint().y());
2015 if (i == -1)
2016 return; // user clicked outside the items
2017
2018 const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index;
2019 const QPersistentModelIndex persistent = indexAt(event->position().toPoint());
2020
2021 if (d->pressedIndex != persistent) {
2023 return;
2024 }
2025
2026 // signal handlers may change the model
2027 emit doubleClicked(persistent);
2028
2029 if (!persistent.isValid())
2030 return;
2031
2032 if (edit(persistent, DoubleClicked, event) || state() != NoState)
2033 return; // the double click triggered editing
2034
2035 if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
2036 emit activated(persistent);
2037
2038 d->releaseFromDoubleClick = true;
2039 d->executePostedLayout(); // we need to make sure viewItems is updated
2040 if (d->itemsExpandable
2041 && d->expandsOnDoubleClick
2042 && d->hasVisibleChildren(persistent)) {
2043 if (!((i < d->viewItems.size()) && (d->viewItems.at(i).index == firstColumnIndex))) {
2044 // find the new index of the item
2045 for (i = 0; i < d->viewItems.size(); ++i) {
2046 if (d->viewItems.at(i).index == firstColumnIndex)
2047 break;
2048 }
2049 if (i == d->viewItems.size())
2050 return;
2051 }
2052 if (d->viewItems.at(i).expanded)
2053 d->collapse(i, true);
2054 else
2055 d->expand(i, true);
2057 viewport()->update();
2058 }
2059 }
2060}
2061
2066{
2067 Q_D(QTreeView);
2068 if (d->itemDecorationAt(event->position().toPoint()) == -1) // ### what about expanding/collapsing state ?
2070}
2071
2076{
2077 Q_D(QTreeView);
2078 QModelIndex current = currentIndex();
2079 //this is the management of the expansion
2080 if (d->isIndexValid(current) && d->model && d->itemsExpandable) {
2081 switch (event->key()) {
2082 case Qt::Key_Asterisk: {
2083 expandRecursively(current);
2084 break; }
2085 case Qt::Key_Plus:
2086 expand(current);
2087 break;
2088 case Qt::Key_Minus:
2089 collapse(current);
2090 break;
2091 }
2092 }
2093
2095}
2096
2101{
2102 Q_D(const QTreeView);
2103 d->executePostedLayout();
2104
2105 int visualIndex = d->itemAtCoordinate(point.y());
2106 QModelIndex idx = d->modelIndex(visualIndex);
2107 if (!idx.isValid())
2108 return QModelIndex();
2109
2110 if (d->viewItems.at(visualIndex).spanning)
2111 return idx;
2112
2113 int column = d->columnAt(point.x());
2114 if (column == idx.column())
2115 return idx;
2116 if (column < 0)
2117 return QModelIndex();
2118 return idx.sibling(idx.row(), column);
2119}
2120
2125{
2126 Q_D(const QTreeView);
2127 if (!d->isIndexValid(index))
2128 return QModelIndex();
2129 d->executePostedLayout();
2130 int i = d->viewIndex(index);
2131 if (--i < 0)
2132 return QModelIndex();
2133 const QModelIndex firstColumnIndex = d->viewItems.at(i).index;
2134 return firstColumnIndex.sibling(firstColumnIndex.row(), index.column());
2135}
2136
2141{
2142 Q_D(const QTreeView);
2143 if (!d->isIndexValid(index))
2144 return QModelIndex();
2145 d->executePostedLayout();
2146 int i = d->viewIndex(index);
2147 if (++i >= d->viewItems.size())
2148 return QModelIndex();
2149 const QModelIndex firstColumnIndex = d->viewItems.at(i).index;
2150 return firstColumnIndex.sibling(firstColumnIndex.row(), index.column());
2151}
2152
2159{
2160 Q_D(QTreeView);
2161 if (d->hasRemovedItems) {
2162 //clean the QSet that may contains old (and this invalid) indexes
2163 d->hasRemovedItems = false;
2164 QSet<QPersistentModelIndex>::iterator it = d->expandedIndexes.begin();
2165 while (it != d->expandedIndexes.end()) {
2166 if (!it->isValid())
2167 it = d->expandedIndexes.erase(it);
2168 else
2169 ++it;
2170 }
2171 it = d->hiddenIndexes.begin();
2172 while (it != d->hiddenIndexes.end()) {
2173 if (!it->isValid())
2174 it = d->hiddenIndexes.erase(it);
2175 else
2176 ++it;
2177 }
2178 }
2179 d->viewItems.clear(); // prepare for new layout
2180 QModelIndex parent = d->root;
2181 if (d->model->hasChildren(parent)) {
2182 d->layout(-1);
2183 }
2185 d->header->doItemsLayout();
2186 d->updateAccessibility();
2187}
2188
2193{
2194 Q_D(QTreeView);
2195 d->expandedIndexes.clear();
2196 d->hiddenIndexes.clear();
2197 d->spanningIndexes.clear();
2198 d->viewItems.clear();
2200}
2201
2211{
2212 Q_D(const QTreeView);
2213 return d->header->offset();
2214}
2215
2222{
2223 Q_D(const QTreeView);
2224 if (d->verticalScrollMode == QAbstractItemView::ScrollPerItem) {
2225 if (d->uniformRowHeights)
2226 return verticalScrollBar()->value() * d->defaultItemHeight;
2227 // If we are scrolling per item and have non-uniform row heights,
2228 // finding the vertical offset in pixels is going to be relatively slow.
2229 // ### find a faster way to do this
2230 d->executePostedLayout();
2231 int offset = 0;
2232 const int cnt = qMin(d->viewItems.size(), verticalScrollBar()->value());
2233 for (int i = 0; i < cnt; ++i)
2234 offset += d->itemHeight(i);
2235 return offset;
2236 }
2237 // scroll per pixel
2238 return verticalScrollBar()->value();
2239}
2240
2245QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
2246{
2247 Q_D(QTreeView);
2249
2250 d->executePostedLayout();
2251
2252 QModelIndex current = currentIndex();
2253 if (!current.isValid()) {
2254 int i = d->below(-1);
2255 int c = 0;
2256 while (c < d->header->count() && d->header->isSectionHidden(d->header->logicalIndex(c)))
2257 ++c;
2258 if (i < d->viewItems.size() && c < d->header->count()) {
2259 return d->modelIndex(i, d->header->logicalIndex(c));
2260 }
2261 return QModelIndex();
2262 }
2263
2264 const int vi = qMax(0, d->viewIndex(current));
2265
2266 if (isRightToLeft()) {
2267 if (cursorAction == MoveRight)
2268 cursorAction = MoveLeft;
2269 else if (cursorAction == MoveLeft)
2270 cursorAction = MoveRight;
2271 }
2272 switch (cursorAction) {
2273 case MoveNext:
2274 case MoveDown:
2275#ifdef QT_KEYPAD_NAVIGATION
2276 if (vi == d->viewItems.count()-1 && QApplicationPrivate::keypadNavigationEnabled())
2277 return d->model->index(0, current.column(), d->root);
2278#endif
2279 return d->modelIndex(d->below(vi), current.column());
2280 case MovePrevious:
2281 case MoveUp:
2282#ifdef QT_KEYPAD_NAVIGATION
2283 if (vi == 0 && QApplicationPrivate::keypadNavigationEnabled())
2284 return d->modelIndex(d->viewItems.count() - 1, current.column());
2285#endif
2286 return d->modelIndex(d->above(vi), current.column());
2287 case MoveLeft: {
2288 QScrollBar *sb = horizontalScrollBar();
2289 if (vi < d->viewItems.size() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum()) {
2290 d->collapse(vi, true);
2291 d->moveCursorUpdatedView = true;
2292 } else {
2293 bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, nullptr, this);
2294 if (descend) {
2295 QModelIndex par = current.parent();
2296 if (par.isValid() && par != rootIndex())
2297 return par;
2298 else
2299 descend = false;
2300 }
2301 if (!descend) {
2302 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
2303 int visualColumn = d->header->visualIndex(current.column()) - 1;
2304 while (visualColumn >= 0 && isColumnHidden(d->header->logicalIndex(visualColumn)))
2305 visualColumn--;
2306 int newColumn = d->header->logicalIndex(visualColumn);
2307 QModelIndex next = current.sibling(current.row(), newColumn);
2308 if (next.isValid())
2309 return next;
2310 }
2311
2312 int oldValue = sb->value();
2313 sb->setValue(sb->value() - sb->singleStep());
2314 if (oldValue != sb->value())
2315 d->moveCursorUpdatedView = true;
2316 }
2317
2318 }
2320 viewport()->update();
2321 break;
2322 }
2323 case MoveRight:
2324 if (vi < d->viewItems.size() && !d->viewItems.at(vi).expanded && d->itemsExpandable
2325 && d->hasVisibleChildren(d->viewItems.at(vi).index)) {
2326 d->expand(vi, true);
2327 d->moveCursorUpdatedView = true;
2328 } else {
2329 bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, nullptr, this);
2330 if (descend) {
2331 QModelIndex idx = d->modelIndex(d->below(vi));
2332 if (idx.parent() == current)
2333 return idx;
2334 else
2335 descend = false;
2336 }
2337 if (!descend) {
2338 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
2339 int visualColumn = d->header->visualIndex(current.column()) + 1;
2340 while (visualColumn < d->model->columnCount(current.parent()) && isColumnHidden(d->header->logicalIndex(visualColumn)))
2341 visualColumn++;
2342 const int newColumn = d->header->logicalIndex(visualColumn);
2343 const QModelIndex next = current.sibling(current.row(), newColumn);
2344 if (next.isValid())
2345 return next;
2346 }
2347
2348 //last restort: we change the scrollbar value
2349 QScrollBar *sb = horizontalScrollBar();
2350 int oldValue = sb->value();
2351 sb->setValue(sb->value() + sb->singleStep());
2352 if (oldValue != sb->value())
2353 d->moveCursorUpdatedView = true;
2354 }
2355 }
2357 viewport()->update();
2358 break;
2359 case MovePageUp:
2360 return d->modelIndex(d->pageUp(vi), current.column());
2361 case MovePageDown:
2362 return d->modelIndex(d->pageDown(vi), current.column());
2363 case MoveHome:
2364 return d->modelIndex(d->itemForKeyHome(), current.column());
2365 case MoveEnd:
2366 return d->modelIndex(d->itemForKeyEnd(), current.column());
2367 }
2368 return current;
2369}
2370
2377void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
2378{
2379 Q_D(QTreeView);
2380 if (!selectionModel() || rect.isNull())
2381 return;
2382
2383 d->executePostedLayout();
2384 QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right())
2385 : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom()));
2386 QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) :
2387 qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom()));
2388 QModelIndex topLeft = indexAt(tl);
2389 QModelIndex bottomRight = indexAt(br);
2390 if (!topLeft.isValid() && !bottomRight.isValid()) {
2391 if (command & QItemSelectionModel::Clear)
2392 selectionModel()->clear();
2393 return;
2394 }
2395 if (!topLeft.isValid() && !d->viewItems.isEmpty())
2396 topLeft = d->viewItems.constFirst().index;
2397 if (!bottomRight.isValid() && !d->viewItems.isEmpty()) {
2398 const int column = d->header->logicalIndex(d->header->count() - 1);
2399 const QModelIndex index = d->viewItems.constLast().index;
2400 bottomRight = index.sibling(index.row(), column);
2401 }
2402
2403 if (!d->isIndexEnabled(topLeft) || !d->isIndexEnabled(bottomRight))
2404 return;
2405
2406 d->select(topLeft, bottomRight, command);
2407}
2408
2417{
2418 Q_D(const QTreeView);
2419 if (selection.isEmpty())
2420 return QRegion();
2421
2422 QRegion selectionRegion;
2423 const QRect &viewportRect = d->viewport->rect();
2424 for (const auto &range : selection) {
2425 if (!range.isValid())
2426 continue;
2427 QModelIndex parent = range.parent();
2428 QModelIndex leftIndex = range.topLeft();
2429 int columnCount = d->model->columnCount(parent);
2430 while (leftIndex.isValid() && isIndexHidden(leftIndex)) {
2431 if (leftIndex.column() + 1 < columnCount)
2432 leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent);
2433 else
2434 leftIndex = QModelIndex();
2435 }
2436 if (!leftIndex.isValid())
2437 continue;
2438 const QRect leftRect = d->visualRect(leftIndex, QTreeViewPrivate::SingleSection);
2439 int top = leftRect.top();
2440 QModelIndex rightIndex = range.bottomRight();
2441 while (rightIndex.isValid() && isIndexHidden(rightIndex)) {
2442 if (rightIndex.column() - 1 >= 0)
2443 rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent);
2444 else
2445 rightIndex = QModelIndex();
2446 }
2447 if (!rightIndex.isValid())
2448 continue;
2449 const QRect rightRect = d->visualRect(rightIndex, QTreeViewPrivate::SingleSection);
2450 int bottom = rightRect.bottom();
2451 if (top > bottom)
2452 qSwap<int>(top, bottom);
2453 int height = bottom - top + 1;
2454 if (d->header->sectionsMoved()) {
2455 for (int c = range.left(); c <= range.right(); ++c) {
2456 const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height);
2457 if (viewportRect.intersects(rangeRect))
2458 selectionRegion += rangeRect;
2459 }
2460 } else {
2461 QRect combined = leftRect|rightRect;
2462 combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
2463 if (viewportRect.intersects(combined))
2464 selectionRegion += combined;
2465 }
2466 }
2467 return selectionRegion;
2468}
2469
2474{
2475 QModelIndexList viewSelected;
2476 QModelIndexList modelSelected;
2477 if (selectionModel())
2478 modelSelected = selectionModel()->selectedIndexes();
2479 for (int i = 0; i < modelSelected.size(); ++i) {
2480 // check that neither the parents nor the index is hidden before we add
2481 QModelIndex index = modelSelected.at(i);
2482 while (index.isValid() && !isIndexHidden(index))
2483 index = index.parent();
2484 if (index.isValid())
2485 continue;
2486 viewSelected.append(modelSelected.at(i));
2487 }
2488 return viewSelected;
2489}
2490
2495{
2496 Q_D(QTreeView);
2497
2498 d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
2499
2500 dx = isRightToLeft() ? -dx : dx;
2501 if (dx) {
2502 int oldOffset = d->header->offset();
2503 d->header->d_func()->setScrollOffset(horizontalScrollBar(), horizontalScrollMode());
2505 int newOffset = d->header->offset();
2506 dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
2507 }
2508 }
2509
2510 const int itemHeight = d->defaultItemHeight <= 0 ? sizeHintForRow(0) : d->defaultItemHeight;
2511 if (d->viewItems.isEmpty() || itemHeight == 0)
2512 return;
2513
2514 // guestimate the number of items in the viewport
2515 int viewCount = d->viewport->height() / itemHeight;
2516 int maxDeltaY = qMin(d->viewItems.size(), viewCount);
2517 // no need to do a lot of work if we are going to redraw the whole thing anyway
2518 if (qAbs(dy) > qAbs(maxDeltaY) && d->editorIndexHash.isEmpty()) {
2519 verticalScrollBar()->update();
2520 d->viewport->update();
2521 return;
2522 }
2523
2525 int currentScrollbarValue = verticalScrollBar()->value();
2526 int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy)
2527 int currentViewIndex = currentScrollbarValue; // the first visible item
2528 int previousViewIndex = previousScrollbarValue;
2529 dy = 0;
2530 if (previousViewIndex < currentViewIndex) { // scrolling down
2531 for (int i = previousViewIndex; i < currentViewIndex; ++i) {
2532 if (i < d->viewItems.size())
2533 dy -= d->itemHeight(i);
2534 }
2535 } else if (previousViewIndex > currentViewIndex) { // scrolling up
2536 for (int i = previousViewIndex - 1; i >= currentViewIndex; --i) {
2537 if (i < d->viewItems.size())
2538 dy += d->itemHeight(i);
2539 }
2540 }
2541 }
2542
2543 d->scrollContentsBy(dx, dy);
2544}
2545
2550{
2551 Q_D(QTreeView);
2553 d->viewport->update();
2554}
2555
2560{
2561 // do nothing
2562}
2563
2568void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
2569{
2570 Q_D(QTreeView);
2571 // if we are going to do a complete relayout anyway, there is no need to update
2572 if (d->delayedPendingLayout) {
2574 return;
2575 }
2576
2577 //don't add a hierarchy on a column != 0
2578 if (parent.column() != 0 && parent.isValid()) {
2580 return;
2581 }
2582
2583 const int parentRowCount = d->model->rowCount(parent);
2584 const int delta = end - start + 1;
2585 if (parent != d->root && !d->isIndexExpanded(parent) && parentRowCount > delta) {
2587 return;
2588 }
2589
2590 const int parentItem = d->viewIndex(parent);
2591 if (((parentItem != -1) && d->viewItems.at(parentItem).expanded)
2592 || (parent == d->root)) {
2593 d->doDelayedItemsLayout();
2594 } else if (parentItem != -1 && parentRowCount == delta) {
2595 // the parent just went from 0 children to more. update to re-paint the decoration
2596 d->viewItems[parentItem].hasChildren = true;
2597 viewport()->update();
2598 }
2600}
2601
2607{
2608 Q_D(QTreeView);
2610 d->viewItems.clear();
2611}
2612
2619void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
2620{
2621 Q_D(QTreeView);
2622 d->viewItems.clear();
2623 d->doDelayedItemsLayout();
2624 d->hasRemovedItems = true;
2625 d->rowsRemoved(parent, start, end);
2626}
2627
2632void QTreeView::columnCountChanged(int oldCount, int newCount)
2633{
2634 Q_D(QTreeView);
2635 if (oldCount == 0 && newCount > 0) {
2636 //if the first column has just been added we need to relayout.
2637 d->doDelayedItemsLayout();
2638 }
2639
2640 if (isVisible())
2642 viewport()->update();
2643}
2644
2651{
2652 Q_D(QTreeView);
2653 d->executePostedLayout();
2654 if (column < 0 || column >= d->header->count())
2655 return;
2657 int header = d->header->isHidden() ? 0 : d->header->sectionSizeHint(column);
2658 d->header->resizeSection(column, qMax(contents, header));
2659}
2660
2673{
2674 Q_D(QTreeView);
2675 if (column < -1)
2676 return;
2677 d->header->setSortIndicator(column, order);
2678 // If sorting is not enabled or has the same order as before, force to sort now
2679 // else sorting will be trigger through sortIndicatorChanged()
2680 if (!d->sortingEnabled ||
2681 (d->header->sortIndicatorSection() == column && d->header->sortIndicatorOrder() == order))
2682 d->model->sort(column, order);
2683}
2684
2689{
2690 Q_D(QTreeView);
2691 if (!selectionModel())
2692 return;
2693 SelectionMode mode = d->selectionMode;
2694 d->executePostedLayout(); //make sure we lay out the items
2695 if (mode != SingleSelection && mode != NoSelection && !d->viewItems.isEmpty()) {
2696 const QModelIndex &idx = d->viewItems.constLast().index;
2697 QModelIndex lastItemIndex = idx.sibling(idx.row(), d->model->columnCount(idx.parent()) - 1);
2698 d->select(d->viewItems.constFirst().index, lastItemIndex,
2701 }
2702}
2703
2708{
2709 Q_D(const QTreeView);
2710 d->executePostedLayout(); // Make sure that viewItems are up to date.
2711
2712 if (d->viewItems.size() == 0)
2714
2715 // Get rect for last item
2716 const QRect deepestRect = d->visualRect(d->viewItems.last().index,
2718
2719 if (!deepestRect.isValid())
2721
2722 QSize result = QSize(d->header->length(), deepestRect.bottom() + 1);
2723
2724 // add size for header
2725 result += QSize(0, d->header->isHidden() ? 0 : d->header->height());
2726
2727 return result;
2728}
2729
2743{
2744 Q_D(QTreeView);
2745 d->viewItems.clear();
2746 d->interruptDelayedItemsLayout();
2747 d->layout(-1, true);
2749 d->viewport->update();
2750 d->updateAccessibility();
2751}
2752
2769{
2770 Q_D(QTreeView);
2771
2772 if (depth < -1)
2773 return;
2774 // do layouting only once after expanding is done
2775 d->doDelayedItemsLayout();
2776 expand(index);
2777 if (depth == 0)
2778 return;
2779 QStack<QPair<QModelIndex, int>> parents;
2780 parents.push({index, 0});
2781 while (!parents.isEmpty()) {
2782 const QPair<QModelIndex, int> elem = parents.pop();
2783 const QModelIndex &parent = elem.first;
2784 const int curDepth = elem.second;
2785 const int rowCount = d->model->rowCount(parent);
2786 for (int row = 0; row < rowCount; ++row) {
2787 const QModelIndex child = d->model->index(row, 0, parent);
2788 if (!d->isIndexValid(child))
2789 break;
2790 if (depth == -1 || curDepth + 1 < depth)
2791 parents.push({child, curDepth + 1});
2792 if (d->isIndexExpanded(child))
2793 continue;
2794 if (d->storeExpanded(child))
2796 }
2797 }
2798}
2799
2808{
2809 Q_D(QTreeView);
2810 QSet<QPersistentModelIndex> old_expandedIndexes;
2811 old_expandedIndexes = d->expandedIndexes;
2812 d->expandedIndexes.clear();
2813 if (!signalsBlocked() && isSignalConnected(QMetaMethod::fromSignal(&QTreeView::collapsed))) {
2814 QSet<QPersistentModelIndex>::const_iterator i = old_expandedIndexes.constBegin();
2815 for (; i != old_expandedIndexes.constEnd(); ++i) {
2816 const QPersistentModelIndex &mi = (*i);
2817 if (mi.isValid() && !(mi.flags() & Qt::ItemNeverHasChildren))
2818 emit collapsed(mi);
2819 }
2820 }
2821 doItemsLayout();
2822}
2823
2834{
2835 Q_D(QTreeView);
2836 d->viewItems.clear();
2837 QSet<QPersistentModelIndex> old_expandedIndexes;
2838 old_expandedIndexes = d->expandedIndexes;
2839 d->expandedIndexes.clear();
2840 d->interruptDelayedItemsLayout();
2841 d->layout(-1);
2842 for (int i = 0; i < d->viewItems.size(); ++i) {
2843 if (d->viewItems.at(i).level <= (uint)depth) {
2844 d->viewItems[i].expanded = true;
2845 d->layout(i);
2846 d->storeExpanded(d->viewItems.at(i).index);
2847 }
2848 }
2849
2850 bool someSignalEnabled = isSignalConnected(QMetaMethod::fromSignal(&QTreeView::collapsed));
2851 someSignalEnabled |= isSignalConnected(QMetaMethod::fromSignal(&QTreeView::expanded));
2852
2853 if (!signalsBlocked() && someSignalEnabled) {
2854 // emit signals
2855 QSet<QPersistentModelIndex> collapsedIndexes = old_expandedIndexes - d->expandedIndexes;
2856 QSet<QPersistentModelIndex>::const_iterator i = collapsedIndexes.constBegin();
2857 for (; i != collapsedIndexes.constEnd(); ++i) {
2858 const QPersistentModelIndex &mi = (*i);
2859 if (mi.isValid() && !(mi.flags() & Qt::ItemNeverHasChildren))
2860 emit collapsed(mi);
2861 }
2862
2863 QSet<QPersistentModelIndex> expandedIndexs = d->expandedIndexes - old_expandedIndexes;
2864 i = expandedIndexs.constBegin();
2865 for (; i != expandedIndexs.constEnd(); ++i) {
2866 const QPersistentModelIndex &mi = (*i);
2867 if (mi.isValid() && !(mi.flags() & Qt::ItemNeverHasChildren))
2868 emit expanded(mi);
2869 }
2870 }
2871
2873 d->viewport->update();
2874 d->updateAccessibility();
2875}
2876
2884void QTreeView::columnResized(int column, int /* oldSize */, int /* newSize */)
2885{
2886 Q_D(QTreeView);
2887 d->columnsToUpdate.append(column);
2888 if (d->columnResizeTimerID == 0)
2889 d->columnResizeTimerID = startTimer(0);
2890}
2891
2896{
2897 Q_D(QTreeView);
2898 if (d->header) {
2899 if (d->geometryRecursionBlock)
2900 return;
2901 d->geometryRecursionBlock = true;
2902 int height = 0;
2903 if (!d->header->isHidden()) {
2904 height = qMax(d->header->minimumHeight(), d->header->sizeHint().height());
2905 height = qMin(height, d->header->maximumHeight());
2906 }
2907 setViewportMargins(0, height, 0, 0);
2908 QRect vg = d->viewport->geometry();
2909 QRect geometryRect(vg.left(), vg.top() - height, vg.width(), height);
2910 d->header->setGeometry(geometryRect);
2911 QMetaObject::invokeMethod(d->header, "updateGeometries");
2912 d->updateScrollBars();
2913 d->geometryRecursionBlock = false;
2914 }
2916}
2917
2933{
2934 Q_D(const QTreeView);
2935 d->executePostedLayout();
2936 if (d->viewItems.isEmpty())
2937 return -1;
2938 ensurePolished();
2939 int w = 0;
2940 QStyleOptionViewItem option;
2942 const QList<QTreeViewItem> viewItems = d->viewItems;
2943
2944 const int maximumProcessRows = d->header->resizeContentsPrecision(); // To avoid this to take forever.
2945
2946 int offset = 0;
2947 int start = d->firstVisibleItem(&offset);
2948 int end = d->lastVisibleItem(start, offset);
2949 if (start < 0 || end < 0 || end == viewItems.size() - 1) {
2950 end = viewItems.size() - 1;
2951 if (maximumProcessRows < 0) {
2952 start = 0;
2953 } else if (maximumProcessRows == 0) {
2954 start = qMax(0, end - 1);
2955 int remainingHeight = viewport()->height();
2956 while (start > 0 && remainingHeight > 0) {
2957 remainingHeight -= d->itemHeight(start);
2958 --start;
2959 }
2960 } else {
2961 start = qMax(0, end - maximumProcessRows);
2962 }
2963 }
2964
2965 int rowsProcessed = 0;
2966
2967 for (int i = start; i <= end; ++i) {
2968 if (viewItems.at(i).spanning)
2969 continue; // we have no good size hint
2970 QModelIndex index = viewItems.at(i).index;
2971 index = index.sibling(index.row(), column);
2972 w = d->widthHintForIndex(index, w, option, i);
2973 ++rowsProcessed;
2974 if (rowsProcessed == maximumProcessRows)
2975 break;
2976 }
2977
2978 --end;
2979 int actualBottom = viewItems.size() - 1;
2980
2981 if (maximumProcessRows == 0)
2982 rowsProcessed = 0; // skip the while loop
2983
2984 while (rowsProcessed != maximumProcessRows && (start > 0 || end < actualBottom)) {
2985 int idx = -1;
2986
2987 if ((rowsProcessed % 2 && start > 0) || end == actualBottom) {
2988 while (start > 0) {
2989 --start;
2990 if (viewItems.at(start).spanning)
2991 continue;
2992 idx = start;
2993 break;
2994 }
2995 } else {
2996 while (end < actualBottom) {
2997 ++end;
2998 if (viewItems.at(end).spanning)
2999 continue;
3000 idx = end;
3001 break;
3002 }
3003 }
3004 if (idx < 0)
3005 continue;
3006
3007 QModelIndex index = viewItems.at(idx).index;
3008 index = index.sibling(index.row(), column);
3009 w = d->widthHintForIndex(index, w, option, idx);
3010 ++rowsProcessed;
3011 }
3012 return w;
3013}
3014
3021{
3022 Q_D(const QTreeView);
3023 if (!d->isIndexValid(index) || !d->itemDelegate)
3024 return 0;
3025
3026 int start = -1;
3027 int end = -1;
3028 int indexRow = index.row();
3029 int count = d->header->count();
3030 bool emptyHeader = (count == 0);
3031 QModelIndex parent = index.parent();
3032
3033 if (count && isVisible()) {
3034 // If the sections have moved, we end up checking too many or too few
3035 start = d->header->visualIndexAt(0);
3036 } else {
3037 // If the header has not been laid out yet, we use the model directly
3038 count = d->model->columnCount(parent);
3039 }
3040
3041 if (isRightToLeft()) {
3042 start = (start == -1 ? count - 1 : start);
3043 end = 0;
3044 } else {
3045 start = (start == -1 ? 0 : start);
3046 end = count - 1;
3047 }
3048
3049 if (end < start)
3050 qSwap(end, start);
3051
3052 int height = -1;
3053 QStyleOptionViewItem option;
3055 // ### If we want word wrapping in the items,
3056 // ### we need to go through all the columns
3057 // ### and set the width of the column
3058
3059 // Hack to speed up the function
3060 option.rect.setWidth(-1);
3061
3062 for (int column = start; column <= end; ++column) {
3063 int logicalColumn = emptyHeader ? column : d->header->logicalIndex(column);
3064 if (d->header->isSectionHidden(logicalColumn))
3065 continue;
3066 QModelIndex idx = d->model->index(indexRow, logicalColumn, parent);
3067 if (idx.isValid()) {
3068 QWidget *editor = d->editorForIndex(idx).widget.data();
3069 if (editor && d->persistent.contains(editor)) {
3070 height = qMax(height, editor->sizeHint().height());
3071 int min = editor->minimumSize().height();
3072 int max = editor->maximumSize().height();
3073 height = qBound(min, height, max);
3074 }
3075 int hint = itemDelegateForIndex(idx)->sizeHint(option, idx).height();
3076 height = qMax(height, hint);
3077 }
3078 }
3079
3080 return height;
3081}
3082
3089{
3090 Q_D(const QTreeView);
3091 d->executePostedLayout();
3092 int i = d->viewIndex(index);
3093 if (i == -1)
3094 return 0;
3095 return d->itemHeight(i);
3096}
3097
3105
3110{
3111 return (isColumnHidden(index.column()) || isRowHidden(index.row(), index.parent()));
3112}
3113
3114/*
3115 private implementation
3116*/
3118{
3119 Q_Q(QTreeView);
3120
3122 updateStyledFrameWidths();
3123 q->setSelectionBehavior(QAbstractItemView::SelectRows);
3124 q->setSelectionMode(QAbstractItemView::SingleSelection);
3125 q->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
3126 q->setAttribute(Qt::WA_MacShowFocusRect);
3127
3132 q->setHeader(header);
3133#if QT_CONFIG(animation)
3134 animationsEnabled = q->style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, q) > 0;
3137 this, &QTreeViewPrivate::endAnimatedOperation);
3138#endif // animation
3139}
3140
3153
3154void QTreeViewPrivate::expand(int item, bool emitSignal)
3155{
3156 Q_Q(QTreeView);
3157
3158 if (item == -1 || viewItems.at(item).expanded)
3159 return;
3161 if (index.flags() & Qt::ItemNeverHasChildren)
3162 return;
3163
3164#if QT_CONFIG(animation)
3165 if (emitSignal && animationsEnabled)
3166 prepareAnimatedOperation(item, QVariantAnimation::Forward);
3167#endif // animation
3168 //if already animating, stateBeforeAnimation is set to the correct value
3173 viewItems[item].expanded = true;
3174 layout(item);
3175 q->setState(stateBeforeAnimation);
3176
3177 if (model->canFetchMore(index))
3179 if (emitSignal) {
3180 emit q->expanded(index);
3181#if QT_CONFIG(animation)
3183 beginAnimatedOperation();
3184#endif // animation
3185 }
3187}
3188
3190{
3191 viewItems.insert(pos, count, viewItem);
3193 for (int i = pos + count; i < viewItems.size(); i++)
3194 if (items[i].parentItem >= pos)
3195 items[i].parentItem += count;
3196}
3197
3199{
3202 for (int i = pos; i < viewItems.size(); i++)
3203 if (items[i].parentItem >= pos)
3204 items[i].parentItem -= count;
3205}
3206
3207#if 0
3208bool QTreeViewPrivate::checkViewItems() const
3209{
3210 for (int i = 0; i < viewItems.count(); ++i) {
3211 const QTreeViewItem &vi = viewItems.at(i);
3212 if (vi.parentItem == -1) {
3213 Q_ASSERT(!vi.index.parent().isValid() || vi.index.parent() == root);
3214 } else {
3216 }
3217 }
3218 return true;
3219}
3220#endif
3221
3222void QTreeViewPrivate::collapse(int item, bool emitSignal)
3223{
3224 Q_Q(QTreeView);
3225
3226 if (item == -1 || expandedIndexes.isEmpty())
3227 return;
3228
3229 //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
3231
3232 int total = viewItems.at(item).total;
3235 return; // if the index is not persistent, no chances it is expanded
3237 if (it == expandedIndexes.end() || viewItems.at(item).expanded == false)
3238 return; // nothing to do
3239
3240#if QT_CONFIG(animation)
3241 if (emitSignal && animationsEnabled)
3242 prepareAnimatedOperation(item, QVariantAnimation::Backward);
3243#endif // animation
3244
3245 //if already animating, stateBeforeAnimation is set to the correct value
3250 viewItems[item].expanded = false;
3251 int index = item;
3252 while (index > -1) {
3253 viewItems[index].total -= total;
3254 index = viewItems[index].parentItem;
3255 }
3256 removeViewItems(item + 1, total); // collapse
3257 q->setState(stateBeforeAnimation);
3258
3259 if (emitSignal) {
3260 emit q->collapsed(modelIndex);
3261#if QT_CONFIG(animation)
3263 beginAnimatedOperation();
3264#endif // animation
3265 }
3266}
3267
3268#if QT_CONFIG(animation)
3269void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction)
3270{
3271 animatedOperation.item = item;
3272 animatedOperation.viewport = viewport;
3273 animatedOperation.setDirection(direction);
3274
3276 QRect rect = viewport->rect();
3277 rect.setTop(top);
3279 const int limit = rect.height() * 2;
3280 int h = 0;
3281 int c = item + viewItems.at(item).total + 1;
3282 for (int i = item + 1; i < c && h < limit; ++i)
3283 h += itemHeight(i);
3284 rect.setHeight(h);
3285 animatedOperation.setEndValue(top + h);
3286 }
3287 animatedOperation.setStartValue(top);
3288 animatedOperation.before = renderTreeToPixmapForAnimation(rect);
3289}
3290
3291void QTreeViewPrivate::beginAnimatedOperation()
3292{
3293 Q_Q(QTreeView);
3294
3295 QRect rect = viewport->rect();
3296 rect.setTop(animatedOperation.top());
3297 if (animatedOperation.direction() == QVariantAnimation::Forward) {
3298 const int limit = rect.height() * 2;
3299 int h = 0;
3300 int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1;
3301 for (int i = animatedOperation.item + 1; i < c && h < limit; ++i)
3302 h += itemHeight(i);
3303 rect.setHeight(h);
3304 animatedOperation.setEndValue(animatedOperation.top() + h);
3305 }
3306
3307 if (!rect.isEmpty()) {
3308 animatedOperation.after = renderTreeToPixmapForAnimation(rect);
3309
3311 animatedOperation.start(); //let's start the animation
3312 }
3313}
3314
3315void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const
3316{
3317 const int start = animatedOperation.startValue().toInt(),
3318 end = animatedOperation.endValue().toInt(),
3319 current = animatedOperation.currentValue().toInt();
3320 bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward;
3321 const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after;
3322 painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height());
3323 const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before;
3325}
3326
3327QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) const
3328{
3329 Q_Q(const QTreeView);
3330 QPixmap pixmap(rect.size() * q->devicePixelRatio());
3331 pixmap.setDevicePixelRatio(q->devicePixelRatio());
3332 if (rect.size().isEmpty())
3333 return pixmap;
3334 pixmap.fill(Qt::transparent); //the base might not be opaque, and we don't want uninitialized pixels.
3336 painter.fillRect(QRect(QPoint(0,0), rect.size()), q->palette().base());
3337 painter.translate(0, -rect.top());
3338 q->drawTree(&painter, QRegion(rect));
3339 painter.end();
3340
3341 //and now let's render the editors the editors
3342 QStyleOptionViewItem option;
3343 q->initViewItemOption(&option);
3345 QWidget *editor = it.key();
3346 const QModelIndex &index = it.value();
3348 if (option.rect.isValid()) {
3349
3350 if (QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index))
3351 delegate->updateEditorGeometry(editor, option, index);
3352
3353 const QPoint pos = editor->pos();
3354 if (rect.contains(pos)) {
3355 editor->render(&pixmap, pos - rect.topLeft());
3356 //the animation uses pixmap to display the treeview's content
3357 //the editor is rendered on this pixmap and thus can (should) be hidden
3358 editor->hide();
3359 }
3360 }
3361 }
3362
3363
3364 return pixmap;
3365}
3366
3367void QTreeViewPrivate::endAnimatedOperation()
3368{
3369 Q_Q(QTreeView);
3370 q->setState(stateBeforeAnimation);
3371 q->updateGeometries();
3372 viewport->update();
3373}
3374#endif // animation
3375
3380
3382{
3383 if (start <= 0 && 0 <= end)
3384 viewItems.clear();
3386}
3387
3389{
3390 if (start <= 0 && 0 <= end)
3393}
3394
3396{
3397#if QT_CONFIG(accessibility)
3398 Q_Q(QTreeView);
3399 if (pendingAccessibilityUpdate) {
3400 pendingAccessibilityUpdate = false;
3401 if (QAccessible::isActive()) {
3402 QAccessibleTableModelChangeEvent event(q, QAccessibleTableModelChangeEvent::ModelReset);
3403 QAccessible::updateAccessibility(&event);
3404 }
3405 }
3406#endif
3407}
3408
3409
3417void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninitialized)
3418{
3419 Q_Q(QTreeView);
3421 QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
3422
3423 if (i>=0 && !parent.isValid()) {
3424 //modelIndex() should never return something invalid for the real items.
3425 //This can happen if columncount has been set to 0.
3426 //To avoid infinite loop we stop here.
3427 return;
3428 }
3429
3430#if QT_CONFIG(accessibility)
3431 // QAccessibleTree's rowCount implementation uses viewItems.size(), so
3432 // we need to invalidate any cached accessibility data structures if
3433 // that value changes during the run of this function.
3434 const auto resetModelIfNeeded = qScopeGuard([oldViewItemsSize = viewItems.size(), this]{
3435 pendingAccessibilityUpdate |= oldViewItemsSize != viewItems.size();
3436 });
3437#endif
3438
3439 int count = 0;
3440 if (model->hasChildren(parent)) {
3441 if (model->canFetchMore(parent)) {
3442 // fetchMore first, otherwise we might not yet have any data for sizeHintForRow
3443 model->fetchMore(parent);
3444 // guestimate the number of items in the viewport, and fetch as many as might fit
3445 const int itemHeight = defaultItemHeight <= 0 ? q->sizeHintForRow(0) : defaultItemHeight;
3446 const int viewCount = itemHeight ? viewport->height() / itemHeight : 0;
3447 int lastCount = -1;
3448 while ((count = model->rowCount(parent)) < viewCount &&
3449 count != lastCount && model->canFetchMore(parent)) {
3450 model->fetchMore(parent);
3451 lastCount = count;
3452 }
3453 } else {
3454 count = model->rowCount(parent);
3455 }
3456 }
3457
3458 bool expanding = true;
3459 if (i == -1) {
3460 if (uniformRowHeights) {
3461 QModelIndex index = model->index(0, 0, parent);
3462 defaultItemHeight = q->indexRowSizeHint(index);
3463 }
3465 afterIsUninitialized = true;
3466 } else if (viewItems[i].total != (uint)count) {
3467 if (!afterIsUninitialized)
3468 insertViewItems(i + 1, count, QTreeViewItem()); // expand
3469 else if (count > 0)
3471 } else {
3472 expanding = false;
3473 }
3474
3475 int first = i + 1;
3476 int level = (i >= 0 ? viewItems.at(i).level + 1 : 0);
3477 int hidden = 0;
3478 int last = 0;
3479 int children = 0;
3480 QTreeViewItem *item = nullptr;
3481 for (int j = first; j < first + count; ++j) {
3482 current = model->index(j - first, 0, parent);
3483 if (isRowHidden(current)) {
3484 ++hidden;
3485 last = j - hidden + children;
3486 } else {
3487 last = j - hidden + children;
3488 if (item)
3489 item->hasMoreSiblings = true;
3490 item = &viewItems[last];
3491 item->index = current;
3492 item->parentItem = i;
3493 item->level = level;
3494 item->height = 0;
3495 item->spanning = q->isFirstColumnSpanned(current.row(), parent);
3496 item->expanded = false;
3497 item->total = 0;
3498 item->hasMoreSiblings = false;
3499 if ((recursiveExpanding && !(current.flags() & Qt::ItemNeverHasChildren)) || isIndexExpanded(current)) {
3500 if (recursiveExpanding && storeExpanded(current) && !q->signalsBlocked())
3501 emit q->expanded(current);
3502 item->expanded = true;
3503 layout(last, recursiveExpanding, afterIsUninitialized);
3504 item = &viewItems[last];
3505 children += item->total;
3506 item->hasChildren = item->total > 0;
3507 last = j - hidden + children;
3508 } else {
3509 item->hasChildren = hasVisibleChildren(current);
3510 }
3511 }
3512 }
3513
3514 // remove hidden items
3515 if (hidden > 0) {
3516 if (!afterIsUninitialized)
3517 removeViewItems(last + 1, hidden);
3518 else
3519 viewItems.resize(viewItems.size() - hidden);
3520 }
3521
3522 if (!expanding)
3523 return; // nothing changed
3524
3525 while (i > -1) {
3526 viewItems[i].total += count - hidden;
3527 i = viewItems[i].parentItem;
3528 }
3529}
3530
3532{
3535 index--;
3536 if (index == -1)
3537 index = 0;
3539 index++;
3540 return index >= viewItems.size() ? 0 : index;
3541}
3542
3544{
3547 index++;
3548 if (index == -1 || index >= viewItems.size())
3549 index = viewItems.size() - 1;
3551 index--;
3552 return index == -1 ? viewItems.size() - 1 : index;
3553}
3554
3556{
3557 int index = 0;
3559 index++;
3560 return index >= viewItems.size() ? 0 : index;
3561}
3562
3564{
3565 int index = viewItems.size() - 1;
3567 index--;
3568 return index == -1 ? viewItems.size() - 1 : index;
3569}
3570
3572{
3573 if (item < 0 || item >= viewItems.size())
3574 return 0;
3575 int level = viewItems.at(item).level;
3576 if (rootDecoration)
3577 ++level;
3578 return level * indent;
3579}
3580
3582{
3585 return defaultItemHeight;
3586 if (viewItems.isEmpty())
3587 return 0;
3589 if (!index.isValid())
3590 return 0;
3591 int height = viewItems.at(item).height;
3592 if (height <= 0) {
3593 height = q_func()->indexRowSizeHint(index);
3594 viewItems[item].height = height;
3595 }
3596 return qMax(height, 0);
3597}
3598
3599
3605{
3608 return (item * defaultItemHeight) - vbar->value();
3609 // ### optimize (maybe do like QHeaderView by letting items have startposition)
3610 int y = 0;
3611 for (int i = 0; i < viewItems.size(); ++i) {
3612 if (i == item)
3613 return y - vbar->value();
3614 y += itemHeight(i);
3615 }
3616 } else { // ScrollPerItem
3617 int topViewItemIndex = vbar->value();
3619 return defaultItemHeight * (item - topViewItemIndex);
3620 if (item >= topViewItemIndex) {
3621 // search in the visible area first and continue down
3622 // ### slow if the item is not visible
3623 int viewItemCoordinate = 0;
3624 int viewItemIndex = topViewItemIndex;
3625 while (viewItemIndex < viewItems.size()) {
3626 if (viewItemIndex == item)
3627 return viewItemCoordinate;
3628 viewItemCoordinate += itemHeight(viewItemIndex);
3629 ++viewItemIndex;
3630 }
3631 // below the last item in the view
3632 Q_ASSERT(false);
3633 return viewItemCoordinate;
3634 } else {
3635 // search the area above the viewport (used for editor widgets)
3636 int viewItemCoordinate = 0;
3637 for (int viewItemIndex = topViewItemIndex; viewItemIndex > 0; --viewItemIndex) {
3638 if (viewItemIndex == item)
3639 return viewItemCoordinate;
3640 viewItemCoordinate -= itemHeight(viewItemIndex - 1);
3641 }
3642 return viewItemCoordinate;
3643 }
3644 }
3645 return 0;
3646}
3647
3655int QTreeViewPrivate::itemAtCoordinate(int coordinate) const
3656{
3657 const int itemCount = viewItems.size();
3658 if (itemCount == 0)
3659 return -1;
3661 return -1;
3663 if (uniformRowHeights) {
3664 const int viewItemIndex = (coordinate + vbar->value()) / defaultItemHeight;
3665 return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
3666 }
3667 // ### optimize
3668 int viewItemCoordinate = 0;
3669 const int contentsCoordinate = coordinate + vbar->value();
3670 for (int viewItemIndex = 0; viewItemIndex < viewItems.size(); ++viewItemIndex) {
3671 viewItemCoordinate += itemHeight(viewItemIndex);
3672 if (viewItemCoordinate > contentsCoordinate)
3673 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
3674 }
3675 } else { // ScrollPerItem
3676 int topViewItemIndex = vbar->value();
3677 if (uniformRowHeights) {
3678 if (coordinate < 0)
3679 coordinate -= defaultItemHeight - 1;
3680 const int viewItemIndex = topViewItemIndex + (coordinate / defaultItemHeight);
3681 return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
3682 }
3683 if (coordinate >= 0) {
3684 // the coordinate is in or below the viewport
3685 int viewItemCoordinate = 0;
3686 for (int viewItemIndex = topViewItemIndex; viewItemIndex < viewItems.size(); ++viewItemIndex) {
3687 viewItemCoordinate += itemHeight(viewItemIndex);
3688 if (viewItemCoordinate > coordinate)
3689 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
3690 }
3691 } else {
3692 // the coordinate is above the viewport
3693 int viewItemCoordinate = 0;
3694 for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) {
3695 if (viewItemCoordinate <= coordinate)
3696 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
3697 viewItemCoordinate -= itemHeight(viewItemIndex);
3698 }
3699 }
3700 }
3701 return -1;
3702}
3703
3705{
3706 if (!_index.isValid() || viewItems.isEmpty())
3707 return -1;
3708
3709 const int totalCount = viewItems.size();
3710 const QModelIndex index = _index.sibling(_index.row(), 0);
3711 const int row = index.row();
3712 const quintptr internalId = index.internalId();
3713
3714 // We start nearest to the lastViewedItem
3715 int localCount = qMin(lastViewedItem - 1, totalCount - lastViewedItem);
3716 for (int i = 0; i < localCount; ++i) {
3717 const QModelIndex &idx1 = viewItems.at(lastViewedItem + i).index;
3718 if (idx1.row() == row && idx1.internalId() == internalId) {
3720 return lastViewedItem;
3721 }
3722 const QModelIndex &idx2 = viewItems.at(lastViewedItem - i - 1).index;
3723 if (idx2.row() == row && idx2.internalId() == internalId) {
3725 return lastViewedItem;
3726 }
3727 }
3728
3729 for (int j = qMax(0, lastViewedItem + localCount); j < totalCount; ++j) {
3730 const QModelIndex &idx = viewItems.at(j).index;
3731 if (idx.row() == row && idx.internalId() == internalId) {
3732 lastViewedItem = j;
3733 return j;
3734 }
3735 }
3736 for (int j = qMin(totalCount, lastViewedItem - localCount) - 1; j >= 0; --j) {
3737 const QModelIndex &idx = viewItems.at(j).index;
3738 if (idx.row() == row && idx.internalId() == internalId) {
3739 lastViewedItem = j;
3740 return j;
3741 }
3742 }
3743
3744 // nothing found
3745 return -1;
3746}
3747
3749{
3750 if (i < 0 || i >= viewItems.size())
3751 return QModelIndex();
3752
3754 if (column)
3755 ret = ret.sibling(ret.row(), column);
3756 return ret;
3757}
3758
3760{
3761 const int value = vbar->value();
3763 if (offset)
3764 *offset = 0;
3765 return (value < 0 || value >= viewItems.size()) ? -1 : value;
3766 }
3767 // ScrollMode == ScrollPerPixel
3768 if (uniformRowHeights) {
3769 if (!defaultItemHeight)
3770 return -1;
3771
3772 if (offset)
3774 return value / defaultItemHeight;
3775 }
3776 int y = 0; // ### (maybe do like QHeaderView by letting items have startposition)
3777 for (int i = 0; i < viewItems.size(); ++i) {
3778 y += itemHeight(i); // the height value is cached
3779 if (y > value) {
3780 if (offset)
3781 *offset = y - value - itemHeight(i);
3782 return i;
3783 }
3784 }
3785 return -1;
3786}
3787
3788int QTreeViewPrivate::lastVisibleItem(int firstVisual, int offset) const
3789{
3790 if (firstVisual < 0 || offset < 0) {
3791 firstVisual = firstVisibleItem(&offset);
3792 if (firstVisual < 0)
3793 return -1;
3794 }
3795 int y = - offset;
3796 int value = viewport->height();
3797
3798 for (int i = firstVisual; i < viewItems.size(); ++i) {
3799 y += itemHeight(i); // the height value is cached
3800 if (y > value)
3801 return i;
3802 }
3803 return viewItems.size() - 1;
3804}
3805
3807{
3808 return header->logicalIndexAt(x);
3809}
3810
3812{
3813 Q_Q(QTreeView);
3814 QSize viewportSize = viewport->size();
3815 if (!viewportSize.isValid())
3816 viewportSize = QSize(0, 0);
3817
3819 if (viewItems.isEmpty()) {
3820 q->doItemsLayout();
3821 }
3822
3823 int itemsInViewport = 0;
3824 if (uniformRowHeights) {
3825 if (defaultItemHeight <= 0)
3826 itemsInViewport = viewItems.size();
3827 else
3828 itemsInViewport = viewportSize.height() / defaultItemHeight;
3829 } else {
3830 const int itemsCount = viewItems.size();
3831 const int viewportHeight = viewportSize.height();
3832 for (int height = 0, item = itemsCount - 1; item >= 0; --item) {
3834 if (height > viewportHeight)
3835 break;
3836 ++itemsInViewport;
3837 }
3838 }
3840 if (!viewItems.isEmpty())
3841 itemsInViewport = qMax(1, itemsInViewport);
3842 vbar->setRange(0, viewItems.size() - itemsInViewport);
3843 vbar->setPageStep(itemsInViewport);
3844 vbar->setSingleStep(1);
3845 } else { // scroll per pixel
3846 int contentsHeight = 0;
3847 if (uniformRowHeights) {
3848 contentsHeight = defaultItemHeight * viewItems.size();
3849 } else { // ### (maybe do like QHeaderView by letting items have startposition)
3850 for (int i = 0; i < viewItems.size(); ++i)
3851 contentsHeight += itemHeight(i);
3852 }
3853 vbar->setRange(0, contentsHeight - viewportSize.height());
3854 vbar->setPageStep(viewportSize.height());
3855 vbar->d_func()->itemviewChangeSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2));
3856 }
3857
3858 const int columnCount = header->count();
3859 const int viewportWidth = viewportSize.width();
3860 int columnsInViewport = 0;
3861 for (int width = 0, column = columnCount - 1; column >= 0; --column) {
3862 int logical = header->logicalIndex(column);
3863 width += header->sectionSize(logical);
3864 if (width > viewportWidth)
3865 break;
3866 ++columnsInViewport;
3867 }
3868 if (columnCount > 0)
3869 columnsInViewport = qMax(1, columnsInViewport);
3871 hbar->setRange(0, columnCount - columnsInViewport);
3872 hbar->setPageStep(columnsInViewport);
3873 hbar->setSingleStep(1);
3874 } else { // scroll per pixel
3875 const int horizontalLength = header->length();
3876 const QSize maxSize = q->maximumViewportSize();
3877 if (maxSize.width() >= horizontalLength && vbar->maximum() <= 0)
3878 viewportSize = maxSize;
3879 hbar->setPageStep(viewportSize.width());
3880 hbar->setRange(0, qMax(horizontalLength - viewportSize.width(), 0));
3881 hbar->d_func()->itemviewChangeSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2));
3882 }
3883}
3884
3886{
3887 Q_Q(const QTreeView);
3889 bool spanned = false;
3890 if (!spanningIndexes.isEmpty()) {
3891 const QModelIndex index = q->indexAt(pos);
3892 if (index.isValid())
3893 spanned = q->isFirstColumnSpanned(index.row(), index.parent());
3894 }
3895 const int column = spanned ? 0 : header->logicalIndexAt(pos.x());
3896 if (!isTreePosition(column))
3897 return -1; // no logical index at x
3898
3899 int viewItemIndex = itemAtCoordinate(pos.y());
3900 QRect returning = itemDecorationRect(modelIndex(viewItemIndex));
3901 if (!returning.contains(pos))
3902 return -1;
3903
3904 return viewItemIndex;
3905}
3906
3908{
3909 Q_Q(const QTreeView);
3910 if (!rootDecoration && index.parent() == root)
3911 return QRect(); // no decoration at root
3912
3913 int viewItemIndex = viewIndex(index);
3914 if (viewItemIndex < 0 || !hasVisibleChildren(viewItems.at(viewItemIndex).index))
3915 return QRect();
3916
3917 int itemIndentation = indentationForItem(viewItemIndex);
3920
3921 QRect rect;
3922 if (q->isRightToLeft())
3923 rect = QRect(position + size - itemIndentation, coordinateForItem(viewItemIndex),
3924 indent, itemHeight(viewItemIndex));
3925 else
3926 rect = QRect(position + itemIndentation - indent, coordinateForItem(viewItemIndex),
3927 indent, itemHeight(viewItemIndex));
3929 opt.initFrom(q);
3930 opt.rect = rect;
3931 return q->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, q);
3932}
3933
3934QList<QPair<int, int>> QTreeViewPrivate::columnRanges(const QModelIndex &topIndex,
3935 const QModelIndex &bottomIndex) const
3936{
3937 const int topVisual = header->visualIndex(topIndex.column()),
3938 bottomVisual = header->visualIndex(bottomIndex.column());
3939
3940 const int start = qMin(topVisual, bottomVisual);
3941 const int end = qMax(topVisual, bottomVisual);
3942
3943 QList<int> logicalIndexes;
3944
3945 //we iterate over the visual indexes to get the logical indexes
3946 for (int c = start; c <= end; c++) {
3947 const int logical = header->logicalIndex(c);
3948 if (!header->isSectionHidden(logical)) {
3949 logicalIndexes << logical;
3950 }
3951 }
3952 //let's sort the list
3953 std::sort(logicalIndexes.begin(), logicalIndexes.end());
3954
3955 QList<QPair<int, int>> ret;
3956 QPair<int, int> current;
3957 current.first = -2; // -1 is not enough because -1+1 = 0
3958 current.second = -2;
3959 for(int i = 0; i < logicalIndexes.size(); ++i) {
3960 const int logicalColumn = logicalIndexes.at(i);
3961 if (current.second + 1 != logicalColumn) {
3962 if (current.first != -2) {
3963 //let's save the current one
3964 ret += current;
3965 }
3966 //let's start a new one
3967 current.first = current.second = logicalColumn;
3968 } else {
3969 current.second++;
3970 }
3971 }
3972
3973 //let's get the last range
3974 if (current.first != -2) {
3975 ret += current;
3976 }
3977
3978 return ret;
3979}
3980
3981void QTreeViewPrivate::select(const QModelIndex &topIndex, const QModelIndex &bottomIndex,
3982 QItemSelectionModel::SelectionFlags command)
3983{
3984 Q_Q(QTreeView);
3986 const int top = viewIndex(topIndex),
3987 bottom = viewIndex(bottomIndex);
3988
3989 const QList<QPair<int, int>> colRanges = columnRanges(topIndex, bottomIndex);
3990 QList<QPair<int, int>>::const_iterator it;
3991 for (it = colRanges.begin(); it != colRanges.end(); ++it) {
3992 const int left = (*it).first,
3993 right = (*it).second;
3994
3995 QModelIndex previous;
3996 QItemSelectionRange currentRange;
3997 QStack<QItemSelectionRange> rangeStack;
3998 for (int i = top; i <= bottom; ++i) {
4000 QModelIndex parent = index.parent();
4001 QModelIndex previousParent = previous.parent();
4002 if (previous.isValid() && parent == previousParent) {
4003 // same parent
4004 if (qAbs(previous.row() - index.row()) > 1) {
4005 //a hole (hidden index inside a range) has been detected
4006 if (currentRange.isValid()) {
4007 selection.append(currentRange);
4008 }
4009 //let's start a new range
4010 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
4011 } else {
4012 QModelIndex tl = model->index(currentRange.top(), currentRange.left(),
4013 currentRange.parent());
4014 currentRange = QItemSelectionRange(tl, index.sibling(index.row(), right));
4015 }
4016 } else if (previous.isValid() && parent == model->index(previous.row(), 0, previousParent)) {
4017 // item is child of previous
4018 rangeStack.push(currentRange);
4019 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
4020 } else {
4021 if (currentRange.isValid())
4022 selection.append(currentRange);
4023 if (rangeStack.isEmpty()) {
4024 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
4025 } else {
4026 currentRange = rangeStack.pop();
4027 index = currentRange.bottomRight(); //let's resume the range
4028 --i; //we process again the current item
4029 }
4030 }
4031 previous = index;
4032 }
4033 if (currentRange.isValid())
4034 selection.append(currentRange);
4035 for (int i = 0; i < rangeStack.size(); ++i)
4036 selection.append(rangeStack.at(i));
4037 }
4038 q->selectionModel()->select(selection, command);
4039}
4040
4042{
4043 Q_Q(const QTreeView);
4044 int start = header->visualIndexAt(rect.left());
4045 int end = header->visualIndexAt(rect.right());
4046 if (q->isRightToLeft()) {
4047 start = (start == -1 ? header->count() - 1 : start);
4048 end = (end == -1 ? 0 : end);
4049 } else {
4050 start = (start == -1 ? 0 : start);
4051 end = (end == -1 ? header->count() - 1 : end);
4052 }
4053 return qMakePair(qMin(start, end), qMax(start, end));
4054}
4055
4057{
4058 Q_Q(const QTreeView);
4059 if (parent.flags() & Qt::ItemNeverHasChildren)
4060 return false;
4061 if (model->hasChildren(parent)) {
4062 if (hiddenIndexes.isEmpty())
4063 return true;
4064 if (q->isIndexHidden(parent))
4065 return false;
4066 int rowCount = model->rowCount(parent);
4067 for (int i = 0; i < rowCount; ++i) {
4068 if (!q->isRowHidden(i, parent))
4069 return true;
4070 }
4071 if (rowCount == 0)
4072 return true;
4073 }
4074 return false;
4075}
4076
4081
4083{
4084 Q_Q(const QTreeView);
4085
4086 // Note that this will include the header, even if its hidden.
4087 return (q->visualIndex(index) + (q->header() ? 1 : 0)) * index.model()->columnCount() + index.column();
4088}
4089
4091{
4092 Q_Q(const QTreeView);
4093 indent = q->style()->pixelMetric(QStyle::PM_TreeViewIndentation, nullptr, q);
4094}
4095
4099void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
4100{
4101 Q_D(QTreeView);
4102 QAbstractItemView::currentChanged(current, previous);
4103
4104 if (allColumnsShowFocus()) {
4105 if (previous.isValid())
4106 viewport()->update(d->visualRect(previous, QTreeViewPrivate::FullRow));
4107 if (current.isValid())
4108 viewport()->update(d->visualRect(current, QTreeViewPrivate::FullRow));
4109 }
4110#if QT_CONFIG(accessibility)
4111 if (QAccessible::isActive() && current.isValid() && hasFocus()) {
4112 Q_D(QTreeView);
4113
4114 QAccessibleEvent event(this, QAccessible::Focus);
4115 event.setChild(d->accessibleTree2Index(current));
4116 QAccessible::updateAccessibility(&event);
4117 }
4118#endif
4119}
4120
4125 const QItemSelection &deselected)
4126{
4127 QAbstractItemView::selectionChanged(selected, deselected);
4128#if QT_CONFIG(accessibility)
4129 if (QAccessible::isActive()) {
4130 Q_D(QTreeView);
4131
4132 // ### does not work properly for selection ranges.
4133 QModelIndex sel = selected.indexes().value(0);
4134 if (sel.isValid()) {
4135 int entry = d->accessibleTree2Index(sel);
4136 Q_ASSERT(entry >= 0);
4137 QAccessibleEvent event(this, QAccessible::SelectionAdd);
4138 event.setChild(entry);
4139 QAccessible::updateAccessibility(&event);
4140 }
4141 QModelIndex desel = deselected.indexes().value(0);
4142 if (desel.isValid()) {
4143 int entry = d->accessibleTree2Index(desel);
4144 Q_ASSERT(entry >= 0);
4145 QAccessibleEvent event(this, QAccessible::SelectionRemove);
4146 event.setChild(entry);
4147 QAccessible::updateAccessibility(&event);
4148 }
4149 }
4150#endif
4151}
4152
4153int QTreeView::visualIndex(const QModelIndex &index) const
4154{
4155 Q_D(const QTreeView);
4156 d->executePostedLayout();
4157 return d->viewIndex(index);
4158}
4159
4165{
4166 Q_D(QTreeView);
4167 if (!d->viewItems.isEmpty() && value == verticalScrollBar()->maximum()) {
4168 QModelIndex ret = d->viewItems.last().index;
4169 // Root index will be handled by base class implementation
4170 while (ret.isValid()) {
4171 if (isExpanded(ret) && d->model->canFetchMore(ret)) {
4172 d->model->fetchMore(ret);
4173 break;
4174 }
4175 ret = ret.parent();
4176 }
4177 }
4179}
4180
4182
4183#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:1220
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:1216
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:398
bool isEmpty() const noexcept
Definition qlist.h:402
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:489
const_reference at(qsizetype i) const noexcept
Definition qlist.h:447
void remove(qsizetype i, qsizetype n=1)
Definition qlist.h:795
qsizetype count() const noexcept
Definition qlist.h:399
pointer data()
Definition qlist.h:432
void resize(qsizetype size)
Definition qlist.h:404
void append(parameter_type t)
Definition qlist.h:459
void clear()
Definition qlist.h:435
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:700
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:74
\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
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
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
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:855
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
QRect united(const QRect &other) const noexcept
Definition qrect.h:420
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:137
iterator end()
Definition qset.h:141
bool isEmpty() const
Definition qset.h:53
void clear()
Definition qset.h:62
iterator erase(const_iterator i)
Definition qset.h:146
iterator find(const T &value)
Definition qset.h:160
bool contains(const T &value) const
Definition qset.h:72
\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:4838
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:8164
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:5108
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 qint64 area(const QSize &s)
Definition qicon.cpp:183
return ret
QT_BEGIN_NAMESPACE constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:19
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:23
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:21
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