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 §ion : 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 §ionHidden) { 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