diff options
-rw-r--r-- | src/widgets/itemviews/qheaderview.cpp | 128 | ||||
-rw-r--r-- | src/widgets/itemviews/qheaderview_p.h | 7 | ||||
-rw-r--r-- | tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp | 123 |
3 files changed, 242 insertions, 16 deletions
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 496d36015e..9b0959dda3 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -753,9 +753,6 @@ void QHeaderView::moveSection(int from, int to) return; } - if (stretchLastSection() && to == d->lastVisibleVisualIndex()) - d->lastSectionSize = sectionSize(from); - d->initializeIndexMapping(); int *visualIndices = d->visualIndices.data(); @@ -788,6 +785,12 @@ void QHeaderView::moveSection(int from, int to) d->viewport->update(); emit sectionMoved(logical, from, to); + + if (stretchLastSection()) { + const int lastSectionVisualIdx = visualIndex(d->lastSectionLogicalIdx); + if (from >= lastSectionVisualIdx || to >= lastSectionVisualIdx) + d->maybeRestorePrevLastSectionAndStretchLast(); + } } /*! @@ -839,6 +842,12 @@ void QHeaderView::swapSections(int first, int second) d->viewport->update(); emit sectionMoved(firstLogical, first, second); emit sectionMoved(secondLogical, second, first); + + if (stretchLastSection()) { + const int lastSectionVisualIdx = visualIndex(d->lastSectionLogicalIdx); + if (first >= lastSectionVisualIdx || second >= lastSectionVisualIdx) + d->maybeRestorePrevLastSectionAndStretchLast(); + } } /*! @@ -877,7 +886,7 @@ void QHeaderView::resizeSection(int logical, int size) d->executePostedLayout(); d->invalidateCachedSizeHint(); - if (stretchLastSection() && visual == d->lastVisibleVisualIndex()) + if (stretchLastSection() && logical == d->lastSectionLogicalIdx) d->lastSectionSize = size; d->createSectionItems(visual, visual, size, d->headerSectionResizeMode(visual)); @@ -1000,11 +1009,16 @@ void QHeaderView::setSectionHidden(int logicalIndex, bool hide) if (hide == d->isVisualIndexHidden(visual)) return; if (hide) { + const bool isHidingLastSection = (stretchLastSection() && logicalIndex == d->lastSectionLogicalIdx); + if (isHidingLastSection) + d->restoreSizeOnPrevLastSection(); // Restore here/now to get the right restore size. int size = d->headerSectionSize(visual); if (!d->hasAutoResizeSections()) resizeSection(logicalIndex, 0); d->hiddenSectionSize.insert(logicalIndex, size); d->setVisualIndexHidden(visual, true); + if (isHidingLastSection) + d->setNewLastSection(d->lastVisibleVisualIndex()); if (d->hasAutoResizeSections()) d->doDelayedResizeSections(); } else { @@ -1012,6 +1026,12 @@ void QHeaderView::setSectionHidden(int logicalIndex, bool hide) d->hiddenSectionSize.remove(logicalIndex); d->setVisualIndexHidden(visual, false); resizeSection(logicalIndex, size); + + const bool newLastSection = (stretchLastSection() && visual > visualIndex(d->lastSectionLogicalIdx)); + if (newLastSection) { + d->restoreSizeOnPrevLastSection(); + d->setNewLastSection(visual); + } } } @@ -1473,13 +1493,17 @@ bool QHeaderView::stretchLastSection() const void QHeaderView::setStretchLastSection(bool stretch) { Q_D(QHeaderView); + const bool changedStretchMode = (d->stretchLastSection != stretch); d->stretchLastSection = stretch; if (d->state != QHeaderViewPrivate::NoState) return; - if (stretch) + if (stretch) { + d->setNewLastSection(d->lastVisibleVisualIndex()); resizeSections(); - else if (count()) - resizeSection(count() - 1, d->defaultSectionSize); + } else { + if (changedStretchMode) + d->restoreSizeOnPrevLastSection(); + } } /*! @@ -1834,6 +1858,21 @@ void QHeaderView::sectionsInserted(const QModelIndex &parent, int insertAt = logicalFirst; int insertCount = logicalLast - logicalFirst + 1; + bool lastSectionActualChange = false; + if (stretchLastSection()) { + + int visualIndexForStretch = d->lastSectionLogicalIdx; + if (d->lastSectionLogicalIdx >= 0 && d->lastSectionLogicalIdx < d->visualIndices.size()) + visualIndexForStretch = d->visualIndices[d->lastSectionLogicalIdx]; // We cannot call visualIndex since it executes executePostedLayout() + // and it is likely to bypass initializeSections() and we may end up here again. Doing the insert twice. + + if (d->lastSectionLogicalIdx < 0 || insertAt >= visualIndexForStretch) + lastSectionActualChange = true; + + if (d->lastSectionLogicalIdx >= logicalFirst) + d->lastSectionLogicalIdx += insertCount; // We do not want to emit resize before we have fixed the count + } + QHeaderViewPrivate::SectionItem section(d->defaultSectionSize, d->globalResizeMode); d->sectionStartposRecalc = true; @@ -1890,6 +1929,9 @@ void QHeaderView::sectionsInserted(const QModelIndex &parent, d->doDelayedResizeSections(); emit sectionCountChanged(oldCount, count()); + if (lastSectionActualChange) + d->maybeRestorePrevLastSectionAndStretchLast(); + // if the new sections were not updated by resizing, we need to update now if (!d->hasAutoResizeSections()) d->viewport->update(); @@ -2000,6 +2042,16 @@ void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent, clear(); invalidateCachedSizeHint(); emit q->sectionCountChanged(oldCount, q->count()); + + if (q->stretchLastSection()) { + const bool lastSectionRemoved = lastSectionLogicalIdx >= logicalFirst && lastSectionLogicalIdx <= logicalLast; + if (lastSectionRemoved) + setNewLastSection(lastVisibleVisualIndex()); + else + lastSectionLogicalIdx = logicalIndex(lastVisibleVisualIndex()); // Just update the last log index. + doDelayedResizeSections(); + } + viewport->update(); } @@ -2078,8 +2130,8 @@ void QHeaderView::initializeSections() } else if (newCount != oldCount) { const int min = qBound(0, oldCount, newCount - 1); initializeSections(min, newCount - 1); - if (stretchLastSection()) // we've already gotten the size hint - d->lastSectionSize = sectionSize(logicalIndex(d->sectionCount() - 1)); + if (stretchLastSection()) // we've already gotten the size hint + d->maybeRestorePrevLastSectionAndStretchLast(); //make sure we update the hidden sections if (newCount < oldCount) @@ -3169,6 +3221,42 @@ int QHeaderViewPrivate::lastVisibleVisualIndex() const return -1; } +void QHeaderViewPrivate::restoreSizeOnPrevLastSection() +{ + Q_Q(QHeaderView); + if (lastSectionLogicalIdx < 0) + return; + int resizeLogIdx = lastSectionLogicalIdx; + lastSectionLogicalIdx = -1; // We do not want resize to catch it as the last section. + q->resizeSection(resizeLogIdx, lastSectionSize); +} + +void QHeaderViewPrivate::setNewLastSection(int visualIndexForLastSection) +{ + Q_Q(QHeaderView); + lastSectionSize = -1; + lastSectionLogicalIdx = q->logicalIndex(visualIndexForLastSection); + lastSectionSize = headerSectionSize(visualIndexForLastSection); // pick size directly since ... + // q->sectionSize(lastSectionLogicalIdx) may do delayed resize and stretch it before we get the value. +} + +void QHeaderViewPrivate::maybeRestorePrevLastSectionAndStretchLast() +{ + Q_Q(const QHeaderView); + if (!q->stretchLastSection()) + return; + + int nowLastVisualSection = lastVisibleVisualIndex(); + if (lastSectionLogicalIdx == q->logicalIndex(nowLastVisualSection)) + return; + + // restore old last section. + restoreSizeOnPrevLastSection(); + setNewLastSection(nowLastVisualSection); + doDelayedResizeSections(); // Do stretch of last section soon (but not now). +} + + /*! \internal Go through and resize all of the sections applying stretchLastSection, @@ -3197,13 +3285,12 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool resizeRecursionBlock = true; invalidateCachedSizeHint(); - - const int lastVisibleSection = lastVisibleVisualIndex(); + const int lastSectionVisualIdx = q->visualIndex(lastSectionLogicalIdx); // find stretchLastSection if we have it int stretchSection = -1; if (stretchLastSection && !useGlobalMode) - stretchSection = lastVisibleVisualIndex(); + stretchSection = lastSectionVisualIdx; // count up the number of stretched sections and how much space left for them int lengthToStretch = (orientation == Qt::Horizontal ? viewport->width() : viewport->height()); @@ -3272,7 +3359,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool ? QHeaderView::Stretch : newSectionResizeMode); if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) { - if (i == lastVisibleSection) + if (i == lastSectionVisualIdx) newSectionLength = qMax(stretchSectionLength, lastSectionSize); else newSectionLength = stretchSectionLength; @@ -3661,10 +3748,12 @@ void QHeaderViewPrivate::write(QDataStream &out) const out << sectionItems; out << resizeContentsPrecision; out << customDefaultSectionSize; + out << lastSectionSize; } bool QHeaderViewPrivate::read(QDataStream &in) { + Q_Q(QHeaderView); int orient, order, align, global; int sortIndicatorSectionIn; bool sortIndicatorShownIn; @@ -3683,7 +3772,6 @@ bool QHeaderViewPrivate::read(QDataStream &in) int minimumSectionSizeIn; QVector<SectionItem> sectionItemsIn; - in >> orient; in >> order; @@ -3776,6 +3864,18 @@ bool QHeaderViewPrivate::read(QDataStream &in) updateDefaultSectionSizeFromStyle(); } + lastSectionSize = -1; + int inLastSectionSize; + in >> inLastSectionSize; + if (in.status() == QDataStream::Ok) + lastSectionSize = inLastSectionSize; + + lastSectionLogicalIdx = -1; + if (stretchLastSection) { + lastSectionLogicalIdx = q->logicalIndex(lastVisibleVisualIndex()); + doDelayedResizeSections(); + } + return true; } diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h index 60542e297a..d1982d4777 100644 --- a/src/widgets/itemviews/qheaderview_p.h +++ b/src/widgets/itemviews/qheaderview_p.h @@ -90,6 +90,7 @@ public: minimumSectionSize(-1), maximumSectionSize(-1), lastSectionSize(0), + lastSectionLogicalIdx(-1), // Only trust when we stretch last section sectionIndicatorOffset(0), sectionIndicator(0), globalResizeMode(QHeaderView::Interactive), @@ -99,6 +100,9 @@ public: int lastVisibleVisualIndex() const; + void restoreSizeOnPrevLastSection(); + void setNewLastSection(int visualIndexForLastSection); + void maybeRestorePrevLastSectionAndStretchLast(); int sectionHandleAt(int position); void setupSectionIndicator(int section, int position); void updateSectionIndicator(int section, int position); @@ -281,7 +285,8 @@ public: int defaultSectionSize; int minimumSectionSize; int maximumSectionSize; - int lastSectionSize; // $$$ + int lastSectionSize; + int lastSectionLogicalIdx; // Only trust if we stretch LastSection int sectionIndicatorOffset; Qt::Alignment defaultAlignment; QLabel *sectionIndicator; diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index bdb12c52f0..dac75dd9fa 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -47,6 +47,7 @@ #include <qitemdelegate.h> #include <qtreewidget.h> #include <qdebug.h> +#include <qscreen.h> typedef QList<int> IntList; @@ -235,6 +236,7 @@ private slots: void resizeToContentTest(); void testStreamWithHide(); void testStylePosition(); + void stretchAndRestoreLastSection(); void sizeHintCrash(); @@ -554,7 +556,7 @@ void tst_QHeaderView::hidden() void tst_QHeaderView::stretch() { - // Show before resize and setStrechLastSection + // Show before resize and setStretchLastSection #if defined(Q_OS_WINCE) QSize viewSize(200,300); #else @@ -2891,5 +2893,124 @@ void tst_QHeaderView::sizeHintCrash() treeView.header()->sizeHintForRow(0); } +void tst_QHeaderView::stretchAndRestoreLastSection() +{ + QStandardItemModel m(10, 10); + QTableView tv; + tv.setModel(&m); + tv.showMaximized(); + + const int defaultSectionSize = 30; + const int someOtherSectionSize = 40; + const int biggerSizeThanAnySection = 50; + + QVERIFY(QTest::qWaitForWindowExposed(&tv)); + + QHeaderView &header = *tv.horizontalHeader(); + header.setDefaultSectionSize(defaultSectionSize); + header.resizeSection(9, someOtherSectionSize); + header.setStretchLastSection(true); + + // Default last section is larger + QCOMPARE(header.sectionSize(8), defaultSectionSize); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + + // Moving last section away (restore old last section 9 - and make 8 larger) + header.swapSections(9, 8); + QCOMPARE(header.sectionSize(9), someOtherSectionSize); + QVERIFY(header.sectionSize(8) >= biggerSizeThanAnySection); + + // Make section 9 the large one again + header.hideSection(8); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + + // Show section 8 again - and make that one the last one. + header.showSection(8); + QVERIFY(header.sectionSize(8) > biggerSizeThanAnySection); + QCOMPARE(header.sectionSize(9), someOtherSectionSize); + + // Swap the sections so the logical indexes are equal to visible indexes again. + header.moveSection(9, 8); + QCOMPARE(header.sectionSize(8), defaultSectionSize); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + + // Append sections + m.setColumnCount(15); + QCOMPARE(header.sectionSize(9), someOtherSectionSize); + QVERIFY(header.sectionSize(14) >= biggerSizeThanAnySection); + + // Truncate sections (remove sections with the last section) + m.setColumnCount(10); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + for (int u = 0; u < 9; ++u) + QCOMPARE(header.sectionSize(u), defaultSectionSize); + + // Insert sections + m.insertColumns(2, 2); + QCOMPARE(header.sectionSize(9), defaultSectionSize); + QCOMPARE(header.sectionSize(10), defaultSectionSize); + QVERIFY(header.sectionSize(11) >= biggerSizeThanAnySection); + + // Append an extra section and check restore + m.setColumnCount(m.columnCount() + 1); + QCOMPARE(header.sectionSize(11), someOtherSectionSize); + QVERIFY(header.sectionSize(12) >= biggerSizeThanAnySection); + + // Remove some sections but not the last one. + m.removeColumns(2, 2); + QCOMPARE(header.sectionSize(9), someOtherSectionSize); + QVERIFY(header.sectionSize(10) >= biggerSizeThanAnySection); + for (int u = 0; u < 9; ++u) + QCOMPARE(header.sectionSize(u), defaultSectionSize); + + // Empty the header and start over with some more tests + m.setColumnCount(0); + m.setColumnCount(10); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + + // Check resize of the last section + header.resizeSection(9, someOtherSectionSize); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); // It should still be stretched + header.swapSections(9, 8); + QCOMPARE(header.sectionSize(9), someOtherSectionSize); + + // Restore the order + header.swapSections(9, 8); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + + // Hide the last 3 sections and test stretch last section on swap/move + // when hidden sections with a larger visual index exists. + header.hideSection(7); + header.hideSection(8); + header.hideSection(9); + QVERIFY(header.sectionSize(6) >= biggerSizeThanAnySection); + header.moveSection(2, 7); + QVERIFY(header.sectionSize(2) >= biggerSizeThanAnySection); + header.swapSections(1, 8); + QCOMPARE(header.sectionSize(2), defaultSectionSize); + QVERIFY(header.sectionSize(1) >= biggerSizeThanAnySection); + + // Inserting sections 2 + m.setColumnCount(0); + m.setColumnCount(10); + header.resizeSection(1, someOtherSectionSize); + header.swapSections(1, 9); + m.insertColumns(9, 2); + header.swapSections(1, 11); + QCOMPARE(header.sectionSize(1), someOtherSectionSize); + + // Test import/export of the original (not stretched) sectionSize. + m.setColumnCount(0); + m.setColumnCount(10); + header.resizeSection(9, someOtherSectionSize); + QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); + QByteArray b = header.saveState(); + m.setColumnCount(0); + m.setColumnCount(10); + header.restoreState(b); + header.setStretchLastSection(false); + QCOMPARE(header.sectionSize(9), someOtherSectionSize); +} + QTEST_MAIN(tst_QHeaderView) #include "tst_qheaderview.moc" |