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

source code of qtbase/src/widgets/itemviews/qheaderview_p.h