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 | #include <QtCore/qabstractitemmodel.h> |
57 | #include <QtCore/qlist.h> |
58 | #if QT_CONFIG(animation) |
59 | #include <QtCore/qvariantanimation.h> |
60 | #endif |
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(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 | QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override; |
139 | |
140 | void layout(int item, bool recusiveExpanding = false, bool afterIsUninitialized = false); |
141 | |
142 | int pageUp(int item) const; |
143 | int pageDown(int item) const; |
144 | int itemForKeyHome() const; |
145 | int itemForKeyEnd() const; |
146 | |
147 | int itemHeight(int item) const; |
148 | int indentationForItem(int item) const; |
149 | int coordinateForItem(int item) const; |
150 | int itemAtCoordinate(int coordinate) const; |
151 | |
152 | int viewIndex(const QModelIndex &index) const; |
153 | QModelIndex modelIndex(int i, int column = 0) const; |
154 | |
155 | void insertViewItems(int pos, int count, const QTreeViewItem &viewItem); |
156 | void removeViewItems(int pos, int count); |
157 | #if 0 |
158 | bool checkViewItems() const; |
159 | #endif |
160 | |
161 | int firstVisibleItem(int *offset = nullptr) const; |
162 | int lastVisibleItem(int firstVisual = -1, int offset = -1) const; |
163 | int columnAt(int x) const; |
164 | bool hasVisibleChildren( const QModelIndex& parent) const; |
165 | |
166 | bool expandOrCollapseItemAtPos(const QPoint &pos); |
167 | |
168 | void updateScrollBars(); |
169 | |
170 | int itemDecorationAt(const QPoint &pos) const; |
171 | QRect itemDecorationRect(const QModelIndex &index) const; |
172 | |
173 | QList<QPair<int, int>> columnRanges(const QModelIndex &topIndex, |
174 | const QModelIndex &bottomIndex) const; |
175 | void select(const QModelIndex &start, const QModelIndex &stop, QItemSelectionModel::SelectionFlags command); |
176 | |
177 | QPair<int,int> startAndEndColumns(const QRect &rect) const; |
178 | |
179 | void updateChildCount(const int parentItem, const int delta); |
180 | |
181 | void paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItem *option, int y, int bottom) const; |
182 | |
183 | // logicalIndices: vector of currently visibly logical indices |
184 | // itemPositions: vector of view item positions (beginning/middle/end/onlyone) |
185 | void calcLogicalIndices(QList<int> *logicalIndices, |
186 | QList<QStyleOptionViewItem::ViewItemPosition> *itemPositions, int left, |
187 | int right) const; |
188 | int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const; |
189 | QHeaderView *; |
190 | int indent; |
191 | |
192 | mutable QList<QTreeViewItem> viewItems; |
193 | mutable int lastViewedItem; |
194 | int defaultItemHeight; // this is just a number; contentsHeight() / numItems |
195 | bool uniformRowHeights; // used when all rows have the same height |
196 | bool rootDecoration; |
197 | bool itemsExpandable; |
198 | bool sortingEnabled; |
199 | bool expandsOnDoubleClick; |
200 | bool allColumnsShowFocus; |
201 | bool customIndent; |
202 | |
203 | // used for drawing |
204 | mutable QPair<int,int> leftAndRight; |
205 | mutable int current; |
206 | mutable bool spanning; |
207 | |
208 | // used when expanding and collapsing items |
209 | QSet<QPersistentModelIndex> expandedIndexes; |
210 | bool animationsEnabled; |
211 | |
212 | inline bool storeExpanded(const QPersistentModelIndex &idx) { |
213 | if (expandedIndexes.contains(idx)) |
214 | return false; |
215 | expandedIndexes.insert(idx); |
216 | return true; |
217 | } |
218 | |
219 | inline bool isIndexExpanded(const QModelIndex &idx) const { |
220 | //We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow |
221 | return !(idx.flags() & Qt::ItemNeverHasChildren) && isPersistent(idx) && expandedIndexes.contains(idx); |
222 | } |
223 | |
224 | // used when hiding and showing items |
225 | QSet<QPersistentModelIndex> hiddenIndexes; |
226 | |
227 | inline bool isRowHidden(const QModelIndex &idx) const { |
228 | if (hiddenIndexes.isEmpty()) |
229 | return false; |
230 | //We first check if the idx is a QPersistentModelIndex, because creating QPersistentModelIndex is slow |
231 | return isPersistent(idx) && hiddenIndexes.contains(idx); |
232 | } |
233 | |
234 | inline bool isItemHiddenOrDisabled(int i) const { |
235 | if (i < 0 || i >= viewItems.count()) |
236 | return false; |
237 | const QModelIndex index = viewItems.at(i).index; |
238 | return isRowHidden(index) || !isIndexEnabled(index); |
239 | } |
240 | |
241 | inline int above(int item) const |
242 | { int i = item; while (isItemHiddenOrDisabled(--item)){} return item < 0 ? i : item; } |
243 | inline int below(int item) const |
244 | { int i = item; while (isItemHiddenOrDisabled(++item)){} return item >= viewItems.count() ? i : item; } |
245 | inline void invalidateHeightCache(int item) const |
246 | { viewItems[item].height = 0; } |
247 | |
248 | inline int accessibleTable2Index(const QModelIndex &index) const { |
249 | return (viewIndex(index) + (header ? 1 : 0)) * model->columnCount()+index.column(); |
250 | } |
251 | |
252 | int accessibleTree2Index(const QModelIndex &index) const; |
253 | |
254 | void updateIndentationFromStyle(); |
255 | |
256 | // used for spanning rows |
257 | QSet<QPersistentModelIndex> spanningIndexes; |
258 | |
259 | // used for updating resized columns |
260 | int columnResizeTimerID; |
261 | QList<int> columnsToUpdate; |
262 | |
263 | // used for the automatic opening of nodes during DND |
264 | int autoExpandDelay; |
265 | QBasicTimer openTimer; |
266 | |
267 | // used for drawing hilighted expand/collapse indicators |
268 | mutable int hoverBranch; |
269 | |
270 | // used for blocking recursion when calling setViewportMargins from updateGeometries |
271 | bool geometryRecursionBlock; |
272 | |
273 | // If we should clean the set |
274 | bool hasRemovedItems; |
275 | |
276 | // tree position |
277 | int treePosition; |
278 | }; |
279 | |
280 | QT_END_NAMESPACE |
281 | |
282 | #endif // QTREEVIEW_P_H |
283 | |