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 | |
4 | #ifndef QTREEVIEW_P_H |
5 | #define QTREEVIEW_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtWidgets/private/qtwidgetsglobal_p.h> |
19 | #include "private/qabstractitemview_p.h" |
20 | #include <QtCore/qabstractitemmodel.h> |
21 | #include <QtCore/qlist.h> |
22 | #if QT_CONFIG(animation) |
23 | #include <QtCore/qvariantanimation.h> |
24 | #endif |
25 | |
26 | QT_REQUIRE_CONFIG(treeview); |
27 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | struct QTreeViewItem |
31 | { |
32 | QTreeViewItem() : parentItem(-1), expanded(false), spanning(false), hasChildren(false), |
33 | hasMoreSiblings(false), total(0), level(0), height(0) {} |
34 | QModelIndex index; // we remove items whenever the indexes are invalidated |
35 | int parentItem; // parent item index in viewItems |
36 | uint expanded : 1; |
37 | uint spanning : 1; |
38 | uint hasChildren : 1; // if the item has visible children (even if collapsed) |
39 | uint hasMoreSiblings : 1; |
40 | uint total : 28; // total number of children visible |
41 | uint level : 16; // indentation |
42 | int height : 16; // row height |
43 | }; |
44 | |
45 | Q_DECLARE_TYPEINFO(QTreeViewItem, Q_RELOCATABLE_TYPE); |
46 | |
47 | class Q_WIDGETS_EXPORT QTreeViewPrivate : public QAbstractItemViewPrivate |
48 | { |
49 | Q_DECLARE_PUBLIC(QTreeView) |
50 | public: |
51 | |
52 | QTreeViewPrivate() |
53 | : QAbstractItemViewPrivate(), |
54 | header(nullptr), indent(20), lastViewedItem(0), defaultItemHeight(-1), |
55 | uniformRowHeights(false), rootDecoration(true), |
56 | itemsExpandable(true), sortingEnabled(false), |
57 | expandsOnDoubleClick(true), |
58 | allColumnsShowFocus(false), customIndent(false), current(0), spanning(false), |
59 | animationsEnabled(false), columnResizeTimerID(0), |
60 | autoExpandDelay(-1), hoverBranch(-1), geometryRecursionBlock(false), hasRemovedItems(false), |
61 | treePosition(0) {} |
62 | |
63 | ~QTreeViewPrivate() {} |
64 | void initialize(); |
65 | int logicalIndexForTree() const; |
66 | inline bool isTreePosition(int logicalIndex) const |
67 | { |
68 | return logicalIndex == logicalIndexForTree(); |
69 | } |
70 | |
71 | QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const override; |
72 | void adjustViewOptionsForIndex(QStyleOptionViewItem *option, const QModelIndex ¤t) const override; |
73 | |
74 | #if QT_CONFIG(animation) |
75 | struct AnimatedOperation : public QVariantAnimation |
76 | { |
77 | int item; |
78 | QPixmap before; |
79 | QPixmap after; |
80 | QWidget *viewport; |
81 | AnimatedOperation() : item(0) { setEasingCurve(QEasingCurve::InOutQuad); } |
82 | int top() const { return startValue().toInt(); } |
83 | QRect rect() const { QRect rect = viewport->rect(); rect.moveTop(pos: top()); return rect; } |
84 | void updateCurrentValue(const QVariant &) override { viewport->update(rect()); } |
85 | void updateState(State state, State) override { if (state == Stopped) before = after = QPixmap(); } |
86 | } animatedOperation; |
87 | void prepareAnimatedOperation(int item, QVariantAnimation::Direction d); |
88 | void beginAnimatedOperation(); |
89 | void drawAnimatedOperation(QPainter *painter) const; |
90 | QPixmap renderTreeToPixmapForAnimation(const QRect &rect) const; |
91 | void _q_endAnimatedOperation(); |
92 | #endif // animation |
93 | |
94 | void expand(int item, bool emitSignal); |
95 | void collapse(int item, bool emitSignal); |
96 | |
97 | void _q_columnsAboutToBeRemoved(const QModelIndex &, int, int) override; |
98 | void _q_columnsRemoved(const QModelIndex &, int, int) override; |
99 | void _q_modelAboutToBeReset(); |
100 | void _q_sortIndicatorChanged(int column, Qt::SortOrder order); |
101 | void _q_modelDestroyed() override; |
102 | QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override; |
103 | |
104 | void layout(int item, bool recusiveExpanding = false, bool afterIsUninitialized = false); |
105 | |
106 | int pageUp(int item) const; |
107 | int pageDown(int item) const; |
108 | int itemForKeyHome() const; |
109 | int itemForKeyEnd() const; |
110 | |
111 | int itemHeight(int item) const; |
112 | int indentationForItem(int item) const; |
113 | int coordinateForItem(int item) const; |
114 | int itemAtCoordinate(int coordinate) const; |
115 | |
116 | int viewIndex(const QModelIndex &index) const; |
117 | QModelIndex modelIndex(int i, int column = 0) const; |
118 | |
119 | void insertViewItems(int pos, int count, const QTreeViewItem &viewItem); |
120 | void removeViewItems(int pos, int count); |
121 | #if 0 |
122 | bool checkViewItems() const; |
123 | #endif |
124 | |
125 | int firstVisibleItem(int *offset = nullptr) const; |
126 | int lastVisibleItem(int firstVisual = -1, int offset = -1) const; |
127 | int columnAt(int x) const; |
128 | bool hasVisibleChildren( const QModelIndex& parent) const; |
129 | |
130 | bool expandOrCollapseItemAtPos(const QPoint &pos); |
131 | |
132 | void updateScrollBars(); |
133 | |
134 | int itemDecorationAt(const QPoint &pos) const; |
135 | QRect itemDecorationRect(const QModelIndex &index) const; |
136 | |
137 | QList<QPair<int, int>> columnRanges(const QModelIndex &topIndex, |
138 | const QModelIndex &bottomIndex) const; |
139 | void select(const QModelIndex &start, const QModelIndex &stop, QItemSelectionModel::SelectionFlags command); |
140 | |
141 | QPair<int,int> startAndEndColumns(const QRect &rect) const; |
142 | |
143 | void updateChildCount(const int parentItem, const int delta); |
144 | |
145 | void paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItem *option, int y, int bottom) const; |
146 | |
147 | // logicalIndices: vector of currently visibly logical indices |
148 | // itemPositions: vector of view item positions (beginning/middle/end/onlyone) |
149 | void calcLogicalIndices(QList<int> *logicalIndices, |
150 | QList<QStyleOptionViewItem::ViewItemPosition> *itemPositions, int left, |
151 | int right) const; |
152 | int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const; |
153 | |
154 | enum RectRule { |
155 | FullRow, |
156 | SingleSection, |
157 | AddRowIndicatorToFirstSection |
158 | }; |
159 | |
160 | // Base class will get the first visual rect including row indicator |
161 | QRect visualRect(const QModelIndex &index) const override |
162 | { |
163 | return visualRect(index, rule: AddRowIndicatorToFirstSection); |
164 | } |
165 | |
166 | QRect visualRect(const QModelIndex &index, RectRule rule) const; |
167 | |
168 | QHeaderView *; |
169 | int indent; |
170 | |
171 | mutable QList<QTreeViewItem> viewItems; |
172 | mutable int lastViewedItem; |
173 | int defaultItemHeight; // this is just a number; contentsHeight() / numItems |
174 | bool uniformRowHeights; // used when all rows have the same height |
175 | bool rootDecoration; |
176 | bool itemsExpandable; |
177 | bool sortingEnabled; |
178 | bool expandsOnDoubleClick; |
179 | bool allColumnsShowFocus; |
180 | bool customIndent; |
181 | |
182 | // used for drawing |
183 | mutable QPair<int,int> leftAndRight; |
184 | mutable int current; |
185 | mutable bool spanning; |
186 | |
187 | // used when expanding and collapsing items |
188 | QSet<QPersistentModelIndex> expandedIndexes; |
189 | bool animationsEnabled; |
190 | |
191 | inline bool storeExpanded(const QPersistentModelIndex &idx) { |
192 | if (expandedIndexes.contains(value: idx)) |
193 | return false; |
194 | expandedIndexes.insert(value: idx); |
195 | return true; |
196 | } |
197 | |
198 | inline bool isIndexExpanded(const QModelIndex &idx) const { |
199 | //We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow |
200 | return !(idx.flags() & Qt::ItemNeverHasChildren) && isPersistent(index: idx) && expandedIndexes.contains(value: idx); |
201 | } |
202 | |
203 | // used when hiding and showing items |
204 | QSet<QPersistentModelIndex> hiddenIndexes; |
205 | |
206 | inline bool isRowHidden(const QModelIndex &idx) const { |
207 | if (hiddenIndexes.isEmpty()) |
208 | return false; |
209 | //We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow |
210 | return isPersistent(index: idx) && hiddenIndexes.contains(value: idx); |
211 | } |
212 | |
213 | inline bool isItemHiddenOrDisabled(int i) const { |
214 | if (i < 0 || i >= viewItems.size()) |
215 | return false; |
216 | const QModelIndex index = viewItems.at(i).index; |
217 | return isRowHidden(idx: index) || !isIndexEnabled(index); |
218 | } |
219 | |
220 | inline int above(int item) const |
221 | { int i = item; while (isItemHiddenOrDisabled(i: --item)){} return item < 0 ? i : item; } |
222 | inline int below(int item) const |
223 | { int i = item; while (isItemHiddenOrDisabled(i: ++item)){} return item >= viewItems.size() ? i : item; } |
224 | inline void invalidateHeightCache(int item) const |
225 | { viewItems[item].height = 0; } |
226 | |
227 | inline int accessibleTable2Index(const QModelIndex &index) const { |
228 | return (viewIndex(index) + (header ? 1 : 0)) * model->columnCount()+index.column(); |
229 | } |
230 | |
231 | int accessibleTree2Index(const QModelIndex &index) const; |
232 | |
233 | void updateIndentationFromStyle(); |
234 | |
235 | // used for spanning rows |
236 | QSet<QPersistentModelIndex> spanningIndexes; |
237 | |
238 | // used for updating resized columns |
239 | int columnResizeTimerID; |
240 | QList<int> columnsToUpdate; |
241 | |
242 | // used for the automatic opening of nodes during DND |
243 | int autoExpandDelay; |
244 | QBasicTimer openTimer; |
245 | |
246 | // used for drawing highlighted expand/collapse indicators |
247 | mutable int hoverBranch; |
248 | |
249 | // used for blocking recursion when calling setViewportMargins from updateGeometries |
250 | bool geometryRecursionBlock; |
251 | |
252 | // If we should clean the set |
253 | bool hasRemovedItems; |
254 | |
255 | // tree position |
256 | int treePosition; |
257 | }; |
258 | |
259 | QT_END_NAMESPACE |
260 | |
261 | #endif // QTREEVIEW_P_H |
262 | |