1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qheaderview.h"
44 #ifndef QT_NO_ITEMVIEWS
45 #include <qbitarray.h>
50 #include <qscrollbar.h>
52 #include <qwhatsthis.h>
54 #include <qstyleoption.h>
56 #include <qapplication.h>
57 #include <qvarlengtharray.h>
58 #include <qabstractitemdelegate.h>
60 #include <private/qheaderview_p.h>
61 #include <private/qabstractitemmodel_p.h>
63 #ifndef QT_NO_DATASTREAM
64 #include <qdatastream.h>
69 #ifndef QT_NO_DATASTREAM
70 QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionItem §ion)
76 QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionItem §ion)
81 #endif // QT_NO_DATASTREAM
87 \brief The QHeaderView class provides a header row or header column for
93 A QHeaderView displays the headers used in item views such as the
94 QTableView and QTreeView classes. It takes the place of Qt3's \c QHeader
95 class previously used for the same purpose, but uses the Qt's model/view
96 architecture for consistency with the item view classes.
98 The QHeaderView class is one of the \l{Model/View Classes} and is part of
99 Qt's \l{Model/View Programming}{model/view framework}.
101 The header gets the data for each section from the model using the
102 QAbstractItemModel::headerData() function. You can set the data by using
103 QAbstractItemModel::setHeaderData().
105 Each header has an orientation() and a number of sections, given by the
106 count() function. A section refers to a part of the header - either a row
107 or a column, depending on the orientation.
109 Sections can be moved and resized using moveSection() and resizeSection();
110 they can also be hidden and shown with hideSection() and showSection().
112 Each section of a header is described by a section ID, specified by its
113 section(), and can be located at a particular visualIndex() in the header.
114 A section can have a sort indicator set with setSortIndicator(); this
115 indicates whether the items in the associated item view will be sorted in
116 the order given by the section.
118 For a horizontal header the section is equivalent to a column in the model,
119 and for a vertical header the section is equivalent to a row in the model.
121 \section1 Moving Header Sections
123 A header can be fixed in place, or made movable with setSectionsMovable(). It can
124 be made clickable with setSectionsClickable(), and has resizing behavior in
125 accordance with setSectionResizeMode()
127 \note Double-clicking on a header to resize a section only applies for
130 A header will emit sectionMoved() if the user moves a section,
131 sectionResized() if the user resizes a section, and sectionClicked() as
132 well as sectionHandleDoubleClicked() in response to mouse clicks. A header
133 will also emit sectionCountChanged().
135 You can identify a section using the logicalIndex() and logicalIndexAt()
136 functions, or by its index position, using the visualIndex() and
137 visualIndexAt() functions. The visual index will change if a section is
138 moved, but the logical index will not change.
142 QTableWidget and QTableView create default headers. If you want
143 the headers to be visible, you can use \l{QFrame::}{setVisible()}.
145 Not all \l{Qt::}{ItemDataRole}s will have an effect on a
146 QHeaderView. If you need to draw other roles, you can subclass
147 QHeaderView and reimplement \l{QHeaderView::}{paintEvent()}.
148 QHeaderView respects the following item data roles:
149 \l{Qt::}{TextAlignmentRole}, \l{Qt::}{DisplayRole},
150 \l{Qt::}{FontRole}, \l{Qt::}{DecorationRole},
151 \l{Qt::}{ForegroundRole}, and \l{Qt::}{BackgroundRole}.
153 \note Each header renders the data for each section itself, and does not
154 rely on a delegate. As a result, calling a header's setItemDelegate()
155 function will have no effect.
157 \sa {Model/View Programming}, QListView, QTableView, QTreeView
161 \enum QHeaderView::ResizeMode
163 The resize mode specifies the behavior of the header sections. It can be
164 set on the entire header view or on individual sections using
165 setSectionResizeMode().
167 \value Interactive The user can resize the section. The section can also be
168 resized programmatically using resizeSection(). The section size
169 defaults to \l defaultSectionSize. (See also
170 \l cascadingSectionResizes.)
172 \value Fixed The user cannot resize the section. The section can only be
173 resized programmatically using resizeSection(). The section size
174 defaults to \l defaultSectionSize.
176 \value Stretch QHeaderView will automatically resize the section to fill
177 the available space. The size cannot be changed by the user or
180 \value ResizeToContents QHeaderView will automatically resize the section
181 to its optimal size based on the contents of the entire column or
182 row. The size cannot be changed by the user or programmatically.
183 (This value was introduced in 4.2)
185 The following values are obsolete:
186 \value Custom Use Fixed instead.
188 \sa setResizeMode(), setSectionResizeMode(), stretchLastSection, minimumSectionSize
192 \fn void QHeaderView::sectionMoved(int logicalIndex, int oldVisualIndex,
195 This signal is emitted when a section is moved. The section's logical index
196 is specified by \a logicalIndex, the old index by \a oldVisualIndex, and
197 the new index position by \a newVisualIndex.
203 \fn void QHeaderView::sectionResized(int logicalIndex, int oldSize,
206 This signal is emitted when a section is resized. The section's logical
207 number is specified by \a logicalIndex, the old size by \a oldSize, and the
208 new size by \a newSize.
214 \fn void QHeaderView::sectionPressed(int logicalIndex)
216 This signal is emitted when a section is pressed. The section's logical
217 index is specified by \a logicalIndex.
219 \sa setSectionsClickable()
223 \fn void QHeaderView::sectionClicked(int logicalIndex)
225 This signal is emitted when a section is clicked. The section's logical
226 index is specified by \a logicalIndex.
228 Note that the sectionPressed signal will also be emitted.
230 \sa setSectionsClickable(), sectionPressed()
234 \fn void QHeaderView::sectionEntered(int logicalIndex)
237 This signal is emitted when the cursor moves over the section and the left
238 mouse button is pressed. The section's logical index is specified by
241 \sa setSectionsClickable(), sectionPressed()
245 \fn void QHeaderView::sectionDoubleClicked(int logicalIndex)
247 This signal is emitted when a section is double-clicked. The section's
248 logical index is specified by \a logicalIndex.
250 \sa setSectionsClickable()
254 \fn void QHeaderView::sectionCountChanged(int oldCount, int newCount)
256 This signal is emitted when the number of sections changes, i.e., when
257 sections are added or deleted. The original count is specified by
258 \a oldCount, and the new count by \a newCount.
260 \sa count(), length(), headerDataChanged()
264 \fn void QHeaderView::sectionHandleDoubleClicked(int logicalIndex)
266 This signal is emitted when a section is double-clicked. The section's
267 logical index is specified by \a logicalIndex.
269 \sa setSectionsClickable()
273 \fn void QHeaderView::sortIndicatorChanged(int logicalIndex,
277 This signal is emitted when the section containing the sort indicator or
278 the order indicated is changed. The section's logical index is specified
279 by \a logicalIndex and the sort order is specified by \a order.
281 \sa setSortIndicator()
285 \fn void QHeaderView::geometriesChanged()
288 This signal is emitted when the header's geometries have changed.
292 \property QHeaderView::highlightSections
293 \brief whether the sections containing selected items are highlighted
295 By default, this property is false.
299 Creates a new generic header with the given \a orientation and \a parent.
301 QHeaderView::QHeaderView(Qt::Orientation orientation, QWidget *parent)
302 : QAbstractItemView(*new QHeaderViewPrivate, parent)
305 d->setDefaultValues(orientation);
312 QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
313 Qt::Orientation orientation, QWidget *parent)
314 : QAbstractItemView(dd, parent)
317 d->setDefaultValues(orientation);
325 QHeaderView::~QHeaderView()
332 void QHeaderView::initialize()
335 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
336 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
337 setFrameStyle(NoFrame);
338 setFocusPolicy(Qt::NoFocus);
339 d->viewport->setMouseTracking(true);
340 d->viewport->setBackgroundRole(QPalette::Button);
341 d->textElideMode = Qt::ElideNone;
342 delete d->itemDelegate;
348 void QHeaderView::setModel(QAbstractItemModel *model)
350 if (model == this->model())
353 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
354 if (d->orientation == Qt::Horizontal) {
355 QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
356 this, SLOT(sectionsInserted(QModelIndex,int,int)));
357 QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
358 this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
359 QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
360 this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
361 QObject::disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
362 this, SLOT(_q_layoutAboutToBeChanged()));
364 QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
365 this, SLOT(sectionsInserted(QModelIndex,int,int)));
366 QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
367 this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
368 QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
369 this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
370 QObject::disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
371 this, SLOT(_q_layoutAboutToBeChanged()));
373 QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
374 this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
375 QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
376 this, SLOT(_q_layoutAboutToBeChanged()));
379 if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
380 if (d->orientation == Qt::Horizontal) {
381 QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
382 this, SLOT(sectionsInserted(QModelIndex,int,int)));
383 QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
384 this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
385 QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
386 this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
387 QObject::connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
388 this, SLOT(_q_layoutAboutToBeChanged()));
390 QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
391 this, SLOT(sectionsInserted(QModelIndex,int,int)));
392 QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
393 this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
394 QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
395 this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
396 QObject::connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
397 this, SLOT(_q_layoutAboutToBeChanged()));
399 QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
400 this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
401 QObject::connect(model, SIGNAL(layoutAboutToBeChanged()),
402 this, SLOT(_q_layoutAboutToBeChanged()));
405 d->state = QHeaderViewPrivate::NoClear;
406 QAbstractItemView::setModel(model);
407 d->state = QHeaderViewPrivate::NoState;
409 // Users want to set sizes and modes before the widget is shown.
410 // Thus, we have to initialize when the model is set,
411 // and not lazily like we do in the other views.
412 initializeSections();
416 Returns the orientation of the header.
421 Qt::Orientation QHeaderView::orientation() const
423 Q_D(const QHeaderView);
424 return d->orientation;
428 Returns the offset of the header: this is the header's left-most (or
429 top-most for vertical headers) visible pixel.
434 int QHeaderView::offset() const
436 Q_D(const QHeaderView);
441 \fn void QHeaderView::setOffset(int offset)
443 Sets the header's offset to \a offset.
445 \sa offset(), length()
448 void QHeaderView::setOffset(int newOffset)
451 if (d->offset == (int)newOffset)
453 int ndelta = d->offset - newOffset;
454 d->offset = newOffset;
455 if (d->orientation == Qt::Horizontal)
456 d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
458 d->viewport->scroll(0, ndelta);
459 if (d->state == QHeaderViewPrivate::ResizeSection && !d->preventCursorChangeInSetOffset) {
460 QPoint cursorPos = QCursor::pos();
461 if (d->orientation == Qt::Horizontal)
462 QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
464 QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
465 d->firstPos += ndelta;
466 d->lastPos += ndelta;
472 Sets the offset to the start of the section at the given \a visualSectionNumber.
473 \a visualSectionNumber is the actual visible section when hiddenSections are
474 not considered. That is not always the same as visualIndex().
476 \sa setOffset(), sectionPosition()
478 void QHeaderView::setOffsetToSectionPosition(int visualSectionNumber)
481 if (visualSectionNumber > -1 && visualSectionNumber < d->sectionCount()) {
482 int position = d->headerSectionPosition(d->adjustedVisualIndex(visualSectionNumber));
489 Sets the offset to make the last section visible.
491 \sa setOffset(), sectionPosition(), setOffsetToSectionPosition()
493 void QHeaderView::setOffsetToLastSection()
495 Q_D(const QHeaderView);
496 int size = (d->orientation == Qt::Horizontal ? viewport()->width() : viewport()->height());
497 int position = length() - size;
502 Returns the length along the orientation of the header.
504 \sa sizeHint(), setSectionResizeMode(), offset()
507 int QHeaderView::length() const
509 Q_D(const QHeaderView);
510 d->executePostedLayout();
511 d->executePostedResize();
512 //Q_ASSERT(d->headerLength() == d->length);
517 Returns a suitable size hint for this header.
519 \sa sectionSizeHint()
522 QSize QHeaderView::sizeHint() const
524 Q_D(const QHeaderView);
525 if (d->cachedSizeHint.isValid())
526 return d->cachedSizeHint;
527 d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint
528 const int sectionCount = count();
530 // get size hint for the first n sections
532 for (int checked = 0; checked < 100 && i < sectionCount; ++i) {
533 if (isSectionHidden(i))
536 QSize hint = sectionSizeFromContents(i);
537 d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
539 // get size hint for the last n sections
540 i = qMax(i, sectionCount - 100 );
541 for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) {
542 if (isSectionHidden(j))
545 QSize hint = sectionSizeFromContents(j);
546 d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
548 return d->cachedSizeHint;
552 Returns a suitable size hint for the section specified by \a logicalIndex.
554 \sa sizeHint(), defaultSectionSize(), minimumSectionSize(),
558 int QHeaderView::sectionSizeHint(int logicalIndex) const
560 Q_D(const QHeaderView);
561 if (isSectionHidden(logicalIndex))
563 if (logicalIndex < 0 || logicalIndex >= count())
566 QVariant value = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
568 size = qvariant_cast<QSize>(value);
570 size = sectionSizeFromContents(logicalIndex);
571 int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
572 return qMax(minimumSectionSize(), hint);
576 Returns the visual index of the section that covers the given \a position
582 int QHeaderView::visualIndexAt(int position) const
584 Q_D(const QHeaderView);
585 int vposition = position;
586 d->executePostedLayout();
587 d->executePostedResize();
588 const int count = d->sectionCount();
593 vposition = d->viewport->width() - vposition;
594 vposition += d->offset;
596 if (vposition > d->length)
598 int visual = d->headerVisualIndexAt(vposition);
602 while (d->isVisualIndexHidden(visual)){
611 Returns the section that covers the given \a position in the viewport.
613 \sa visualIndexAt(), isSectionHidden()
616 int QHeaderView::logicalIndexAt(int position) const
618 const int visual = visualIndexAt(position);
620 return logicalIndex(visual);
625 Returns the width (or height for vertical headers) of the given
628 \sa length(), setSectionResizeMode(), defaultSectionSize()
631 int QHeaderView::sectionSize(int logicalIndex) const
633 Q_D(const QHeaderView);
634 if (isSectionHidden(logicalIndex))
636 if (logicalIndex < 0 || logicalIndex >= count())
638 int visual = visualIndex(logicalIndex);
641 d->executePostedResize();
642 return d->headerSectionSize(visual);
647 Returns the section position of the given \a logicalIndex, or -1
648 if the section is hidden. The position is measured in pixels from
649 the first visible item's top-left corner to the top-left corner of
650 the item with \a logicalIndex. The measurement is along the x-axis
651 for horizontal headers and along the y-axis for vertical headers.
653 \sa sectionViewportPosition()
656 int QHeaderView::sectionPosition(int logicalIndex) const
658 Q_D(const QHeaderView);
659 int visual = visualIndex(logicalIndex);
660 // in some cases users may change the selections
661 // before we have a chance to do the layout
664 d->executePostedResize();
665 return d->headerSectionPosition(visual);
669 Returns the section viewport position of the given \a logicalIndex.
671 If the section is hidden, the return value is undefined.
673 \sa sectionPosition(), isSectionHidden()
676 int QHeaderView::sectionViewportPosition(int logicalIndex) const
678 Q_D(const QHeaderView);
679 if (logicalIndex >= count())
681 int position = sectionPosition(logicalIndex);
683 return position; // the section was hidden
684 int offsetPosition = position - d->offset;
686 return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
687 return offsetPosition;
691 \fn int QHeaderView::logicalIndexAt(int x, int y) const
693 Returns the logical index of the section at the given coordinate. If the
694 header is horizontal \a x will be used, otherwise \a y will be used to
695 find the logical index.
699 \fn int QHeaderView::logicalIndexAt(const QPoint &pos) const
701 Returns the logical index of the section at the position given in \a pos.
702 If the header is horizontal the x-coordinate will be used, otherwise the
703 y-coordinate will be used to find the logical index.
705 \sa sectionPosition()
709 Moves the section at visual index \a from to occupy visual index \a to.
714 void QHeaderView::moveSection(int from, int to)
718 d->executePostedLayout();
719 if (from < 0 || from >= d->sectionCount() || to < 0 || to >= d->sectionCount())
723 int logical = logicalIndex(from);
724 Q_ASSERT(logical != -1);
725 updateSection(logical);
729 if (stretchLastSection() && to == d->lastVisibleVisualIndex())
730 d->lastSectionSize = sectionSize(from);
732 //int oldHeaderLength = length(); // ### for debugging; remove later
733 d->initializeIndexMapping();
735 QBitArray sectionHidden = d->sectionHidden;
736 int *visualIndices = d->visualIndices.data();
737 int *logicalIndices = d->logicalIndices.data();
738 int logical = logicalIndices[from];
741 int affected_count = qAbs(to - from) + 1;
742 QVarLengthArray<int> sizes(affected_count);
743 QVarLengthArray<ResizeMode> modes(affected_count);
745 // move sections and indices
747 sizes[to - from] = d->headerSectionSize(from);
748 modes[to - from] = d->headerSectionResizeMode(from);
749 while (visual < to) {
750 sizes[visual - from] = d->headerSectionSize(visual + 1);
751 modes[visual - from] = d->headerSectionResizeMode(visual + 1);
752 if (!sectionHidden.isEmpty())
753 sectionHidden.setBit(visual, sectionHidden.testBit(visual + 1));
754 visualIndices[logicalIndices[visual + 1]] = visual;
755 logicalIndices[visual] = logicalIndices[visual + 1];
759 sizes[0] = d->headerSectionSize(from);
760 modes[0] = d->headerSectionResizeMode(from);
761 while (visual > to) {
762 sizes[visual - to] = d->headerSectionSize(visual - 1);
763 modes[visual - to] = d->headerSectionResizeMode(visual - 1);
764 if (!sectionHidden.isEmpty())
765 sectionHidden.setBit(visual, sectionHidden.testBit(visual - 1));
766 visualIndices[logicalIndices[visual - 1]] = visual;
767 logicalIndices[visual] = logicalIndices[visual - 1];
771 if (!sectionHidden.isEmpty()) {
772 sectionHidden.setBit(to, d->sectionHidden.testBit(from));
773 d->sectionHidden = sectionHidden;
775 visualIndices[logical] = to;
776 logicalIndices[to] = logical;
778 //Q_ASSERT(oldHeaderLength == length());
780 // ### check for items of section sizes here
782 for (visual = from; visual <= to; ++visual) {
783 int size = sizes[visual - from];
784 ResizeMode mode = modes[visual - from];
785 d->createSectionItems(visual, visual, size, mode);
788 for (visual = to; visual <= from; ++visual) {
789 int size = sizes[visual - to];
790 ResizeMode mode = modes[visual - to];
791 d->createSectionItems(visual, visual, size, mode);
794 //Q_ASSERT(d->headerLength() == length());
795 //Q_ASSERT(oldHeaderLength == length());
796 //Q_ASSERT(d->logicalIndices.count() == d->sectionCount);
798 if (d->hasAutoResizeSections())
799 d->doDelayedResizeSections();
800 d->viewport->update();
802 emit sectionMoved(logical, from, to);
807 Swaps the section at visual index \a first with the section at visual
812 void QHeaderView::swapSections(int first, int second)
818 d->executePostedLayout();
819 if (first < 0 || first >= d->sectionCount() || second < 0 || second >= d->sectionCount())
822 int firstSize = d->headerSectionSize(first);
823 ResizeMode firstMode = d->headerSectionResizeMode(first);
824 int firstLogical = d->logicalIndex(first);
826 int secondSize = d->headerSectionSize(second);
827 ResizeMode secondMode = d->headerSectionResizeMode(second);
828 int secondLogical = d->logicalIndex(second);
830 if (d->state == QHeaderViewPrivate::ResizeSection)
831 d->preventCursorChangeInSetOffset = true;
833 d->createSectionItems(second, second, firstSize, firstMode);
834 d->createSectionItems(first, first, secondSize, secondMode);
836 d->initializeIndexMapping();
838 d->visualIndices[firstLogical] = second;
839 d->logicalIndices[second] = firstLogical;
841 d->visualIndices[secondLogical] = first;
842 d->logicalIndices[first] = secondLogical;
844 if (!d->sectionHidden.isEmpty()) {
845 bool firstHidden = d->sectionHidden.testBit(first);
846 bool secondHidden = d->sectionHidden.testBit(second);
847 d->sectionHidden.setBit(first, secondHidden);
848 d->sectionHidden.setBit(second, firstHidden);
851 d->viewport->update();
852 emit sectionMoved(firstLogical, first, second);
853 emit sectionMoved(secondLogical, second, first);
857 \fn void QHeaderView::resizeSection(int logicalIndex, int size)
859 Resizes the section specified by \a logicalIndex to \a size measured in
860 pixels. The size parameter must be a value larger or equal to zero. A
861 size equal to zero is however not recommended. In that situation hideSection
862 should be used instead.
864 \sa sectionResized(), resizeMode(), sectionSize(), hideSection()
867 void QHeaderView::resizeSection(int logical, int size)
870 if (logical < 0 || logical >= count() || size < 0)
873 if (isSectionHidden(logical)) {
874 d->hiddenSectionSize.insert(logical, size);
878 int visual = visualIndex(logical);
882 if (d->state == QHeaderViewPrivate::ResizeSection && !d->cascadingResizing && logical != d->section)
883 d->preventCursorChangeInSetOffset = true;
885 int oldSize = d->headerSectionSize(visual);
889 d->executePostedLayout();
890 d->invalidateCachedSizeHint();
892 if (stretchLastSection() && visual == d->lastVisibleVisualIndex())
893 d->lastSectionSize = size;
895 d->createSectionItems(visual, visual, size, d->headerSectionResizeMode(visual));
897 if (!updatesEnabled()) {
898 if (d->hasAutoResizeSections())
899 d->doDelayedResizeSections();
900 emit sectionResized(logical, oldSize, size);
904 int w = d->viewport->width();
905 int h = d->viewport->height();
906 int pos = sectionViewportPosition(logical);
908 if (d->orientation == Qt::Horizontal)
910 r.setRect(0, 0, pos + size, h);
912 r.setRect(pos, 0, w - pos, h);
914 r.setRect(0, pos, w, h - pos);
916 if (d->hasAutoResizeSections()) {
917 d->doDelayedResizeSections();
918 r = d->viewport->rect();
920 d->viewport->update(r.normalized());
921 emit sectionResized(logical, oldSize, size);
925 Resizes the sections according to the given \a mode, ignoring the current
928 \sa resizeMode(), sectionResized()
931 void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
934 d->resizeSections(mode, true);
938 \fn void QHeaderView::hideSection(int logicalIndex)
939 Hides the section specified by \a logicalIndex.
941 \sa showSection(), isSectionHidden(), hiddenSectionCount(),
946 \fn void QHeaderView::showSection(int logicalIndex)
947 Shows the section specified by \a logicalIndex.
949 \sa hideSection(), isSectionHidden(), hiddenSectionCount(),
954 Returns true if the section specified by \a logicalIndex is explicitly
955 hidden from the user; otherwise returns false.
957 \sa hideSection(), showSection(), setSectionHidden(), hiddenSectionCount()
960 bool QHeaderView::isSectionHidden(int logicalIndex) const
962 Q_D(const QHeaderView);
963 d->executePostedLayout();
964 if (logicalIndex >= d->sectionHidden.count() || logicalIndex < 0 || logicalIndex >= d->sectionCount())
966 int visual = visualIndex(logicalIndex);
967 Q_ASSERT(visual != -1);
968 return d->sectionHidden.testBit(visual);
974 Returns the number of sections in the header that has been hidden.
976 \sa setSectionHidden(), isSectionHidden()
978 int QHeaderView::hiddenSectionCount() const
980 Q_D(const QHeaderView);
981 return d->hiddenSectionSize.count();
985 If \a hide is true the section specified by \a logicalIndex is hidden;
986 otherwise the section is shown.
988 \sa isSectionHidden(), hiddenSectionCount()
991 void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
994 if (logicalIndex < 0 || logicalIndex >= count())
997 d->executePostedLayout();
998 int visual = visualIndex(logicalIndex);
999 Q_ASSERT(visual != -1);
1000 if (hide == d->isVisualIndexHidden(visual))
1003 int size = d->headerSectionSize(visual);
1004 if (!d->hasAutoResizeSections())
1005 resizeSection(logicalIndex, 0);
1006 d->hiddenSectionSize.insert(logicalIndex, size);
1007 if (d->sectionHidden.count() < count())
1008 d->sectionHidden.resize(count());
1009 d->sectionHidden.setBit(visual, true);
1010 if (d->hasAutoResizeSections())
1011 d->doDelayedResizeSections();
1013 int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
1014 d->hiddenSectionSize.remove(logicalIndex);
1015 if (d->hiddenSectionSize.isEmpty()) {
1016 d->sectionHidden.clear();
1018 Q_ASSERT(visual <= d->sectionHidden.count());
1019 d->sectionHidden.setBit(visual, false);
1021 resizeSection(logicalIndex, size);
1026 Returns the number of sections in the header.
1028 \sa sectionCountChanged(), length()
1031 int QHeaderView::count() const
1033 Q_D(const QHeaderView);
1034 //Q_ASSERT(d->sectionCount == d->headerSectionCount());
1035 // ### this may affect the lazy layout
1036 d->executePostedLayout();
1037 return d->sectionCount();
1041 Returns the visual index position of the section specified by the given
1042 \a logicalIndex, or -1 otherwise.
1044 Hidden sections still have valid visual indexes.
1049 int QHeaderView::visualIndex(int logicalIndex) const
1051 Q_D(const QHeaderView);
1052 if (logicalIndex < 0)
1054 d->executePostedLayout();
1055 if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
1056 if (logicalIndex < d->sectionCount())
1057 return logicalIndex;
1058 } else if (logicalIndex < d->visualIndices.count()) {
1059 int visual = d->visualIndices.at(logicalIndex);
1060 Q_ASSERT(visual < d->sectionCount());
1067 Returns the logicalIndex for the section at the given \a visualIndex
1068 position, or -1 if visualIndex < 0 or visualIndex >= QHeaderView::count().
1070 Note that the visualIndex is not affected by hidden sections.
1072 \sa visualIndex(), sectionPosition()
1075 int QHeaderView::logicalIndex(int visualIndex) const
1077 Q_D(const QHeaderView);
1078 if (visualIndex < 0 || visualIndex >= d->sectionCount())
1080 return d->logicalIndex(visualIndex);
1084 If \a movable is true, the header may be moved by the user; otherwise it
1087 \sa sectionsMovable(), sectionMoved()
1090 void QHeaderView::setSectionsMovable(bool movable)
1093 d->movableSections = movable;
1096 // ### Qt 6 - remove this obsolete function
1099 \fn void QHeaderView::setMovable(bool movable)
1101 Use setSectionsMovable instead.
1103 \sa setSectionsMovable()
1107 Returns true if the header can be moved by the user; otherwise returns
1110 \sa setSectionsMovable()
1113 bool QHeaderView::sectionsMovable() const
1115 Q_D(const QHeaderView);
1116 return d->movableSections;
1119 // ### Qt 6 - remove this obsolete function
1122 \fn bool QHeaderView::isMovable() const
1124 Use sectionsMovable instead.
1126 \sa sectionsMovable()
1130 If \a clickable is true, the header will respond to single clicks.
1132 \sa sectionsClickable(), sectionClicked(), sectionPressed(),
1133 setSortIndicatorShown()
1136 void QHeaderView::setSectionsClickable(bool clickable)
1139 d->clickableSections = clickable;
1142 // ### Qt 6 - remove this obsolete function
1145 \fn void QHeaderView::setClickable(bool clickable)
1147 Use setSectionsClickable instead.
1149 \sa setSectionsClickable()
1153 Returns true if the header is clickable; otherwise returns false. A
1154 clickable header could be set up to allow the user to change the
1155 representation of the data in the view related to the header.
1157 \sa setSectionsClickable()
1160 bool QHeaderView::sectionsClickable() const
1162 Q_D(const QHeaderView);
1163 return d->clickableSections;
1166 // ### Qt 6 - remove this obsolete function
1169 \fn bool QHeaderView::isClickable() const
1171 Use sectionsClickable instead.
1173 \sa sectionsClickable()
1176 void QHeaderView::setHighlightSections(bool highlight)
1179 d->highlightSelected = highlight;
1182 bool QHeaderView::highlightSections() const
1184 Q_D(const QHeaderView);
1185 return d->highlightSelected;
1189 Sets the constraints on how the header can be resized to those described
1190 by the given \a mode.
1192 \sa resizeMode(), length(), sectionResized()
1195 void QHeaderView::setSectionResizeMode(ResizeMode mode)
1198 initializeSections();
1199 d->stretchSections = (mode == Stretch ? count() : 0);
1200 d->contentsSections = (mode == ResizeToContents ? count() : 0);
1201 d->setGlobalHeaderResizeMode(mode);
1202 if (d->hasAutoResizeSections())
1203 d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1207 Sets the constraints on how the section specified by \a logicalIndex in
1208 the header can be resized to those described by the given \a mode. The logical
1209 index should exist at the time this function is called.
1211 \note This setting will be ignored for the last section if the stretchLastSection
1212 property is set to true. This is the default for the horizontal headers provided
1215 \sa setStretchLastSection()
1218 void QHeaderView::setSectionResizeMode(int logicalIndex, ResizeMode mode)
1221 int visual = visualIndex(logicalIndex);
1222 Q_ASSERT(visual != -1);
1224 ResizeMode old = d->headerSectionResizeMode(visual);
1225 d->setHeaderSectionResizeMode(visual, mode);
1227 if (mode == Stretch && old != Stretch)
1228 ++d->stretchSections;
1229 else if (mode == ResizeToContents && old != ResizeToContents)
1230 ++d->contentsSections;
1231 else if (mode != Stretch && old == Stretch)
1232 --d->stretchSections;
1233 else if (mode != ResizeToContents && old == ResizeToContents)
1234 --d->contentsSections;
1236 if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
1237 d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1240 // ### Qt 6 - remove this obsolete function
1244 \fn void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
1246 Use setSectionResizeMode instead.
1248 \sa setSectionResizeMode()
1253 \fn void QHeaderView::setResizeMode(ResizeMode mode)
1255 Use setSectionResizeMode instead.
1257 \sa setSectionResizeMode()
1261 Returns the resize mode that applies to the section specified by the given
1264 \sa setSectionResizeMode()
1267 QHeaderView::ResizeMode QHeaderView::sectionResizeMode(int logicalIndex) const
1269 Q_D(const QHeaderView);
1270 int visual = visualIndex(logicalIndex);
1272 return Fixed; //the default value
1273 return d->headerSectionResizeMode(visual);
1276 // ### Qt 6 - remove this obsolete function
1279 \fn QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
1281 Use sectionResizeMode instead.
1283 \sa sectionResizeMode()
1289 Returns the number of sections that are set to resize mode stretch. In
1290 views, this can be used to see if the headerview needs to resize the
1291 sections when the view's geometry changes.
1293 \sa stretchLastSection, resizeMode()
1296 int QHeaderView::stretchSectionCount() const
1298 Q_D(const QHeaderView);
1299 return d->stretchSections;
1303 \property QHeaderView::showSortIndicator
1304 \brief whether the sort indicator is shown
1306 By default, this property is false.
1308 \sa setSectionsClickable()
1311 void QHeaderView::setSortIndicatorShown(bool show)
1314 if (d->sortIndicatorShown == show)
1317 d->sortIndicatorShown = show;
1319 if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
1322 if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
1325 d->viewport->update();
1328 bool QHeaderView::isSortIndicatorShown() const
1330 Q_D(const QHeaderView);
1331 return d->sortIndicatorShown;
1335 Sets the sort indicator for the section specified by the given
1336 \a logicalIndex in the direction specified by \a order, and removes the
1337 sort indicator from any other section that was showing it.
1339 \a logicalIndex may be -1, in which case no sort indicator will be shown
1340 and the model will return to its natural, unsorted order. Note that not
1341 all models support this and may even crash in this case.
1343 \sa sortIndicatorSection(), sortIndicatorOrder()
1346 void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
1350 // This is so that people can set the position of the sort indicator before the fill the model
1351 int old = d->sortIndicatorSection;
1352 if (old == logicalIndex && order == d->sortIndicatorOrder)
1354 d->sortIndicatorSection = logicalIndex;
1355 d->sortIndicatorOrder = order;
1357 if (logicalIndex >= d->sectionCount()) {
1358 emit sortIndicatorChanged(logicalIndex, order);
1359 return; // nothing to do
1362 if (old != logicalIndex
1363 && ((logicalIndex >= 0 && sectionResizeMode(logicalIndex) == ResizeToContents)
1364 || old >= d->sectionCount() || (old >= 0 && sectionResizeMode(old) == ResizeToContents))) {
1366 d->viewport->update();
1368 if (old >= 0 && old != logicalIndex)
1370 if (logicalIndex >= 0)
1371 updateSection(logicalIndex);
1374 emit sortIndicatorChanged(logicalIndex, order);
1378 Returns the logical index of the section that has a sort indicator.
1379 By default this is section 0.
1381 \sa setSortIndicator(), sortIndicatorOrder(), setSortIndicatorShown()
1384 int QHeaderView::sortIndicatorSection() const
1386 Q_D(const QHeaderView);
1387 return d->sortIndicatorSection;
1391 Returns the order for the sort indicator. If no section has a sort
1392 indicator the return value of this function is undefined.
1394 \sa setSortIndicator(), sortIndicatorSection()
1397 Qt::SortOrder QHeaderView::sortIndicatorOrder() const
1399 Q_D(const QHeaderView);
1400 return d->sortIndicatorOrder;
1404 \property QHeaderView::stretchLastSection
1405 \brief whether the last visible section in the header takes up all the
1408 The default value is false.
1410 \note The horizontal headers provided by QTreeView are configured with this
1411 property set to true, ensuring that the view does not waste any of the
1412 space assigned to it for its header. If this value is set to true, this
1413 property will override the resize mode set on the last section in the
1416 \sa setSectionResizeMode()
1418 bool QHeaderView::stretchLastSection() const
1420 Q_D(const QHeaderView);
1421 return d->stretchLastSection;
1424 void QHeaderView::setStretchLastSection(bool stretch)
1427 d->stretchLastSection = stretch;
1428 if (d->state != QHeaderViewPrivate::NoState)
1433 resizeSection(count() - 1, d->defaultSectionSize);
1438 \property QHeaderView::cascadingSectionResizes
1439 \brief whether interactive resizing will be cascaded to the following
1440 sections once the section being resized by the user has reached its
1443 This property only affects sections that have \l Interactive as their
1446 The default value is false.
1448 \sa setSectionResizeMode()
1450 bool QHeaderView::cascadingSectionResizes() const
1452 Q_D(const QHeaderView);
1453 return d->cascadingResizing;
1456 void QHeaderView::setCascadingSectionResizes(bool enable)
1459 d->cascadingResizing = enable;
1463 \property QHeaderView::defaultSectionSize
1464 \brief the default size of the header sections before resizing.
1466 This property only affects sections that have \l Interactive or \l Fixed
1467 as their resize mode.
1469 \sa setSectionResizeMode(), minimumSectionSize
1471 int QHeaderView::defaultSectionSize() const
1473 Q_D(const QHeaderView);
1474 return d->defaultSectionSize;
1477 void QHeaderView::setDefaultSectionSize(int size)
1482 d->setDefaultSectionSize(size);
1487 \property QHeaderView::minimumSectionSize
1488 \brief the minimum size of the header sections.
1490 The minimum section size is the smallest section size allowed. If the
1491 minimum section size is set to -1, QHeaderView will use the maximum of
1492 the \l{QApplication::globalStrut()}{global strut} or the
1493 \l{fontMetrics()}{font metrics} size.
1495 This property is honored by all \l{ResizeMode}{resize modes}.
1497 \sa setSectionResizeMode(), defaultSectionSize
1499 int QHeaderView::minimumSectionSize() const
1501 Q_D(const QHeaderView);
1502 if (d->minimumSectionSize == -1) {
1503 QSize strut = QApplication::globalStrut();
1504 int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
1505 if (d->orientation == Qt::Horizontal)
1506 return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
1507 return qMax(strut.height(), (fontMetrics().height() + margin));
1509 return d->minimumSectionSize;
1512 void QHeaderView::setMinimumSectionSize(int size)
1517 d->minimumSectionSize = size;
1522 \property QHeaderView::defaultAlignment
1523 \brief the default alignment of the text in each header section
1526 Qt::Alignment QHeaderView::defaultAlignment() const
1528 Q_D(const QHeaderView);
1529 return d->defaultAlignment;
1532 void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
1535 if (d->defaultAlignment == alignment)
1538 d->defaultAlignment = alignment;
1539 d->viewport->update();
1545 void QHeaderView::doItemsLayout()
1547 initializeSections();
1548 QAbstractItemView::doItemsLayout();
1552 Returns true if sections in the header has been moved; otherwise returns
1557 bool QHeaderView::sectionsMoved() const
1559 Q_D(const QHeaderView);
1560 return !d->visualIndices.isEmpty();
1566 Returns true if sections in the header has been hidden; otherwise returns
1569 \sa setSectionHidden()
1571 bool QHeaderView::sectionsHidden() const
1573 Q_D(const QHeaderView);
1574 return !d->hiddenSectionSize.isEmpty();
1577 #ifndef QT_NO_DATASTREAM
1581 Saves the current state of this header view.
1583 To restore the saved state, pass the return value to restoreState().
1587 QByteArray QHeaderView::saveState() const
1589 Q_D(const QHeaderView);
1591 QDataStream stream(&data, QIODevice::WriteOnly);
1592 stream << QHeaderViewPrivate::VersionMarker;
1593 stream << 0; // current version is 0
1600 Restores the \a state of this header view.
1601 This function returns \c true if the state was restored; otherwise returns
1606 bool QHeaderView::restoreState(const QByteArray &state)
1609 if (state.isEmpty())
1611 QByteArray data = state;
1612 QDataStream stream(&data, QIODevice::ReadOnly);
1617 if (stream.status() != QDataStream::Ok
1618 || marker != QHeaderViewPrivate::VersionMarker
1619 || ver != 0) // current version is 0
1622 if (d->read(stream)) {
1623 emit sortIndicatorChanged(d->sortIndicatorSection, d->sortIndicatorOrder );
1624 d->viewport->update();
1629 #endif // QT_NO_DATASTREAM
1634 void QHeaderView::reset()
1636 QAbstractItemView::reset();
1637 // it would be correct to call clear, but some apps rely
1638 // on the header keeping the sections, even after calling reset
1640 initializeSections();
1644 Updates the changed header sections with the given \a orientation, from
1645 \a logicalFirst to \a logicalLast inclusive.
1647 void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
1650 if (d->orientation != orientation)
1653 if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
1656 d->invalidateCachedSizeHint();
1658 int firstVisualIndex = INT_MAX, lastVisualIndex = -1;
1660 for (int section = logicalFirst; section <= logicalLast; ++section) {
1661 const int visual = visualIndex(section);
1662 firstVisualIndex = qMin(firstVisualIndex, visual);
1663 lastVisualIndex = qMax(lastVisualIndex, visual);
1666 d->executePostedResize();
1667 const int first = d->headerSectionPosition(firstVisualIndex),
1668 last = d->headerSectionPosition(lastVisualIndex)
1669 + d->headerSectionSize(lastVisualIndex);
1671 if (orientation == Qt::Horizontal) {
1672 d->viewport->update(first, 0, last - first, d->viewport->height());
1674 d->viewport->update(0, first, d->viewport->width(), last - first);
1682 Updates the section specified by the given \a logicalIndex.
1685 void QHeaderView::updateSection(int logicalIndex)
1688 if (d->orientation == Qt::Horizontal)
1689 d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
1690 0, sectionSize(logicalIndex), d->viewport->height()));
1692 d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
1693 d->viewport->width(), sectionSize(logicalIndex)));
1697 Resizes the sections according to their size hints. Normally, you do not
1698 have to call this function.
1701 void QHeaderView::resizeSections()
1704 if (d->hasAutoResizeSections())
1705 d->resizeSections(Interactive, false); // no global resize mode
1709 This slot is called when sections are inserted into the \a parent.
1710 \a logicalFirst and \a logicalLast indices signify where the new sections
1713 If only one section is inserted, \a logicalFirst and \a logicalLast will
1717 void QHeaderView::sectionsInserted(const QModelIndex &parent,
1718 int logicalFirst, int logicalLast)
1721 if (parent != d->root)
1722 return; // we only handle changes in the root level
1723 int oldCount = d->sectionCount();
1725 d->invalidateCachedSizeHint();
1727 if (d->state == QHeaderViewPrivate::ResizeSection)
1728 d->preventCursorChangeInSetOffset = true;
1730 // add the new sections
1731 int insertAt = logicalFirst;
1732 int insertCount = logicalLast - logicalFirst + 1;
1734 QHeaderViewPrivate::SectionItem section(d->defaultSectionSize, d->globalResizeMode);
1735 d->sectionStartposRecalc = true;
1737 if (d->sectionItems.isEmpty() || insertAt >= d->sectionItems.count()) {
1738 int insertLength = d->defaultSectionSize * insertCount;
1739 d->length += insertLength;
1740 d->sectionItems.insert(d->sectionItems.count(), insertCount, section); // append
1742 // separate them out into their own sections
1743 int insertLength = d->defaultSectionSize * insertCount;
1744 d->length += insertLength;
1745 d->sectionItems.insert(insertAt, insertCount, section);
1748 // update sorting column
1749 if (d->sortIndicatorSection >= logicalFirst)
1750 d->sortIndicatorSection += insertCount;
1752 // update resize mode section counts
1753 if (d->globalResizeMode == Stretch)
1754 d->stretchSections = d->sectionCount();
1755 else if (d->globalResizeMode == ResizeToContents)
1756 d->contentsSections = d->sectionCount();
1758 // clear selection cache
1759 d->sectionSelected.clear();
1762 if (!d->visualIndices.isEmpty() && !d->logicalIndices.isEmpty()) {
1763 Q_ASSERT(d->visualIndices.count() == d->logicalIndices.count());
1764 int mappingCount = d->visualIndices.count();
1765 for (int i = 0; i < mappingCount; ++i) {
1766 if (d->visualIndices.at(i) >= logicalFirst)
1767 d->visualIndices[i] += insertCount;
1768 if (d->logicalIndices.at(i) >= logicalFirst)
1769 d->logicalIndices[i] += insertCount;
1771 for (int j = logicalFirst; j <= logicalLast; ++j) {
1772 d->visualIndices.insert(j, j);
1773 d->logicalIndices.insert(j, j);
1777 // insert sections into sectionsHidden
1778 if (!d->sectionHidden.isEmpty()) {
1779 QBitArray sectionHidden(d->sectionHidden);
1780 sectionHidden.resize(sectionHidden.count() + insertCount);
1781 sectionHidden.fill(false, logicalFirst, logicalLast + 1);
1782 for (int j = logicalLast + 1; j < sectionHidden.count(); ++j)
1783 //here we simply copy the old sectionHidden
1784 sectionHidden.setBit(j, d->sectionHidden.testBit(j - insertCount));
1785 d->sectionHidden = sectionHidden;
1788 // insert sections into hiddenSectionSize
1789 QHash<int, int> newHiddenSectionSize; // from logical index to section size
1790 for (int i = 0; i < logicalFirst; ++i)
1791 if (isSectionHidden(i))
1792 newHiddenSectionSize[i] = d->hiddenSectionSize[i];
1793 for (int j = logicalLast + 1; j < d->sectionCount(); ++j)
1794 if (isSectionHidden(j))
1795 newHiddenSectionSize[j] = d->hiddenSectionSize[j - insertCount];
1796 d->hiddenSectionSize = newHiddenSectionSize;
1798 d->doDelayedResizeSections();
1799 emit sectionCountChanged(oldCount, count());
1801 // if the new sections were not updated by resizing, we need to update now
1802 if (!d->hasAutoResizeSections())
1803 d->viewport->update();
1807 This slot is called when sections are removed from the \a parent.
1808 \a logicalFirst and \a logicalLast signify where the sections were removed.
1810 If only one section is removed, \a logicalFirst and \a logicalLast will
1814 void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
1815 int logicalFirst, int logicalLast)
1818 Q_UNUSED(logicalFirst);
1819 Q_UNUSED(logicalLast);
1822 void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
1825 const int changeCount = logicalLast - logicalFirst + 1;
1827 // remove sections from hiddenSectionSize
1828 QHash<int, int> newHiddenSectionSize; // from logical index to section size
1829 for (int i = 0; i < logicalFirst; ++i)
1830 if (q->isSectionHidden(i))
1831 newHiddenSectionSize[i] = hiddenSectionSize[i];
1832 for (int j = logicalLast + 1; j < sectionCount(); ++j)
1833 if (q->isSectionHidden(j))
1834 newHiddenSectionSize[j - changeCount] = hiddenSectionSize[j];
1835 hiddenSectionSize = newHiddenSectionSize;
1837 // remove sections from sectionsHidden
1838 if (!sectionHidden.isEmpty()) {
1839 const int newsize = qMin(sectionCount() - changeCount, sectionHidden.size());
1840 QBitArray newSectionHidden(newsize);
1841 for (int j = 0, k = 0; j < sectionHidden.size(); ++j) {
1842 const int logical = logicalIndex(j);
1843 if (logical < logicalFirst || logical > logicalLast) {
1844 newSectionHidden[k++] = sectionHidden[j];
1847 sectionHidden = newSectionHidden;
1851 void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
1852 int logicalFirst, int logicalLast)
1856 return; // we only handle changes in the root level
1857 if (qMin(logicalFirst, logicalLast) < 0
1858 || qMax(logicalLast, logicalFirst) >= sectionCount())
1860 int oldCount = q->count();
1861 int changeCount = logicalLast - logicalFirst + 1;
1863 if (state == QHeaderViewPrivate::ResizeSection)
1864 preventCursorChangeInSetOffset = true;
1866 updateHiddenSections(logicalFirst, logicalLast);
1868 if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
1869 //Q_ASSERT(headerSectionCount() == sectionCount);
1870 removeSectionsFromSectionItems(logicalFirst, logicalLast);
1872 if (logicalFirst == logicalLast) { // Remove just one index.
1873 int l = logicalFirst;
1874 int visual = visualIndices.at(l);
1875 Q_ASSERT(sectionCount() == logicalIndices.count());
1876 for (int v = 0; v < sectionCount(); ++v) {
1878 int logical = logicalIndices.at(v);
1879 --(visualIndices[logical]);
1881 if (logicalIndex(v) > l) // no need to move the positions before l
1882 --(logicalIndices[v]);
1884 logicalIndices.remove(visual);
1885 visualIndices.remove(l);
1886 //Q_ASSERT(headerSectionCount() == sectionCount);
1887 removeSectionsFromSectionItems(visual, visual);
1889 sectionStartposRecalc = true; // We will need to recalc positions after removing items
1890 for (int u = 0; u < sectionItems.count(); ++u) // Store section info
1891 sectionItems.at(u).tmpLogIdx = logicalIndices.at(u);
1892 for (int v = sectionItems.count() - 1; v >= 0; --v) { // Remove the sections
1893 if (logicalFirst <= sectionItems.at(v).tmpLogIdx && sectionItems.at(v).tmpLogIdx <= logicalLast)
1894 removeSectionsFromSectionItems(v, v);
1896 visualIndices.resize(sectionItems.count());
1897 logicalIndices.resize(sectionItems.count());
1898 int* visual_data = visualIndices.data();
1899 int* logical_data = logicalIndices.data();
1900 for (int w = 0; w < sectionItems.count(); ++w) { // Restore visual and logical indexes
1901 int logindex = sectionItems.at(w).tmpLogIdx;
1902 if (logindex > logicalFirst)
1903 logindex -= changeCount;
1904 visual_data[logindex] = w;
1905 logical_data[w] = logindex;
1908 // ### handle sectionSelection (sectionHidden is handled by updateHiddenSections)
1911 // update sorting column
1912 if (sortIndicatorSection >= logicalFirst) {
1913 if (sortIndicatorSection <= logicalLast)
1914 sortIndicatorSection = -1;
1916 sortIndicatorSection -= changeCount;
1919 // if we only have the last section (the "end" position) left, the header is empty
1920 if (sectionCount() <= 0)
1922 invalidateCachedSizeHint();
1923 emit q->sectionCountChanged(oldCount, q->count());
1927 void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
1929 //if there is no row/column we can't have mapping for columns
1930 //because no QModelIndex in the model would be valid
1931 // ### this is far from being bullet-proof and we would need a real system to
1932 // ### map columns or rows persistently
1933 if ((orientation == Qt::Horizontal && model->rowCount(root) == 0)
1934 || model->columnCount(root) == 0)
1937 for (int i = 0; i < sectionHidden.count(); ++i)
1938 if (sectionHidden.testBit(i)) // ### note that we are using column or row 0
1939 persistentHiddenSections.append(orientation == Qt::Horizontal
1940 ? model->index(0, logicalIndex(i), root)
1941 : model->index(logicalIndex(i), 0, root));
1944 void QHeaderViewPrivate::_q_layoutChanged()
1948 if (persistentHiddenSections.isEmpty() || modelIsEmpty()) {
1949 if (modelSectionCount() != sectionCount())
1950 q->initializeSections();
1951 persistentHiddenSections.clear();
1955 QBitArray oldSectionHidden = sectionHidden;
1956 bool sectionCountChanged = false;
1958 for (int i = 0; i < persistentHiddenSections.count(); ++i) {
1959 QModelIndex index = persistentHiddenSections.at(i);
1960 if (index.isValid()) {
1961 const int logical = (orientation == Qt::Horizontal
1964 q->setSectionHidden(logical, true);
1965 oldSectionHidden.setBit(logical, false);
1966 } else if (!sectionCountChanged && (modelSectionCount() != sectionCount())) {
1967 sectionCountChanged = true;
1971 persistentHiddenSections.clear();
1973 for (int i = 0; i < oldSectionHidden.count(); ++i) {
1974 if (oldSectionHidden.testBit(i))
1975 q->setSectionHidden(i, false);
1978 // the number of sections changed; we need to reread the state of the model
1979 if (sectionCountChanged)
1980 q->initializeSections();
1987 void QHeaderView::initializeSections()
1990 const int oldCount = d->sectionCount();
1991 const int newCount = d->modelSectionCount();
1992 if (newCount <= 0) {
1994 emit sectionCountChanged(oldCount, 0);
1995 } else if (newCount != oldCount) {
1996 const int min = qBound(0, oldCount, newCount - 1);
1997 initializeSections(min, newCount - 1);
1998 if (stretchLastSection()) // we've already gotten the size hint
1999 d->lastSectionSize = sectionSize(logicalIndex(d->sectionCount() - 1));
2001 //make sure we update the hidden sections
2002 if (newCount < oldCount)
2003 d->updateHiddenSections(0, newCount-1);
2011 void QHeaderView::initializeSections(int start, int end)
2015 Q_ASSERT(start >= 0);
2018 d->invalidateCachedSizeHint();
2019 int oldCount = d->sectionCount();
2021 if (end + 1 < d->sectionCount()) {
2022 int newCount = end + 1;
2023 d->removeSectionsFromSectionItems(newCount, d->sectionCount() - 1);
2024 if (!d->hiddenSectionSize.isEmpty()) {
2025 if (oldCount - newCount > d->hiddenSectionSize.count()) {
2026 for (int i = end + 1; i < d->sectionCount(); ++i)
2027 d->hiddenSectionSize.remove(i);
2029 QHash<int, int>::iterator it = d->hiddenSectionSize.begin();
2030 while (it != d->hiddenSectionSize.end()) {
2032 it = d->hiddenSectionSize.erase(it);
2040 int newSectionCount = end + 1;
2042 if (!d->logicalIndices.isEmpty()) {
2043 if (oldCount <= newSectionCount) {
2044 d->logicalIndices.resize(newSectionCount);
2045 d->visualIndices.resize(newSectionCount);
2046 for (int i = oldCount; i < newSectionCount; ++i) {
2047 d->logicalIndices[i] = i;
2048 d->visualIndices[i] = i;
2052 for (int i = 0; i < oldCount; ++i) {
2053 int v = d->logicalIndices.at(i);
2054 if (v < newSectionCount) {
2055 d->logicalIndices[j] = v;
2056 d->visualIndices[v] = j;
2060 d->logicalIndices.resize(newSectionCount);
2061 d->visualIndices.resize(newSectionCount);
2065 if (d->globalResizeMode == Stretch)
2066 d->stretchSections = newSectionCount;
2067 else if (d->globalResizeMode == ResizeToContents)
2068 d->contentsSections = newSectionCount;
2069 if (!d->sectionHidden.isEmpty())
2070 d->sectionHidden.resize(newSectionCount);
2072 if (newSectionCount > oldCount)
2073 d->createSectionItems(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
2074 //Q_ASSERT(d->headerLength() == d->length);
2076 if (d->sectionCount() != oldCount)
2077 emit sectionCountChanged(oldCount, d->sectionCount());
2078 d->viewport->update();
2085 void QHeaderView::currentChanged(const QModelIndex ¤t, const QModelIndex &old)
2089 if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
2090 if (old.isValid() && old.parent() == d->root)
2091 d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
2092 sectionSize(old.column()), d->viewport->height()));
2093 if (current.isValid() && current.parent() == d->root)
2094 d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
2095 sectionSize(current.column()), d->viewport->height()));
2096 } else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
2097 if (old.isValid() && old.parent() == d->root)
2098 d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
2099 d->viewport->width(), sectionSize(old.row())));
2100 if (current.isValid() && current.parent() == d->root)
2101 d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
2102 d->viewport->width(), sectionSize(current.row())));
2111 bool QHeaderView::event(QEvent *e)
2114 switch (e->type()) {
2115 case QEvent::HoverEnter: {
2116 QHoverEvent *he = static_cast<QHoverEvent*>(e);
2117 d->hover = logicalIndexAt(he->pos());
2119 updateSection(d->hover);
2122 case QEvent::HoverLeave: {
2124 updateSection(d->hover);
2127 case QEvent::HoverMove: {
2128 QHoverEvent *he = static_cast<QHoverEvent*>(e);
2129 int oldHover = d->hover;
2130 d->hover = logicalIndexAt(he->pos());
2131 if (d->hover != oldHover) {
2133 updateSection(oldHover);
2135 updateSection(d->hover);
2138 case QEvent::Timer: {
2139 QTimerEvent *te = static_cast<QTimerEvent*>(e);
2140 if (te->timerId() == d->delayedResize.timerId()) {
2141 d->delayedResize.stop();
2148 return QAbstractItemView::event(e);
2155 void QHeaderView::paintEvent(QPaintEvent *e)
2162 QPainter painter(d->viewport);
2163 const QPoint offset = d->scrollDelayOffset;
2164 QRect translatedEventRect = e->rect();
2165 translatedEventRect.translate(offset);
2169 if (d->orientation == Qt::Horizontal) {
2170 start = visualIndexAt(translatedEventRect.left());
2171 end = visualIndexAt(translatedEventRect.right());
2173 start = visualIndexAt(translatedEventRect.top());
2174 end = visualIndexAt(translatedEventRect.bottom());
2178 start = (start == -1 ? count() - 1 : start);
2179 end = (end == -1 ? 0 : end);
2181 start = (start == -1 ? 0 : start);
2182 end = (end == -1 ? count() - 1 : end);
2186 start = qMin(start, end);
2187 end = qMax(tmp, end);
2189 d->prepareSectionSelected(); // clear and resize the bit array
2191 QRect currentSectionRect;
2193 const int width = d->viewport->width();
2194 const int height = d->viewport->height();
2195 for (int i = start; i <= end; ++i) {
2196 if (d->isVisualIndexHidden(i))
2199 logical = logicalIndex(i);
2200 if (d->orientation == Qt::Horizontal) {
2201 currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
2203 currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
2205 currentSectionRect.translate(offset);
2207 QVariant variant = d->model->headerData(logical, d->orientation,
2209 if (variant.isValid() && variant.canConvert<QFont>()) {
2210 QFont sectionFont = qvariant_cast<QFont>(variant);
2211 painter.setFont(sectionFont);
2213 paintSection(&painter, currentSectionRect, logical);
2219 // Paint the area beyond where there are indexes
2221 opt.state |= QStyle::State_Horizontal;
2222 if (currentSectionRect.left() > translatedEventRect.left()) {
2223 opt.rect = QRect(translatedEventRect.left(), 0,
2224 currentSectionRect.left() - translatedEventRect.left(), height);
2225 style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2227 } else if (currentSectionRect.right() < translatedEventRect.right()) {
2228 // paint to the right
2229 opt.state |= QStyle::State_Horizontal;
2230 opt.rect = QRect(currentSectionRect.right() + 1, 0,
2231 translatedEventRect.right() - currentSectionRect.right(), height);
2232 style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2233 } else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
2234 // paint the bottom section
2235 opt.state &= ~QStyle::State_Horizontal;
2236 opt.rect = QRect(0, currentSectionRect.bottom() + 1,
2237 width, height - currentSectionRect.bottom() - 1);
2238 style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2242 // ### visualize sections
2243 for (int a = 0, i = 0; i < d->sectionItems.count(); ++i) {
2244 QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
2245 if (d->orientation == Qt::Horizontal)
2246 painter.fillRect(a - d->offset, 0, d->sectionItems.at(i).size, 4, color);
2248 painter.fillRect(0, a - d->offset, 4, d->sectionItems.at(i).size, color);
2249 a += d->sectionItems.at(i).size;
2259 void QHeaderView::mousePressEvent(QMouseEvent *e)
2262 if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
2264 int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2265 int handle = d->sectionHandleAt(pos);
2266 d->originalSize = -1; // clear the stored original size
2268 d->pressed = logicalIndexAt(pos);
2269 if (d->clickableSections)
2270 emit sectionPressed(d->pressed);
2271 if (d->movableSections) {
2272 d->section = d->target = d->pressed;
2273 if (d->section == -1)
2275 d->state = QHeaderViewPrivate::MoveSection;
2276 d->setupSectionIndicator(d->section, pos);
2277 } else if (d->clickableSections && d->pressed != -1) {
2278 updateSection(d->pressed);
2279 d->state = QHeaderViewPrivate::SelectSections;
2281 } else if (sectionResizeMode(handle) == Interactive) {
2282 d->originalSize = sectionSize(handle);
2283 d->state = QHeaderViewPrivate::ResizeSection;
2284 d->section = handle;
2285 d->preventCursorChangeInSetOffset = false;
2291 d->clearCascadingSections();
2298 void QHeaderView::mouseMoveEvent(QMouseEvent *e)
2301 int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2304 if (e->buttons() == Qt::NoButton) {
2305 #if !defined(Q_WS_MAC)
2306 // Under Cocoa, when the mouse button is released, may include an extra
2307 // simulated mouse moved event. The state of the buttons when this event
2308 // is generated is already "no button" and the code below gets executed
2309 // just before the mouseReleaseEvent and resets the state. This prevents
2310 // column dragging from working. So this code is disabled under Cocoa.
2311 d->state = QHeaderViewPrivate::NoState;
2316 case QHeaderViewPrivate::ResizeSection: {
2317 Q_ASSERT(d->originalSize != -1);
2318 if (d->cascadingResizing) {
2319 int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
2320 int visual = visualIndex(d->section);
2321 d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
2323 int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
2324 resizeSection(d->section, qMax(d->originalSize + delta, minimumSectionSize()));
2329 case QHeaderViewPrivate::MoveSection: {
2330 if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
2331 || !d->sectionIndicator->isHidden()) {
2332 int visual = visualIndexAt(pos);
2335 int posThreshold = d->headerSectionPosition(visual) + d->headerSectionSize(visual) / 2;
2336 int moving = visualIndex(d->section);
2337 if (visual < moving) {
2338 if (pos < posThreshold)
2339 d->target = d->logicalIndex(visual);
2341 d->target = d->logicalIndex(visual + 1);
2342 } else if (visual > moving) {
2343 if (pos > posThreshold)
2344 d->target = d->logicalIndex(visual);
2346 d->target = d->logicalIndex(visual - 1);
2348 d->target = d->section;
2350 d->updateSectionIndicator(d->section, pos);
2354 case QHeaderViewPrivate::SelectSections: {
2355 int logical = logicalIndexAt(pos);
2356 if (logical == d->pressed)
2357 return; // nothing to do
2358 else if (d->pressed != -1)
2359 updateSection(d->pressed);
2360 d->pressed = logical;
2361 if (d->clickableSections && logical != -1) {
2362 emit sectionEntered(d->pressed);
2363 updateSection(d->pressed);
2367 case QHeaderViewPrivate::NoState: {
2368 #ifndef QT_NO_CURSOR
2369 int handle = d->sectionHandleAt(pos);
2370 bool hasCursor = testAttribute(Qt::WA_SetCursor);
2371 if (handle != -1 && (sectionResizeMode(handle) == Interactive)) {
2373 setCursor(d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
2374 } else if (hasCursor) {
2389 void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
2392 int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2394 case QHeaderViewPrivate::MoveSection:
2395 if (!d->sectionIndicator->isHidden()) { // moving
2396 int from = visualIndex(d->section);
2397 Q_ASSERT(from != -1);
2398 int to = visualIndex(d->target);
2400 moveSection(from, to);
2401 d->section = d->target = -1;
2402 d->updateSectionIndicator(d->section, pos);
2405 case QHeaderViewPrivate::SelectSections:
2406 if (!d->clickableSections) {
2407 int section = logicalIndexAt(pos);
2408 updateSection(section);
2411 case QHeaderViewPrivate::NoState:
2412 if (d->clickableSections) {
2413 int section = logicalIndexAt(pos);
2414 if (section != -1 && section == d->pressed) {
2415 d->flipSortIndicator(section);
2416 emit sectionClicked(section);
2418 if (d->pressed != -1)
2419 updateSection(d->pressed);
2422 case QHeaderViewPrivate::ResizeSection:
2423 d->originalSize = -1;
2424 d->clearCascadingSections();
2429 d->state = QHeaderViewPrivate::NoState;
2437 void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
2440 int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2441 int handle = d->sectionHandleAt(pos);
2442 if (handle > -1 && sectionResizeMode(handle) == Interactive) {
2443 emit sectionHandleDoubleClicked(handle);
2444 #ifndef QT_NO_CURSOR
2445 Qt::CursorShape splitCursor = (d->orientation == Qt::Horizontal)
2446 ? Qt::SplitHCursor : Qt::SplitVCursor;
2447 if (cursor().shape() == splitCursor) {
2448 // signal handlers may have changed the section size
2449 handle = d->sectionHandleAt(pos);
2450 if (!(handle > -1 && sectionResizeMode(handle) == Interactive))
2451 setCursor(Qt::ArrowCursor);
2455 emit sectionDoubleClicked(logicalIndexAt(e->pos()));
2463 bool QHeaderView::viewportEvent(QEvent *e)
2466 switch (e->type()) {
2467 #ifndef QT_NO_TOOLTIP
2468 case QEvent::ToolTip: {
2469 QHelpEvent *he = static_cast<QHelpEvent*>(e);
2470 int logical = logicalIndexAt(he->pos());
2471 if (logical != -1) {
2472 QVariant variant = d->model->headerData(logical, d->orientation, Qt::ToolTipRole);
2473 if (variant.isValid()) {
2474 QToolTip::showText(he->globalPos(), variant.toString(), this);
2480 #ifndef QT_NO_WHATSTHIS
2481 case QEvent::QueryWhatsThis: {
2482 QHelpEvent *he = static_cast<QHelpEvent*>(e);
2483 int logical = logicalIndexAt(he->pos());
2485 && d->model->headerData(logical, d->orientation, Qt::WhatsThisRole).isValid())
2488 case QEvent::WhatsThis: {
2489 QHelpEvent *he = static_cast<QHelpEvent*>(e);
2490 int logical = logicalIndexAt(he->pos());
2491 if (logical != -1) {
2492 QVariant whatsthis = d->model->headerData(logical, d->orientation,
2494 if (whatsthis.isValid()) {
2495 QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
2500 #endif // QT_NO_WHATSTHIS
2501 #ifndef QT_NO_STATUSTIP
2502 case QEvent::StatusTip: {
2503 QHelpEvent *he = static_cast<QHelpEvent*>(e);
2504 int logical = logicalIndexAt(he->pos());
2505 if (logical != -1) {
2506 QString statustip = d->model->headerData(logical, d->orientation,
2507 Qt::StatusTipRole).toString();
2508 if (!statustip.isEmpty())
2509 setStatusTip(statustip);
2512 #endif // QT_NO_STATUSTIP
2515 case QEvent::FontChange:
2516 case QEvent::StyleChange:{
2517 QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget());
2518 if (parent && parent->isVisible()) // Only resize if we have a visible parent
2520 emit geometriesChanged();
2522 case QEvent::ContextMenu: {
2523 d->state = QHeaderViewPrivate::NoState;
2524 d->pressed = d->section = d->target = -1;
2525 d->updateSectionIndicator(d->section, -1);
2527 case QEvent::Wheel: {
2528 QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea *>(parentWidget());
2530 return QApplication::sendEvent(asa->viewport(), e);
2535 return QAbstractItemView::viewportEvent(e);
2539 Paints the section specified by the given \a logicalIndex, using the given
2540 \a painter and \a rect.
2542 Normally, you do not have to call this function.
2545 void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
2547 Q_D(const QHeaderView);
2548 if (!rect.isValid())
2550 // get the state of the section
2551 QStyleOptionHeader opt;
2552 initStyleOption(&opt);
2553 QStyle::State state = QStyle::State_None;
2555 state |= QStyle::State_Enabled;
2556 if (window()->isActiveWindow())
2557 state |= QStyle::State_Active;
2558 if (d->clickableSections) {
2559 if (logicalIndex == d->hover)
2560 state |= QStyle::State_MouseOver;
2561 if (logicalIndex == d->pressed)
2562 state |= QStyle::State_Sunken;
2563 else if (d->highlightSelected) {
2564 if (d->sectionIntersectsSelection(logicalIndex))
2565 state |= QStyle::State_On;
2566 if (d->isSectionSelected(logicalIndex))
2567 state |= QStyle::State_Sunken;
2571 if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
2572 opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
2573 ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
2575 // setup the style options structure
2576 QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
2577 Qt::TextAlignmentRole);
2579 opt.section = logicalIndex;
2581 opt.textAlignment = Qt::Alignment(textAlignment.isValid()
2582 ? Qt::Alignment(textAlignment.toInt())
2583 : d->defaultAlignment);
2585 opt.iconAlignment = Qt::AlignVCenter;
2586 opt.text = d->model->headerData(logicalIndex, d->orientation,
2587 Qt::DisplayRole).toString();
2588 if (d->textElideMode != Qt::ElideNone)
2589 opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4);
2591 QVariant variant = d->model->headerData(logicalIndex, d->orientation,
2592 Qt::DecorationRole);
2593 opt.icon = qvariant_cast<QIcon>(variant);
2594 if (opt.icon.isNull())
2595 opt.icon = qvariant_cast<QPixmap>(variant);
2596 QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
2597 Qt::ForegroundRole);
2598 if (foregroundBrush.canConvert<QBrush>())
2599 opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
2601 QPointF oldBO = painter->brushOrigin();
2602 QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
2603 Qt::BackgroundRole);
2604 if (backgroundBrush.canConvert<QBrush>()) {
2605 opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
2606 opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
2607 painter->setBrushOrigin(opt.rect.topLeft());
2610 // the section position
2611 int visual = visualIndex(logicalIndex);
2612 Q_ASSERT(visual != -1);
2614 opt.position = QStyleOptionHeader::OnlyOneSection;
2615 else if (visual == 0)
2616 opt.position = QStyleOptionHeader::Beginning;
2617 else if (visual == count() - 1)
2618 opt.position = QStyleOptionHeader::End;
2620 opt.position = QStyleOptionHeader::Middle;
2621 opt.orientation = d->orientation;
2622 // the selected position
2623 bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
2624 bool nextSelected = d->isSectionSelected(this->logicalIndex(visual + 1));
2625 if (previousSelected && nextSelected)
2626 opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
2627 else if (previousSelected)
2628 opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
2629 else if (nextSelected)
2630 opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
2632 opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
2634 style()->drawControl(QStyle::CE_Header, &opt, painter, this);
2636 painter->setBrushOrigin(oldBO);
2640 Returns the size of the contents of the section specified by the given
2643 \sa defaultSectionSize()
2646 QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
2648 Q_D(const QHeaderView);
2649 Q_ASSERT(logicalIndex >= 0);
2654 QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
2655 if (variant.isValid())
2656 return qvariant_cast<QSize>(variant);
2658 // otherwise use the contents
2659 QStyleOptionHeader opt;
2660 initStyleOption(&opt);
2661 opt.section = logicalIndex;
2662 QVariant var = d->model->headerData(logicalIndex, d->orientation,
2665 if (var.isValid() && var.canConvert<QFont>())
2666 fnt = qvariant_cast<QFont>(var);
2670 opt.fontMetrics = QFontMetrics(fnt);
2671 opt.text = d->model->headerData(logicalIndex, d->orientation,
2672 Qt::DisplayRole).toString();
2673 variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole);
2674 opt.icon = qvariant_cast<QIcon>(variant);
2675 if (opt.icon.isNull())
2676 opt.icon = qvariant_cast<QPixmap>(variant);
2677 QSize size = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
2678 if (isSortIndicatorShown()) {
2679 int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, &opt, this);
2680 if (d->orientation == Qt::Horizontal)
2681 size.rwidth() += size.height() + margin;
2683 size.rheight() += size.width() + margin;
2689 Returns the horizontal offset of the header. This is 0 for vertical
2695 int QHeaderView::horizontalOffset() const
2697 Q_D(const QHeaderView);
2698 if (d->orientation == Qt::Horizontal)
2704 Returns the vertical offset of the header. This is 0 for horizontal
2710 int QHeaderView::verticalOffset() const
2712 Q_D(const QHeaderView);
2713 if (d->orientation == Qt::Vertical)
2723 void QHeaderView::updateGeometries()
2726 d->layoutChildren();
2727 if (d->hasAutoResizeSections())
2728 d->doDelayedResizeSections();
2736 void QHeaderView::scrollContentsBy(int dx, int dy)
2739 d->scrollDirtyRegion(dx, dy);
2746 void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &)
2749 d->invalidateCachedSizeHint();
2750 if (d->hasAutoResizeSections()) {
2751 bool resizeRequired = d->globalResizeMode == ResizeToContents;
2752 int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row();
2753 int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row();
2754 for (int i = first; i <= last && !resizeRequired; ++i)
2755 resizeRequired = (sectionResizeMode(i) == ResizeToContents);
2757 d->doDelayedResizeSections();
2765 Empty implementation because the header doesn't show QModelIndex items.
2767 void QHeaderView::rowsInserted(const QModelIndex &, int, int)
2776 Empty implementation because the header doesn't show QModelIndex items.
2779 QRect QHeaderView::visualRect(const QModelIndex &) const
2788 Empty implementation because the header doesn't show QModelIndex items.
2791 void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
2793 // do nothing - the header only displays sections
2800 Empty implementation because the header doesn't show QModelIndex items.
2803 QModelIndex QHeaderView::indexAt(const QPoint &) const
2805 return QModelIndex();
2812 Empty implementation because the header doesn't show QModelIndex items.
2815 bool QHeaderView::isIndexHidden(const QModelIndex &) const
2817 return true; // the header view has no items, just sections
2824 Empty implementation because the header doesn't show QModelIndex items.
2827 QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
2829 return QModelIndex();
2835 Selects the items in the given \a rect according to the specified
2838 The base class implementation does nothing.
2841 void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
2850 QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
2852 Q_D(const QHeaderView);
2853 const int max = d->modelSectionCount();
2854 if (d->orientation == Qt::Horizontal) {
2857 int rangeLeft, rangeRight;
2859 for (int i = 0; i < selection.count(); ++i) {
2860 QItemSelectionRange r = selection.at(i);
2861 if (r.parent().isValid() || !r.isValid())
2862 continue; // we only know about toplevel items and we don't want invalid ranges
2863 // FIXME an item inside the range may be the leftmost or rightmost
2864 rangeLeft = visualIndex(r.left());
2865 if (rangeLeft == -1) // in some cases users may change the selections
2866 continue; // before we have a chance to do the layout
2867 rangeRight = visualIndex(r.right());
2868 if (rangeRight == -1) // in some cases users may change the selections
2869 continue; // before we have a chance to do the layout
2870 if (rangeLeft < left)
2872 if (rangeRight > right)
2876 int logicalLeft = logicalIndex(left);
2877 int logicalRight = logicalIndex(right);
2879 if (logicalLeft < 0 || logicalLeft >= count() ||
2880 logicalRight < 0 || logicalRight >= count())
2883 int leftPos = sectionViewportPosition(logicalLeft);
2884 int rightPos = sectionViewportPosition(logicalRight);
2885 rightPos += sectionSize(logicalRight);
2886 return QRect(leftPos, 0, rightPos - leftPos, height());
2888 // orientation() == Qt::Vertical
2891 int rangeTop, rangeBottom;
2893 for (int i = 0; i < selection.count(); ++i) {
2894 QItemSelectionRange r = selection.at(i);
2895 if (r.parent().isValid() || !r.isValid())
2896 continue; // we only know about toplevel items
2897 // FIXME an item inside the range may be the leftmost or rightmost
2898 rangeTop = visualIndex(r.top());
2899 if (rangeTop == -1) // in some cases users may change the selections
2900 continue; // before we have a chance to do the layout
2901 rangeBottom = visualIndex(r.bottom());
2902 if (rangeBottom == -1) // in some cases users may change the selections
2903 continue; // before we have a chance to do the layout
2906 if (rangeBottom > bottom)
2907 bottom = rangeBottom;
2910 int logicalTop = logicalIndex(top);
2911 int logicalBottom = logicalIndex(bottom);
2913 if (logicalTop == -1 || logicalBottom == -1)
2916 int topPos = sectionViewportPosition(logicalTop);
2917 int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
2919 return QRect(0, topPos, width(), bottomPos - topPos);
2923 // private implementation
2925 int QHeaderViewPrivate::sectionHandleAt(int position)
2928 int visual = q->visualIndexAt(position);
2931 int log = logicalIndex(visual);
2932 int pos = q->sectionViewportPosition(log);
2933 int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, q);
2935 bool atLeft = position < pos + grip;
2936 bool atRight = (position > pos + q->sectionSize(log) - grip);
2938 qSwap(atLeft, atRight);
2941 //grip at the beginning of the section
2942 while(visual > -1) {
2943 int logical = q->logicalIndex(--visual);
2944 if (!q->isSectionHidden(logical))
2947 } else if (atRight) {
2948 //grip at the end of the section
2954 void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
2957 if (!sectionIndicator) {
2958 sectionIndicator = new QLabel(viewport);
2962 int p = q->sectionViewportPosition(section);
2963 if (orientation == Qt::Horizontal) {
2964 w = q->sectionSize(section);
2965 h = viewport->height();
2967 w = viewport->width();
2968 h = q->sectionSize(section);
2970 sectionIndicator->resize(w, h);
2973 pm.fill(QColor(0, 0, 0, 45));
2974 QRect rect(0, 0, w, h);
2976 QPainter painter(&pm);
2977 painter.setOpacity(0.75);
2978 q->paintSection(&painter, rect, section);
2981 sectionIndicator->setPixmap(pm);
2982 sectionIndicatorOffset = position - qMax(p, 0);
2985 void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
2987 if (!sectionIndicator)
2990 if (section == -1 || target == -1) {
2991 sectionIndicator->hide();
2995 if (orientation == Qt::Horizontal)
2996 sectionIndicator->move(position - sectionIndicatorOffset, 0);
2998 sectionIndicator->move(0, position - sectionIndicatorOffset);
3000 sectionIndicator->show();
3004 Initialize \a option with the values from this QHeaderView. This method is
3005 useful for subclasses when they need a QStyleOptionHeader, but do not want
3006 to fill in all the information themselves.
3008 \sa QStyleOption::initFrom()
3010 void QHeaderView::initStyleOption(QStyleOptionHeader *option) const
3012 Q_D(const QHeaderView);
3013 option->initFrom(this);
3014 option->state = QStyle::State_None | QStyle::State_Raised;
3015 option->orientation = d->orientation;
3016 if (d->orientation == Qt::Horizontal)
3017 option->state |= QStyle::State_Horizontal;
3019 option->state |= QStyle::State_Enabled;
3020 option->section = 0;
3023 bool QHeaderViewPrivate::isSectionSelected(int section) const
3025 int i = section * 2;
3026 if (i < 0 || i >= sectionSelected.count())
3028 if (sectionSelected.testBit(i)) // if the value was cached
3029 return sectionSelected.testBit(i + 1);
3031 if (orientation == Qt::Horizontal)
3032 s = isColumnSelected(section);
3034 s = isRowSelected(section);
3035 sectionSelected.setBit(i + 1, s); // selection state
3036 sectionSelected.setBit(i, true); // cache state
3042 Returns the last visible (ie. not hidden) visual index
3044 int QHeaderViewPrivate::lastVisibleVisualIndex() const
3046 Q_Q(const QHeaderView);
3047 for (int visual = q->count()-1; visual >= 0; --visual) {
3048 if (!q->isSectionHidden(q->logicalIndex(visual)))
3052 //default value if no section is actually visible
3058 Go through and resize all of the sections applying stretchLastSection,
3059 manual stretches, sizes, and useGlobalMode.
3061 The different resize modes are:
3062 Interactive - the user decides the size
3063 Stretch - take up whatever space is left
3064 Fixed - the size is set programmatically outside the header
3065 ResizeToContentes - the size is set based on the contents of the row or column in the parent view
3067 The resize mode will not affect the last section if stretchLastSection is true.
3069 void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
3072 //stop the timer in case it is delayed
3073 delayedResize.stop();
3075 executePostedLayout();
3076 if (sectionCount() == 0)
3079 if (resizeRecursionBlock)
3081 resizeRecursionBlock = true;
3083 invalidateCachedSizeHint();
3085 const int lastVisibleSection = lastVisibleVisualIndex();
3087 // find stretchLastSection if we have it
3088 int stretchSection = -1;
3089 if (stretchLastSection && !useGlobalMode)
3090 stretchSection = lastVisibleVisualIndex();
3092 // count up the number of stretched sections and how much space left for them
3093 int lengthToStretch = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
3094 int numberOfStretchedSections = 0;
3095 QList<int> section_sizes;
3096 for (int i = 0; i < sectionCount(); ++i) {
3097 if (isVisualIndexHidden(i))
3100 QHeaderView::ResizeMode resizeMode;
3101 if (useGlobalMode && (i != stretchSection))
3102 resizeMode = globalMode;
3104 resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i));
3106 if (resizeMode == QHeaderView::Stretch) {
3107 ++numberOfStretchedSections;
3108 section_sizes.append(headerSectionSize(i));
3112 // because it isn't stretch, determine its width and remove that from lengthToStretch
3113 int sectionSize = 0;
3114 if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
3115 sectionSize = headerSectionSize(i);
3116 } else { // resizeMode == QHeaderView::ResizeToContents
3117 int logicalIndex = q->logicalIndex(i);
3118 sectionSize = qMax(viewSectionSizeHint(logicalIndex),
3119 q->sectionSizeHint(logicalIndex));
3121 section_sizes.append(sectionSize);
3122 lengthToStretch -= sectionSize;
3125 // calculate the new length for all of the stretched sections
3126 int stretchSectionLength = -1;
3127 int pixelReminder = 0;
3128 if (numberOfStretchedSections > 0 && lengthToStretch > 0) { // we have room to stretch in
3129 int hintLengthForEveryStretchedSection = lengthToStretch / numberOfStretchedSections;
3130 stretchSectionLength = qMax(hintLengthForEveryStretchedSection, q->minimumSectionSize());
3131 pixelReminder = lengthToStretch % numberOfStretchedSections;
3134 // ### The code below would be nicer if it was cleaned up a bit (since spans has been replaced with items)
3135 int spanStartSection = 0;
3136 int previousSectionLength = 0;
3138 QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
3140 // resize each section along the total length
3141 for (int i = 0; i < sectionCount(); ++i) {
3142 int oldSectionLength = headerSectionSize(i);
3143 int newSectionLength = -1;
3144 QHeaderView::ResizeMode newSectionResizeMode = headerSectionResizeMode(i);
3146 if (isVisualIndexHidden(i)) {
3147 newSectionLength = 0;
3149 QHeaderView::ResizeMode resizeMode;
3151 resizeMode = globalMode;
3153 resizeMode = (i == stretchSection
3154 ? QHeaderView::Stretch
3155 : newSectionResizeMode);
3156 if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) {
3157 if (i == lastVisibleSection)
3158 newSectionLength = qMax(stretchSectionLength, lastSectionSize);
3160 newSectionLength = stretchSectionLength;
3161 if (pixelReminder > 0) {
3162 newSectionLength += 1;
3165 section_sizes.removeFirst();
3167 newSectionLength = section_sizes.front();
3168 section_sizes.removeFirst();
3172 //Q_ASSERT(newSectionLength > 0);
3173 if ((previousSectionResizeMode != newSectionResizeMode
3174 || previousSectionLength != newSectionLength) && i > 0) {
3175 int spanLength = (i - spanStartSection) * previousSectionLength;
3176 createSectionItems(spanStartSection, i - 1, spanLength, previousSectionResizeMode);
3177 //Q_ASSERT(headerLength() == length);
3178 spanStartSection = i;
3181 if (newSectionLength != oldSectionLength)
3182 emit q->sectionResized(logicalIndex(i), oldSectionLength, newSectionLength);
3184 previousSectionLength = newSectionLength;
3185 previousSectionResizeMode = newSectionResizeMode;
3188 createSectionItems(spanStartSection, sectionCount() - 1,
3189 (sectionCount() - spanStartSection) * previousSectionLength,
3190 previousSectionResizeMode);
3191 //Q_ASSERT(headerLength() == length);
3192 resizeRecursionBlock = false;
3196 void QHeaderViewPrivate::createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode)
3198 int sizePerSection = size / (end - start + 1);
3199 if (end >= sectionItems.count()) {
3200 sectionItems.resize(end + 1);
3201 sectionStartposRecalc = true;
3203 SectionItem *sectiondata = sectionItems.data();
3204 for (int i = start; i <= end; ++i) {
3205 length += (sizePerSection - sectiondata[i].size);
3206 sectionStartposRecalc |= (sectiondata[i].size != sizePerSection);
3207 sectiondata[i].size = sizePerSection;
3208 sectiondata[i].resizeMode = mode;
3212 void QHeaderViewPrivate::removeSectionsFromSectionItems(int start, int end)
3215 sectionStartposRecalc |= (end != sectionItems.count() - 1);
3216 int removedlength = 0;
3217 for (int u = start; u <= end; ++u)
3218 removedlength += sectionItems.at(u).size;
3219 length -= removedlength;
3220 sectionItems.remove(start, end - start + 1);
3223 void QHeaderViewPrivate::clear()
3225 if (state != NoClear) {
3227 visualIndices.clear();
3228 logicalIndices.clear();
3229 sectionSelected.clear();
3230 sectionHidden.clear();
3231 hiddenSectionSize.clear();
3232 sectionItems.clear();
3236 void QHeaderViewPrivate::flipSortIndicator(int section)
3239 Qt::SortOrder sortOrder;
3240 if (sortIndicatorSection == section) {
3241 sortOrder = (sortIndicatorOrder == Qt::DescendingOrder) ? Qt::AscendingOrder : Qt::DescendingOrder;
3243 const QVariant value = model->headerData(section, orientation, Qt::InitialSortOrderRole);
3244 if (value.canConvert(QVariant::Int))
3245 sortOrder = static_cast<Qt::SortOrder>(value.toInt());
3247 sortOrder = Qt::AscendingOrder;
3249 q->setSortIndicator(section, sortOrder);
3252 void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
3255 const int minimumSize = q->minimumSectionSize();
3256 const int oldSize = headerSectionSize(visual);
3257 int delta = newSize - oldSize;
3259 if (delta > 0) { // larger
3260 bool sectionResized = false;
3262 // restore old section sizes
3263 for (int i = firstCascadingSection; i < visual; ++i) {
3264 if (cascadingSectionSize.contains(i)) {
3265 int currentSectionSize = headerSectionSize(i);
3266 int originalSectionSize = cascadingSectionSize.value(i);
3267 if (currentSectionSize < originalSectionSize) {
3268 int newSectionSize = currentSectionSize + delta;
3269 resizeSectionItem(i, currentSectionSize, newSectionSize);
3270 if (newSectionSize >= originalSectionSize && false)
3271 cascadingSectionSize.remove(i); // the section is now restored
3272 sectionResized = true;
3279 // resize the section
3280 if (!sectionResized) {
3281 newSize = qMax(newSize, minimumSize);
3282 if (oldSize != newSize)
3283 resizeSectionItem(visual, oldSize, newSize);
3286 // cascade the section size change
3287 for (int i = visual + 1; i < sectionCount(); ++i) {
3288 if (!sectionIsCascadable(i))
3290 int currentSectionSize = headerSectionSize(i);
3291 if (currentSectionSize <= minimumSize)
3293 int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
3294 //qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
3295 resizeSectionItem(i, currentSectionSize, newSectionSize);
3296 saveCascadingSectionSize(i, currentSectionSize);
3297 delta = delta - (currentSectionSize - newSectionSize);
3298 //qDebug() << "new delta" << delta;
3299 //if (newSectionSize != minimumSize)
3304 bool sectionResized = false;
3306 // restore old section sizes
3307 for (int i = lastCascadingSection; i > visual; --i) {
3308 if (!cascadingSectionSize.contains(i))
3310 int currentSectionSize = headerSectionSize(i);
3311 int originalSectionSize = cascadingSectionSize.value(i);
3312 if (currentSectionSize >= originalSectionSize)
3314 int newSectionSize = currentSectionSize - delta;
3315 resizeSectionItem(i, currentSectionSize, newSectionSize);
3316 if (newSectionSize >= originalSectionSize && false) {
3317 //qDebug() << "section" << i << "restored to" << originalSectionSize;
3318 cascadingSectionSize.remove(i); // the section is now restored
3320 sectionResized = true;
3324 // resize the section
3325 resizeSectionItem(visual, oldSize, qMax(newSize, minimumSize));
3327 // cascade the section size change
3328 if (delta < 0 && newSize < minimumSize) {
3329 for (int i = visual - 1; i >= 0; --i) {
3330 if (!sectionIsCascadable(i))
3332 int sectionSize = headerSectionSize(i);
3333 if (sectionSize <= minimumSize)
3335 resizeSectionItem(i, sectionSize, qMax(sectionSize + delta, minimumSize));
3336 saveCascadingSectionSize(i, sectionSize);
3341 // let the next section get the space from the resized section
3342 if (!sectionResized) {
3343 for (int i = visual + 1; i < sectionCount(); ++i) {
3344 if (!sectionIsCascadable(i))
3346 int currentSectionSize = headerSectionSize(i);
3347 int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
3348 resizeSectionItem(i, currentSectionSize, newSectionSize);
3354 if (hasAutoResizeSections())
3355 doDelayedResizeSections();
3360 void QHeaderViewPrivate::setDefaultSectionSize(int size)
3363 defaultSectionSize = size;
3364 for (int i = 0; i < sectionItems.count(); ++i) {
3365 QHeaderViewPrivate::SectionItem §ion = sectionItems[i];
3366 if (sectionHidden.isEmpty() || !sectionHidden.testBit(i)) { // resize on not hidden.
3367 const int newSize = size;
3368 if (newSize != section.size) {
3369 length += newSize - section.size; //the whole length is changed
3370 const int oldSectionSize = section.sectionSize();
3371 section.size = size;
3372 emit q->sectionResized(logicalIndex(i), oldSectionSize, size);
3378 void QHeaderViewPrivate::recalcSectionStartPos() const // linear (but fast)
3381 for (QVector<SectionItem>::const_iterator i = sectionItems.constBegin(); i != sectionItems.constEnd(); ++i) {
3382 i->calculated_startpos = pixelpos; // write into const mutable
3383 pixelpos += i->size;
3385 sectionStartposRecalc = false;
3388 void QHeaderViewPrivate::resizeSectionItem(int visualIndex, int oldSize, int newSize)
3391 QHeaderView::ResizeMode mode = headerSectionResizeMode(visualIndex);
3392 createSectionItems(visualIndex, visualIndex, newSize, mode);
3393 emit q->sectionResized(logicalIndex(visualIndex), oldSize, newSize);
3396 int QHeaderViewPrivate::headerSectionSize(int visual) const
3398 if (visual < sectionCount() && visual >= 0)
3399 return sectionItems.at(visual).sectionSize();
3403 int QHeaderViewPrivate::headerSectionPosition(int visual) const
3405 if (visual < sectionCount() && visual >= 0) {
3406 if (sectionStartposRecalc)
3407 recalcSectionStartPos();
3408 return sectionItems.at(visual).calculated_startpos;
3413 int QHeaderViewPrivate::headerVisualIndexAt(int position) const
3415 if (sectionStartposRecalc)
3416 recalcSectionStartPos();
3418 int endidx = sectionItems.count() - 1;
3419 while (startidx <= endidx) {
3420 int middle = (endidx + startidx) / 2;
3421 if (sectionItems.at(middle).calculated_startpos > position) {
3422 endidx = middle - 1;
3424 if (sectionItems.at(middle).calculatedEndPos() <= position)
3425 startidx = middle + 1;
3426 else // we found it.
3433 void QHeaderViewPrivate::setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode)
3435 int size = headerSectionSize(visual);
3436 createSectionItems(visual, visual, size, mode);
3439 QHeaderView::ResizeMode QHeaderViewPrivate::headerSectionResizeMode(int visual) const
3441 if (visual < 0 || visual >= sectionItems.count())
3442 return globalResizeMode;
3443 return sectionItems.at(visual).resizeMode;
3446 void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode)
3448 globalResizeMode = mode;
3449 for (int i = 0; i < sectionItems.count(); ++i)
3450 sectionItems[i].resizeMode = mode;
3453 int QHeaderViewPrivate::viewSectionSizeHint(int logical) const
3455 if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent)) {
3456 return (orientation == Qt::Horizontal
3457 ? view->sizeHintForColumn(logical)
3458 : view->sizeHintForRow(logical));
3463 int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const
3465 if (!sectionHidden.isEmpty()) {
3466 int adjustedVisualIndex = visualIndex;
3467 int currentVisualIndex = 0;
3468 for (int i = 0; i < sectionItems.count(); ++i) {
3469 if (sectionHidden.testBit(i))
3470 ++adjustedVisualIndex;
3472 ++currentVisualIndex;
3473 if (currentVisualIndex >= visualIndex)
3476 visualIndex = adjustedVisualIndex;
3481 #ifndef QT_NO_DATASTREAM
3482 void QHeaderViewPrivate::write(QDataStream &out) const
3484 out << int(orientation);
3485 out << int(sortIndicatorOrder);
3486 out << sortIndicatorSection;
3487 out << sortIndicatorShown;
3489 out << visualIndices;
3490 out << logicalIndices;
3492 out << sectionHidden;
3493 out << hiddenSectionSize;
3496 out << sectionCount();
3497 out << movableSections;
3498 out << clickableSections;
3499 out << highlightSelected;
3500 out << stretchLastSection;
3501 out << cascadingResizing;
3502 out << stretchSections;
3503 out << contentsSections;
3504 out << defaultSectionSize;
3505 out << minimumSectionSize;
3507 out << int(defaultAlignment);
3508 out << int(globalResizeMode);
3510 out << sectionItems;
3513 bool QHeaderViewPrivate::read(QDataStream &in)
3515 int orient, order, align, global;
3517 orientation = (Qt::Orientation)orient;
3520 sortIndicatorOrder = (Qt::SortOrder)order;
3522 in >> sortIndicatorSection;
3523 in >> sortIndicatorShown;
3525 in >> visualIndices;
3526 in >> logicalIndices;
3528 in >> sectionHidden;
3529 in >> hiddenSectionSize;
3532 int unusedSectionCount; // For compatibility
3533 in >> unusedSectionCount;
3534 in >> movableSections;
3535 in >> clickableSections;
3536 in >> highlightSelected;
3537 in >> stretchLastSection;
3538 in >> cascadingResizing;
3539 in >> stretchSections;
3540 in >> contentsSections;
3541 in >> defaultSectionSize;
3542 in >> minimumSectionSize;
3545 defaultAlignment = Qt::Alignment(align);
3548 globalResizeMode = (QHeaderView::ResizeMode)global;
3551 // In Qt4 we had a vector of spans where one span could hold information on more sections.
3552 // Now we have an itemvector where one items contains information about one section
3553 // For backward compatibility with Qt4 we do the following
3554 QVector<SectionItem> newSectionItems;
3555 for (int u = 0; u < sectionItems.count(); ++u) {
3556 int count = sectionItems.at(u).tmpDataStreamSectionCount;
3557 for (int n = 0; n < count; ++n)
3558 newSectionItems.append(sectionItems[u]);
3560 sectionItems = newSectionItems;
3561 recalcSectionStartPos();
3565 #endif // QT_NO_DATASTREAM
3569 #endif // QT_NO_ITEMVIEWS
3571 #include "moc_qheaderview.cpp"