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