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 QHEADERVIEW_P_H |
5 | #define QHEADERVIEW_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 "qheaderview.h" |
20 | #include "private/qabstractitemview_p.h" |
21 | |
22 | #include "QtCore/qbitarray.h" |
23 | #include "QtWidgets/qapplication.h" |
24 | #if QT_CONFIG(label) |
25 | #include "QtWidgets/qlabel.h" |
26 | #endif |
27 | |
28 | #include <array> |
29 | |
30 | QT_REQUIRE_CONFIG(itemviews); |
31 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | class QHeaderViewPrivate: public QAbstractItemViewPrivate |
35 | { |
36 | Q_DECLARE_PUBLIC(QHeaderView) |
37 | |
38 | public: |
39 | enum StateVersion { VersionMarker = 0xff }; |
40 | |
41 | QHeaderViewPrivate() |
42 | : state(NoState), |
43 | headerOffset(0), |
44 | sortIndicatorOrder(Qt::DescendingOrder), |
45 | sortIndicatorSection(0), |
46 | sortIndicatorShown(false), |
47 | sortIndicatorClearable(false), |
48 | lastPos(-1), |
49 | firstPos(-1), |
50 | originalSize(-1), |
51 | section(-1), |
52 | target(-1), |
53 | firstPressed(-1), |
54 | pressed(-1), |
55 | hover(-1), |
56 | length(0), |
57 | preventCursorChangeInSetOffset(false), |
58 | movableSections(false), |
59 | clickableSections(false), |
60 | highlightSelected(false), |
61 | stretchLastSection(false), |
62 | cascadingResizing(false), |
63 | resizeRecursionBlock(false), |
64 | allowUserMoveOfSection0(true), // will be false for QTreeView and true for QTableView |
65 | customDefaultSectionSize(false), |
66 | stretchSections(0), |
67 | contentsSections(0), |
68 | minimumSectionSize(-1), |
69 | maximumSectionSize(-1), |
70 | lastSectionSize(0), |
71 | lastSectionLogicalIdx(-1), // Only trust when we stretch last section |
72 | sectionIndicatorOffset(0), |
73 | #if QT_CONFIG(label) |
74 | sectionIndicator(nullptr), |
75 | #endif |
76 | globalResizeMode(QHeaderView::Interactive), |
77 | sectionStartposRecalc(true), |
78 | resizeContentsPrecision(1000) |
79 | {} |
80 | |
81 | |
82 | int lastVisibleVisualIndex() const; |
83 | void restoreSizeOnPrevLastSection(); |
84 | void setNewLastSection(int visualIndexForLastSection); |
85 | void maybeRestorePrevLastSectionAndStretchLast(); |
86 | int sectionHandleAt(int position); |
87 | void setupSectionIndicator(int section, int position); |
88 | void updateSectionIndicator(int section, int position); |
89 | void updateHiddenSections(int logicalFirst, int logicalLast); |
90 | void resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode = false); |
91 | void sectionsRemoved(const QModelIndex &,int,int); |
92 | void sectionsAboutToBeMoved(const QModelIndex &sourceParent, int logicalStart, |
93 | int logicalEnd, const QModelIndex &destinationParent, |
94 | int logicalDestination); |
95 | void sectionsMoved(const QModelIndex &sourceParent, int logicalStart, |
96 | int logicalEnd, const QModelIndex &destinationParent, |
97 | int logicalDestination); |
98 | void sectionsAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), |
99 | QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); |
100 | void sectionsChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), |
101 | QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); |
102 | |
103 | bool isSectionSelected(int section) const; |
104 | bool isFirstVisibleSection(int section) const; |
105 | bool isLastVisibleSection(int section) const; |
106 | |
107 | inline bool rowIntersectsSelection(int row) const { |
108 | return (selectionModel ? selectionModel->rowIntersectsSelection(row, parent: root) : false); |
109 | } |
110 | |
111 | inline bool columnIntersectsSelection(int column) const { |
112 | return (selectionModel ? selectionModel->columnIntersectsSelection(column, parent: root) : false); |
113 | } |
114 | |
115 | inline bool sectionIntersectsSelection(int logical) const { |
116 | return (orientation == Qt::Horizontal ? columnIntersectsSelection(column: logical) : rowIntersectsSelection(row: logical)); |
117 | } |
118 | |
119 | inline bool isRowSelected(int row) const { |
120 | return (selectionModel ? selectionModel->isRowSelected(row, parent: root) : false); |
121 | } |
122 | |
123 | inline bool isColumnSelected(int column) const { |
124 | return (selectionModel ? selectionModel->isColumnSelected(column, parent: root) : false); |
125 | } |
126 | |
127 | inline void prepareSectionSelected() { |
128 | if (!selectionModel || !selectionModel->hasSelection()) |
129 | sectionSelected.clear(); |
130 | else if (sectionSelected.size() != sectionCount() * 2) |
131 | sectionSelected.fill(aval: false, asize: sectionCount() * 2); |
132 | else sectionSelected.fill(aval: false); |
133 | } |
134 | |
135 | inline int sectionCount() const {return sectionItems.size();} |
136 | |
137 | inline bool reverse() const { |
138 | return orientation == Qt::Horizontal && q_func()->isRightToLeft(); |
139 | } |
140 | |
141 | inline int logicalIndex(int visualIndex) const { |
142 | return logicalIndices.isEmpty() ? visualIndex : logicalIndices.at(i: visualIndex); |
143 | } |
144 | |
145 | inline int visualIndex(int logicalIndex) const { |
146 | return visualIndices.isEmpty() ? logicalIndex : visualIndices.at(i: logicalIndex); |
147 | } |
148 | |
149 | inline void setDefaultValues(Qt::Orientation o) { |
150 | orientation = o; |
151 | updateDefaultSectionSizeFromStyle(); |
152 | defaultAlignment = (o == Qt::Horizontal |
153 | ? Qt::Alignment(Qt::AlignCenter) |
154 | : Qt::AlignLeft|Qt::AlignVCenter); |
155 | } |
156 | |
157 | inline bool isVisualIndexHidden(int visual) const { |
158 | return sectionItems.at(i: visual).isHidden; |
159 | } |
160 | |
161 | inline void setVisualIndexHidden(int visual, bool hidden) { |
162 | sectionItems[visual].isHidden = hidden; |
163 | } |
164 | |
165 | inline bool hasAutoResizeSections() const { |
166 | return stretchSections || stretchLastSection || contentsSections; |
167 | } |
168 | |
169 | QStyleOptionHeader getStyleOption() const; |
170 | |
171 | inline void invalidateCachedSizeHint() const { |
172 | cachedSizeHint = QSize(); |
173 | } |
174 | |
175 | inline void initializeIndexMapping() const { |
176 | if (visualIndices.size() != sectionCount() |
177 | || logicalIndices.size() != sectionCount()) { |
178 | visualIndices.resize(size: sectionCount()); |
179 | logicalIndices.resize(size: sectionCount()); |
180 | for (int s = 0; s < sectionCount(); ++s) { |
181 | visualIndices[s] = s; |
182 | logicalIndices[s] = s; |
183 | } |
184 | } |
185 | } |
186 | |
187 | inline void clearCascadingSections() { |
188 | firstCascadingSection = sectionItems.size(); |
189 | lastCascadingSection = 0; |
190 | cascadingSectionSize.clear(); |
191 | } |
192 | |
193 | inline void saveCascadingSectionSize(int visual, int size) { |
194 | if (!cascadingSectionSize.contains(key: visual)) { |
195 | cascadingSectionSize.insert(key: visual, value: size); |
196 | firstCascadingSection = qMin(a: firstCascadingSection, b: visual); |
197 | lastCascadingSection = qMax(a: lastCascadingSection, b: visual); |
198 | } |
199 | } |
200 | |
201 | inline bool sectionIsCascadable(int visual) const { |
202 | return headerSectionResizeMode(visual) == QHeaderView::Interactive; |
203 | } |
204 | |
205 | inline int modelSectionCount() const { |
206 | return (orientation == Qt::Horizontal |
207 | ? model->columnCount(parent: root) |
208 | : model->rowCount(parent: root)); |
209 | } |
210 | |
211 | inline void doDelayedResizeSections() { |
212 | if (!delayedResize.isActive()) |
213 | delayedResize.start(msec: 0, obj: q_func()); |
214 | } |
215 | |
216 | inline void executePostedResize() const { |
217 | if (delayedResize.isActive() && state == NoState) { |
218 | const_cast<QHeaderView*>(q_func())->resizeSections(); |
219 | } |
220 | } |
221 | |
222 | inline void disconnectModel() |
223 | { |
224 | for (const QMetaObject::Connection &connection : modelConnections) |
225 | QObject::disconnect(connection); |
226 | } |
227 | |
228 | void clear(); |
229 | void flipSortIndicator(int section); |
230 | Qt::SortOrder defaultSortOrderForSection(int section) const; |
231 | void cascadingResize(int visual, int newSize); |
232 | |
233 | enum State { NoState, ResizeSection, MoveSection, SelectSections, NoClear } state; |
234 | |
235 | int headerOffset; |
236 | Qt::Orientation orientation; |
237 | Qt::SortOrder sortIndicatorOrder; |
238 | int sortIndicatorSection; |
239 | bool sortIndicatorShown; |
240 | bool sortIndicatorClearable; |
241 | |
242 | mutable QList<int> visualIndices; // visualIndex = visualIndices.at(logicalIndex) |
243 | mutable QList<int> logicalIndices; // logicalIndex = row or column in the model |
244 | mutable QBitArray sectionSelected; // from logical index to bit |
245 | mutable QHash<int, int> hiddenSectionSize; // from logical index to section size |
246 | mutable QHash<int, int> cascadingSectionSize; // from visual index to section size |
247 | mutable QSize cachedSizeHint; |
248 | mutable QBasicTimer delayedResize; |
249 | |
250 | int firstCascadingSection; |
251 | int lastCascadingSection; |
252 | |
253 | int lastPos; |
254 | int firstPos; |
255 | int originalSize; |
256 | int section; // used for resizing and moving sections |
257 | int target; |
258 | int firstPressed; |
259 | int pressed; |
260 | int hover; |
261 | |
262 | int length; |
263 | bool preventCursorChangeInSetOffset; |
264 | bool movableSections; |
265 | bool clickableSections; |
266 | bool highlightSelected; |
267 | bool stretchLastSection; |
268 | bool cascadingResizing; |
269 | bool resizeRecursionBlock; |
270 | bool allowUserMoveOfSection0; |
271 | bool customDefaultSectionSize; |
272 | int stretchSections; |
273 | int contentsSections; |
274 | int defaultSectionSize; |
275 | int oldDefaultSectionSize = -1; |
276 | int minimumSectionSize; |
277 | int maximumSectionSize; |
278 | int lastSectionSize; |
279 | int lastSectionLogicalIdx; // Only trust if we stretch LastSection |
280 | int sectionIndicatorOffset; |
281 | Qt::Alignment defaultAlignment; |
282 | #if QT_CONFIG(label) |
283 | QLabel *sectionIndicator; |
284 | #endif |
285 | QHeaderView::ResizeMode globalResizeMode; |
286 | mutable bool sectionStartposRecalc; |
287 | int resizeContentsPrecision; |
288 | // header sections |
289 | |
290 | struct SectionItem { |
291 | uint size : 20; |
292 | uint isHidden : 1; |
293 | uint resizeMode : 5; // (holding QHeaderView::ResizeMode) |
294 | uint currentlyUnusedPadding : 6; |
295 | |
296 | union { // This union is made in order to save space and ensure good vector performance (on remove) |
297 | mutable int calculated_startpos; // <- this is the primary used member. |
298 | mutable int tmpLogIdx; // When one of these 'tmp'-members has been used we call |
299 | int tmpDataStreamSectionCount; // recalcSectionStartPos() or set sectionStartposRecalc to true |
300 | }; // to ensure that calculated_startpos will be calculated afterwards. |
301 | |
302 | inline SectionItem() : size(0), isHidden(0), resizeMode(QHeaderView::Interactive) {} |
303 | inline SectionItem(int length, QHeaderView::ResizeMode mode) |
304 | : size(length), isHidden(0), resizeMode(mode), calculated_startpos(-1) {} |
305 | inline int sectionSize() const { return size; } |
306 | inline int calculatedEndPos() const { return calculated_startpos + size; } |
307 | #ifndef QT_NO_DATASTREAM |
308 | inline void write(QDataStream &out) const |
309 | { out << static_cast<int>(size); out << 1; out << (int)resizeMode; } |
310 | inline void read(QDataStream &in) |
311 | { int m; in >> m; size = m; in >> tmpDataStreamSectionCount; in >> m; resizeMode = m; } |
312 | #endif |
313 | }; |
314 | |
315 | QList<SectionItem> sectionItems; |
316 | struct LayoutChangeItem { |
317 | QPersistentModelIndex index; |
318 | SectionItem section; |
319 | }; |
320 | QList<LayoutChangeItem> layoutChangePersistentSections; |
321 | std::array<QMetaObject::Connection, 8> modelConnections; |
322 | |
323 | void createSectionItems(int start, int end, int sectionSize, QHeaderView::ResizeMode mode); |
324 | void removeSectionsFromSectionItems(int start, int end); |
325 | void resizeSectionItem(int visualIndex, int oldSize, int newSize); |
326 | void setDefaultSectionSize(int size); |
327 | void updateDefaultSectionSizeFromStyle(); |
328 | void recalcSectionStartPos() const; // not really const |
329 | |
330 | inline int headerLength() const { // for debugging |
331 | int len = 0; |
332 | for (const auto §ion : sectionItems) |
333 | len += section.size; |
334 | return len; |
335 | } |
336 | |
337 | QBitArray sectionsHiddenToBitVector() const |
338 | { |
339 | QBitArray sectionHidden; |
340 | if (!hiddenSectionSize.isEmpty()) { |
341 | sectionHidden.resize(size: sectionItems.size()); |
342 | for (int u = 0; u < sectionItems.size(); ++u) |
343 | sectionHidden[u] = sectionItems.at(i: u).isHidden; |
344 | } |
345 | return sectionHidden; |
346 | } |
347 | |
348 | void setHiddenSectionsFromBitVector(const QBitArray §ionHidden) { |
349 | SectionItem *sectionData = sectionItems.data(); |
350 | for (int i = 0; i < sectionHidden.size(); ++i) |
351 | sectionData[i].isHidden = sectionHidden.at(i); |
352 | } |
353 | |
354 | int headerSectionSize(int visual) const; |
355 | int headerSectionPosition(int visual) const; |
356 | int headerVisualIndexAt(int position) const; |
357 | |
358 | // resize mode |
359 | void setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode); |
360 | QHeaderView::ResizeMode headerSectionResizeMode(int visual) const; |
361 | void setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode); |
362 | |
363 | // other |
364 | int viewSectionSizeHint(int logical) const; |
365 | int adjustedVisualIndex(int visualIndex) const; |
366 | void setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode); |
367 | void updateSectionsBeforeAfter(int logical); |
368 | |
369 | #ifndef QT_NO_DATASTREAM |
370 | void write(QDataStream &out) const; |
371 | bool read(QDataStream &in); |
372 | #endif |
373 | |
374 | }; |
375 | Q_DECLARE_TYPEINFO(QHeaderViewPrivate::SectionItem, Q_PRIMITIVE_TYPE); |
376 | Q_DECLARE_TYPEINFO(QHeaderViewPrivate::LayoutChangeItem, Q_RELOCATABLE_TYPE); |
377 | |
378 | QT_END_NAMESPACE |
379 | |
380 | #endif // QHEADERVIEW_P_H |
381 |
Definitions
- QHeaderViewPrivate
- StateVersion
- QHeaderViewPrivate
- rowIntersectsSelection
- columnIntersectsSelection
- sectionIntersectsSelection
- isRowSelected
- isColumnSelected
- prepareSectionSelected
- sectionCount
- reverse
- logicalIndex
- visualIndex
- setDefaultValues
- isVisualIndexHidden
- setVisualIndexHidden
- hasAutoResizeSections
- invalidateCachedSizeHint
- initializeIndexMapping
- clearCascadingSections
- saveCascadingSectionSize
- sectionIsCascadable
- modelSectionCount
- doDelayedResizeSections
- executePostedResize
- disconnectModel
- State
- SectionItem
- SectionItem
- SectionItem
- sectionSize
- calculatedEndPos
- write
- read
- LayoutChangeItem
- headerLength
- sectionsHiddenToBitVector
Start learning QML with our Intro Training
Find out more