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 {
QTreeViewItemQTreeViewItem68     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 {
Q_DECLARE_PUBLIC(QTreeView)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 
~QTreeViewPrivate()99     ~QTreeViewPrivate() {}
100     void initialize();
101     int logicalIndexForTree() const;
isTreePosition(int logicalIndex)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 &current) 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;
AnimatedOperationAnimatedOperation117         AnimatedOperation() : item(0) { setEasingCurve(QEasingCurve::InOutQuad); }
topAnimatedOperation118         int top() const { return startValue().toInt(); }
rectAnimatedOperation119         QRect rect() const { QRect rect = viewport->rect(); rect.moveTop(top()); return rect; }
updateCurrentValueAnimatedOperation120         void updateCurrentValue(const QVariant &) override { viewport->update(rect()); }
updateStateAnimatedOperation121         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 *header;
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 
storeExpanded(const QPersistentModelIndex & idx)209     inline bool storeExpanded(const QPersistentModelIndex &idx) {
210         if (expandedIndexes.contains(idx))
211             return false;
212         expandedIndexes.insert(idx);
213         return true;
214     }
215 
isIndexExpanded(const QModelIndex & idx)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(idx) && expandedIndexes.contains(idx);
219     }
220 
221     // used when hiding and showing items
222     QSet<QPersistentModelIndex> hiddenIndexes;
223 
isRowHidden(const QModelIndex & idx)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(idx) && hiddenIndexes.contains(idx);
229     }
230 
isItemHiddenOrDisabled(int i)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(index) || !isIndexEnabled(index);
236     }
237 
above(int item)238     inline int above(int item) const
239         { int i = item; while (isItemHiddenOrDisabled(--item)){} return item < 0 ? i : item; }
below(int item)240     inline int below(int item) const
241         { int i = item; while (isItemHiddenOrDisabled(++item)){} return item >= viewItems.count() ? i : item; }
invalidateHeightCache(int item)242     inline void invalidateHeightCache(int item) const
243         { viewItems[item].height = 0; }
244 
accessibleTable2Index(const QModelIndex & index)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