src/gui/itemviews/qheaderview.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/itemviews/qheaderview.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3579 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qheaderview.h"
+
+#ifndef QT_NO_ITEMVIEWS
+#include <qbitarray.h>
+#include <qbrush.h>
+#include <qdebug.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qscrollbar.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qvector.h>
+#include <qapplication.h>
+#include <qvarlengtharray.h>
+#include <qabstractitemdelegate.h>
+#include <qvariant.h>
+#include <private/qheaderview_p.h>
+#include <private/qabstractitemmodel_p.h>
+
+#ifndef QT_NO_DATASTREAM
+#include <qdatastream.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DATASTREAM
+QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionSpan &span)
+{
+    span.write(out);
+    return out;
+}
+
+QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionSpan &span)
+{
+    span.read(in);
+    return in;
+}
+#endif // QT_NO_DATASTREAM
+
+
+/*!
+    \class QHeaderView
+
+    \brief The QHeaderView class provides a header row or header column for
+    item views.
+
+    \ingroup model-view
+
+
+    A QHeaderView displays the headers used in item views such as the
+    QTableView and QTreeView classes. It takes the place of Qt3's \c QHeader
+    class previously used for the same purpose, but uses the Qt's model/view
+    architecture for consistency with the item view classes.
+
+    The QHeaderView class is one of the \l{Model/View Classes} and is part of
+    Qt's \l{Model/View Programming}{model/view framework}.
+
+    The header gets the data for each section from the model using the
+    QAbstractItemModel::headerData() function. You can set the data by using
+    QAbstractItemModel::setHeaderData().
+
+    Each header has an orientation() and a number of sections, given by the
+    count() function. A section refers to a part of the header - either a row
+    or a column, depending on the orientation.
+
+    Sections can be moved and resized using moveSection() and resizeSection();
+    they can also be hidden and shown with hideSection() and showSection().
+
+    Each section of a header is described by a section ID, specified by its
+    section(), and can be located at a particular visualIndex() in the header.
+    A section can have a sort indicator set with setSortIndicator(); this
+    indicates whether the items in the associated item view will be sorted in
+    the order given by the section.
+
+    For a horizontal header the section is equivalent to a column in the model,
+    and for a vertical header the section is equivalent to a row in the model.
+
+    \section1 Moving Header Sections
+
+    A header can be fixed in place, or made movable with setMovable(). It can
+    be made clickable with setClickable(), and has resizing behavior in
+    accordance with setResizeMode().
+
+    \note Double-clicking on a header to resize a section only applies for
+    visible rows.
+
+    A header will emit sectionMoved() if the user moves a section,
+    sectionResized() if the user resizes a section, and sectionClicked() as
+    well as sectionHandleDoubleClicked() in response to mouse clicks. A header
+    will also emit sectionCountChanged() and sectionAutoResize().
+
+    You can identify a section using the logicalIndex() and logicalIndexAt()
+    functions, or by its index position, using the visualIndex() and
+    visualIndexAt() functions. The visual index will change if a section is
+    moved, but the logical index will not change.
+
+    \section1 Appearance
+
+    QTableWidget and QTableView create default headers. If you want
+    the headers to be visible, you can use \l{QFrame::}{setVisible()}.
+
+    Not all \l{Qt::}{ItemDataRole}s will have an effect on a
+    QHeaderView. If you need to draw other roles, you can subclass
+    QHeaderView and reimplement \l{QHeaderView::}{paintEvent()}.
+    QHeaderView respects the following item data roles:
+    \l{Qt::}{TextAlignmentRole}, \l{Qt::}{DisplayRole},
+    \l{Qt::}{FontRole}, \l{Qt::}{DecorationRole},
+    \l{Qt::}{ForegroundRole}, and \l{Qt::}{BackgroundRole}.
+
+    \note Each header renders the data for each section itself, and does not
+    rely on a delegate. As a result, calling a header's setItemDelegate()
+    function will have no effect.
+
+    \sa {Model/View Programming}, QListView, QTableView, QTreeView
+*/
+
+/*!
+    \enum QHeaderView::ResizeMode
+
+    The resize mode specifies the behavior of the header sections. It can be
+    set on the entire header view or on individual sections using
+    setResizeMode().
+
+    \value Interactive The user can resize the section. The section can also be
+           resized programmatically using resizeSection().  The section size
+           defaults to \l defaultSectionSize. (See also
+           \l cascadingSectionResizes.)
+
+    \value Fixed The user cannot resize the section. The section can only be
+           resized programmatically using resizeSection(). The section size
+           defaults to \l defaultSectionSize.
+
+    \value Stretch QHeaderView will automatically resize the section to fill
+           the available space. The size cannot be changed by the user or
+           programmatically.
+
+    \value ResizeToContents QHeaderView will automatically resize the section
+           to its optimal size based on the contents of the entire column or
+           row. The size cannot be changed by the user or programmatically.
+           (This value was introduced in 4.2)
+
+    The following values are obsolete:
+    \value Custom Use Fixed instead.
+
+    \sa setResizeMode() stretchLastSection minimumSectionSize
+*/
+
+/*!
+    \fn void QHeaderView::sectionMoved(int logicalIndex, int oldVisualIndex,
+    int newVisualIndex)
+
+    This signal is emitted when a section is moved. The section's logical index
+    is specified by \a logicalIndex, the old index by \a oldVisualIndex, and
+    the new index position by \a newVisualIndex.
+
+    \sa moveSection()
+*/
+
+/*!
+    \fn void QHeaderView::sectionResized(int logicalIndex, int oldSize,
+    int newSize)
+
+    This signal is emitted when a section is resized. The section's logical
+    number is specified by \a logicalIndex, the old size by \a oldSize, and the
+    new size by \a newSize.
+
+    \sa resizeSection()
+*/
+
+/*!
+    \fn void QHeaderView::sectionPressed(int logicalIndex)
+
+    This signal is emitted when a section is pressed. The section's logical
+    index is specified by \a logicalIndex.
+
+    \sa setClickable()
+*/
+
+/*!
+    \fn void QHeaderView::sectionClicked(int logicalIndex)
+
+    This signal is emitted when a section is clicked. The section's logical
+    index is specified by \a logicalIndex.
+
+    Note that the sectionPressed signal will also be emitted.
+
+    \sa setClickable(), sectionPressed()
+*/
+
+/*!
+    \fn void QHeaderView::sectionEntered(int logicalIndex)
+    \since 4.3
+
+    This signal is emitted when the cursor moves over the section and the left
+    mouse button is pressed. The section's logical index is specified by
+    \a logicalIndex.
+
+    \sa setClickable(), sectionPressed()
+*/
+
+/*!
+    \fn void QHeaderView::sectionDoubleClicked(int logicalIndex)
+
+    This signal is emitted when a section is double-clicked. The section's
+    logical index is specified by \a logicalIndex.
+
+    \sa setClickable()
+*/
+
+/*!
+    \fn void QHeaderView::sectionCountChanged(int oldCount, int newCount)
+
+    This signal is emitted when the number of sections changes, i.e., when
+    sections are added or deleted. The original count is specified by
+    \a oldCount, and the new count by \a newCount.
+
+    \sa count(), length(), headerDataChanged()
+*/
+
+/*!
+    \fn void QHeaderView::sectionHandleDoubleClicked(int logicalIndex)
+
+    This signal is emitted when a section is double-clicked. The section's
+    logical index is specified by \a logicalIndex.
+
+    \sa setClickable()
+*/
+
+/*!
+    \fn void QHeaderView::sortIndicatorChanged(int logicalIndex,
+    Qt::SortOrder order)
+    \since 4.3
+
+    This signal is emitted when the section containing the sort indicator or
+    the order indicated is changed. The section's logical index is specified
+    by \a logicalIndex and the sort order is specified by \a order.
+
+    \sa setSortIndicator()
+*/
+
+/*!
+    \fn void QHeaderView::sectionAutoResize(int logicalIndex,
+    QHeaderView::ResizeMode mode)
+
+    This signal is emitted when a section is automatically resized. The
+    section's logical index is specified by \a logicalIndex, and the resize
+    mode by \a mode.
+
+    \sa setResizeMode(), stretchLastSection()
+*/
+// ### Qt 5: change to sectionAutoResized()
+
+/*!
+    \fn void QHeaderView::geometriesChanged()
+    \since 4.2
+
+    This signal is emitted when the header's geometries have changed.
+*/
+
+/*!
+    \property QHeaderView::highlightSections
+    \brief whether the sections containing selected items are highlighted
+
+    By default, this property is false.
+*/
+
+/*!
+    Creates a new generic header with the given \a orientation and \a parent.
+*/
+QHeaderView::QHeaderView(Qt::Orientation orientation, QWidget *parent)
+    : QAbstractItemView(*new QHeaderViewPrivate, parent)
+{
+    Q_D(QHeaderView);
+    d->setDefaultValues(orientation);
+    initialize();
+}
+
+/*!
+  \internal
+*/
+QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
+                         Qt::Orientation orientation, QWidget *parent)
+    : QAbstractItemView(dd, parent)
+{
+    Q_D(QHeaderView);
+    d->setDefaultValues(orientation);
+    initialize();
+}
+
+/*!
+  Destroys the header.
+*/
+
+QHeaderView::~QHeaderView()
+{
+}
+
+/*!
+  \internal
+*/
+void QHeaderView::initialize()
+{
+    Q_D(QHeaderView);
+    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    setFrameStyle(NoFrame);
+    setFocusPolicy(Qt::NoFocus);
+    d->viewport->setMouseTracking(true);
+    d->viewport->setBackgroundRole(QPalette::Button);
+    d->textElideMode = Qt::ElideNone;
+    delete d->itemDelegate;
+}
+
+/*!
+  \reimp
+*/
+void QHeaderView::setModel(QAbstractItemModel *model)
+{
+    if (model == this->model())
+        return;
+    Q_D(QHeaderView);
+    if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
+    if (d->orientation == Qt::Horizontal) {
+        QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
+                            this, SLOT(sectionsInserted(QModelIndex,int,int)));
+        QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
+                            this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
+        QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+                            this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
+    } else {
+        QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+                            this, SLOT(sectionsInserted(QModelIndex,int,int)));
+        QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+                            this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
+        QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                            this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
+    }
+    QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
+                        this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
+        QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
+                            this, SLOT(_q_layoutAboutToBeChanged()));
+    }
+
+    if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
+        if (d->orientation == Qt::Horizontal) {
+            QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
+                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
+            QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
+                this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
+            QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+                this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
+        } else {
+            QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
+            QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
+            QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
+        }
+        QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
+                         this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
+        QObject::connect(model, SIGNAL(layoutAboutToBeChanged()),
+                         this, SLOT(_q_layoutAboutToBeChanged()));
+    }
+
+    d->state = QHeaderViewPrivate::NoClear;
+    QAbstractItemView::setModel(model);
+    d->state = QHeaderViewPrivate::NoState;
+
+    // Users want to set sizes and modes before the widget is shown.
+    // Thus, we have to initialize when the model is set,
+    // and not lazily like we do in the other views.
+    initializeSections();
+}
+
+/*!
+    Returns the orientation of the header.
+
+    \sa Qt::Orientation
+*/
+
+Qt::Orientation QHeaderView::orientation() const
+{
+    Q_D(const QHeaderView);
+    return d->orientation;
+}
+
+/*!
+    Returns the offset of the header: this is the header's left-most (or
+    top-most for vertical headers) visible pixel.
+
+    \sa setOffset()
+*/
+
+int QHeaderView::offset() const
+{
+    Q_D(const QHeaderView);
+    return d->offset;
+}
+
+/*!
+    \fn void QHeaderView::setOffset(int offset)
+
+    Sets the header's offset to \a offset.
+
+    \sa offset(), length()
+*/
+
+void QHeaderView::setOffset(int newOffset)
+{
+    Q_D(QHeaderView);
+    if (d->offset == (int)newOffset)
+        return;
+    int ndelta = d->offset - newOffset;
+    d->offset = newOffset;
+    if (d->orientation == Qt::Horizontal)
+        d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
+    else
+        d->viewport->scroll(0, ndelta);
+    if (d->state == QHeaderViewPrivate::ResizeSection) {
+        QPoint cursorPos = QCursor::pos();
+        if (d->orientation == Qt::Horizontal)
+            QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
+        else
+            QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
+        d->firstPos += ndelta;
+        d->lastPos += ndelta;
+    }
+}
+
+/*!
+    \since 4.2
+    Sets the offset to the start of the section at the given \a visualIndex.
+
+    \sa setOffset(), sectionPosition()
+*/
+void QHeaderView::setOffsetToSectionPosition(int visualIndex)
+{
+    Q_D(QHeaderView);
+    if (visualIndex > -1 && visualIndex < d->sectionCount) {
+        int position = d->headerSectionPosition(d->adjustedVisualIndex(visualIndex));
+        setOffset(position);
+    }
+}
+
+/*!
+    \since 4.2
+    Sets the offset to make the last section visible.
+
+    \sa setOffset(), sectionPosition(), setOffsetToSectionPosition()
+*/
+void QHeaderView::setOffsetToLastSection()
+{
+    Q_D(const QHeaderView);
+    int size = (d->orientation == Qt::Horizontal ? viewport()->width() : viewport()->height());
+    int position = length() - size;
+    setOffset(position);
+}
+
+/*!
+    Returns the length along the orientation of the header.
+
+    \sa sizeHint(), setResizeMode(), offset()
+*/
+
+int QHeaderView::length() const
+{
+    Q_D(const QHeaderView);
+    //Q_ASSERT(d->headerLength() == d->length);
+    return d->length;
+}
+
+/*!
+    Returns a suitable size hint for this header.
+
+    \sa sectionSizeHint()
+*/
+
+QSize QHeaderView::sizeHint() const
+{
+    Q_D(const QHeaderView);
+    if (d->cachedSizeHint.isValid())
+        return d->cachedSizeHint;
+    d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint
+    const int sectionCount = count();
+
+    // get size hint for the first n sections
+    int i = 0;
+    for (int checked = 0; checked < 100 && i < sectionCount; ++i) {
+        if (isSectionHidden(i))
+            continue;
+        checked++;
+        QSize hint = sectionSizeFromContents(i);
+        d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
+    }
+    // get size hint for the last n sections
+    i = qMax(i, sectionCount - 100 );
+    for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) {
+        if (isSectionHidden(j))
+            continue;
+        checked++;
+        QSize hint = sectionSizeFromContents(j);
+        d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint);
+    }
+    return d->cachedSizeHint;
+}
+
+/*!
+    Returns a suitable size hint for the section specified by \a logicalIndex.
+
+    \sa sizeHint(), defaultSectionSize(), minimumSectionSize(),
+    Qt::SizeHintRole
+*/
+
+int QHeaderView::sectionSizeHint(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    if (isSectionHidden(logicalIndex))
+        return 0;
+    if (logicalIndex < 0 || logicalIndex >= count())
+        return -1;
+    QSize size;
+    QVariant value = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
+    if (value.isValid())
+        size = qvariant_cast<QSize>(value);
+    else
+        size = sectionSizeFromContents(logicalIndex);
+    int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
+    return qMax(minimumSectionSize(), hint);
+}
+
+/*!
+    Returns the visual index of the section that covers the given \a position
+    in the viewport.
+
+    \sa logicalIndexAt()
+*/
+
+int QHeaderView::visualIndexAt(int position) const
+{
+    Q_D(const QHeaderView);
+    int vposition = position;
+    d->executePostedLayout();
+    d->executePostedResize();
+    const int count = d->sectionCount;
+    if (count < 1)
+        return -1;
+
+    if (d->reverse())
+        vposition = d->viewport->width() - vposition;
+    vposition += d->offset;
+
+    if (vposition > d->length)
+        return -1;
+    int visual = d->headerVisualIndexAt(vposition);
+    if (visual < 0)
+        return -1;
+
+    while (d->isVisualIndexHidden(visual)){
+        ++visual;
+        if (visual >= count)
+            return -1;
+    }
+    return visual;
+}
+
+/*!
+    Returns the section that covers the given \a position in the viewport.
+
+    \sa visualIndexAt(), isSectionHidden()
+*/
+
+int QHeaderView::logicalIndexAt(int position) const
+{
+    const int visual = visualIndexAt(position);
+    if (visual > -1)
+        return logicalIndex(visual);
+    return -1;
+}
+
+/*!
+    Returns the width (or height for vertical headers) of the given
+    \a logicalIndex.
+
+    \sa length(), setResizeMode(), defaultSectionSize()
+*/
+
+int QHeaderView::sectionSize(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    if (isSectionHidden(logicalIndex))
+        return 0;
+    if (logicalIndex < 0 || logicalIndex >= count())
+        return 0;
+    int visual = visualIndex(logicalIndex);
+    if (visual == -1)
+        return 0;
+    d->executePostedResize();
+    return d->headerSectionSize(visual);
+}
+
+/*!
+    Returns the section position of the given \a logicalIndex, or -1 if the
+    section is hidden.
+
+    \sa sectionViewportPosition()
+*/
+
+int QHeaderView::sectionPosition(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    int visual = visualIndex(logicalIndex);
+    // in some cases users may change the selections
+    // before we have a chance to do the layout
+    if (visual == -1)
+        return -1;
+    d->executePostedResize();
+    return d->headerSectionPosition(visual);
+}
+
+/*!
+    Returns the section viewport position of the given \a logicalIndex.
+
+    If the section is hidden, the return value is undefined.
+
+    \sa sectionPosition(), isSectionHidden()
+*/
+
+int QHeaderView::sectionViewportPosition(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    if (logicalIndex >= count())
+        return -1;
+    int position = sectionPosition(logicalIndex);
+    if (position < 0)
+        return position; // the section was hidden
+    int offsetPosition = position - d->offset;
+    if (d->reverse())
+        return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
+    return offsetPosition;
+}
+
+/*!
+    \fn int QHeaderView::logicalIndexAt(int x, int y) const
+
+    Returns the logical index of the section at the given coordinate. If the
+    header is horizontal \a x will be used, otherwise \a y will be used to
+    find the logical index.
+*/
+
+/*!
+    \fn int QHeaderView::logicalIndexAt(const QPoint &pos) const
+
+    Returns the logical index of the section at the position given in \a pos.
+    If the header is horizontal the x-coordinate will be used, otherwise the
+    y-coordinate will be used to find the logical index.
+
+    \sa sectionPosition()
+*/
+
+/*!
+    Moves the section at visual index \a from to occupy visual index \a to.
+
+    \sa sectionsMoved()
+*/
+
+void QHeaderView::moveSection(int from, int to)
+{
+    Q_D(QHeaderView);
+
+    d->executePostedLayout();
+    if (from < 0 || from >= d->sectionCount || to < 0 || to >= d->sectionCount)
+        return;
+
+    if (from == to) {
+        int logical = logicalIndex(from);
+        Q_ASSERT(logical != -1);
+        updateSection(logical);
+        return;
+    }
+
+    if (stretchLastSection() &&  to == d->lastVisibleVisualIndex())
+        d->lastSectionSize = sectionSize(from);
+
+    //int oldHeaderLength = length(); // ### for debugging; remove later
+    d->initializeIndexMapping();
+
+    QBitArray sectionHidden = d->sectionHidden;
+    int *visualIndices = d->visualIndices.data();
+    int *logicalIndices = d->logicalIndices.data();
+    int logical = logicalIndices[from];
+    int visual = from;
+
+    int affected_count = qAbs(to - from) + 1;
+    QVarLengthArray<int> sizes(affected_count);
+    QVarLengthArray<ResizeMode> modes(affected_count);
+
+    // move sections and indices
+    if (to > from) {
+        sizes[to - from] = d->headerSectionSize(from);
+        modes[to - from] = d->headerSectionResizeMode(from);
+        while (visual < to) {
+            sizes[visual - from] = d->headerSectionSize(visual + 1);
+            modes[visual - from] = d->headerSectionResizeMode(visual + 1);
+            if (!sectionHidden.isEmpty())
+                sectionHidden.setBit(visual, sectionHidden.testBit(visual + 1));
+            visualIndices[logicalIndices[visual + 1]] = visual;
+            logicalIndices[visual] = logicalIndices[visual + 1];
+            ++visual;
+        }
+    } else {
+        sizes[0] = d->headerSectionSize(from);
+        modes[0] = d->headerSectionResizeMode(from);
+        while (visual > to) {
+            sizes[visual - to] = d->headerSectionSize(visual - 1);
+            modes[visual - to] = d->headerSectionResizeMode(visual - 1);
+            if (!sectionHidden.isEmpty())
+                sectionHidden.setBit(visual, sectionHidden.testBit(visual - 1));
+            visualIndices[logicalIndices[visual - 1]] = visual;
+            logicalIndices[visual] = logicalIndices[visual - 1];
+            --visual;
+        }
+    }
+    if (!sectionHidden.isEmpty()) {
+        sectionHidden.setBit(to, d->sectionHidden.testBit(from));
+        d->sectionHidden = sectionHidden;
+    }
+    visualIndices[logical] = to;
+    logicalIndices[to] = logical;
+
+    //Q_ASSERT(oldHeaderLength == length());
+    // move sizes
+    // ### check for spans of section sizes here
+    if (to > from) {
+        for (visual = from; visual <= to; ++visual) {
+            int size = sizes[visual - from];
+            ResizeMode mode = modes[visual - from];
+            d->createSectionSpan(visual, visual, size, mode);
+        }
+    } else {
+        for (visual = to; visual <= from; ++visual) {
+            int size = sizes[visual - to];
+            ResizeMode mode = modes[visual - to];
+            d->createSectionSpan(visual, visual, size, mode);
+        }
+    }
+    //Q_ASSERT(d->headerLength() == length());
+    //Q_ASSERT(oldHeaderLength == length());
+    //Q_ASSERT(d->logicalIndices.count() == d->sectionCount);
+
+    if (d->hasAutoResizeSections())
+        d->doDelayedResizeSections();
+    d->viewport->update();
+
+    emit sectionMoved(logical, from, to);
+}
+
+/*!
+    \since 4.2
+    Swaps the section at visual index \a first with the section at visual
+    index \a second.
+
+    \sa moveSection()
+*/
+void QHeaderView::swapSections(int first, int second)
+{
+    Q_D(QHeaderView);
+
+    if (first == second)
+        return;
+    d->executePostedLayout();
+    if (first < 0 || first >= d->sectionCount || second < 0 || second >= d->sectionCount)
+        return;
+
+    int firstSize = d->headerSectionSize(first);
+    ResizeMode firstMode = d->headerSectionResizeMode(first);
+    int firstLogical = d->logicalIndex(first);
+
+    int secondSize = d->headerSectionSize(second);
+    ResizeMode secondMode = d->headerSectionResizeMode(second);
+    int secondLogical = d->logicalIndex(second);
+
+    d->createSectionSpan(second, second, firstSize, firstMode);
+    d->createSectionSpan(first, first, secondSize, secondMode);
+
+    d->initializeIndexMapping();
+
+    d->visualIndices[firstLogical] = second;
+    d->logicalIndices[second] = firstLogical;
+
+    d->visualIndices[secondLogical] = first;
+    d->logicalIndices[first] = secondLogical;
+
+    if (!d->sectionHidden.isEmpty()) {
+        bool firstHidden = d->sectionHidden.testBit(first);
+        bool secondHidden = d->sectionHidden.testBit(second);
+        d->sectionHidden.setBit(first, secondHidden);
+        d->sectionHidden.setBit(second, firstHidden);
+    }
+
+    d->viewport->update();
+    emit sectionMoved(firstLogical, first, second);
+    emit sectionMoved(secondLogical, second, first);
+}
+
+/*!
+    \fn void QHeaderView::resizeSection(int logicalIndex, int size)
+
+    Resizes the section specified by \a logicalIndex to \a size measured in
+    pixels.
+
+    \sa sectionResized(), resizeMode(), sectionSize()
+*/
+
+void QHeaderView::resizeSection(int logical, int size)
+{
+    Q_D(QHeaderView);
+    if (logical < 0 || logical >= count())
+        return;
+
+    if (isSectionHidden(logical)) {
+        d->hiddenSectionSize.insert(logical, size);
+        return;
+    }
+
+    int visual = visualIndex(logical);
+    if (visual == -1)
+        return;
+
+    int oldSize = d->headerSectionSize(visual);
+    if (oldSize == size)
+        return;
+
+    d->executePostedLayout();
+    d->invalidateCachedSizeHint();
+
+    if (stretchLastSection() && visual == d->lastVisibleVisualIndex())
+        d->lastSectionSize = size;
+
+    if (size != oldSize)
+        d->createSectionSpan(visual, visual, size, d->headerSectionResizeMode(visual));
+
+    int w = d->viewport->width();
+    int h = d->viewport->height();
+    int pos = sectionViewportPosition(logical);
+    QRect r;
+    if (d->orientation == Qt::Horizontal)
+        if (isRightToLeft())
+            r.setRect(0, 0, pos + size, h);
+        else
+            r.setRect(pos, 0, w - pos, h);
+    else
+        r.setRect(0, pos, w, h - pos);
+
+    if (d->hasAutoResizeSections()) {
+        d->doDelayedResizeSections();
+        r = d->viewport->rect();
+    }
+    d->viewport->update(r.normalized());
+    emit sectionResized(logical, oldSize, size);
+}
+
+/*!
+    Resizes the sections according to the given \a mode, ignoring the current
+    resize mode.
+
+    \sa resizeMode(), sectionResized()
+*/
+
+void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
+{
+    Q_D(QHeaderView);
+    d->resizeSections(mode, true);
+}
+
+/*!
+    \fn void QHeaderView::hideSection(int logicalIndex)
+    Hides the section specified by \a logicalIndex.
+
+    \sa showSection(), isSectionHidden(), hiddenSectionCount(),
+    setSectionHidden()
+*/
+
+/*!
+    \fn void QHeaderView::showSection(int logicalIndex)
+    Shows the section specified by \a logicalIndex.
+
+    \sa hideSection(), isSectionHidden(), hiddenSectionCount(),
+    setSectionHidden()
+*/
+
+/*!
+    Returns true if the section specified by \a logicalIndex is explicitly
+    hidden from the user; otherwise returns false.
+
+    \sa hideSection(), showSection(), setSectionHidden(), hiddenSectionCount()
+*/
+
+bool QHeaderView::isSectionHidden(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    d->executePostedLayout();
+    if (logicalIndex >= d->sectionHidden.count() || logicalIndex < 0 || logicalIndex >= d->sectionCount)
+        return false;
+    int visual = visualIndex(logicalIndex);
+    Q_ASSERT(visual != -1);
+    return d->sectionHidden.testBit(visual);
+}
+
+/*!
+    \since 4.1
+
+    Returns the number of sections in the header that has been hidden.
+
+    \sa setSectionHidden(), isSectionHidden()
+*/
+int QHeaderView::hiddenSectionCount() const
+{
+    Q_D(const QHeaderView);
+    return d->hiddenSectionSize.count();
+}
+
+/*!
+  If \a hide is true the section specified by \a logicalIndex is hidden;
+  otherwise the section is shown.
+
+  \sa isSectionHidden(), hiddenSectionCount()
+*/
+
+void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
+{
+    Q_D(QHeaderView);
+    if (logicalIndex < 0 || logicalIndex >= count())
+        return;
+
+    d->executePostedLayout();
+    int visual = visualIndex(logicalIndex);
+    Q_ASSERT(visual != -1);
+    if (hide == d->isVisualIndexHidden(visual))
+        return;
+    if (hide) {
+        int size = d->headerSectionSize(visual);
+        if (!d->hasAutoResizeSections())
+            resizeSection(logicalIndex, 0);
+        d->hiddenSectionSize.insert(logicalIndex, size);
+        if (d->sectionHidden.count() < count())
+            d->sectionHidden.resize(count());
+        d->sectionHidden.setBit(visual, true);
+        if (d->hasAutoResizeSections())
+            d->doDelayedResizeSections();
+    } else {
+        int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
+        d->hiddenSectionSize.remove(logicalIndex);
+        if (d->hiddenSectionSize.isEmpty()) {
+            d->sectionHidden.clear();
+        } else {
+            Q_ASSERT(visual <= d->sectionHidden.count());
+            d->sectionHidden.setBit(visual, false);
+        }
+        resizeSection(logicalIndex, size);
+    }
+}
+
+/*!
+    Returns the number of sections in the header.
+
+    \sa  sectionCountChanged(), length()
+*/
+
+int QHeaderView::count() const
+{
+    Q_D(const QHeaderView);
+    //Q_ASSERT(d->sectionCount == d->headerSectionCount());
+    // ### this may affect the lazy layout
+    d->executePostedLayout();
+    return d->sectionCount;
+}
+
+/*!
+    Returns the visual index position of the section specified by the given
+    \a logicalIndex, or -1 otherwise.
+
+    Hidden sections still have valid visual indexes.
+
+    \sa logicalIndex()
+*/
+
+int QHeaderView::visualIndex(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    if (logicalIndex < 0)
+        return -1;
+    d->executePostedLayout();
+    if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
+        if (logicalIndex < d->sectionCount)
+            return logicalIndex;
+    } else if (logicalIndex < d->visualIndices.count()) {
+        int visual = d->visualIndices.at(logicalIndex);
+        Q_ASSERT(visual < d->sectionCount);
+        return visual;
+    }
+    return -1;
+}
+
+/*!
+    Returns the logicalIndex for the section at the given \a visualIndex
+    position, or -1 if visualIndex < 0 or visualIndex >= QHeaderView::count().
+
+    Note that the visualIndex is not affected by hidden sections.
+
+    \sa visualIndex(), sectionPosition()
+*/
+
+int QHeaderView::logicalIndex(int visualIndex) const
+{
+    Q_D(const QHeaderView);
+    if (visualIndex < 0 || visualIndex >= d->sectionCount)
+        return -1;
+    return d->logicalIndex(visualIndex);
+}
+
+/*!
+    If \a movable is true, the header may be moved by the user; otherwise it
+    is fixed in place.
+
+    \sa isMovable(), sectionMoved()
+*/
+
+// ### Qt 5: change to setSectionsMovable()
+void QHeaderView::setMovable(bool movable)
+{
+    Q_D(QHeaderView);
+    d->movableSections = movable;
+}
+
+/*!
+    Returns true if the header can be moved by the user; otherwise returns
+    false.
+
+    \sa setMovable()
+*/
+
+// ### Qt 5: change to sectionsMovable()
+bool QHeaderView::isMovable() const
+{
+    Q_D(const QHeaderView);
+    return d->movableSections;
+}
+
+/*!
+    If \a clickable is true, the header will respond to single clicks.
+
+    \sa isClickable(), sectionClicked(), sectionPressed(),
+    setSortIndicatorShown()
+*/
+
+// ### Qt 5: change to setSectionsClickable()
+void QHeaderView::setClickable(bool clickable)
+{
+    Q_D(QHeaderView);
+    d->clickableSections = clickable;
+}
+
+/*!
+    Returns true if the header is clickable; otherwise returns false. A
+    clickable header could be set up to allow the user to change the
+    representation of the data in the view related to the header.
+
+    \sa setClickable()
+*/
+
+// ### Qt 5: change to sectionsClickable()
+bool QHeaderView::isClickable() const
+{
+    Q_D(const QHeaderView);
+    return d->clickableSections;
+}
+
+void QHeaderView::setHighlightSections(bool highlight)
+{
+    Q_D(QHeaderView);
+    d->highlightSelected = highlight;
+}
+
+bool QHeaderView::highlightSections() const
+{
+    Q_D(const QHeaderView);
+    return d->highlightSelected;
+}
+
+/*!
+    Sets the constraints on how the header can be resized to those described
+    by the given \a mode.
+
+    \sa resizeMode(), length(), sectionResized(), sectionAutoResize()
+*/
+
+void QHeaderView::setResizeMode(ResizeMode mode)
+{
+    Q_D(QHeaderView);
+    initializeSections();
+    d->stretchSections = (mode == Stretch ? count() : 0);
+    d->contentsSections =  (mode == ResizeToContents ? count() : 0);
+    d->setGlobalHeaderResizeMode(mode);
+    if (d->hasAutoResizeSections())
+        d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
+}
+
+/*!
+    \overload
+
+    Sets the constraints on how the section specified by \a logicalIndex in
+    the header can be resized to those described by the given \a mode. The logical
+    index should exist at the time this function is called.
+
+    \note This setting will be ignored for the last section if the stretchLastSection
+    property is set to true. This is the default for the horizontal headers provided
+    by QTreeView.
+
+    \sa setStretchLastSection()
+*/
+
+// ### Qt 5: change to setSectionResizeMode()
+void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
+{
+    Q_D(QHeaderView);
+    int visual = visualIndex(logicalIndex);
+    Q_ASSERT(visual != -1);
+
+    ResizeMode old = d->headerSectionResizeMode(visual);
+    d->setHeaderSectionResizeMode(visual, mode);
+
+    if (mode == Stretch && old != Stretch)
+        ++d->stretchSections;
+    else if (mode == ResizeToContents && old != ResizeToContents)
+        ++d->contentsSections;
+    else if (mode != Stretch && old == Stretch)
+        --d->stretchSections;
+    else if (mode != ResizeToContents && old == ResizeToContents)
+        --d->contentsSections;
+
+    if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
+        d->doDelayedResizeSections(); // section sizes may change as a result of the new mode
+}
+
+/*!
+    Returns the resize mode that applies to the section specified by the given
+    \a logicalIndex.
+
+    \sa setResizeMode()
+*/
+
+QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    int visual = visualIndex(logicalIndex);
+    if (visual == -1)
+        return Fixed; //the default value
+    return d->headerSectionResizeMode(visual);
+}
+
+/*!
+    \since 4.1
+
+    Returns the number of sections that are set to resize mode stretch. In
+    views, this can be used to see if the headerview needs to resize the
+    sections when the view's geometry changes.
+
+    \sa stretchLastSection, resizeMode()
+*/
+
+int QHeaderView::stretchSectionCount() const
+{
+    Q_D(const QHeaderView);
+    return d->stretchSections;
+}
+
+/*!
+  \property QHeaderView::showSortIndicator
+  \brief whether the sort indicator is shown
+
+  By default, this property is false.
+
+  \sa setClickable()
+*/
+
+void QHeaderView::setSortIndicatorShown(bool show)
+{
+    Q_D(QHeaderView);
+    if (d->sortIndicatorShown == show)
+        return;
+
+    d->sortIndicatorShown = show;
+
+    if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
+        return;
+
+    if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents)
+        resizeSections();
+
+    d->viewport->update();
+}
+
+bool QHeaderView::isSortIndicatorShown() const
+{
+    Q_D(const QHeaderView);
+    return d->sortIndicatorShown;
+}
+
+/*!
+    Sets the sort indicator for the section specified by the given
+    \a logicalIndex in the direction specified by \a order, and removes the
+    sort indicator from any other section that was showing it.
+
+    \a logicalIndex may be -1, in which case no sort indicator will be shown
+    and the model will return to its natural, unsorted order. Note that not
+    all models support this and may even crash in this case.
+
+    \sa sortIndicatorSection() sortIndicatorOrder()
+*/
+
+void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
+{
+    Q_D(QHeaderView);
+
+    // This is so that people can set the position of the sort indicator before the fill the model
+    int old = d->sortIndicatorSection;
+    d->sortIndicatorSection = logicalIndex;
+    d->sortIndicatorOrder = order;
+
+    if (logicalIndex >= d->sectionCount) {
+        emit sortIndicatorChanged(logicalIndex, order);
+        return; // nothing to do
+    }
+
+    if (old != logicalIndex
+        && ((logicalIndex >= 0 && resizeMode(logicalIndex) == ResizeToContents)
+            || old >= d->sectionCount || (old >= 0 && resizeMode(old) == ResizeToContents))) {
+        resizeSections();
+        d->viewport->update();
+    } else {
+        if (old >= 0 && old != logicalIndex)
+            updateSection(old);
+        if (logicalIndex >= 0)
+            updateSection(logicalIndex);
+    }
+
+    emit sortIndicatorChanged(logicalIndex, order);
+}
+
+/*!
+    Returns the logical index of the section that has a sort indicator.
+    By default this is section 0.
+
+    \sa setSortIndicator() sortIndicatorOrder() setSortIndicatorShown()
+*/
+
+int QHeaderView::sortIndicatorSection() const
+{
+    Q_D(const QHeaderView);
+    return d->sortIndicatorSection;
+}
+
+/*!
+    Returns the order for the sort indicator. If no section has a sort
+    indicator the return value of this function is undefined.
+
+    \sa setSortIndicator() sortIndicatorSection()
+*/
+
+Qt::SortOrder QHeaderView::sortIndicatorOrder() const
+{
+    Q_D(const QHeaderView);
+    return d->sortIndicatorOrder;
+}
+
+/*!
+    \property QHeaderView::stretchLastSection
+    \brief whether the last visible section in the header takes up all the
+    available space
+
+    The default value is false.
+
+    \note The horizontal headers provided by QTreeView are configured with this
+    property set to true, ensuring that the view does not waste any of the
+    space assigned to it for its header. If this value is set to true, this
+    property will override the resize mode set on the last section in the
+    header.
+
+    \sa setResizeMode()
+*/
+bool QHeaderView::stretchLastSection() const
+{
+    Q_D(const QHeaderView);
+    return d->stretchLastSection;
+}
+
+void QHeaderView::setStretchLastSection(bool stretch)
+{
+    Q_D(QHeaderView);
+    d->stretchLastSection = stretch;
+    if (d->state != QHeaderViewPrivate::NoState)
+        return;
+    if (stretch)
+        resizeSections();
+    else if (count())
+        resizeSection(count() - 1, d->defaultSectionSize);
+}
+
+/*!
+    \since 4.2
+    \property QHeaderView::cascadingSectionResizes
+    \brief whether interactive resizing will be cascaded to the following
+    sections once the section being resized by the user has reached its
+    minimum size
+
+    This property only affects sections that have \l Interactive as their
+    resize mode.
+
+    The default value is false.
+
+    \sa setResizeMode()
+*/
+bool QHeaderView::cascadingSectionResizes() const
+{
+    Q_D(const QHeaderView);
+    return d->cascadingResizing;
+}
+
+void QHeaderView::setCascadingSectionResizes(bool enable)
+{
+    Q_D(QHeaderView);
+    d->cascadingResizing = enable;
+}
+
+/*!
+    \property QHeaderView::defaultSectionSize
+    \brief the default size of the header sections before resizing.
+
+    This property only affects sections that have \l Interactive or \l Fixed
+    as their resize mode.
+
+    \sa setResizeMode() minimumSectionSize
+*/
+int QHeaderView::defaultSectionSize() const
+{
+    Q_D(const QHeaderView);
+    return d->defaultSectionSize;
+}
+
+void QHeaderView::setDefaultSectionSize(int size)
+{
+    Q_D(QHeaderView);
+    d->setDefaultSectionSize(size);
+}
+
+/*!
+    \since 4.2
+    \property QHeaderView::minimumSectionSize
+    \brief the minimum size of the header sections.
+
+    The minimum section size is the smallest section size allowed. If the
+    minimum section size is set to -1, QHeaderView will use the maximum of
+    the \l{QApplication::globalStrut()}{global strut} or the
+    \l{fontMetrics()}{font metrics} size.
+
+    This property is honored by all \l{ResizeMode}{resize modes}.
+
+    \sa setResizeMode() defaultSectionSize
+*/
+int QHeaderView::minimumSectionSize() const
+{
+    Q_D(const QHeaderView);
+    if (d->minimumSectionSize == -1) {
+        QSize strut = QApplication::globalStrut();
+        int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this);
+        if (d->orientation == Qt::Horizontal)
+            return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
+        return qMax(strut.height(), (fontMetrics().lineSpacing() + margin));
+    }
+    return d->minimumSectionSize;
+}
+
+void QHeaderView::setMinimumSectionSize(int size)
+{
+    Q_D(QHeaderView);
+    d->minimumSectionSize = size;
+}
+
+/*!
+    \since 4.1
+    \property QHeaderView::defaultAlignment
+    \brief the default alignment of the text in each header section
+*/
+
+Qt::Alignment QHeaderView::defaultAlignment() const
+{
+    Q_D(const QHeaderView);
+    return d->defaultAlignment;
+}
+
+void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
+{
+    Q_D(QHeaderView);
+    if (d->defaultAlignment == alignment)
+        return;
+
+    d->defaultAlignment = alignment;
+    d->viewport->update();
+}
+
+/*!
+    \internal
+*/
+void QHeaderView::doItemsLayout()
+{
+    initializeSections();
+    QAbstractItemView::doItemsLayout();
+}
+
+/*!
+    Returns true if sections in the header has been moved; otherwise returns
+    false;
+
+    \sa moveSection()
+*/
+bool QHeaderView::sectionsMoved() const
+{
+    Q_D(const QHeaderView);
+    return !d->visualIndices.isEmpty();
+}
+
+/*!
+    \since 4.1
+
+    Returns true if sections in the header has been hidden; otherwise returns
+    false;
+
+    \sa setSectionHidden()
+*/
+bool QHeaderView::sectionsHidden() const
+{
+    Q_D(const QHeaderView);
+    return !d->hiddenSectionSize.isEmpty();
+}
+
+#ifndef QT_NO_DATASTREAM
+/*!
+    \since 4.3
+
+    Saves the current state of this header view.
+
+    To restore the saved state, pass the return value to restoreState().
+
+    \sa restoreState()
+*/
+QByteArray QHeaderView::saveState() const
+{
+    Q_D(const QHeaderView);
+    QByteArray data;
+    QDataStream stream(&data, QIODevice::WriteOnly);
+    stream << QHeaderViewPrivate::VersionMarker;
+    stream << 0; // current version is 0
+    d->write(stream);
+    return data;
+}
+
+/*!
+    \since 4.3
+    Restores the \a state of this header view.
+    This function returns \c true if the state was restored; otherwise returns
+    false.
+
+    \sa saveState()
+*/
+bool QHeaderView::restoreState(const QByteArray &state)
+{
+    Q_D(QHeaderView);
+    if (state.isEmpty())
+        return false;
+    QByteArray data = state;
+    QDataStream stream(&data, QIODevice::ReadOnly);
+    int marker;
+    int ver;
+    stream >> marker;
+    stream >> ver;
+    if (stream.status() != QDataStream::Ok
+        || marker != QHeaderViewPrivate::VersionMarker
+        || ver != 0) // current version is 0
+        return false;
+
+    if (d->read(stream)) {
+        emit sortIndicatorChanged(d->sortIndicatorSection, d->sortIndicatorOrder );
+        d->viewport->update();
+        return true;
+    }
+    return false;
+}
+#endif // QT_NO_DATASTREAM
+
+/*!
+  \reimp
+*/
+void QHeaderView::reset()
+{
+    QAbstractItemView::reset();
+    // it would be correct to call clear, but some apps rely
+    // on the header keeping the sections, even after calling reset
+    //d->clear();
+    initializeSections();
+}
+
+/*!
+    Updates the changed header sections with the given \a orientation, from
+    \a logicalFirst to \a logicalLast inclusive.
+*/
+void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
+{
+    Q_D(QHeaderView);
+    if (d->orientation != orientation)
+        return;
+
+    if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
+        return;
+
+    d->invalidateCachedSizeHint();
+
+    int firstVisualIndex = INT_MAX, lastVisualIndex = -1;
+
+    for (int section = logicalFirst; section <= logicalLast; ++section) {
+        const int visual = visualIndex(section);
+        firstVisualIndex = qMin(firstVisualIndex, visual);
+        lastVisualIndex =  qMax(lastVisualIndex,  visual);
+    }
+
+    d->executePostedResize();
+    const int first = d->headerSectionPosition(firstVisualIndex),
+              last = d->headerSectionPosition(lastVisualIndex)
+                        + d->headerSectionSize(lastVisualIndex);
+
+    if (orientation == Qt::Horizontal) {
+        d->viewport->update(first, 0, last - first, d->viewport->height());
+    } else {
+        d->viewport->update(0, first, d->viewport->width(), last - first);
+    }
+}
+
+/*!
+    \internal
+    \since 4.2
+
+    Updates the section specified by the given \a logicalIndex.
+*/
+
+void QHeaderView::updateSection(int logicalIndex)
+{
+    Q_D(QHeaderView);
+    if (d->orientation == Qt::Horizontal)
+        d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
+                                  0, sectionSize(logicalIndex), d->viewport->height()));
+    else
+        d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
+                                  d->viewport->width(), sectionSize(logicalIndex)));
+}
+
+/*!
+    Resizes the sections according to their size hints. Normally, you do not
+    have to call this function.
+*/
+
+void QHeaderView::resizeSections()
+{
+    Q_D(QHeaderView);
+    if (d->hasAutoResizeSections())
+        d->resizeSections(Interactive, false); // no global resize mode
+}
+
+/*!
+    This slot is called when sections are inserted into the \a parent.
+    \a logicalFirst and \a logicalLast indices signify where the new sections
+    were inserted.
+
+    If only one section is inserted, \a logicalFirst and \a logicalLast will
+    be the same.
+*/
+
+void QHeaderView::sectionsInserted(const QModelIndex &parent,
+                                   int logicalFirst, int logicalLast)
+{
+    Q_D(QHeaderView);
+    if (parent != d->root)
+        return; // we only handle changes in the top level
+    int oldCount = d->sectionCount;
+
+    d->invalidateCachedSizeHint();
+
+    // add the new sections
+    int insertAt = 0;
+    for (int spanStart = 0; insertAt < d->sectionSpans.count() && spanStart < logicalFirst; ++insertAt)
+        spanStart += d->sectionSpans.at(insertAt).count;
+
+    int insertCount = logicalLast - logicalFirst + 1;
+    d->sectionCount += insertCount;
+
+    if (d->sectionSpans.isEmpty() || insertAt >= d->sectionSpans.count()) {
+        int insertLength = d->defaultSectionSize * insertCount;
+        d->length += insertLength;
+        QHeaderViewPrivate::SectionSpan span(insertLength, insertCount, d->globalResizeMode);
+        d->sectionSpans.append(span);
+    } else if ((d->sectionSpans.at(insertAt).sectionSize() == d->defaultSectionSize)
+               && d->sectionSpans.at(insertAt).resizeMode == d->globalResizeMode) {
+        // add the new sections to an existing span
+        int insertLength = d->sectionSpans.at(insertAt).sectionSize() * insertCount;
+        d->length += insertLength;
+        d->sectionSpans[insertAt].size += insertLength;
+        d->sectionSpans[insertAt].count += insertCount;
+    } else {
+        // separate them out into their own span
+        int insertLength = d->defaultSectionSize * insertCount;
+        d->length += insertLength;
+        QHeaderViewPrivate::SectionSpan span(insertLength, insertCount, d->globalResizeMode);
+        d->sectionSpans.insert(insertAt, span);
+    }
+
+    // update sorting column
+    if (d->sortIndicatorSection >= logicalFirst)
+        d->sortIndicatorSection += insertCount;
+
+    // update resize mode section counts
+    if (d->globalResizeMode == Stretch)
+        d->stretchSections = d->sectionCount;
+    else if (d->globalResizeMode == ResizeToContents)
+        d->contentsSections = d->sectionCount;
+
+    // clear selection cache
+    d->sectionSelected.clear();
+
+    // update mapping
+    if (!d->visualIndices.isEmpty() && !d->logicalIndices.isEmpty()) {
+        Q_ASSERT(d->visualIndices.count() == d->logicalIndices.count());
+        int mappingCount = d->visualIndices.count();
+        for (int i = 0; i < mappingCount; ++i) {
+            if (d->visualIndices.at(i) >= logicalFirst)
+               d->visualIndices[i] += insertCount;
+            if (d->logicalIndices.at(i) >= logicalFirst)
+                d->logicalIndices[i] += insertCount;
+        }
+        for (int j = logicalFirst; j <= logicalLast; ++j) {
+            d->visualIndices.insert(j, j);
+            d->logicalIndices.insert(j, j);
+        }
+    }
+
+    // insert sections into sectionsHidden
+    if (!d->sectionHidden.isEmpty()) {
+        QBitArray sectionHidden(d->sectionHidden);
+        sectionHidden.resize(sectionHidden.count() + insertCount);
+        //sectionHidden.fill(false, logicalFirst, logicalLast + 1);
+        for (int i = logicalFirst; i <= logicalLast; ++i)
+            // visual == logical in this range (see previous block)
+            sectionHidden.setBit(i, false);
+        for (int j = logicalLast + 1; j < sectionHidden.count(); ++j)
+            sectionHidden.setBit(d->visualIndex(j),
+                    d->sectionHidden.testBit(d->visualIndex(j - insertCount)));
+        d->sectionHidden = sectionHidden;
+    }
+
+    // insert sections into hiddenSectionSize
+    QHash<int, int> newHiddenSectionSize; // from logical index to section size
+    for (int i = 0; i < logicalFirst; ++i)
+        if (isSectionHidden(i))
+            newHiddenSectionSize[i] = d->hiddenSectionSize[i];
+    for (int j = logicalLast + 1; j < d->sectionCount; ++j)
+        if (isSectionHidden(j))
+            newHiddenSectionSize[j] = d->hiddenSectionSize[j - insertCount];
+    d->hiddenSectionSize = newHiddenSectionSize;
+
+    d->doDelayedResizeSections();
+    emit sectionCountChanged(oldCount, count());
+
+    // if the new sections were not updated by resizing, we need to update now
+    if (!d->hasAutoResizeSections())
+        d->viewport->update();
+}
+
+/*!
+    This slot is called when sections are removed from the \a parent.
+    \a logicalFirst and \a logicalLast signify where the sections were removed.
+
+    If only one section is removed, \a logicalFirst and \a logicalLast will
+    be the same.
+*/
+
+void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
+                                           int logicalFirst, int logicalLast)
+{
+    Q_UNUSED(parent);
+    Q_UNUSED(logicalFirst);
+    Q_UNUSED(logicalLast);
+}
+
+void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
+{
+    Q_Q(QHeaderView);
+    const int changeCount = logicalLast - logicalFirst + 1;
+
+    // remove sections from hiddenSectionSize
+    QHash<int, int> newHiddenSectionSize; // from logical index to section size
+    for (int i = 0; i < logicalFirst; ++i)
+        if (q->isSectionHidden(i))
+            newHiddenSectionSize[i] = hiddenSectionSize[i];
+    for (int j = logicalLast + 1; j < sectionCount; ++j)
+        if (q->isSectionHidden(j))
+            newHiddenSectionSize[j - changeCount] = hiddenSectionSize[j];
+    hiddenSectionSize = newHiddenSectionSize;
+
+    // remove sections from sectionsHidden
+    if (!sectionHidden.isEmpty()) {
+        const int newsize = qMin(sectionCount - changeCount, sectionHidden.size());
+        QBitArray newSectionHidden(newsize);
+        for (int j = 0, k = 0; j < sectionHidden.size(); ++j) {
+            const int logical = logicalIndex(j);
+            if (logical < logicalFirst || logical > logicalLast) {
+                newSectionHidden[k++] = sectionHidden[j];
+            }
+        }
+        sectionHidden = newSectionHidden;
+    }
+}
+
+void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
+                                            int logicalFirst, int logicalLast)
+{
+    Q_Q(QHeaderView);
+    if (parent != root)
+        return; // we only handle changes in the top level
+    if (qMin(logicalFirst, logicalLast) < 0
+        || qMax(logicalLast, logicalFirst) >= sectionCount)
+        return;
+    int oldCount = q->count();
+    int changeCount = logicalLast - logicalFirst + 1;
+
+    updateHiddenSections(logicalFirst, logicalLast);
+
+    if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
+        //Q_ASSERT(headerSectionCount() == sectionCount);
+        removeSectionsFromSpans(logicalFirst, logicalLast);
+    } else {
+        for (int l = logicalLast; l >= logicalFirst; --l) {
+            int visual = visualIndices.at(l);
+            for (int v = 0; v < sectionCount; ++v) {
+                if (v >= logicalIndices.count())
+                    continue; // the section doesn't exist
+                if (v > visual) {
+                    int logical = logicalIndices.at(v);
+                    --(visualIndices[logical]);
+                }
+                if (logicalIndex(v) > l) // no need to move the positions before l
+                    --(logicalIndices[v]);
+            }
+            logicalIndices.remove(visual);
+            visualIndices.remove(l);
+            //Q_ASSERT(headerSectionCount() == sectionCount);
+            removeSectionsFromSpans(visual, visual);
+        }
+        // ### handle sectionSelection, sectionHidden
+    }
+    sectionCount -= changeCount;
+
+    // update sorting column
+    if (sortIndicatorSection >= logicalFirst) {
+        if (sortIndicatorSection <= logicalLast)
+            sortIndicatorSection = -1;
+        else
+            sortIndicatorSection -= changeCount;
+    }
+
+    // if we only have the last section (the "end" position) left, the header is empty
+    if (sectionCount <= 0)
+        clear();
+    invalidateCachedSizeHint();
+    emit q->sectionCountChanged(oldCount, q->count());
+    viewport->update();
+}
+
+void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
+{
+    //if there is no row/column we can't have mapping for columns
+    //because no QModelIndex in the model would be valid
+    // ### this is far from being bullet-proof and we would need a real system to 
+    // ### map columns or rows persistently
+    if ((orientation == Qt::Horizontal && model->rowCount(root) == 0)
+        || model->columnCount(root) == 0)
+        return;
+
+    for (int i = 0; i < sectionHidden.count(); ++i)
+        if (sectionHidden.testBit(i)) // ### note that we are using column or row 0
+            persistentHiddenSections.append(orientation == Qt::Horizontal
+                                            ? model->index(0, logicalIndex(i), root)
+                                            : model->index(logicalIndex(i), 0, root));
+}
+
+void QHeaderViewPrivate::_q_layoutChanged()
+{
+    Q_Q(QHeaderView);
+    viewport->update();
+    if (persistentHiddenSections.isEmpty() || modelIsEmpty()) {
+        if (modelSectionCount() != sectionCount)
+            q->initializeSections();
+        persistentHiddenSections.clear();
+        return;
+    }
+    bool sectionCountChanged = false;
+    for (int i = 0; i < sectionHidden.count(); ++i) {
+        if (sectionHidden.testBit(i))
+            q->setSectionHidden(logicalIndex(i), false);
+    }
+
+    for (int i = 0; i < persistentHiddenSections.count(); ++i) {
+        QModelIndex index = persistentHiddenSections.at(i);
+        if (index.isValid()) {
+            const int logical = (orientation == Qt::Horizontal
+                                 ? index.column()
+                                 : index.row());
+            q->setSectionHidden(logical, true);
+        } else if (!sectionCountChanged && (modelSectionCount() != sectionCount)) {
+            sectionCountChanged = true;
+            break;
+        }
+    }
+    persistentHiddenSections.clear();
+
+    // the number of sections changed; we need to reread the state of the model
+    if (sectionCountChanged)
+        q->initializeSections();
+}
+
+/*!
+  \internal
+*/
+
+void QHeaderView::initializeSections()
+{
+    Q_D(QHeaderView);
+    const int oldCount = d->sectionCount;
+    const int newCount = d->modelSectionCount();
+    if (newCount <= 0) {
+            d->clear();
+            emit sectionCountChanged(oldCount, 0);
+    } else if (newCount != oldCount) {
+        const int min = qBound(0, oldCount, newCount - 1);
+        initializeSections(min, newCount - 1);
+        if (stretchLastSection()) // we've already gotten the size hint
+            d->lastSectionSize = sectionSize(logicalIndex(d->sectionCount - 1));
+
+        //make sure we update the hidden sections
+        if (newCount < oldCount)
+            d->updateHiddenSections(0, newCount-1);
+    }
+}
+
+/*!
+    \internal
+*/
+
+void QHeaderView::initializeSections(int start, int end)
+{
+    Q_D(QHeaderView);
+
+    Q_ASSERT(start >= 0);
+    Q_ASSERT(end >= 0);
+
+    d->executePostedLayout();
+    d->invalidateCachedSizeHint();
+
+    if (end + 1 < d->sectionCount) {
+        int newCount = end + 1;
+        d->removeSectionsFromSpans(newCount, d->sectionCount);
+        if (!d->hiddenSectionSize.isEmpty()) {
+            if (d->sectionCount - newCount > d->hiddenSectionSize.count()) {
+                for (int i = end + 1; i < d->sectionCount; ++i)
+                    d->hiddenSectionSize.remove(i);
+            } else {
+                QHash<int, int>::iterator it = d->hiddenSectionSize.begin();
+                while (it != d->hiddenSectionSize.end()) {
+                    if (it.key() > end)
+                        it = d->hiddenSectionSize.erase(it);
+                    else
+                        ++it;
+                }
+            }
+        }
+    }
+
+    int oldCount = d->sectionCount;
+    d->sectionCount = end + 1;
+
+    if (!d->logicalIndices.isEmpty()) {
+        d->logicalIndices.resize(d->sectionCount);
+        d->visualIndices.resize(d->sectionCount);
+        for (int i = start; i < d->sectionCount; ++i){
+            d->logicalIndices[i] = i;
+            d->visualIndices[i] = i;
+        }
+    }
+
+    if (d->globalResizeMode == Stretch)
+        d->stretchSections = d->sectionCount;
+    else if (d->globalResizeMode == ResizeToContents)
+         d->contentsSections = d->sectionCount;
+    if (!d->sectionHidden.isEmpty())
+        d->sectionHidden.resize(d->sectionCount);
+
+    if (d->sectionCount > oldCount)
+        d->createSectionSpan(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
+    //Q_ASSERT(d->headerLength() == d->length);
+
+    if (d->sectionCount != oldCount)
+        emit sectionCountChanged(oldCount,  d->sectionCount);
+    d->viewport->update();
+}
+
+/*!
+  \reimp
+*/
+
+void QHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &old)
+{
+    Q_D(QHeaderView);
+
+    if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
+        if (old.isValid() && old.parent() == d->root)
+            d->viewport->update(QRect(sectionViewportPosition(old.column()), 0,
+                                    sectionSize(old.column()), d->viewport->height()));
+        if (current.isValid() && current.parent() == d->root)
+            d->viewport->update(QRect(sectionViewportPosition(current.column()), 0,
+                                    sectionSize(current.column()), d->viewport->height()));
+    } else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
+        if (old.isValid() && old.parent() == d->root)
+            d->viewport->update(QRect(0, sectionViewportPosition(old.row()),
+                                    d->viewport->width(), sectionSize(old.row())));
+        if (current.isValid() && current.parent() == d->root)
+            d->viewport->update(QRect(0, sectionViewportPosition(current.row()),
+                                    d->viewport->width(), sectionSize(current.row())));
+    }
+}
+
+
+/*!
+  \reimp
+*/
+
+bool QHeaderView::event(QEvent *e)
+{
+    Q_D(QHeaderView);
+    switch (e->type()) {
+    case QEvent::HoverEnter: {
+        QHoverEvent *he = static_cast<QHoverEvent*>(e);
+        d->hover = logicalIndexAt(he->pos());
+        if (d->hover != -1)
+            updateSection(d->hover);
+        break; }
+    case QEvent::Leave:
+    case QEvent::HoverLeave: {
+        if (d->hover != -1)
+            updateSection(d->hover);
+        d->hover = -1;
+        break; }
+    case QEvent::HoverMove: {
+        QHoverEvent *he = static_cast<QHoverEvent*>(e);
+        int oldHover = d->hover;
+        d->hover = logicalIndexAt(he->pos());
+        if (d->hover != oldHover) {
+            if (oldHover != -1)
+                updateSection(oldHover);
+            if (d->hover != -1)
+                updateSection(d->hover);
+        }
+        break; }
+    case QEvent::Timer: { // ### reimplement timerEvent() instead ?
+        QTimerEvent *te = static_cast<QTimerEvent*>(e);
+        if (te->timerId() == d->delayedResize.timerId()) {
+            d->delayedResize.stop();
+            resizeSections();
+        }
+        break; }
+    default:
+        break;
+    }
+    return QAbstractItemView::event(e);
+}
+
+/*!
+  \reimp
+*/
+
+void QHeaderView::paintEvent(QPaintEvent *e)
+{
+    Q_D(QHeaderView);
+
+    if (count() == 0)
+        return;
+
+    QPainter painter(d->viewport);
+    const QPoint offset = d->scrollDelayOffset;
+    QRect translatedEventRect = e->rect();
+    translatedEventRect.translate(offset);
+
+    int start = -1;
+    int end = -1;
+    if (d->orientation == Qt::Horizontal) {
+        start = visualIndexAt(translatedEventRect.left());
+        end = visualIndexAt(translatedEventRect.right());
+    } else {
+        start = visualIndexAt(translatedEventRect.top());
+        end = visualIndexAt(translatedEventRect.bottom());
+    }
+
+    if (d->reverse()) {
+        start = (start == -1 ? count() - 1 : start);
+        end = (end == -1 ? 0 : end);
+    } else {
+        start = (start == -1 ? 0 : start);
+        end = (end == -1 ? count() - 1 : end);
+    }
+
+    int tmp = start;
+    start = qMin(start, end);
+    end = qMax(tmp, end);
+
+    d->prepareSectionSelected(); // clear and resize the bit array
+
+    QRect currentSectionRect;
+    int logical;
+    const int width = d->viewport->width();
+    const int height = d->viewport->height();
+    for (int i = start; i <= end; ++i) {
+        if (d->isVisualIndexHidden(i))
+            continue;
+        painter.save();
+        logical = logicalIndex(i);
+        if (d->orientation == Qt::Horizontal) {
+            currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
+        } else {
+            currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
+        }
+        currentSectionRect.translate(offset);
+
+        QVariant variant = d->model->headerData(logical, d->orientation,
+                                                Qt::FontRole);
+        if (variant.isValid() && qVariantCanConvert<QFont>(variant)) {
+            QFont sectionFont = qvariant_cast<QFont>(variant);
+            painter.setFont(sectionFont);
+        }
+        paintSection(&painter, currentSectionRect, logical);
+        painter.restore();
+    }
+
+    QStyleOption opt;
+    opt.init(this);
+    // Paint the area beyond where there are indexes
+    if (d->reverse()) {
+        opt.state |= QStyle::State_Horizontal;
+        if (currentSectionRect.left() > translatedEventRect.left()) {
+            opt.rect = QRect(translatedEventRect.left(), 0,
+                             currentSectionRect.left() - translatedEventRect.left(), height);
+            style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
+        }
+    } else if (currentSectionRect.right() < translatedEventRect.right()) {
+        // paint to the right
+        opt.state |= QStyle::State_Horizontal;
+        opt.rect = QRect(currentSectionRect.right() + 1, 0,
+                         translatedEventRect.right() - currentSectionRect.right(), height);
+        style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
+    } else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
+        // paint the bottom section
+        opt.state &= ~QStyle::State_Horizontal;
+        opt.rect = QRect(0, currentSectionRect.bottom() + 1,
+                         width, height - currentSectionRect.bottom() - 1);
+        style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, &painter, this);
+    }
+
+#if 0
+    // ### visualize section spans
+    for (int a = 0, i = 0; i < d->sectionSpans.count(); ++i) {
+        QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
+        if (d->orientation == Qt::Horizontal)
+            painter.fillRect(a - d->offset, 0, d->sectionSpans.at(i).size, 4, color);
+        else
+            painter.fillRect(0, a - d->offset, 4, d->sectionSpans.at(i).size, color);
+        a += d->sectionSpans.at(i).size;
+    }
+
+#endif
+}
+
+/*!
+  \reimp
+*/
+
+void QHeaderView::mousePressEvent(QMouseEvent *e)
+{
+    Q_D(QHeaderView);
+    if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
+        return;
+    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
+    int handle = d->sectionHandleAt(pos);
+    d->originalSize = -1; // clear the stored original size
+    if (handle == -1) {
+        d->pressed = logicalIndexAt(pos);
+        if (d->clickableSections)
+            emit sectionPressed(d->pressed);
+        if (d->movableSections) {
+            d->section = d->target = d->pressed;
+            if (d->section == -1)
+                return;
+            d->state = QHeaderViewPrivate::MoveSection;
+            d->setupSectionIndicator(d->section, pos);
+        } else if (d->clickableSections && d->pressed != -1) {
+            updateSection(d->pressed);
+            d->state = QHeaderViewPrivate::SelectSections;
+        }
+    } else if (resizeMode(handle) == Interactive) {
+        d->originalSize = sectionSize(handle);
+        d->state = QHeaderViewPrivate::ResizeSection;
+        d->section = handle;
+    }
+
+    d->firstPos = pos;
+    d->lastPos = pos;
+
+    d->clearCascadingSections();
+}
+
+/*!
+  \reimp
+*/
+
+void QHeaderView::mouseMoveEvent(QMouseEvent *e)
+{
+    Q_D(QHeaderView);
+    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
+    if (pos < 0)
+        return;
+    if (e->buttons() == Qt::NoButton) {
+        d->state = QHeaderViewPrivate::NoState;
+        d->pressed = -1;
+    }
+    switch (d->state) {
+        case QHeaderViewPrivate::ResizeSection: {
+            Q_ASSERT(d->originalSize != -1);
+            if (d->cascadingResizing) {
+                int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
+                int visual = visualIndex(d->section);
+                d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
+            } else {
+                int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
+                resizeSection(d->section, qMax(d->originalSize + delta, minimumSectionSize()));
+            }
+            d->lastPos = pos;
+            return;
+        }
+        case QHeaderViewPrivate::MoveSection: {
+            if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()) {
+                int indicatorCenter = (d->orientation == Qt::Horizontal
+                                       ? d->sectionIndicator->width()
+                                       : d->sectionIndicator->height()) / 2;
+                int centerOffset = indicatorCenter - d->sectionIndicatorOffset;
+                // This will drop the moved section to the position under the center of the indicator.
+                // If centerOffset is 0, the section will be moved to the position of the mouse cursor.
+                int visual = visualIndexAt(pos + centerOffset);
+                if (visual == -1)
+                    return;
+                d->target = d->logicalIndex(visual);
+                d->updateSectionIndicator(d->section, pos);
+            } else {
+                int visual = visualIndexAt(d->firstPos);
+                if (visual == -1)
+                    return;
+                d->target = d->logicalIndex(visual);
+                d->updateSectionIndicator(d->section, d->firstPos);
+            }
+            return;
+        }
+        case QHeaderViewPrivate::SelectSections: {
+            int logical = logicalIndexAt(pos);
+            if (logical == d->pressed)
+                return; // nothing to do
+            else if (d->pressed != -1)
+                updateSection(d->pressed);
+            d->pressed = logical;
+            if (d->clickableSections && logical != -1) {
+                emit sectionEntered(d->pressed);
+                updateSection(d->pressed);
+            }
+            return;
+        }
+        case QHeaderViewPrivate::NoState: {
+#ifndef QT_NO_CURSOR
+            int handle = d->sectionHandleAt(pos);
+            bool hasCursor = testAttribute(Qt::WA_SetCursor);
+            if (handle != -1 && (resizeMode(handle) == Interactive)) {
+                if (!hasCursor)
+                    setCursor(d->orientation == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
+            } else if (hasCursor) {
+                unsetCursor();
+            }
+#endif
+            return;
+        }
+        default:
+            break;
+    }
+}
+
+/*!
+  \reimp
+*/
+
+void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
+{
+    Q_D(QHeaderView);
+    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
+    switch (d->state) {
+    case QHeaderViewPrivate::MoveSection:
+        if (!d->sectionIndicator->isHidden()) { // moving
+            int from = visualIndex(d->section);
+            Q_ASSERT(from != -1);
+            int to = visualIndex(d->target);
+            Q_ASSERT(to != -1);
+            moveSection(from, to);
+            d->section = d->target = -1;
+            d->updateSectionIndicator(d->section, pos);
+            break;
+        } // not moving
+    case QHeaderViewPrivate::SelectSections:
+        if (!d->clickableSections) {
+            int section = logicalIndexAt(pos);
+            updateSection(section);
+        }
+        // fall through
+    case QHeaderViewPrivate::NoState:
+        if (d->clickableSections) {
+            int section = logicalIndexAt(pos);
+            if (section != -1 && section == d->pressed) {
+                d->flipSortIndicator(section);
+                emit sectionClicked(logicalIndexAt(pos));
+            }
+            if (d->pressed != -1)
+                updateSection(d->pressed);
+        }
+        break;
+    case QHeaderViewPrivate::ResizeSection:
+        d->originalSize = -1;
+        d->clearCascadingSections();
+        break;
+    default:
+        break;
+    }
+    d->state = QHeaderViewPrivate::NoState;
+    d->pressed = -1;
+}
+
+/*!
+  \reimp
+*/
+
+void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    Q_D(QHeaderView);
+    int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
+    int handle = d->sectionHandleAt(pos);
+    if (handle > -1 && resizeMode(handle) == Interactive) {
+        emit sectionHandleDoubleClicked(handle);
+#ifndef QT_NO_CURSOR
+        Qt::CursorShape splitCursor = (d->orientation == Qt::Horizontal)
+                                      ? Qt::SplitHCursor : Qt::SplitVCursor;
+        if (cursor().shape() == splitCursor) {
+            // signal handlers may have changed the section size
+            handle = d->sectionHandleAt(pos);
+            if (!(handle > -1 && resizeMode(handle) == Interactive))
+                setCursor(Qt::ArrowCursor);
+        }
+#endif
+    } else {
+        emit sectionDoubleClicked(logicalIndexAt(e->pos()));
+    }
+}
+
+/*!
+  \reimp
+*/
+
+bool QHeaderView::viewportEvent(QEvent *e)
+{
+    Q_D(QHeaderView);
+    switch (e->type()) {
+#ifndef QT_NO_TOOLTIP
+    case QEvent::ToolTip: {
+        QHelpEvent *he = static_cast<QHelpEvent*>(e);
+        int logical = logicalIndexAt(he->pos());
+        if (logical != -1) {
+            QVariant variant = d->model->headerData(logical, d->orientation, Qt::ToolTipRole);
+            if (variant.isValid()) {
+                QToolTip::showText(he->globalPos(), variant.toString(), this);
+                return true;
+            }
+        }
+        break; }
+#endif
+#ifndef QT_NO_WHATSTHIS
+    case QEvent::QueryWhatsThis: {
+        QHelpEvent *he = static_cast<QHelpEvent*>(e);
+        int logical = logicalIndexAt(he->pos());
+        if (logical != -1
+            && d->model->headerData(logical, d->orientation, Qt::WhatsThisRole).isValid())
+            return true;
+        break; }
+    case QEvent::WhatsThis: {
+        QHelpEvent *he = static_cast<QHelpEvent*>(e);
+        int logical = logicalIndexAt(he->pos());
+        if (logical != -1) {
+             QVariant whatsthis = d->model->headerData(logical, d->orientation,
+                                                      Qt::WhatsThisRole);
+             if (whatsthis.isValid()) {
+                 QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
+                 return true;
+             }
+        }
+        break; }
+#endif // QT_NO_WHATSTHIS
+#ifndef QT_NO_STATUSTIP
+    case QEvent::StatusTip: {
+        QHelpEvent *he = static_cast<QHelpEvent*>(e);
+        int logical = logicalIndexAt(he->pos());
+        if (logical != -1) {
+            QString statustip = d->model->headerData(logical, d->orientation,
+                                                    Qt::StatusTipRole).toString();
+            if (!statustip.isEmpty())
+                setStatusTip(statustip);
+        }
+        return true; }
+#endif // QT_NO_STATUSTIP
+    case QEvent::Hide:
+    case QEvent::Show:
+    case QEvent::FontChange:
+    case QEvent::StyleChange:
+        d->invalidateCachedSizeHint();
+        resizeSections();
+        emit geometriesChanged();
+        break;
+    case QEvent::ContextMenu: {
+        d->state = QHeaderViewPrivate::NoState;
+        d->pressed = d->section = d->target = -1;
+        d->updateSectionIndicator(d->section, -1);
+    }
+    default:
+        break;
+    }
+    return QAbstractItemView::viewportEvent(e);
+}
+
+/*!
+    Paints the section specified by the given \a logicalIndex, using the given
+    \a painter and \a rect.
+
+    Normally, you do not have to call this function.
+*/
+
+void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    if (!rect.isValid())
+        return;
+    // get the state of the section
+    QStyleOptionHeader opt;
+    initStyleOption(&opt);
+    QStyle::State state = QStyle::State_None;
+    if (isEnabled())
+        state |= QStyle::State_Enabled;
+    if (window()->isActiveWindow())
+        state |= QStyle::State_Active;
+    if (d->clickableSections) {
+        if (logicalIndex == d->hover)
+            state |= QStyle::State_MouseOver;
+        if (logicalIndex == d->pressed)
+            state |= QStyle::State_Sunken;
+        else if (d->highlightSelected) {
+            if (d->sectionIntersectsSelection(logicalIndex))
+                state |= QStyle::State_On;
+            if (d->isSectionSelected(logicalIndex))
+                state |= QStyle::State_Sunken;
+        }
+
+    }
+    if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
+        opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
+                            ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
+
+    // setup the style options structure
+    QVariant textAlignment = d->model->headerData(logicalIndex, d->orientation,
+                                                  Qt::TextAlignmentRole);
+    opt.rect = rect;
+    opt.section = logicalIndex;
+    opt.state |= state;
+    opt.textAlignment = Qt::Alignment(textAlignment.isValid()
+                                      ? Qt::Alignment(textAlignment.toInt())
+                                      : d->defaultAlignment);
+
+    opt.iconAlignment = Qt::AlignVCenter;
+    opt.text = d->model->headerData(logicalIndex, d->orientation,
+                                    Qt::DisplayRole).toString();
+    if (d->textElideMode != Qt::ElideNone)
+        opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4);
+
+    QVariant variant = d->model->headerData(logicalIndex, d->orientation,
+                                    Qt::DecorationRole);
+    opt.icon = qvariant_cast<QIcon>(variant);
+    if (opt.icon.isNull())
+        opt.icon = qvariant_cast<QPixmap>(variant);
+    QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation,
+                                                    Qt::ForegroundRole);
+    if (qVariantCanConvert<QBrush>(foregroundBrush))
+        opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
+
+    QPointF oldBO = painter->brushOrigin();
+    QVariant backgroundBrush = d->model->headerData(logicalIndex, d->orientation,
+                                                    Qt::BackgroundRole);
+    if (qVariantCanConvert<QBrush>(backgroundBrush)) {
+        opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
+        opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
+        painter->setBrushOrigin(opt.rect.topLeft());
+    }
+
+    // the section position
+    int visual = visualIndex(logicalIndex);
+    Q_ASSERT(visual != -1);
+    if (count() == 1)
+        opt.position = QStyleOptionHeader::OnlyOneSection;
+    else if (visual == 0)
+        opt.position = QStyleOptionHeader::Beginning;
+    else if (visual == count() - 1)
+        opt.position = QStyleOptionHeader::End;
+    else
+        opt.position = QStyleOptionHeader::Middle;
+    opt.orientation = d->orientation;
+    // the selected position
+    bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
+    bool nextSelected =  d->isSectionSelected(this->logicalIndex(visual + 1));
+    if (previousSelected && nextSelected)
+        opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
+    else if (previousSelected)
+        opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
+    else if (nextSelected)
+        opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
+    else
+        opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
+    // draw the section
+    style()->drawControl(QStyle::CE_Header, &opt, painter, this);
+
+    painter->setBrushOrigin(oldBO);
+}
+
+/*!
+    Returns the size of the contents of the section specified by the given
+    \a logicalIndex.
+
+    \sa defaultSectionSize()
+*/
+
+QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
+{
+    Q_D(const QHeaderView);
+    Q_ASSERT(logicalIndex >= 0);
+
+    // use SizeHintRole
+    QVariant variant = d->model->headerData(logicalIndex, d->orientation, Qt::SizeHintRole);
+    if (variant.isValid())
+        return qvariant_cast<QSize>(variant);
+
+    // otherwise use the contents
+    QStyleOptionHeader opt;
+    initStyleOption(&opt);
+    opt.section = logicalIndex;
+    QVariant var = d->model->headerData(logicalIndex, d->orientation,
+                                            Qt::FontRole);
+    QFont fnt;
+    if (var.isValid() && qVariantCanConvert<QFont>(var))
+        fnt = qvariant_cast<QFont>(var);
+    else
+        fnt = font();
+    fnt.setBold(true);
+    opt.fontMetrics = QFontMetrics(fnt);
+    opt.text = d->model->headerData(logicalIndex, d->orientation,
+                                    Qt::DisplayRole).toString();
+    variant = d->model->headerData(logicalIndex, d->orientation, Qt::DecorationRole);
+    opt.icon = qvariant_cast<QIcon>(variant);
+    if (opt.icon.isNull())
+        opt.icon = qvariant_cast<QPixmap>(variant);
+    QSize size = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this);
+    if (isSortIndicatorShown()) {
+        int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, &opt, this);
+        if (d->orientation == Qt::Horizontal)
+            size.rwidth() += size.height() + margin;
+        else
+            size.rheight() += size.width() + margin;
+    }
+    return size;
+}
+
+/*!
+    Returns the horizontal offset of the header. This is 0 for vertical
+    headers.
+
+    \sa offset()
+*/
+
+int QHeaderView::horizontalOffset() const
+{
+    Q_D(const QHeaderView);
+    if (d->orientation == Qt::Horizontal)
+        return d->offset;
+    return 0;
+}
+
+/*!
+    Returns the vertical offset of the header. This is 0 for horizontal
+    headers.
+
+    \sa offset()
+*/
+
+int QHeaderView::verticalOffset() const
+{
+    Q_D(const QHeaderView);
+    if (d->orientation == Qt::Vertical)
+        return d->offset;
+    return 0;
+}
+
+/*!
+    \reimp
+    \internal
+*/
+
+void QHeaderView::updateGeometries()
+{
+    Q_D(QHeaderView);
+    d->layoutChildren();
+    if (d->hasAutoResizeSections())
+        resizeSections();
+}
+
+/*!
+    \reimp
+    \internal
+*/
+
+void QHeaderView::scrollContentsBy(int dx, int dy)
+{
+    Q_D(QHeaderView);
+    d->scrollDirtyRegion(dx, dy);
+}
+
+/*!
+    \reimp
+    \internal
+*/
+void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+    Q_D(QHeaderView);
+    d->invalidateCachedSizeHint();
+    if (d->hasAutoResizeSections()) {
+        bool resizeRequired = d->globalResizeMode == ResizeToContents;
+        int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row();
+        int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row();
+        for (int i = first; i <= last && !resizeRequired; ++i)
+            resizeRequired = (resizeMode(i) == ResizeToContents);
+        if (resizeRequired)
+            d->doDelayedResizeSections();
+    }
+}
+
+/*!
+    \reimp
+    \internal
+
+    Empty implementation because the header doesn't show QModelIndex items.
+*/
+void QHeaderView::rowsInserted(const QModelIndex &, int, int)
+{
+    // do nothing
+}
+
+/*!
+    \reimp
+    \internal
+
+    Empty implementation because the header doesn't show QModelIndex items.
+*/
+
+QRect QHeaderView::visualRect(const QModelIndex &) const
+{
+    return QRect();
+}
+
+/*!
+    \reimp
+    \internal
+
+    Empty implementation because the header doesn't show QModelIndex items.
+*/
+
+void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
+{
+    // do nothing - the header only displays sections
+}
+
+/*!
+    \reimp
+    \internal
+
+    Empty implementation because the header doesn't show QModelIndex items.
+*/
+
+QModelIndex QHeaderView::indexAt(const QPoint &) const
+{
+    return QModelIndex();
+}
+
+/*!
+    \reimp
+    \internal
+
+    Empty implementation because the header doesn't show QModelIndex items.
+*/
+
+bool QHeaderView::isIndexHidden(const QModelIndex &) const
+{
+    return true; // the header view has no items, just sections
+}
+
+/*!
+    \reimp
+    \internal
+
+    Empty implementation because the header doesn't show QModelIndex items.
+*/
+
+QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
+{
+    return QModelIndex();
+}
+
+/*!
+    \reimp
+
+    Selects the items in the given \a rect according to the specified
+    \a flags.
+
+    The base class implementation does nothing.
+*/
+
+void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
+{
+    // do nothing
+}
+
+/*!
+    \internal
+*/
+
+QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
+{
+    Q_D(const QHeaderView);
+    const int max = d->modelSectionCount();
+    if (d->orientation == Qt::Horizontal) {
+        int left = max;
+        int right = 0;
+        int rangeLeft, rangeRight;
+
+        for (int i = 0; i < selection.count(); ++i) {
+            QItemSelectionRange r = selection.at(i);
+            if (r.parent().isValid() || !r.isValid())
+                continue; // we only know about toplevel items and we don't want invalid ranges
+            // FIXME an item inside the range may be the leftmost or rightmost
+            rangeLeft = visualIndex(r.left());
+            if (rangeLeft == -1) // in some cases users may change the selections
+                continue;        // before we have a chance to do the layout
+            rangeRight = visualIndex(r.right());
+            if (rangeRight == -1) // in some cases users may change the selections
+                continue;         // before we have a chance to do the layout
+            if (rangeLeft < left)
+                left = rangeLeft;
+            if (rangeRight > right)
+                right = rangeRight;
+        }
+
+        int logicalLeft = logicalIndex(left);
+        int logicalRight = logicalIndex(right);
+
+        if (logicalLeft < 0  || logicalLeft >= count() ||
+            logicalRight < 0 || logicalRight >= count())
+            return QRegion();
+
+        int leftPos = sectionViewportPosition(logicalLeft);
+        int rightPos = sectionViewportPosition(logicalRight);
+        rightPos += sectionSize(logicalRight);
+        return QRect(leftPos, 0, rightPos - leftPos, height());
+    }
+    // orientation() == Qt::Vertical
+    int top = max;
+    int bottom = 0;
+    int rangeTop, rangeBottom;
+
+    for (int i = 0; i < selection.count(); ++i) {
+        QItemSelectionRange r = selection.at(i);
+        if (r.parent().isValid() || !r.isValid())
+            continue; // we only know about toplevel items
+        // FIXME an item inside the range may be the leftmost or rightmost
+        rangeTop = visualIndex(r.top());
+        if (rangeTop == -1) // in some cases users may change the selections
+            continue;       // before we have a chance to do the layout
+        rangeBottom = visualIndex(r.bottom());
+        if (rangeBottom == -1) // in some cases users may change the selections
+            continue;          // before we have a chance to do the layout
+        if (rangeTop < top)
+            top = rangeTop;
+        if (rangeBottom > bottom)
+            bottom = rangeBottom;
+    }
+
+    int logicalTop = logicalIndex(top);
+    int logicalBottom = logicalIndex(bottom);
+
+    if (logicalTop == -1 || logicalBottom == -1)
+        return QRect();
+
+    int topPos = sectionViewportPosition(logicalTop);
+    int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
+
+    return QRect(0, topPos, width(), bottomPos - topPos);
+}
+
+
+// private implementation
+
+int QHeaderViewPrivate::sectionHandleAt(int position)
+{
+    Q_Q(QHeaderView);
+    int visual = q->visualIndexAt(position);
+    if (visual == -1)
+        return -1;
+    int log = logicalIndex(visual);
+    int pos = q->sectionViewportPosition(log);
+    int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin, 0, q);
+
+    bool atLeft = position < pos + grip;
+    bool atRight = (position > pos + q->sectionSize(log) - grip);
+    if (reverse())
+        qSwap(atLeft, atRight);
+
+    if (atLeft) {
+        //grip at the beginning of the section
+        while(visual > -1) {
+            int logical = q->logicalIndex(--visual);
+            if (!q->isSectionHidden(logical))
+                return logical;
+        }
+    } else if (atRight) {
+        //grip at the end of the section
+        return log;
+    }
+    return -1;
+}
+
+void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
+{
+    Q_Q(QHeaderView);
+    if (!sectionIndicator) {
+        sectionIndicator = new QLabel(viewport);
+    }
+
+    int w, h;
+    int p = q->sectionViewportPosition(section);
+    if (orientation == Qt::Horizontal) {
+        w = q->sectionSize(section);
+        h = viewport->height();
+    } else {
+        w = viewport->width();
+        h = q->sectionSize(section);
+    }
+    sectionIndicator->resize(w, h);
+
+    QPixmap pm(w, h);
+    pm.fill(QColor(0, 0, 0, 45));
+    QRect rect(0, 0, w, h);
+
+    QPainter painter(&pm);
+    painter.setOpacity(0.75);
+    q->paintSection(&painter, rect, section);
+    painter.end();
+
+    sectionIndicator->setPixmap(pm);
+    sectionIndicatorOffset = position - qMax(p, 0);
+}
+
+void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
+{
+    if (!sectionIndicator)
+        return;
+
+    if (section == -1 || target == -1) {
+        sectionIndicator->hide();
+        return;
+    }
+
+    if (orientation == Qt::Horizontal)
+        sectionIndicator->move(position - sectionIndicatorOffset, 0);
+    else
+        sectionIndicator->move(0, position - sectionIndicatorOffset);
+
+    sectionIndicator->show();
+}
+
+/*!
+    Initialize \a option with the values from this QHeaderView. This method is
+    useful for subclasses when they need a QStyleOptionHeader, but do not want
+    to fill in all the information themselves.
+
+    \sa QStyleOption::initFrom()
+*/
+void QHeaderView::initStyleOption(QStyleOptionHeader *option) const
+{
+    Q_D(const QHeaderView);
+    option->initFrom(this);
+    option->state = QStyle::State_None | QStyle::State_Raised;
+    option->orientation = d->orientation;
+    if (d->orientation == Qt::Horizontal)
+        option->state |= QStyle::State_Horizontal;
+    if (isEnabled())
+        option->state |= QStyle::State_Enabled;
+    option->section = 0;
+}
+
+bool QHeaderViewPrivate::isSectionSelected(int section) const
+{
+    int i = section * 2;
+    if (i < 0 || i >= sectionSelected.count())
+        return false;
+    if (sectionSelected.testBit(i)) // if the value was cached
+        return sectionSelected.testBit(i + 1);
+    bool s = false;
+    if (orientation == Qt::Horizontal)
+        s = isColumnSelected(section);
+    else
+        s = isRowSelected(section);
+    sectionSelected.setBit(i + 1, s); // selection state
+    sectionSelected.setBit(i, true); // cache state
+    return s;
+}
+
+/*!
+    \internal
+    Returns the last visible (ie. not hidden) visual index
+*/
+int QHeaderViewPrivate::lastVisibleVisualIndex() const
+{
+    Q_Q(const QHeaderView);
+    for (int visual = q->count()-1; visual >= 0; --visual) {
+        if (!q->isSectionHidden(q->logicalIndex(visual)))
+            return visual;
+    }
+
+    //default value if no section is actually visible
+    return -1;
+}
+
+/*!
+    \internal
+    Go through and resize all of the sections applying stretchLastSection,
+    manualy stretches, sizes, and useGlobalMode.
+
+    The different resize modes are:
+    Interactive - the user decides the size
+    Stretch - take up whatever space is left
+    Fixed - the size is set programmatically outside the header
+    ResizeToContentes - the size is set based on the contents of the row or column in the parent view
+
+    The resize mode will not affect the last section if stretchLastSection is true.
+*/
+void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
+{
+    Q_Q(QHeaderView);
+    //stop the timer in case it is delayed
+    delayedResize.stop();
+
+    executePostedLayout();
+    if (sectionCount == 0)
+        return;
+
+    if (resizeRecursionBlock)
+        return;
+    resizeRecursionBlock = true;
+
+    invalidateCachedSizeHint();
+
+    const int lastVisibleSection = lastVisibleVisualIndex();
+
+    // find stretchLastSection if we have it
+    int stretchSection = -1;
+    if (stretchLastSection && !useGlobalMode)
+        stretchSection = lastVisibleVisualIndex();
+
+    // count up the number of strected sections and how much space left for them
+    int lengthToStrech = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
+    int numberOfStretchedSections = 0;
+    QList<int> section_sizes;
+    for (int i = 0; i < sectionCount; ++i) {
+        if (isVisualIndexHidden(i))
+            continue;
+
+        QHeaderView::ResizeMode resizeMode;
+        if (useGlobalMode && (i != stretchSection))
+            resizeMode = globalMode;
+        else
+            resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i));
+
+        if (resizeMode == QHeaderView::Stretch) {
+            ++numberOfStretchedSections;
+            section_sizes.append(headerSectionSize(i));
+            continue;
+        }
+
+        // because it isn't stretch, determine its width and remove that from lengthToStrech
+        int sectionSize = 0;
+        if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
+            sectionSize = headerSectionSize(i);
+        } else { // resizeMode == QHeaderView::ResizeToContents
+            int logicalIndex = q->logicalIndex(i);
+            sectionSize = qMax(viewSectionSizeHint(logicalIndex),
+                               q->sectionSizeHint(logicalIndex));
+        }
+        section_sizes.append(sectionSize);
+        lengthToStrech -= sectionSize;
+    }
+
+    // calculate the new length for all of the stretched sections
+    int stretchSectionLength = -1;
+    int pixelReminder = 0;
+    if (numberOfStretchedSections > 0 && lengthToStrech > 0) { // we have room to stretch in
+        int hintLengthForEveryStretchedSection = lengthToStrech / numberOfStretchedSections;
+        stretchSectionLength = qMax(hintLengthForEveryStretchedSection, q->minimumSectionSize());
+        pixelReminder = lengthToStrech % numberOfStretchedSections;
+    }
+
+    int spanStartSection = 0;
+    int previousSectionLength = 0;
+
+    QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
+
+    // resize each section along the total length
+    for (int i = 0; i < sectionCount; ++i) {
+        int oldSectionLength = headerSectionSize(i);
+        int newSectionLength = -1;
+        QHeaderView::ResizeMode newSectionResizeMode = headerSectionResizeMode(i);
+
+        if (isVisualIndexHidden(i)) {
+            newSectionLength = 0;
+        } else {
+            QHeaderView::ResizeMode resizeMode;
+            if (useGlobalMode)
+                resizeMode = globalMode;
+            else
+                resizeMode = (i == stretchSection
+                              ? QHeaderView::Stretch
+                              : newSectionResizeMode);
+            if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) {
+                if (i == lastVisibleSection)
+                    newSectionLength = qMax(stretchSectionLength, lastSectionSize);
+                else
+                    newSectionLength = stretchSectionLength;
+                if (pixelReminder > 0) {
+                    newSectionLength += 1;
+                    --pixelReminder;
+                }
+                section_sizes.removeFirst();
+            } else {
+                newSectionLength = section_sizes.front();
+                section_sizes.removeFirst();
+            }
+        }
+
+        //Q_ASSERT(newSectionLength > 0);
+        if ((previousSectionResizeMode != newSectionResizeMode
+            || previousSectionLength != newSectionLength) && i > 0) {
+            int spanLength = (i - spanStartSection) * previousSectionLength;
+            createSectionSpan(spanStartSection, i - 1, spanLength, previousSectionResizeMode);
+            //Q_ASSERT(headerLength() == length);
+            spanStartSection = i;
+        }
+
+        if (newSectionLength != oldSectionLength)
+            emit q->sectionResized(logicalIndex(i), oldSectionLength, newSectionLength);
+
+        previousSectionLength = newSectionLength;
+        previousSectionResizeMode = newSectionResizeMode;
+    }
+
+    createSectionSpan(spanStartSection, sectionCount - 1,
+                      (sectionCount - spanStartSection) * previousSectionLength,
+                      previousSectionResizeMode);
+    //Q_ASSERT(headerLength() == length);
+    resizeRecursionBlock = false;
+    viewport->update();
+}
+
+void QHeaderViewPrivate::createSectionSpan(int start, int end, int size, QHeaderView::ResizeMode mode)
+{
+    // ### the code for merging spans does not merge at all opertuneties
+    // ### what if the number of sections is reduced ?
+
+    SectionSpan span(size, (end - start) + 1, mode);
+    int start_section = 0;
+#ifndef QT_NO_DEBUG
+    int initial_section_count = headerSectionCount(); // ### debug code
+#endif
+
+    QList<int> spansToRemove;
+    for (int i = 0; i < sectionSpans.count(); ++i) {
+        int end_section = start_section + sectionSpans.at(i).count - 1;
+        int section_count = sectionSpans.at(i).count;
+        if (start <= start_section && end > end_section) {
+            // the existing span is entirely coveded by the new span
+            spansToRemove.append(i);
+        } else if (start < start_section && end >= end_section) {
+            // the existing span is entirely coveded by the new span
+            spansToRemove.append(i);
+        } else if (start == start_section && end == end_section) {
+            // the new span is covered by an existin span
+            length -= sectionSpans.at(i).size;
+            length += size;
+            sectionSpans[i].size = size;
+            sectionSpans[i].resizeMode = mode;
+            // ### check if we can merge the section with any of its neighbours
+            removeSpans(spansToRemove);
+            Q_ASSERT(initial_section_count == headerSectionCount());
+            return;
+        } else if (start > start_section && end < end_section) {
+            if (sectionSpans.at(i).sectionSize() == span.sectionSize()
+                && sectionSpans.at(i).resizeMode == span.resizeMode) {
+                Q_ASSERT(initial_section_count == headerSectionCount());
+                return;
+            }
+            // the new span is in the middle of the old span, so we have to split it
+            length -= sectionSpans.at(i).size;
+            int section_size = sectionSpans.at(i).sectionSize();
+#ifndef QT_NO_DEBUG
+            int span_count = sectionSpans.at(i).count;
+#endif
+            QHeaderView::ResizeMode span_mode = sectionSpans.at(i).resizeMode;
+            // first span
+            int first_span_count = start - start_section;
+            int first_span_size = section_size * first_span_count;
+            sectionSpans[i].count = first_span_count;
+            sectionSpans[i].size = first_span_size;
+            sectionSpans[i].resizeMode = span_mode;
+            length += first_span_size;
+            // middle span (the new span)
+#ifndef QT_NO_DEBUG
+            int mid_span_count = span.count;
+#endif
+            int mid_span_size = span.size;
+            sectionSpans.insert(i + 1, span);
+            length += mid_span_size;
+            // last span
+            int last_span_count = end_section - end;
+            int last_span_size = section_size * last_span_count;
+            sectionSpans.insert(i + 2, SectionSpan(last_span_size, last_span_count, span_mode));
+            length += last_span_size;
+            Q_ASSERT(span_count == first_span_count + mid_span_count + last_span_count);
+            removeSpans(spansToRemove);
+            Q_ASSERT(initial_section_count == headerSectionCount());
+            return;
+        } else if (start > start_section && start <= end_section && end >= end_section) {
+            // the new span covers the last part of the existing span
+            length -= sectionSpans.at(i).size;
+            int removed_count = (end_section - start + 1);
+            int span_count = sectionSpans.at(i).count - removed_count;
+            int section_size = sectionSpans.at(i).sectionSize();
+            int span_size = section_size * span_count;
+            sectionSpans[i].count = span_count;
+            sectionSpans[i].size = span_size;
+            length += span_size;
+            if (end == end_section) {
+                sectionSpans.insert(i + 1, span); // insert after
+                length += span.size;
+                removeSpans(spansToRemove);
+                Q_ASSERT(initial_section_count == headerSectionCount());
+                return;
+            }
+        } else if (end < end_section && end >= start_section && start <= start_section) {
+            // the new span covers the first part of the existing span
+            length -= sectionSpans.at(i).size;
+            int removed_count = (end - start_section + 1);
+            int section_size = sectionSpans.at(i).sectionSize();
+            int span_count = sectionSpans.at(i).count - removed_count;
+            int span_size = section_size * span_count;
+            sectionSpans[i].count = span_count;
+            sectionSpans[i].size = span_size;
+            length += span_size;
+            sectionSpans.insert(i, span); // insert before
+            length += span.size;
+            removeSpans(spansToRemove);
+            Q_ASSERT(initial_section_count == headerSectionCount());
+            return;
+        }
+        start_section += section_count;
+    }
+
+    // ### adding and removing _ sections_  in addition to spans
+    // ### add some more checks here
+
+    if (spansToRemove.isEmpty()) {
+        if (!sectionSpans.isEmpty()
+            && sectionSpans.last().sectionSize() == span.sectionSize()
+            && sectionSpans.last().resizeMode == span.resizeMode) {
+            length += span.size;
+            int last = sectionSpans.count() - 1;
+            sectionSpans[last].count += span.count;
+            sectionSpans[last].size += span.size;
+            sectionSpans[last].resizeMode = span.resizeMode;
+        } else {
+            length += span.size;
+            sectionSpans.append(span);
+        }
+    } else {
+        removeSpans(spansToRemove);
+        length += span.size;
+        sectionSpans.insert(spansToRemove.first(), span);
+        //Q_ASSERT(initial_section_count == headerSectionCount());
+    }
+}
+
+void QHeaderViewPrivate::removeSectionsFromSpans(int start, int end)
+{
+    // remove sections
+    int start_section = 0;
+    QList<int> spansToRemove;
+    for (int i = 0; i < sectionSpans.count(); ++i) {
+        int end_section = start_section + sectionSpans.at(i).count - 1;
+        int section_size = sectionSpans.at(i).sectionSize();
+        int section_count = sectionSpans.at(i).count;
+        if (start <= start_section && end >= end_section) {
+            // the change covers the entire span
+            spansToRemove.append(i);
+            if (end == end_section)
+                break;
+        } else if (start > start_section && end < end_section) {
+            // all the removed sections are inside the span
+            int change = (end - start + 1);
+            sectionSpans[i].count -= change;
+            sectionSpans[i].size = section_size * sectionSpans.at(i).count;
+            length -= (change * section_size);
+            break;
+        } else if (start >= start_section && start <= end_section) {
+            // the some of the removed sections are inside the span,at the end
+            int change = qMin(end_section - start + 1, end - start + 1);
+            sectionSpans[i].count -= change;
+            sectionSpans[i].size = section_size * sectionSpans.at(i).count;
+            start += change;
+            length -= (change * section_size);
+            // the change affects several spans
+        } else if (end >= start_section && end <= end_section) {
+            // the some of the removed sections are inside the span, at the beginning
+            int change = qMin((end - start_section + 1), end - start + 1);
+            sectionSpans[i].count -= change;
+            sectionSpans[i].size = section_size * sectionSpans.at(i).count;
+            length -= (change * section_size);
+            break;
+        }
+        start_section += section_count;
+    }
+
+    for (int i = spansToRemove.count() - 1; i >= 0; --i) {
+        int s = spansToRemove.at(i);
+        length -= sectionSpans.at(s).size;
+        sectionSpans.remove(s);
+        // ### merge remaining spans
+    }
+}
+
+void QHeaderViewPrivate::clear()
+{
+    if (state != NoClear) {
+    length = 0;
+    sectionCount = 0;
+    visualIndices.clear();
+    logicalIndices.clear();
+    sectionSelected.clear();
+    sectionHidden.clear();
+    hiddenSectionSize.clear();
+    sectionSpans.clear();
+    }
+}
+
+void QHeaderViewPrivate::flipSortIndicator(int section)
+{
+    Q_Q(QHeaderView);
+    bool ascending = (sortIndicatorSection != section
+                      || sortIndicatorOrder == Qt::DescendingOrder);
+    q->setSortIndicator(section, ascending ? Qt::AscendingOrder : Qt::DescendingOrder);
+}
+
+void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
+{
+    Q_Q(QHeaderView);
+    const int minimumSize = q->minimumSectionSize();
+    const int oldSize = headerSectionSize(visual);
+    int delta = newSize - oldSize;
+
+    if (delta > 0) { // larger
+        bool sectionResized = false;
+
+        // restore old section sizes
+        for (int i = firstCascadingSection; i < visual; ++i) {
+            if (cascadingSectionSize.contains(i)) {
+                int currentSectionSize = headerSectionSize(i);
+                int originalSectionSize = cascadingSectionSize.value(i);
+                if (currentSectionSize < originalSectionSize) {
+                    int newSectionSize = currentSectionSize + delta;
+                    resizeSectionSpan(i, currentSectionSize, newSectionSize);
+                    if (newSectionSize >= originalSectionSize && false)
+                        cascadingSectionSize.remove(i); // the section is now restored
+                    sectionResized = true;
+                    break;
+                }
+            }
+
+        }
+
+        // resize the section
+        if (!sectionResized) {
+            newSize = qMax(newSize, minimumSize);
+            if (oldSize != newSize)
+                resizeSectionSpan(visual, oldSize, newSize);
+        }
+
+        // cascade the section size change
+        for (int i = visual + 1; i < sectionCount; ++i) {
+            if (!sectionIsCascadable(i))
+                continue;
+            int currentSectionSize = headerSectionSize(i);
+            if (currentSectionSize <= minimumSize)
+                continue;
+            int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
+            //qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
+            resizeSectionSpan(i, currentSectionSize, newSectionSize);
+            saveCascadingSectionSize(i, currentSectionSize);
+            delta = delta - (currentSectionSize - newSectionSize);
+            //qDebug() << "new delta" << delta;
+            //if (newSectionSize != minimumSize)
+            if (delta <= 0)
+                break;
+        }
+    } else { // smaller
+        bool sectionResized = false;
+
+        // restore old section sizes
+        for (int i = lastCascadingSection; i > visual; --i) {
+            if (!cascadingSectionSize.contains(i))
+                continue;
+            int currentSectionSize = headerSectionSize(i);
+            int originalSectionSize = cascadingSectionSize.value(i);
+            if (currentSectionSize >= originalSectionSize)
+                continue;
+            int newSectionSize = currentSectionSize - delta;
+            resizeSectionSpan(i, currentSectionSize, newSectionSize);
+            if (newSectionSize >= originalSectionSize && false) {
+                //qDebug() << "section" << i << "restored to" << originalSectionSize;
+                cascadingSectionSize.remove(i); // the section is now restored
+            }
+            sectionResized = true;
+            break;
+        }
+
+        // resize the section
+        resizeSectionSpan(visual, oldSize, qMax(newSize, minimumSize));
+
+        // cascade the section size change
+        if (delta < 0 && newSize < minimumSize) {
+            for (int i = visual - 1; i >= 0; --i) {
+                if (!sectionIsCascadable(i))
+                    continue;
+                int sectionSize = headerSectionSize(i);
+                if (sectionSize <= minimumSize)
+                    continue;
+                resizeSectionSpan(i, sectionSize, qMax(sectionSize + delta, minimumSize));
+                saveCascadingSectionSize(i, sectionSize);
+                break;
+            }
+        }
+
+        // let the next section get the space from the resized section
+        if (!sectionResized) {
+            for (int i = visual + 1; i < sectionCount; ++i) {
+                if (!sectionIsCascadable(i))
+                    continue;
+                int currentSectionSize = headerSectionSize(i);
+                int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
+                resizeSectionSpan(i, currentSectionSize, newSectionSize);
+                break;
+            }
+        }
+    }
+
+    if (hasAutoResizeSections())
+        doDelayedResizeSections();
+
+    viewport->update();
+}
+
+void QHeaderViewPrivate::setDefaultSectionSize(int size)
+{
+    Q_Q(QHeaderView);
+    defaultSectionSize = size;
+    int currentVisualIndex = 0;
+    for (int i = 0; i < sectionSpans.count(); ++i) {
+        QHeaderViewPrivate::SectionSpan &span = sectionSpans[i];
+        if (span.size > 0) {
+            //we resize it if it is not hidden (ie size > 0)
+            const int newSize = span.count * size;
+            if (newSize != span.size) {
+                length += newSize - span.size; //the whole length is changed
+                const int oldSectionSize = span.sectionSize();
+                span.size = span.count * size;
+                for (int i = currentVisualIndex; i < currentVisualIndex + span.count; ++i) {
+                    emit q->sectionResized(logicalIndex(i), oldSectionSize, size);
+                }
+            }
+        }
+        currentVisualIndex += span.count;
+    }
+}
+
+void QHeaderViewPrivate::resizeSectionSpan(int visualIndex, int oldSize, int newSize)
+{
+    Q_Q(QHeaderView);
+    QHeaderView::ResizeMode mode = headerSectionResizeMode(visualIndex);
+    createSectionSpan(visualIndex, visualIndex, newSize, mode);
+    emit q->sectionResized(logicalIndex(visualIndex), oldSize, newSize);
+}
+
+int QHeaderViewPrivate::headerSectionSize(int visual) const
+{
+    // ### stupid iteration
+    int section_start = 0;
+    const int sectionSpansCount = sectionSpans.count();
+    for (int i = 0; i < sectionSpansCount; ++i) {
+        const QHeaderViewPrivate::SectionSpan &currentSection = sectionSpans.at(i);
+        int section_end = section_start + currentSection.count - 1;
+        if (visual >= section_start && visual <= section_end)
+            return currentSection.sectionSize();
+        section_start = section_end + 1;
+    }
+    return -1;
+}
+
+int QHeaderViewPrivate::headerSectionPosition(int visual) const
+{
+    // ### stupid iteration
+    int section_start = 0;
+    int span_position = 0;
+    const int sectionSpansCount = sectionSpans.count();
+    for (int i = 0; i < sectionSpansCount; ++i) {
+        const QHeaderViewPrivate::SectionSpan &currentSection = sectionSpans.at(i);
+        int section_end = section_start + currentSection.count - 1;
+        if (visual >= section_start && visual <= section_end)
+            return span_position + (visual - section_start) * currentSection.sectionSize();
+        section_start = section_end + 1;
+        span_position += currentSection.size;
+    }
+    return -1;
+}
+
+int QHeaderViewPrivate::headerVisualIndexAt(int position) const
+{
+    // ### stupid iteration
+    int span_start_section = 0;
+    int span_position = 0;
+    const int sectionSpansCount = sectionSpans.count();
+    for (int i = 0; i < sectionSpansCount; ++i) {
+        const QHeaderViewPrivate::SectionSpan &currentSection = sectionSpans.at(i);
+        int next_span_start_section = span_start_section + currentSection.count;
+        int next_span_position = span_position + currentSection.size;
+        if (position == span_position)
+            return span_start_section; // spans with no size
+        if (position > span_position && position < next_span_position) {
+            int position_in_span = position - span_position;
+            return span_start_section + (position_in_span / currentSection.sectionSize());
+        }
+        span_start_section = next_span_start_section;
+        span_position = next_span_position;
+    }
+    return -1;
+}
+
+void QHeaderViewPrivate::setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode)
+{
+    int size = headerSectionSize(visual);
+    createSectionSpan(visual, visual, size, mode);
+}
+
+QHeaderView::ResizeMode QHeaderViewPrivate::headerSectionResizeMode(int visual) const
+{
+    int span = sectionSpanIndex(visual);
+    if (span == -1)
+        return globalResizeMode;
+    return sectionSpans.at(span).resizeMode;
+}
+
+void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode)
+{
+    globalResizeMode = mode;
+    for (int i = 0; i < sectionSpans.count(); ++i)
+        sectionSpans[i].resizeMode = mode;
+}
+
+int QHeaderViewPrivate::viewSectionSizeHint(int logical) const
+{
+    if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent)) {
+        return (orientation == Qt::Horizontal
+                ? view->sizeHintForColumn(logical)
+                : view->sizeHintForRow(logical));
+    }
+    return 0;
+}
+
+int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const
+{
+    if (hiddenSectionSize.count() > 0) {
+        int adjustedVisualIndex = visualIndex;
+        int currentVisualIndex = 0;
+        for (int i = 0; i < sectionSpans.count(); ++i) {
+            if (sectionSpans.at(i).size == 0)
+                adjustedVisualIndex += sectionSpans.at(i).count;
+            else
+                currentVisualIndex += sectionSpans.at(i).count;
+            if (currentVisualIndex >= visualIndex)
+                break;
+        }
+        visualIndex = adjustedVisualIndex;
+    }
+    return visualIndex;
+}
+
+#ifndef QT_NO_DATASTREAM
+void QHeaderViewPrivate::write(QDataStream &out) const
+{
+    out << int(orientation);
+    out << int(sortIndicatorOrder);
+    out << sortIndicatorSection;
+    out << sortIndicatorShown;
+
+    out << visualIndices;
+    out << logicalIndices;
+
+    out << sectionHidden;
+    out << hiddenSectionSize;
+
+    out << length;
+    out << sectionCount;
+    out << movableSections;
+    out << clickableSections;
+    out << highlightSelected;
+    out << stretchLastSection;
+    out << cascadingResizing;
+    out << stretchSections;
+    out << contentsSections;
+    out << defaultSectionSize;
+    out << minimumSectionSize;
+
+    out << int(defaultAlignment);
+    out << int(globalResizeMode);
+
+    out << sectionSpans;
+}
+
+bool QHeaderViewPrivate::read(QDataStream &in)
+{
+    int orient, order, align, global;
+    in >> orient;
+    orientation = (Qt::Orientation)orient;
+
+    in >> order;
+    sortIndicatorOrder = (Qt::SortOrder)order;
+
+    in >> sortIndicatorSection;
+    in >> sortIndicatorShown;
+
+    in >> visualIndices;
+    in >> logicalIndices;
+
+    in >> sectionHidden;
+    in >> hiddenSectionSize;
+
+    in >> length;
+    in >> sectionCount;
+    in >> movableSections;
+    in >> clickableSections;
+    in >> highlightSelected;
+    in >> stretchLastSection;
+    in >> cascadingResizing;
+    in >> stretchSections;
+    in >> contentsSections;
+    in >> defaultSectionSize;
+    in >> minimumSectionSize;
+
+    in >> align;
+    defaultAlignment = Qt::Alignment(align);
+
+    in >> global;
+    globalResizeMode = (QHeaderView::ResizeMode)global;
+
+    in >> sectionSpans;
+
+    return true;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ITEMVIEWS
+
+#include "moc_qheaderview.cpp"