Auto-scroll while selecting entire rows/columns did not work
[qt:qt.git] / src / gui / itemviews / qheaderview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 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::SectionSpan &span)
71 {
72     span.write(out);
73     return out;
74 }
75
76 QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionSpan &span)
77 {
78     span.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
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 setMovable(). It can
124     be made clickable with setClickable(), and has resizing behavior in
125     accordance with setResizeMode().
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() and sectionAutoResize().
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     setResizeMode().
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() 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 setClickable()
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 setClickable(), 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 setClickable(), 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 setClickable()
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 setClickable()
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::sectionAutoResize(int logicalIndex,
286     QHeaderView::ResizeMode mode)
287
288     This signal is emitted when a section is automatically resized. The
289     section's logical index is specified by \a logicalIndex, and the resize
290     mode by \a mode.
291
292     \sa setResizeMode(), stretchLastSection()
293 */
294 // ### Qt 5: change to sectionAutoResized()
295
296 /*!
297     \fn void QHeaderView::geometriesChanged()
298     \since 4.2
299
300     This signal is emitted when the header's geometries have changed.
301 */
302
303 /*!
304     \property QHeaderView::highlightSections
305     \brief whether the sections containing selected items are highlighted
306
307     By default, this property is false.
308 */
309
310 /*!
311     Creates a new generic header with the given \a orientation and \a parent.
312 */
313 QHeaderView::QHeaderView(Qt::Orientation orientation, QWidget *parent)
314     : QAbstractItemView(*new QHeaderViewPrivate, parent)
315 {
316     Q_D(QHeaderView);
317     d->setDefaultValues(orientation);
318     initialize();
319 }
320
321 /*!
322   \internal
323 */
324 QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
325                          Qt::Orientation orientation, QWidget *parent)
326     : QAbstractItemView(dd, parent)
327 {
328     Q_D(QHeaderView);
329     d->setDefaultValues(orientation);
330     initialize();
331 }
332
333 /*!
334   Destroys the header.
335 */
336
337 QHeaderView::~QHeaderView()
338 {
339 }
340
341 /*!
342   \internal
343 */
344 void QHeaderView::initialize()
345 {
346     Q_D(QHeaderView);
347     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
348     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
349     setFrameStyle(NoFrame);
350     setFocusPolicy(Qt::NoFocus);
351     d->viewport->setMouseTracking(true);
352     d->viewport->setBackgroundRole(QPalette::Button);
353     d->textElideMode = Qt::ElideNone;
354     delete d->itemDelegate;
355 }
356
357 /*!
358   \reimp
359 */
360 void QHeaderView::setModel(QAbstractItemModel *model)
361 {
362     if (model == this->model())
363         return;
364     Q_D(QHeaderView);
365     if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
366     if (d->orientation == Qt::Horizontal) {
367         QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
368                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
369         QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
370                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
371         QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
372                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
373     } else {
374         QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
375                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
376         QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
377                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
378         QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
379                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
380     }
381     QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
382                         this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
383         QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
384                             this, SLOT(_q_layoutAboutToBeChanged()));
385     }
386
387     if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
388         if (d->orientation == Qt::Horizontal) {
389             QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
390                              this, SLOT(sectionsInserted(QModelIndex,int,int)));
391             QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
392                 this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
393             QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
394                 this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
395         } else {
396             QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
397                              this, SLOT(sectionsInserted(QModelIndex,int,int)));
398             QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
399                              this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
400             QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
401                              this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
402         }
403         QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
404                          this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
405         QObject::connect(model, SIGNAL(layoutAboutToBeChanged()),
406                          this, SLOT(_q_layoutAboutToBeChanged()));
407     }
408
409     d->state = QHeaderViewPrivate::NoClear;
410     QAbstractItemView::setModel(model);
411     d->state = QHeaderViewPrivate::NoState;
412
413     // Users want to set sizes and modes before the widget is shown.
414     // Thus, we have to initialize when the model is set,
415     // and not lazily like we do in the other views.
416     initializeSections();
417 }
418
419 /*!
420     Returns the orientation of the header.
421
422     \sa Qt::Orientation
423 */
424
425 Qt::Orientation QHeaderView::orientation() const
426 {
427     Q_D(const QHeaderView);
428     return d->orientation;
429 }
430
431 /*!
432     Returns the offset of the header: this is the header's left-most (or
433     top-most for vertical headers) visible pixel.
434
435     \sa setOffset()
436 */
437
438 int QHeaderView::offset() const
439 {
440     Q_D(const QHeaderView);
441     return d->offset;
442 }
443
444 /*!
445     \fn void QHeaderView::setOffset(int offset)
446
447     Sets the header's offset to \a offset.
448
449     \sa offset(), length()
450 */
451
452 void QHeaderView::setOffset(int newOffset)
453 {
454     Q_D(QHeaderView);
455     if (d->offset == (int)newOffset)
456         return;
457     int ndelta = d->offset - newOffset;
458     d->offset = newOffset;
459     if (d->orientation == Qt::Horizontal)
460         d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
461     else
462         d->viewport->scroll(0, ndelta);
463     if (d->state == QHeaderViewPrivate::ResizeSection) {
464         QPoint cursorPos = QCursor::pos();
465         if (d->orientation == Qt::Horizontal)
466             QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
467         else
468             QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
469         d->firstPos += ndelta;
470         d->lastPos += ndelta;
471     }
472 }
473
474 /*!
475     \since 4.2
476     Sets the offset to the start of the section at the given \a visualIndex.
477
478     \sa setOffset(), sectionPosition()
479 */
480 void QHeaderView::setOffsetToSectionPosition(int visualIndex)
481 {
482     Q_D(QHeaderView);
483     if (visualIndex > -1 && visualIndex < d->sectionCount) {
484         int position = d->headerSectionPosition(d->adjustedVisualIndex(visualIndex));
485         setOffset(position);
486     }
487 }
488
489 /*!
490     \since 4.2
491     Sets the offset to make the last section visible.
492
493     \sa setOffset(), sectionPosition(), setOffsetToSectionPosition()
494 */
495 void QHeaderView::setOffsetToLastSection()
496 {
497     Q_D(const QHeaderView);
498     int size = (d->orientation == Qt::Horizontal ? viewport()->width() : viewport()->height());
499     int position = length() - size;
500     setOffset(position);
501 }
502
503 /*!
504     Returns the length along the orientation of the header.
505
506     \sa sizeHint(), setResizeMode(), offset()
507 */
508
509 int QHeaderView::length() const
510 {
511     Q_D(const QHeaderView);
512     d->executePostedLayout();
513     d->executePostedResize();
514     //Q_ASSERT(d->headerLength() == d->length);
515     return d->length;
516 }
517
518 /*!
519     Returns a suitable size hint for this header.
520
521     \sa sectionSizeHint()
522 */
523
524 QSize QHeaderView::sizeHint() const
525 {
526     Q_D(const QHeaderView);
527     if (d->cachedSizeHint.isValid())
528         return d->cachedSizeHint;
529     d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint
530     const int sectionCount = count();
531
532     // get size hint for the first n sections
533     int i = 0;
534     for (int checked = 0; checked < 100 && i < sectionCount; ++i) {
535         if (isSectionHidden(i))
536             continue;
537         checked++;
538         QSize hint = sectionSizeFromContents(i);
539         d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
540     }
541     // get size hint for the last n sections
542     i = qMax(i, sectionCount - 100 );
543     for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) {
544         if (isSectionHidden(j))
545             continue;
546         checked++;
547         QSize hint = sectionSizeFromContents(j);
548         d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
549     }
550     return d->cachedSizeHint;
551 }
552
553 /*!
554     Returns a suitable size hint for the section specified by \a logicalIndex.
555
556     \sa sizeHint(), defaultSectionSize(), minimumSectionSize(),
557     Qt::SizeHintRole
558 */
559
560 int QHeaderView::sectionSizeHint(int logicalIndex) const
561 {
562     Q_D(const QHeaderView);
563     if (isSectionHidden(logicalIndex))
564         return 0;
565     if (logicalIndex < 0 || logicalIndex >= count())
566         return -1;
567     QSize size;
568     QVariant value = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
569     if (value.isValid())
570         size = qvariant_cast<QSize>(value);
571     else
572         size = sectionSizeFromContents(logicalIndex);
573     int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
574     return qMax(minimumSectionSize(), hint);
575 }
576
577 /*!
578     Returns the visual index of the section that covers the given \a position
579     in the viewport.
580
581     \sa logicalIndexAt()
582 */
583
584 int QHeaderView::visualIndexAt(int position) const
585 {
586     Q_D(const QHeaderView);
587     int vposition = position;
588     d->executePostedLayout();
589     d->executePostedResize();
590     const int count = d->sectionCount;
591     if (count < 1)
592         return -1;
593
594     if (d->reverse())
595         vposition = d->viewport->width() - vposition;
596     vposition += d->offset;
597
598     if (vposition > d->length)
599         return -1;
600     int visual = d->headerVisualIndexAt(vposition);
601     if (visual < 0)
602         return -1;
603
604     while (d->isVisualIndexHidden(visual)){
605         ++visual;
606         if (visual >= count)
607             return -1;
608     }
609     return visual;
610 }
611
612 /*!
613     Returns the section that covers the given \a position in the viewport.
614
615     \sa visualIndexAt(), isSectionHidden()
616 */
617
618 int QHeaderView::logicalIndexAt(int position) const
619 {
620     const int visual = visualIndexAt(position);
621     if (visual > -1)
622         return logicalIndex(visual);
623     return -1;
624 }
625
626 /*!
627     Returns the width (or height for vertical headers) of the given
628     \a logicalIndex.
629
630     \sa length(), setResizeMode(), defaultSectionSize()
631 */
632
633 int QHeaderView::sectionSize(int logicalIndex) const
634 {
635     Q_D(const QHeaderView);
636     if (isSectionHidden(logicalIndex))
637         return 0;
638     if (logicalIndex < 0 || logicalIndex >= count())
639         return 0;
640     int visual = visualIndex(logicalIndex);
641     if (visual == -1)
642         return 0;
643     d->executePostedResize();
644     return d->headerSectionSize(visual);
645 }
646
647 /*!
648
649     Returns the section position of the given \a logicalIndex, or -1
650     if the section is hidden. The position is measured in pixels from
651     the first visible item's top-left corner to the top-left corner of
652     the item with \a logicalIndex. The measurement is along the x-axis
653     for horizontal headers and along the y-axis for vertical headers.
654
655     \sa sectionViewportPosition()
656 */
657
658 int QHeaderView::sectionPosition(int logicalIndex) const
659 {
660     Q_D(const QHeaderView);
661     int visual = visualIndex(logicalIndex);
662     // in some cases users may change the selections
663     // before we have a chance to do the layout
664     if (visual == -1)
665         return -1;
666     d->executePostedResize();
667     return d->headerSectionPosition(visual);
668 }
669
670 /*!
671     Returns the section viewport position of the given \a logicalIndex.
672
673     If the section is hidden, the return value is undefined.
674
675     \sa sectionPosition(), isSectionHidden()
676 */
677
678 int QHeaderView::sectionViewportPosition(int logicalIndex) const
679 {
680     Q_D(const QHeaderView);
681     if (logicalIndex >= count())
682         return -1;
683     int position = sectionPosition(logicalIndex);
684     if (position < 0)
685         return position; // the section was hidden
686     int offsetPosition = position - d->offset;
687     if (d->reverse())
688         return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
689     return offsetPosition;
690 }
691
692 /*!
693     \fn int QHeaderView::logicalIndexAt(int x, int y) const
694
695     Returns the logical index of the section at the given coordinate. If the
696     header is horizontal \a x will be used, otherwise \a y will be used to
697     find the logical index.
698 */
699
700 /*!
701     \fn int QHeaderView::logicalIndexAt(const QPoint &pos) const
702
703     Returns the logical index of the section at the position given in \a pos.
704     If the header is horizontal the x-coordinate will be used, otherwise the
705     y-coordinate will be used to find the logical index.
706
707     \sa sectionPosition()
708 */
709
710 /*!
711     Moves the section at visual index \a from to occupy visual index \a to.
712
713     \sa sectionsMoved()
714 */
715
716 void QHeaderView::moveSection(int from, int to)
717 {
718     Q_D(QHeaderView);
719
720     d->executePostedLayout();
721     if (from < 0 || from >= d->sectionCount || to < 0 || to >= d->sectionCount)
722         return;
723
724     if (from == to) {
725         int logical = logicalIndex(from);
726         Q_ASSERT(logical != -1);
727         updateSection(logical);
728         return;
729     }
730
731     if (stretchLastSection() &&  to == d->lastVisibleVisualIndex())
732         d->lastSectionSize = sectionSize(from);
733
734     //int oldHeaderLength = length(); // ### for debugging; remove later
735     d->initializeIndexMapping();
736
737     QBitArray sectionHidden = d->sectionHidden;
738     int *visualIndices = d->visualIndices.data();
739     int *logicalIndices = d->logicalIndices.data();
740     int logical = logicalIndices[from];
741     int visual = from;
742
743     int affected_count = qAbs(to - from) + 1;
744     QVarLengthArray<int> sizes(affected_count);
745     QVarLengthArray<ResizeMode> modes(affected_count);
746
747     // move sections and indices
748     if (to > from) {
749         sizes[to - from] = d->headerSectionSize(from);
750         modes[to - from] = d->headerSectionResizeMode(from);
751         while (visual < to) {
752             sizes[visual - from] = d->headerSectionSize(visual + 1);
753             modes[visual - from] = d->headerSectionResizeMode(visual + 1);
754             if (!sectionHidden.isEmpty())
755                 sectionHidden.setBit(visual, sectionHidden.testBit(visual + 1));
756             visualIndices[logicalIndices[visual + 1]] = visual;
757             logicalIndices[visual] = logicalIndices[visual + 1];
758             ++visual;
759         }
760     } else {
761         sizes[0] = d->headerSectionSize(from);
762         modes[0] = d->headerSectionResizeMode(from);
763         while (visual > to) {
764             sizes[visual - to] = d->headerSectionSize(visual - 1);
765             modes[visual - to] = d->headerSectionResizeMode(visual - 1);
766             if (!sectionHidden.isEmpty())
767                 sectionHidden.setBit(visual, sectionHidden.testBit(visual - 1));
768             visualIndices[logicalIndices[visual - 1]] = visual;
769             logicalIndices[visual] = logicalIndices[visual - 1];
770             --visual;
771         }
772     }
773     if (!sectionHidden.isEmpty()) {
774         sectionHidden.setBit(to, d->sectionHidden.testBit(from));
775         d->sectionHidden = sectionHidden;
776     }
777     visualIndices[logical] = to;
778     logicalIndices[to] = logical;
779
780     //Q_ASSERT(oldHeaderLength == length());
781     // move sizes
782     // ### check for spans of section sizes here
783     if (to > from) {
784         for (visual = from; visual <= to; ++visual) {
785             int size = sizes[visual - from];
786             ResizeMode mode = modes[visual - from];
787             d->createSectionSpan(visual, visual, size, mode);
788         }
789     } else {
790         for (visual = to; visual <= from; ++visual) {
791             int size = sizes[visual - to];
792             ResizeMode mode = modes[visual - to];
793             d->createSectionSpan(visual, visual, size, mode);
794         }
795     }
796     //Q_ASSERT(d->headerLength() == length());
797     //Q_ASSERT(oldHeaderLength == length());
798     //Q_ASSERT(d->logicalIndices.count() == d->sectionCount);
799
800     if (d->hasAutoResizeSections())
801         d->doDelayedResizeSections();
802     d->viewport->update();
803
804     emit sectionMoved(logical, from, to);
805 }
806
807 /*!
808     \since 4.2
809     Swaps the section at visual index \a first with the section at visual
810     index \a second.
811
812     \sa moveSection()
813 */
814 void QHeaderView::swapSections(int first, int second)
815 {
816     Q_D(QHeaderView);
817
818     if (first == second)
819         return;
820     d->executePostedLayout();
821     if (first < 0 || first >= d->sectionCount || second < 0 || second >= d->sectionCount)
822         return;
823
824     int firstSize = d->headerSectionSize(first);
825     ResizeMode firstMode = d->headerSectionResizeMode(first);
826     int firstLogical = d->logicalIndex(first);
827
828     int secondSize = d->headerSectionSize(second);
829     ResizeMode secondMode = d->headerSectionResizeMode(second);
830     int secondLogical = d->logicalIndex(second);
831
832     d->createSectionSpan(second, second, firstSize, firstMode);
833     d->createSectionSpan(first, first, secondSize, secondMode);
834
835     d->initializeIndexMapping();
836
837     d->visualIndices[firstLogical] = second;
838     d->logicalIndices[second] = firstLogical;
839
840     d->visualIndices[secondLogical] = first;
841     d->logicalIndices[first] = secondLogical;
842
843     if (!d->sectionHidden.isEmpty()) {
844         bool firstHidden = d->sectionHidden.testBit(first);
845         bool secondHidden = d->sectionHidden.testBit(second);
846         d->sectionHidden.setBit(first, secondHidden);
847         d->sectionHidden.setBit(second, firstHidden);
848     }
849
850     d->viewport->update();
851     emit sectionMoved(firstLogical, first, second);
852     emit sectionMoved(secondLogical, second, first);
853 }
854
855 /*!
856     \fn void QHeaderView::resizeSection(int logicalIndex, int size)
857
858     Resizes the section specified by \a logicalIndex to \a size measured in
859     pixels.
860
861     \sa sectionResized(), resizeMode(), sectionSize()
862 */
863
864 void QHeaderView::resizeSection(int logical, int size)
865 {
866     Q_D(QHeaderView);
867     if (logical < 0 || logical >= count())
868         return;
869
870     if (isSectionHidden(logical)) {
871         d->hiddenSectionSize.insert(logical, size);
872         return;
873     }
874
875     int visual = visualIndex(logical);
876     if (visual == -1)
877         return;
878
879     int oldSize = d->headerSectionSize(visual);
880     if (oldSize == size)
881         return;
882
883     d->executePostedLayout();
884     d->invalidateCachedSizeHint();
885
886     if (stretchLastSection() && visual == d->lastVisibleVisualIndex())
887         d->lastSectionSize = size;
888
889     if (size != oldSize)
890         d->createSectionSpan(visual, visual, size, d->headerSectionResizeMode(visual));
891
892     if (!updatesEnabled()) {
893         if (d->hasAutoResizeSections())
894             d->doDelayedResizeSections();
895         emit sectionResized(logical, oldSize, size);
896         return;
897     }
898
899     int w = d->viewport->width();
900     int h = d->viewport->height();
901     int pos = sectionViewportPosition(logical);
902     QRect r;
903     if (d->orientation == Qt::Horizontal)
904         if (isRightToLeft())
905             r.setRect(0, 0, pos + size, h);
906         else
907             r.setRect(pos, 0, w - pos, h);
908     else
909         r.setRect(0, pos, w, h - pos);
910
911     if (d->hasAutoResizeSections()) {
912         d->doDelayedResizeSections();
913         r = d->viewport->rect();
914     }
915     d->viewport->update(r.normalized());
916     emit sectionResized(logical, oldSize, size);
917 }
918
919 /*!
920     Resizes the sections according to the given \a mode, ignoring the current
921     resize mode.
922
923     \sa resizeMode(), sectionResized()
924 */
925
926 void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
927 {
928     Q_D(QHeaderView);
929     d->resizeSections(mode, true);
930 }
931
932 /*!
933     \fn void QHeaderView::hideSection(int logicalIndex)
934     Hides the section specified by \a logicalIndex.
935
936     \sa showSection(), isSectionHidden(), hiddenSectionCount(),
937     setSectionHidden()
938 */
939
940 /*!
941     \fn void QHeaderView::showSection(int logicalIndex)
942     Shows the section specified by \a logicalIndex.
943
944     \sa hideSection(), isSectionHidden(), hiddenSectionCount(),
945     setSectionHidden()
946 */
947
948 /*!
949     Returns true if the section specified by \a logicalIndex is explicitly
950     hidden from the user; otherwise returns false.
951
952     \sa hideSection(), showSection(), setSectionHidden(), hiddenSectionCount()
953 */
954
955 bool QHeaderView::isSectionHidden(int logicalIndex) const
956 {
957     Q_D(const QHeaderView);
958     d->executePostedLayout();
959     if (logicalIndex >= d->sectionHidden.count() || logicalIndex < 0 || logicalIndex >= d->sectionCount)
960         return false;
961     int visual = visualIndex(logicalIndex);
962     Q_ASSERT(visual != -1);
963     return d->sectionHidden.testBit(visual);
964 }
965
966 /*!
967     \since 4.1
968
969     Returns the number of sections in the header that has been hidden.
970
971     \sa setSectionHidden(), isSectionHidden()
972 */
973 int QHeaderView::hiddenSectionCount() const
974 {
975     Q_D(const QHeaderView);
976     return d->hiddenSectionSize.count();
977 }
978
979 /*!
980   If \a hide is true the section specified by \a logicalIndex is hidden;
981   otherwise the section is shown.
982
983   \sa isSectionHidden(), hiddenSectionCount()
984 */
985
986 void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
987 {
988     Q_D(QHeaderView);
989     if (logicalIndex < 0 || logicalIndex >= count())
990         return;
991
992     d->executePostedLayout();
993     int visual = visualIndex(logicalIndex);
994     Q_ASSERT(visual != -1);
995     if (hide == d->isVisualIndexHidden(visual))
996         return;
997     if (hide) {
998         int size = d->headerSectionSize(visual);
999         if (!d->hasAutoResizeSections())
1000             resizeSection(logicalIndex, 0);
1001         d->hiddenSectionSize.insert(logicalIndex, size);
1002         if (d->sectionHidden.count() < count())
1003             d->sectionHidden.resize(count());
1004         d->sectionHidden.setBit(visual, true);
1005         if (d->hasAutoResizeSections())
1006             d->doDelayedResizeSections();
1007     } else {
1008         int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
1009         d->hiddenSectionSize.remove(logicalIndex);
1010         if (d->hiddenSectionSize.isEmpty()) {
1011             d->sectionHidden.clear();
1012         } else {
1013             Q_ASSERT(visual <= d->sectionHidden.count());
1014             d->sectionHidden.setBit(visual, false);
1015         }
1016         resizeSection(logicalIndex, size);
1017     }
1018 }
1019
1020 /*!
1021     Returns the number of sections in the header.
1022
1023     \sa  sectionCountChanged(), length()
1024 */
1025
1026 int QHeaderView::count() const
1027 {
1028     Q_D(const QHeaderView);
1029     //Q_ASSERT(d->sectionCount == d->headerSectionCount());
1030     // ### this may affect the lazy layout
1031     d->executePostedLayout();
1032     return d->sectionCount;
1033 }
1034
1035 /*!
1036     Returns the visual index position of the section specified by the given
1037     \a logicalIndex, or -1 otherwise.
1038
1039     Hidden sections still have valid visual indexes.
1040
1041     \sa logicalIndex()
1042 */
1043
1044 int QHeaderView::visualIndex(int logicalIndex) const
1045 {
1046     Q_D(const QHeaderView);
1047     if (logicalIndex < 0)
1048         return -1;
1049     d->executePostedLayout();
1050     if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
1051         if (logicalIndex < d->sectionCount)
1052             return logicalIndex;
1053     } else if (logicalIndex < d->visualIndices.count()) {
1054         int visual = d->visualIndices.at(logicalIndex);
1055         Q_ASSERT(visual < d->sectionCount);
1056         return visual;
1057     }
1058     return -1;
1059 }
1060
1061 /*!
1062     Returns the logicalIndex for the section at the given \a visualIndex
1063     position, or -1 if visualIndex < 0 or visualIndex >= QHeaderView::count().
1064
1065     Note that the visualIndex is not affected by hidden sections.
1066
1067     \sa visualIndex(), sectionPosition()
1068 */
1069
1070 int QHeaderView::logicalIndex(int visualIndex) const
1071 {
1072     Q_D(const QHeaderView);
1073     if (visualIndex < 0 || visualIndex >= d->sectionCount)
1074         return -1;
1075     return d->logicalIndex(visualIndex);
1076 }
1077
1078 /*!
1079     If \a movable is true, the header may be moved by the user; otherwise it
1080     is fixed in place.
1081
1082     \sa isMovable(), sectionMoved()
1083 */
1084
1085 // ### Qt 5: change to setSectionsMovable()
1086 void QHeaderView::setMovable(bool movable)
1087 {
1088     Q_D(QHeaderView);
1089     d->movableSections = movable;
1090 }
1091
1092 /*!
1093     Returns true if the header can be moved by the user; otherwise returns
1094     false.
1095
1096     \sa setMovable()
1097 */
1098
1099 // ### Qt 5: change to sectionsMovable()
1100 bool QHeaderView::isMovable() const
1101 {
1102     Q_D(const QHeaderView);
1103     return d->movableSections;
1104 }
1105
1106 /*!
1107     If \a clickable is true, the header will respond to single clicks.
1108
1109     \sa isClickable(), sectionClicked(), sectionPressed(),
1110     setSortIndicatorShown()
1111 */
1112
1113 // ### Qt 5: change to setSectionsClickable()
1114 void QHeaderView::setClickable(bool clickable)
1115 {
1116     Q_D(QHeaderView);
1117     d->clickableSections = clickable;
1118 }
1119
1120 /*!
1121     Returns true if the header is clickable; otherwise returns false. A
1122     clickable header could be set up to allow the user to change the
1123     representation of the data in the view related to the header.
1124
1125     \sa setClickable()
1126 */
1127
1128 // ### Qt 5: change to sectionsClickable()
1129 bool QHeaderView::isClickable() const
1130 {
1131     Q_D(const QHeaderView);
1132     return d->clickableSections;
1133 }
1134
1135 void QHeaderView::setHighlightSections(bool highlight)
1136 {
1137     Q_D(QHeaderView);
1138     d->highlightSelected = highlight;
1139 }
1140
1141 bool QHeaderView::highlightSections() const
1142 {
1143     Q_D(const QHeaderView);
1144     return d->highlightSelected;
1145 }
1146
1147 /*!
1148     Sets the constraints on how the header can be resized to those described
1149     by the given \a mode.
1150
1151     \sa resizeMode(), length(), sectionResized(), sectionAutoResize()
1152 */
1153
1154 void QHeaderView::setResizeMode(ResizeMode mode)
1155 {
1156     Q_D(QHeaderView);
1157     initializeSections();
1158     d->stretchSections = (mode == Stretch ? count() : 0);
1159     d->contentsSections =  (mode == ResizeToContents ? count() : 0);
1160     d->setGlobalHeaderResizeMode(mode);
1161     if (d->hasAutoResizeSections())
1162         d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1163 }
1164
1165 /*!
1166     \overload
1167
1168     Sets the constraints on how the section specified by \a logicalIndex in
1169     the header can be resized to those described by the given \a mode. The logical
1170     index should exist at the time this function is called.
1171
1172     \note This setting will be ignored for the last section if the stretchLastSection
1173     property is set to true. This is the default for the horizontal headers provided
1174     by QTreeView.
1175
1176     \sa setStretchLastSection()
1177 */
1178
1179 // ### Qt 5: change to setSectionResizeMode()
1180 void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
1181 {
1182     Q_D(QHeaderView);
1183     int visual = visualIndex(logicalIndex);
1184     Q_ASSERT(visual != -1);
1185
1186     ResizeMode old = d->headerSectionResizeMode(visual);
1187     d->setHeaderSectionResizeMode(visual, mode);
1188
1189     if (mode == Stretch && old != Stretch)
1190         ++d->stretchSections;
1191     else if (mode == ResizeToContents && old != ResizeToContents)
1192         ++d->contentsSections;
1193     else if (mode != Stretch && old == Stretch)
1194         --d->stretchSections;
1195     else if (mode != ResizeToContents && old == ResizeToContents)
1196         --d->contentsSections;
1197
1198     if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
1199         d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
1200 }
1201
1202 /*!
1203     Returns the resize mode that applies to the section specified by the given
1204     \a logicalIndex.
1205
1206     \sa setResizeMode()
1207 */
1208
1209 QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
1210 {
1211     Q_D(const QHeaderView);
1212     int visual = visualIndex(logicalIndex);
1213     if (visual == -1)
1214         return Fixed; //the default value
1215     return d->headerSectionResizeMode(visual);
1216 }
1217
1218 /*!
1219     \since 4.1
1220
1221     Returns the number of sections that are set to resize mode stretch. In
1222     views, this can be used to see if the headerview needs to resize the
1223     sections when the view's geometry changes.
1224
1225     \sa stretchLastSection, resizeMode()
1226 */
1227
1228 int QHeaderView::stretchSectionCount() const
1229 {
1230     Q_D(const QHeaderView);
1231     return d->stretchSections;
1232 }
1233
1234 /*!
1235   \property QHeaderView::showSortIndicator
1236   \brief whether the sort indicator is shown
1237
1238   By default, this property is false.
1239
1240   \sa setClickable()
1241 */
1242
1243 void QHeaderView::setSortIndicatorShown(bool show)
1244 {
1245     Q_D(QHeaderView);
1246     if (d->sortIndicatorShown == show)
1247         return;
1248
1249     d->sortIndicatorShown = show;
1250
1251     if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
1252         return;
1253
1254     if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
1255         resizeSections();
1256
1257     d->viewport->update();
1258 }
1259
1260 bool QHeaderView::isSortIndicatorShown() const
1261 {
1262     Q_D(const QHeaderView);
1263     return d->sortIndicatorShown;
1264 }
1265
1266 /*!
1267     Sets the sort indicator for the section specified by the given
1268     \a logicalIndex in the direction specified by \a order, and removes the
1269     sort indicator from any other section that was showing it.
1270
1271     \a logicalIndex may be -1, in which case no sort indicator will be shown
1272     and the model will return to its natural, unsorted order. Note that not
1273     all models support this and may even crash in this case.
1274
1275     \sa sortIndicatorSection() sortIndicatorOrder()
1276 */
1277
1278 void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
1279 {
1280     Q_D(QHeaderView);
1281
1282     // This is so that people can set the position of the sort indicator before the fill the model
1283     int old = d->sortIndicatorSection;
1284     d->sortIndicatorSection = logicalIndex;
1285     d->sortIndicatorOrder = order;
1286
1287     if (logicalIndex >= d->sectionCount) {
1288         emit sortIndicatorChanged(logicalIndex, order);
1289         return; // nothing to do
1290     }
1291
1292     if (old != logicalIndex
1293         && ((logicalIndex >= 0 && resizeMode(logicalIndex) == ResizeToContents)
1294             || old >= d->sectionCount || (old >= 0 && resizeMode(old) == ResizeToContents))) {
1295         resizeSections();
1296         d->viewport->update();
1297     } else {
1298         if (old >= 0 && old != logicalIndex)
1299             updateSection(old);
1300         if (logicalIndex >= 0)
1301             updateSection(logicalIndex);
1302     }
1303
1304     emit sortIndicatorChanged(logicalIndex, order);
1305 }
1306
1307 /*!
1308     Returns the logical index of the section that has a sort indicator.
1309     By default this is section 0.
1310
1311     \sa setSortIndicator() sortIndicatorOrder() setSortIndicatorShown()
1312 */
1313
1314 int QHeaderView::sortIndicatorSection() const
1315 {
1316     Q_D(const QHeaderView);
1317     return d->sortIndicatorSection;
1318 }
1319
1320 /*!
1321     Returns the order for the sort indicator. If no section has a sort
1322     indicator the return value of this function is undefined.
1323
1324     \sa setSortIndicator() sortIndicatorSection()
1325 */
1326
1327 Qt::SortOrder QHeaderView::sortIndicatorOrder() const
1328 {
1329     Q_D(const QHeaderView);
1330     return d->sortIndicatorOrder;
1331 }
1332
1333 /*!
1334     \property QHeaderView::stretchLastSection
1335     \brief whether the last visible section in the header takes up all the
1336     available space
1337
1338     The default value is false.
1339
1340     \note The horizontal headers provided by QTreeView are configured with this
1341     property set to true, ensuring that the view does not waste any of the
1342     space assigned to it for its header. If this value is set to true, this
1343     property will override the resize mode set on the last section in the
1344     header.
1345
1346     \sa setResizeMode()
1347 */
1348 bool QHeaderView::stretchLastSection() const
1349 {
1350     Q_D(const QHeaderView);
1351     return d->stretchLastSection;
1352 }
1353
1354 void QHeaderView::setStretchLastSection(bool stretch)
1355 {
1356     Q_D(QHeaderView);
1357     d->stretchLastSection = stretch;
1358     if (d->state != QHeaderViewPrivate::NoState)
1359         return;
1360     if (stretch)
1361         resizeSections();
1362     else if (count())
1363         resizeSection(count() - 1, d->defaultSectionSize);
1364 }
1365
1366 /*!
1367     \since 4.2
1368     \property QHeaderView::cascadingSectionResizes
1369     \brief whether interactive resizing will be cascaded to the following
1370     sections once the section being resized by the user has reached its
1371     minimum size
1372
1373     This property only affects sections that have \l Interactive as their
1374     resize mode.
1375
1376     The default value is false.
1377
1378     \sa setResizeMode()
1379 */
1380 bool QHeaderView::cascadingSectionResizes() const
1381 {
1382     Q_D(const QHeaderView);
1383     return d->cascadingResizing;
1384 }
1385
1386 void QHeaderView::setCascadingSectionResizes(bool enable)
1387 {
1388     Q_D(QHeaderView);
1389     d->cascadingResizing = enable;
1390 }
1391
1392 /*!
1393     \property QHeaderView::defaultSectionSize
1394     \brief the default size of the header sections before resizing.
1395
1396     This property only affects sections that have \l Interactive or \l Fixed
1397     as their resize mode.
1398
1399     \sa setResizeMode() minimumSectionSize
1400 */
1401 int QHeaderView::defaultSectionSize() const
1402 {
1403     Q_D(const QHeaderView);
1404     return d->defaultSectionSize;
1405 }
1406
1407 void QHeaderView::setDefaultSectionSize(int size)
1408 {
1409     Q_D(QHeaderView);
1410     d->setDefaultSectionSize(size);
1411 }
1412
1413 /*!
1414     \since 4.2
1415     \property QHeaderView::minimumSectionSize
1416     \brief the minimum size of the header sections.
1417
1418     The minimum section size is the smallest section size allowed. If the
1419     minimum section size is set to -1, QHeaderView will use the maximum of
1420     the \l{QApplication::globalStrut()}{global strut} or the
1421     \l{fontMetrics()}{font metrics} size.
1422
1423     This property is honored by all \l{ResizeMode}{resize modes}.
1424
1425     \sa setResizeMode() defaultSectionSize
1426 */
1427 int QHeaderView::minimumSectionSize() const
1428 {
1429     Q_D(const QHeaderView);
1430     if (d->minimumSectionSize == -1) {
1431         QSize strut = QApplication::globalStrut();
1432         int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
1433         if (d->orientation == Qt::Horizontal)
1434             return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
1435         return qMax(strut.height(), (fontMetrics().height() + margin));
1436     }
1437     return d->minimumSectionSize;
1438 }
1439
1440 void QHeaderView::setMinimumSectionSize(int size)
1441 {
1442     Q_D(QHeaderView);
1443     d->minimumSectionSize = size;
1444 }
1445
1446 /*!
1447     \since 4.1
1448     \property QHeaderView::defaultAlignment
1449     \brief the default alignment of the text in each header section
1450 */
1451
1452 Qt::Alignment QHeaderView::defaultAlignment() const
1453 {
1454     Q_D(const QHeaderView);
1455     return d->defaultAlignment;
1456 }
1457
1458 void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
1459 {
1460     Q_D(QHeaderView);
1461     if (d->defaultAlignment == alignment)
1462         return;
1463
1464     d->defaultAlignment = alignment;
1465     d->viewport->update();
1466 }
1467
1468 /*!
1469     \internal
1470 */
1471 void QHeaderView::doItemsLayout()
1472 {
1473     initializeSections();
1474     QAbstractItemView::doItemsLayout();
1475 }
1476
1477 /*!
1478     Returns true if sections in the header has been moved; otherwise returns
1479     false;
1480
1481     \sa moveSection()
1482 */
1483 bool QHeaderView::sectionsMoved() const
1484 {
1485     Q_D(const QHeaderView);
1486     return !d->visualIndices.isEmpty();
1487 }
1488
1489 /*!
1490     \since 4.1
1491
1492     Returns true if sections in the header has been hidden; otherwise returns
1493     false;
1494
1495     \sa setSectionHidden()
1496 */
1497 bool QHeaderView::sectionsHidden() const
1498 {
1499     Q_D(const QHeaderView);
1500     return !d->hiddenSectionSize.isEmpty();
1501 }
1502
1503 #ifndef QT_NO_DATASTREAM
1504 /*!
1505     \since 4.3
1506
1507     Saves the current state of this header view.
1508
1509     To restore the saved state, pass the return value to restoreState().
1510
1511     \sa restoreState()
1512 */
1513 QByteArray QHeaderView::saveState() const
1514 {
1515     Q_D(const QHeaderView);
1516     QByteArray data;
1517     QDataStream stream(&data, QIODevice::WriteOnly);
1518     stream << QHeaderViewPrivate::VersionMarker;
1519     stream << 0; // current version is 0
1520     d->write(stream);
1521     return data;
1522 }
1523
1524 /*!
1525     \since 4.3
1526     Restores the \a state of this header view.
1527     This function returns \c true if the state was restored; otherwise returns
1528     false.
1529
1530     \sa saveState()
1531 */
1532 bool QHeaderView::restoreState(const QByteArray &state)
1533 {
1534     Q_D(QHeaderView);
1535     if (state.isEmpty())
1536         return false;
1537     QByteArray data = state;
1538     QDataStream stream(&data, QIODevice::ReadOnly);
1539     int marker;
1540     int ver;
1541     stream >> marker;
1542     stream >> ver;
1543     if (stream.status() != QDataStream::Ok
1544         || marker != QHeaderViewPrivate::VersionMarker
1545         || ver != 0) // current version is 0
1546         return false;
1547
1548     if (d->read(stream)) {
1549         emit sortIndicatorChanged(d->sortIndicatorSection, d->sortIndicatorOrder );
1550         d->viewport->update();
1551         return true;
1552     }
1553     return false;
1554 }
1555 #endif // QT_NO_DATASTREAM
1556
1557 /*!
1558   \reimp
1559 */
1560 void QHeaderView::reset()
1561 {
1562     QAbstractItemView::reset();
1563     // it would be correct to call clear, but some apps rely
1564     // on the header keeping the sections, even after calling reset
1565     //d->clear();
1566     initializeSections();
1567 }
1568
1569 /*!
1570     Updates the changed header sections with the given \a orientation, from
1571     \a logicalFirst to \a logicalLast inclusive.
1572 */
1573 void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
1574 {
1575     Q_D(QHeaderView);
1576     if (d->orientation != orientation)
1577         return;
1578
1579     if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
1580         return;
1581
1582     d->invalidateCachedSizeHint();
1583
1584     int firstVisualIndex = INT_MAX, lastVisualIndex = -1;
1585
1586     for (int section = logicalFirst; section <= logicalLast; ++section) {
1587         const int visual = visualIndex(section);
1588         firstVisualIndex = qMin(firstVisualIndex, visual);
1589         lastVisualIndex =  qMax(lastVisualIndex,  visual);
1590     }
1591
1592     d->executePostedResize();
1593     const int first = d->headerSectionPosition(firstVisualIndex),
1594               last = d->headerSectionPosition(lastVisualIndex)
1595                         + d->headerSectionSize(lastVisualIndex);
1596
1597     if (orientation == Qt::Horizontal) {
1598         d->viewport->update(first, 0, last - first, d->viewport->height());
1599     } else {
1600         d->viewport->update(0, first, d->viewport->width(), last - first);
1601     }
1602 }
1603
1604 /*!
1605     \internal
1606     \since 4.2
1607
1608     Updates the section specified by the given \a logicalIndex.
1609 */
1610
1611 void QHeaderView::updateSection(int logicalIndex)
1612 {
1613     Q_D(QHeaderView);
1614     if (d->orientation == Qt::Horizontal)
1615         d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
1616                                   0, sectionSize(logicalIndex), d->viewport->height()));
1617     else
1618         d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
1619                                   d->viewport->width(), sectionSize(logicalIndex)));
1620 }
1621
1622 /*!
1623     Resizes the sections according to their size hints. Normally, you do not
1624     have to call this function.
1625 */
1626
1627 void QHeaderView::resizeSections()
1628 {
1629     Q_D(QHeaderView);
1630     if (d->hasAutoResizeSections())
1631         d->resizeSections(Interactive, false); // no global resize mode
1632 }
1633
1634 /*!
1635     This slot is called when sections are inserted into the \a parent.
1636     \a logicalFirst and \a logicalLast indices signify where the new sections
1637     were inserted.
1638
1639     If only one section is inserted, \a logicalFirst and \a logicalLast will
1640     be the same.
1641 */
1642
1643 void QHeaderView::sectionsInserted(const QModelIndex &parent,
1644                                    int logicalFirst, int logicalLast)
1645 {
1646     Q_D(QHeaderView);
1647     if (parent != d->root)
1648         return; // we only handle changes in the top level
1649     int oldCount = d->sectionCount;
1650
1651     d->invalidateCachedSizeHint();
1652
1653     // add the new sections
1654     int insertAt = 0;
1655     for (int spanStart = 0; insertAt < d->sectionSpans.count() && spanStart < logicalFirst; ++insertAt)
1656         spanStart += d->sectionSpans.at(insertAt).count;
1657
1658     int insertCount = logicalLast - logicalFirst + 1;
1659     d->sectionCount += insertCount;
1660
1661     if (d->sectionSpans.isEmpty() || insertAt >= d->sectionSpans.count()) {
1662         int insertLength = d->defaultSectionSize * insertCount;
1663         d->length += insertLength;
1664         QHeaderViewPrivate::SectionSpan span(insertLength, insertCount, d->globalResizeMode);
1665         d->sectionSpans.append(span);
1666     } else if ((d->sectionSpans.at(insertAt).sectionSize() == d->defaultSectionSize)
1667                && d->sectionSpans.at(insertAt).resizeMode == d->globalResizeMode) {
1668         // add the new sections to an existing span
1669         int insertLength = d->sectionSpans.at(insertAt).sectionSize() * insertCount;
1670         d->length += insertLength;
1671         d->sectionSpans[insertAt].size += insertLength;
1672         d->sectionSpans[insertAt].count += insertCount;
1673     } else {
1674         // separate them out into their own span
1675         int insertLength = d->defaultSectionSize * insertCount;
1676         d->length += insertLength;
1677         QHeaderViewPrivate::SectionSpan span(insertLength, insertCount, d->globalResizeMode);
1678         d->sectionSpans.insert(insertAt, span);
1679     }
1680
1681     // update sorting column
1682     if (d->sortIndicatorSection >= logicalFirst)
1683         d->sortIndicatorSection += insertCount;
1684
1685     // update resize mode section counts
1686     if (d->globalResizeMode == Stretch)
1687         d->stretchSections = d->sectionCount;
1688     else if (d->globalResizeMode == ResizeToContents)
1689         d->contentsSections = d->sectionCount;
1690
1691     // clear selection cache
1692     d->sectionSelected.clear();
1693
1694     // update mapping
1695     if (!d->visualIndices.isEmpty() && !d->logicalIndices.isEmpty()) {
1696         Q_ASSERT(d->visualIndices.count() == d->logicalIndices.count());
1697         int mappingCount = d->visualIndices.count();
1698         for (int i = 0; i < mappingCount; ++i) {
1699             if (d->visualIndices.at(i) >= logicalFirst)
1700                d->visualIndices[i] += insertCount;
1701             if (d->logicalIndices.at(i) >= logicalFirst)
1702                 d->logicalIndices[i] += insertCount;
1703         }
1704         for (int j = logicalFirst; j <= logicalLast; ++j) {
1705             d->visualIndices.insert(j, j);
1706             d->logicalIndices.insert(j, j);
1707         }
1708     }
1709
1710     // insert sections into sectionsHidden
1711     if (!d->sectionHidden.isEmpty()) {
1712         QBitArray sectionHidden(d->sectionHidden);
1713         sectionHidden.resize(sectionHidden.count() + insertCount);
1714         sectionHidden.fill(false, logicalFirst, logicalLast + 1);
1715         for (int j = logicalLast + 1; j < sectionHidden.count(); ++j)
1716             //here we simply copy the old sectionHidden
1717             sectionHidden.setBit(j, d->sectionHidden.testBit(j - insertCount));
1718         d->sectionHidden = sectionHidden;
1719     }
1720
1721     // insert sections into hiddenSectionSize
1722     QHash<int, int> newHiddenSectionSize; // from logical index to section size
1723     for (int i = 0; i < logicalFirst; ++i)
1724         if (isSectionHidden(i))
1725             newHiddenSectionSize[i] = d->hiddenSectionSize[i];
1726     for (int j = logicalLast + 1; j < d->sectionCount; ++j)
1727         if (isSectionHidden(j))
1728             newHiddenSectionSize[j] = d->hiddenSectionSize[j - insertCount];
1729     d->hiddenSectionSize = newHiddenSectionSize;
1730
1731     d->doDelayedResizeSections();
1732     emit sectionCountChanged(oldCount, count());
1733
1734     // if the new sections were not updated by resizing, we need to update now
1735     if (!d->hasAutoResizeSections())
1736         d->viewport->update();
1737 }
1738
1739 /*!
1740     This slot is called when sections are removed from the \a parent.
1741     \a logicalFirst and \a logicalLast signify where the sections were removed.
1742
1743     If only one section is removed, \a logicalFirst and \a logicalLast will
1744     be the same.
1745 */
1746
1747 void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
1748                                            int logicalFirst, int logicalLast)
1749 {
1750     Q_UNUSED(parent);
1751     Q_UNUSED(logicalFirst);
1752     Q_UNUSED(logicalLast);
1753 }
1754
1755 void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
1756 {
1757     Q_Q(QHeaderView);
1758     const int changeCount = logicalLast - logicalFirst + 1;
1759
1760     // remove sections from hiddenSectionSize
1761     QHash<int, int> newHiddenSectionSize; // from logical index to section size
1762     for (int i = 0; i < logicalFirst; ++i)
1763         if (q->isSectionHidden(i))
1764             newHiddenSectionSize[i] = hiddenSectionSize[i];
1765     for (int j = logicalLast + 1; j < sectionCount; ++j)
1766         if (q->isSectionHidden(j))
1767             newHiddenSectionSize[j - changeCount] = hiddenSectionSize[j];
1768     hiddenSectionSize = newHiddenSectionSize;
1769
1770     // remove sections from sectionsHidden
1771     if (!sectionHidden.isEmpty()) {
1772         const int newsize = qMin(sectionCount - changeCount, sectionHidden.size());
1773         QBitArray newSectionHidden(newsize);
1774         for (int j = 0, k = 0; j < sectionHidden.size(); ++j) {
1775             const int logical = logicalIndex(j);
1776             if (logical < logicalFirst || logical > logicalLast) {
1777                 newSectionHidden[k++] = sectionHidden[j];
1778             }
1779         }
1780         sectionHidden = newSectionHidden;
1781     }
1782 }
1783
1784 void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
1785                                             int logicalFirst, int logicalLast)
1786 {
1787     Q_Q(QHeaderView);
1788     if (parent != root)
1789         return; // we only handle changes in the top level
1790     if (qMin(logicalFirst, logicalLast) < 0
1791         || qMax(logicalLast, logicalFirst) >= sectionCount)
1792         return;
1793     int oldCount = q->count();
1794     int changeCount = logicalLast - logicalFirst + 1;
1795
1796     updateHiddenSections(logicalFirst, logicalLast);
1797
1798     if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
1799         //Q_ASSERT(headerSectionCount() == sectionCount);
1800         removeSectionsFromSpans(logicalFirst, logicalLast);
1801     } else {
1802         for (int l = logicalLast; l >= logicalFirst; --l) {
1803             int visual = visualIndices.at(l);
1804             for (int v = 0; v < sectionCount; ++v) {
1805                 if (v >= logicalIndices.count())
1806                     continue; // the section doesn't exist
1807                 if (v > visual) {
1808                     int logical = logicalIndices.at(v);
1809                     --(visualIndices[logical]);
1810                 }
1811                 if (logicalIndex(v) > l) // no need to move the positions before l
1812                     --(logicalIndices[v]);
1813             }
1814             logicalIndices.remove(visual);
1815             visualIndices.remove(l);
1816             //Q_ASSERT(headerSectionCount() == sectionCount);
1817             removeSectionsFromSpans(visual, visual);
1818         }
1819         // ### handle sectionSelection, sectionHidden
1820     }
1821     sectionCount -= changeCount;
1822
1823     // update sorting column
1824     if (sortIndicatorSection >= logicalFirst) {
1825         if (sortIndicatorSection <= logicalLast)
1826             sortIndicatorSection = -1;
1827         else
1828             sortIndicatorSection -= changeCount;
1829     }
1830
1831     // if we only have the last section (the "end" position) left, the header is empty
1832     if (sectionCount <= 0)
1833         clear();
1834     invalidateCachedSizeHint();
1835     emit q->sectionCountChanged(oldCount, q->count());
1836     viewport->update();
1837 }
1838
1839 void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
1840 {
1841     //if there is no row/column we can't have mapping for columns
1842     //because no QModelIndex in the model would be valid
1843     // ### this is far from being bullet-proof and we would need a real system to 
1844     // ### map columns or rows persistently
1845     if ((orientation == Qt::Horizontal && model->rowCount(root) == 0)
1846         || model->columnCount(root) == 0)
1847         return;
1848
1849     for (int i = 0; i < sectionHidden.count(); ++i)
1850         if (sectionHidden.testBit(i)) // ### note that we are using column or row 0
1851             persistentHiddenSections.append(orientation == Qt::Horizontal
1852                                             ? model->index(0, logicalIndex(i), root)
1853                                             : model->index(logicalIndex(i), 0, root));
1854 }
1855
1856 void QHeaderViewPrivate::_q_layoutChanged()
1857 {
1858     Q_Q(QHeaderView);
1859     viewport->update();
1860     if (persistentHiddenSections.isEmpty() || modelIsEmpty()) {
1861         if (modelSectionCount() != sectionCount)
1862             q->initializeSections();
1863         persistentHiddenSections.clear();
1864         return;
1865     }
1866
1867     QBitArray oldSectionHidden = sectionHidden;
1868     bool sectionCountChanged = false;
1869
1870     for (int i = 0; i < persistentHiddenSections.count(); ++i) {
1871         QModelIndex index = persistentHiddenSections.at(i);
1872         if (index.isValid()) {
1873             const int logical = (orientation == Qt::Horizontal
1874                                  ? index.column()
1875                                  : index.row());
1876             q->setSectionHidden(logical, true);
1877             oldSectionHidden.setBit(logical, false);
1878         } else if (!sectionCountChanged && (modelSectionCount() != sectionCount)) {
1879             sectionCountChanged = true;
1880             break;
1881         }
1882     }
1883     persistentHiddenSections.clear();
1884
1885     for (int i = 0; i < oldSectionHidden.count(); ++i) {
1886         if (oldSectionHidden.testBit(i))
1887             q->setSectionHidden(i, false);
1888     }
1889
1890     // the number of sections changed; we need to reread the state of the model
1891     if (sectionCountChanged)
1892         q->initializeSections();
1893 }
1894
1895 /*!
1896   \internal
1897 */
1898
1899 void QHeaderView::initializeSections()
1900 {
1901     Q_D(QHeaderView);
1902     const int oldCount = d->sectionCount;
1903     const int newCount = d->modelSectionCount();
1904     if (newCount <= 0) {
1905             d->clear();
1906             emit sectionCountChanged(oldCount, 0);
1907     } else if (newCount != oldCount) {
1908         const int min = qBound(0, oldCount, newCount - 1);
1909         initializeSections(min, newCount - 1);
1910         if (stretchLastSection()) // we've already gotten the size hint
1911             d->lastSectionSize = sectionSize(logicalIndex(d->sectionCount - 1));
1912
1913         //make sure we update the hidden sections
1914         if (newCount < oldCount)
1915             d->updateHiddenSections(0, newCount-1);
1916     }
1917 }
1918
1919 /*!
1920     \internal
1921 */
1922
1923 void QHeaderView::initializeSections(int start, int end)
1924 {
1925     Q_D(QHeaderView);
1926
1927     Q_ASSERT(start >= 0);
1928     Q_ASSERT(end >= 0);
1929
1930     d->invalidateCachedSizeHint();
1931
1932     if (end + 1 < d->sectionCount) {
1933         int newCount = end + 1;
1934         d->removeSectionsFromSpans(newCount, d->sectionCount);
1935         if (!d->hiddenSectionSize.isEmpty()) {
1936             if (d->sectionCount - newCount > d->hiddenSectionSize.count()) {
1937                 for (int i = end + 1; i < d->sectionCount; ++i)
1938                     d->hiddenSectionSize.remove(i);
1939             } else {
1940                 QHash<int, int>::iterator it = d->hiddenSectionSize.begin();
1941                 while (it != d->hiddenSectionSize.end()) {
1942                     if (it.key() > end)
1943                         it = d->hiddenSectionSize.erase(it);
1944                     else
1945                         ++it;
1946                 }
1947             }
1948         }
1949     }
1950
1951     int oldCount = d->sectionCount;
1952     d->sectionCount = end + 1;
1953
1954     if (!d->logicalIndices.isEmpty()) {
1955         if (oldCount <= d->sectionCount) {
1956             d->logicalIndices.resize(d->sectionCount);
1957             d->visualIndices.resize(d->sectionCount);
1958             for (int i = oldCount; i < d->sectionCount; ++i) {
1959                 d->logicalIndices[i] = i;
1960                 d->visualIndices[i] = i;
1961             }
1962         } else {
1963             int j = 0;
1964             for (int i = 0; i < oldCount; ++i) {
1965                 int v = d->logicalIndices.at(i);
1966                 if (v < d->sectionCount) {
1967                     d->logicalIndices[j] = v;
1968                     d->visualIndices[v] = j;
1969                     j++;
1970                 }
1971             }
1972             d->logicalIndices.resize(d->sectionCount);
1973             d->visualIndices.resize(d->sectionCount);
1974         }
1975     }
1976
1977     if (d->globalResizeMode == Stretch)
1978         d->stretchSections = d->sectionCount;
1979     else if (d->globalResizeMode == ResizeToContents)
1980          d->contentsSections = d->sectionCount;
1981     if (!d->sectionHidden.isEmpty())
1982         d->sectionHidden.resize(d->sectionCount);
1983
1984     if (d->sectionCount > oldCount)
1985         d->createSectionSpan(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
1986     //Q_ASSERT(d->headerLength() == d->length);
1987
1988     if (d->sectionCount != oldCount)
1989         emit sectionCountChanged(oldCount,  d->sectionCount);
1990     d->viewport->update();
1991 }
1992
1993 /*!
1994   \reimp
1995 */
1996
1997 void QHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &old)
1998 {
1999     Q_D(QHeaderView);
2000
2001     if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
2002         if (old.isValid() && old.parent() == d->root)
2003             d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
2004                                     sectionSize(old.column()), d->viewport->height()));
2005         if (current.isValid() && current.parent() == d->root)
2006             d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
2007                                     sectionSize(current.column()), d->viewport->height()));
2008     } else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
2009         if (old.isValid() && old.parent() == d->root)
2010             d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
2011                                     d->viewport->width(), sectionSize(old.row())));
2012         if (current.isValid() && current.parent() == d->root)
2013             d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
2014                                     d->viewport->width(), sectionSize(current.row())));
2015     }
2016 }
2017
2018
2019 /*!
2020   \reimp
2021 */
2022
2023 bool QHeaderView::event(QEvent *e)
2024 {
2025     Q_D(QHeaderView);
2026     switch (e->type()) {
2027     case QEvent::HoverEnter: {
2028         QHoverEvent *he = static_cast<QHoverEvent*>(e);
2029         d->hover = logicalIndexAt(he->pos());
2030         if (d->hover != -1)
2031             updateSection(d->hover);
2032         break; }
2033     case QEvent::Leave:
2034     case QEvent::HoverLeave: {
2035         if (d->hover != -1)
2036             updateSection(d->hover);
2037         d->hover = -1;
2038         break; }
2039     case QEvent::HoverMove: {
2040         QHoverEvent *he = static_cast<QHoverEvent*>(e);
2041         int oldHover = d->hover;
2042         d->hover = logicalIndexAt(he->pos());
2043         if (d->hover != oldHover) {
2044             if (oldHover != -1)
2045                 updateSection(oldHover);
2046             if (d->hover != -1)
2047                 updateSection(d->hover);
2048         }
2049         break; }
2050     case QEvent::Timer: {
2051         QTimerEvent *te = static_cast<QTimerEvent*>(e);
2052         if (te->timerId() == d->delayedResize.timerId()) {
2053             d->delayedResize.stop();
2054             resizeSections();
2055         }
2056         break; }
2057     default:
2058         break;
2059     }
2060     return QAbstractItemView::event(e);
2061 }
2062
2063 /*!
2064   \reimp
2065 */
2066
2067 void QHeaderView::paintEvent(QPaintEvent *e)
2068 {
2069     Q_D(QHeaderView);
2070
2071     if (count() == 0)
2072         return;
2073
2074     QPainter painter(d->viewport);
2075     const QPoint offset = d->scrollDelayOffset;
2076     QRect translatedEventRect = e->rect();
2077     translatedEventRect.translate(offset);
2078
2079     int start = -1;
2080     int end = -1;
2081     if (d->orientation == Qt::Horizontal) {
2082         start = visualIndexAt(translatedEventRect.left());
2083         end = visualIndexAt(translatedEventRect.right());
2084     } else {
2085         start = visualIndexAt(translatedEventRect.top());
2086         end = visualIndexAt(translatedEventRect.bottom());
2087     }
2088
2089     if (d->reverse()) {
2090         start = (start == -1 ? count() - 1 : start);
2091         end = (end == -1 ? 0 : end);
2092     } else {
2093         start = (start == -1 ? 0 : start);
2094         end = (end == -1 ? count() - 1 : end);
2095     }
2096
2097     int tmp = start;
2098     start = qMin(start, end);
2099     end = qMax(tmp, end);
2100
2101     d->prepareSectionSelected(); // clear and resize the bit array
2102
2103     QRect currentSectionRect;
2104     int logical;
2105     const int width = d->viewport->width();
2106     const int height = d->viewport->height();
2107     for (int i = start; i <= end; ++i) {
2108         if (d->isVisualIndexHidden(i))
2109             continue;
2110         painter.save();
2111         logical = logicalIndex(i);
2112         if (d->orientation == Qt::Horizontal) {
2113             currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
2114         } else {
2115             currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
2116         }
2117         currentSectionRect.translate(offset);
2118
2119         QVariant variant = d->model->headerData(logical, d->orientation,
2120                                                 Qt::FontRole);
2121         if (variant.isValid() && variant.canConvert<QFont>()) {
2122             QFont sectionFont = qvariant_cast<QFont>(variant);
2123             painter.setFont(sectionFont);
2124         }
2125         paintSection(&painter, currentSectionRect, logical);
2126         painter.restore();
2127     }
2128
2129     QStyleOption opt;
2130     opt.init(this);
2131     // Paint the area beyond where there are indexes
2132     if (d->reverse()) {
2133         opt.state |= QStyle::State_Horizontal;
2134         if (currentSectionRect.left() > translatedEventRect.left()) {
2135             opt.rect = QRect(translatedEventRect.left(), 0,
2136                              currentSectionRect.left() - translatedEventRect.left(), height);
2137             style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2138         }
2139     } else if (currentSectionRect.right() < translatedEventRect.right()) {
2140         // paint to the right
2141         opt.state |= QStyle::State_Horizontal;
2142         opt.rect = QRect(currentSectionRect.right() + 1, 0,
2143                          translatedEventRect.right() - currentSectionRect.right(), height);
2144         style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2145     } else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
2146         // paint the bottom section
2147         opt.state &= ~QStyle::State_Horizontal;
2148         opt.rect = QRect(0, currentSectionRect.bottom() + 1,
2149                          width, height - currentSectionRect.bottom() - 1);
2150         style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
2151     }
2152
2153 #if 0
2154     // ### visualize section spans
2155     for (int a = 0, i = 0; i < d->sectionSpans.count(); ++i) {
2156         QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
2157         if (d->orientation == Qt::Horizontal)
2158             painter.fillRect(a - d->offset, 0, d->sectionSpans.at(i).size, 4, color);
2159         else
2160             painter.fillRect(0, a - d->offset, 4, d->sectionSpans.at(i).size, color);
2161         a += d->sectionSpans.at(i).size;
2162     }
2163
2164 #endif
2165 }
2166
2167 /*!
2168   \reimp
2169 */
2170
2171 void QHeaderView::mousePressEvent(QMouseEvent *e)
2172 {
2173     Q_D(QHeaderView);
2174     if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
2175         return;
2176     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2177     int handle = d->sectionHandleAt(pos);
2178     d->originalSize = -1; // clear the stored original size
2179     if (handle == -1) {
2180         d->pressed = logicalIndexAt(pos);
2181         if (d->clickableSections)
2182             emit sectionPressed(d->pressed);
2183         if (d->movableSections) {
2184             d->section = d->target = d->pressed;
2185             if (d->section == -1)
2186                 return;
2187             d->state = QHeaderViewPrivate::MoveSection;
2188             d->setupSectionIndicator(d->section, pos);
2189         } else if (d->clickableSections && d->pressed != -1) {
2190             updateSection(d->pressed);
2191             d->state = QHeaderViewPrivate::SelectSections;
2192         }
2193     } else if (resizeMode(handle) == Interactive) {
2194         d->originalSize = sectionSize(handle);
2195         d->state = QHeaderViewPrivate::ResizeSection;
2196         d->section = handle;
2197     }
2198
2199     d->firstPos = pos;
2200     d->lastPos = pos;
2201
2202     d->clearCascadingSections();
2203 }
2204
2205 /*!
2206   \reimp
2207 */
2208
2209 void QHeaderView::mouseMoveEvent(QMouseEvent *e)
2210 {
2211     Q_D(QHeaderView);
2212     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2213     if (pos < 0 && d->state != QHeaderViewPrivate::SelectSections)
2214         return;
2215     if (e->buttons() == Qt::NoButton) {
2216 #if !defined(Q_WS_MAC)
2217         // Under Cocoa, when the mouse button is released, may include an extra
2218         // simulated mouse moved event. The state of the buttons when this event
2219         // is generated is already "no button" and the code below gets executed
2220         // just before the mouseReleaseEvent and resets the state. This prevents
2221         // column dragging from working. So this code is disabled under Cocoa.
2222         d->state = QHeaderViewPrivate::NoState;
2223         d->pressed = -1;
2224 #endif
2225     }
2226     switch (d->state) {
2227         case QHeaderViewPrivate::ResizeSection: {
2228             Q_ASSERT(d->originalSize != -1);
2229             if (d->cascadingResizing) {
2230                 int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
2231                 int visual = visualIndex(d->section);
2232                 d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
2233             } else {
2234                 int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
2235                 resizeSection(d->section, qMax(d->originalSize + delta, minimumSectionSize()));
2236             }
2237             d->lastPos = pos;
2238             return;
2239         }
2240         case QHeaderViewPrivate::MoveSection: {
2241             if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
2242                 || !d->sectionIndicator->isHidden()) {
2243                 int visual = visualIndexAt(pos);
2244                 if (visual == -1)
2245                     return;
2246                 int posThreshold = d->headerSectionPosition(visual) - d->offset + d->headerSectionSize(visual) / 2;
2247                 int moving = visualIndex(d->section);
2248                 if (visual < moving) {
2249                     if (pos < posThreshold)
2250                         d->target = d->logicalIndex(visual);
2251                     else
2252                         d->target = d->logicalIndex(visual + 1);
2253                 } else if (visual > moving) {
2254                     if (pos > posThreshold)
2255                         d->target = d->logicalIndex(visual);
2256                     else
2257                         d->target = d->logicalIndex(visual - 1);
2258                 } else {
2259                     d->target = d->section;
2260                 }
2261                 d->updateSectionIndicator(d->section, pos);
2262             }
2263             return;
2264         }
2265         case QHeaderViewPrivate::SelectSections: {
2266             int logical = logicalIndexAt(qMax(-d->offset, pos));
2267             if (logical == -1 && pos > 0)
2268                 logical = d->lastVisibleVisualIndex();
2269             if (logical == d->pressed)
2270                 return; // nothing to do
2271             else if (d->pressed != -1)
2272                 updateSection(d->pressed);
2273             d->pressed = logical;
2274             if (d->clickableSections && logical != -1) {
2275                 emit sectionEntered(d->pressed);
2276                 updateSection(d->pressed);
2277             }
2278             return;
2279         }
2280         case QHeaderViewPrivate::NoState: {
2281 #ifndef QT_NO_CURSOR
2282             int handle = d->sectionHandleAt(pos);
2283             bool hasCursor = testAttribute(Qt::WA_SetCursor);
2284             if (handle != -1 && (resizeMode(handle) == Interactive)) {
2285                 if (!hasCursor)
2286                     setCursor(d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
2287             } else if (hasCursor) {
2288                 unsetCursor();
2289             }
2290 #endif
2291             return;
2292         }
2293         default:
2294             break;
2295     }
2296 }
2297
2298 /*!
2299   \reimp
2300 */
2301
2302 void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
2303 {
2304     Q_D(QHeaderView);
2305     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2306     switch (d->state) {
2307     case QHeaderViewPrivate::MoveSection:
2308         if (!d->sectionIndicator->isHidden()) { // moving
2309             int from = visualIndex(d->section);
2310             Q_ASSERT(from != -1);
2311             int to = visualIndex(d->target);
2312             Q_ASSERT(to != -1);
2313             moveSection(from, to);
2314             d->section = d->target = -1;
2315             d->updateSectionIndicator(d->section, pos);
2316             break;
2317         } // not moving
2318     case QHeaderViewPrivate::SelectSections:
2319         if (!d->clickableSections) {
2320             int section = logicalIndexAt(pos);
2321             updateSection(section);
2322         }
2323         // fall through
2324     case QHeaderViewPrivate::NoState:
2325         if (d->clickableSections) {
2326             int section = logicalIndexAt(pos);
2327             if (section != -1 && section == d->pressed) {
2328                 d->flipSortIndicator(section);
2329                 emit sectionClicked(section);
2330             }
2331             if (d->pressed != -1)
2332                 updateSection(d->pressed);
2333         }
2334         break;
2335     case QHeaderViewPrivate::ResizeSection:
2336         d->originalSize = -1;
2337         d->clearCascadingSections();
2338         break;
2339     default:
2340         break;
2341     }
2342     d->state = QHeaderViewPrivate::NoState;
2343     d->pressed = -1;
2344 }
2345
2346 /*!
2347   \reimp
2348 */
2349
2350 void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
2351 {
2352     Q_D(QHeaderView);
2353     int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
2354     int handle = d->sectionHandleAt(pos);
2355     if (handle > -1 && resizeMode(handle) == Interactive) {
2356         emit sectionHandleDoubleClicked(handle);
2357 #ifndef QT_NO_CURSOR
2358         Qt::CursorShape splitCursor = (d->orientation == Qt::Horizontal)
2359                                       ? Qt::SplitHCursor : Qt::SplitVCursor;
2360         if (cursor().shape() == splitCursor) {
2361             // signal handlers may have changed the section size
2362             handle = d->sectionHandleAt(pos);
2363             if (!(handle > -1 && resizeMode(handle) == Interactive))
2364                 setCursor(Qt::ArrowCursor);
2365         }
2366 #endif
2367     } else {
2368         emit sectionDoubleClicked(logicalIndexAt(e->pos()));
2369     }
2370 }
2371
2372 /*!
2373   \reimp
2374 */
2375
2376 bool QHeaderView::viewportEvent(QEvent *e)
2377 {
2378     Q_D(QHeaderView);
2379     switch (e->type()) {
2380 #ifndef QT_NO_TOOLTIP
2381     case QEvent::ToolTip: {
2382         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2383         int logical = logicalIndexAt(he->pos());
2384         if (logical != -1) {
2385             QVariant variant = d->model->headerData(logical, d->orientation, Qt::ToolTipRole);
2386             if (variant.isValid()) {
2387                 QToolTip::showText(he->globalPos(), variant.toString(), this);
2388                 return true;
2389             }
2390         }
2391         break; }
2392 #endif
2393 #ifndef QT_NO_WHATSTHIS
2394     case QEvent::QueryWhatsThis: {
2395         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2396         int logical = logicalIndexAt(he->pos());
2397         if (logical != -1
2398             && d->model->headerData(logical, d->orientation, Qt::WhatsThisRole).isValid())
2399             return true;
2400         break; }
2401     case QEvent::WhatsThis: {
2402         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2403         int logical = logicalIndexAt(he->pos());
2404         if (logical != -1) {
2405              QVariant whatsthis = d->model->headerData(logical, d->orientation,
2406                                                       Qt::WhatsThisRole);
2407              if (whatsthis.isValid()) {
2408                  QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
2409                  return true;
2410              }
2411         }
2412         break; }
2413 #endif // QT_NO_WHATSTHIS
2414 #ifndef QT_NO_STATUSTIP
2415     case QEvent::StatusTip: {
2416         QHelpEvent *he = static_cast<QHelpEvent*>(e);
2417         int logical = logicalIndexAt(he->pos());
2418         if (logical != -1) {
2419             QString statustip = d->model->headerData(logical, d->orientation,
2420                                                     Qt::StatusTipRole).toString();
2421             if (!statustip.isEmpty())
2422                 setStatusTip(statustip);
2423         }
2424         return true; }
2425 #endif // QT_NO_STATUSTIP
2426     case QEvent::Hide:
2427     case QEvent::Show:
2428     case QEvent::FontChange:
2429     case QEvent::StyleChange:
2430         d->invalidateCachedSizeHint();
2431         resizeSections();
2432         emit geometriesChanged();
2433         break;
2434     case QEvent::ContextMenu: {
2435         d->state = QHeaderViewPrivate::NoState;
2436         d->pressed = d->section = d->target = -1;
2437         d->updateSectionIndicator(d->section, -1);
2438         break; }
2439     case QEvent::Wheel: {
2440         QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea *>(parentWidget());
2441         if (asa)
2442             return QApplication::sendEvent(asa->viewport(), e);
2443         break; }
2444     default:
2445         break;
2446     }
2447     return QAbstractItemView::viewportEvent(e);
2448 }
2449
2450 /*!
2451     Paints the section specified by the given \a logicalIndex, using the given
2452     \a painter and \a rect.
2453
2454     Normally, you do not have to call this function.
2455 */
2456
2457 void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
2458 {
2459     Q_D(const QHeaderView);
2460     if (!rect.isValid())
2461         return;
2462     // get the state of the section
2463     QStyleOptionHeader opt;
2464     initStyleOption(&opt);
2465     QStyle::State state = QStyle::State_None;
2466     if (isEnabled())
2467         state |= QStyle::State_Enabled;
2468     if (window()->isActiveWindow())
2469         state |= QStyle::State_Active;
2470     if (d->clickableSections) {
2471         if (logicalIndex == d->hover)
2472             state |= QStyle::State_MouseOver;
2473         if (logicalIndex == d->pressed)
2474             state |= QStyle::State_Sunken;
2475         else if (d->highlightSelected) {
2476             if (d->sectionIntersectsSelection(logicalIndex))
2477                 state |= QStyle::State_On;
2478             if (d->isSectionSelected(logicalIndex))
2479                 state |= QStyle::State_Sunken;
2480         }
2481
2482     }
2483     if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
2484         opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
2485                             ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
2486
2487     // setup the style options structure
2488     QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
2489                                                   Qt::TextAlignmentRole);
2490     opt.rect = rect;
2491     opt.section = logicalIndex;
2492     opt.state |= state;
2493     opt.textAlignment = Qt::Alignment(textAlignment.isValid()
2494                                       ? Qt::Alignment(textAlignment.toInt())
2495                                       : d->defaultAlignment);
2496
2497     opt.iconAlignment = Qt::AlignVCenter;
2498     opt.text = d->model->headerData(logicalIndex, d->orientation,
2499                                     Qt::DisplayRole).toString();
2500     if (d->textElideMode != Qt::ElideNone)
2501         opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4);
2502
2503     QVariant variant = d->model->headerData(logicalIndex, d->orientation,
2504                                     Qt::DecorationRole);
2505     opt.icon = qvariant_cast<QIcon>(variant);
2506     if (opt.icon.isNull())
2507         opt.icon = qvariant_cast<QPixmap>(variant);
2508     QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
2509                                                     Qt::ForegroundRole);
2510     if (foregroundBrush.canConvert<QBrush>())
2511         opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
2512
2513     QPointF oldBO = painter->brushOrigin();
2514     QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
2515                                                     Qt::BackgroundRole);
2516     if (backgroundBrush.canConvert<QBrush>()) {
2517         opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
2518         opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
2519         painter->setBrushOrigin(opt.rect.topLeft());
2520     }
2521
2522     // the section position
2523     int visual = visualIndex(logicalIndex);
2524     Q_ASSERT(visual != -1);
2525     if (count() == 1)
2526         opt.position = QStyleOptionHeader::OnlyOneSection;
2527     else if (visual == 0)
2528         opt.position = QStyleOptionHeader::Beginning;
2529     else if (visual == count() - 1)
2530         opt.position = QStyleOptionHeader::End;
2531     else
2532         opt.position = QStyleOptionHeader::Middle;
2533     opt.orientation = d->orientation;
2534     // the selected position
2535     bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
2536     bool nextSelected =  d->isSectionSelected(this->logicalIndex(visual + 1));
2537     if (previousSelected && nextSelected)
2538         opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
2539     else if (previousSelected)
2540         opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
2541     else if (nextSelected)
2542         opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
2543     else
2544         opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
2545     // draw the section
2546     style()->drawControl(QStyle::CE_Header, &opt, painter, this);
2547
2548     painter->setBrushOrigin(oldBO);
2549 }
2550
2551 /*!
2552     Returns the size of the contents of the section specified by the given
2553     \a logicalIndex.
2554
2555     \sa defaultSectionSize()
2556 */
2557
2558 QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
2559 {
2560     Q_D(const QHeaderView);
2561     Q_ASSERT(logicalIndex >= 0);
2562
2563     ensurePolished();
2564
2565     // use SizeHintRole
2566     QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
2567     if (variant.isValid())
2568         return qvariant_cast<QSize>(variant);
2569
2570     // otherwise use the contents
2571     QStyleOptionHeader opt;
2572     initStyleOption(&opt);
2573     opt.section = logicalIndex;
2574     QVariant var = d->model->headerData(logicalIndex, d->orientation,
2575                                             Qt::FontRole);
2576     QFont fnt;
2577     if (var.isValid() && var.canConvert<QFont>())
2578         fnt = qvariant_cast<QFont>(var);
2579     else
2580         fnt = font();
2581     fnt.setBold(true);
2582     opt.fontMetrics = QFontMetrics(fnt);
2583     opt.text = d->model->headerData(logicalIndex, d->orientation,
2584                                     Qt::DisplayRole).toString();
2585     variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole);
2586     opt.icon = qvariant_cast<QIcon>(variant);
2587     if (opt.icon.isNull())
2588         opt.icon = qvariant_cast<QPixmap>(variant);
2589     QSize size = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
2590     if (isSortIndicatorShown()) {
2591         int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, &opt, this);
2592         if (d->orientation == Qt::Horizontal)
2593             size.rwidth() += size.height() + margin;
2594         else
2595             size.rheight() += size.width() + margin;
2596     }
2597     return size;
2598 }
2599
2600 /*!
2601     Returns the horizontal offset of the header. This is 0 for vertical
2602     headers.
2603
2604     \sa offset()
2605 */
2606
2607 int QHeaderView::horizontalOffset() const
2608 {
2609     Q_D(const QHeaderView);
2610     if (d->orientation == Qt::Horizontal)
2611         return d->offset;
2612     return 0;
2613 }
2614
2615 /*!
2616     Returns the vertical offset of the header. This is 0 for horizontal
2617     headers.
2618
2619     \sa offset()
2620 */
2621
2622 int QHeaderView::verticalOffset() const
2623 {
2624     Q_D(const QHeaderView);
2625     if (d->orientation == Qt::Vertical)
2626         return d->offset;
2627     return 0;
2628 }
2629
2630 /*!
2631     \reimp
2632     \internal
2633 */
2634
2635 void QHeaderView::updateGeometries()
2636 {
2637     Q_D(QHeaderView);
2638     d->layoutChildren();
2639     if (d->hasAutoResizeSections())
2640         d->doDelayedResizeSections();
2641 }
2642
2643 /*!
2644     \reimp
2645     \internal
2646 */
2647
2648 void QHeaderView::scrollContentsBy(int dx, int dy)
2649 {
2650     Q_D(QHeaderView);
2651     d->scrollDirtyRegion(dx, dy);
2652 }
2653
2654 /*!
2655     \reimp
2656     \internal
2657 */
2658 void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
2659 {
2660     Q_D(QHeaderView);
2661     d->invalidateCachedSizeHint();
2662     if (d->hasAutoResizeSections()) {
2663         bool resizeRequired = d->globalResizeMode == ResizeToContents;
2664         int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row();
2665         int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row();
2666         for (int i = first; i <= last && !resizeRequired; ++i)
2667             resizeRequired = (resizeMode(i) == ResizeToContents);
2668         if (resizeRequired)
2669             d->doDelayedResizeSections();
2670     }
2671 }
2672
2673 /*!
2674     \reimp
2675     \internal
2676
2677     Empty implementation because the header doesn't show QModelIndex items.
2678 */
2679 void QHeaderView::rowsInserted(const QModelIndex &, int, int)
2680 {
2681     // do nothing
2682 }
2683
2684 /*!
2685     \reimp
2686     \internal
2687
2688     Empty implementation because the header doesn't show QModelIndex items.
2689 */
2690
2691 QRect QHeaderView::visualRect(const QModelIndex &) const
2692 {
2693     return QRect();
2694 }
2695
2696 /*!
2697     \reimp
2698     \internal
2699
2700     Empty implementation because the header doesn't show QModelIndex items.
2701 */
2702
2703 void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
2704 {
2705     // do nothing - the header only displays sections
2706 }
2707
2708 /*!
2709     \reimp
2710     \internal
2711
2712     Empty implementation because the header doesn't show QModelIndex items.
2713 */
2714
2715 QModelIndex QHeaderView::indexAt(const QPoint &) const
2716 {
2717     return QModelIndex();
2718 }
2719
2720 /*!
2721     \reimp
2722     \internal
2723
2724     Empty implementation because the header doesn't show QModelIndex items.
2725 */
2726
2727 bool QHeaderView::isIndexHidden(const QModelIndex &) const
2728 {
2729     return true; // the header view has no items, just sections
2730 }
2731
2732 /*!
2733     \reimp
2734     \internal
2735
2736     Empty implementation because the header doesn't show QModelIndex items.
2737 */
2738
2739 QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
2740 {
2741     return QModelIndex();
2742 }
2743
2744 /*!
2745     \reimp
2746
2747     Selects the items in the given \a rect according to the specified
2748     \a flags.
2749
2750     The base class implementation does nothing.
2751 */
2752
2753 void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
2754 {
2755     // do nothing
2756 }
2757
2758 /*!
2759     \internal
2760 */
2761
2762 QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
2763 {
2764     Q_D(const QHeaderView);
2765     const int max = d->modelSectionCount();
2766     if (d->orientation == Qt::Horizontal) {
2767         int left = max;
2768         int right = 0;
2769         int rangeLeft, rangeRight;
2770
2771         for (int i = 0; i < selection.count(); ++i) {
2772             QItemSelectionRange r = selection.at(i);
2773             if (r.parent().isValid() || !r.isValid())
2774                 continue; // we only know about toplevel items and we don't want invalid ranges
2775             // FIXME an item inside the range may be the leftmost or rightmost
2776             rangeLeft = visualIndex(r.left());
2777             if (rangeLeft == -1) // in some cases users may change the selections
2778                 continue;        // before we have a chance to do the layout
2779             rangeRight = visualIndex(r.right());
2780             if (rangeRight == -1) // in some cases users may change the selections
2781                 continue;         // before we have a chance to do the layout
2782             if (rangeLeft < left)
2783                 left = rangeLeft;
2784             if (rangeRight > right)
2785                 right = rangeRight;
2786         }
2787
2788         int logicalLeft = logicalIndex(left);
2789         int logicalRight = logicalIndex(right);
2790
2791         if (logicalLeft < 0  || logicalLeft >= count() ||
2792             logicalRight < 0 || logicalRight >= count())
2793             return QRegion();
2794
2795         int leftPos = sectionViewportPosition(logicalLeft);
2796         int rightPos = sectionViewportPosition(logicalRight);
2797         rightPos += sectionSize(logicalRight);
2798         return QRect(leftPos, 0, rightPos - leftPos, height());
2799     }
2800     // orientation() == Qt::Vertical
2801     int top = max;
2802     int bottom = 0;
2803     int rangeTop, rangeBottom;
2804
2805     for (int i = 0; i < selection.count(); ++i) {
2806         QItemSelectionRange r = selection.at(i);
2807         if (r.parent().isValid() || !r.isValid())
2808             continue; // we only know about toplevel items
2809         // FIXME an item inside the range may be the leftmost or rightmost
2810         rangeTop = visualIndex(r.top());
2811         if (rangeTop == -1) // in some cases users may change the selections
2812             continue;       // before we have a chance to do the layout
2813         rangeBottom = visualIndex(r.bottom());
2814         if (rangeBottom == -1) // in some cases users may change the selections
2815             continue;          // before we have a chance to do the layout
2816         if (rangeTop < top)
2817             top = rangeTop;
2818         if (rangeBottom > bottom)
2819             bottom = rangeBottom;
2820     }
2821
2822     int logicalTop = logicalIndex(top);
2823     int logicalBottom = logicalIndex(bottom);
2824
2825     if (logicalTop == -1 || logicalBottom == -1)
2826         return QRect();
2827
2828     int topPos = sectionViewportPosition(logicalTop);
2829     int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
2830
2831     return QRect(0, topPos, width(), bottomPos - topPos);
2832 }
2833
2834
2835 // private implementation
2836
2837 int QHeaderViewPrivate::sectionHandleAt(int position)
2838 {
2839     Q_Q(QHeaderView);
2840     int visual = q->visualIndexAt(position);
2841     if (visual == -1)
2842         return -1;
2843     int log = logicalIndex(visual);
2844     int pos = q->sectionViewportPosition(log);
2845     int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, q);
2846
2847     bool atLeft = position < pos + grip;
2848     bool atRight = (position > pos + q->sectionSize(log) - grip);
2849     if (reverse())
2850         qSwap(atLeft, atRight);
2851
2852     if (atLeft) {
2853         //grip at the beginning of the section
2854         while(visual > -1) {
2855             int logical = q->logicalIndex(--visual);
2856             if (!q->isSectionHidden(logical))
2857                 return logical;
2858         }
2859     } else if (atRight) {
2860         //grip at the end of the section
2861         return log;
2862     }
2863     return -1;
2864 }
2865
2866 void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
2867 {
2868     Q_Q(QHeaderView);
2869     if (!sectionIndicator) {
2870         sectionIndicator = new QLabel(viewport);
2871     }
2872
2873     int w, h;
2874     int p = q->sectionViewportPosition(section);
2875     if (orientation == Qt::Horizontal) {
2876         w = q->sectionSize(section);
2877         h = viewport->height();
2878     } else {
2879         w = viewport->width();
2880         h = q->sectionSize(section);
2881     }
2882     sectionIndicator->resize(w, h);
2883
2884     QPixmap pm(w, h);
2885     pm.fill(QColor(0, 0, 0, 45));
2886     QRect rect(0, 0, w, h);
2887
2888     QPainter painter(&pm);
2889     painter.setOpacity(0.75);
2890     q->paintSection(&painter, rect, section);
2891     painter.end();
2892
2893     sectionIndicator->setPixmap(pm);
2894     sectionIndicatorOffset = position - qMax(p, 0);
2895 }
2896
2897 void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
2898 {
2899     if (!sectionIndicator)
2900         return;
2901
2902     if (section == -1 || target == -1) {
2903         sectionIndicator->hide();
2904         return;
2905     }
2906
2907     if (orientation == Qt::Horizontal)
2908         sectionIndicator->move(position - sectionIndicatorOffset, 0);
2909     else
2910         sectionIndicator->move(0, position - sectionIndicatorOffset);
2911
2912     sectionIndicator->show();
2913 }
2914
2915 /*!
2916     Initialize \a option with the values from this QHeaderView. This method is
2917     useful for subclasses when they need a QStyleOptionHeader, but do not want
2918     to fill in all the information themselves.
2919
2920     \sa QStyleOption::initFrom()
2921 */
2922 void QHeaderView::initStyleOption(QStyleOptionHeader *option) const
2923 {
2924     Q_D(const QHeaderView);
2925     option->initFrom(this);
2926     option->state = QStyle::State_None | QStyle::State_Raised;
2927     option->orientation = d->orientation;
2928     if (d->orientation == Qt::Horizontal)
2929         option->state |= QStyle::State_Horizontal;
2930     if (isEnabled())
2931         option->state |= QStyle::State_Enabled;
2932     option->section = 0;
2933 }
2934
2935 bool QHeaderViewPrivate::isSectionSelected(int section) const
2936 {
2937     int i = section * 2;
2938     if (i < 0 || i >= sectionSelected.count())
2939         return false;
2940     if (sectionSelected.testBit(i)) // if the value was cached
2941         return sectionSelected.testBit(i + 1);
2942     bool s = false;
2943     if (orientation == Qt::Horizontal)
2944         s = isColumnSelected(section);
2945     else
2946         s = isRowSelected(section);
2947     sectionSelected.setBit(i + 1, s); // selection state
2948     sectionSelected.setBit(i, true); // cache state
2949     return s;
2950 }
2951
2952 /*!
2953     \internal
2954     Returns the last visible (ie. not hidden) visual index
2955 */
2956 int QHeaderViewPrivate::lastVisibleVisualIndex() const
2957 {
2958     Q_Q(const QHeaderView);
2959     for (int visual = q->count()-1; visual >= 0; --visual) {
2960         if (!q->isSectionHidden(q->logicalIndex(visual)))
2961             return visual;
2962     }
2963
2964     //default value if no section is actually visible
2965     return -1;
2966 }
2967
2968 /*!
2969     \internal
2970     Go through and resize all of the sections applying stretchLastSection,
2971     manualy stretches, sizes, and useGlobalMode.
2972
2973     The different resize modes are:
2974     Interactive - the user decides the size
2975     Stretch - take up whatever space is left
2976     Fixed - the size is set programmatically outside the header
2977     ResizeToContentes - the size is set based on the contents of the row or column in the parent view
2978
2979     The resize mode will not affect the last section if stretchLastSection is true.
2980 */
2981 void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
2982 {
2983     Q_Q(QHeaderView);
2984     //stop the timer in case it is delayed
2985     delayedResize.stop();
2986
2987     executePostedLayout();
2988     if (sectionCount == 0)
2989         return;
2990
2991     if (resizeRecursionBlock)
2992         return;
2993     resizeRecursionBlock = true;
2994
2995     invalidateCachedSizeHint();
2996
2997     const int lastVisibleSection = lastVisibleVisualIndex();
2998
2999     // find stretchLastSection if we have it
3000     int stretchSection = -1;
3001     if (stretchLastSection && !useGlobalMode)
3002         stretchSection = lastVisibleVisualIndex();
3003
3004     // count up the number of strected sections and how much space left for them
3005     int lengthToStrech = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
3006     int numberOfStretchedSections = 0;
3007     QList<int> section_sizes;
3008     for (int i = 0; i < sectionCount; ++i) {
3009         if (isVisualIndexHidden(i))
3010             continue;
3011
3012         QHeaderView::ResizeMode resizeMode;
3013         if (useGlobalMode && (i != stretchSection))
3014             resizeMode = globalMode;
3015         else
3016             resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i));
3017
3018         if (resizeMode == QHeaderView::Stretch) {
3019             ++numberOfStretchedSections;
3020             section_sizes.append(headerSectionSize(i));
3021             continue;
3022         }
3023
3024         // because it isn't stretch, determine its width and remove that from lengthToStrech
3025         int sectionSize = 0;
3026         if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
3027             sectionSize = headerSectionSize(i);
3028         } else { // resizeMode == QHeaderView::ResizeToContents
3029             int logicalIndex = q->logicalIndex(i);
3030             sectionSize = qMax(viewSectionSizeHint(logicalIndex),
3031                                q->sectionSizeHint(logicalIndex));
3032         }
3033         section_sizes.append(sectionSize);
3034         lengthToStrech -= sectionSize;
3035     }
3036
3037     // calculate the new length for all of the stretched sections
3038     int stretchSectionLength = -1;
3039     int pixelReminder = 0;
3040     if (numberOfStretchedSections > 0 && lengthToStrech > 0) { // we have room to stretch in
3041         int hintLengthForEveryStretchedSection = lengthToStrech / numberOfStretchedSections;
3042         stretchSectionLength = qMax(hintLengthForEveryStretchedSection, q->minimumSectionSize());
3043         pixelReminder = lengthToStrech % numberOfStretchedSections;
3044     }
3045
3046     int spanStartSection = 0;
3047     int previousSectionLength = 0;
3048
3049     QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
3050
3051     // resize each section along the total length
3052     for (int i = 0; i < sectionCount; ++i) {
3053         int oldSectionLength = headerSectionSize(i);
3054         int newSectionLength = -1;
3055         QHeaderView::ResizeMode newSectionResizeMode = headerSectionResizeMode(i);
3056
3057         if (isVisualIndexHidden(i)) {
3058             newSectionLength = 0;
3059         } else {
3060             QHeaderView::ResizeMode resizeMode;
3061             if (useGlobalMode)
3062                 resizeMode = globalMode;
3063             else
3064                 resizeMode = (i == stretchSection
3065                               ? QHeaderView::Stretch
3066                               : newSectionResizeMode);
3067             if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) {
3068                 if (i == lastVisibleSection)
3069                     newSectionLength = qMax(stretchSectionLength, lastSectionSize);
3070                 else
3071                     newSectionLength = stretchSectionLength;
3072                 if (pixelReminder > 0) {
3073                     newSectionLength += 1;
3074                     --pixelReminder;
3075                 }
3076                 section_sizes.removeFirst();
3077             } else {
3078                 newSectionLength = section_sizes.front();
3079                 section_sizes.removeFirst();
3080             }
3081         }
3082
3083         //Q_ASSERT(newSectionLength > 0);
3084         if ((previousSectionResizeMode != newSectionResizeMode
3085             || previousSectionLength != newSectionLength) && i > 0) {
3086             int spanLength = (i - spanStartSection) * previousSectionLength;
3087             createSectionSpan(spanStartSection, i - 1, spanLength, previousSectionResizeMode);
3088             //Q_ASSERT(headerLength() == length);
3089             spanStartSection = i;
3090         }
3091
3092         if (newSectionLength != oldSectionLength)
3093             emit q->sectionResized(logicalIndex(i), oldSectionLength, newSectionLength);
3094
3095         previousSectionLength = newSectionLength;
3096         previousSectionResizeMode = newSectionResizeMode;
3097     }
3098
3099     createSectionSpan(spanStartSection, sectionCount - 1,
3100                       (sectionCount - spanStartSection) * previousSectionLength,
3101                       previousSectionResizeMode);
3102     //Q_ASSERT(headerLength() == length);
3103     resizeRecursionBlock = false;
3104     viewport->update();
3105 }
3106
3107 void QHeaderViewPrivate::createSectionSpan(int start, int end, int size, QHeaderView::ResizeMode mode)
3108 {
3109     // ### the code for merging spans does not merge at all opertuneties
3110     // ### what if the number of sections is reduced ?
3111
3112     SectionSpan span(size, (end - start) + 1, mode);
3113     int start_section = 0;
3114 #ifndef QT_NO_DEBUG
3115     int initial_section_count = headerSectionCount(); // ### debug code
3116 #endif
3117
3118     QList<int> spansToRemove;
3119     for (int i = 0; i < sectionSpans.count(); ++i) {
3120         int end_section = start_section + sectionSpans.at(i).count - 1;
3121         int section_count = sectionSpans.at(i).count;
3122         if (start <= start_section && end > end_section) {
3123             // the existing span is entirely coveded by the new span
3124             spansToRemove.append(i);
3125         } else if (start < start_section && end >= end_section) {
3126             // the existing span is entirely coveded by the new span
3127             spansToRemove.append(i);
3128         } else if (start == start_section && end == end_section) {
3129             // the new span is covered by an existin span
3130             length -= sectionSpans.at(i).size;
3131             length += size;
3132             sectionSpans[i].size = size;
3133             sectionSpans[i].resizeMode = mode;
3134             // ### check if we can merge the section with any of its neighbours
3135             removeSpans(spansToRemove);
3136             Q_ASSERT(initial_section_count == headerSectionCount());
3137             return;
3138         } else if (start > start_section && end < end_section) {
3139             if (sectionSpans.at(i).sectionSize() == span.sectionSize()
3140                 && sectionSpans.at(i).resizeMode == span.resizeMode) {
3141                 Q_ASSERT(initial_section_count == headerSectionCount());
3142                 return;
3143             }
3144             // the new span is in the middle of the old span, so we have to split it
3145             length -= sectionSpans.at(i).size;
3146             int section_size = sectionSpans.at(i).sectionSize();
3147 #ifndef QT_NO_DEBUG
3148             int span_count = sectionSpans.at(i).count;
3149 #endif
3150             QHeaderView::ResizeMode span_mode = sectionSpans.at(i).resizeMode;
3151             // first span
3152             int first_span_count = start - start_section;
3153             int first_span_size = section_size * first_span_count;
3154             sectionSpans[i].count = first_span_count;
3155             sectionSpans[i].size = first_span_size;
3156             sectionSpans[i].resizeMode = span_mode;
3157             length += first_span_size;
3158             // middle span (the new span)
3159 #ifndef QT_NO_DEBUG
3160             int mid_span_count = span.count;
3161 #endif
3162             int mid_span_size = span.size;
3163             sectionSpans.insert(i + 1, span);
3164             length += mid_span_size;
3165             // last span
3166             int last_span_count = end_section - end;
3167             int last_span_size = section_size * last_span_count;
3168             sectionSpans.insert(i + 2, SectionSpan(last_span_size, last_span_count, span_mode));
3169             length += last_span_size;
3170             Q_ASSERT(span_count == first_span_count + mid_span_count + last_span_count);
3171             removeSpans(spansToRemove);
3172             Q_ASSERT(initial_section_count == headerSectionCount());
3173             return;
3174         } else if (start > start_section && start <= end_section && end >= end_section) {
3175             // the new span covers the last part of the existing span
3176             length -= sectionSpans.at(i).size;
3177             int removed_count = (end_section - start + 1);
3178             int span_count = sectionSpans.at(i).count - removed_count;
3179             int section_size = sectionSpans.at(i).sectionSize();
3180             int span_size = section_size * span_count;
3181             sectionSpans[i].count = span_count;
3182             sectionSpans[i].size = span_size;
3183             length += span_size;
3184             if (end == end_section) {
3185                 sectionSpans.insert(i + 1, span); // insert after
3186                 length += span.size;
3187                 removeSpans(spansToRemove);
3188                 Q_ASSERT(initial_section_count == headerSectionCount());
3189                 return;
3190             }
3191         } else if (end < end_section && end >= start_section && start <= start_section) {
3192             // the new span covers the first part of the existing span
3193             length -= sectionSpans.at(i).size;
3194             int removed_count = (end - start_section + 1);
3195             int section_size = sectionSpans.at(i).sectionSize();
3196             int span_count = sectionSpans.at(i).count - removed_count;
3197             int span_size = section_size * span_count;
3198             sectionSpans[i].count = span_count;
3199             sectionSpans[i].size = span_size;
3200             length += span_size;
3201             sectionSpans.insert(i, span); // insert before
3202             length += span.size;
3203             removeSpans(spansToRemove);
3204             Q_ASSERT(initial_section_count == headerSectionCount());
3205             return;
3206         }
3207         start_section += section_count;
3208     }
3209
3210     // ### adding and removing _ sections_  in addition to spans
3211     // ### add some more checks here
3212
3213     if (spansToRemove.isEmpty()) {
3214         if (!sectionSpans.isEmpty()
3215             && sectionSpans.last().sectionSize() == span.sectionSize()
3216             && sectionSpans.last().resizeMode == span.resizeMode) {
3217             length += span.size;
3218             int last = sectionSpans.count() - 1;
3219             sectionSpans[last].count += span.count;
3220             sectionSpans[last].size += span.size;
3221             sectionSpans[last].resizeMode = span.resizeMode;
3222         } else {
3223             length += span.size;
3224             sectionSpans.append(span);
3225         }
3226     } else {
3227         removeSpans(spansToRemove);
3228         length += span.size;
3229         sectionSpans.insert(spansToRemove.first(), span);
3230         //Q_ASSERT(initial_section_count == headerSectionCount());
3231     }
3232 }
3233
3234 void QHeaderViewPrivate::removeSectionsFromSpans(int start, int end)
3235 {
3236     // remove sections
3237     int start_section = 0;
3238     QList<int> spansToRemove;
3239     for (int i = 0; i < sectionSpans.count(); ++i) {
3240         int end_section = start_section + sectionSpans.at(i).count - 1;
3241         int section_size = sectionSpans.at(i).sectionSize();
3242         int section_count = sectionSpans.at(i).count;
3243         if (start <= start_section && end >= end_section) {
3244             // the change covers the entire span
3245             spansToRemove.append(i);
3246             if (end == end_section)
3247                 break;
3248         } else if (start > start_section && end < end_section) {
3249             // all the removed sections are inside the span
3250             int change = (end - start + 1);
3251             sectionSpans[i].count -= change;
3252             sectionSpans[i].size = section_size * sectionSpans.at(i).count;
3253             length -= (change * section_size);
3254             break;
3255         } else if (start >= start_section && start <= end_section) {
3256             // the some of the removed sections are inside the span,at the end
3257             int change = qMin(end_section - start + 1, end - start + 1);
3258             sectionSpans[i].count -= change;
3259             sectionSpans[i].size = section_size * sectionSpans.at(i).count;
3260             start += change;
3261             length -= (change * section_size);
3262             // the change affects several spans
3263         } else if (end >= start_section && end <= end_section) {
3264             // the some of the removed sections are inside the span, at the beginning
3265             int change = qMin((end - start_section + 1), end - start + 1);
3266             sectionSpans[i].count -= change;
3267             sectionSpans[i].size = section_size * sectionSpans.at(i).count;
3268             length -= (change * section_size);
3269             break;
3270         }
3271         start_section += section_count;
3272     }
3273
3274     for (int i = spansToRemove.count() - 1; i >= 0; --i) {
3275         int s = spansToRemove.at(i);
3276         length -= sectionSpans.at(s).size;
3277         sectionSpans.remove(s);
3278         // ### merge remaining spans
3279     }
3280 }
3281
3282 void QHeaderViewPrivate::clear()
3283 {
3284     if (state != NoClear) {
3285     length = 0;
3286     sectionCount = 0;
3287     visualIndices.clear();
3288     logicalIndices.clear();
3289     sectionSelected.clear();
3290     sectionHidden.clear();
3291     hiddenSectionSize.clear();
3292     sectionSpans.clear();
3293     invalidateCachedSizeHint();
3294     }
3295 }
3296
3297 void QHeaderViewPrivate::flipSortIndicator(int section)
3298 {
3299     Q_Q(QHeaderView);
3300     Qt::SortOrder sortOrder;
3301     if (sortIndicatorSection == section) {
3302         sortOrder = (sortIndicatorOrder == Qt::DescendingOrder) ? Qt::AscendingOrder : Qt::DescendingOrder;
3303     } else {
3304         const QVariant value = model->headerData(section, orientation, Qt::InitialSortOrderRole);
3305         if (value.canConvert(QVariant::Int))
3306             sortOrder = static_cast<Qt::SortOrder>(value.toInt());
3307         else
3308             sortOrder = Qt::AscendingOrder;
3309     }
3310     q->setSortIndicator(section, sortOrder);
3311 }
3312
3313 void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
3314 {
3315     Q_Q(QHeaderView);
3316     const int minimumSize = q->minimumSectionSize();
3317     const int oldSize = headerSectionSize(visual);
3318     int delta = newSize - oldSize;
3319
3320     if (delta > 0) { // larger
3321         bool sectionResized = false;
3322
3323         // restore old section sizes
3324         for (int i = firstCascadingSection; i < visual; ++i) {
3325             if (cascadingSectionSize.contains(i)) {
3326                 int currentSectionSize = headerSectionSize(i);
3327                 int originalSectionSize = cascadingSectionSize.value(i);
3328                 if (currentSectionSize < originalSectionSize) {
3329                     int newSectionSize = currentSectionSize + delta;
3330                     resizeSectionSpan(i, currentSectionSize, newSectionSize);
3331                     if (newSectionSize >= originalSectionSize && false)
3332                         cascadingSectionSize.remove(i); // the section is now restored
3333                     sectionResized = true;
3334                     break;
3335                 }
3336             }
3337
3338         }
3339
3340         // resize the section
3341         if (!sectionResized) {
3342             newSize = qMax(newSize, minimumSize);
3343             if (oldSize != newSize)
3344                 resizeSectionSpan(visual, oldSize, newSize);
3345         }
3346
3347         // cascade the section size change
3348         for (int i = visual + 1; i < sectionCount; ++i) {
3349             if (!sectionIsCascadable(i))
3350                 continue;
3351             int currentSectionSize = headerSectionSize(i);
3352             if (currentSectionSize <= minimumSize)
3353                 continue;
3354             int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
3355             //qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
3356             resizeSectionSpan(i, currentSectionSize, newSectionSize);
3357             saveCascadingSectionSize(i, currentSectionSize);
3358             delta = delta - (currentSectionSize - newSectionSize);
3359             //qDebug() << "new delta" << delta;
3360             //if (newSectionSize != minimumSize)
3361             if (delta <= 0)
3362                 break;
3363         }
3364     } else { // smaller
3365         bool sectionResized = false;
3366
3367         // restore old section sizes
3368         for (int i = lastCascadingSection; i > visual; --i) {
3369             if (!cascadingSectionSize.contains(i))
3370                 continue;
3371             int currentSectionSize = headerSectionSize(i);
3372             int originalSectionSize = cascadingSectionSize.value(i);
3373             if (currentSectionSize >= originalSectionSize)
3374                 continue;
3375             int newSectionSize = currentSectionSize - delta;
3376             resizeSectionSpan(i, currentSectionSize, newSectionSize);
3377             if (newSectionSize >= originalSectionSize && false) {
3378                 //qDebug() << "section" << i << "restored to" << originalSectionSize;
3379                 cascadingSectionSize.remove(i); // the section is now restored
3380             }
3381             sectionResized = true;
3382             break;
3383         }
3384
3385         // resize the section
3386         resizeSectionSpan(visual, oldSize, qMax(newSize, minimumSize));
3387
3388         // cascade the section size change
3389         if (delta < 0 && newSize < minimumSize) {
3390             for (int i = visual - 1; i >= 0; --i) {
3391                 if (!sectionIsCascadable(i))
3392                     continue;
3393                 int sectionSize = headerSectionSize(i);
3394                 if (sectionSize <= minimumSize)
3395                     continue;
3396                 resizeSectionSpan(i, sectionSize, qMax(sectionSize + delta, minimumSize));
3397                 saveCascadingSectionSize(i, sectionSize);
3398                 break;
3399             }
3400         }
3401
3402         // let the next section get the space from the resized section
3403         if (!sectionResized) {
3404             for (int i = visual + 1; i < sectionCount; ++i) {
3405                 if (!sectionIsCascadable(i))
3406                     continue;
3407                 int currentSectionSize = headerSectionSize(i);
3408                 int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
3409                 resizeSectionSpan(i, currentSectionSize, newSectionSize);
3410                 break;
3411             }
3412         }
3413     }
3414
3415     if (hasAutoResizeSections())
3416         doDelayedResizeSections();
3417
3418     viewport->update();
3419 }
3420
3421 void QHeaderViewPrivate::setDefaultSectionSize(int size)
3422 {
3423     Q_Q(QHeaderView);
3424     defaultSectionSize = size;
3425     int currentVisualIndex = 0;
3426     for (int i = 0; i < sectionSpans.count(); ++i) {
3427         QHeaderViewPrivate::SectionSpan &span = sectionSpans[i];
3428         if (span.size > 0) {
3429             //we resize it if it is not hidden (ie size > 0)
3430             const int newSize = span.count * size;
3431             if (newSize != span.size) {
3432                 length += newSize - span.size; //the whole length is changed
3433                 const int oldSectionSize = span.sectionSize();
3434                 span.size = span.count * size;
3435                 for (int i = currentVisualIndex; i < currentVisualIndex + span.count; ++i) {
3436                     emit q->sectionResized(logicalIndex(i), oldSectionSize, size);
3437                 }
3438             }
3439         }
3440         currentVisualIndex += span.count;
3441     }
3442 }
3443
3444 void QHeaderViewPrivate::resizeSectionSpan(int visualIndex, int oldSize, int newSize)
3445 {
3446     Q_Q(QHeaderView);
3447     QHeaderView::ResizeMode mode = headerSectionResizeMode(visualIndex);
3448     createSectionSpan(visualIndex, visualIndex, newSize, mode);
3449     emit q->sectionResized(logicalIndex(visualIndex), oldSize, newSize);
3450 }
3451
3452 int QHeaderViewPrivate::headerSectionSize(int visual) const
3453 {
3454     // ### stupid iteration
3455     int section_start = 0;
3456     const int sectionSpansCount = sectionSpans.count();
3457     for (int i = 0; i < sectionSpansCount; ++i) {
3458         const QHeaderViewPrivate::SectionSpan &currentSection = sectionSpans.at(i);
3459         int section_end = section_start + currentSection.count - 1;
3460         if (visual >= section_start && visual <= section_end)
3461             return currentSection.sectionSize();
3462         section_start = section_end + 1;
3463     }
3464     return -1;
3465 }
3466
3467 int QHeaderViewPrivate::headerSectionPosition(int visual) const
3468 {
3469     // ### stupid iteration
3470     int section_start = 0;
3471     int span_position = 0;
3472     const int sectionSpansCount = sectionSpans.count();
3473     for (int i = 0; i < sectionSpansCount; ++i) {
3474         const QHeaderViewPrivate::SectionSpan &currentSection = sectionSpans.at(i);
3475         int section_end = section_start + currentSection.count - 1;
3476         if (visual >= section_start && visual <= section_end)
3477             return span_position + (visual - section_start) * currentSection.sectionSize();
3478         section_start = section_end + 1;
3479         span_position += currentSection.size;
3480     }
3481     return -1;
3482 }
3483
3484 int QHeaderViewPrivate::headerVisualIndexAt(int position) const
3485 {
3486     // ### stupid iteration
3487     int span_start_section = 0;
3488     int span_position = 0;
3489     const int sectionSpansCount = sectionSpans.count();
3490     for (int i = 0; i < sectionSpansCount; ++i) {
3491         const QHeaderViewPrivate::SectionSpan &currentSection = sectionSpans.at(i);
3492         int next_span_start_section = span_start_section + currentSection.count;
3493         int next_span_position = span_position + currentSection.size;
3494         if (position == span_position && currentSection.size > 0)
3495             return span_start_section;
3496         if (position > span_position && position < next_span_position) {
3497             int position_in_span = position - span_position;
3498             return span_start_section + (position_in_span / currentSection.sectionSize());
3499         }
3500         span_start_section = next_span_start_section;
3501         span_position = next_span_position;
3502     }
3503     return -1;
3504 }
3505
3506 void QHeaderViewPrivate::setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode)
3507 {
3508     int size = headerSectionSize(visual);
3509     createSectionSpan(visual, visual, size, mode);
3510 }
3511
3512 QHeaderView::ResizeMode QHeaderViewPrivate::headerSectionResizeMode(int visual) const
3513 {
3514     int span = sectionSpanIndex(visual);
3515     if (span == -1)
3516         return globalResizeMode;
3517     return sectionSpans.at(span).resizeMode;
3518 }
3519
3520 void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode)
3521 {
3522     globalResizeMode = mode;
3523     for (int i = 0; i < sectionSpans.count(); ++i)
3524         sectionSpans[i].resizeMode = mode;
3525 }
3526
3527 int QHeaderViewPrivate::viewSectionSizeHint(int logical) const
3528 {
3529     if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent)) {
3530         return (orientation == Qt::Horizontal
3531                 ? view->sizeHintForColumn(logical)
3532                 : view->sizeHintForRow(logical));
3533     }
3534     return 0;
3535 }
3536
3537 int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const
3538 {
3539     if (hiddenSectionSize.count() > 0) {
3540         int adjustedVisualIndex = visualIndex;
3541         int currentVisualIndex = 0;
3542         for (int i = 0; i < sectionSpans.count(); ++i) {
3543             if (sectionSpans.at(i).size == 0)
3544                 adjustedVisualIndex += sectionSpans.at(i).count;
3545             else
3546                 currentVisualIndex += sectionSpans.at(i).count;
3547             if (currentVisualIndex >= visualIndex)
3548                 break;
3549         }
3550         visualIndex = adjustedVisualIndex;
3551     }
3552     return visualIndex;