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