diff options
author | Thorbjørn Martsum <tmartsum@gmail.com> | 2015-06-26 06:36:54 +0200 |
---|---|---|
committer | Thorbjørn Lund Martsum <tmartsum@gmail.com> | 2016-01-01 12:56:29 +0000 |
commit | 024a52d0d12aaceffd67d0a1423408fb1f377d11 (patch) | |
tree | 6cf3c0f597fa021ebafeee189408edb66d558824 /src/widgets | |
parent | 9059931cd2103a814d247d35998d49f03e9131e5 (diff) |
QHeaderView - fix broken stretchLastSection
In setStretchLastSection we restore a default section size
if we no longer use stretch. That size was however not
sufficient - we should restore the actual size.
Furthermore we should also always stretch the last section
(last visible index) - and not leave a section with a
huge size and stretch another.
This patch refactors stretch handling and keeps track
of the last section and its size in eg. moveSection,
swapSection, hideSection, showSection etc.
There is an auto test showing and guarding its behavior.
[ChangeLog][QtWidgets][QHeaderView] Fixed some issues
(e.g QTBUG-39010) with restoring of section size after
a section is no longer the last visible section
(in stretchLastSection mode).
Task-number: QTBUG-39010
Change-Id: Id47075b5a9dfeb250027374ecbd10eb8babbf9ef
Reviewed-by: David Faure <david.faure@kdab.com>
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/itemviews/qheaderview.cpp | 128 | ||||
-rw-r--r-- | src/widgets/itemviews/qheaderview_p.h | 7 |
2 files changed, 120 insertions, 15 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; |