QHeaderView 5.0 - no emit of sortIndicatorChanged when unchanged
[qt:qtbase.git] / src / widgets / itemviews / qheaderview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qheaderview.h"
43
44 #ifndef QT_NO_ITEMVIEWS
45 #include <qbitarray.h>
46 #include <qbrush.h>
47 #include <qdebug.h>
48 #include <qevent.h>
49 #include <qpainter.h>
50 #include <qscrollbar.h>
51 #include <qtooltip.h>
52 #include <qwhatsthis.h>
53 #include <qstyle.h>
54 #include <qstyleoption.h>
55 #include <qvector.h>
56 #include <qapplication.h>
57 #include <qvarlengtharray.h>
58 #include <qabstractitemdelegate.h>
59 #include <qvariant.h>
60 #include <private/qheaderview_p.h>
61 #include <private/qabstractitemmodel_p.h>
62
63 #ifndef QT_NO_DATASTREAM
64 #include <qdatastream.h>
65 #endif
66
67 QT_BEGIN_NAMESPACE
68
69 #ifndef QT_NO_DATASTREAM
70 QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionItem &section)
71 {
72     section.write(out);
73     return out;
74 }
75
76 QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionItem &section)
77 {
78     section.read(in);
79     return in;
80 }
81 #endif // QT_NO_DATASTREAM
82
83
84 /*!
85     \class QHeaderView
86
87     \brief The QHeaderView class provides a header row or header column for
88     item views.
89
90     \ingroup model-view
91     \inmodule QtWidgets
92
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.
97
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}.
100
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().
104
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.
108
109     Sections can be moved and resized using moveSection() and resizeSection();
110     they can also be hidden and shown with hideSection() and showSection().
111
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.
117
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.
120
121     \section1 Moving Header Sections
122
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()
126
127     \note Double-clicking on a header to resize a section only applies for
128     visible rows.
129
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().
134
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.
139
140     \section1 Appearance
141
142     QTableWidget and QTableView create default headers. If you want
143     the headers to be visible, you can use \l{QFrame::}{setVisible()}.
144
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}.
152
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.
156
157     \sa {Model/View Programming}, QListView, QTableView, QTreeView
158 */
159
160 /*!
161     \enum QHeaderView::ResizeMode
162
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().
166
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.)
171
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.
175
176     \value Stretch QHeaderView will automatically resize the section to fill
177            the available space. The size cannot be changed by the user or
178            programmatically.
179
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)
184
185     The following values are obsolete:
186     \value Custom Use Fixed instead.
187
188     \sa setResizeMode(), setSectionResizeMode(), stretchLastSection, minimumSectionSize
189 */
190
191 /*!
192     \fn void QHeaderView::sectionMoved(int logicalIndex, int oldVisualIndex,
193     int newVisualIndex)
194
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.
198
199     \sa moveSection()
200 */
201
202 /*!
203     \fn void QHeaderView::sectionResized(int logicalIndex, int oldSize,
204     int newSize)
205
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.
209
210     \sa resizeSection()
211 */
212
213 /*!
214     \fn void QHeaderView::sectionPressed(int logicalIndex)
215
216     This signal is emitted when a section is pressed. The section's logical
217     index is specified by \a logicalIndex.
218
219     \sa setSectionsClickable()
220 */
221
222 /*!
223     \fn void QHeaderView::sectionClicked(int logicalIndex)
224
225     This signal is emitted when a section is clicked. The section's logical
226     index is specified by \a logicalIndex.
227
228     Note that the sectionPressed signal will also be emitted.
229
230     \sa setSectionsClickable(), sectionPressed()
231 */
232
233 /*!
234     \fn void QHeaderView::sectionEntered(int logicalIndex)
235     \since 4.3
236
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
239     \a logicalIndex.
240
241     \sa setSectionsClickable(), sectionPressed()
242 */
243
244 /*!
245     \fn void QHeaderView::sectionDoubleClicked(int logicalIndex)
246
247     This signal is emitted when a section is double-clicked. The section's
248     logical index is specified by \a logicalIndex.
249
250     \sa setSectionsClickable()
251 */
252
253 /*!
254     \fn void QHeaderView::sectionCountChanged(int oldCount, int newCount)
255
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.
259
260     \sa count(), length(), headerDataChanged()
261 */
262
263 /*!
264     \fn void QHeaderView::sectionHandleDoubleClicked(int logicalIndex)
265
266     This signal is emitted when a section is double-clicked. The section's
267     logical index is specified by \a logicalIndex.
268
269     \sa setSectionsClickable()
270 */
271
272 /*!
273     \fn void QHeaderView::sortIndicatorChanged(int logicalIndex,
274     Qt::SortOrder order)
275     \since 4.3
276
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.
280
281     \sa setSortIndicator()
282 */
283
284 /*!
285     \fn void QHeaderView::geometriesChanged()
286     \since 4.2
287
288     This signal is emitted when the header's geometries have changed.
289 */
290
291 /*!
292     \property QHeaderView::highlightSections
293     \brief whether the sections containing selected items are highlighted
294
295     By default, this property is false.
296 */
297
298 /*!
299     Creates a new generic header with the given \a orientation and \a parent.
300 */
301 QHeaderView::QHeaderView(Qt::Orientation orientation, QWidget *parent)
302     : QAbstractItemView(*new QHeaderViewPrivate, parent)
303 {
304     Q_D(QHeaderView);
305     d->setDefaultValues(orientation);
306     initialize();
307 }
308
309 /*!
310   \internal
311 */
312 QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
313                          Qt::Orientation orientation, QWidget *parent)
314     : QAbstractItemView(dd, parent)
315 {
316     Q_D(QHeaderView);
317     d->setDefaultValues(orientation);
318     initialize();
319 }
320
321 /*!
322   Destroys the header.
323 */
324
325 QHeaderView::~QHeaderView()
326 {
327 }
328
329 /*!
330   \internal
331 */
332 void QHeaderView::initialize()
333 {
334     Q_D(QHeaderView);
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;
343 }
344
345 /*!
346   \reimp
347 */
348 void QHeaderView::setModel(QAbstractItemModel *model)
349 {
350     if (model == this->model())
351         return;
352     Q_D(QHeaderView);
353     if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
354     if (d->orientation == Qt::Horizontal) {
355         QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
356                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
357         QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
358                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
359         QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
360                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
361         QObject::disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
362                             this, SLOT(_q_layoutAboutToBeChanged()));
363     } else {
364         QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
365                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
366         QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
367                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
368         QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
369                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
370         QObject::disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
371                             this, SLOT(_q_layoutAboutToBeChanged()));
372     }
373     QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
374                         this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
375     QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
376                         this, SLOT(_q_layoutAboutToBeChanged()));
377     }
378
379     if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
380         if (d->orientation == Qt::Horizontal) {
381             QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
382                              this, SLOT(sectionsInserted(QModelIndex,int,int)));
383             QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
384                              this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
385             QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
386                              this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
387             QObject::connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
388                              this, SLOT(_q_layoutAboutToBeChanged()));
389         } else {
390             QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
391                              this, SLOT(sectionsInserted(QModelIndex,int,int)));
392             QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
393                              this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
394             QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
395                              this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
396             QObject::connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
397                              this, SLOT(_q_layoutAboutToBeChanged()));
398         }
399         QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
400                          this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
401         QObject::connect(model, SIGNAL(layoutAboutToBeChanged()),
402                          this, SLOT(_q_layoutAboutToBeChanged()));
403     }
404
405     d->state = QHeaderViewPrivate::NoClear;
406     QAbstractItemView::setModel(model);
407     d->state = QHeaderViewPrivate::NoState;
408
409     // Users want to set sizes and modes before the widget is shown.
410     // Thus, we have to initialize when the model is set,
411     // and not lazily like we do in the other views.
412     initializeSections();
413 }
414
415 /*!
416     Returns the orientation of the header.
417
418     \sa Qt::Orientation
419 */
420
421 Qt::Orientation QHeaderView::orientation() const
422 {
423     Q_D(const QHeaderView);
424     return d->orientation;
425 }
426
427 /*!
428     Returns the offset of the header: this is the header's left-most (or
429     top-most for vertical headers) visible pixel.
430
431     \sa setOffset()
432 */
433
434 int QHeaderView::offset() const
435 {
436     Q_D(const QHeaderView);
437     return d->offset;
438 }
439
440 /*!
441     \fn void QHeaderView::setOffset(int offset)
442
443     Sets the header's offset to \a offset.
444
445     \sa offset(), length()
446 */
447
448 void QHeaderView::setOffset(int newOffset)
449 {
450     Q_D(QHeaderView);
451     if (d->offset == (int)newOffset)
452         return;
453     int ndelta = d->offset - newOffset;
454     d->offset = newOffset;
455     if (d->orientation == Qt::Horizontal)
456         d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
457     else
458         d->viewport->scroll(0, ndelta);
459     if (d->state == QHeaderViewPrivate::ResizeSection && !d->preventCursorChangeInSetOffset) {
460         QPoint cursorPos = QCursor::pos();
461         if (d->orientation == Qt::Horizontal)
462             QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
463         else
464             QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
465         d->firstPos += ndelta;
466         d->lastPos += ndelta;
467     }
468 }
469
470 /*!
471     \since 4.2
472     Sets the offset to the start of the section at the given \a visualSectionNumber.
473     \a visualSectionNumber is the actual visible section when hiddenSections are
474     not considered. That is not always the same as visualIndex().
475
476     \sa setOffset(), sectionPosition()
477 */
478 void QHeaderView::setOffsetToSectionPosition(int visualSectionNumber)
479 {
480     Q_D(QHeaderView);
481     if (visualSectionNumber > -1 && visualSectionNumber < d->sectionCount()) {
482         int position = d->headerSectionPosition(d->adjustedVisualIndex(visualSectionNumber));
483         setOffset(position);
484     }
485 }
486
487 /*!
488     \since 4.2
489     Sets the offset to make the last section visible.
490
491     \sa setOffset(), sectionPosition(), setOffsetToSectionPosition()
492 */
493 void QHeaderView::setOffsetToLastSection()
494 {
495     Q_D(const QHeaderView);
496     int size = (d->orientation == Qt::Horizontal ? viewport()->width() : viewport()->height());
497     int position = length() - size;
498     setOffset(position);
499 }
500
501 /*!
502     Returns the length along the orientation of the header.
503
504     \sa sizeHint(), setSectionResizeMode(), offset()
505 */
506
507 int QHeaderView::length() const
508 {
509     Q_D(const QHeaderView);
510     d->executePostedLayout();
511     d->executePostedResize();
512     //Q_ASSERT(d->headerLength() == d->length);
513     return d->length;
514 }
515
516 /*!
517     Returns a suitable size hint for this header.
518
519     \sa sectionSizeHint()
520 */
521
522 QSize QHeaderView::sizeHint() const
523 {
524     Q_D(const QHeaderView);
525     if (d->cachedSizeHint.isValid())
526         return d->cachedSizeHint;
527     d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint
528     const int sectionCount = count();
529
530     // get size hint for the first n sections
531     int i = 0;
532     for (int checked = 0; checked < 100 && i < sectionCount; ++i) {
533         if (isSectionHidden(i))
534             continue;
535         checked++;
536         QSize hint = sectionSizeFromContents(i);
537         d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
538     }
539     // get size hint for the last n sections
540     i = qMax(i, sectionCount - 100 );
541     for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) {
542         if (isSectionHidden(j))
543             continue;
544         checked++;
545         QSize hint = sectionSizeFromContents(j);
546         d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
547     }
548     return d->cachedSizeHint;
549 }
550
551 /*!
552     Returns a suitable size hint for the section specified by \a logicalIndex.
553
554     \sa sizeHint(), defaultSectionSize(), minimumSectionSize(),
555     Qt::SizeHintRole
556 */
557
558 int QHeaderView::sectionSizeHint(int logicalIndex) const
559 {
560     Q_D(const QHeaderView);
561     if (isSectionHidden(logicalIndex))
562         return 0;
563     if (logicalIndex < 0 || logicalIndex >= count())
564         return -1;
565     QSize size;
566     QVariant value = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
567     if (value.isValid())
568         size = qvariant_cast<QSize>(value);
569     else
570         size = sectionSizeFromContents(logicalIndex);
571     int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
572     return qMax(minimumSectionSize(), hint);
573 }
574
575 /*!
576     Returns the visual index of the section that covers the given \a position
577     in the viewport.
578
579     \sa logicalIndexAt()
580 */
581
582 int QHeaderView::visualIndexAt(int position) const
583 {
584     Q_D(const QHeaderView);
585     int vposition = position;
586     d->executePostedLayout();
587     d->executePostedResize();
588     const int count = d->sectionCount();
589     if (count < 1)
590         return -1;
591
592     if (d->reverse())
593         vposition = d->viewport->width() - vposition;
594     vposition += d->offset;
595
596     if (vposition > d->length)
597         return -1;
598     int visual = d->headerVisualIndexAt(vposition);
599     if (visual < 0)
600         return -1;
601
602     while (d->isVisualIndexHidden(visual)){
603         ++visual;
604         if (visual >= count)
605             return -1;
606     }
607     return visual;
608 }
609
610 /*!
611     Returns the section that covers the given \a position in the viewport.
612
613     \sa visualIndexAt(), isSectionHidden()
614 */
615
616 int QHeaderView::logicalIndexAt(int position) const
617 {
618     const int visual = visualIndexAt(position);
619     if (visual > -1)
620         return logicalIndex(visual);
621     return -1;
622 }
623
624 /*!
625     Returns the width (or height for vertical headers) of the given
626     \a logicalIndex.
627
628     \sa length(), setSectionResizeMode(), defaultSectionSize()
629 */
630
631 int QHeaderView::sectionSize(int logicalIndex) const
632 {
633     Q_D(const QHeaderView);
634     if (isSectionHidden(logicalIndex))
635         return 0;
636     if (logicalIndex < 0 || logicalIndex >= count())
637         return 0;
638     int visual = visualIndex(logicalIndex);
639     if (visual == -1)
640         return 0;
641     d->executePostedResize();
642     return d->headerSectionSize(visual);
643 }
644
645 /*!
646
647     Returns the section position of the given \a logicalIndex, or -1
648     if the section is hidden. The position is measured in pixels from
649     the first visible item's top-left corner to the top-left corner of
650     the item with \a logicalIndex. The measurement is along the x-axis
651     for horizontal headers and along the y-axis for vertical headers.
652
653     \sa sectionViewportPosition()
654 */
655
656 int QHeaderView::sectionPosition(int logicalIndex) const
657 {
658     Q_D(const QHeaderView);
659     int visual = visualIndex(logicalIndex);
660     // in some cases users may change the selections
661     // before we have a chance to do the layout
662     if (visual == -1)
663         return -1;
664     d->executePostedResize();
665     return d->headerSectionPosition(visual);
666 }
667
668 /*!
669     Returns the section viewport position of the given \a logicalIndex.
670
671     If the section is hidden, the return value is undefined.
672
673     \sa sectionPosition(), isSectionHidden()
674 */
675
676 int QHeaderView::sectionViewportPosition(int logicalIndex) const
677 {
678     Q_D(const QHeaderView);
679     if (logicalIndex >= count())
680         return -1;
681     int position = sectionPosition(logicalIndex);
682     if (position < 0)
683         return position; // the section was hidden
684     int offsetPosition = position - d->offset;
685     if (d->reverse())
686         return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
687     return offsetPosition;
688 }
689
690 /*!
691     \fn int QHeaderView::logicalIndexAt(int x, int y) const
692
693     Returns the logical index of the section at the given coordinate. If the
694     header is horizontal \a x will be used, otherwise \a y will be used to
695     find the logical index.
696 */
697
698 /*!
699     \fn int QHeaderView::logicalIndexAt(const QPoint &pos) const
700
701     Returns the logical index of the section at the position given in \a pos.
702     If the header is horizontal the x-coordinate will be used, otherwise the
703     y-coordinate will be used to find the logical index.
704
705     \sa sectionPosition()
706 */
707
708 /*!
709     Moves the section at visual index \a from to occupy visual index \a to.
710
711     \sa sectionsMoved()
712 */
713
714 void QHeaderView::moveSection(int from, int to)
715 {
716     Q_D(QHeaderView);
717
718     d->executePostedLayout();
719     if (from < 0 || from >= d->sectionCount() || to < 0 || to >= d->sectionCount())
720         return;
721
722     if (from == to) {
723         int logical = logicalIndex(from);
724         Q_ASSERT(logical != -1);
725         updateSection(logical);
726         return;
727     }
728
729     if (stretchLastSection() &&  to == d->lastVisibleVisualIndex())
730         d->lastSectionSize = sectionSize(from);
731
732     //int oldHeaderLength = length(); // ### for debugging; remove later
733     d->initializeIndexMapping();
734
735     QBitArray sectionHidden = d->sectionHidden;
736     int *visualIndices = d->visualIndices.data();
737     int *logicalIndices = d->logicalIndices.data();
738     int logical = logicalIndices[from];
739     int visual = from;
740
741     int affected_count = qAbs(to - from) + 1;
742     QVarLengthArray<int> sizes(affected_count);
743     QVarLengthArray<ResizeMode> modes(affected_count);
744
745     // move sections and indices
746     if (to > from) {
747         sizes[to - from] = d->headerSectionSize(from);
748         modes[to - from] = d->headerSectionResizeMode(from);
749         while (visual < to) {
750             sizes[visual - from] = d->headerSectionSize(visual + 1);
751             modes[visual - from] = d->headerSectionResizeMode(visual + 1);
752             if (!sectionHidden.isEmpty())
753                 sectionHidden.setBit(visual, sectionHidden.testBit(visual + 1));
754             visualIndices[logicalIndices[visual + 1]] = visual;
755             logicalIndices[visual] = logicalIndices[visual + 1];
756             ++visual;
757         }
758     } else {
759         sizes[0] = d->headerSectionSize(from);
760         modes[0] = d->headerSectionResizeMode(from);
761         while (visual > to) {
762             sizes[visual - to] = d->headerSectionSize(visual - 1);
763             modes[visual - to] = d->headerSectionResizeMode(visual - 1);
764             if (!sectionHidden.isEmpty())
765                 sectionHidden.setBit(visual, sectionHidden.testBit(visual - 1));
766             visualIndices[logicalIndices[visual - 1]] = visual;
767             logicalIndices[visual] = logicalIndices[visual - 1];
768             --visual;
769         }
770     }
771     if (!sectionHidden.isEmpty()) {
772         sectionHidden.setBit(to, d->sectionHidden.testBit(from));
773         d->sectionHidden = sectionHidden;
774     }
775     visualIndices[logical] = to;
776     logicalIndices[to] = logical;
777
778     //Q_ASSERT(oldHeaderLength == length());
779     // move sizes
780     // ### check for items of section sizes here
781     if (to > from) {
782         for (visual = from; visual <= to; ++visual) {
783             int size = sizes[visual - from];
784             ResizeMode mode = modes[visual - from];
785             d->createSectionItems(visual, visual, size, mode);
786         }
787     } else {
788         for (visual = to; visual <= from; ++visual) {
789             int size = sizes[visual - to];
790             ResizeMode mode = modes[visual - to];
791             d->createSectionItems(visual, visual, size, mode);
792         }
793     }
794     //Q_ASSERT(d->headerLength() == length());
795     //Q_ASSERT(oldHeaderLength == length());
796     //Q_ASSERT(d->logicalIndices.count() == d->sectionCount);
797
798     if (d->hasAutoResizeSections())
799         d->doDelayedResizeSections();
800     d->viewport->update();
801
802     emit sectionMoved(logical, from, to);
803 }
804
805 /*!
806     \since 4.2
807     Swaps the section at visual index \a first with the section at visual
808     index \a second.
809
810     \sa moveSection()
811 */
812 void QHeaderView::swapSections(int first, int second)
813 {
814     Q_D(QHeaderView);
815
816     if (first == second)
817         return;
818     d->executePostedLayout();
819     if (first < 0 || first >= d->sectionCount() || second < 0 || second >= d->sectionCount())
820         return;
821
822     int firstSize = d->headerSectionSize(first);
823     ResizeMode firstMode = d->headerSectionResizeMode(first);
824     int firstLogical = d->logicalIndex(first);
825
826     int secondSize = d->headerSectionSize(second);
827     ResizeMode secondMode = d->headerSectionResizeMode(second);
828     int secondLogical = d->logicalIndex(second);
829
830     if (d->state == QHeaderViewPrivate::ResizeSection)
831         d->preventCursorChangeInSetOffset = true;
832
833     d->createSectionItems(second, second, firstSize, firstMode);
834     d->createSectionItems(first, first, secondSize, secondMode);
835
836     d->initializeIndexMapping();
837
838     d->visualIndices[firstLogical] = second;
839     d->logicalIndices[second] = firstLogical;
840
841     d->visualIndices[secondLogical] = first;
842     d->logicalIndices[first] = secondLogical;
843
844     if (!d->sectionHidden.isEmpty()) {
845         bool firstHidden = d->sectionHidden.testBit(first);
846         bool secondHidden = d->sectionHidden.testBit(second);
847         d->sectionHidden.setBit(first, secondHidden);
848         d->sectionHidden.setBit(second, firstHidden);
849     }
850
851     d->viewport->update();
852     emit sectionMoved(firstLogical, first, second);
853     emit sectionMoved(secondLogical, second, first);
854 }
855
856 /*!
857     \fn void QHeaderView::resizeSection(int logicalIndex, int size)
858
859     Resizes the section specified by \a logicalIndex to \a size measured in
860     pixels. The size parameter must be a value larger or equal to zero. A
861     size equal to zero is however not recommended. In that situation hideSection
862     should be used instead.
863
864     \sa sectionResized(), resizeMode(), sectionSize(), hideSection()
865 */
866
867 void QHeaderView::resizeSection(int logical, int size)
868 {
869     Q_D(QHeaderView);
870     if (logical < 0 || logical >= count() || size < 0)
871         return;
872
873     if (isSectionHidden(logical)) {
874         d->hiddenSectionSize.insert(logical, size);
875         return;
876     }
877
878     int visual = visualIndex(logical);
879     if (visual == -1)
880         return;
881
882     if (d->state == QHeaderViewPrivate::ResizeSection && !d->cascadingResizing && logical != d->section)
883         d->preventCursorChangeInSetOffset = true;
884
885     int oldSize = d->headerSectionSize(visual);
886     if (oldSize == size)
887         return;
888
889     d->executePostedLayout();
890     d->invalidateCachedSizeHint();
891
892     if (stretchLastSection() && visual == d->lastVisibleVisualIndex())
893         d->lastSectionSize = size;
894
895     d->createSectionItems(visual, visual, size, d->headerSectionResizeMode(visual));
896
897     if (!updatesEnabled()) {
898         if (d->hasAutoResizeSections())
899             d->doDelayedResizeSections();
900         emit sectionResized(logical, oldSize, size);
901         return;
902     }
903
904     int w = d->viewport->width();
905     int h = d->viewport->height();
906     int pos = sectionViewportPosition(logical);
907     QRect r;
908     if (d->orientation == Qt::Horizontal)
909         if (isRightToLeft())
910             r.setRect(0, 0, pos + size, h);
911         else
912             r.setRect(pos, 0, w - pos, h);
913     else
914         r.setRect(0, pos, w, h - pos);
915
916     if (d->hasAutoResizeSections()) {
917         d->doDelayedResizeSections();
918         r = d->viewport->rect();
919     }
920     d->viewport->update(r.normalized());
921     emit sectionResized(logical, oldSize, size);
922 }
923
924 /*!
925     Resizes the sections according to the given \a mode, ignoring the current
926     resize mode.
927
928     \sa resizeMode(), sectionResized()
929 */
930
931 void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
932 {
933     Q_D(QHeaderView);
934     d->resizeSections(mode, true);
935 }
936
937 /*!
938     \fn void QHeaderView::hideSection(int logicalIndex)
939     Hides the section specified by \a logicalIndex.
940
941     \sa showSection(), isSectionHidden(), hiddenSectionCount(),
942     setSectionHidden()
943 */
944
945 /*!
946     \fn void QHeaderView::showSection(int logicalIndex)
947     Shows the section specified by \a logicalIndex.
948
949     \sa hideSection(), isSectionHidden(), hiddenSectionCount(),
950     setSectionHidden()
951 */
952
953 /*!
954     Returns true if the section specified by \a logicalIndex is explicitly
955     hidden from the user; otherwise returns false.
956
957     \sa hideSection(), showSection(), setSectionHidden(), hiddenSectionCount()
958 */
959
960 bool QHeaderView::isSectionHidden(int logicalIndex) const
961 {
962     Q_D(const QHeaderView);
963     d->executePostedLayout();
964     if (logicalIndex >= d->sectionHidden.count() || logicalIndex < 0 || logicalIndex >= d->sectionCount())
965         return false;
966     int visual = visualIndex(logicalIndex);
967     Q_ASSERT(visual != -1);
968     return d->sectionHidden.testBit(visual);
969 }
970
971 /*!
972     \since 4.1
973
974     Returns the number of sections in the header that has been hidden.
975
976     \sa setSectionHidden(), isSectionHidden()
977 */
978 int QHeaderView::hiddenSectionCount() const
979 {
980     Q_D(const QHeaderView);
981     return d->hiddenSectionSize.count();
982 }
983
984 /*!
985   If \a hide is true the section specified by \a logicalIndex is hidden;
986   otherwise the section is shown.
987
988   \sa isSectionHidden(), hiddenSectionCount()
989 */
990
991 void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
992 {
993     Q_D(QHeaderView);
994     if (logicalIndex < 0 || logicalIndex >= count())
995         return;
996
997     d->executePostedLayout();
998     int visual = visualIndex(logicalIndex);
999     Q_ASSERT(visual != -1);
1000     if (hide == d->isVisualIndexHidden(visual))
1001         return;
1002     if (hide) {
1003         int size = d->headerSectionSize(visual);
1004         if (!d->hasAutoResizeSections())
1005             resizeSection(logicalIndex, 0);
1006         d->hiddenSectionSize.insert(logicalIndex, size);
1007         if (d->sectionHidden.count() < count())
1008             d->sectionHidden.resize(count());
1009         d->sectionHidden.setBit(visual, true);
1010         if (d->hasAutoResizeSections())
1011             d->doDelayedResizeSections();
1012     } else {
1013         int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
1014         d->hiddenSectionSize.remove(logicalIndex);
1015         if (d->hiddenSectionSize.isEmpty()) {
1016             d->sectionHidden.clear();
1017         } else {
1018             Q_ASSERT(visual <= d->sectionHidden.count());
1019             d->sectionHidden.setBit(visual, false);
1020         }
1021         resizeSection(logicalIndex, size);
1022     }
1023 }
1024
1025 /*!
1026     Returns the number of sections in the header.
1027
1028     \sa sectionCountChanged(), length()
1029 */
1030
1031 int QHeaderView::count() const
1032 {
1033     Q_D(const QHeaderView);
1034     //Q_ASSERT(d->sectionCount == d->headerSectionCount());
1035     // ### this may affect the lazy layout
1036     d->executePostedLayout();
1037     return d->sectionCount();
1038 }
1039
1040 /*!
1041     Returns the visual index position of the section specified by the given
1042     \a logicalIndex, or -1 otherwise.
1043
1044     Hidden sections still have valid visual indexes.
1045
1046     \sa logicalIndex()
1047 */
1048
1049 int QHeaderView::visualIndex(int logicalIndex) const
1050 {
1051     Q_D(const QHeaderView);
1052     if (logicalIndex < 0)
1053         return -1;
1054     d->executePostedLayout();
1055     if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
1056         if (logicalIndex < d->sectionCount())
1057             return logicalIndex;
1058     } else if (logicalIndex < d->visualIndices.count()) {
1059         int visual = d->visualIndices.at(logicalIndex);
1060         Q_ASSERT(visual < d->sectionCount());
1061         return visual;
1062     }
1063     return -1;
1064 }
1065
1066 /*!
1067     Returns the logicalIndex for the section at the given \a visualIndex
1068     position, or -1 if visualIndex < 0 or visualIndex >= QHeaderView::count().
1069
1070     Note that the visualIndex is not affected by hidden sections.
1071
1072     \sa visualIndex(), sectionPosition()
1073 */
1074
1075 int QHeaderView::logicalIndex(int visualIndex) const
1076 {
1077     Q_D(const QHeaderView);
1078     if (visualIndex < 0 || visualIndex >= d->sectionCount())
1079         return -1;
1080     return d->logicalIndex(visualIndex);
1081 }
1082
1083 /*!
1084     If \a movable is true, the header may be moved by the user; otherwise it
1085     is fixed in place.
1086
1087     \sa sectionsMovable(), sectionMoved()
1088 */
1089
1090 void QHeaderView::setSectionsMovable(bool movable)
1091 {
1092     Q_D(QHeaderView);
1093     d->movableSections = movable;
1094 }
1095
1096 // ### Qt 6 - remove this obsolete function
1097 /*!
1098     \obsolete
1099     \fn void QHeaderView::setMovable(bool movable)
1100
1101     Use setSectionsMovable instead.
1102
1103     \sa setSectionsMovable()
1104 */
1105
1106 /*!
1107     Returns true if the header can be moved by the user; otherwise returns
1108     false.
1109
1110     \sa setSectionsMovable()
1111 */
1112
1113 bool QHeaderView::sectionsMovable() const
1114 {
1115     Q_D(const QHeaderView);
1116     return d->movableSections;
1117 }
1118
1119 // ### Qt 6 - remove this obsolete function
1120 /*!
1121     \obsolete
1122     \fn bool QHeaderView::isMovable() const
1123
1124     Use sectionsMovable instead.
1125
1126     \sa sectionsMovable()
1127 */
1128
1129 /*!
1130     If \a clickable is true, the header will respond to single clicks.
1131
1132     \sa sectionsClickable(), sectionClicked(), sectionPressed(),
1133     setSortIndicatorShown()
1134 */
1135
1136 void QHeaderView::setSectionsClickable(bool clickable)
1137 {
1138     Q_D(QHeaderView);
1139     d->clickableSections = clickable;
1140 }
1141
1142 // ### Qt 6 - remove this obsolete function
1143 /*!
1144     \obsolete
1145     \fn void QHeaderView::setClickable(bool clickable)
1146
1147     Use setSectionsClickable instead.
1148
1149     \sa setSectionsClickable()
1150 */
1151
1152 /*!
1153     Returns true if the header is clickable; otherwise returns false. A
1154     clickable header could be set up to allow the user to change the
1155     representation of the data in the view related to the header.
1156
1157     \sa setSectionsClickable()
1158 */
1159
1160 bool QHeaderView::sectionsClickable() const
1161 {
1162     Q_D(const QHeaderView);
1163     return d->clickableSections;
1164 }
1165
1166 // ### Qt 6 - remove this obsolete function
1167 /*!
1168     \obsolete
1169     \fn bool QHeaderView::isClickable() const
1170
1171     Use sectionsClickable instead.
1172
1173     \sa sectionsClickable()
1174 */
1175
1176 void QHeaderView::setHighlightSections(bool highlight)
1177 {
1178     Q_D(QHeaderView);
1179     d->highlightSelected = highlight;
1180 }
1181
1182 bool QHeaderView::highlightSections() const
1183 {
1184     Q_D(const QHeaderView);
1185     return d->highlightSelected;
1186 }
1187
1188 /*!
1189     Sets the constraints on how the header can be resized to those described
1190     by the given \a mode.
1191
1192     \sa resizeMode(), length(), sectionResized()
1193 */
1194
1195 void QHeaderView::setSectionResizeMode(ResizeMode mode)
1196 {
1197     Q_D(QHeaderView);
1198     initializeSections();
1199     d->stretchSections = (mode == Stretch ? count() : 0);
1200     d->contentsSections =  (mode == ResizeToContents ? count() : 0);
1201     d->setGlobalHeaderResizeMode(mode);
1202     if (d->hasAutoResizeSections())
1203         d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1204 }
1205
1206 /*!
1207     Sets the constraints on how the section specified by \a logicalIndex in
1208     the header can be resized to those described by the given \a mode. The logical
1209     index should exist at the time this function is called.
1210
1211     \note This setting will be ignored for the last section if the stretchLastSection
1212     property is set to true. This is the default for the horizontal headers provided
1213     by QTreeView.
1214
1215     \sa setStretchLastSection()
1216 */
1217
1218 void QHeaderView::setSectionResizeMode(int logicalIndex, ResizeMode mode)
1219 {
1220     Q_D(QHeaderView);
1221     int visual = visualIndex(logicalIndex);
1222     Q_ASSERT(visual != -1);
1223
1224     ResizeMode old = d->headerSectionResizeMode(visual);
1225     d->setHeaderSectionResizeMode(visual, mode);
1226
1227     if (mode == Stretch && old != Stretch)
1228         ++d->stretchSections;
1229     else if (mode == ResizeToContents && old != ResizeToContents)
1230         ++d->contentsSections;
1231     else if (mode != Stretch && old == Stretch)
1232         --d->stretchSections;
1233     else if (mode != ResizeToContents && old == ResizeToContents)
1234         --d->contentsSections;
1235
1236     if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
1237         d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1238 }
1239
1240 // ### Qt 6 - remove this obsolete function
1241 /*!
1242     \overload
1243     \obsolete
1244     \fn void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
1245
1246     Use setSectionResizeMode instead.
1247
1248     \sa setSectionResizeMode()
1249 */
1250
1251 /*!
1252     \obsolete
1253     \fn void QHeaderView::setResizeMode(ResizeMode mode)
1254
1255     Use setSectionResizeMode instead.
1256
1257     \sa setSectionResizeMode()
1258 */
1259
1260 /*!
1261     Returns the resize mode that applies to the section specified by the given
1262     \a logicalIndex.
1263
1264     \sa setSectionResizeMode()
1265 */
1266
1267 QHeaderView::ResizeMode QHeaderView::sectionResizeMode(int logicalIndex) const
1268 {
1269     Q_D(const QHeaderView);
1270     int visual = visualIndex(logicalIndex);
1271     if (visual == -1)
1272         return Fixed; //the default value
1273     return d->headerSectionResizeMode(visual);
1274 }
1275
1276 // ### Qt 6 - remove this obsolete function
1277 /*!
1278     \obsolete
1279     \fn QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
1280
1281     Use sectionResizeMode instead.
1282
1283     \sa sectionResizeMode()
1284 */
1285
1286 /*!
1287     \since 4.1
1288
1289     Returns the number of sections that are set to resize mode stretch. In
1290     views, this can be used to see if the headerview needs to resize the
1291     sections when the view's geometry changes.
1292
1293     \sa stretchLastSection, resizeMode()
1294 */
1295
1296 int QHeaderView::stretchSectionCount() const
1297 {
1298     Q_D(const QHeaderView);
1299     return d->stretchSections;
1300 }
1301
1302 /*!
1303   \property QHeaderView::showSortIndicator
1304   \brief whether the sort indicator is shown
1305
1306   By default, this property is false.
1307
1308   \sa setSectionsClickable()
1309 */
1310
1311 void QHeaderView::setSortIndicatorShown(bool show)
1312 {
1313     Q_D(QHeaderView);
1314     if (d->sortIndicatorShown == show)
1315         return;
1316
1317     d->sortIndicatorShown = show;
1318
1319     if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
1320         return;
1321
1322     if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
1323         resizeSections();
1324
1325     d->viewport->update();
1326 }
1327
1328 bool QHeaderView::isSortIndicatorShown() const
1329 {
1330     Q_D(const QHeaderView);
1331     return d->sortIndicatorShown;
1332 }
1333
1334 /*!
1335     Sets the sort indicator for the section specified by the given
1336     \a logicalIndex in the direction specified by \a order, and removes the
1337     sort indicator from any other section that was showing it.
1338
1339     \a logicalIndex may be -1, in which case no sort indicator will be shown
1340     and the model will return to its natural, unsorted order. Note that not
1341     all models support this and may even crash in this case.
1342
1343     \sa sortIndicatorSection(), sortIndicatorOrder()
1344 */
1345
1346 void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
1347 {
1348     Q_D(QHeaderView);
1349
1350     // This is so that people can set the position of the sort indicator before the fill the model
1351     int old = d->sortIndicatorSection;
1352     if (old == logicalIndex && order == d->sortIndicatorOrder)
1353         return;
1354     d->sortIndicatorSection = logicalIndex;
1355     d->sortIndicatorOrder = order;
1356
1357     if (logicalIndex >= d->sectionCount()) {
1358         emit sortIndicatorChanged(logicalIndex, order);
1359         return; // nothing to do
1360     }
1361
1362     if (old != logicalIndex
1363         && ((logicalIndex >= 0 && sectionResizeMode(logicalIndex) == ResizeToContents)
1364             || old >= d->sectionCount() || (old >= 0 && sectionResizeMode(old) == ResizeToContents))) {
1365         resizeSections();
1366         d->viewport->update();
1367     } else {
1368         if (old >= 0 && old != logicalIndex)
1369             updateSection(old);
1370         if (logicalIndex >= 0)
1371             updateSection(logicalIndex);
1372     }
1373
1374     emit sortIndicatorChanged(logicalIndex, order);
1375 }
1376
1377 /*!
1378     Returns the logical index of the section that has a sort indicator.
1379     By default this is section 0.
1380
1381     \sa setSortIndicator(), sortIndicatorOrder(), setSortIndicatorShown()
1382 */
1383
1384 int QHeaderView::sortIndicatorSection() const
1385 {
1386     Q_D(const QHeaderView);
1387     return d->sortIndicatorSection;
1388 }
1389
1390 /*!
1391     Returns the order for the sort indicator. If no section has a sort
1392     indicator the return value of this function is undefined.
1393
1394     \sa setSortIndicator(), sortIndicatorSection()
1395 */
1396
1397 Qt::SortOrder QHeaderView::sortIndicatorOrder() const
1398 {
1399     Q_D(const QHeaderView);
1400     return d->sortIndicatorOrder;
1401 }
1402
1403 /*!
1404     \property QHeaderView::stretchLastSection
1405     \brief whether the last visible section in the header takes up all the
1406     available space
1407
1408     The default value is false.
1409
1410     \note The horizontal headers provided by QTreeView are configured with this
1411     property set to true, ensuring that the view does not waste any of the
1412     space assigned to it for its header. If this value is set to true, this
1413     property will override the resize mode set on the last section in the
1414     header.
1415
1416     \sa setSectionResizeMode()
1417 */
1418 bool QHeaderView::stretchLastSection() const
1419 {
1420     Q_D(const QHeaderView);
1421     return d->stretchLastSection;
1422 }
1423
1424 void QHeaderView::setStretchLastSection(bool stretch)
1425 {
1426     Q_D(QHeaderView);
1427     d->stretchLastSection = stretch;
1428     if (d->state != QHeaderViewPrivate::NoState)
1429         return;
1430     if (stretch)
1431         resizeSections();
1432     else if (count())
1433         resizeSection(count() - 1, d->defaultSectionSize);
1434 }
1435
1436 /*!
1437     \since 4.2
1438     \property QHeaderView::cascadingSectionResizes
1439     \brief whether interactive resizing will be cascaded to the following
1440     sections once the section being resized by the user has reached its
1441     minimum size
1442
1443     This property only affects sections that have \l Interactive as their
1444     resize mode.
1445
1446     The default value is false.
1447
1448     \sa setSectionResizeMode()
1449 */
1450 bool QHeaderView::cascadingSectionResizes() const
1451 {
1452     Q_D(const QHeaderView);
1453     return d->cascadingResizing;
1454 }
1455
1456 void QHeaderView::setCascadingSectionResizes(bool enable)
1457 {
1458     Q_D(QHeaderView);
1459     d->cascadingResizing = enable;
1460 }
1461
1462 /*!
1463     \property QHeaderView::defaultSectionSize
1464     \brief the default size of the header sections before resizing.
1465
1466     This property only affects sections that have \l Interactive or \l Fixed
1467     as their resize mode.
1468
1469     \sa setSectionResizeMode(), minimumSectionSize
1470 */
1471 int QHeaderView::defaultSectionSize() const
1472 {
1473     Q_D(const QHeaderView);
1474     return d->defaultSectionSize;
1475 }
1476
1477 void QHeaderView::setDefaultSectionSize(int size)
1478 {
1479     Q_D(QHeaderView);
1480     if (size < 0)
1481         return;
1482     d->setDefaultSectionSize(size);
1483 }
1484
1485 /*!
1486     \since 4.2
1487     \property QHeaderView::minimumSectionSize
1488     \brief the minimum size of the header sections.
1489
1490     The minimum section size is the smallest section size allowed. If the
1491     minimum section size is set to -1, QHeaderView will use the maximum of
1492     the \l{QApplication::globalStrut()}{global strut} or the
1493     \l{fontMetrics()}{font metrics} size.
1494
1495     This property is honored by all \l{ResizeMode}{resize modes}.
1496
1497     \sa setSectionResizeMode(), defaultSectionSize
1498 */
1499 int QHeaderView::minimumSectionSize() const
1500 {
1501     Q_D(const QHeaderView);
1502     if (d->minimumSectionSize == -1) {
1503         QSize strut = QApplication::globalStrut();
1504         int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
1505         if (d->orientation == Qt::Horizontal)
1506             return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
1507         return qMax(strut.height(), (fontMetrics().height() + margin));
1508     }
1509     return d->minimumSectionSize;
1510 }
1511
1512 void QHeaderView::setMinimumSectionSize(int size)
1513 {
1514     Q_D(QHeaderView);
1515     if (size < 0)
1516         return;
1517     d->minimumSectionSize = size;
1518 }
1519
1520 /*!
1521     \since 4.1
1522     \property QHeaderView::defaultAlignment
1523     \brief the default alignment of the text in each header section
1524 */
1525
1526 Qt::Alignment QHeaderView::defaultAlignment() const
1527 {
1528     Q_D(const QHeaderView);
1529     return d->defaultAlignment;
1530 }
1531
1532 void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
1533 {
1534     Q_D(QHeaderView);
1535     if (d->defaultAlignment == alignment)
1536         return;
1537
1538     d->defaultAlignment = alignment;
1539     d->viewport->update();
1540 }
1541
1542 /*!
1543     \internal
1544 */
1545 void QHeaderView::doItemsLayout()
1546 {
1547     initializeSections();
1548     QAbstractItemView::doItemsLayout();
1549 }
1550
1551 /*!
1552     Returns true if sections in the header has been moved; otherwise returns
1553     false;
1554
1555     \sa moveSection()
1556 */
1557 bool QHeaderView::sectionsMoved() const
1558 {
1559     Q_D(const QHeaderView);
1560     return !d->visualIndices.isEmpty();
1561 }
1562
1563 /*!
1564     \since 4.1
1565
1566     Returns true if sections in the header has been hidden; otherwise returns
1567     false;
1568
1569     \sa setSectionHidden()
1570 */
1571 bool QHeaderView::sectionsHidden() const
1572 {
1573     Q_D(const QHeaderView);
1574     return !d->hiddenSectionSize.isEmpty();
1575 }
1576
1577 #ifndef QT_NO_DATASTREAM
1578 /*!
1579     \since 4.3
1580
1581     Saves the current state of this header view.
1582
1583     To restore the saved state, pass the return value to restoreState().
1584
1585     \sa restoreState()
1586 */
1587 QByteArray QHeaderView::saveState() const
1588 {
1589     Q_D(const QHeaderView);
1590     QByteArray data;
1591     QDataStream stream(&data, QIODevice::WriteOnly);
1592     stream << QHeaderViewPrivate::VersionMarker;
1593     stream << 0; // current version is 0
1594     d->write(stream);
1595     return data;
1596 }
1597
1598 /*!
1599     \since 4.3
1600     Restores the \a state of this header view.
1601     This function returns \c true if the state was restored; otherwise returns
1602     false.
1603
1604     \sa saveState()
1605 */
1606 bool QHeaderView::restoreState(const QByteArray &state)
1607 {
1608     Q_D(QHeaderView);
1609     if (state.isEmpty())
1610         return false;
1611     QByteArray data = state;
1612     QDataStream stream(&data, QIODevice::ReadOnly);
1613     int marker;
1614     int ver;
1615     stream >> marker;
1616     stream >> ver;
1617     if (stream.status() != QDataStream::Ok
1618         || marker != QHeaderViewPrivate::VersionMarker
1619         || ver != 0) // current version is 0
1620         return false;
1621
1622     if (d->read(stream)) {
1623         emit sortIndicatorChanged(d->sortIndicatorSection, d->sortIndicatorOrder );
1624         d->viewport->update();
1625         return true;
1626     }
1627     return false;
1628 }
1629 #endif // QT_NO_DATASTREAM
1630
1631 /*!
1632   \reimp
1633 */
1634 void QHeaderView::reset()
1635 {
1636     QAbstractItemView::reset();
1637     // it would be correct to call clear, but some apps rely
1638     // on the header keeping the sections, even after calling reset
1639     //d->clear();
1640     initializeSections();
1641 }
1642
1643 /*!
1644     Updates the changed header sections with the given \a orientation, from
1645     \a logicalFirst to \a logicalLast inclusive.
1646 */
1647 void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
1648 {
1649     Q_D(QHeaderView);
1650     if (d->orientation != orientation)
1651         return;
1652
1653     if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
1654         return;
1655
1656     d->invalidateCachedSizeHint();
1657
1658     int firstVisualIndex = INT_MAX, lastVisualIndex = -1;
1659
1660     for (int section = logicalFirst; section <= logicalLast; ++section) {
1661         const int visual = visualIndex(section);
1662         firstVisualIndex = qMin(firstVisualIndex, visual);
1663         lastVisualIndex =  qMax(lastVisualIndex,  visual);
1664     }
1665
1666     d->executePostedResize();
1667     const int first = d->headerSectionPosition(firstVisualIndex),
1668               last = d->headerSectionPosition(lastVisualIndex)
1669                         + d->headerSectionSize(lastVisualIndex);
1670
1671     if (orientation == Qt::Horizontal) {
1672         d->viewport->update(first, 0, last - first, d->viewport->height());
1673     } else {
1674         d->viewport->update(0, first, d->viewport->width(), last - first);
1675     }
1676 }
1677
1678 /*!
1679     \internal
1680     \since 4.2
1681
1682     Updates the section specified by the given \a logicalIndex.
1683 */
1684
1685 void QHeaderView::updateSection(int logicalIndex)
1686 {
1687     Q_D(QHeaderView);
1688     if (d->orientation == Qt::Horizontal)
1689         d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
1690                                   0, sectionSize(logicalIndex), d->viewport->height()));
1691     else
1692         d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
1693                                   d->viewport->width(), sectionSize(logicalIndex)));
1694 }
1695
1696 /*!
1697     Resizes the sections according to their size hints. Normally, you do not
1698     have to call this function.
1699 */
1700
1701 void QHeaderView::resizeSections()
1702 {
1703     Q_D(QHeaderView);
1704     if (d->hasAutoResizeSections())
1705         d->resizeSections(Interactive, false); // no global resize mode
1706 }
1707
1708 /*!
1709     This slot is called when sections are inserted into the \a parent.
1710     \a logicalFirst and \a logicalLast indices signify where the new sections
1711     were inserted.
1712
1713     If only one section is inserted, \a logicalFirst and \a logicalLast will
1714     be the same.
1715 */
1716
1717 void QHeaderView::sectionsInserted(const QModelIndex &parent,
1718                                    int logicalFirst, int logicalLast)
1719 {
1720     Q_D(QHeaderView);
1721     if (parent != d->root)
1722         return; // we only handle changes in the root level
1723     int oldCount = d->sectionCount();
1724
1725     d->invalidateCachedSizeHint();
1726
1727     if (d->state == QHeaderViewPrivate::ResizeSection)
1728         d->preventCursorChangeInSetOffset = true;
1729
1730     // add the new sections
1731     int insertAt = logicalFirst;
1732     int insertCount = logicalLast - logicalFirst + 1;
1733
1734     QHeaderViewPrivate::SectionItem section(d->defaultSectionSize, d->globalResizeMode);
1735     d->sectionStartposRecalc = true;
1736
1737     if (d->sectionItems.isEmpty() || insertAt >= d->sectionItems.count()) {
1738         int insertLength = d->defaultSectionSize * insertCount;
1739         d->length += insertLength;
1740         d->sectionItems.insert(d->sectionItems.count(), insertCount, section); // append
1741     } else {
1742         // separate them out into their own sections
1743         int insertLength = d->defaultSectionSize * insertCount;
1744         d->length += insertLength;
1745         d->sectionItems.insert(insertAt, insertCount, section);
1746     }
1747
1748     // update sorting column
1749     if (d->sortIndicatorSection >= logicalFirst)
1750         d->sortIndicatorSection += insertCount;
1751
1752     // update resize mode section counts
1753     if (d->globalResizeMode == Stretch)
1754         d->stretchSections = d->sectionCount();
1755     else if (d->globalResizeMode == ResizeToContents)
1756         d->contentsSections = d->sectionCount();
1757
1758     // clear selection cache
1759     d->sectionSelected.clear();
1760
1761     // update mapping
1762     if (!d->visualIndices.isEmpty() && !d->logicalIndices.isEmpty()) {
1763         Q_ASSERT(d->visualIndices.count() == d->logicalIndices.count());
1764         int mappingCount = d->visualIndices.count();
1765         for (int i = 0; i < mappingCount; ++i) {
1766             if (d->visualIndices.at(i) >= logicalFirst)
1767                d->visualIndices[i] += insertCount;
1768             if (d->logicalIndices.at(i) >= logicalFirst)
1769                 d->logicalIndices[i] += insertCount;
1770         }
1771         for (int j = logicalFirst; j <= logicalLast; ++j) {
1772             d->visualIndices.insert(j, j);
1773             d->logicalIndices.insert(j, j);
1774         }
1775     }
1776
1777     // insert sections into sectionsHidden
1778     if (!d->sectionHidden.isEmpty()) {
1779         QBitArray sectionHidden(d->sectionHidden);
1780         sectionHidden.resize(sectionHidden.count() + insertCount);
1781         sectionHidden.fill(false, logicalFirst, logicalLast + 1);
1782         for (int j = logicalLast + 1; j < sectionHidden.count(); ++j)
1783             //here we simply copy the old sectionHidden
1784             sectionHidden.setBit(j, d->sectionHidden.testBit(j - insertCount));
1785         d->sectionHidden = sectionHidden;
1786     }
1787
1788     // insert sections into hiddenSectionSize
1789     QHash<int, int> newHiddenSectionSize; // from logical index to section size
1790     for (int i = 0; i < logicalFirst; ++i)
1791         if (isSectionHidden(i))
1792             newHiddenSectionSize[i] = d->hiddenSectionSize[i];
1793     for (int j = logicalLast + 1; j < d->sectionCount(); ++j)
1794         if (isSectionHidden(j))
1795             newHiddenSectionSize[j] = d->hiddenSectionSize[j - insertCount];
1796     d->hiddenSectionSize = newHiddenSectionSize;
1797
1798     d->doDelayedResizeSections();
1799     emit sectionCountChanged(oldCount, count());
1800
1801     // if the new sections were not updated by resizing, we need to update now
1802     if (!d->hasAutoResizeSections())
1803         d->viewport->update();
1804 }
1805
1806 /*!
1807     This slot is called when sections are removed from the \a parent.
1808     \a logicalFirst and \a logicalLast signify where the sections were removed.
1809
1810     If only one section is removed, \a logicalFirst and \a logicalLast will
1811     be the same.
1812 */
1813
1814 void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
1815                                            int logicalFirst, int logicalLast)
1816 {
1817     Q_UNUSED(parent);
1818     Q_UNUSED(logicalFirst);
1819     Q_UNUSED(logicalLast);
1820 }
1821
1822 void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
1823 {
1824     Q_Q(QHeaderView);
1825     const int changeCount = logicalLast - logicalFirst + 1;
1826
1827     // remove sections from hiddenSectionSize
1828     QHash<int, int> newHiddenSectionSize; // from logical index to section size
1829     for (int i = 0; i < logicalFirst; ++i)
1830         if (q->isSectionHidden(i))
1831             newHiddenSectionSize[i] = hiddenSectionSize[i];
1832     for (int j = logicalLast + 1; j < sectionCount(); ++j)
1833         if (q->isSectionHidden(j))
1834             newHiddenSectionSize[j - changeCount] = hiddenSectionSize[j];
1835     hiddenSectionSize = newHiddenSectionSize;
1836
1837     // remove sections from sectionsHidden
1838     if (!sectionHidden.isEmpty()) {
1839         const int newsize = qMin(sectionCount() - changeCount, sectionHidden.size());
1840         QBitArray newSectionHidden(newsize);
1841         for (int j = 0, k = 0; j < sectionHidden.size(); ++j) {
1842             const int logical = logicalIndex(j);
1843             if (logical < logicalFirst || logical > logicalLast) {
1844                 newSectionHidden[k++] = sectionHidden[j];
1845             }
1846         }
1847         sectionHidden = newSectionHidden;
1848     }
1849 }
1850
1851 void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
1852                                             int logicalFirst, int logicalLast)
1853 {
1854     Q_Q(QHeaderView);
1855     if (parent != root)
1856         return; // we only handle changes in the root level
1857     if (qMin(logicalFirst, logicalLast) < 0
1858         || qMax(logicalLast, logicalFirst) >= sectionCount())
1859         return;
1860     int oldCount = q->count();
1861     int changeCount = logicalLast - logicalFirst + 1;
1862
1863     if (state == QHeaderViewPrivate::ResizeSection)
1864         preventCursorChangeInSetOffset = true;
1865
1866     updateHiddenSections(logicalFirst, logicalLast);
1867
1868     if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
1869         //Q_ASSERT(headerSectionCount() == sectionCount);
1870         removeSectionsFromSectionItems(logicalFirst, logicalLast);
1871     } else {
1872         if (logicalFirst == logicalLast) { // Remove just one index.
1873             int l = logicalFirst;
1874             int visual = visualIndices.at(l);
1875             Q_ASSERT(sectionCount() == logicalIndices.count());
1876             for (int v = 0; v < sectionCount(); ++v) {
1877                 if (v > visual) {
1878                     int logical = logicalIndices.at(v);
1879                     --(visualIndices[logical]);
1880                 }
1881                 if (logicalIndex(v) > l) // no need to move the positions before l
1882                     --(logicalIndices[v]);
1883             }
1884             logicalIndices.remove(visual);
1885             visualIndices.remove(l);
1886             //Q_ASSERT(headerSectionCount() == sectionCount);
1887             removeSectionsFromSectionItems(visual, visual);
1888         } else {
1889             sectionStartposRecalc = true; // We will need to recalc positions after removing items
1890             for (int u = 0; u < sectionItems.count(); ++u)  // Store section info
1891                 sectionItems.at(u).tmpLogIdx = logicalIndices.at(u);
1892             for (int v = sectionItems.count() - 1; v >= 0; --v) {  // Remove the sections
1893                 if (logicalFirst <= sectionItems.at(v).tmpLogIdx && sectionItems.at(v).tmpLogIdx <= logicalLast)
1894                     removeSectionsFromSectionItems(v, v);
1895             }
1896             visualIndices.resize(sectionItems.count());
1897             logicalIndices.resize(sectionItems.count());
1898             int* visual_data = visualIndices.data();
1899             int* logical_data = logicalIndices.data();
1900             for (int w = 0; w < sectionItems.count(); ++w) { // Restore visual and logical indexes
1901                 int logindex = sectionItems.at(w).tmpLogIdx;
1902                 if (logindex > logicalFirst)
1903                     logindex -= changeCount;
1904                 visual_data[logindex] = w;
1905                 logical_data[w] = logindex;
1906             }
1907         }
1908         // ### handle sectionSelection (sectionHidden is handled by updateHiddenSections)
1909     }
1910
1911     // update sorting column
1912     if (sortIndicatorSection >= logicalFirst) {
1913         if (sortIndicatorSection <= logicalLast)
1914             sortIndicatorSection = -1;
1915         else
1916             sortIndicatorSection -= changeCount;
1917     }
1918
1919     // if we only have the last section (the "end" position) left, the header is empty
1920     if (sectionCount() <= 0)
1921         clear();
1922     invalidateCachedSizeHint();
1923     emit q->sectionCountChanged(oldCount, q->count());
1924     viewport->update();
1925 }
1926
1927 void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
1928 {
1929     //if there is no row/column we can't have mapping for columns
1930     //because no QModelIndex in the model would be valid
1931     // ### this is far from being bullet-proof and we would need a real system to
1932     // ### map columns or rows persistently
1933     if ((orientation == Qt::Horizontal && model->rowCount(root) == 0)
1934         || model->columnCount(root) == 0)
1935         return;
1936
1937     for (int i = 0; i < sectionHidden.count(); ++i)
1938         if (sectionHidden.testBit(i)) // ### note that we are using column or row 0
1939             persistentHiddenSections.append(orientation == Qt::Horizontal
1940                                             ? model->index(0, logicalIndex(i), root)
1941                                             : model->index(logicalIndex(i), 0, root));
1942 }
1943
1944 void QHeaderViewPrivate::_q_layoutChanged()
1945 {
1946     Q_Q(QHeaderView);
1947     viewport->update();
1948     if (persistentHiddenSections.isEmpty() || modelIsEmpty()) {
1949         if (modelSectionCount() != sectionCount())
1950             q->initializeSections();
1951         persistentHiddenSections.clear();
1952         return;
1953     }
1954
1955     QBitArray oldSectionHidden = sectionHidden;
1956     bool sectionCountChanged = false;
1957
1958     for (int i = 0; i < persistentHiddenSections.count(); ++i) {
1959         QModelIndex index = persistentHiddenSections.at(i);
1960         if (index.isValid()) {
1961             const int logical = (orientation == Qt::Horizontal
1962                                  ? index.column()
1963                                  : index.row());
1964             q->setSectionHidden(logical, true);
1965             oldSectionHidden.setBit(logical, false);
1966         } else if (!sectionCountChanged && (modelSectionCount() != sectionCount())) {
1967             sectionCountChanged = true;
1968             break;
1969         }
1970     }
1971     persistentHiddenSections.clear();
1972
1973     for (int i = 0; i < oldSectionHidden.count(); ++i) {
1974         if (oldSectionHidden.testBit(i))
1975             q->setSectionHidden(i, false);
1976     }
1977
1978     // the number of sections changed; we need to reread the state of the model
1979     if (sectionCountChanged)
1980         q->initializeSections();
1981 }
1982
1983 /*!
1984   \internal
1985 */
1986
1987 void QHeaderView::initializeSections()
1988 {
1989     Q_D(QHeaderView);
1990     const int oldCount = d->sectionCount();
1991     const int newCount = d->modelSectionCount();
1992     if (newCount <= 0) {
1993             d->clear();
1994             emit sectionCountChanged(oldCount, 0);
1995     } else if (newCount != oldCount) {
1996         const int min = qBound(0, oldCount, newCount - 1);
1997         initializeSections(min, newCount - 1);
1998         if (stretchLastSection()) // we've already gotten the size hint
1999             d->lastSectionSize = sectionSize(logicalIndex(d->sectionCount() - 1));
2000
2001         //make sure we update the hidden sections
2002         if (newCount < oldCount)
2003             d->updateHiddenSections(0, newCount-1);
2004     }
2005 }
2006
2007 /*!
2008     \internal
2009 */
2010
2011 void QHeaderView::initializeSections(int start, int end)
2012 {
2013     Q_D(QHeaderView);
2014
2015     Q_ASSERT(start >= 0);
2016     Q_ASSERT(end >= 0);
2017
2018     d->invalidateCachedSizeHint();
2019     int oldCount = d->sectionCount();
2020
2021     if (end + 1 < d->sectionCount()) {
2022         int newCount = end + 1;
2023         d->removeSectionsFromSectionItems(newCount, d->sectionCount() - 1);
2024         if (!d->hiddenSectionSize.isEmpty()) {
2025             if (oldCount - newCount > d->hiddenSectionSize.count()) {
2026                 for (int i = end + 1; i < d->sectionCount(); ++i)
2027                     d->hiddenSectionSize.remove(i);
2028             } else {
2029                 QHash<int, int>::iterator it = d->hiddenSectionSize.begin();
2030                 while (it != d->hiddenSectionSize.end()) {
2031                     if (it.key() > end)
2032                         it = d->hiddenSectionSize.erase(it);
2033                     else
2034                         ++it;
2035                 }
2036             }
2037         }
2038     }
2039
2040     int newSectionCount = end + 1;
2041
2042     if (!d->logicalIndices.isEmpty()) {
2043         if (oldCount <= newSectionCount) {
2044             d->logicalIndices.resize(newSectionCount);
2045             d->visualIndices.resize(newSectionCount);
2046             for (int i = oldCount; i < newSectionCount; ++i) {
2047                 d->logicalIndices[i] = i;
2048                 d->visualIndices[i] = i;
2049             }
2050         } else {
2051             int j = 0;
2052             for (int i = 0; i < oldCount; ++i) {
2053                 int v = d->logicalIndices.at(i);
2054                 if (v < newSectionCount) {
2055                     d->logicalIndices[j] = v;
2056                     d->visualIndices[v] = j;
2057                     j++;
2058                 }
2059             }
2060             d->logicalIndices.resize(newSectionCount);
2061             d->visualIndices.resize(newSectionCount);
2062         }
2063     }
2064
2065     if (d->globalResizeMode == Stretch)
2066         d->stretchSections = newSectionCount;
2067     else if (d->globalResizeMode == ResizeToContents)
2068          d->contentsSections = newSectionCount;
2069     if (!d->sectionHidden.isEmpty())
2070         d->sectionHidden.resize(newSectionCount);
2071
2072     if (newSectionCount > oldCount)
2073         d->createSectionItems(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
2074     //Q_ASSERT(d->headerLength() == d->length);
2075
2076     if (d->sectionCount() != oldCount)
2077         emit sectionCountChanged(oldCount,  d->sectionCount());
2078     d->viewport->update();
2079 }
2080
2081 /*!
2082   \reimp
2083 */
2084
2085 void QHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &old)
2086 {
2087     Q_D(QHeaderView);
2088
2089     if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
2090         if (old.isValid() && old.parent() == d->root)
2091             d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
2092                                     sectionSize(old.column()), d->viewport->height()));
2093         if (current.isValid() && current.parent() == d->root)
2094             d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
2095                                     sectionSize(current.column()), d->viewport->height()));
2096     } else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
2097         if (old.isValid() && old.parent() == d->root)
2098             d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
2099                                     d->viewport->width(), sectionSize(old.row())));
2100         if (current.isValid() && current.parent() == d->root)
2101             d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
2102                                     d->viewport->width(), sectionSize(current.row())));
2103     }
2104 }
2105
2106
2107 /*!
2108   \reimp
2109 */
2110
2111 bool QHeaderView::event(QEvent *e)
2112 {
2113     Q_D(QHeaderView);
2114     switch (e->type()) {
2115     case QEvent::HoverEnter: {
2116         QHoverEvent *he = static_cast<QHoverEvent*>(e);
2117         d->hover = logicalIndexAt(he->pos());
2118         if (d->hover != -1)
2119             updateSection(d->hover);
2120         break; }
2121     case QEvent::Leave:
2122     case QEvent::HoverLeave: {
2123         if (d->hover != -1)
2124             updateSection(d->hover);
2125         d->hover = -1;
2126         break; }
2127     case QEvent::HoverMove: {
2128         QHoverEvent *he = static_cast<QHoverEvent*>(e);
2129         int oldHover = d->hover;
2130         d->hover = logicalIndexAt(he->pos());
2131         if (d->hover != oldHover) {
2132             if (oldHover != -1)
2133                 updateSection(oldHover);
2134             if (d->hover != -1)
2135                 updateSection(d->hover);
2136         }
2137         break; }
2138     case QEvent::Timer: {
2139         QTimerEvent *te = static_cast<QTimerEvent*>(e);
2140         if (te->timerId() == d->delayedResize.timerId()) {
2141             d->delayedResize.stop();
2142             resizeSections();
2143         }
2144         break; }
2145     default:
2146         break;
2147     }
2148     return QAbstractItemView::event(e);
2149 }
2150
2151 /*!
2152   \reimp
2153 */
2154
2155 void QHeaderView::paintEvent(QPaintEvent *e)
2156 {
2157     Q_D(QHeaderView);
2158
2159     if (count() == 0)
2160         return;
2161
2162     QPainter painter(d->viewport);
2163     const QPoint offset = d->scrollDelayOffset;
2164     QRect translatedEventRect = e->rect();
2165     translatedEventRect.translate(offset);
2166
2167     int start = -1;
2168     int end = -1;
2169     if (d->orientation == Qt::Horizontal) {
2170         start = visualIndexAt(translatedEventRect.left());
2171         end = visualIndexAt(translatedEventRect.right());
2172     } else {
2173         start = visualIndexAt(translatedEventRect.top());
2174         end = visualIndexAt(translatedEventRect.bottom());
2175     }
2176
2177     if (d->reverse()) {
2178         start = (start == -1 ? count() - 1 : start);
2179         end = (end == -1 ? 0 : end);
2180     } else {
2181         start = (start == -1 ? 0 : start);
2182         end = (end == -1 ? count() - 1 : end);
2183     }
2184
2185     int tmp = start;
2186     start = qMin(start, end);
2187     end = qMax(tmp, end);
2188
2189     d->prepareSectionSelected(); // clear and resize the bit array
2190
2191     QRect currentSectionRect;
2192     int logical;
2193     const int width = d->viewport->width();
2194     const int height = d->viewport->height();
2195     for (int i = start; i <= end; ++i) {
2196         if (d->isVisualIndexHidden(i))
2197             continue;
2198         painter.save();
2199         logical = logicalIndex(i);
2200         if (d->orientation == Qt::Horizontal) {
2201             currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
2202         } else {
2203             currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
2204         }
2205         currentSectionRect.translate(offset);
2206
2207         QVariant variant = d->model->headerData(logical, d->orientation,
2208                                                 Qt::FontRole);
2209         if (variant.isValid() && variant.canConvert<QFont>()) {
2210             QFont sectionFont = qvariant_cast<QFont>(variant);
2211             painter.setFont(sectionFont);
2212         }
2213         paintSection(&painter, currentSectionRect, logical);
2214         painter.restore();
2215     }
2216
2217     QStyleOption opt;
2218     opt.init(this);
2219     // Paint the area beyond where there are indexes
2220     if (d->reverse()) {
2221         opt.state |= QStyle::State_Horizontal;
2222         if (currentSectionRect.left() > translatedEventRect.left()) {
2223             opt.rect = QRect(translatedEventRect.left(), 0,
2224                              currentSectionRect.left() - translatedEventRect.left(), height);
2225             style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2226         }
2227     } else if (currentSectionRect.right() < translatedEventRect.right()) {
2228         // paint to the right
2229         opt.state |= QStyle::State_Horizontal;
2230         opt.rect = QRect(currentSectionRect.right() + 1, 0,
2231                          translatedEventRect.right() - currentSectionRect.right(), height);
2232         style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2233     } else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
2234         // paint the bottom section
2235         opt.state &= ~QStyle::State_Horizontal;
2236         opt.rect = QRect(0, currentSectionRect.bottom() + 1,
2237                          width, height - currentSectionRect.bottom() - 1);
2238         style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2239     }
2240
2241 #if 0
2242     // ### visualize sections
2243     for (int a = 0, i = 0; i < d->sectionItems.count(); ++i) {
2244         QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
2245         if (d->orientation == Qt::Horizontal)
2246             painter.fillRect(a - d->offset, 0, d->sectionItems.at(i).size, 4, color);
2247         else
2248             painter.fillRect(0, a - d->offset, 4, d->sectionItems.at(i).size, color);
2249         a += d->sectionItems.at(i).size;
2250     }
2251
2252 #endif
2253 }
2254
2255 /*!
2256   \reimp
2257 */
2258
2259 void QHeaderView::mousePressEvent(QMouseEvent *e)
2260 {
2261     Q_D(QHeaderView);
2262     if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
2263         return;
2264     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2265     int handle = d->sectionHandleAt(pos);
2266     d->originalSize = -1; // clear the stored original size
2267     if (handle == -1) {
2268         d->pressed = logicalIndexAt(pos);
2269         if (d->clickableSections)
2270             emit sectionPressed(d->pressed);
2271         if (d->movableSections) {
2272             d->section = d->target = d->pressed;
2273             if (d->section == -1)
2274                 return;
2275             d->state = QHeaderViewPrivate::MoveSection;
2276             d->setupSectionIndicator(d->section, pos);
2277         } else if (d->clickableSections && d->pressed != -1) {
2278             updateSection(d->pressed);
2279             d->state = QHeaderViewPrivate::SelectSections;
2280         }
2281     } else if (sectionResizeMode(handle) == Interactive) {
2282         d->originalSize = sectionSize(handle);
2283         d->state = QHeaderViewPrivate::ResizeSection;
2284         d->section = handle;
2285         d->preventCursorChangeInSetOffset = false;
2286     }
2287
2288     d->firstPos = pos;
2289     d->lastPos = pos;
2290
2291     d->clearCascadingSections();
2292 }
2293
2294 /*!
2295   \reimp
2296 */
2297
2298 void QHeaderView::mouseMoveEvent(QMouseEvent *e)
2299 {
2300     Q_D(QHeaderView);
2301     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2302     if (pos < 0)
2303         return;
2304     if (e->buttons() == Qt::NoButton) {
2305 #if !defined(Q_WS_MAC)
2306         // Under Cocoa, when the mouse button is released, may include an extra
2307         // simulated mouse moved event. The state of the buttons when this event
2308         // is generated is already "no button" and the code below gets executed
2309         // just before the mouseReleaseEvent and resets the state. This prevents
2310         // column dragging from working. So this code is disabled under Cocoa.
2311         d->state = QHeaderViewPrivate::NoState;
2312         d->pressed = -1;
2313 #endif
2314     }
2315     switch (d->state) {
2316         case QHeaderViewPrivate::ResizeSection: {
2317             Q_ASSERT(d->originalSize != -1);
2318             if (d->cascadingResizing) {
2319                 int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
2320                 int visual = visualIndex(d->section);
2321                 d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
2322             } else {
2323                 int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
2324                 resizeSection(d->section, qMax(d->originalSize + delta, minimumSectionSize()));
2325             }
2326             d->lastPos = pos;
2327             return;
2328         }
2329         case QHeaderViewPrivate::MoveSection: {
2330             if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
2331                 || !d->sectionIndicator->isHidden()) {
2332                 int visual = visualIndexAt(pos);
2333                 if (visual == -1)
2334                     return;
2335                 int posThreshold = d->headerSectionPosition(visual) + d->headerSectionSize(visual) / 2;
2336                 int moving = visualIndex(d->section);
2337                 if (visual < moving) {
2338                     if (pos < posThreshold)
2339                         d->target = d->logicalIndex(visual);
2340                     else
2341                         d->target = d->logicalIndex(visual + 1);
2342                 } else if (visual > moving) {
2343                     if (pos > posThreshold)
2344                         d->target = d->logicalIndex(visual);
2345                     else
2346                         d->target = d->logicalIndex(visual - 1);
2347                 } else {
2348                     d->target = d->section;
2349                 }
2350                 d->updateSectionIndicator(d->section, pos);
2351             }
2352             return;
2353         }
2354         case QHeaderViewPrivate::SelectSections: {
2355             int logical = logicalIndexAt(pos);
2356             if (logical == d->pressed)
2357                 return; // nothing to do
2358             else if (d->pressed != -1)
2359                 updateSection(d->pressed);
2360             d->pressed = logical;
2361             if (d->clickableSections && logical != -1) {
2362                 emit sectionEntered(d->pressed);
2363                 updateSection(d->pressed);
2364             }
2365             return;
2366         }
2367         case QHeaderViewPrivate::NoState: {
2368 #ifndef QT_NO_CURSOR
2369             int handle = d->sectionHandleAt(pos);
2370             bool hasCursor = testAttribute(Qt::WA_SetCursor);
2371             if (handle != -1 && (sectionResizeMode(handle) == Interactive)) {
2372                 if (!hasCursor)
2373                     setCursor(d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
2374             } else if (hasCursor) {
2375                 unsetCursor();
2376             }
2377 #endif
2378             return;
2379         }
2380         default:
2381             break;
2382     }
2383 }
2384
2385 /*!
2386   \reimp
2387 */
2388
2389 void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
2390 {
2391     Q_D(QHeaderView);
2392     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2393     switch (d->state) {
2394     case QHeaderViewPrivate::MoveSection:
2395         if (!d->sectionIndicator->isHidden()) { // moving
2396             int from = visualIndex(d->section);
2397             Q_ASSERT(from != -1);
2398             int to = visualIndex(d->target);
2399             Q_ASSERT(to != -1);
2400             moveSection(from, to);
2401             d->section = d->target = -1;
2402             d->updateSectionIndicator(d->section, pos);
2403             break;
2404         } // not moving
2405     case QHeaderViewPrivate::SelectSections:
2406         if (!d->clickableSections) {
2407             int section = logicalIndexAt(pos);
2408             updateSection(section);
2409         }
2410         // fall through
2411     case QHeaderViewPrivate::NoState:
2412         if (d->clickableSections) {
2413             int section = logicalIndexAt(pos);
2414             if (section != -1 && section == d->pressed) {
2415                 d->flipSortIndicator(section);
2416                 emit sectionClicked(section);
2417             }
2418             if (d->pressed != -1)
2419                 updateSection(d->pressed);
2420         }
2421         break;
2422     case QHeaderViewPrivate::ResizeSection:
2423         d->originalSize = -1;
2424         d->clearCascadingSections();
2425         break;
2426     default:
2427         break;
2428     }
2429     d->state = QHeaderViewPrivate::NoState;
2430     d->pressed = -1;
2431 }
2432
2433 /*!
2434   \reimp
2435 */
2436
2437 void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
2438 {
2439     Q_D(QHeaderView);
2440     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2441     int handle = d->sectionHandleAt(pos);
2442     if (handle > -1 && sectionResizeMode(handle) == Interactive) {
2443         emit sectionHandleDoubleClicked(handle);
2444 #ifndef QT_NO_CURSOR
2445         Qt::CursorShape splitCursor = (d->orientation == Qt::Horizontal)
2446                                       ? Qt::SplitHCursor : Qt::SplitVCursor;
2447         if (cursor().shape() == splitCursor) {
2448             // signal handlers may have changed the section size
2449             handle = d->sectionHandleAt(pos);
2450             if (!(handle > -1 && sectionResizeMode(handle) == Interactive))
2451                 setCursor(Qt::ArrowCursor);
2452         }
2453 #endif
2454     } else {
2455         emit sectionDoubleClicked(logicalIndexAt(e->pos()));
2456     }
2457 }
2458
2459 /*!
2460   \reimp
2461 */
2462
2463 bool QHeaderView::viewportEvent(QEvent *e)
2464 {
2465     Q_D(QHeaderView);
2466     switch (e->type()) {
2467 #ifndef QT_NO_TOOLTIP
2468     case QEvent::ToolTip: {
2469         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2470         int logical = logicalIndexAt(he->pos());
2471         if (logical != -1) {
2472             QVariant variant = d->model->headerData(logical, d->orientation, Qt::ToolTipRole);
2473             if (variant.isValid()) {
2474                 QToolTip::showText(he->globalPos(), variant.toString(), this);
2475                 return true;
2476             }
2477         }
2478         break; }
2479 #endif
2480 #ifndef QT_NO_WHATSTHIS
2481     case QEvent::QueryWhatsThis: {
2482         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2483         int logical = logicalIndexAt(he->pos());
2484         if (logical != -1
2485             && d->model->headerData(logical, d->orientation, Qt::WhatsThisRole).isValid())
2486             return true;
2487         break; }
2488     case QEvent::WhatsThis: {
2489         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2490         int logical = logicalIndexAt(he->pos());
2491         if (logical != -1) {
2492              QVariant whatsthis = d->model->headerData(logical, d->orientation,
2493                                                       Qt::WhatsThisRole);
2494              if (whatsthis.isValid()) {
2495                  QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
2496                  return true;
2497              }
2498         }
2499         break; }
2500 #endif // QT_NO_WHATSTHIS
2501 #ifndef QT_NO_STATUSTIP
2502     case QEvent::StatusTip: {
2503         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2504         int logical = logicalIndexAt(he->pos());
2505         if (logical != -1) {
2506             QString statustip = d->model->headerData(logical, d->orientation,
2507                                                     Qt::StatusTipRole).toString();
2508             if (!statustip.isEmpty())
2509                 setStatusTip(statustip);
2510         }
2511         return true; }
2512 #endif // QT_NO_STATUSTIP
2513     case QEvent::Hide:
2514     case QEvent::Show:
2515     case QEvent::FontChange:
2516     case QEvent::StyleChange:{
2517         QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea *>(parentWidget());
2518         if (parent && parent->isVisible()) // Only resize if we have a visible parent
2519             resizeSections();
2520         emit geometriesChanged();
2521         break;}
2522     case QEvent::ContextMenu: {
2523         d->state = QHeaderViewPrivate::NoState;
2524         d->pressed = d->section = d->target = -1;
2525         d->updateSectionIndicator(d->section, -1);
2526         break; }
2527     case QEvent::Wheel: {
2528         QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea *>(parentWidget());
2529         if (asa)
2530             return QApplication::sendEvent(asa->viewport(), e);
2531         break; }
2532     default:
2533         break;
2534     }
2535     return QAbstractItemView::viewportEvent(e);
2536 }
2537
2538 /*!
2539     Paints the section specified by the given \a logicalIndex, using the given
2540     \a painter and \a rect.
2541
2542     Normally, you do not have to call this function.
2543 */
2544
2545 void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
2546 {
2547     Q_D(const QHeaderView);
2548     if (!rect.isValid())
2549         return;
2550     // get the state of the section
2551     QStyleOptionHeader opt;
2552     initStyleOption(&opt);
2553     QStyle::State state = QStyle::State_None;
2554     if (isEnabled())
2555         state |= QStyle::State_Enabled;
2556     if (window()->isActiveWindow())
2557         state |= QStyle::State_Active;
2558     if (d->clickableSections) {
2559         if (logicalIndex == d->hover)
2560             state |= QStyle::State_MouseOver;
2561         if (logicalIndex == d->pressed)
2562             state |= QStyle::State_Sunken;
2563         else if (d->highlightSelected) {
2564             if (d->sectionIntersectsSelection(logicalIndex))
2565                 state |= QStyle::State_On;
2566             if (d->isSectionSelected(logicalIndex))
2567                 state |= QStyle::State_Sunken;
2568         }
2569
2570     }
2571     if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
2572         opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
2573                             ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
2574
2575     // setup the style options structure
2576     QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
2577                                                   Qt::TextAlignmentRole);
2578     opt.rect = rect;
2579     opt.section = logicalIndex;
2580     opt.state |= state;
2581     opt.textAlignment = Qt::Alignment(textAlignment.isValid()
2582                                       ? Qt::Alignment(textAlignment.toInt())
2583                                       : d->defaultAlignment);
2584
2585     opt.iconAlignment = Qt::AlignVCenter;
2586     opt.text = d->model->headerData(logicalIndex, d->orientation,
2587                                     Qt::DisplayRole).toString();
2588     if (d->textElideMode != Qt::ElideNone)
2589         opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4);
2590
2591     QVariant variant = d->model->headerData(logicalIndex, d->orientation,
2592                                     Qt::DecorationRole);
2593     opt.icon = qvariant_cast<QIcon>(variant);
2594     if (opt.icon.isNull())
2595         opt.icon = qvariant_cast<QPixmap>(variant);
2596     QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
2597                                                     Qt::ForegroundRole);
2598     if (foregroundBrush.canConvert<QBrush>())
2599         opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
2600
2601     QPointF oldBO = painter->brushOrigin();
2602     QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
2603                                                     Qt::BackgroundRole);
2604     if (backgroundBrush.canConvert<QBrush>()) {
2605         opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
2606         opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
2607         painter->setBrushOrigin(opt.rect.topLeft());
2608     }
2609
2610     // the section position
2611     int visual = visualIndex(logicalIndex);
2612     Q_ASSERT(visual != -1);
2613     if (count() == 1)
2614         opt.position = QStyleOptionHeader::OnlyOneSection;
2615     else if (visual == 0)
2616         opt.position = QStyleOptionHeader::Beginning;
2617     else if (visual == count() - 1)
2618         opt.position = QStyleOptionHeader::End;
2619     else
2620         opt.position = QStyleOptionHeader::Middle;
2621     opt.orientation = d->orientation;
2622     // the selected position
2623     bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
2624     bool nextSelected =  d->isSectionSelected(this->logicalIndex(visual + 1));
2625     if (previousSelected && nextSelected)
2626         opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
2627     else if (previousSelected)
2628         opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
2629     else if (nextSelected)
2630         opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
2631     else
2632         opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
2633     // draw the section
2634     style()->drawControl(QStyle::CE_Header, &opt, painter, this);
2635
2636     painter->setBrushOrigin(oldBO);
2637 }
2638
2639 /*!
2640     Returns the size of the contents of the section specified by the given
2641     \a logicalIndex.
2642
2643     \sa defaultSectionSize()
2644 */
2645
2646 QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
2647 {
2648     Q_D(const QHeaderView);
2649     Q_ASSERT(logicalIndex >= 0);
2650
2651     ensurePolished();
2652
2653     // use SizeHintRole
2654     QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
2655     if (variant.isValid())
2656         return qvariant_cast<QSize>(variant);
2657
2658     // otherwise use the contents
2659     QStyleOptionHeader opt;
2660     initStyleOption(&opt);
2661     opt.section = logicalIndex;
2662     QVariant var = d->model->headerData(logicalIndex, d->orientation,
2663                                             Qt::FontRole);
2664     QFont fnt;
2665     if (var.isValid() && var.canConvert<QFont>())
2666         fnt = qvariant_cast<QFont>(var);
2667     else
2668         fnt = font();
2669     fnt.setBold(true);
2670     opt.fontMetrics = QFontMetrics(fnt);
2671     opt.text = d->model->headerData(logicalIndex, d->orientation,
2672                                     Qt::DisplayRole).toString();
2673     variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole);
2674     opt.icon = qvariant_cast<QIcon>(variant);
2675     if (opt.icon.isNull())
2676         opt.icon = qvariant_cast<QPixmap>(variant);
2677     QSize size = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
2678     if (isSortIndicatorShown()) {
2679         int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, &opt, this);
2680         if (d->orientation == Qt::Horizontal)
2681             size.rwidth() += size.height() + margin;
2682         else
2683             size.rheight() += size.width() + margin;
2684     }
2685     return size;
2686 }
2687
2688 /*!
2689     Returns the horizontal offset of the header. This is 0 for vertical
2690     headers.
2691
2692     \sa offset()
2693 */
2694
2695 int QHeaderView::horizontalOffset() const
2696 {
2697     Q_D(const QHeaderView);
2698     if (d->orientation == Qt::Horizontal)
2699         return d->offset;
2700     return 0;
2701 }
2702
2703 /*!
2704     Returns the vertical offset of the header. This is 0 for horizontal
2705     headers.
2706
2707     \sa offset()
2708 */
2709
2710 int QHeaderView::verticalOffset() const
2711 {
2712     Q_D(const QHeaderView);
2713     if (d->orientation == Qt::Vertical)
2714         return d->offset;
2715     return 0;
2716 }
2717
2718 /*!
2719     \reimp
2720     \internal
2721 */
2722
2723 void QHeaderView::updateGeometries()
2724 {
2725     Q_D(QHeaderView);
2726     d->layoutChildren();
2727     if (d->hasAutoResizeSections())
2728         d->doDelayedResizeSections();
2729 }
2730
2731 /*!
2732     \reimp
2733     \internal
2734 */
2735
2736 void QHeaderView::scrollContentsBy(int dx, int dy)
2737 {
2738     Q_D(QHeaderView);
2739     d->scrollDirtyRegion(dx, dy);
2740 }
2741
2742 /*!
2743     \reimp
2744     \internal
2745 */
2746 void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &)
2747 {
2748     Q_D(QHeaderView);
2749     d->invalidateCachedSizeHint();
2750     if (d->hasAutoResizeSections()) {
2751         bool resizeRequired = d->globalResizeMode == ResizeToContents;
2752         int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row();
2753         int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row();
2754         for (int i = first; i <= last && !resizeRequired; ++i)
2755             resizeRequired = (sectionResizeMode(i) == ResizeToContents);
2756         if (resizeRequired)
2757             d->doDelayedResizeSections();
2758     }
2759 }
2760
2761 /*!
2762     \reimp
2763     \internal
2764
2765     Empty implementation because the header doesn't show QModelIndex items.
2766 */
2767 void QHeaderView::rowsInserted(const QModelIndex &, int, int)
2768 {
2769     // do nothing
2770 }
2771
2772 /*!
2773     \reimp
2774     \internal
2775
2776     Empty implementation because the header doesn't show QModelIndex items.
2777 */
2778
2779 QRect QHeaderView::visualRect(const QModelIndex &) const
2780 {
2781     return QRect();
2782 }
2783
2784 /*!
2785     \reimp
2786     \internal
2787
2788     Empty implementation because the header doesn't show QModelIndex items.
2789 */
2790
2791 void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
2792 {
2793     // do nothing - the header only displays sections
2794 }
2795
2796 /*!
2797     \reimp
2798     \internal
2799
2800     Empty implementation because the header doesn't show QModelIndex items.
2801 */
2802
2803 QModelIndex QHeaderView::indexAt(const QPoint &) const
2804 {
2805     return QModelIndex();
2806 }
2807
2808 /*!
2809     \reimp
2810     \internal
2811
2812     Empty implementation because the header doesn't show QModelIndex items.
2813 */
2814
2815 bool QHeaderView::isIndexHidden(const QModelIndex &) const
2816 {
2817     return true; // the header view has no items, just sections
2818 }
2819
2820 /*!
2821     \reimp
2822     \internal
2823
2824     Empty implementation because the header doesn't show QModelIndex items.
2825 */
2826
2827 QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
2828 {
2829     return QModelIndex();
2830 }
2831
2832 /*!
2833     \reimp
2834
2835     Selects the items in the given \a rect according to the specified
2836     \a flags.
2837
2838     The base class implementation does nothing.
2839 */
2840
2841 void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
2842 {
2843     // do nothing
2844 }
2845
2846 /*!
2847     \internal
2848 */
2849
2850 QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
2851 {
2852     Q_D(const QHeaderView);
2853     const int max = d->modelSectionCount();
2854     if (d->orientation == Qt::Horizontal) {
2855         int left = max;
2856         int right = 0;
2857         int rangeLeft, rangeRight;
2858
2859         for (int i = 0; i < selection.count(); ++i) {
2860             QItemSelectionRange r = selection.at(i);
2861             if (r.parent().isValid() || !r.isValid())
2862                 continue; // we only know about toplevel items and we don't want invalid ranges
2863             // FIXME an item inside the range may be the leftmost or rightmost
2864             rangeLeft = visualIndex(r.left());
2865             if (rangeLeft == -1) // in some cases users may change the selections
2866                 continue;        // before we have a chance to do the layout
2867             rangeRight = visualIndex(r.right());
2868             if (rangeRight == -1) // in some cases users may change the selections
2869                 continue;         // before we have a chance to do the layout
2870             if (rangeLeft < left)
2871                 left = rangeLeft;
2872             if (rangeRight > right)
2873                 right = rangeRight;
2874         }
2875
2876         int logicalLeft = logicalIndex(left);
2877         int logicalRight = logicalIndex(right);
2878
2879         if (logicalLeft < 0  || logicalLeft >= count() ||
2880             logicalRight < 0 || logicalRight >= count())
2881             return QRegion();
2882
2883         int leftPos = sectionViewportPosition(logicalLeft);
2884         int rightPos = sectionViewportPosition(logicalRight);
2885         rightPos += sectionSize(logicalRight);
2886         return QRect(leftPos, 0, rightPos - leftPos, height());
2887     }
2888     // orientation() == Qt::Vertical
2889     int top = max;
2890     int bottom = 0;
2891     int rangeTop, rangeBottom;
2892
2893     for (int i = 0; i < selection.count(); ++i) {
2894         QItemSelectionRange r = selection.at(i);
2895         if (r.parent().isValid() || !r.isValid())
2896             continue; // we only know about toplevel items
2897         // FIXME an item inside the range may be the leftmost or rightmost
2898         rangeTop = visualIndex(r.top());
2899         if (rangeTop == -1) // in some cases users may change the selections
2900             continue;       // before we have a chance to do the layout
2901         rangeBottom = visualIndex(r.bottom());
2902         if (rangeBottom == -1) // in some cases users may change the selections
2903             continue;          // before we have a chance to do the layout
2904         if (rangeTop < top)
2905             top = rangeTop;
2906         if (rangeBottom > bottom)
2907             bottom = rangeBottom;
2908     }
2909
2910     int logicalTop = logicalIndex(top);
2911     int logicalBottom = logicalIndex(bottom);
2912
2913     if (logicalTop == -1 || logicalBottom == -1)
2914         return QRect();
2915
2916     int topPos = sectionViewportPosition(logicalTop);
2917     int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
2918
2919     return QRect(0, topPos, width(), bottomPos - topPos);
2920 }
2921
2922
2923 // private implementation
2924
2925 int QHeaderViewPrivate::sectionHandleAt(int position)
2926 {
2927     Q_Q(QHeaderView);
2928     int visual = q->visualIndexAt(position);
2929     if (visual == -1)
2930         return -1;
2931     int log = logicalIndex(visual);
2932     int pos = q->sectionViewportPosition(log);
2933     int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, q);
2934
2935     bool atLeft = position < pos + grip;
2936     bool atRight = (position > pos + q->sectionSize(log) - grip);
2937     if (reverse())
2938         qSwap(atLeft, atRight);
2939
2940     if (atLeft) {
2941         //grip at the beginning of the section
2942         while(visual > -1) {
2943             int logical = q->logicalIndex(--visual);
2944             if (!q->isSectionHidden(logical))
2945                 return logical;
2946         }
2947     } else if (atRight) {
2948         //grip at the end of the section
2949         return log;
2950     }
2951     return -1;
2952 }
2953
2954 void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
2955 {
2956     Q_Q(QHeaderView);
2957     if (!sectionIndicator) {
2958         sectionIndicator = new QLabel(viewport);
2959     }
2960
2961     int w, h;
2962     int p = q->sectionViewportPosition(section);
2963     if (orientation == Qt::Horizontal) {
2964         w = q->sectionSize(section);
2965         h = viewport->height();
2966     } else {
2967         w = viewport->width();
2968         h = q->sectionSize(section);
2969     }
2970     sectionIndicator->resize(w, h);
2971
2972     QPixmap pm(w, h);
2973     pm.fill(QColor(0, 0, 0, 45));
2974     QRect rect(0, 0, w, h);
2975
2976     QPainter painter(&pm);
2977     painter.setOpacity(0.75);
2978     q->paintSection(&painter, rect, section);
2979     painter.end();
2980
2981     sectionIndicator->setPixmap(pm);