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