src/gui/itemviews/qheaderview.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qheaderview.h"
00025 
00026 #ifndef QT_NO_ITEMVIEWS
00027 #include <qbitarray.h>
00028 #include <qbrush.h>
00029 #include <qdebug.h>
00030 #include <qevent.h>
00031 #include <qpainter.h>
00032 #include <qscrollbar.h>
00033 #include <qtooltip.h>
00034 #include <qwhatsthis.h>
00035 #include <qstyle.h>
00036 #include <qstyleoption.h>
00037 #include <qvector.h>
00038 #include <qapplication.h>
00039 #include <qvarlengtharray.h>
00040 #include <qabstractitemdelegate.h>
00041 #include <qvariant.h>
00042 #include <private/qheaderview_p.h>
00043 
00204 // ### Qt 5: change to sectionAutoResized()
00205 
00221 QHeaderView::QHeaderView(Qt::Orientation orientation, QWidget *parent)
00222     : QAbstractItemView(*new QHeaderViewPrivate, parent)
00223 {
00224     Q_D(QHeaderView);
00225     d->setDefaultValues(orientation);
00226     initialize();
00227 }
00228 
00232 QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
00233                          Qt::Orientation orientation, QWidget *parent)
00234     : QAbstractItemView(dd, parent)
00235 {
00236     Q_D(QHeaderView);
00237     d->setDefaultValues(orientation);
00238     initialize();
00239 }
00240 
00245 QHeaderView::~QHeaderView()
00246 {
00247 }
00248 
00252 void QHeaderView::initialize()
00253 {
00254     Q_D(QHeaderView);
00255     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00256     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00257     setFrameStyle(NoFrame);
00258     d->viewport->setMouseTracking(true);
00259     d->viewport->setBackgroundRole(QPalette::Button);
00260     d->textElideMode = Qt::ElideNone;
00261     delete d->itemDelegate;
00262 }
00263 
00267 void QHeaderView::setModel(QAbstractItemModel *model)
00268 {
00269     // Don't optimize away:
00270     // if (model == this->model())
00271     //      return;
00272     // This is the only way to reset moved sections
00273     Q_D(QHeaderView);
00274     if (d->orientation == Qt::Horizontal) {
00275         QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
00276                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
00277         QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
00278                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
00279         QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
00280                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
00281     } else {
00282         QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
00283                             this, SLOT(sectionsInserted(QModelIndex,int,int)));
00284         QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
00285                             this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
00286         QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00287                             this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
00288     }
00289     QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
00290                         this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
00291 
00292     if (model) {
00293         if (d->orientation == Qt::Horizontal) {
00294             QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
00295                              this, SLOT(sectionsInserted(QModelIndex,int,int)));
00296             QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
00297                 this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
00298             QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
00299                 this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
00300         } else {
00301             QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
00302                              this, SLOT(sectionsInserted(QModelIndex,int,int)));
00303             QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
00304                              this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
00305             QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00306                              this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
00307         }
00308         QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
00309                          this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
00310     }
00311     d->clear();
00312 
00313     QAbstractItemView::setModel(model);
00314     // Users want to set sizes and modes before the widget is shown.
00315     // Thus, we have to initialize when the model is set,
00316     // and not lazily like we do in the other views.
00317     initializeSections();
00318 }
00319 
00326 Qt::Orientation QHeaderView::orientation() const
00327 {
00328     Q_D(const QHeaderView);
00329     return d->orientation;
00330 }
00331 
00339 int QHeaderView::offset() const
00340 {
00341     Q_D(const QHeaderView);
00342     return d->offset;
00343 }
00344 
00353 void QHeaderView::setOffset(int newOffset)
00354 {
00355     Q_D(QHeaderView);
00356     if (d->offset == (uint)newOffset)
00357         return;
00358     int ndelta = d->offset - newOffset;
00359     d->offset = newOffset;
00360     if (d->orientation == Qt::Horizontal)
00361         d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
00362     else
00363         d->viewport->scroll(0, ndelta);
00364     if (d->state == QHeaderViewPrivate::ResizeSection) {
00365         QPoint cursorPos = QCursor::pos();
00366         if (d->orientation == Qt::Horizontal)
00367             QCursor::setPos(cursorPos.x() + ndelta, cursorPos.y());
00368         else
00369             QCursor::setPos(cursorPos.x(), cursorPos.y() + ndelta);
00370         d->firstPos += ndelta;
00371         d->lastPos += ndelta;
00372     }
00373 }
00374 
00381 void QHeaderView::setOffsetToSectionPosition(int visualIndex)
00382 {
00383     Q_D(QHeaderView);
00384     if (visualIndex > -1 && visualIndex < d->sectionCount) {
00385         int position = d->headerSectionPosition(d->adjustedVisualIndex(visualIndex));
00386         setOffset(position);
00387     }
00388 }
00389 
00396 int QHeaderView::length() const
00397 {
00398     Q_D(const QHeaderView);
00399     //Q_ASSERT(d->headerLength() == d->length);
00400     return d->length;
00401 }
00402 
00409 QSize QHeaderView::sizeHint() const
00410 {
00411     Q_D(const QHeaderView);
00412     if (count() < 1)
00413         return QSize(0, 0);
00414     if (d->cachedSizeHint.isValid())
00415         return d->cachedSizeHint;
00416     int width = 0;
00417     int height = 0;
00418     // get size hint for the first n sections
00419     int c = qMin(count(), 100);
00420     for (int i = 0; i < c; ++i) {
00421         QSize hint = sectionSizeFromContents(i);
00422         width = qMax(hint.width(), width);
00423         height = qMax(hint.height(), height);
00424     }
00425     // get size hint for the last n sections
00426     c = qMax(count() - 100, c);
00427     for (int j = count() - 1; j >= c; --j) {
00428         QSize hint = sectionSizeFromContents(j);
00429         width = qMax(hint.width(), width);
00430         height = qMax(hint.height(), height);
00431     }
00432     d->cachedSizeHint = QSize(width, height);
00433     return d->cachedSizeHint;
00434 }
00435 
00442 int QHeaderView::sectionSizeHint(int logicalIndex) const
00443 {
00444     Q_D(const QHeaderView);
00445     if (logicalIndex < 0 || logicalIndex >= count())
00446         return -1;
00447     QSize size = sectionSizeFromContents(logicalIndex);
00448     int hint = d->orientation == Qt::Horizontal ? size.width() : size.height();
00449     return qMax(minimumSectionSize(), hint);
00450 }
00451 
00458 int QHeaderView::visualIndexAt(int position) const
00459 {
00460     Q_D(const QHeaderView);
00461     uint vposition = position;
00462     d->executePostedLayout();
00463     const int count = d->sectionCount;
00464     if (count < 1)
00465         return -1;
00466 
00467     if (d->reverse())
00468         vposition = d->viewport->width() - vposition;
00469     vposition += d->offset;
00470 
00471     if (vposition > d->length)
00472         return -1;
00473     int visual = d->headerVisualIndexAt(vposition);
00474     if (visual < 0)
00475         return -1;
00476 
00477     while (d->isVisualIndexHidden(visual)){
00478         ++visual;
00479         if (visual >= count)
00480             return -1;
00481     }
00482     return visual;
00483 }
00484 
00491 int QHeaderView::logicalIndexAt(int position) const
00492 {
00493     const int visual = visualIndexAt(position);
00494     if (visual > -1)
00495         return logicalIndex(visual);
00496     return -1;
00497 }
00498 
00505 int QHeaderView::sectionSize(int logicalIndex) const
00506 {
00507     Q_D(const QHeaderView);
00508     if (logicalIndex < 0 || logicalIndex >= count())
00509         return 0;
00510     if (isSectionHidden(logicalIndex))
00511         return 0;
00512     int visual = visualIndex(logicalIndex);
00513     if (visual == -1)
00514         return 0;
00515     return d->headerSectionSize(visual);
00516 }
00517 
00525 int QHeaderView::sectionPosition(int logicalIndex) const
00526 {
00527     Q_D(const QHeaderView);
00528     int visual = visualIndex(logicalIndex);
00529     // in some cases users may change the selections
00530     // before we have a chance to do the layout
00531     if (visual == -1)
00532         return -1;
00533     return d->headerSectionPosition(visual);
00534 }
00535 
00544 int QHeaderView::sectionViewportPosition(int logicalIndex) const
00545 {
00546     Q_D(const QHeaderView);
00547     if (logicalIndex < 0 || logicalIndex >= count())
00548         return -1;
00549     int position = sectionPosition(logicalIndex);
00550     if (position < 0)
00551         return position; // the section was hidden
00552     int offsetPosition = position - d->offset;
00553     if (d->reverse())
00554         return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
00555     return offsetPosition;
00556 }
00557 
00582 void QHeaderView::moveSection(int from, int to)
00583 {
00584     Q_D(QHeaderView);
00585 
00586     d->executePostedLayout();
00587     if (from < 0 || from >= d->sectionCount || to < 0 || to >= d->sectionCount)
00588         return;
00589 
00590     if (from == to) {
00591         int logical = logicalIndex(from);
00592         Q_ASSERT(logical != -1);
00593         updateSection(logical);
00594         return;
00595     }
00596 
00597     //int oldHeaderLength = length(); // ### for debugging; remove later
00598     d->initializeIndexMapping();
00599 
00600     QBitArray sectionHidden = d->sectionHidden;
00601     int *visualIndices = d->visualIndices.data();
00602     int *logicalIndices = d->logicalIndices.data();
00603     int logical = logicalIndices[from];
00604     int visual = from;
00605 
00606     int affected_count = qAbs(to - from) + 1;
00607     QVarLengthArray<int> sizes(affected_count);
00608     QVarLengthArray<ResizeMode> modes(affected_count);
00609 
00610     // move sections and indices
00611     if (to > from) {
00612         sizes[to - from] = d->headerSectionSize(from);
00613         modes[to - from] = d->headerSectionResizeMode(from);
00614         while (visual < to) {
00615             sizes[visual - from] = d->headerSectionSize(visual + 1);
00616             modes[visual - from] = d->headerSectionResizeMode(visual + 1);
00617             if (!sectionHidden.isEmpty())
00618                 sectionHidden.setBit(visual, sectionHidden.testBit(visual + 1));
00619             visualIndices[logicalIndices[visual + 1]] = visual;
00620             logicalIndices[visual] = logicalIndices[visual + 1];
00621             ++visual;
00622         }
00623     } else {
00624         sizes[0] = d->headerSectionSize(from);
00625         modes[0] = d->headerSectionResizeMode(from);
00626         while (visual > to) {
00627             sizes[visual - to] = d->headerSectionSize(visual - 1);
00628             modes[visual - to] = d->headerSectionResizeMode(visual - 1);
00629             if (!sectionHidden.isEmpty())
00630                 sectionHidden.setBit(visual, sectionHidden.testBit(visual - 1));
00631             visualIndices[logicalIndices[visual - 1]] = visual;
00632             logicalIndices[visual] = logicalIndices[visual - 1];
00633             --visual;
00634         }
00635     }
00636     if (!sectionHidden.isEmpty()) {
00637         sectionHidden.setBit(to, d->sectionHidden.testBit(from));
00638         d->sectionHidden = sectionHidden;
00639     }
00640     visualIndices[logical] = to;
00641     logicalIndices[to] = logical;
00642 
00643     //Q_ASSERT(oldHeaderLength == length());
00644     // move sizes
00645     // ### check for spans of section sizes here
00646     if (to > from) {
00647         for (visual = from; visual <= to; ++visual) {
00648             int size = sizes[visual - from];
00649             ResizeMode mode = modes[visual - from];
00650             d->createSectionSpan(visual, visual, size, mode);
00651         }
00652     } else {
00653         for (visual = to; visual <= from; ++visual) {
00654             int size = sizes[visual - to];
00655             ResizeMode mode = modes[visual - to];
00656             d->createSectionSpan(visual, visual, size, mode);
00657         }
00658     }
00659     //Q_ASSERT(d->headerLength() == length());
00660     //Q_ASSERT(oldHeaderLength == length());
00661 
00662     d->viewport->update();
00663     emit sectionMoved(logical, from, to);
00664 }
00665 
00672 void QHeaderView::swapSections(int first, int second)
00673 {
00674     Q_D(QHeaderView);
00675 
00676     if (first == second)
00677         return;
00678     d->executePostedLayout();
00679     if (first < 0 || first >= d->sectionCount || second < 0 || second >= d->sectionCount)
00680         return;
00681 
00682     int firstSize = d->headerSectionSize(first);
00683     ResizeMode firstMode = d->headerSectionResizeMode(first);
00684     int firstLogical = d->logicalIndex(first);
00685 
00686     int secondSize = d->headerSectionSize(second);
00687     ResizeMode secondMode = d->headerSectionResizeMode(second);
00688     int secondLogical = d->logicalIndex(second);
00689 
00690     d->createSectionSpan(second, second, firstSize, firstMode);
00691     d->createSectionSpan(first, first, secondSize, secondMode);
00692 
00693     d->initializeIndexMapping();
00694 
00695     d->visualIndices[firstLogical] = second;
00696     d->logicalIndices[second] = firstLogical;
00697 
00698     d->visualIndices[secondLogical] = first;
00699     d->logicalIndices[first] = secondLogical;
00700 
00701     if (!d->sectionHidden.isEmpty()) {
00702         bool firstHidden = d->sectionHidden.testBit(first);
00703         bool secondHidden = d->sectionHidden.testBit(second);
00704         d->sectionHidden.setBit(first, secondHidden);
00705         d->sectionHidden.setBit(second, firstHidden);
00706     }
00707 
00708     d->viewport->update();
00709     emit sectionMoved(firstLogical, first, second);
00710     emit sectionMoved(secondLogical, second, first);
00711 }
00712 
00721 void QHeaderView::resizeSection(int logical, int size)
00722 {
00723     Q_D(QHeaderView);
00724     if (logical < 0 || logical >= count())
00725         return;
00726 
00727     if (isSectionHidden(logical))
00728         return;
00729 
00730     int oldSize = sectionSize(logical);
00731     if (oldSize == size)
00732         return;
00733 
00734     d->executePostedLayout();
00735     d->invalidateCachedSizeHint();
00736 
00737     int visual = visualIndex(logical);
00738     Q_ASSERT(visual != -1);
00739 
00740     if (stretchLastSection() && visual == count() - 1)
00741         d->lastSectionSize = size;
00742 
00743     if (size != oldSize)
00744         d->createSectionSpan(visual, visual, size, d->headerSectionResizeMode(visual));
00745 
00746     int w = d->viewport->width();
00747     int h = d->viewport->height();
00748     int pos = sectionViewportPosition(logical);
00749     QRect r;
00750     if (orientation() == Qt::Horizontal)
00751         if (isRightToLeft())
00752             r.setRect(0, 0, pos + size, h);
00753         else
00754             r.setRect(pos, 0, w - pos, h);
00755     else
00756         r.setRect(0, pos, w, h - pos);
00757 
00758     if (d->hasAutoResizeSections()) {
00759         resizeSections();
00760         r = d->viewport->rect();
00761     }
00762     d->viewport->update(r.normalized());
00763     emit sectionResized(logical, oldSize, size);
00764 }
00765 
00773 void QHeaderView::resizeSections(QHeaderView::ResizeMode mode)
00774 {
00775     Q_D(QHeaderView);
00776     d->resizeSections(mode, true);
00777 }
00778 
00800 bool QHeaderView::isSectionHidden(int logicalIndex) const
00801 {
00802     Q_D(const QHeaderView);
00803     if (logicalIndex >= d->sectionHidden.count() || logicalIndex < 0 || logicalIndex >= d->sectionCount)
00804         return false;
00805     d->executePostedLayout();
00806     int visual = visualIndex(logicalIndex);
00807     Q_ASSERT(visual != -1);
00808     return d->sectionHidden.testBit(visual);
00809 }
00810 
00818 int QHeaderView::hiddenSectionCount() const
00819 {
00820     Q_D(const QHeaderView);
00821     return d->hiddenSectionSize.count();
00822 }
00823 
00831 void QHeaderView::setSectionHidden(int logicalIndex, bool hide)
00832 {
00833     Q_D(QHeaderView);
00834     if (logicalIndex < 0 || logicalIndex >= count())
00835         return;
00836 
00837     d->executePostedLayout();
00838     int visual = visualIndex(logicalIndex);
00839     Q_ASSERT(visual != -1);
00840     if (hide && d->isVisualIndexHidden(visual))
00841         return;
00842     if (hide) {
00843         int size = sectionSize(logicalIndex);
00844         if (!d->hasAutoResizeSections())
00845             resizeSection(logicalIndex, 0);
00846         d->hiddenSectionSize.insert(logicalIndex, size);
00847         if (d->sectionHidden.count() < count())
00848             d->sectionHidden.resize(count());
00849         d->sectionHidden.setBit(visual, true);
00850         if (d->hasAutoResizeSections())
00851             resizeSections();
00852     } else if (d->isVisualIndexHidden(visual)) {
00853         int size = d->hiddenSectionSize.value(logicalIndex, d->defaultSectionSize);
00854         d->hiddenSectionSize.remove(logicalIndex);
00855         if (d->hiddenSectionSize.isEmpty()) {
00856             d->sectionHidden.clear();
00857         } else {
00858             Q_ASSERT(visual <= d->sectionHidden.count());
00859             d->sectionHidden.setBit(visual, false);
00860         }
00861         resizeSection(logicalIndex, size);
00862     }
00863 }
00864 
00871 int QHeaderView::count() const
00872 {
00873     Q_D(const QHeaderView);
00874     //Q_ASSERT(d->sectionCount == d->headerSectionCount());
00875     // ### this may affect the lazy layout
00876     d->executePostedLayout();
00877     return d->sectionCount;
00878 }
00879 
00888 int QHeaderView::visualIndex(int logicalIndex) const
00889 {
00890     Q_D(const QHeaderView);
00891     if (logicalIndex < 0)
00892         return -1;
00893     d->executePostedLayout();
00894     if (d->visualIndices.isEmpty()) { // nothing has been moved, so we have no mapping
00895         if (logicalIndex < d->sectionCount)
00896             return logicalIndex;
00897     } else if (logicalIndex < d->visualIndices.count()) {
00898         int visual = d->visualIndices.at(logicalIndex);
00899         Q_ASSERT(visual < d->sectionCount);
00900         return visual;
00901     }
00902     return -1;
00903 }
00904 
00912 int QHeaderView::logicalIndex(int visualIndex) const
00913 {
00914     Q_D(const QHeaderView);
00915     if (visualIndex < 0 || visualIndex >= d->sectionCount)
00916         return -1;
00917     return d->logicalIndex(visualIndex);
00918 }
00919 
00927 // ### Qt 5: change to setSectionsMovable()
00928 void QHeaderView::setMovable(bool movable)
00929 {
00930     Q_D(QHeaderView);
00931     d->movableSections = movable;
00932 }
00933 
00941 // ### Qt 5: change to sectionsMovable()
00942 bool QHeaderView::isMovable() const
00943 {
00944     Q_D(const QHeaderView);
00945     return d->movableSections;
00946 }
00947 
00954 // ### Qt 5: change to setSectionsClickable()
00955 void QHeaderView::setClickable(bool clickable)
00956 {
00957     Q_D(QHeaderView);
00958     d->clickableSections = clickable;
00959 }
00960 
00969 // ### Qt 5: change to sectionsClickable()
00970 bool QHeaderView::isClickable() const
00971 {
00972     Q_D(const QHeaderView);
00973     return d->clickableSections;
00974 }
00975 
00976 void QHeaderView::setHighlightSections(bool highlight)
00977 {
00978     Q_D(QHeaderView);
00979     d->highlightSelected = highlight;
00980 }
00981 
00982 bool QHeaderView::highlightSections() const
00983 {
00984     Q_D(const QHeaderView);
00985     return d->highlightSelected;
00986 }
00987 
00995 void QHeaderView::setResizeMode(ResizeMode mode)
00996 {
00997     Q_D(QHeaderView);
00998     initializeSections();
00999     d->stretchSections = (mode == Stretch ? count() : 0);
01000     d->contentsSections =  (mode == ResizeToContents ? count() : 0);
01001     d->setGlobalHeaderResizeMode(mode);
01002     if (d->hasAutoResizeSections())
01003         resizeSections(); // section sizes may change as a result of the new mode
01004 }
01005 
01013 // ### Qt 5: change to setSectionResizeMode()
01014 void QHeaderView::setResizeMode(int logicalIndex, ResizeMode mode)
01015 {
01016     Q_D(QHeaderView);
01017     int visual = visualIndex(logicalIndex);
01018     Q_ASSERT(visual != -1);
01019 
01020     ResizeMode old = d->headerSectionResizeMode(visual);
01021     d->setHeaderSectionResizeMode(visual, mode);
01022 
01023     if (mode == Stretch && old != Stretch)
01024         ++d->stretchSections;
01025     else if (mode == ResizeToContents && old != ResizeToContents)
01026         ++d->contentsSections;
01027     else if (mode != Stretch && old == Stretch)
01028         --d->stretchSections;
01029     else if (mode != ResizeToContents && old == ResizeToContents)
01030         --d->contentsSections;
01031 
01032     if (d->hasAutoResizeSections() && d->state == QHeaderViewPrivate::NoState)
01033         resizeSections(); // section sizes may change as a result of the new mode
01034 }
01035 
01042 QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const
01043 {
01044     Q_D(const QHeaderView);
01045     int visual = visualIndex(logicalIndex);
01046     Q_ASSERT(visual != -1);
01047     return d->visualIndexResizeMode(visual);
01048 }
01049 
01059 int QHeaderView::stretchSectionCount() const
01060 {
01061     Q_D(const QHeaderView);
01062     return d->stretchSections;
01063 }
01064 
01072 void QHeaderView::setSortIndicatorShown(bool show)
01073 {
01074     Q_D(QHeaderView);
01075     d->sortIndicatorShown = show;
01076 
01077     if (sortIndicatorSection() < 0 || sortIndicatorSection() > count())
01078         return;
01079 
01080     if (d->visualIndexResizeMode(sortIndicatorSection()) == ResizeToContents) {
01081         resizeSections();
01082         d->viewport->update();
01083     }
01084 }
01085 
01086 bool QHeaderView::isSortIndicatorShown() const
01087 {
01088     Q_D(const QHeaderView);
01089     return d->sortIndicatorShown;
01090 }
01091 
01100 void QHeaderView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
01101 {
01102     Q_D(QHeaderView);
01103 
01104     Q_ASSERT(logicalIndex >= 0);
01105 
01106     // This is so that people can set the position of the sort indicator before the fill the model
01107     int old = d->sortIndicatorSection;
01108     d->sortIndicatorSection = logicalIndex;
01109     d->sortIndicatorOrder = order;
01110 
01111     if (logicalIndex >= d->sectionCount)
01112         return; // nothing to do
01113 
01114     if (old != logicalIndex && resizeMode(logicalIndex) == ResizeToContents) {
01115         resizeSections();
01116         d->viewport->update();
01117     } else {
01118         if (old != logicalIndex)
01119             updateSection(old);
01120         updateSection(logicalIndex);
01121     }
01122 }
01123 
01131 int QHeaderView::sortIndicatorSection() const
01132 {
01133     Q_D(const QHeaderView);
01134     return d->sortIndicatorSection;
01135 }
01136 
01144 Qt::SortOrder QHeaderView::sortIndicatorOrder() const
01145 {
01146     Q_D(const QHeaderView);
01147     return d->sortIndicatorOrder;
01148 }
01149 
01162 bool QHeaderView::stretchLastSection() const
01163 {
01164     Q_D(const QHeaderView);
01165     return d->stretchLastSection;
01166 }
01167 
01168 void QHeaderView::setStretchLastSection(bool stretch)
01169 {
01170     Q_D(QHeaderView);
01171     d->stretchLastSection = stretch;
01172     if (d->state != QHeaderViewPrivate::NoState)
01173         return;
01174     if (stretch)
01175         resizeSections();
01176     else if (count())
01177         resizeSection(count() - 1, d->defaultSectionSize);
01178 }
01179 
01192 bool QHeaderView::cascadingSectionResizes() const
01193 {
01194     Q_D(const QHeaderView);
01195     return d->cascadingResizing;
01196 }
01197 
01198 void QHeaderView::setCascadingSectionResizes(bool enable)
01199 {
01200     Q_D(QHeaderView);
01201     d->cascadingResizing = enable;
01202 }
01203 
01212 int QHeaderView::defaultSectionSize() const
01213 {
01214     Q_D(const QHeaderView);
01215     return d->defaultSectionSize;
01216 }
01217 
01218 void QHeaderView::setDefaultSectionSize(int size)
01219 {
01220     Q_D(QHeaderView);
01221     d->defaultSectionSize = size;
01222 }
01223 
01238 int QHeaderView::minimumSectionSize() const
01239 {
01240     Q_D(const QHeaderView);
01241     if (d->minimumSectionSize == -1) {
01242         QSize strut = QApplication::globalStrut();
01243         int margin = style()->pixelMetric(QStyle::PM_HeaderMargin);
01244         if (orientation() == Qt::Horizontal)
01245             return qMax(strut.width(), (fontMetrics().maxWidth() + margin));
01246         return qMax(strut.height(), (fontMetrics().lineSpacing() + margin));
01247     }
01248     return d->minimumSectionSize;
01249 }
01250 
01251 void QHeaderView::setMinimumSectionSize(int size)
01252 {
01253     Q_D(QHeaderView);
01254     d->minimumSectionSize = size;
01255 }
01256 
01263 Qt::Alignment QHeaderView::defaultAlignment() const
01264 {
01265     Q_D(const QHeaderView);
01266     return d->defaultAlignment;
01267 }
01268 
01269 void QHeaderView::setDefaultAlignment(Qt::Alignment alignment)
01270 {
01271     Q_D(QHeaderView);
01272     d->defaultAlignment = alignment;
01273 }
01274 
01278 void QHeaderView::doItemsLayout()
01279 {
01280     initializeSections();
01281     QAbstractItemView::doItemsLayout();
01282 }
01283 
01290 bool QHeaderView::sectionsMoved() const
01291 {
01292     Q_D(const QHeaderView);
01293     return !d->visualIndices.isEmpty();
01294 }
01295 
01304 bool QHeaderView::sectionsHidden() const
01305 {
01306     Q_D(const QHeaderView);
01307     return !d->hiddenSectionSize.isEmpty();
01308 }
01309 
01314 void QHeaderView::headerDataChanged(Qt::Orientation orientation, int logicalFirst, int logicalLast)
01315 {
01316     Q_D(QHeaderView);
01317     if (d->orientation != orientation)
01318         return;
01319 
01320     if (logicalFirst < 0 || logicalLast < 0 || logicalFirst >= count() || logicalLast >= count())
01321         return;
01322 
01323     d->invalidateCachedSizeHint();
01324 
01325     if (orientation == Qt::Horizontal) {
01326         int left = sectionViewportPosition(logicalFirst);
01327         int right = sectionViewportPosition(logicalLast);
01328         right += sectionSize(logicalLast);
01329         d->viewport->update(left, 0, right - left, d->viewport->height());
01330     } else {
01331         int top = sectionViewportPosition(logicalFirst);
01332         int bottom = sectionViewportPosition(logicalLast);
01333         bottom += sectionSize(logicalLast);
01334         d->viewport->update(0, top, d->viewport->width(), bottom - top);
01335     }
01336 }
01337 
01345 void QHeaderView::updateSection(int logicalIndex)
01346 {
01347     Q_D(QHeaderView);
01348     if (orientation() == Qt::Horizontal)
01349         d->viewport->update(QRect(sectionViewportPosition(logicalIndex),
01350                                   0, sectionSize(logicalIndex), d->viewport->height()));
01351     else
01352         d->viewport->update(QRect(0, sectionViewportPosition(logicalIndex),
01353                                   d->viewport->width(), sectionSize(logicalIndex)));
01354 }
01355 
01361 void QHeaderView::resizeSections()
01362 {
01363     Q_D(QHeaderView);
01364     if (d->hasAutoResizeSections())
01365         d->resizeSections(Interactive, false); // no global resize mode
01366 }
01367 
01377 void QHeaderView::sectionsInserted(const QModelIndex &parent, int logicalFirst, int)
01378 {
01379     Q_D(QHeaderView);
01380     if (parent != d->root)
01381         return; // we only handle changes in the top level
01382     int lastSection;
01383     if (d->orientation == Qt::Horizontal)
01384         lastSection = qMax(d->model->columnCount(d->root) - 1, 0);
01385     else
01386         lastSection = qMax(d->model->rowCount(d->root) -  1, 0);
01387     int oldCount = d->sectionCount;
01388     int oldLastSection = qMax(oldCount - 1, 0);
01389     initializeSections(qMin(oldLastSection + 1, logicalFirst), lastSection);
01390     resizeSections();
01391     emit sectionCountChanged(oldCount, count());
01392 }
01393 
01401 void QHeaderView::sectionsAboutToBeRemoved(const QModelIndex &parent,
01402                                            int logicalFirst, int logicalLast)
01403 {
01404     Q_UNUSED(parent);
01405     Q_UNUSED(logicalFirst);
01406     Q_UNUSED(logicalLast);
01407 }
01408 
01409 void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
01410                                             int logicalFirst, int logicalLast)
01411 {
01412     Q_Q(QHeaderView);
01413     if (parent != root)
01414         return; // we only handle changes in the top level
01415     if (qMin(logicalFirst, logicalLast) < 0
01416         || qMax(logicalLast, logicalFirst) >= sectionCount)
01417         return;
01418     int oldCount = q->count();
01419     int changeCount = logicalLast - logicalFirst + 1;
01420     if (visualIndices.isEmpty() && logicalIndices.isEmpty()) {
01421         for (int i = logicalFirst; i <= changeCount+logicalFirst; ++i)
01422             hiddenSectionSize.remove(i);
01423         //Q_ASSERT(headerSectionCount() == sectionCount);
01424         removeSectionsFromSpans(logicalFirst, logicalLast);
01425     } else {
01426         for (int l = logicalLast; l >= logicalFirst; --l) {
01427             int visual = visualIndices.at(l);
01428             for (int v = 0; v < sectionCount; ++v) {
01429                 if (v > visual) {
01430                     int logical = logicalIndex(v);
01431                     --(visualIndices[logical]);
01432                 }
01433                 if (logicalIndex(v) > l) // no need to move the positions before l
01434                     --(logicalIndices[v]);
01435             }
01436             hiddenSectionSize.remove(l);
01437             logicalIndices.remove(visual);
01438             visualIndices.remove(l);
01439             //Q_ASSERT(headerSectionCount() == sectionCount);
01440             removeSectionsFromSpans(visual, visual);
01441         }
01442         // ### handle sectionSelection, sectionHidden
01443     }
01444     sectionCount -= changeCount;
01445 
01446     // if we only have the last section (the "end" position) left, the header is empty
01447     if (sectionCount <= 0)
01448         clear();
01449     invalidateCachedSizeHint();
01450     emit q->sectionCountChanged(oldCount, q->count());
01451     viewport->update();
01452 }
01453 
01458 void QHeaderView::initializeSections()
01459 {
01460     Q_D(QHeaderView);
01461     if (d->orientation == Qt::Horizontal) {
01462         int c = d->model->columnCount(d->root);
01463         if (c == 0) {
01464             int oldCount = count();
01465             d->clear();
01466             emit sectionCountChanged(oldCount, 0);
01467         } else if (c != count() && c > 0) {
01468             initializeSections(0, c - 1);
01469         }
01470     } else {
01471         int r = d->model->rowCount(d->root);
01472         if (r == 0) {
01473             int oldCount = count();
01474             d->clear();
01475             emit sectionCountChanged(oldCount, 0);
01476         } else if (r != count() && r > 0) {
01477             initializeSections(0, r - 1);
01478         }
01479     }
01480     if (stretchLastSection())
01481         d->lastSectionSize = sectionSizeHint(logicalIndex(count() - 1));
01482 }
01483 
01488 void QHeaderView::initializeSections(int start, int end)
01489 {
01490     Q_D(QHeaderView);
01491 
01492     Q_ASSERT(start >= 0);
01493     Q_ASSERT(end >= 0);
01494 
01495     d->invalidateCachedSizeHint();
01496 
01497     // Edge case such as when a model emits layoutChanged when removing items
01498     if (end < count())
01499         d->removeSectionsFromSpans(end + 1, count());
01500 
01501     int oldCount = d->sectionCount;
01502     d->sectionCount = end + 1;
01503 
01504     if (!d->logicalIndices.isEmpty()) {
01505         d->logicalIndices.resize(d->sectionCount);
01506         d->visualIndices.resize(d->sectionCount);
01507         for (int i = start; i < d->sectionCount; ++i){
01508             d->logicalIndices[i] = i;
01509             d->visualIndices[i] = i;
01510         }
01511     }
01512 
01513     if (d->globalResizeMode == Stretch)
01514         d->stretchSections = d->sectionCount;
01515     else if (d->globalResizeMode == ResizeToContents)
01516          d->contentsSections = d->sectionCount;
01517     if (!d->sectionHidden.isEmpty())
01518         d->sectionHidden.resize(d->sectionCount);
01519 
01520     d->createSectionSpan(start, end, (end - start + 1) * d->defaultSectionSize, d->globalResizeMode);
01521     //Q_ASSERT(d->headerLength() == d->length);
01522 
01523     emit sectionCountChanged(oldCount,  d->sectionCount);
01524     d->viewport->update();
01525 }
01526 
01531 void QHeaderView::currentChanged(const QModelIndex &current, const QModelIndex &old)
01532 {
01533     Q_D(QHeaderView);
01534 
01535     if (d->orientation == Qt::Horizontal && current.column() != old.column()) {
01536         if (old.isValid() && old.parent() == d->root)
01537             d->setDirtyRegion(QRect(sectionViewportPosition(old.column()), 0,
01538                                     sectionSize(old.column()), d->viewport->height()));
01539         if (current.isValid() && current.parent() == d->root)
01540             d->setDirtyRegion(QRect(sectionViewportPosition(current.column()), 0,
01541                                     sectionSize(current.column()), d->viewport->height()));
01542     } else if (d->orientation == Qt::Vertical && current.row() != old.row()) {
01543         if (old.isValid() && old.parent() == d->root)
01544             d->setDirtyRegion(QRect(0, sectionViewportPosition(old.row()),
01545                                     d->viewport->width(), sectionSize(old.row())));
01546         if (current.isValid() && current.parent() == d->root)
01547             d->setDirtyRegion(QRect(0, sectionViewportPosition(current.row()),
01548                                     d->viewport->width(), sectionSize(current.row())));
01549     }
01550     d->updateDirtyRegion();
01551 }
01552 
01553 
01558 bool QHeaderView::event(QEvent *e)
01559 {
01560     Q_D(QHeaderView);
01561     switch (e->type()) {
01562     case QEvent::HoverEnter: {
01563         QHoverEvent *he = static_cast<QHoverEvent*>(e);
01564         d->hover = logicalIndexAt(he->pos());
01565         if (d->hover != -1)
01566             updateSection(d->hover);
01567         break; }
01568     case QEvent::HoverLeave: {
01569         if (d->hover != -1)
01570             updateSection(d->hover);
01571         d->hover = -1;
01572         break; }
01573     case QEvent::HoverMove: {
01574         QHoverEvent *he = static_cast<QHoverEvent*>(e);
01575         int oldHover = d->hover;
01576         d->hover = logicalIndexAt(he->pos());
01577         if (d->hover != oldHover) {
01578             if (oldHover != -1)
01579                 updateSection(oldHover);
01580             if (d->hover != -1)
01581                 updateSection(d->hover);
01582         }
01583         break; }
01584     default:
01585         break;
01586     }
01587     return QAbstractItemView::event(e);
01588 }
01589 
01594 void QHeaderView::paintEvent(QPaintEvent *e)
01595 {
01596     Q_D(QHeaderView);
01597 
01598     if (count() == 0)
01599         return;
01600 
01601     QPainter painter(d->viewport);
01602     const QPoint offset = d->scrollDelayOffset;
01603     QRect translatedEventRect = e->rect();
01604     translatedEventRect.translate(offset);
01605 
01606     int start = -1;
01607     int end = -1;
01608     if (orientation() == Qt::Horizontal) {
01609         start = visualIndexAt(translatedEventRect.left());
01610         end = visualIndexAt(translatedEventRect.right());
01611     } else {
01612         start = visualIndexAt(translatedEventRect.top());
01613         end = visualIndexAt(translatedEventRect.bottom());
01614     }
01615 
01616     if (d->reverse()) {
01617         start = (start == -1 ? count() - 1 : start);
01618         end = (end == -1 ? 0 : end);
01619     } else {
01620         start = (start == -1 ? 0 : start);
01621         end = (end == -1 ? count() - 1 : end);
01622     }
01623 
01624     int tmp = start;
01625     start = qMin(start, end);
01626     end = qMax(tmp, end);
01627 
01628     d->prepareSectionSelected(); // clear and resize the bit array
01629 
01630     QRect currentSectionRect;
01631     int logical;
01632     const int width = d->viewport->width();
01633     const int height = d->viewport->height();
01634     const bool active = isActiveWindow();
01635     for (int i = start; i <= end; ++i) {
01636         if (d->isVisualIndexHidden(i))
01637             continue;
01638         painter.save();
01639         logical = logicalIndex(i);
01640         bool highlight = false;
01641         if (orientation() == Qt::Horizontal) {
01642             currentSectionRect.setRect(sectionViewportPosition(logical), 0, sectionSize(logical), height);
01643             if (d->highlightSelected && active)
01644                 highlight = d->columnIntersectsSelection(logical);
01645         } else {
01646             currentSectionRect.setRect(0, sectionViewportPosition(logical), width, sectionSize(logical));
01647             if (d->highlightSelected && active)
01648                 highlight = d->rowIntersectsSelection(logical);
01649         }
01650         currentSectionRect.translate(offset);
01651 
01652         QVariant variant = d->model->headerData(logical, orientation(),
01653                                                 Qt::FontRole);
01654         if (variant.isValid() && qVariantCanConvert<QFont>(variant)) {
01655             QFont sectionFont = qvariant_cast<QFont>(variant);
01656             if (highlight)
01657                 sectionFont.setBold(true);
01658             painter.setFont(sectionFont);
01659         }
01660         paintSection(&painter, currentSectionRect, logical);
01661         painter.restore();
01662     }
01663 
01664     // Paint the area beyond where there are indexes
01665     if (d->reverse()) {
01666         if (currentSectionRect.left() > translatedEventRect.left())
01667             painter.fillRect(translatedEventRect.left(), 0,
01668                              currentSectionRect.left() - translatedEventRect.left(), height,
01669                              palette().background());
01670     } else if (currentSectionRect.right() < translatedEventRect.right()) {
01671         // paint to the right
01672         painter.fillRect(currentSectionRect.right() + 1, 0,
01673                          translatedEventRect.right() - currentSectionRect.right(), height,
01674                          palette().background());
01675     } else if (currentSectionRect.bottom() < translatedEventRect.bottom()) {
01676         painter.fillRect(0, currentSectionRect.bottom() + 1,
01677                          width, height - currentSectionRect.bottom() - 1,
01678                          palette().background());
01679     }
01680 
01681 #if 0
01682     // ### visualize section spans
01683     for (int a = 0, i = 0; i < d->sectionSpans.count(); ++i) {
01684         QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
01685         if (orientation() == Qt::Horizontal)
01686             painter.fillRect(a - d->offset, 0, d->sectionSpans.at(i).size, 4, color);
01687         else
01688             painter.fillRect(0, a - d->offset, 4, d->sectionSpans.at(i).size, color);
01689         a += d->sectionSpans.at(i).size;
01690     }
01691 
01692 #endif
01693 }
01694 
01699 void QHeaderView::mousePressEvent(QMouseEvent *e)
01700 {
01701     Q_D(QHeaderView);
01702     if (d->state != QHeaderViewPrivate::NoState || e->button() != Qt::LeftButton)
01703         return;
01704     int pos = orientation() == Qt::Horizontal ? e->x() : e->y();
01705     int handle = d->sectionHandleAt(pos);
01706     while (handle > -1 && isSectionHidden(handle)) --handle;
01707     if (handle == -1) {
01708         d->pressed = logicalIndexAt(pos);
01709         if (d->movableSections) {
01710             d->section = d->target = d->pressed;
01711             if (d->section == -1)
01712                 return;
01713             d->state = QHeaderViewPrivate::MoveSection;
01714             d->setupSectionIndicator(d->section, pos);
01715         }
01716         if (d->clickableSections && d->pressed != -1) {
01717             updateSection(d->pressed);
01718             emit sectionPressed(d->pressed);
01719         }
01720     } else if (resizeMode(handle) == Interactive) {
01721         Q_ASSERT(d->originalSize == -1);
01722         d->originalSize = sectionSize(handle);
01723         d->state = QHeaderViewPrivate::ResizeSection;
01724         d->section = handle;
01725     }
01726 
01727     d->firstPos = pos;
01728     d->lastPos = pos;
01729 
01730     d->clearCascadingSections();
01731 }
01732 
01737 void QHeaderView::mouseMoveEvent(QMouseEvent *e)
01738 {
01739     Q_D(QHeaderView);
01740     int pos = orientation() == Qt::Horizontal ? e->x() : e->y();
01741     if (pos < 0)
01742         return;
01743     if (e->buttons() == Qt::NoButton) {
01744         d->state = QHeaderViewPrivate::NoState;
01745         d->pressed = -1;
01746     }
01747     switch (d->state) {
01748         case QHeaderViewPrivate::ResizeSection: {
01749             Q_ASSERT(d->originalSize != -1);
01750             if (d->cascadingResizing) {
01751                 int delta = d->reverse() ? d->lastPos - pos : pos - d->lastPos;
01752                 int visual = visualIndex(d->section);
01753                 d->cascadingResize(visual, d->headerSectionSize(visual) + delta);
01754             } else {
01755                 int delta = d->reverse() ? d->firstPos - pos : pos - d->firstPos;
01756                 resizeSection(d->section, qMax(d->originalSize + delta, minimumSectionSize()));
01757             }
01758             d->lastPos = pos;
01759             return;
01760         }
01761         case QHeaderViewPrivate::MoveSection: {
01762             if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()) {
01763                 int indicatorCenter = (orientation() == Qt::Horizontal
01764                                        ? d->sectionIndicator->width()
01765                                        : d->sectionIndicator->height()) / 2;
01766                 int centerOffset = indicatorCenter - d->sectionIndicatorOffset;
01767                 // This will drop the moved section to the position under the center of the indicator.
01768                 // If centerOffset is 0, the section will be moved to the position of the mouse cursor.
01769                 int visual = visualIndexAt(pos + centerOffset);
01770                 if (visual == -1)
01771                     return;
01772                 d->target = d->logicalIndex(visual);
01773                 d->updateSectionIndicator(d->section, pos);
01774             } else {
01775                 int visual = visualIndexAt(d->firstPos);
01776                 if (visual == -1)
01777                     return;
01778                 d->target = d->logicalIndex(visual);
01779                 d->updateSectionIndicator(d->section, d->firstPos);
01780             }
01781             return;
01782         }
01783         case QHeaderViewPrivate::NoState: {
01784 #ifndef QT_NO_CURSOR
01785             int handle = d->sectionHandleAt(pos);
01786             if (handle != -1 && (resizeMode(handle) == Interactive))
01787                 setCursor(orientation() == Qt::Horizontal ? Qt::SplitHCursor : Qt::SplitVCursor);
01788             else
01789                 setCursor(Qt::ArrowCursor);
01790 #endif
01791             return;
01792         }
01793     }
01794 }
01795 
01800 void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
01801 {
01802     Q_D(QHeaderView);
01803     int pos = orientation() == Qt::Horizontal ? e->x() : e->y();
01804     switch (d->state) {
01805     case QHeaderViewPrivate::MoveSection:
01806         if (!d->sectionIndicator->isHidden()) { // moving
01807             int from = visualIndex(d->section);
01808             Q_ASSERT(from != -1);
01809             int to = visualIndex(d->target);
01810             Q_ASSERT(to != -1);
01811             moveSection(from, to);
01812             d->section = d->target = -1;
01813             d->updateSectionIndicator(d->section, pos);
01814             break;
01815         } // not moving
01816     case QHeaderViewPrivate::NoState:
01817         if (d->clickableSections) {
01818             int section = logicalIndexAt(pos);
01819             if (section != -1 && section == d->pressed) {
01820                 if (d->sortIndicatorShown)
01821                     d->flipSortIndicator(section);
01822                 emit sectionClicked(logicalIndexAt(pos));
01823             }
01824             if (d->pressed != -1)
01825                 updateSection(d->pressed);
01826         }
01827         break;
01828     case QHeaderViewPrivate::ResizeSection:
01829         d->originalSize = -1;
01830         d->clearCascadingSections();
01831         break;
01832     }
01833     d->state = QHeaderViewPrivate::NoState;
01834     d->pressed = -1;
01835 }
01836 
01841 void QHeaderView::mouseDoubleClickEvent(QMouseEvent *e)
01842 {
01843     Q_D(QHeaderView);
01844     int pos = orientation() == Qt::Horizontal ? e->x() : e->y();
01845     int handle = d->sectionHandleAt(pos);
01846     while (handle > -1 && isSectionHidden(handle)) handle--;
01847     if (handle > -1 && resizeMode(handle) == Interactive) {
01848         emit sectionHandleDoubleClicked(handle);
01849 #ifndef QT_NO_CURSOR
01850         Qt::CursorShape splitCursor = (orientation() == Qt::Horizontal)
01851                                       ? Qt::SplitHCursor : Qt::SplitVCursor;
01852         if (cursor().shape() == splitCursor) {
01853             // signal handlers may have changed the section size
01854             handle = d->sectionHandleAt(pos);
01855             while (handle > -1 && isSectionHidden(handle)) handle--;
01856             if (!(handle > -1 && resizeMode(handle) == Interactive))
01857                 setCursor(Qt::ArrowCursor);
01858         }
01859 #endif
01860     } else {
01861         emit sectionDoubleClicked(logicalIndexAt(e->pos()));
01862     }
01863 }
01864 
01869 bool QHeaderView::viewportEvent(QEvent *e)
01870 {
01871     Q_D(QHeaderView);
01872     switch (e->type()) {
01873 #ifndef QT_NO_TOOLTIP
01874     case QEvent::ToolTip: {
01875         if (!isActiveWindow())
01876             break;
01877         QHelpEvent *he = static_cast<QHelpEvent*>(e);
01878         int logical = logicalIndexAt(he->pos());
01879         if (logical != -1) {
01880             QVariant variant = d->model->headerData(logical, orientation(), Qt::ToolTipRole);
01881             if (variant.isValid()) {
01882                 QToolTip::showText(he->globalPos(), variant.toString(), this);
01883                 return true;
01884             }
01885         }
01886         break; }
01887 #endif
01888 #ifndef QT_NO_WHATSTHIS
01889     case QEvent::QueryWhatsThis: {
01890         QHelpEvent *he = static_cast<QHelpEvent*>(e);
01891         int logical = logicalIndexAt(he->pos());
01892         if (logical != -1
01893             && d->model->headerData(logical, orientation(), Qt::WhatsThisRole).isValid())
01894             return true;
01895         break; }
01896     case QEvent::WhatsThis: {
01897         QHelpEvent *he = static_cast<QHelpEvent*>(e);
01898         int logical = logicalIndexAt(he->pos());
01899         if (logical != -1) {
01900              QVariant whatsthis = d->model->headerData(logical, orientation(),
01901                                                       Qt::WhatsThisRole);
01902              if (whatsthis.isValid()) {
01903                  QWhatsThis::showText(he->globalPos(), whatsthis.toString(), this);
01904                  return true;
01905              }
01906         }
01907         break; }
01908 #endif // QT_NO_WHATSTHIS
01909 #ifndef QT_NO_STATUSTIP
01910     case QEvent::StatusTip: {
01911         QHelpEvent *he = static_cast<QHelpEvent*>(e);
01912         int logical = logicalIndexAt(he->pos());
01913         if (logical != -1) {
01914             QString statustip = d->model->headerData(logical, orientation(),
01915                                                     Qt::StatusTipRole).toString();
01916             if (!statustip.isEmpty())
01917                 setStatusTip(statustip);
01918         }
01919         return true; }
01920 #endif // QT_NO_STATUSTIP
01921     case QEvent::Hide:
01922     case QEvent::Show:
01923     case QEvent::FontChange:
01924         resizeSections();
01925         emit geometriesChanged();
01926         break;
01927     case QEvent::ContextMenu: {
01928         d->state = QHeaderViewPrivate::NoState;
01929         d->pressed =d->section = d->target = -1;
01930         d->updateSectionIndicator(d->section, -1);
01931     }
01932     default:
01933         break;
01934     }
01935     return QAbstractItemView::viewportEvent(e);
01936 }
01937 
01944 void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
01945 {
01946     Q_D(const QHeaderView);
01947     if (!rect.isValid())
01948         return;
01949     // get the state of the section
01950     QStyleOptionHeader opt = d->getStyleOption();
01951     QStyle::State state = QStyle::State_None;
01952     if (isEnabled())
01953         state |= QStyle::State_Enabled;
01954     if (window()->isActiveWindow())
01955         state |= QStyle::State_Active;
01956     if (d->clickableSections) {
01957         if (logicalIndex == d->hover)
01958             state |= QStyle::State_MouseOver;
01959         if (logicalIndex == d->pressed)
01960             state |= QStyle::State_Sunken;
01961         else if (d->highlightSelected && d->isSectionSelected(logicalIndex))
01962             state |= QStyle::State_On | QStyle::State_Sunken;
01963     }
01964     if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
01965         opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
01966                             ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
01967 
01968     // setup the style options structure
01969     QVariant textAlignment = d->model->headerData(logicalIndex, orientation(),
01970                                                   Qt::TextAlignmentRole);
01971     opt.rect = rect;
01972     opt.section = logicalIndex;
01973     opt.state |= state;
01974     opt.textAlignment = Qt::Alignment(textAlignment.isValid()
01975                                       ? Qt::Alignment(textAlignment.toInt())
01976                                       : d->defaultAlignment);
01977     opt.iconAlignment = Qt::AlignVCenter;
01978     opt.text = d->model->headerData(logicalIndex, orientation(),
01979                                     Qt::DisplayRole).toString();
01980     if (d->textElideMode != Qt::ElideNone)
01981         opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - 4);
01982 
01983     QVariant variant = d->model->headerData(logicalIndex, orientation(),
01984                                     Qt::DecorationRole);
01985     opt.icon = qvariant_cast<QIcon>(variant);
01986     if (opt.icon.isNull())
01987         opt.icon = qvariant_cast<QPixmap>(variant);
01988     QVariant foregroundBrush = d->model->headerData(logicalIndex, orientation(),
01989                                                     Qt::ForegroundRole);
01990     if (qVariantCanConvert<QBrush>(foregroundBrush))
01991         opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(foregroundBrush));
01992 
01993     QPointF oldBO = painter->brushOrigin();
01994     QVariant backgroundBrush = d->model->headerData(logicalIndex, orientation(),
01995                                                     Qt::BackgroundRole);
01996     if (qVariantCanConvert<QBrush>(backgroundBrush)) {
01997         opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(backgroundBrush));
01998         opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(backgroundBrush));
01999         painter->setBrushOrigin(opt.rect.topLeft());
02000     }
02001 
02002     // the section position
02003     int visual = visualIndex(logicalIndex);
02004     Q_ASSERT(visual != -1);
02005     if (count() == 1)
02006         opt.position = QStyleOptionHeader::OnlyOneSection;
02007     else if (visual == 0)
02008         opt.position = QStyleOptionHeader::Beginning;
02009     else if (visual == count() - 1)
02010         opt.position = QStyleOptionHeader::End;
02011     else
02012         opt.position = QStyleOptionHeader::Middle;
02013     opt.orientation = d->orientation;
02014     // the selected position
02015     bool previousSelected = d->isSectionSelected(this->logicalIndex(visual - 1));
02016     bool nextSelected =  d->isSectionSelected(this->logicalIndex(visual + 1));
02017     if (previousSelected && nextSelected)
02018         opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
02019     else if (previousSelected)
02020         opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
02021     else if (nextSelected)
02022         opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
02023     else
02024         opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
02025     // draw the section
02026     style()->drawControl(QStyle::CE_Header, &opt, painter, this);
02027 
02028     painter->setBrushOrigin(oldBO);
02029 }
02030 
02037 QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const
02038 {
02039     Q_D(const QHeaderView);
02040     Q_ASSERT(logicalIndex >= 0);
02041     QSize size(100, 30); // ### make this depend on the font size
02042 
02043     // use SizeHintRole
02044     QVariant variant = d->model->headerData(logicalIndex, orientation(), Qt::SizeHintRole);
02045     if (variant.isValid())
02046         return qvariant_cast<QSize>(variant);
02047 
02048     // otherwise use the contents
02049     QStyleOptionHeader opt = d->getStyleOption();
02050     QVariant var = d->model->headerData(logicalIndex, orientation(),
02051                                             Qt::FontRole);
02052     QFont fnt;
02053     if (var.isValid() && qVariantCanConvert<QFont>(var))
02054         fnt = qvariant_cast<QFont>(var);
02055     else
02056         fnt = font();
02057     fnt.setBold(true);
02058     opt.fontMetrics = QFontMetrics(fnt);
02059     opt.text = d->model->headerData(logicalIndex, orientation(),
02060                                     Qt::DisplayRole).toString();
02061     variant = d->model->headerData(logicalIndex, orientation(), Qt::DecorationRole);
02062     opt.icon = qvariant_cast<QIcon>(variant);
02063     if (opt.icon.isNull())
02064         opt.icon = qvariant_cast<QPixmap>(variant);
02065     size = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, size, this);
02066 
02067     if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex) {
02068         int margin = style()->pixelMetric(QStyle::PM_HeaderMargin);
02069         if (orientation() == Qt::Horizontal)
02070             size.rwidth() += size.height() + margin;
02071         else
02072             size.rheight() += size.width() + margin;
02073     }
02074     return size;
02075 }
02076 
02084 int QHeaderView::horizontalOffset() const
02085 {
02086     Q_D(const QHeaderView);
02087     if (orientation() == Qt::Horizontal)
02088         return d->offset;
02089     return 0;
02090 }
02091 
02099 int QHeaderView::verticalOffset() const
02100 {
02101     Q_D(const QHeaderView);
02102     if (orientation() == Qt::Vertical)
02103         return d->offset;
02104     return 0;
02105 }
02106 
02112 void QHeaderView::updateGeometries()
02113 {
02114     Q_D(QHeaderView);
02115     d->layoutChildren();
02116     if (d->hasAutoResizeSections())
02117         resizeSections();
02118 }
02119 
02125 void QHeaderView::scrollContentsBy(int dx, int dy)
02126 {
02127     Q_D(QHeaderView);
02128     d->scrollDirtyRegion(dx, dy);
02129 }
02130 
02135 void QHeaderView::dataChanged(const QModelIndex &, const QModelIndex &)
02136 {
02137     Q_D(QHeaderView);
02138     d->invalidateCachedSizeHint();
02139 }
02140 
02147 void QHeaderView::rowsInserted(const QModelIndex &, int, int)
02148 {
02149     // do nothing
02150 }
02151 
02159 QRect QHeaderView::visualRect(const QModelIndex &) const
02160 {
02161     return QRect();
02162 }
02163 
02171 void QHeaderView::scrollTo(const QModelIndex &, ScrollHint)
02172 {
02173     // do nothing - the header only displays sections
02174 }
02175 
02183 QModelIndex QHeaderView::indexAt(const QPoint &) const
02184 {
02185     return QModelIndex();
02186 }
02187 
02195 bool QHeaderView::isIndexHidden(const QModelIndex &) const
02196 {
02197     return true; // the header view has no items, just sections
02198 }
02199 
02207 QModelIndex QHeaderView::moveCursor(CursorAction, Qt::KeyboardModifiers)
02208 {
02209     return QModelIndex();
02210 }
02211 
02221 void QHeaderView::setSelection(const QRect&, QItemSelectionModel::SelectionFlags)
02222 {
02223     // do nothing
02224 }
02225 
02230 QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) const
02231 {
02232     Q_D(const QHeaderView);
02233     if (orientation() == Qt::Horizontal) {
02234         int left = d->model->columnCount(d->root) - 1;
02235         int right = 0;
02236         int rangeLeft, rangeRight;
02237 
02238         for (int i = 0; i < selection.count(); ++i) {
02239             QItemSelectionRange r = selection.at(i);
02240             if (r.parent().isValid() || !r.isValid())
02241                 continue; // we only know about toplevel items and we don't want invalid ranges
02242             // FIXME an item inside the range may be the leftmost or rightmost
02243             rangeLeft = visualIndex(r.left());
02244             if (rangeLeft == -1) // in some cases users may change the selections
02245                 continue;        // before we have a chance to do the layout
02246             rangeRight = visualIndex(r.right());
02247             if (rangeRight == -1) // in some cases users may change the selections
02248                 continue;         // before we have a chance to do the layout
02249             if (rangeLeft < left)
02250                 left = rangeLeft;
02251             if (rangeRight > right)
02252                 right = rangeRight;
02253         }
02254 
02255         int logicalLeft = logicalIndex(left);
02256         int logicalRight = logicalIndex(right);
02257 
02258         if (logicalLeft < 0  || logicalLeft >= count() ||
02259             logicalRight < 0 || logicalRight >= count())
02260             return QRegion();
02261 
02262         int leftPos = sectionViewportPosition(logicalLeft);
02263         int rightPos = sectionViewportPosition(logicalRight);
02264         rightPos += sectionSize(logicalRight);
02265         return QRect(leftPos, 0, rightPos - leftPos, height());
02266     }
02267     // orientation() == Qt::Vertical
02268     int top = d->model->rowCount(d->root) - 1;
02269     int bottom = 0;
02270     int rangeTop, rangeBottom;
02271 
02272     for (int i = 0; i < selection.count(); ++i) {
02273         QItemSelectionRange r = selection.at(i);
02274         if (r.parent().isValid() || !r.isValid())
02275             continue; // we only know about toplevel items
02276         // FIXME an item inside the range may be the leftmost or rightmost
02277         rangeTop = visualIndex(r.top());
02278         if (rangeTop == -1) // in some cases users may change the selections
02279             continue;       // before we have a chance to do the layout
02280         rangeBottom = visualIndex(r.bottom());
02281         if (rangeBottom == -1) // in some cases users may change the selections
02282             continue;          // before we have a chance to do the layout
02283         if (rangeTop < top)
02284             top = rangeTop;
02285         if (rangeBottom > bottom)
02286             bottom = rangeBottom;
02287     }
02288 
02289     int logicalTop = logicalIndex(top);
02290     int logicalBottom = logicalIndex(bottom);
02291 
02292     if (logicalTop == -1 || logicalBottom == -1)
02293         return QRect();
02294 
02295     int topPos = sectionViewportPosition(logicalTop);
02296     int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);
02297 
02298     return QRect(0, topPos, width(), bottomPos - topPos);
02299 }
02300 
02301 
02302 // private implementation
02303 
02304 int QHeaderViewPrivate::sectionHandleAt(int position)
02305 {
02306     Q_Q(QHeaderView);
02307     int visual = q->visualIndexAt(position);
02308     if (visual == -1)
02309         return -1;
02310     int log = logicalIndex(visual);
02311     int pos = q->sectionViewportPosition(log);
02312     int grip = q->style()->pixelMetric(QStyle::PM_HeaderGripMargin);
02313     if (reverse()) {
02314         if (position < pos + grip)
02315             return log;
02316         if (visual > 0 && position > pos + q->sectionSize(log) - grip)
02317             return q->logicalIndex(visual - 1);
02318     } else {
02319         if (visual > 0 && position < pos + grip)
02320             return q->logicalIndex(visual - 1);
02321         if (position > pos + q->sectionSize(log) - grip)
02322             return log;
02323     }
02324     return -1;
02325 }
02326 
02327 void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
02328 {
02329     Q_Q(QHeaderView);
02330     if (!sectionIndicator) {
02331         sectionIndicator = new QLabel(viewport);
02332         sectionIndicator->setWindowOpacity(0.75);
02333     }
02334 
02335     int x, y, w, h;
02336     int p = q->sectionViewportPosition(section);
02337     if (orientation == Qt::Horizontal) {
02338         x = p;
02339         y = 0;
02340         w = q->sectionSize(section);
02341         h = viewport->height();
02342     } else {
02343         x = 0;
02344         y = p;
02345         w = viewport->width();
02346         h = q->sectionSize(section);
02347     }
02348     sectionIndicator->resize(w, h);
02349     QPixmap pix = QPixmap::grabWidget(viewport, x, y, w, h);
02350     sectionIndicator->setPixmap(pix);
02351     sectionIndicatorOffset = position - qMax(p, 0);
02352 
02353 }
02354 
02355 void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
02356 {
02357     if (!sectionIndicator)
02358         return;
02359 
02360     if (section == -1 || target == -1) {
02361         sectionIndicator->hide();
02362         return;
02363     }
02364 
02365     if (orientation == Qt::Horizontal)
02366         sectionIndicator->move(position - sectionIndicatorOffset, 0);
02367     else
02368         sectionIndicator->move(0, position - sectionIndicatorOffset);
02369 
02370     sectionIndicator->show();
02371 }
02372 
02373 QStyleOptionHeader QHeaderViewPrivate::getStyleOption() const
02374 {
02375     Q_Q(const QHeaderView);
02376     QStyleOptionHeader opt;
02377     opt.initFrom(q);
02378     opt.state = QStyle::State_None | QStyle::State_Raised;
02379     opt.orientation = orientation;
02380     if (orientation == Qt::Horizontal)
02381         opt.state |= QStyle::State_Horizontal;
02382     if (q->isEnabled())
02383         opt.state |= QStyle::State_Enabled;
02384     opt.section = 0;
02385     return opt;
02386 }
02387 
02388 bool QHeaderViewPrivate::isSectionSelected(int section) const
02389 {
02390     int i = section * 2;
02391     if (i < 0 || i >= sectionSelected.count())
02392         return false;
02393     if (sectionSelected.testBit(i)) // if the value was cached
02394         return sectionSelected.testBit(i + 1);
02395     bool s = false;
02396     if (orientation == Qt::Horizontal)
02397         s = isColumnSelected(section);
02398     else
02399         s = isRowSelected(section);
02400     sectionSelected.setBit(i + 1, s); // selection state
02401     sectionSelected.setBit(i, true); // cache state
02402     return s;
02403 }
02404 
02418 void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode)
02419 {
02420     Q_Q(QHeaderView);
02421 
02422     executePostedLayout();
02423     if (sectionCount == 0)
02424         return;
02425     invalidateCachedSizeHint();
02426 
02427     // find stretchLastSection if we have it
02428     int stretchSection = -1;
02429     if (stretchLastSection && !useGlobalMode) {
02430         for (int i = sectionCount - 1; i >= 0; --i) {
02431             if (!isVisualIndexHidden(i)) {
02432                 stretchSection = i;
02433                 break;
02434             }
02435         }
02436     }
02437 
02438     // count up the number of strected sections and how much space left for them
02439     int lengthToStrech = (orientation == Qt::Horizontal ? viewport->width() : viewport->height());
02440     int numberOfStretchedSections = 0;
02441     QList<int> section_sizes;
02442     for (int i = 0; i < sectionCount; ++i) {
02443         if (isVisualIndexHidden(i))
02444             continue;
02445 
02446         QHeaderView::ResizeMode resizeMode;
02447         if (useGlobalMode && (i != stretchSection))
02448             resizeMode = globalMode;
02449         else
02450             resizeMode = (i == stretchSection ? QHeaderView::Stretch : visualIndexResizeMode(i));
02451 
02452         if (resizeMode == QHeaderView::Stretch) {
02453             ++numberOfStretchedSections;
02454             continue;
02455         }
02456 
02457         // because it isn't stretch, determine its width and remove that from lengthToStrech
02458         int sectionSize = 0;
02459         if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
02460             sectionSize = headerSectionSize(i);
02461         } else { // resizeMode == QHeaderView::ResizeToContents
02462             int logicalIndex = q->logicalIndex(i);
02463             sectionSize = qMax(viewSectionSizeHint(logicalIndex),
02464                                q->sectionSizeHint(logicalIndex));
02465         }
02466         section_sizes.append(sectionSize);
02467         lengthToStrech -= sectionSize;
02468     }
02469 
02470     // calculate the new length for all of the stretched sections
02471     int stretchSectionLength = 0;
02472     int pixelReminder = 0;
02473     if (numberOfStretchedSections > 0) {
02474         int hintLengthForEveryStretchedSection = lengthToStrech / numberOfStretchedSections;
02475         stretchSectionLength = qMax(hintLengthForEveryStretchedSection, q->minimumSectionSize());
02476         pixelReminder = lengthToStrech % numberOfStretchedSections;
02477     }
02478 
02479     int spanStartSection = 0;
02480     int previousSectionLength = 0;
02481     QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive;
02482 
02483     // resize each section along the total length
02484     for (int i = 0; i < sectionCount; ++i) {
02485         int oldSectionLength = headerSectionSize(i);
02486         int newSectionLength = -1;
02487         QHeaderView::ResizeMode newSectionResizeMode = headerSectionResizeMode(i);
02488 
02489         if (isVisualIndexHidden(i)) {
02490             newSectionLength = 0;
02491         } else {
02492             QHeaderView::ResizeMode resizeMode;
02493             if (useGlobalMode)
02494                 resizeMode = globalMode;
02495             else
02496                 resizeMode = (i == stretchSection
02497                               ? QHeaderView::Stretch
02498                               : visualIndexResizeMode(i));
02499             if (resizeMode == QHeaderView::Stretch) {
02500                 if (i == sectionCount - 1)
02501                     newSectionLength = qMax(stretchSectionLength, lastSectionSize);
02502                 else
02503                     newSectionLength = stretchSectionLength;
02504                 if (pixelReminder > 0) {
02505                     newSectionLength += 1;
02506                     --pixelReminder;
02507                 }
02508             } else {
02509                 newSectionLength = section_sizes.front();
02510                 section_sizes.removeFirst();
02511             }
02512         }
02513 
02514         //Q_ASSERT(newSectionLength > 0);
02515         if ((previousSectionResizeMode != newSectionResizeMode
02516             || previousSectionLength != newSectionLength) && i > 0) {
02517             int spanLength = (i - spanStartSection) * previousSectionLength;
02518             createSectionSpan(spanStartSection, i - 1, spanLength, previousSectionResizeMode);
02519             //Q_ASSERT(headerLength() == length);
02520             spanStartSection = i;
02521         }
02522 
02523         if (newSectionLength != oldSectionLength)
02524             emit q->sectionResized(i, oldSectionLength, newSectionLength);
02525 
02526         previousSectionLength = newSectionLength;
02527         previousSectionResizeMode = newSectionResizeMode;
02528     }
02529 
02530     createSectionSpan(spanStartSection, sectionCount - 1,
02531                       (sectionCount - spanStartSection) * previousSectionLength,
02532                       previousSectionResizeMode);
02533     //Q_ASSERT(headerLength() == length);
02534 
02535     viewport->update();
02536 }
02537 
02538 void QHeaderViewPrivate::createSectionSpan(int start, int end, int size, QHeaderView::ResizeMode mode)
02539 {
02540     // ### the code for merging spans does not merge at all opertuneties
02541     // ### what if the number of sections is reduced ?
02542 
02543     SectionSpan span(size, (end - start) + 1, mode);
02544     int start_section = 0;
02545 #ifndef QT_NO_DEBUG
02546     int initial_section_count = headerSectionCount(); // ### debug code
02547 #endif
02548 
02549     QList<int> spansToRemove;
02550     for (int i = 0; i < sectionSpans.count(); ++i) {
02551         int end_section = start_section + sectionSpans.at(i).count - 1;
02552         int section_count = sectionSpans.at(i).count;
02553         if (start <= start_section && end > end_section) {
02554             // the existing span is entirely coveded by the new span
02555             spansToRemove.append(i);
02556         } else if (start < start_section && end >= end_section) {
02557             // the existing span is entirely coveded by the new span
02558             spansToRemove.append(i);
02559         } else if (start == start_section && end == end_section) {
02560             // the new span is covered by an existin span
02561             length -= sectionSpans.at(i).size;
02562             length += size;
02563             sectionSpans[i].size = size;
02564             sectionSpans[i].resizeMode = mode;
02565             // ### check if we can merge the section with any of its neighbours
02566             removeSpans(spansToRemove);
02567             Q_ASSERT(initial_section_count == headerSectionCount());
02568             return;
02569         } else if (start > start_section && end < end_section) {
02570             if (sectionSpans.at(i).sectionSize() == span.sectionSize()
02571                 && sectionSpans.at(i).resizeMode == span.resizeMode) {
02572                 Q_ASSERT(initial_section_count == headerSectionCount());
02573                 return;
02574             }
02575             // the new span is in the middle of the old span, so we have to split it
02576             length -= sectionSpans.at(i).size;
02577             int section_size = sectionSpans.at(i).sectionSize();
02578 #ifndef QT_NO_DEBUG
02579             int span_count = sectionSpans.at(i).count;
02580 #endif
02581             QHeaderView::ResizeMode span_mode = sectionSpans.at(i).resizeMode;
02582             // first span
02583             int first_span_count = start - start_section;
02584             int first_span_size = section_size * first_span_count;
02585             sectionSpans[i].count = first_span_count;
02586             sectionSpans[i].size = first_span_size;
02587             sectionSpans[i].resizeMode = span_mode;
02588             length += first_span_size;
02589             // middle span (the new span)
02590 #ifndef QT_NO_DEBUG
02591             int mid_span_count = span.count;
02592 #endif
02593             int mid_span_size = span.size;
02594             sectionSpans.insert(i + 1, span);
02595             length += mid_span_size;
02596             // last span
02597             int last_span_count = end_section - end;
02598             int last_span_size = section_size * last_span_count;
02599             sectionSpans.insert(i + 2, SectionSpan(last_span_size, last_span_count, span_mode));
02600             length += last_span_size;
02601             Q_ASSERT(span_count == first_span_count + mid_span_count + last_span_count);
02602             removeSpans(spansToRemove);
02603             Q_ASSERT(initial_section_count == headerSectionCount());
02604             return;
02605         } else if (start > start_section && start <= end_section && end >= end_section) {
02606             // the new span covers the last part of the existing span
02607             length -= sectionSpans.at(i).size;
02608             int removed_count = (end_section - start + 1);
02609             int span_count = sectionSpans.at(i).count - removed_count;
02610             int section_size = sectionSpans.at(i).sectionSize();
02611             int span_size = section_size * span_count;
02612             sectionSpans[i].count = span_count;
02613             sectionSpans[i].size = span_size;
02614             length += span_size;
02615             if (end == end_section) {
02616                 sectionSpans.insert(i + 1, span); // insert after
02617                 length += span.size;
02618                 removeSpans(spansToRemove);
02619                 Q_ASSERT(initial_section_count == headerSectionCount());
02620                 return;
02621             }
02622         } else if (end < end_section && end >= start_section && start <= start_section) {
02623             // the new span covers the first part of the existing span
02624             length -= sectionSpans.at(i).size;
02625             int removed_count = (end - start_section + 1);
02626             int section_size = sectionSpans.at(i).sectionSize();
02627             int span_count = sectionSpans.at(i).count - removed_count;
02628             int span_size = section_size * span_count;
02629             sectionSpans[i].count = span_count;
02630             sectionSpans[i].size = span_size;
02631             length += span_size;
02632             sectionSpans.insert(i, span); // insert before
02633             length += span.size;
02634             removeSpans(spansToRemove);
02635             Q_ASSERT(initial_section_count == headerSectionCount());
02636             return;
02637         }
02638         start_section += section_count;
02639     }
02640 
02641     // ### adding and removing _ sections_  in addition to spans
02642     // ### add some more checks here
02643 
02644     if (spansToRemove.isEmpty()) {
02645         if (!sectionSpans.isEmpty()
02646             && sectionSpans.last().sectionSize() == span.sectionSize()
02647             && sectionSpans.last().resizeMode == span.resizeMode) {
02648             length += span.size;
02649             int last = sectionSpans.count() - 1;
02650             sectionSpans[last].count += span.count;
02651             sectionSpans[last].size += span.size;
02652             sectionSpans[last].resizeMode = span.resizeMode;
02653         } else {
02654             length += span.size;
02655             sectionSpans.append(span);
02656         }
02657     } else {
02658         removeSpans(spansToRemove);
02659         length += span.size;
02660         sectionSpans.insert(spansToRemove.first(), span);
02661         //Q_ASSERT(initial_section_count == headerSectionCount());
02662     }
02663 }
02664 
02665 void QHeaderViewPrivate::removeSectionsFromSpans(int start, int end)
02666 {
02667     // remove sections
02668     int start_section = 0;
02669     QList<int> spansToRemove;
02670     for (int i = 0; i < sectionSpans.count(); ++i) {
02671         int end_section = start_section + sectionSpans.at(i).count - 1;
02672         int section_size = sectionSpans.at(i).sectionSize();
02673         int section_count = sectionSpans.at(i).count;
02674         if (start <= start_section && end >= end_section) {
02675             // the change covers the entire span
02676             spansToRemove.append(i);
02677             if (end == end_section)
02678                 break;
02679         } else if (start > start_section && end < end_section) {
02680             // all the removed sections are inside the span
02681             int change = (end - start + 1);
02682             sectionSpans[i].count -= change;
02683             sectionSpans[i].size = section_size * sectionSpans.at(i).count;
02684             length -= (change * section_size);
02685             break;
02686         } else if (start >= start_section && start <= end_section) {
02687             // the some of the removed sections are inside the span,at the end
02688             int change = qMin(end_section - start + 1, end - start + 1);
02689             sectionSpans[i].count -= change;
02690             sectionSpans[i].size = section_size * sectionSpans.at(i).count;
02691             start += change;
02692             length -= (change * section_size);
02693             // the change affects several spans
02694         } else if (end >= start_section && end <= end_section) {
02695             // the some of the removed sections are inside the span, at the beginning
02696             int change = qMin((end - start_section + 1), end - start + 1);
02697             sectionSpans[i].count -= change;
02698             sectionSpans[i].size = section_size * sectionSpans.at(i).count;
02699             length -= (change * section_size);
02700             break;
02701         }
02702         start_section += section_count;
02703     }
02704 
02705     for (int i = spansToRemove.count() - 1; i >= 0; --i) {
02706         int s = spansToRemove.at(i);
02707         length -= sectionSpans.at(s).size;
02708         sectionSpans.remove(s);
02709         // ### merge remaining spans
02710     }
02711 }
02712 
02713 void QHeaderViewPrivate::clear()
02714 {
02715     length = 0;
02716     sectionCount = 0;
02717     visualIndices.clear();
02718     logicalIndices.clear();
02719     sectionSelected.clear();
02720     sectionHidden.clear();
02721     hiddenSectionSize.clear();
02722     sectionSpans.clear();
02723 }
02724 
02725 void QHeaderViewPrivate::flipSortIndicator(int section)
02726 {
02727     Q_Q(QHeaderView);
02728     bool ascending = (sortIndicatorSection != section
02729                       || sortIndicatorOrder == Qt::DescendingOrder);
02730     q->setSortIndicator(section, ascending ? Qt::AscendingOrder : Qt::DescendingOrder);
02731 }
02732 
02733 void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
02734 {
02735     Q_Q(QHeaderView);
02736     const int minimumSize = q->minimumSectionSize();
02737     const int oldSize = headerSectionSize(visual);
02738     int delta = newSize - oldSize;
02739 
02740     if (delta > 0) { // larger
02741         bool sectionResized = false;
02742 
02743         // restore old section sizes
02744         for (int i = firstCascadingSection; i < visual; ++i) {
02745             if (cascadingSectionSize.contains(i)) {
02746                 int currentSectionSize = headerSectionSize(i);
02747                 int originalSectionSize = cascadingSectionSize.value(i);
02748                 if (currentSectionSize < originalSectionSize) {
02749                     int newSectionSize = currentSectionSize + delta;
02750                     resizeSectionSpan(i, currentSectionSize, newSectionSize);
02751                     if (newSectionSize >= originalSectionSize && false)
02752                         cascadingSectionSize.remove(i); // the section is now restored
02753                     sectionResized = true;
02754                     break;
02755                 }
02756             }
02757 
02758         }
02759 
02760         // resize the section
02761         if (!sectionResized) {
02762             newSize = qMax(newSize, minimumSize);
02763             if (oldSize != newSize)
02764                 resizeSectionSpan(visual, oldSize, newSize);
02765         }
02766 
02767         // cascade the section size change
02768         for (int i = visual + 1; i < sectionCount; ++i) {
02769             if (!sectionIsCascadable(i))
02770                 continue;
02771             int currentSectionSize = headerSectionSize(i);
02772             if (currentSectionSize <= minimumSize)
02773                 continue;
02774             int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
02775             //qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
02776             resizeSectionSpan(i, currentSectionSize, newSectionSize);
02777             saveCascadingSectionSize(i, currentSectionSize);
02778             delta = delta - (currentSectionSize - newSectionSize);
02779             //qDebug() << "new delta" << delta;
02780             //if (newSectionSize != minimumSize)
02781             if (delta <= 0)
02782                 break;
02783         }
02784     } else { // smaller
02785         bool sectionResized = false;
02786 
02787         // restore old section sizes
02788         for (int i = lastCascadingSection; i > visual; --i) {
02789             if (!cascadingSectionSize.contains(i))
02790                 continue;
02791             int currentSectionSize = headerSectionSize(i);
02792             int originalSectionSize = cascadingSectionSize.value(i);
02793             if (currentSectionSize >= originalSectionSize)
02794                 continue;
02795             int newSectionSize = currentSectionSize - delta;
02796             resizeSectionSpan(i, currentSectionSize, newSectionSize);
02797             if (newSectionSize >= originalSectionSize && false) {
02798                 //qDebug() << "section" << i << "restored to" << originalSectionSize;
02799                 cascadingSectionSize.remove(i); // the section is now restored
02800             }
02801             sectionResized = true;
02802             break;
02803         }
02804 
02805         // resize the section
02806         resizeSectionSpan(visual, oldSize, qMax(newSize, minimumSize));
02807 
02808         // cascade the section size change
02809         if (delta < 0 && newSize < minimumSize) {
02810             for (int i = visual - 1; i >= 0; --i) {
02811                 if (!sectionIsCascadable(i))
02812                     continue;
02813                 int sectionSize = headerSectionSize(i);
02814                 if (sectionSize <= minimumSize)
02815                     continue;
02816                 resizeSectionSpan(i, sectionSize, qMax(sectionSize + delta, minimumSize));
02817                 saveCascadingSectionSize(i, sectionSize);
02818                 break;
02819             }
02820         }
02821 
02822         // let the next section get the space from the resized section
02823         if (!sectionResized) {
02824             for (int i = visual + 1; i < sectionCount; ++i) {
02825                 if (!sectionIsCascadable(i))
02826                     continue;
02827                 int currentSectionSize = headerSectionSize(i);
02828                 int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
02829                 resizeSectionSpan(i, currentSectionSize, newSectionSize);
02830                 break;
02831             }
02832         }
02833     }
02834 
02835     if (hasAutoResizeSections())
02836         q->resizeSections();
02837 
02838     viewport->update();
02839 }
02840 
02841 void QHeaderViewPrivate::resizeSectionSpan(int visualIndex, uint oldSize, uint newSize)
02842 {
02843     Q_Q(QHeaderView);
02844     QHeaderView::ResizeMode mode = headerSectionResizeMode(visualIndex);
02845     createSectionSpan(visualIndex, visualIndex, newSize, mode);
02846     emit q->sectionResized(logicalIndex(visualIndex), oldSize, newSize);
02847 }
02848 
02849 int QHeaderViewPrivate::headerSectionSize(int visual) const
02850 {
02851     // ### stupid iteration
02852     int section_start = 0;
02853     for (int i = 0; i < sectionSpans.count(); ++i) {
02854         int section_end = section_start + sectionSpans.at(i).count - 1;
02855         if (visual >= section_start && visual <= section_end)
02856             return sectionSpans.at(i).sectionSize();
02857         section_start = section_end + 1;
02858     }
02859     return -1;
02860 }
02861 
02862 int QHeaderViewPrivate::headerSectionPosition(int visual) const
02863 {
02864     // ### stupid iteration
02865     int section_start = 0;
02866     int span_position = 0;
02867     for (int i = 0; i < sectionSpans.count(); ++i) {
02868         int section_end = section_start + sectionSpans.at(i).count - 1;
02869         if (visual >= section_start && visual <= section_end)
02870             return span_position + (visual - section_start) * sectionSpans.at(i).sectionSize();
02871         section_start = section_end + 1;
02872         span_position += sectionSpans.at(i).size;
02873     }
02874     return -1;
02875 }
02876 
02877 int QHeaderViewPrivate::headerVisualIndexAt(uint position) const
02878 {
02879     // ### stupid iteration
02880     uint span_start_section = 0;
02881     uint span_position = 0;
02882     for (int i = 0; i < sectionSpans.count(); ++i) {
02883         uint next_span_start_section = span_start_section + sectionSpans.at(i).count;
02884         uint next_span_position = span_position + sectionSpans.at(i).size;
02885         if (position == span_position)
02886             return span_start_section; // spans with no size
02887         if (position > span_position && position < next_span_position) {
02888             uint position_in_span = position - span_position;
02889             return span_start_section + (position_in_span / sectionSpans.at(i).sectionSize());
02890         }
02891         span_start_section = next_span_start_section;
02892         span_position = next_span_position;
02893     }
02894     return -1;
02895 }
02896 
02897 void QHeaderViewPrivate::setHeaderSectionResizeMode(int visual, QHeaderView::ResizeMode mode)
02898 {
02899     int size = headerSectionSize(visual);
02900     createSectionSpan(visual, visual, size, mode);
02901 }
02902 
02903 QHeaderView::ResizeMode QHeaderViewPrivate::headerSectionResizeMode(int visual) const
02904 {
02905     int span = sectionSpanIndex(visual);
02906     if (span == -1)
02907         return globalResizeMode;
02908     return sectionSpans.at(span).resizeMode;
02909 }
02910 
02911 void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode)
02912 {
02913     globalResizeMode = mode;
02914     for (int i = 0; i < sectionSpans.count(); ++i)
02915         sectionSpans[i].resizeMode = mode;
02916 }
02917 
02918 int QHeaderViewPrivate::viewSectionSizeHint(int logical) const
02919 {
02920     Q_Q(const QHeaderView);
02921     if (QAbstractItemView *parent = ::qobject_cast<QAbstractItemView*>(q->parent())) {
02922         return (orientation == Qt::Horizontal
02923                 ? parent->sizeHintForColumn(logical)
02924                 : parent->sizeHintForRow(logical));
02925     }
02926     return 0;
02927 }
02928 
02929 int QHeaderViewPrivate::adjustedVisualIndex(int visualIndex) const
02930 {
02931     if (hiddenSectionSize.count() > 0) {
02932         int adjustedVisualIndex = visualIndex;
02933         int currentVisualIndex = 0;
02934         for (int i = 0; i < sectionSpans.count(); ++i) {
02935             if (sectionSpans.at(i).size == 0)
02936                 adjustedVisualIndex += sectionSpans.at(i).count;
02937             else
02938                 currentVisualIndex += sectionSpans.at(i).count;
02939             if (currentVisualIndex >= visualIndex)
02940                 break;
02941         }
02942         visualIndex = adjustedVisualIndex;
02943     }
02944     return visualIndex;
02945 }
02946 
02947 #endif // QT_NO_ITEMVIEWS
02948 
02949 #include "moc_qheaderview.cpp"

Generated on Thu Mar 15 11:54:47 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1