1
/****************************************************************************
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
6
** This file is part of the QtWidgets 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 The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 3 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 3 requirements
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25
** GNU General Public License Usage
26
** Alternatively, this file may be used under the terms of the GNU
27
** General Public License version 2.0 or (at your option) the GNU General
28
** Public license version 3 or any later version approved by the KDE Free
29
** Qt Foundation. The licenses are as published by the Free Software
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31
** included in the packaging of this file. Please review the following
32
** information to ensure the GNU General Public License requirements will
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34
** https://www.gnu.org/licenses/gpl-3.0.html.
38
****************************************************************************/
40
#include "qheaderview.h"
42
#ifndef QT_NO_ITEMVIEWS
43
#include <qbitarray.h>
48
#include <qscrollbar.h>
50
#include <qwhatsthis.h>
52
#include <qstyleoption.h>
54
#include <qapplication.h>
55
#include <qvarlengtharray.h>
56
#include <qabstractitemdelegate.h>
58
#include <private/qheaderview_p.h>
59
#include <private/qabstractitemmodel_p.h>
61
#ifndef QT_NO_DATASTREAM
62
#include <qdatastream.h>
67
#ifndef QT_NO_DATASTREAM
68
QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionItem §ion)
74
QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionItem §ion)
79
#endif // QT_NO_DATASTREAM
81
static const int maxSizeSection = 1048575; // since section size is in a bitfield (uint 20). See qheaderview_p.h
82
// if this is changed then the docs in maximumSectionSize should be changed.
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 \c 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
d->persistentHiddenSections.clear();
354
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
355
if (d->orientation == Qt::Horizontal) {
356
QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
357
this, SLOT(sectionsInserted(QModelIndex,int,int)));
358
QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
359
this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
360
QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
361
this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
362
QObject::disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
363
this, SLOT(_q_layoutAboutToBeChanged()));
365
QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
366
this, SLOT(sectionsInserted(QModelIndex,int,int)));
367
QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
368
this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
369
QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
370
this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
371
QObject::disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
372
this, SLOT(_q_layoutAboutToBeChanged()));
374
QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
375
this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
376
QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
377
this, SLOT(_q_layoutAboutToBeChanged()));
380
if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
381
if (d->orientation == Qt::Horizontal) {
382
QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
383
this, SLOT(sectionsInserted(QModelIndex,int,int)));
384
QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
385
this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
386
QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
387
this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
388
QObject::connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
389
this, SLOT(_q_layoutAboutToBeChanged()));
391
QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
392
this, SLOT(sectionsInserted(QModelIndex,int,int)));
393
QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
394
this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
395
QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
396
this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
397
QObject::connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
398
this, SLOT(_q_layoutAboutToBeChanged()));
400
QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
401
this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
402
QObject::connect(model, SIGNAL(layoutAboutToBeChanged()),
403
this, SLOT(_q_layoutAboutToBeChanged()));
406
d->state = QHeaderViewPrivate::NoClear;
407
QAbstractItemView::setModel(model);
408
d->state = QHeaderViewPrivate::NoState;
410
// Users want to set sizes and modes before the widget is shown.
411
// Thus, we have to initialize when the model is set,
412
// and not lazily like we do in the other views.
413
initializeSections();
417
Returns the orientation of the header.
422
Qt::Orientation QHeaderView::orientation() const
424
Q_D(const QHeaderView);
425
return d->orientation;
429
Returns the offset of the header: this is the header's left-most (or
430
top-most for vertical headers) visible pixel.
435
int QHeaderView::offset() const
437
Q_D(const QHeaderView);
442
\fn void QHeaderView::setOffset(int offset)
444
Sets the header's offset to \a offset.
446
\sa offset(), length()
449
void QHeaderView::setOffset(int newOffset)
452
if (d->offset == (int)newOffset)
454
int ndelta = d->offset - newOffset;
455
d->offset = newOffset;
456
if (d->orientation == Qt::Horizontal)
457
d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
459
d->viewport->scroll(0, ndelta);
460
if (d->state == QHeaderViewPrivate::ResizeSection && !d->preventCursorChangeInSetOffset) {
461
QPoint cursorPos = QCursor::pos();
462
if (d->orientation == Qt::Horizontal)
463
QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
465
QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
466
d->firstPos += ndelta;
467
d->lastPos += ndelta;
473
Sets the offset to the start of the section at the given \a visualSectionNumber.
474
\a visualSectionNumber is the actual visible section when hiddenSections are
475
not considered. That is not always the same as visualIndex().
477
\sa setOffset(), sectionPosition()
479
void QHeaderView::setOffsetToSectionPosition(int visualSectionNumber)
482
if (visualSectionNumber > -1 && visualSectionNumber < d->sectionCount()) {
483
int position = d->headerSectionPosition(d->adjustedVisualIndex(visualSectionNumber));
490
Sets the offset to make the last section visible.
492
\sa setOffset(), sectionPosition(), setOffsetToSectionPosition()
494
void QHeaderView::setOffsetToLastSection()
496
Q_D(const QHeaderView);
497
int size = (d->orientation == Qt::Horizontal ? viewport()->width() : viewport()->height());
498
int position = length() - size;
503
Returns the length along the orientation of the header.
505
\sa sizeHint(), setSectionResizeMode(), offset()
508
int QHeaderView::length() const
510
Q_D(const QHeaderView);
511
d->executePostedLayout();
512
d->executePostedResize();
513
//Q_ASSERT(d->headerLength() == d->length);
518
Returns a suitable size hint for this header.
520
\sa sectionSizeHint()
523
QSize QHeaderView::sizeHint() const
525
Q_D(const QHeaderView);
526
if (d->cachedSizeHint.isValid())
527
return d->cachedSizeHint;
528
d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint
529
const int sectionCount = count();
531
// get size hint for the first n sections
533
for (int checked = 0; checked < 100 && i < sectionCount; ++i) {
534
if (isSectionHidden(i))
537
QSize hint = sectionSizeFromContents(i);
538
d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
540
// get size hint for the last n sections
541
i = qMax(i, sectionCount - 100 );
542
for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) {
543
if (isSectionHidden(j))
546
QSize hint = sectionSizeFromContents(j);
547
d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
549
return d->cachedSizeHint;
556
void QHeaderView::setVisible(bool v)
558
bool actualChange = (v != isVisible());
559
QAbstractItemView::setVisible(v);
561
QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea*>(parentWidget());
563
parent->updateGeometry();
569
Returns a suitable size hint for the section specified by \a logicalIndex.
571
\sa sizeHint(), defaultSectionSize(), minimumSectionSize(), maximumSectionSize()
575
int QHeaderView::sectionSizeHint(int logicalIndex) const
577
Q_D(const QHeaderView);
578
if (isSectionHidden(logicalIndex))
580
if (logicalIndex < 0 || logicalIndex >= count())
583
QVariant value = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
585
size = qvariant_cast<QSize>(value);
587
size = sectionSizeFromContents(logicalIndex);
588
int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
589
return qBound(minimumSectionSize(), hint, maximumSectionSize());
593
Returns the visual index of the section that covers the given \a position
599
int QHeaderView::visualIndexAt(int position) const
601
Q_D(const QHeaderView);
602
int vposition = position;
603
d->executePostedLayout();
604
d->executePostedResize();
605
const int count = d->sectionCount();
610
vposition = d->viewport->width() - vposition;
611
vposition += d->offset;
613
if (vposition > d->length)
615
int visual = d->headerVisualIndexAt(vposition);
619
while (d->isVisualIndexHidden(visual)){
628
Returns the section that covers the given \a position in the viewport.
630
\sa visualIndexAt(), isSectionHidden()
633
int QHeaderView::logicalIndexAt(int position) const
635
const int visual = visualIndexAt(position);
637
return logicalIndex(visual);
642
Returns the width (or height for vertical headers) of the given
645
\sa length(), setSectionResizeMode(), defaultSectionSize()
648
int QHeaderView::sectionSize(int logicalIndex) const
650
Q_D(const QHeaderView);
651
if (isSectionHidden(logicalIndex))
653
if (logicalIndex < 0 || logicalIndex >= count())
655
int visual = visualIndex(logicalIndex);
658
d->executePostedResize();
659
return d->headerSectionSize(visual);
664
Returns the section position of the given \a logicalIndex, or -1
665
if the section is hidden. The position is measured in pixels from
666
the first visible item's top-left corner to the top-left corner of
667
the item with \a logicalIndex. The measurement is along the x-axis
668
for horizontal headers and along the y-axis for vertical headers.
670
\sa sectionViewportPosition()
673
int QHeaderView::sectionPosition(int logicalIndex) const
675
Q_D(const QHeaderView);
676
int visual = visualIndex(logicalIndex);
677
// in some cases users may change the selections
678
// before we have a chance to do the layout
681
d->executePostedResize();
682
return d->headerSectionPosition(visual);
686
Returns the section viewport position of the given \a logicalIndex.
688
If the section is hidden, the return value is undefined.
690
\sa sectionPosition(), isSectionHidden()
693
int QHeaderView::sectionViewportPosition(int logicalIndex) const
695
Q_D(const QHeaderView);
696
if (logicalIndex >= count())
698
int position = sectionPosition(logicalIndex);
700
return position; // the section was hidden
701
int offsetPosition = position - d->offset;
703
return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
704
return offsetPosition;
708
\fn int QHeaderView::logicalIndexAt(int x, int y) const
710
Returns the logical index of the section at the given coordinate. If the
711
header is horizontal \a x will be used, otherwise \a y will be used to
712
find the logical index.
716
\fn int QHeaderView::logicalIndexAt(const QPoint &pos) const
718
Returns the logical index of the section at the position given in \a pos.
719
If the header is horizontal the x-coordinate will be used, otherwise the
720
y-coordinate will be used to find the logical index.
722
\sa sectionPosition()
725
template<typename Container>
726
static void qMoveRange(Container& c,
727
typename Container::size_type rangeStart,
728
typename Container::size_type rangeEnd,
729
typename Container::size_type targetPosition)
731
Q_ASSERT(targetPosition <= c.size());
732
Q_ASSERT(targetPosition < rangeStart || targetPosition >= rangeEnd);
734
const bool forwardMove = targetPosition > rangeStart;
735
typename Container::size_type first = std::min(rangeStart, targetPosition);
736
typename Container::size_type mid = forwardMove ? rangeEnd : rangeStart;
737
typename Container::size_type last = forwardMove ? targetPosition + 1 : rangeEnd;
738
std::rotate(c.begin() + first, c.begin() + mid, c.begin() + last);
742
Moves the section at visual index \a from to occupy visual index \a to.
747
void QHeaderView::moveSection(int from, int to)
751
d->executePostedLayout();
752
if (from < 0 || from >= d->sectionCount() || to < 0 || to >= d->sectionCount())
756
int logical = logicalIndex(from);
757
Q_ASSERT(logical != -1);
758
updateSection(logical);
762
d->initializeIndexMapping();
764
int *visualIndices = d->visualIndices.data();
765
int *logicalIndices = d->logicalIndices.data();
766
int logical = logicalIndices[from];
770
while (visual < to) {
771
visualIndices[logicalIndices[visual + 1]] = visual;
772
logicalIndices[visual] = logicalIndices[visual + 1];
776
while (visual > to) {
777
visualIndices[logicalIndices[visual - 1]] = visual;
778
logicalIndices[visual] = logicalIndices[visual - 1];
782
visualIndices[logical] = to;
783
logicalIndices[to] = logical;
785
qMoveRange(d->sectionItems, from, from + 1, to);
787
d->sectionStartposRecalc = true;
789
if (d->hasAutoResizeSections())
790
d->doDelayedResizeSections();
791
d->viewport->update();
793
emit sectionMoved(logical, from, to);
795
if (stretchLastSection()) {
796
const int lastSectionVisualIdx = visualIndex(d->lastSectionLogicalIdx);
797
if (from >= lastSectionVisualIdx || to >= lastSectionVisualIdx)
798
d->maybeRestorePrevLastSectionAndStretchLast();
804
Swaps the section at visual index \a first with the section at visual
809
void QHeaderView::swapSections(int first, int second)
815
d->executePostedLayout();
816
if (first < 0 || first >= d->sectionCount() || second < 0 || second >= d->sectionCount())
819
int firstSize = d->headerSectionSize(first);
820
ResizeMode firstMode = d->headerSectionResizeMode(first);
821
int firstLogical = d->logicalIndex(first);
823
int secondSize = d->headerSectionSize(second);
824
ResizeMode secondMode = d->headerSectionResizeMode(second);
825
int secondLogical = d->logicalIndex(second);
827
if (d->state == QHeaderViewPrivate::ResizeSection)
828
d->preventCursorChangeInSetOffset = true;
830
d->createSectionItems(second, second, firstSize, firstMode);
831
d->createSectionItems(first, first, secondSize, secondMode);
833
d->initializeIndexMapping();
835
d->visualIndices[firstLogical] = second;
836
d->logicalIndices[second] = firstLogical;
838
d->visualIndices[secondLogical] = first;
839
d->logicalIndices[first] = secondLogical;
841
if (!d->hiddenSectionSize.isEmpty()) {
842
bool firstHidden = d->isVisualIndexHidden(first);
843
bool secondHidden = d->isVisualIndexHidden(second);
844
d->setVisualIndexHidden(first, secondHidden);
845
d->setVisualIndexHidden(second, firstHidden);
848
d->viewport->update();
849
emit sectionMoved(firstLogical, first, second);
850
emit sectionMoved(secondLogical, second, first);
852
if (stretchLastSection()) {
853
const int lastSectionVisualIdx = visualIndex(d->lastSectionLogicalIdx);
854
if (first >= lastSectionVisualIdx || second >= lastSectionVisualIdx)
855
d->maybeRestorePrevLastSectionAndStretchLast();
860
\fn void QHeaderView::resizeSection(int logicalIndex, int size)
862
Resizes the section specified by \a logicalIndex to \a size measured in
863
pixels. The size parameter must be a value larger or equal to zero. A
864
size equal to zero is however not recommended. In that situation hideSection
865
should be used instead.
867
\sa sectionResized(), resizeMode(), sectionSize(), hideSection()
870
void QHeaderView::resizeSection(int logical, int size)
873
if (logical < 0 || logical >= count() || size < 0 || size > maxSizeSection)
876
if (isSectionHidden(logical)) {
877
d->hiddenSectionSize.insert(logical, size);
881
int visual = visualIndex(logical);
885
if (d->state == QHeaderViewPrivate::ResizeSection && !d->cascadingResizing && logical != d->section)
886
d->preventCursorChangeInSetOffset = true;
888
int oldSize = d->headerSectionSize(visual);
892
d->executePostedLayout();
893
d->invalidateCachedSizeHint();
895
if (stretchLastSection() && logical == d->lastSectionLogicalIdx)
896
d->lastSectionSize = size;
898
d->createSectionItems(visual, visual, size, d->headerSectionResizeMode(visual));
900
if (!updatesEnabled()) {
901
if (d->hasAutoResizeSections())
902
d->doDelayedResizeSections();
903
emit sectionResized(logical, oldSize, size);
907
int w = d->viewport->width();
908
int h = d->viewport->height();
909
int pos = sectionViewportPosition(logical);
911
if (d->orientation == Qt::Horizontal)
913
r.setRect(0, 0, pos + size, h);
915
r.setRect(pos, 0, w - pos, h);
917
r.setRect(0, pos, w, h - pos);
919
if (d->hasAutoResizeSections()) {
920
d->doDelayedResizeSections();
921
r = d->viewport->rect();
924
// If the parent is a QAbstractScrollArea with QAbstractScrollArea::AdjustToContents
925
// then we want to change the geometry on that widget. Not doing it at once can/will
926
// cause scrollbars flicker as they would be shown at first but then removed.
927
// In the same situation it will also allow shrinking the whole view when stretchLastSection is set
928
// (It is default on QTreeViews - and it wouldn't shrink since the last stretch was made before the
929
// viewport was resized)
931
QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget());
932
if (parent && parent->sizeAdjustPolicy() == QAbstractScrollArea::AdjustToContents)
933
parent->updateGeometry();
935
d->viewport->update(r.normalized());
936
emit sectionResized(logical, oldSize, size);
940
Resizes the sections according to the given \a mode, ignoring the current
943
\sa resizeMode(), sectionResized()
946
void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
949
d->resizeSections(mode, true);
953
\fn void QHeaderView::hideSection(int logicalIndex)
954
Hides the section specified by \a logicalIndex.
956
\sa showSection(), isSectionHidden(), hiddenSectionCount(),
961
\fn void QHeaderView::showSection(int logicalIndex)
962
Shows the section specified by \a logicalIndex.
964
\sa hideSection(), isSectionHidden(), hiddenSectionCount(),
969
Returns \c true if the section specified by \a logicalIndex is explicitly
970
hidden from the user; otherwise returns \c false.
972
\sa hideSection(), showSection(), setSectionHidden(), hiddenSectionCount()
975
bool QHeaderView::isSectionHidden(int logicalIndex) const
977
Q_D(const QHeaderView);
978
d->executePostedLayout();
979
if (d->hiddenSectionSize.isEmpty() || logicalIndex < 0 || logicalIndex >= d->sectionCount())
981
int visual = visualIndex(logicalIndex);
982
Q_ASSERT(visual != -1);
983
return d->isVisualIndexHidden(visual);
989
Returns the number of sections in the header that has been hidden.
991
\sa setSectionHidden(), isSectionHidden()
993
int QHeaderView::hiddenSectionCount() const
995
Q_D(const QHeaderView);
996
return d->hiddenSectionSize.count();
1000
If \a hide is true the section specified by \a logicalIndex is hidden;
1001
otherwise the section is shown.
1003
\sa isSectionHidden(), hiddenSectionCount()
1006
void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
1009
if (logicalIndex < 0 || logicalIndex >= count())
1012
d->executePostedLayout();
1013
int visual = visualIndex(logicalIndex);
1014
Q_ASSERT(visual != -1);
1015
if (hide == d->isVisualIndexHidden(visual))
1018
const bool isHidingLastSection = (stretchLastSection() && logicalIndex == d->lastSectionLogicalIdx);
1019
if (isHidingLastSection)
1020
d->restoreSizeOnPrevLastSection(); // Restore here/now to get the right restore size.
1021
int size = d->headerSectionSize(visual);
1022
if (!d->hasAutoResizeSections())
1023
resizeSection(logicalIndex, 0);
1024
d->hiddenSectionSize.insert(logicalIndex, size);
1025
d->setVisualIndexHidden(visual, true);
1026
if (isHidingLastSection)
1027
d->setNewLastSection(d->lastVisibleVisualIndex());
1028
if (d->hasAutoResizeSections())
1029
d->doDelayedResizeSections();
1031
int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
1032
d->hiddenSectionSize.remove(logicalIndex);
1033
d->setVisualIndexHidden(visual, false);
1034
resizeSection(logicalIndex, size);
1036
const bool newLastSection = (stretchLastSection() && visual > visualIndex(d->lastSectionLogicalIdx));
1037
if (newLastSection) {
1038
d->restoreSizeOnPrevLastSection();
1039
d->setNewLastSection(visual);
1045
Returns the number of sections in the header.
1047
\sa sectionCountChanged(), length()
1050
int QHeaderView::count() const
1052
Q_D(const QHeaderView);
1053
//Q_ASSERT(d->sectionCount == d->headerSectionCount());
1054
// ### this may affect the lazy layout
1055
d->executePostedLayout();
1056
return d->sectionCount();
1060
Returns the visual index position of the section specified by the given
1061
\a logicalIndex, or -1 otherwise.
1063
Hidden sections still have valid visual indexes.
1068
int QHeaderView::visualIndex(int logicalIndex) const
1070
Q_D(const QHeaderView);
1071
if (logicalIndex < 0)
1073
d->executePostedLayout();
1074
if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
1075
if (logicalIndex < d->sectionCount())
1076
return logicalIndex;
1077
} else if (logicalIndex < d->visualIndices.count()) {
1078
int visual = d->visualIndices.at(logicalIndex);
1079
Q_ASSERT(visual < d->sectionCount());
1086
Returns the logicalIndex for the section at the given \a visualIndex
1087
position, or -1 if visualIndex < 0 or visualIndex >= QHeaderView::count().
1089
Note that the visualIndex is not affected by hidden sections.
1091
\sa visualIndex(), sectionPosition()
1094
int QHeaderView::logicalIndex(int visualIndex) const
1096
Q_D(const QHeaderView);
1097
if (visualIndex < 0 || visualIndex >= d->sectionCount())
1099
return d->logicalIndex(visualIndex);
1105
If \a movable is true, the header may be moved by the user; otherwise it
1108
\sa sectionsMovable(), sectionMoved()
1111
void QHeaderView::setSectionsMovable(bool movable)
1114
d->movableSections = movable;
1117
// ### Qt 6 - remove this obsolete function
1120
\fn void QHeaderView::setMovable(bool movable)
1122
Use setSectionsMovable instead.
1124
\sa setSectionsMovable()
1130
Returns \c true if the header can be moved by the user; otherwise returns
1133
\sa setSectionsMovable()
1136
bool QHeaderView::sectionsMovable() const
1138
Q_D(const QHeaderView);
1139
return d->movableSections;
1142
// ### Qt 6 - remove this obsolete function
1145
\fn bool QHeaderView::isMovable() const
1147
Use sectionsMovable instead.
1149
\sa sectionsMovable()
1155
If \a clickable is true, the header will respond to single clicks.
1157
\sa sectionsClickable(), sectionClicked(), sectionPressed(),
1158
setSortIndicatorShown()
1161
void QHeaderView::setSectionsClickable(bool clickable)
1164
d->clickableSections = clickable;
1167
// ### Qt 6 - remove this obsolete function
1170
\fn void QHeaderView::setClickable(bool clickable)
1172
Use setSectionsClickable instead.
1174
\sa setSectionsClickable()
1180
Returns \c true if the header is clickable; otherwise returns \c false. A
1181
clickable header could be set up to allow the user to change the
1182
representation of the data in the view related to the header.
1184
\sa setSectionsClickable()
1187
bool QHeaderView::sectionsClickable() const
1189
Q_D(const QHeaderView);
1190
return d->clickableSections;
1193
// ### Qt 6 - remove this obsolete function
1196
\fn bool QHeaderView::isClickable() const
1198
Use sectionsClickable instead.
1200
\sa sectionsClickable()
1203
void QHeaderView::setHighlightSections(bool highlight)
1206
d->highlightSelected = highlight;
1209
bool QHeaderView::highlightSections() const
1211
Q_D(const QHeaderView);
1212
return d->highlightSelected;
1218
Sets the constraints on how the header can be resized to those described
1219
by the given \a mode.
1221
\sa resizeMode(), length(), sectionResized()
1224
void QHeaderView::setSectionResizeMode(ResizeMode mode)
1227
initializeSections();
1228
d->stretchSections = (mode == Stretch ? count() : 0);
1229
d->contentsSections = (mode == ResizeToContents ? count() : 0);
1230
d->setGlobalHeaderResizeMode(mode);
1231
if (d->hasAutoResizeSections())
1232
d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1238
Sets the constraints on how the section specified by \a logicalIndex in
1239
the header can be resized to those described by the given \a mode. The logical
1240
index should exist at the time this function is called.
1242
\note This setting will be ignored for the last section if the stretchLastSection
1243
property is set to true. This is the default for the horizontal headers provided
1246
\sa setStretchLastSection(), resizeContentsPrecision()
1249
void QHeaderView::setSectionResizeMode(int logicalIndex, ResizeMode mode)
1252
int visual = visualIndex(logicalIndex);
1253
Q_ASSERT(visual != -1);
1255
ResizeMode old = d->headerSectionResizeMode(visual);
1256
d->setHeaderSectionResizeMode(visual, mode);
1258
if (mode == Stretch && old != Stretch)
1259
++d->stretchSections;
1260
else if (mode == ResizeToContents && old != ResizeToContents)
1261
++d->contentsSections;
1262
else if (mode != Stretch && old == Stretch)
1263
--d->stretchSections;
1264
else if (mode != ResizeToContents && old == ResizeToContents)
1265
--d->contentsSections;
1267
if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
1268
d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1271
// ### Qt 6 - remove this obsolete function
1275
\fn void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
1277
Use setSectionResizeMode instead.
1279
\sa setSectionResizeMode()
1284
\fn void QHeaderView::setResizeMode(ResizeMode mode)
1286
Use setSectionResizeMode instead.
1288
\sa setSectionResizeMode()
1294
Returns the resize mode that applies to the section specified by the given
1297
\sa setSectionResizeMode()
1300
QHeaderView::ResizeMode QHeaderView::sectionResizeMode(int logicalIndex) const
1302
Q_D(const QHeaderView);
1303
int visual = visualIndex(logicalIndex);
1305
return Fixed; //the default value
1306
return d->headerSectionResizeMode(visual);
1311
Sets how precise QHeaderView should calculate the size when ResizeToContents is used.
1312
A low value will provide a less accurate but fast auto resize while a higher
1313
value will provide a more accurate resize that however can be slow.
1315
The number \a precision specifies how many sections that should be consider
1316
when calculating the preferred size.
1318
The default value is 1000 meaning that a horizontal column with auto-resize will look
1319
at maximum 1000 rows on calculating when doing an auto resize.
1321
Special value 0 means that it will look at only the visible area.
1322
Special value -1 will imply looking at all elements.
1324
This value is used in QTableView::sizeHintForColumn(), QTableView::sizeHintForRow()
1325
and QTreeView::sizeHintForColumn(). Reimplementing these functions can make this
1326
function not having an effect.
1328
\sa resizeContentsPrecision(), setSectionResizeMode(), resizeSections(), QTableView::sizeHintForColumn(), QTableView::sizeHintForRow(), QTreeView::sizeHintForColumn()
1331
void QHeaderView::setResizeContentsPrecision(int precision)
1334
d->resizeContentsPrecision = precision;
1339
Returns how precise QHeaderView will calculate on ResizeToContents.
1341
\sa setResizeContentsPrecision(), setSectionResizeMode()
1345
int QHeaderView::resizeContentsPrecision() const
1347
Q_D(const QHeaderView);
1348
return d->resizeContentsPrecision;
1351
// ### Qt 6 - remove this obsolete function
1354
\fn QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
1356
Use sectionResizeMode instead.
1358
\sa sectionResizeMode()
1364
Returns the number of sections that are set to resize mode stretch. In
1365
views, this can be used to see if the headerview needs to resize the
1366
sections when the view's geometry changes.
1368
\sa stretchLastSection, resizeMode()
1371
int QHeaderView::stretchSectionCount() const
1373
Q_D(const QHeaderView);
1374
return d->stretchSections;
1378
\property QHeaderView::showSortIndicator
1379
\brief whether the sort indicator is shown
1381
By default, this property is \c false.
1383
\sa setSectionsClickable()
1386
void QHeaderView::setSortIndicatorShown(bool show)
1389
if (d->sortIndicatorShown == show)
1392
d->sortIndicatorShown = show;
1394
if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
1397
if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
1400
d->viewport->update();
1403
bool QHeaderView::isSortIndicatorShown() const
1405
Q_D(const QHeaderView);
1406
return d->sortIndicatorShown;
1410
Sets the sort indicator for the section specified by the given
1411
\a logicalIndex in the direction specified by \a order, and removes the
1412
sort indicator from any other section that was showing it.
1414
\a logicalIndex may be -1, in which case no sort indicator will be shown
1415
and the model will return to its natural, unsorted order. Note that not
1416
all models support this and may even crash in this case.
1418
\sa sortIndicatorSection(), sortIndicatorOrder()
1421
void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
1425
// This is so that people can set the position of the sort indicator before the fill the model
1426
int old = d->sortIndicatorSection;
1427
if (old == logicalIndex && order == d->sortIndicatorOrder)
1429
d->sortIndicatorSection = logicalIndex;
1430
d->sortIndicatorOrder = order;
1432
if (logicalIndex >= d->sectionCount()) {
1433
emit sortIndicatorChanged(logicalIndex, order);
1434
return; // nothing to do
1437
if (old != logicalIndex
1438
&& ((logicalIndex >= 0 && sectionResizeMode(logicalIndex) == ResizeToContents)
1439
|| old >= d->sectionCount() || (old >= 0 && sectionResizeMode(old) == ResizeToContents))) {
1441
d->viewport->update();
1443
if (old >= 0 && old != logicalIndex)
1445
if (logicalIndex >= 0)
1446
updateSection(logicalIndex);
1449
emit sortIndicatorChanged(logicalIndex, order);
1453
Returns the logical index of the section that has a sort indicator.
1454
By default this is section 0.
1456
\sa setSortIndicator(), sortIndicatorOrder(), setSortIndicatorShown()
1459
int QHeaderView::sortIndicatorSection() const
1461
Q_D(const QHeaderView);
1462
return d->sortIndicatorSection;
1466
Returns the order for the sort indicator. If no section has a sort
1467
indicator the return value of this function is undefined.
1469
\sa setSortIndicator(), sortIndicatorSection()
1472
Qt::SortOrder QHeaderView::sortIndicatorOrder() const
1474
Q_D(const QHeaderView);
1475
return d->sortIndicatorOrder;
1479
\property QHeaderView::stretchLastSection
1480
\brief whether the last visible section in the header takes up all the
1483
The default value is false.
1485
\note The horizontal headers provided by QTreeView are configured with this
1486
property set to true, ensuring that the view does not waste any of the
1487
space assigned to it for its header. If this value is set to true, this
1488
property will override the resize mode set on the last section in the
1491
\sa setSectionResizeMode()
1493
bool QHeaderView::stretchLastSection() const
1495
Q_D(const QHeaderView);
1496
return d->stretchLastSection;
1499
void QHeaderView::setStretchLastSection(bool stretch)
1502
if (d->stretchLastSection == stretch)
1504
d->stretchLastSection = stretch;
1505
if (d->state != QHeaderViewPrivate::NoState)
1508
d->setNewLastSection(d->lastVisibleVisualIndex());
1511
d->restoreSizeOnPrevLastSection();
1517
\property QHeaderView::cascadingSectionResizes
1518
\brief whether interactive resizing will be cascaded to the following
1519
sections once the section being resized by the user has reached its
1522
This property only affects sections that have \l Interactive as their
1525
The default value is false.
1527
\sa setSectionResizeMode()
1529
bool QHeaderView::cascadingSectionResizes() const
1531
Q_D(const QHeaderView);
1532
return d->cascadingResizing;
1535
void QHeaderView::setCascadingSectionResizes(bool enable)
1538
d->cascadingResizing = enable;
1542
\property QHeaderView::defaultSectionSize
1543
\brief the default size of the header sections before resizing.
1545
This property only affects sections that have \l Interactive or \l Fixed
1546
as their resize mode.
1548
By default, the value of this property is style dependent.
1549
Thus, when the style changes, this property updates from it.
1550
Calling setDefaultSectionSize() stops the updates, calling
1551
resetDefaultSectionSize() will restore default behavior.
1553
\sa setSectionResizeMode(), minimumSectionSize
1555
int QHeaderView::defaultSectionSize() const
1557
Q_D(const QHeaderView);
1558
return d->defaultSectionSize;
1561
void QHeaderView::setDefaultSectionSize(int size)
1564
if (size < 0 || size > maxSizeSection)
1566
d->setDefaultSectionSize(size);
1569
void QHeaderView::resetDefaultSectionSize()
1572
if (d->customDefaultSectionSize) {
1573
d->updateDefaultSectionSizeFromStyle();
1574
d->customDefaultSectionSize = false;
1580
\property QHeaderView::minimumSectionSize
1581
\brief the minimum size of the header sections.
1583
The minimum section size is the smallest section size allowed. If the
1584
minimum section size is set to -1, QHeaderView will use the maximum of
1585
the \l{QApplication::globalStrut()}{global strut} or the
1586
\l{fontMetrics()}{font metrics} size.
1588
This property is honored by all \l{ResizeMode}{resize modes}.
1590
\sa setSectionResizeMode(), defaultSectionSize
1592
int QHeaderView::minimumSectionSize() const
1594
Q_D(const QHeaderView);
1595
if (d->minimumSectionSize == -1) {
1596
QSize strut = QApplication::globalStrut();
1597
int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
1598
if (d->orientation == Qt::Horizontal)
1599
return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
1600
return qMax(strut.height(), (fontMetrics().height() + margin));
1602
return d->minimumSectionSize;
1605
void QHeaderView::setMinimumSectionSize(int size)
1608
if (size < -1 || size > maxSizeSection)
1610
d->minimumSectionSize = size;
1611
if (d->minimumSectionSize > maximumSectionSize())
1612
d->maximumSectionSize = size;
1617
\property QHeaderView::maximumSectionSize
1618
\brief the maximum size of the header sections.
1620
The maximum section size is the largest section size allowed.
1621
The default value for this property is 1048575, which is also the largest
1622
possible size for a section. Setting maximum to -1 will reset the value to
1623
the largest section size.
1625
With exception of stretch this property is honored by all \l{ResizeMode}{resize modes}
1627
\sa setSectionResizeMode(), defaultSectionSize
1629
int QHeaderView::maximumSectionSize() const
1631
Q_D(const QHeaderView);
1632
if (d->maximumSectionSize == -1)
1633
return maxSizeSection;
1634
return d->maximumSectionSize;
1637
void QHeaderView::setMaximumSectionSize(int size)
1641
d->maximumSectionSize = maxSizeSection;
1644
if (size < 0 || size > maxSizeSection)
1646
if (minimumSectionSize() > size)
1647
d->minimumSectionSize = size;
1649
d->maximumSectionSize = size;
1655
\property QHeaderView::defaultAlignment
1656
\brief the default alignment of the text in each header section
1659
Qt::Alignment QHeaderView::defaultAlignment() const
1661
Q_D(const QHeaderView);
1662
return d->defaultAlignment;
1665
void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
1668
if (d->defaultAlignment == alignment)
1671
d->defaultAlignment = alignment;
1672
d->viewport->update();
1678
void QHeaderView::doItemsLayout()
1680
initializeSections();
1681
QAbstractItemView::doItemsLayout();
1685
Returns \c true if sections in the header has been moved; otherwise returns
1690
bool QHeaderView::sectionsMoved() const
1692
Q_D(const QHeaderView);
1693
return !d->visualIndices.isEmpty();
1699
Returns \c true if sections in the header has been hidden; otherwise returns
1702
\sa setSectionHidden()
1704
bool QHeaderView::sectionsHidden() const
1706
Q_D(const QHeaderView);
1707
return !d->hiddenSectionSize.isEmpty();
1710
#ifndef QT_NO_DATASTREAM
1714
Saves the current state of this header view.
1716
To restore the saved state, pass the return value to restoreState().
1720
QByteArray QHeaderView::saveState() const
1722
Q_D(const QHeaderView);
1724
QDataStream stream(&data, QIODevice::WriteOnly);
1725
stream << QHeaderViewPrivate::VersionMarker;
1726
stream << 0; // current version is 0
1733
Restores the \a state of this header view.
1734
This function returns \c true if the state was restored; otherwise returns
1739
bool QHeaderView::restoreState(const QByteArray &state)
1742
if (state.isEmpty())
1744
QByteArray data = state;
1745
QDataStream stream(&data, QIODevice::ReadOnly);
1750
if (stream.status() != QDataStream::Ok
1751
|| marker != QHeaderViewPrivate::VersionMarker
1752
|| ver != 0) // current version is 0
1755
if (d->read(stream)) {
1756
emit sortIndicatorChanged(d->sortIndicatorSection, d->sortIndicatorOrder );
1757
d->viewport->update();
1762
#endif // QT_NO_DATASTREAM
1767
void QHeaderView::reset()
1769
QAbstractItemView::reset();
1770
// it would be correct to call clear, but some apps rely
1771
// on the header keeping the sections, even after calling reset
1773
initializeSections();
1777
Updates the changed header sections with the given \a orientation, from
1778
\a logicalFirst to \a logicalLast inclusive.
1780
void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
1783
if (d->orientation != orientation)
1786
if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
1789
d->invalidateCachedSizeHint();
1791
int firstVisualIndex = INT_MAX, lastVisualIndex = -1;
1793
for (int section = logicalFirst; section <= logicalLast; ++section) {
1794
const int visual = visualIndex(section);
1795
firstVisualIndex = qMin(firstVisualIndex, visual);
1796
lastVisualIndex = qMax(lastVisualIndex, visual);
1799
d->executePostedResize();
1800
const int first = d->headerSectionPosition(firstVisualIndex),
1801
last = d->headerSectionPosition(lastVisualIndex)
1802
+ d->headerSectionSize(lastVisualIndex);
1804
if (orientation == Qt::Horizontal) {
1805
d->viewport->update(first, 0, last - first, d->viewport->height());
1807
d->viewport->update(0, first, d->viewport->width(), last - first);
1815
Updates the section specified by the given \a logicalIndex.
1818
void QHeaderView::updateSection(int logicalIndex)
1821
if (d->orientation == Qt::Horizontal)
1822
d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
1823
0, sectionSize(logicalIndex), d->viewport->height()));
1825
d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
1826
d->viewport->width(), sectionSize(logicalIndex)));
1830
Resizes the sections according to their size hints. Normally, you do not
1831
have to call this function.
1834
void QHeaderView::resizeSections()
1837
if (d->hasAutoResizeSections())
1838
d->resizeSections(Interactive, false); // no global resize mode
1842
This slot is called when sections are inserted into the \a parent.
1843
\a logicalFirst and \a logicalLast indices signify where the new sections
1846
If only one section is inserted, \a logicalFirst and \a logicalLast will
1850
void QHeaderView::sectionsInserted(const QModelIndex &parent,
1851
int logicalFirst, int logicalLast)
1854
if (parent != d->root)
1855
return; // we only handle changes in the root level
1856
int oldCount = d->sectionCount();
1858
d->invalidateCachedSizeHint();
1860
if (d->state == QHeaderViewPrivate::ResizeSection)
1861
d->preventCursorChangeInSetOffset = true;
1863
// add the new sections
1864
int insertAt = logicalFirst;
1865
int insertCount = logicalLast - logicalFirst + 1;
1867
bool lastSectionActualChange = false;
1868
if (stretchLastSection()) {
1870
int visualIndexForStretch = d->lastSectionLogicalIdx;
1871
if (d->lastSectionLogicalIdx >= 0 && d->lastSectionLogicalIdx < d->visualIndices.size())
1872
visualIndexForStretch = d->visualIndices[d->lastSectionLogicalIdx]; // We cannot call visualIndex since it executes executePostedLayout()
1873
// and it is likely to bypass initializeSections() and we may end up here again. Doing the insert twice.
1875
if (d->lastSectionLogicalIdx < 0 || insertAt >= visualIndexForStretch)
1876
lastSectionActualChange = true;
1878
if (d->lastSectionLogicalIdx >= logicalFirst)
1879
d->lastSectionLogicalIdx += insertCount; // We do not want to emit resize before we have fixed the count
1882
QHeaderViewPrivate::SectionItem section(d->defaultSectionSize, d->globalResizeMode);
1883
d->sectionStartposRecalc = true;
1885
if (d->sectionItems.isEmpty() || insertAt >= d->sectionItems.count()) {
1886
int insertLength = d->defaultSectionSize * insertCount;
1887
d->length += insertLength;
1888
d->sectionItems.insert(d->sectionItems.count(), insertCount, section); // append
1890
// separate them out into their own sections
1891
int insertLength = d->defaultSectionSize * insertCount;
1892
d->length += insertLength;
1893
d->sectionItems.insert(insertAt, insertCount, section);
1896
// update sorting column
1897
if (d->sortIndicatorSection >= logicalFirst)
1898
d->sortIndicatorSection += insertCount;
1900
// update resize mode section counts
1901
if (d->globalResizeMode == Stretch)
1902
d->stretchSections = d->sectionCount();
1903
else if (d->globalResizeMode == ResizeToContents)
1904
d->contentsSections = d->sectionCount();
1906
// clear selection cache
1907
d->sectionSelected.clear();
1910
if (!d->visualIndices.isEmpty() && !d->logicalIndices.isEmpty()) {
1911
Q_ASSERT(d->visualIndices.count() == d->logicalIndices.count());
1912
int mappingCount = d->visualIndices.count();
1913
for (int i = 0; i < mappingCount; ++i) {
1914
if (d->visualIndices.at(i) >= logicalFirst)
1915
d->visualIndices[i] += insertCount;
1916
if (d->logicalIndices.at(i) >= logicalFirst)
1917
d->logicalIndices[i] += insertCount;
1919
for (int j = logicalFirst; j <= logicalLast; ++j) {
1920
d->visualIndices.insert(j, j);
1921
d->logicalIndices.insert(j, j);
1925
// insert sections into hiddenSectionSize
1926
QHash<int, int> newHiddenSectionSize; // from logical index to section size
1927
for (QHash<int, int>::const_iterator it = d->hiddenSectionSize.cbegin(),
1928
end = d->hiddenSectionSize.cend(); it != end; ++it) {
1929
const int oldIndex = it.key();
1930
const int newIndex = (oldIndex < logicalFirst) ? oldIndex : oldIndex + insertCount;
1931
newHiddenSectionSize[newIndex] = it.value();
1933
d->hiddenSectionSize.swap(newHiddenSectionSize);
1935
d->doDelayedResizeSections();
1936
emit sectionCountChanged(oldCount, count());
1938
if (lastSectionActualChange)
1939
d->maybeRestorePrevLastSectionAndStretchLast();
1941
// if the new sections were not updated by resizing, we need to update now
1942
if (!d->hasAutoResizeSections())
1943
d->viewport->update();
1947
This slot is called when sections are removed from the \a parent.
1948
\a logicalFirst and \a logicalLast signify where the sections were removed.
1950
If only one section is removed, \a logicalFirst and \a logicalLast will
1954
void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
1955
int logicalFirst, int logicalLast)
1958
Q_UNUSED(logicalFirst);
1959
Q_UNUSED(logicalLast);
1962
void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
1965
const int changeCount = logicalLast - logicalFirst + 1;
1967
// remove sections from hiddenSectionSize
1968
QHash<int, int> newHiddenSectionSize; // from logical index to section size
1969
for (int i = 0; i < logicalFirst; ++i)
1970
if (q->isSectionHidden(i))
1971
newHiddenSectionSize[i] = hiddenSectionSize[i];
1972
for (int j = logicalLast + 1; j < sectionCount(); ++j)
1973
if (q->isSectionHidden(j))
1974
newHiddenSectionSize[j - changeCount] = hiddenSectionSize[j];
1975
hiddenSectionSize = newHiddenSectionSize;
1978
void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
1979
int logicalFirst, int logicalLast)
1983
return; // we only handle changes in the root level
1984
if (qMin(logicalFirst, logicalLast) < 0
1985
|| qMax(logicalLast, logicalFirst) >= sectionCount())
1987
int oldCount = q->count();
1988
int changeCount = logicalLast - logicalFirst + 1;
1990
if (state == QHeaderViewPrivate::ResizeSection)
1991
preventCursorChangeInSetOffset = true;
1993
updateHiddenSections(logicalFirst, logicalLast);
1995
if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
1996
//Q_ASSERT(headerSectionCount() == sectionCount);
1997
removeSectionsFromSectionItems(logicalFirst, logicalLast);
1999
if (logicalFirst == logicalLast) { // Remove just one index.
2000
int l = logicalFirst;
2001
int visual = visualIndices.at(l);
2002
Q_ASSERT(sectionCount() == logicalIndices.count());
2003
for (int v = 0; v < sectionCount(); ++v) {
2005
int logical = logicalIndices.at(v);
2006
--(visualIndices[logical]);
2008
if (logicalIndex(v) > l) // no need to move the positions before l
2009
--(logicalIndices[v]);
2011
logicalIndices.remove(visual);
2012
visualIndices.remove(l);
2013
//Q_ASSERT(headerSectionCount() == sectionCount);
2014
removeSectionsFromSectionItems(visual, visual);
2016
sectionStartposRecalc = true; // We will need to recalc positions after removing items
2017
for (int u = 0; u < sectionItems.count(); ++u) // Store section info
2018
sectionItems.at(u).tmpLogIdx = logicalIndices.at(u);
2019
for (int v = sectionItems.count() - 1; v >= 0; --v) { // Remove the sections
2020
if (logicalFirst <= sectionItems.at(v).tmpLogIdx && sectionItems.at(v).tmpLogIdx <= logicalLast)
2021
removeSectionsFromSectionItems(v, v);
2023
visualIndices.resize(sectionItems.count());
2024
logicalIndices.resize(sectionItems.count());
2025
int* visual_data = visualIndices.data();
2026
int* logical_data = logicalIndices.data();
2027
for (int w = 0; w < sectionItems.count(); ++w) { // Restore visual and logical indexes
2028
int logindex = sectionItems.at(w).tmpLogIdx;
2029
if (logindex > logicalFirst)
2030
logindex -= changeCount;
2031
visual_data[logindex] = w;
2032
logical_data[w] = logindex;
2035
// ### handle sectionSelection (sectionHidden is handled by updateHiddenSections)
2038
// update sorting column
2039
if (sortIndicatorSection >= logicalFirst) {
2040
if (sortIndicatorSection <= logicalLast)
2041
sortIndicatorSection = -1;
2043
sortIndicatorSection -= changeCount;
2046
// if we only have the last section (the "end" position) left, the header is empty
2047
if (sectionCount() <= 0)
2049
invalidateCachedSizeHint();
2050
emit q->sectionCountChanged(oldCount, q->count());
2052
if (q->stretchLastSection()) {
2053
const bool lastSectionRemoved = lastSectionLogicalIdx >= logicalFirst && lastSectionLogicalIdx <= logicalLast;
2054
if (lastSectionRemoved)
2055
setNewLastSection(lastVisibleVisualIndex());
2057
lastSectionLogicalIdx = logicalIndex(lastVisibleVisualIndex()); // Just update the last log index.
2058
doDelayedResizeSections();
2064
void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
2066
//if there is no row/column we can't have mapping for columns
2067
//because no QModelIndex in the model would be valid
2068
// ### this is far from being bullet-proof and we would need a real system to
2069
// ### map columns or rows persistently
2070
if ((orientation == Qt::Horizontal && model->rowCount(root) == 0)
2071
|| model->columnCount(root) == 0)
2074
if (hiddenSectionSize.count() == 0)
2077
for (int i = 0; i < sectionItems.count(); ++i)
2078
if (isVisualIndexHidden(i)) // ### note that we are using column or row 0
2079
persistentHiddenSections.append(orientation == Qt::Horizontal
2080
? model->index(0, logicalIndex(i), root)
2081
: model->index(logicalIndex(i), 0, root));
2084
void QHeaderViewPrivate::_q_layoutChanged()
2088
if (persistentHiddenSections.isEmpty() || modelIsEmpty()) {
2089
if (modelSectionCount() != sectionCount())
2090
q->initializeSections();
2091
persistentHiddenSections.clear();
2095
QBitArray oldSectionHidden = sectionsHiddenToBitVector();
2096
oldSectionHidden.resize(sectionItems.size());
2097
bool sectionCountChanged = false;
2099
for (int i = 0; i < persistentHiddenSections.count(); ++i) {
2100
QModelIndex index = persistentHiddenSections.at(i);
2101
if (index.isValid()) {
2102
const int logical = (orientation == Qt::Horizontal
2105
q->setSectionHidden(logical, true);
2106
oldSectionHidden.setBit(logical, false);
2107
} else if (!sectionCountChanged && (modelSectionCount() != sectionCount())) {
2108
sectionCountChanged = true;
2112
persistentHiddenSections.clear();
2114
for (int i = 0; i < oldSectionHidden.count(); ++i) {
2115
if (oldSectionHidden.testBit(i))
2116
q->setSectionHidden(i, false);
2119
// the number of sections changed; we need to reread the state of the model
2120
if (sectionCountChanged)
2121
q->initializeSections();
2128
void QHeaderView::initializeSections()
2131
const int oldCount = d->sectionCount();
2132
const int newCount = d->modelSectionCount();
2133
if (newCount <= 0) {
2135
emit sectionCountChanged(oldCount, 0);
2136
} else if (newCount != oldCount) {
2137
const int min = qBound(0, oldCount, newCount - 1);
2138
initializeSections(min, newCount - 1);
2139
if (stretchLastSection()) // we've already gotten the size hint
2140
d->maybeRestorePrevLastSectionAndStretchLast();
2142
//make sure we update the hidden sections
2143
if (newCount < oldCount)
2144
d->updateHiddenSections(0, newCount-1);
2152
void QHeaderView::initializeSections(int start, int end)
2156
Q_ASSERT(start >= 0);
2159
d->invalidateCachedSizeHint();
2160
int oldCount = d->sectionCount();
2162
if (end + 1 < d->sectionCount()) {
2163
int newCount = end + 1;
2164
d->removeSectionsFromSectionItems(newCount, d->sectionCount() - 1);
2165
if (!d->hiddenSectionSize.isEmpty()) {
2166
if (oldCount - newCount > d->hiddenSectionSize.count()) {
2167
for (int i = end + 1; i < d->sectionCount(); ++i)
2168
d->hiddenSectionSize.remove(i);
2170
QHash<int, int>::iterator it = d->hiddenSectionSize.begin();
2171
while (it != d->hiddenSectionSize.end()) {
2173
it = d->hiddenSectionSize.erase(it);
2181
int newSectionCount = end + 1;
2183
if (!d->logicalIndices.isEmpty()) {
2184
if (oldCount <= newSectionCount) {
2185
d->logicalIndices.resize(newSectionCount);
2186
d->visualIndices.resize(newSectionCount);
2187
for (int i = oldCount; i < newSectionCount; ++i) {
2188
d->logicalIndices[i] = i;
2189
d->visualIndices[i] = i;
2193
for (int i = 0; i < oldCount; ++i) {
2194
int v = d->logicalIndices.at(i);
2195
if (v < newSectionCount) {
2196
d->logicalIndices[j] = v;
2197
d->visualIndices[v] = j;
2201
d->logicalIndices.resize(newSectionCount);
2202
d->visualIndices.resize(newSectionCount);
2206
if (d->globalResizeMode == Stretch)
2207
d->stretchSections = newSectionCount;
2208
else if (d->globalResizeMode == ResizeToContents)
2209
d->contentsSections = newSectionCount;
2211
if (newSectionCount > oldCount)
2212
d->createSectionItems(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
2213
//Q_ASSERT(d->headerLength() == d->length);
2215
if (d->sectionCount() != oldCount)
2216
emit sectionCountChanged(oldCount, d->sectionCount());
2217
d->viewport->update();
2224
void QHeaderView::currentChanged(const QModelIndex ¤t, const QModelIndex &old)
2228
if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
2229
if (old.isValid() && old.parent() == d->root)
2230
d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
2231
sectionSize(old.column()), d->viewport->height()));
2232
if (current.isValid() && current.parent() == d->root)
2233
d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
2234
sectionSize(current.column()), d->viewport->height()));
2235
} else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
2236
if (old.isValid() && old.parent() == d->root)
2237
d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
2238
d->viewport->width(), sectionSize(old.row())));
2239
if (current.isValid() && current.parent() == d->root)
2240
d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
2241
d->viewport->width(), sectionSize(current.row())));
2250
bool QHeaderView::event(QEvent *e)
2253
switch (e->type()) {
2254
case QEvent::HoverEnter: {
2255
QHoverEvent *he = static_cast<QHoverEvent*>(e);
2256
d->hover = logicalIndexAt(he->pos());
2258
updateSection(d->hover);
2261
case QEvent::HoverLeave: {
2263
updateSection(d->hover);
2266
case QEvent::HoverMove: {
2267
QHoverEvent *he = static_cast<QHoverEvent*>(e);
2268
int oldHover = d->hover;
2269
d->hover = logicalIndexAt(he->pos());
2270
if (d->hover != oldHover) {
2272
updateSection(oldHover);
2274
updateSection(d->hover);
2277
case QEvent::Timer: {
2278
QTimerEvent *te = static_cast<QTimerEvent*>(e);
2279
if (te->timerId() == d->delayedResize.timerId()) {
2280
d->delayedResize.stop();
2284
case QEvent::StyleChange:
2285
if (!d->customDefaultSectionSize)
2286
d->updateDefaultSectionSizeFromStyle();
2291
return QAbstractItemView::event(e);
2298
void QHeaderView::paintEvent(QPaintEvent *e)
2305
QPainter painter(d->viewport);
2306
const QPoint offset = d->scrollDelayOffset;
2307
QRect translatedEventRect = e->rect();
2308
translatedEventRect.translate(offset);
2312
if (d->orientation == Qt::Horizontal) {
2313
start = visualIndexAt(translatedEventRect.left());
2314
end = visualIndexAt(translatedEventRect.right());
2316
start = visualIndexAt(translatedEventRect.top());
2317
end = visualIndexAt(translatedEventRect.bottom());
2321
start = (start == -1 ? count() - 1 : start);
2322
end = (end == -1 ? 0 : end);
2324
start = (start == -1 ? 0 : start);
2325
end = (end == -1 ? count() - 1 : end);
2329
start = qMin(start, end);
2330
end = qMax(tmp, end);
2332
d->prepareSectionSelected(); // clear and resize the bit array
2334
QRect currentSectionRect;
2336
const int width = d->viewport->width();
2337
const int height = d->viewport->height();
2338
for (int i = start; i <= end; ++i) {
2339
if (d->isVisualIndexHidden(i))
2342
logical = logicalIndex(i);
2343
if (d->orientation == Qt::Horizontal) {
2344
currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
2346
currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
2348
currentSectionRect.translate(offset);
2350
QVariant variant = d->model->headerData(logical, d->orientation,
2352
if (variant.isValid() && variant.canConvert<QFont>()) {
2353
QFont sectionFont = qvariant_cast<QFont>(variant);
2354
painter.setFont(sectionFont);
2356
paintSection(&painter, currentSectionRect, logical);
2362
// Paint the area beyond where there are indexes
2364
opt.state |= QStyle::State_Horizontal;
2365
if (currentSectionRect.left() > translatedEventRect.left()) {
2366
opt.rect = QRect(translatedEventRect.left(), 0,
2367
currentSectionRect.left() - translatedEventRect.left(), height);
2368
style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2370
} else if (currentSectionRect.right() < translatedEventRect.right()) {
2371
// paint to the right
2372
opt.state |= QStyle::State_Horizontal;
2373
opt.rect = QRect(currentSectionRect.right() + 1, 0,
2374
translatedEventRect.right() - currentSectionRect.right(), height);
2375
style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2376
} else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
2377
// paint the bottom section
2378
opt.state &= ~QStyle::State_Horizontal;
2379
opt.rect = QRect(0, currentSectionRect.bottom() + 1,
2380
width, height - currentSectionRect.bottom() - 1);
2381
style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2385
// ### visualize sections
2386
for (int a = 0, i = 0; i < d->sectionItems.count(); ++i) {
2387
QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
2388
if (d->orientation == Qt::Horizontal)
2389
painter.fillRect(a - d->offset, 0, d->sectionItems.at(i).size, 4, color);
2391
painter.fillRect(0, a - d->offset, 4, d->sectionItems.at(i).size, color);
2392
a += d->sectionItems.at(i).size;
2402
void QHeaderView::mousePressEvent(QMouseEvent *e)
2405
if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
2407
int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2408
int handle = d->sectionHandleAt(pos);
2409
d->originalSize = -1; // clear the stored original size
2411
d->pressed = logicalIndexAt(pos);
2412
if (d->clickableSections)
2413
emit sectionPressed(d->pressed);
2415
bool acceptMoveSection = d->movableSections;
2416
if (acceptMoveSection && d->pressed == 0 && !d->allowUserMoveOfSection0)
2417
acceptMoveSection = false; // Do not allow moving the tree nod
2419
if (acceptMoveSection) {
2420
d->section = d->target = d->pressed;
2421
if (d->section == -1)
2423
d->state = QHeaderViewPrivate::MoveSection;
2424
d->setupSectionIndicator(d->section, pos);
2425
} else if (d->clickableSections && d->pressed != -1) {
2426
updateSection(d->pressed);
2427
d->state = QHeaderViewPrivate::SelectSections;
2429
} else if (sectionResizeMode(handle) == Interactive) {
2430
d->originalSize = sectionSize(handle);
2431
d->state = QHeaderViewPrivate::ResizeSection;
2432
d->section = handle;
2433
d->preventCursorChangeInSetOffset = false;
2439
d->clearCascadingSections();
2446
void QHeaderView::mouseMoveEvent(QMouseEvent *e)
2449
int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2450
if (pos < 0 && d->state != QHeaderViewPrivate::SelectSections)
2452
if (e->buttons() == Qt::NoButton) {
2453
#if !defined(Q_DEAD_CODE_FROM_QT4_MAC)
2454
// Under Cocoa, when the mouse button is released, may include an extra
2455
// simulated mouse moved event. The state of the buttons when this event
2456
// is generated is already "no button" and the code below gets executed
2457
// just before the mouseReleaseEvent and resets the state. This prevents
2458
// column dragging from working. So this code is disabled under Cocoa.
2459
d->state = QHeaderViewPrivate::NoState;
2464
case QHeaderViewPrivate::ResizeSection: {
2465
Q_ASSERT(d->originalSize != -1);
2466
if (d->cascadingResizing) {
2467
int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
2468
int visual = visualIndex(d->section);
2469
d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
2471
int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
2472
int newsize = qBound(minimumSectionSize(), d->originalSize + delta, maximumSectionSize());
2473
resizeSection(d->section, newsize);
2478
case QHeaderViewPrivate::MoveSection: {
2479
if (d->shouldAutoScroll(e->pos()))
2480
d->startAutoScroll();
2481
if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
2482
|| !d->sectionIndicator->isHidden()) {
2483
int visual = visualIndexAt(pos);
2486
if (visual == 0 && logicalIndex(0) == 0 && !d->allowUserMoveOfSection0)
2489
int posThreshold = d->headerSectionPosition(visual) - d->offset + d->headerSectionSize(visual) / 2;
2490
int moving = visualIndex(d->section);
2491
if (visual < moving) {
2492
if (pos < posThreshold)
2493
d->target = d->logicalIndex(visual);
2495
d->target = d->logicalIndex(visual + 1);
2496
} else if (visual > moving) {
2497
if (pos > posThreshold)
2498
d->target = d->logicalIndex(visual);
2500
d->target = d->logicalIndex(visual - 1);
2502
d->target = d->section;
2504
d->updateSectionIndicator(d->section, pos);
2508
case QHeaderViewPrivate::SelectSections: {
2509
int logical = logicalIndexAt(qMax(-d->offset, pos));
2510
if (logical == -1 && pos > 0)
2511
logical = logicalIndex(d->lastVisibleVisualIndex());
2512
if (logical == d->pressed)
2513
return; // nothing to do
2514
else if (d->pressed != -1)
2515
updateSection(d->pressed);
2516
d->pressed = logical;
2517
if (d->clickableSections && logical != -1) {
2518
emit sectionEntered(d->pressed);
2519
updateSection(d->pressed);
2523
case QHeaderViewPrivate::NoState: {
2524
#ifndef QT_NO_CURSOR
2525
int handle = d->sectionHandleAt(pos);
2526
bool hasCursor = testAttribute(Qt::WA_SetCursor);
2527
if (handle != -1 && (sectionResizeMode(handle) == Interactive)) {
2529
setCursor(d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
2530
} else if (hasCursor) {
2545
void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
2548
int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2550
case QHeaderViewPrivate::MoveSection:
2551
if (!d->sectionIndicator->isHidden()) { // moving
2552
int from = visualIndex(d->section);
2553
Q_ASSERT(from != -1);
2554
int to = visualIndex(d->target);
2556
moveSection(from, to);
2557
d->section = d->target = -1;
2558
d->updateSectionIndicator(d->section, pos);
2561
case QHeaderViewPrivate::SelectSections:
2562
if (!d->clickableSections) {
2563
int section = logicalIndexAt(pos);
2564
updateSection(section);
2567
case QHeaderViewPrivate::NoState:
2568
if (d->clickableSections) {
2569
int section = logicalIndexAt(pos);
2570
if (section != -1 && section == d->pressed) {
2571
d->flipSortIndicator(section);
2572
emit sectionClicked(section);
2574
if (d->pressed != -1)
2575
updateSection(d->pressed);
2578
case QHeaderViewPrivate::ResizeSection:
2579
d->originalSize = -1;
2580
d->clearCascadingSections();
2585
d->state = QHeaderViewPrivate::NoState;
2593
void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
2596
int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2597
int handle = d->sectionHandleAt(pos);
2598
if (handle > -1 && sectionResizeMode(handle) == Interactive) {
2599
emit sectionHandleDoubleClicked(handle);
2600
#ifndef QT_NO_CURSOR
2601
Qt::CursorShape splitCursor = (d->orientation == Qt::Horizontal)
2602
? Qt::SplitHCursor : Qt::SplitVCursor;
2603
if (cursor().shape() == splitCursor) {
2604
// signal handlers may have changed the section size
2605
handle = d->sectionHandleAt(pos);
2606
if (!(handle > -1 && sectionResizeMode(handle) == Interactive))
2607
setCursor(Qt::ArrowCursor);
2611
emit sectionDoubleClicked(logicalIndexAt(e->pos()));
2619
bool QHeaderView::viewportEvent(QEvent *e)
2622
switch (e->type()) {
2623
#ifndef QT_NO_TOOLTIP
2624
case QEvent::ToolTip: {
2625
QHelpEvent *he = static_cast<QHelpEvent*>(e);
2626
int logical = logicalIndexAt(he->pos());
2627
if (logical != -1) {
2628
QVariant variant = d->model->headerData(logical, d->orientation, Qt::ToolTipRole);
2629
if (variant.isValid()) {
2630
QToolTip::showText(he->globalPos(), variant.toString(), this);
2636
#ifndef QT_NO_WHATSTHIS
2637
case QEvent::QueryWhatsThis: {
2638
QHelpEvent *he = static_cast<QHelpEvent*>(e);
2639
int logical = logicalIndexAt(he->pos());
2641
&& d->model->headerData(logical, d->orientation, Qt::WhatsThisRole).isValid())
2644
case QEvent::WhatsThis: {
2645
QHelpEvent *he = static_cast<QHelpEvent*>(e);
2646
int logical = logicalIndexAt(he->pos());
2647
if (logical != -1) {
2648
QVariant whatsthis = d->model->headerData(logical, d->orientation,
2650
if (whatsthis.isValid()) {
2651
QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
2656
#endif // QT_NO_WHATSTHIS
2657
#ifndef QT_NO_STATUSTIP
2658
case QEvent::StatusTip: {
2659
QHelpEvent *he = static_cast<QHelpEvent*>(e);
2660
int logical = logicalIndexAt(he->pos());
2661
if (logical != -1) {
2662
QString statustip = d->model->headerData(logical, d->orientation,
2663
Qt::StatusTipRole).toString();
2664
if (!statustip.isEmpty())
2665
setStatusTip(statustip);
2668
#endif // QT_NO_STATUSTIP
2669
case QEvent::FontChange:
2670
case QEvent::StyleChange:
2671
d->invalidateCachedSizeHint();
2674
case QEvent::Show: {
2675
QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget());
2676
if (parent && parent->isVisible()) // Only resize if we have a visible parent
2678
emit geometriesChanged();
2680
case QEvent::ContextMenu: {
2681
d->state = QHeaderViewPrivate::NoState;
2682
d->pressed = d->section = d->target = -1;
2683
d->updateSectionIndicator(d->section, -1);
2685
case QEvent::Wheel: {
2686
QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea *>(parentWidget());
2688
return QApplication::sendEvent(asa->viewport(), e);
2693
return QAbstractItemView::viewportEvent(e);
2697
Paints the section specified by the given \a logicalIndex, using the given
2698
\a painter and \a rect.
2700
Normally, you do not have to call this function.
2703
void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
2705
Q_D(const QHeaderView);
2706
if (!rect.isValid())
2708
// get the state of the section
2709
QStyleOptionHeader opt;
2710
initStyleOption(&opt);
2711
QStyle::State state = QStyle::State_None;
2713
state |= QStyle::State_Enabled;
2714
if (window()->isActiveWindow())
2715
state |= QStyle::State_Active;
2716
if (d->clickableSections) {
2717
if (logicalIndex == d->hover)
2718
state |= QStyle::State_MouseOver;
2719
if (logicalIndex == d->pressed)
2720
state |= QStyle::State_Sunken;
2721
else if (d->highlightSelected) {
2722
if (d->sectionIntersectsSelection(logicalIndex))
2723
state |= QStyle::State_On;
2724
if (d->isSectionSelected(logicalIndex))
2725
state |= QStyle::State_Sunken;
2729
if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
2730
opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
2731
? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
2733
// setup the style options structure
2734
QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
2735
Qt::TextAlignmentRole);
2737
opt.section = logicalIndex;
2739
opt.textAlignment = Qt::Alignment(textAlignment.isValid()
2740
? Qt::Alignment(textAlignment.toInt())
2741
: d->defaultAlignment);
2743
opt.iconAlignment = Qt::AlignVCenter;
2744
opt.text = d->model->headerData(logicalIndex, d->orientation,
2745
Qt::DisplayRole).toString();
2747
int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
2749
const Qt::Alignment headerArrowAlignment = static_cast<Qt::Alignment>(style()->styleHint(QStyle::SH_Header_ArrowAlignment, 0, this));
2750
const bool isHeaderArrowOnTheSide = headerArrowAlignment & Qt::AlignVCenter;
2751
if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex && isHeaderArrowOnTheSide)
2752
margin += style()->pixelMetric(QStyle::PM_HeaderMarkSize, 0, this);
2754
if (d->textElideMode != Qt::ElideNone)
2755
opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin);
2757
QVariant variant = d->model->headerData(logicalIndex, d->orientation,
2758
Qt::DecorationRole);
2759
opt.icon = qvariant_cast<QIcon>(variant);
2760
if (opt.icon.isNull())
2761
opt.icon = qvariant_cast<QPixmap>(variant);
2762
QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
2763
Qt::ForegroundRole);
2764
if (foregroundBrush.canConvert<QBrush>())
2765
opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
2767
QPointF oldBO = painter->brushOrigin();
2768
QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
2769
Qt::BackgroundRole);
2770
if (backgroundBrush.canConvert<QBrush>()) {
2771
opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
2772
opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
2773
painter->setBrushOrigin(opt.rect.topLeft());
2776
// the section position
2777
int visual = visualIndex(logicalIndex);
2778
Q_ASSERT(visual != -1);
2779
bool first = d->isFirstVisibleSection(visual);
2780
bool last = d->isLastVisibleSection(visual);
2782
opt.position = QStyleOptionHeader::OnlyOneSection;
2784
opt.position = QStyleOptionHeader::Beginning;
2786
opt.position = QStyleOptionHeader::End;
2788
opt.position = QStyleOptionHeader::Middle;
2789
opt.orientation = d->orientation;
2790
// the selected position
2791
bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
2792
bool nextSelected = d->isSectionSelected(this->logicalIndex(visual + 1));
2793
if (previousSelected && nextSelected)
2794
opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
2795
else if (previousSelected)
2796
opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
2797
else if (nextSelected)
2798
opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
2800
opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
2802
style()->drawControl(QStyle::CE_Header, &opt, painter, this);
2804
painter->setBrushOrigin(oldBO);
2808
Returns the size of the contents of the section specified by the given
2811
\sa defaultSectionSize()
2814
QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
2816
Q_D(const QHeaderView);
2817
Q_ASSERT(logicalIndex >= 0);
2822
QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
2823
if (variant.isValid())
2824
return qvariant_cast<QSize>(variant);
2826
// otherwise use the contents
2827
QStyleOptionHeader opt;
2828
initStyleOption(&opt);
2829
opt.section = logicalIndex;
2830
QVariant var = d->model->headerData(logicalIndex, d->orientation,
2833
if (var.isValid() && var.canConvert<QFont>())
2834
fnt = qvariant_cast<QFont>(var);
2838
opt.fontMetrics = QFontMetrics(fnt);
2839
opt.text = d->model->headerData(logicalIndex, d->orientation,
2840
Qt::DisplayRole).toString();
2841
variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole);
2842
opt.icon = qvariant_cast<QIcon>(variant);
2843
if (opt.icon.isNull())
2844
opt.icon = qvariant_cast<QPixmap>(variant);
2845
if (isSortIndicatorShown())
2846
opt.sortIndicator = QStyleOptionHeader::SortDown;
2847
return style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
2851
Returns the horizontal offset of the header. This is 0 for vertical
2857
int QHeaderView::horizontalOffset() const
2859
Q_D(const QHeaderView);
2860
if (d->orientation == Qt::Horizontal)
2866
Returns the vertical offset of the header. This is 0 for horizontal
2872
int QHeaderView::verticalOffset() const
2874
Q_D(const QHeaderView);
2875
if (d->orientation == Qt::Vertical)
2885
void QHeaderView::updateGeometries()
2888
d->layoutChildren();
2889
if (d->hasAutoResizeSections())
2890
d->doDelayedResizeSections();
2898
void QHeaderView::scrollContentsBy(int dx, int dy)
2901
d->scrollDirtyRegion(dx, dy);
2908
void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &)
2911
d->invalidateCachedSizeHint();
2912
if (d->hasAutoResizeSections()) {
2913
bool resizeRequired = d->globalResizeMode == ResizeToContents;
2914
int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row();
2915
int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row();
2916
for (int i = first; i <= last && !resizeRequired; ++i)
2917
resizeRequired = (sectionResizeMode(i) == ResizeToContents);
2919
d->doDelayedResizeSections();
2927
Empty implementation because the header doesn't show QModelIndex items.
2929
void QHeaderView::rowsInserted(const QModelIndex &, int, int)
2938
Empty implementation because the header doesn't show QModelIndex items.
2941
QRect QHeaderView::visualRect(const QModelIndex &) const
2950
Empty implementation because the header doesn't show QModelIndex items.
2953
void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
2955
// do nothing - the header only displays sections
2962
Empty implementation because the header doesn't show QModelIndex items.
2965
QModelIndex QHeaderView::indexAt(const QPoint &) const
2967
return QModelIndex();
2974
Empty implementation because the header doesn't show QModelIndex items.
2977
bool QHeaderView::isIndexHidden(const QModelIndex &) const
2979
return true; // the header view has no items, just sections
2986
Empty implementation because the header doesn't show QModelIndex items.
2989
QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
2991
return QModelIndex();
2997
Selects the items in the given \a rect according to the specified
3000
The base class implementation does nothing.
3003
void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
3012
QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
3014
Q_D(const QHeaderView);
3015
const int max = d->modelSectionCount();
3017
if (d->orientation == Qt::Horizontal) {
3018
int logicalLeft = max;
3019
int logicalRight = 0;
3021
if (d->visualIndices.empty()) {
3022
// If no reordered sections, skip redundant visual-to-logical transformations
3023
for (const auto &r : selection) {
3024
if (r.parent().isValid() || !r.isValid())
3025
continue; // we only know about toplevel items and we don't want invalid ranges
3026
if (r.left() < logicalLeft)
3027
logicalLeft = r.left();
3028
if (r.right() > logicalRight)
3029
logicalRight = r.right();
3034
for (const auto &r : selection) {
3035
if (r.parent().isValid() || !r.isValid())
3036
continue; // we only know about toplevel items and we don't want invalid ranges
3037
for (int k = r.left(); k <= r.right(); ++k) {
3038
int visual = visualIndex(k);
3039
if (visual == -1) // in some cases users may change the selections
3040
continue; // before we have a chance to do the layout
3047
logicalLeft = logicalIndex(left);
3048
logicalRight = logicalIndex(right);
3051
if (logicalLeft < 0 || logicalLeft >= count() ||
3052
logicalRight < 0 || logicalRight >= count())
3055
int leftPos = sectionViewportPosition(logicalLeft);
3056
int rightPos = sectionViewportPosition(logicalRight);
3057
rightPos += sectionSize(logicalRight);
3058
return QRect(leftPos, 0, rightPos - leftPos, height());
3060
// orientation() == Qt::Vertical
3061
int logicalTop = max;
3062
int logicalBottom = 0;
3064
if (d->visualIndices.empty()) {
3065
// If no reordered sections, skip redundant visual-to-logical transformations
3066
for (const auto &r : selection) {
3067
if (r.parent().isValid() || !r.isValid())
3068
continue; // we only know about toplevel items and we don't want invalid ranges
3069
if (r.top() < logicalTop)
3070
logicalTop = r.top();
3071
if (r.bottom() > logicalBottom)
3072
logicalBottom = r.bottom();
3078
for (const auto &r : selection) {
3079
if (r.parent().isValid() || !r.isValid())
3080
continue; // we only know about toplevel items and we don't want invalid ranges
3081
for (int k = r.top(); k <= r.bottom(); ++k) {
3082
int visual = visualIndex(k);
3083
if (visual == -1) // in some cases users may change the selections
3084
continue; // before we have a chance to do the layout
3087
if (visual > bottom)
3092
logicalTop = logicalIndex(top);
3093
logicalBottom = logicalIndex(bottom);
3096
if (logicalTop < 0 || logicalTop >= count() ||
3097
logicalBottom < 0 || logicalBottom >= count())
3100
int topPos = sectionViewportPosition(logicalTop);
3101
int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
3103
return QRect(0, topPos, width(), bottomPos - topPos);
3107
// private implementation
3109
int QHeaderViewPrivate::sectionHandleAt(int position)
3112
int visual = q->visualIndexAt(position);
3115
int log = logicalIndex(visual);
3116
int pos = q->sectionViewportPosition(log);
3117
int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, q);
3119
bool atLeft = position < pos + grip;
3120
bool atRight = (position > pos + q->sectionSize(log) - grip);
3122
qSwap(atLeft, atRight);
3125
//grip at the beginning of the section
3126
while(visual > -1) {
3127
int logical = q->logicalIndex(--visual);
3128
if (!q->isSectionHidden(logical))
3131
} else if (atRight) {
3132
//grip at the end of the section
3138
void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
3141
if (!sectionIndicator) {
3142
sectionIndicator = new QLabel(viewport);
3146
int p = q->sectionViewportPosition(section);
3147
if (orientation == Qt::Horizontal) {
3148
w = q->sectionSize(section);
3149
h = viewport->height();
3151
w = viewport->width();
3152
h = q->sectionSize(section);
3154
sectionIndicator->resize(w, h);
3157
pm.fill(QColor(0, 0, 0, 45));
3158
QRect rect(0, 0, w, h);
3160
QPainter painter(&pm);
3161
painter.setOpacity(0.75);
3162
q->paintSection(&painter, rect, section);
3165
sectionIndicator->setPixmap(pm);
3166
sectionIndicatorOffset = position - qMax(p, 0);
3169
void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
3171
if (!sectionIndicator)
3174
if (section == -1 || target == -1) {
3175
sectionIndicator->hide();
3179
if (orientation == Qt::Horizontal)
3180
sectionIndicator->move(position - sectionIndicatorOffset, 0);
3182
sectionIndicator->move(0, position - sectionIndicatorOffset);
3184
sectionIndicator->show();
3188
Initialize \a option with the values from this QHeaderView. This method is
3189
useful for subclasses when they need a QStyleOptionHeader, but do not want
3190
to fill in all the information themselves.
3192
\sa QStyleOption::initFrom()
3194
void QHeaderView::initStyleOption(QStyleOptionHeader *option) const
3196
Q_D(const QHeaderView);
3197
option->initFrom(this);
3198
option->state = QStyle::State_None | QStyle::State_Raised;
3199
option->orientation = d->orientation;
3200
if (d->orientation == Qt::Horizontal)
3201
option->state |= QStyle::State_Horizontal;
3203
option->state |= QStyle::State_Enabled;
3204
option->section = 0;
3207
bool QHeaderViewPrivate::isSectionSelected(int section) const
3209
int i = section * 2;
3210
if (i < 0 || i >= sectionSelected.count())
3212
if (sectionSelected.testBit(i)) // if the value was cached
3213
return sectionSelected.testBit(i + 1);
3215
if (orientation == Qt::Horizontal)
3216
s = isColumnSelected(section);
3218
s = isRowSelected(section);
3219
sectionSelected.setBit(i + 1, s); // selection state
3220
sectionSelected.setBit(i, true); // cache state
3224
bool QHeaderViewPrivate::isFirstVisibleSection(int section) const
3226
if (sectionStartposRecalc)
3227
recalcSectionStartPos();
3228
const SectionItem &item = sectionItems.at(section);
3229
return item.size > 0 && item.calculated_startpos == 0;
3232
bool QHeaderViewPrivate::isLastVisibleSection(int section) const
3234
if (sectionStartposRecalc)
3235
recalcSectionStartPos();
3236
const SectionItem &item = sectionItems.at(section);
3237
return item.size > 0 && item.calculatedEndPos() == length;
3242
Returns the last visible (ie. not hidden) visual index
3244
int QHeaderViewPrivate::lastVisibleVisualIndex() const
3246
Q_Q(const QHeaderView);
3247
for (int visual = q->count()-1; visual >= 0; --visual) {
3248
if (!q->isSectionHidden(q->logicalIndex(visual)))
3252
//default value if no section is actually visible
3256
void QHeaderViewPrivate::restoreSizeOnPrevLastSection()
3259
if (lastSectionLogicalIdx < 0)
3261
int resizeLogIdx = lastSectionLogicalIdx;
3262
lastSectionLogicalIdx = -1; // We do not want resize to catch it as the last section.
3263
q->resizeSection(resizeLogIdx, lastSectionSize);
3266
void QHeaderViewPrivate::setNewLastSection(int visualIndexForLastSection)
3269
lastSectionSize = -1;
3270
lastSectionLogicalIdx = q->logicalIndex(visualIndexForLastSection);
3271
lastSectionSize = headerSectionSize(visualIndexForLastSection); // pick size directly since ...
3272
// q->sectionSize(lastSectionLogicalIdx) may do delayed resize and stretch it before we get the value.
3275
void QHeaderViewPrivate::maybeRestorePrevLastSectionAndStretchLast()
3277
Q_Q(const QHeaderView);
3278
if (!q->stretchLastSection())
3281
int nowLastVisualSection = lastVisibleVisualIndex();
3282
if (lastSectionLogicalIdx == q->logicalIndex(nowLastVisualSection))
3285
// restore old last section.
3286
restoreSizeOnPrevLastSection();
3287
setNewLastSection(nowLastVisualSection);
3288
doDelayedResizeSections(); // Do stretch of last section soon (but not now).
3294
Go through and resize all of the sections applying stretchLastSection,
3295
manual stretches, sizes, and useGlobalMode.
3297
The different resize modes are:
3298
Interactive - the user decides the size
3299
Stretch - take up whatever space is left
3300
Fixed - the size is set programmatically outside the header
3301
ResizeToContentes - the size is set based on the contents of the row or column in the parent view
3303
The resize mode will not affect the last section if stretchLastSection is true.
3305
void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
3308
//stop the timer in case it is delayed
3309
delayedResize.stop();
3311
executePostedLayout();
3312
if (sectionCount() == 0)
3315
if (resizeRecursionBlock)
3317
resizeRecursionBlock = true;
3319
invalidateCachedSizeHint();
3320
const int lastSectionVisualIdx = q->visualIndex(lastSectionLogicalIdx);
3322
// find stretchLastSection if we have it
3323
int stretchSection = -1;
3324
if (stretchLastSection && !useGlobalMode)
3325
stretchSection = lastSectionVisualIdx;
3327
// count up the number of stretched sections and how much space left for them
3328
int lengthToStretch = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
3329
int numberOfStretchedSections = 0;
3330
QList<int> section_sizes;
3331
for (int i = 0; i < sectionCount(); ++i) {
3332
if (isVisualIndexHidden(i))
3335
QHeaderView::ResizeMode resizeMode;
3336
if (useGlobalMode && (i != stretchSection))
3337
resizeMode = globalMode;
3339
resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i));
3341
if (resizeMode == QHeaderView::Stretch) {
3342
++numberOfStretchedSections;
3343
section_sizes.append(headerSectionSize(i));
3347
// because it isn't stretch, determine its width and remove that from lengthToStretch
3348
int sectionSize = 0;
3349
if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
3350
sectionSize = headerSectionSize(i);
3351
} else { // resizeMode == QHeaderView::ResizeToContents
3352
int logicalIndex = q->logicalIndex(i);
3353
sectionSize = qMax(viewSectionSizeHint(logicalIndex),
3354
q->sectionSizeHint(logicalIndex));
3355
if (sectionSize > q->maximumSectionSize())
3356
sectionSize = q->maximumSectionSize();
3358
section_sizes.append(sectionSize);
3359
lengthToStretch -= sectionSize;
3362
// calculate the new length for all of the stretched sections
3363
int stretchSectionLength = -1;
3364
int pixelReminder = 0;
3365
if (numberOfStretchedSections > 0 && lengthToStretch > 0) { // we have room to stretch in
3366
int hintLengthForEveryStretchedSection = lengthToStretch / numberOfStretchedSections;
3367
stretchSectionLength = qMax(hintLengthForEveryStretchedSection, q->minimumSectionSize());
3368
pixelReminder = lengthToStretch % numberOfStretchedSections;
3371
// ### The code below would be nicer if it was cleaned up a bit (since spans has been replaced with items)
3372
int spanStartSection = 0;
3373
int previousSectionLength = 0;
3375
QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
3377
// resize each section along the total length
3378
for (int i = 0; i < sectionCount(); ++i) {
3379
int oldSectionLength = headerSectionSize(i);
3380
int newSectionLength = -1;
3381
QHeaderView::ResizeMode newSectionResizeMode = headerSectionResizeMode(i);
3383
if (isVisualIndexHidden(i)) {
3384
newSectionLength = 0;
3386
QHeaderView::ResizeMode resizeMode;
3388
resizeMode = globalMode;
3390
resizeMode = (i == stretchSection
3391
? QHeaderView::Stretch
3392
: newSectionResizeMode);
3393
if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) {
3394
if (i == lastSectionVisualIdx)
3395
newSectionLength = qMax(stretchSectionLength, lastSectionSize);
3397
newSectionLength = stretchSectionLength;
3398
if (pixelReminder > 0) {
3399
newSectionLength += 1;
3402
section_sizes.removeFirst();
3404
newSectionLength = section_sizes.takeFirst();
3408
//Q_ASSERT(newSectionLength > 0);
3409
if ((previousSectionResizeMode != newSectionResizeMode
3410
|| previousSectionLength != newSectionLength) && i > 0) {
3411
int spanLength = (i - spanStartSection) * previousSectionLength;
3412
createSectionItems(spanStartSection, i - 1, spanLength, previousSectionResizeMode);
3413
//Q_ASSERT(headerLength() == length);
3414
spanStartSection = i;
3417
if (newSectionLength != oldSectionLength)
3418
emit q->sectionResized(logicalIndex(i), oldSectionLength, newSectionLength);
3420
previousSectionLength = newSectionLength;
3421
previousSectionResizeMode = newSectionResizeMode;
3424
createSectionItems(spanStartSection, sectionCount() - 1,
3425
(sectionCount() - spanStartSection) * previousSectionLength,
3426
previousSectionResizeMode);
3427
//Q_ASSERT(headerLength() == length);
3428
resizeRecursionBlock = false;
3432
void QHeaderViewPrivate::createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode)
3434
int sizePerSection = size / (end - start + 1);
3435
if (end >= sectionItems.count()) {
3436
sectionItems.resize(end + 1);
3437
sectionStartposRecalc = true;
3439
SectionItem *sectiondata = sectionItems.data();
3440
for (int i = start; i <= end; ++i) {
3441
length += (sizePerSection - sectiondata[i].size);
3442
sectionStartposRecalc |= (sectiondata[i].size != sizePerSection);
3443
sectiondata[i].size = sizePerSection;
3444
sectiondata[i].resizeMode = mode;
3448
void QHeaderViewPrivate::removeSectionsFromSectionItems(int start, int end)
3451
sectionStartposRecalc |= (end != sectionItems.count() - 1);
3452
int removedlength = 0;
3453
for (int u = start; u <= end; ++u)
3454
removedlength += sectionItems.at(u).size;
3455
length -= removedlength;
3456
sectionItems.remove(start, end - start + 1);
3459
void QHeaderViewPrivate::clear()
3461
if (state != NoClear) {
3463
visualIndices.clear();
3464
logicalIndices.clear();
3465
sectionSelected.clear();
3466
hiddenSectionSize.clear();
3467
sectionItems.clear();
3468
lastSectionLogicalIdx = -1;
3469
invalidateCachedSizeHint();
3473
void QHeaderViewPrivate::flipSortIndicator(int section)
3476
Qt::SortOrder sortOrder;
3477
if (sortIndicatorSection == section) {
3478
sortOrder = (sortIndicatorOrder == Qt::DescendingOrder) ? Qt::AscendingOrder : Qt::DescendingOrder;
3480
const QVariant value = model->headerData(section, orientation, Qt::InitialSortOrderRole);
3481
if (value.canConvert(QVariant::Int))
3482
sortOrder = static_cast<Qt::SortOrder>(value.toInt());
3484
sortOrder = Qt::AscendingOrder;
3486
q->setSortIndicator(section, sortOrder);
3489
void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
3492
const int minimumSize = q->minimumSectionSize();
3493
const int oldSize = headerSectionSize(visual);
3494
int delta = newSize - oldSize;
3496
if (delta > 0) { // larger
3497
bool sectionResized = false;
3499
// restore old section sizes
3500
for (int i = firstCascadingSection; i < visual; ++i) {
3501
if (cascadingSectionSize.contains(i)) {
3502
int currentSectionSize = headerSectionSize(i);
3503
int originalSectionSize = cascadingSectionSize.value(i);
3504
if (currentSectionSize < originalSectionSize) {
3505
int newSectionSize = currentSectionSize + delta;
3506
resizeSectionItem(i, currentSectionSize, newSectionSize);
3507
if (newSectionSize >= originalSectionSize && false)
3508
cascadingSectionSize.remove(i); // the section is now restored
3509
sectionResized = true;
3516
// resize the section
3517
if (!sectionResized) {
3518
newSize = qMax(newSize, minimumSize);
3519
if (oldSize != newSize)
3520
resizeSectionItem(visual, oldSize, newSize);
3523
// cascade the section size change
3524
for (int i = visual + 1; i < sectionCount(); ++i) {
3525
if (!sectionIsCascadable(i))
3527
int currentSectionSize = headerSectionSize(i);
3528
if (currentSectionSize <= minimumSize)
3530
int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
3531
//qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
3532
resizeSectionItem(i, currentSectionSize, newSectionSize);
3533
saveCascadingSectionSize(i, currentSectionSize);
3534
delta = delta - (currentSectionSize - newSectionSize);
3535
//qDebug() << "new delta" << delta;
3536
//if (newSectionSize != minimumSize)
3541
bool sectionResized = false;
3543
// restore old section sizes
3544
for (int i = lastCascadingSection; i > visual; --i) {
3545
if (!cascadingSectionSize.contains(i))
3547
int currentSectionSize = headerSectionSize(i);
3548
int originalSectionSize = cascadingSectionSize.value(i);
3549
if (currentSectionSize >= originalSectionSize)
3551
int newSectionSize = currentSectionSize - delta;
3552
resizeSectionItem(i, currentSectionSize, newSectionSize);
3553
if (newSectionSize >= originalSectionSize && false) {
3554
//qDebug() << "section" << i << "restored to" << originalSectionSize;
3555
cascadingSectionSize.remove(i); // the section is now restored
3557
sectionResized = true;
3561
// resize the section
3562
resizeSectionItem(visual, oldSize, qMax(newSize, minimumSize));
3564
// cascade the section size change
3565
if (delta < 0 && newSize < minimumSize) {
3566
for (int i = visual - 1; i >= 0; --i) {
3567
if (!sectionIsCascadable(i))
3569
int sectionSize = headerSectionSize(i);
3570
if (sectionSize <= minimumSize)
3572
resizeSectionItem(i, sectionSize, qMax(sectionSize + delta, minimumSize));
3573
saveCascadingSectionSize(i, sectionSize);
3578
// let the next section get the space from the resized section
3579
if (!sectionResized) {
3580
for (int i = visual + 1; i < sectionCount(); ++i) {
3581
if (!sectionIsCascadable(i))
3583
int currentSectionSize = headerSectionSize(i);
3584
int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
3585
resizeSectionItem(i, currentSectionSize, newSectionSize);
3591
if (hasAutoResizeSections())
3592
doDelayedResizeSections();
3597
void QHeaderViewPrivate::setDefaultSectionSize(int size)
3600
executePostedLayout();
3601
invalidateCachedSizeHint();
3602
defaultSectionSize = size;
3603
customDefaultSectionSize = true;
3604
if (state == QHeaderViewPrivate::ResizeSection)
3605
preventCursorChangeInSetOffset = true;
3606
for (int i = 0; i < sectionItems.count(); ++i) {
3607
QHeaderViewPrivate::SectionItem §ion = sectionItems[i];
3608
if (hiddenSectionSize.isEmpty() || !isVisualIndexHidden(i)) { // resize on not hidden.
3609
const int newSize = size;
3610
if (newSize != section.size) {
3611
length += newSize - section.size; //the whole length is changed
3612
const int oldSectionSize = section.sectionSize();
3613
section.size = size;
3614
emit q->sectionResized(logicalIndex(i), oldSectionSize, size);
3618
sectionStartposRecalc = true;
3619
if (hasAutoResizeSections())
3620
doDelayedResizeSections();
3624
void QHeaderViewPrivate::updateDefaultSectionSizeFromStyle()
3627
if (orientation == Qt::Horizontal) {
3628
defaultSectionSize = q->style()->pixelMetric(QStyle::PM_HeaderDefaultSectionSizeHorizontal, 0, q);
3630
defaultSectionSize = qMax(q->minimumSectionSize(),
3631
q->style()->pixelMetric(QStyle::PM_HeaderDefaultSectionSizeVertical, 0, q));
3635
void QHeaderViewPrivate::recalcSectionStartPos() const // linear (but fast)
3638
for (QVector<SectionItem>::const_iterator i = sectionItems.constBegin(); i != sectionItems.constEnd(); ++i) {
3639
i->calculated_startpos = pixelpos; // write into const mutable
3640
pixelpos += i->size;
3642
sectionStartposRecalc = false;
3645
void QHeaderViewPrivate::resizeSectionItem(int visualIndex, int oldSize, int newSize)
3648
QHeaderView::ResizeMode mode = headerSectionResizeMode(visualIndex);
3649
createSectionItems(visualIndex, visualIndex, newSize, mode);
3650
emit q->sectionResized(logicalIndex(visualIndex), oldSize, newSize);
3653
int QHeaderViewPrivate::headerSectionSize(int visual) const
3655
if (visual < sectionCount() && visual >= 0)
3656
return sectionItems.at(visual).sectionSize();
3660
int QHeaderViewPrivate::headerSectionPosition(int visual) const
3662
if (visual < sectionCount() && visual >= 0) {
3663
if (sectionStartposRecalc)
3664
recalcSectionStartPos();
3665
return sectionItems.at(visual).calculated_startpos;
3670
int QHeaderViewPrivate::headerVisualIndexAt(int position) const
3672
if (sectionStartposRecalc)
3673
recalcSectionStartPos();
3675
int endidx = sectionItems.count() - 1;
3676
while (startidx <= endidx) {
3677
int middle = (endidx + startidx) / 2;
3678
if (sectionItems.at(middle).calculated_startpos > position) {
3679
endidx = middle - 1;
3681
if (sectionItems.at(middle).calculatedEndPos() <= position)
3682
startidx = middle + 1;
3683
else // we found it.
3690
void QHeaderViewPrivate::setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode)
3692
int size = headerSectionSize(visual);
3693
createSectionItems(visual, visual, size, mode);
3696
QHeaderView::ResizeMode QHeaderViewPrivate::headerSectionResizeMode(int visual) const
3698
if (visual < 0 || visual >= sectionItems.count())
3699
return globalResizeMode;
3700
return static_cast<QHeaderView::ResizeMode>(sectionItems.at(visual).resizeMode);
3703
void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode)
3705
globalResizeMode = mode;
3706
for (int i = 0; i < sectionItems.count(); ++i)
3707
sectionItems[i].resizeMode = mode;
3710
int QHeaderViewPrivate::viewSectionSizeHint(int logical) const
3712
if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent)) {
3713
return (orientation == Qt::Horizontal
3714
? view->sizeHintForColumn(logical)
3715
: view->sizeHintForRow(logical));
3720
int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const
3722
if (!hiddenSectionSize.isEmpty()) {
3723
int adjustedVisualIndex = visualIndex;
3724
int currentVisualIndex = 0;
3725
for (int i = 0; i < sectionItems.count(); ++i) {
3726
if (isVisualIndexHidden(i))
3727
++adjustedVisualIndex;
3729
++currentVisualIndex;
3730
if (currentVisualIndex >= visualIndex)
3733
visualIndex = adjustedVisualIndex;
3738
void QHeaderViewPrivate::setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode)
3741
if (scrollMode == QAbstractItemView::ScrollPerItem) {
3742
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
3743
q->setOffsetToLastSection();
3745
q->setOffsetToSectionPosition(scrollBar->value());
3747
q->setOffset(scrollBar->value());
3751
#ifndef QT_NO_DATASTREAM
3752
void QHeaderViewPrivate::write(QDataStream &out) const
3754
out << int(orientation);
3755
out << int(sortIndicatorOrder);
3756
out << sortIndicatorSection;
3757
out << sortIndicatorShown;
3759
out << visualIndices;
3760
out << logicalIndices;
3762
out << sectionsHiddenToBitVector();
3763
out << hiddenSectionSize;
3766
out << sectionCount();
3767
out << movableSections;
3768
out << clickableSections;
3769
out << highlightSelected;
3770
out << stretchLastSection;
3771
out << cascadingResizing;
3772
out << stretchSections;
3773
out << contentsSections;
3774
out << defaultSectionSize;
3775
out << minimumSectionSize;
3777
out << int(defaultAlignment);
3778
out << int(globalResizeMode);
3780
out << sectionItems;
3781
out << resizeContentsPrecision;
3782
out << customDefaultSectionSize;
3783
out << lastSectionSize;
3786
bool QHeaderViewPrivate::read(QDataStream &in)
3789
int orient, order, align, global;
3790
int sortIndicatorSectionIn;
3791
bool sortIndicatorShownIn;
3793
QVector<int> visualIndicesIn;
3794
QVector<int> logicalIndicesIn;
3795
QHash<int, int> hiddenSectionSizeIn;
3796
bool movableSectionsIn;
3797
bool clickableSectionsIn;
3798
bool highlightSelectedIn;
3799
bool stretchLastSectionIn;
3800
bool cascadingResizingIn;
3801
int stretchSectionsIn;
3802
int contentsSectionsIn;
3803
int defaultSectionSizeIn;
3804
int minimumSectionSizeIn;
3805
QVector<SectionItem> sectionItemsIn;
3810
in >> sortIndicatorSectionIn;
3811
in >> sortIndicatorShownIn;
3813
in >> visualIndicesIn;
3814
in >> logicalIndicesIn;
3816
QBitArray sectionHidden;
3817
in >> sectionHidden;
3818
in >> hiddenSectionSizeIn;
3821
int unusedSectionCount; // For compatibility
3822
in >> unusedSectionCount;
3824
if (in.status() != QDataStream::Ok || lengthIn < 0)
3827
in >> movableSectionsIn;
3828
in >> clickableSectionsIn;
3829
in >> highlightSelectedIn;
3830
in >> stretchLastSectionIn;
3831
in >> cascadingResizingIn;
3832
in >> stretchSectionsIn;
3833
in >> contentsSectionsIn;
3834
in >> defaultSectionSizeIn;
3835
in >> minimumSectionSizeIn;
3841
in >> sectionItemsIn;
3842
// In Qt4 we had a vector of spans where one span could hold information on more sections.
3843
// Now we have an itemvector where one items contains information about one section
3844
// For backward compatibility with Qt4 we do the following
3845
QVector<SectionItem> newSectionItems;
3846
for (int u = 0; u < sectionItemsIn.count(); ++u) {
3847
int count = sectionItemsIn.at(u).tmpDataStreamSectionCount;
3849
sectionItemsIn[u].size /= count;
3850
for (int n = 0; n < count; ++n)
3851
newSectionItems.append(sectionItemsIn[u]);
3854
int sectionItemsLengthTotal = 0;
3855
foreach (const SectionItem §ion, newSectionItems)
3856
sectionItemsLengthTotal += section.size;
3857
if (sectionItemsLengthTotal != lengthIn)
3860
orientation = static_cast<Qt::Orientation>(orient);
3861
sortIndicatorOrder = static_cast<Qt::SortOrder>(order);
3862
sortIndicatorSection = sortIndicatorSectionIn;
3863
sortIndicatorShown = sortIndicatorShownIn;
3864
visualIndices = visualIndicesIn;
3865
logicalIndices = logicalIndicesIn;
3866
hiddenSectionSize = hiddenSectionSizeIn;
3869
movableSections = movableSectionsIn;
3870
clickableSections = clickableSectionsIn;
3871
highlightSelected = highlightSelectedIn;
3872
stretchLastSection = stretchLastSectionIn;
3873
cascadingResizing = cascadingResizingIn;
3874
stretchSections = stretchSectionsIn;
3875
contentsSections = contentsSectionsIn;
3876
defaultSectionSize = defaultSectionSizeIn;
3877
minimumSectionSize = minimumSectionSizeIn;
3879
defaultAlignment = Qt::Alignment(align);
3880
globalResizeMode = static_cast<QHeaderView::ResizeMode>(global);
3882
sectionItems = newSectionItems;
3883
setHiddenSectionsFromBitVector(sectionHidden);
3884
recalcSectionStartPos();
3888
if (in.status() == QDataStream::Ok) // we haven't read past end
3889
resizeContentsPrecision = tmpint;
3893
if (in.status() == QDataStream::Ok) { // we haven't read past end
3894
customDefaultSectionSize = tmpbool;
3895
if (!customDefaultSectionSize)
3896
updateDefaultSectionSizeFromStyle();
3899
lastSectionSize = -1;
3900
int inLastSectionSize;
3901
in >> inLastSectionSize;
3902
if (in.status() == QDataStream::Ok)
3903
lastSectionSize = inLastSectionSize;
3905
lastSectionLogicalIdx = -1;
3906
if (stretchLastSection) {
3907
lastSectionLogicalIdx = q->logicalIndex(lastVisibleVisualIndex());
3908
doDelayedResizeSections();
3914
#endif // QT_NO_DATASTREAM
3918
#endif // QT_NO_ITEMVIEWS
3920
#include "moc_qheaderview.cpp"