227 lines
8.6 KiB
Diff
227 lines
8.6 KiB
Diff
From 3adfcbf1ed9b63c3ce41d7417658db3836fd3530 Mon Sep 17 00:00:00 2001
|
|
From: Christian Ehrlicher <ch.ehrlicher@gmx.de>
|
|
Date: Sun, 21 Jan 2018 19:55:40 +0100
|
|
Subject: [PATCH 68/74] QHeaderView: properly restore section data after
|
|
layoutChanged()
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
QHeaderView is doing a complete rebuild of the sections when the layout
|
|
changed because everything could have happened. But since layoutChanged
|
|
is also called during e.g. sorting, the old data must be restored when
|
|
possible.
|
|
|
|
Task-number: QTBUG-65478
|
|
Change-Id: I088d4d843cad362b97df6dc5e0dcb9819b13547f
|
|
Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
|
|
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
|
|
---
|
|
src/widgets/itemviews/qheaderview.cpp | 88 ++++++++++++++++------
|
|
src/widgets/itemviews/qheaderview_p.h | 11 +--
|
|
.../itemviews/qheaderview/tst_qheaderview.cpp | 13 +++-
|
|
3 files changed, 82 insertions(+), 30 deletions(-)
|
|
|
|
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
|
|
index 0905a20812..e1aec3f4bd 100644
|
|
--- a/src/widgets/itemviews/qheaderview.cpp
|
|
+++ b/src/widgets/itemviews/qheaderview.cpp
|
|
@@ -351,7 +351,7 @@ void QHeaderView::setModel(QAbstractItemModel *model)
|
|
if (model == this->model())
|
|
return;
|
|
Q_D(QHeaderView);
|
|
- d->persistentHiddenSections.clear();
|
|
+ d->layoutChangePersistentSections.clear();
|
|
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
|
|
if (d->orientation == Qt::Horizontal) {
|
|
QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
|
@@ -2072,14 +2072,28 @@ void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
|
|
|| model->columnCount(root) == 0)
|
|
return;
|
|
|
|
- if (hiddenSectionSize.count() == 0)
|
|
- return;
|
|
+ layoutChangePersistentSections.clear();
|
|
+ layoutChangePersistentSections.reserve(std::min(10, sectionItems.count()));
|
|
+ // after layoutChanged another section can be last stretched section
|
|
+ if (stretchLastSection) {
|
|
+ const int visual = visualIndex(lastSectionLogicalIdx);
|
|
+ sectionItems[visual].size = lastSectionSize;
|
|
+ }
|
|
+ for (int i = 0; i < sectionItems.size(); ++i) {
|
|
+ const auto &s = sectionItems.at(i);
|
|
+ // only add if the section is not default and not visually moved
|
|
+ if (s.size == defaultSectionSize && !s.isHidden && s.resizeMode == globalResizeMode)
|
|
+ continue;
|
|
|
|
- for (int i = 0; i < sectionItems.count(); ++i)
|
|
- if (isVisualIndexHidden(i)) // ### note that we are using column or row 0
|
|
- persistentHiddenSections.append(orientation == Qt::Horizontal
|
|
- ? model->index(0, logicalIndex(i), root)
|
|
- : model->index(logicalIndex(i), 0, root));
|
|
+ // ### note that we are using column or row 0
|
|
+ layoutChangePersistentSections.append({orientation == Qt::Horizontal
|
|
+ ? model->index(0, logicalIndex(i), root)
|
|
+ : model->index(logicalIndex(i), 0, root),
|
|
+ s});
|
|
+
|
|
+ if (layoutChangePersistentSections.size() > 1000)
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
void QHeaderViewPrivate::_q_layoutChanged()
|
|
@@ -2087,25 +2101,57 @@ void QHeaderViewPrivate::_q_layoutChanged()
|
|
Q_Q(QHeaderView);
|
|
viewport->update();
|
|
|
|
- const auto hiddenSections = persistentHiddenSections;
|
|
- persistentHiddenSections.clear();
|
|
-
|
|
- clear();
|
|
- q->initializeSections();
|
|
- invalidateCachedSizeHint();
|
|
+ const auto oldPersistentSections = layoutChangePersistentSections;
|
|
+ layoutChangePersistentSections.clear();
|
|
|
|
- if (modelIsEmpty()) {
|
|
+ const int newCount = modelSectionCount();
|
|
+ const int oldCount = sectionItems.size();
|
|
+ if (newCount == 0) {
|
|
+ clear();
|
|
+ if (oldCount != 0)
|
|
+ emit q->sectionCountChanged(oldCount, 0);
|
|
return;
|
|
}
|
|
|
|
- for (const auto &index : hiddenSections) {
|
|
- if (index.isValid()) {
|
|
- const int logical = (orientation == Qt::Horizontal
|
|
- ? index.column()
|
|
- : index.row());
|
|
- q->setSectionHidden(logical, true);
|
|
+ // adjust section size
|
|
+ if (newCount != oldCount) {
|
|
+ const int min = qBound(0, oldCount, newCount - 1);
|
|
+ q->initializeSections(min, newCount - 1);
|
|
+ }
|
|
+ // reset sections
|
|
+ sectionItems.fill(SectionItem(defaultSectionSize, globalResizeMode), newCount);
|
|
+
|
|
+ // all hidden sections are in oldPersistentSections
|
|
+ hiddenSectionSize.clear();
|
|
+
|
|
+ for (const auto &item : oldPersistentSections) {
|
|
+ const auto &index = item.index;
|
|
+ if (!index.isValid())
|
|
+ continue;
|
|
+
|
|
+ const int newLogicalIndex = (orientation == Qt::Horizontal
|
|
+ ? index.column()
|
|
+ : index.row());
|
|
+ // the new visualIndices are already adjusted / reset by initializeSections()
|
|
+ const int newVisualIndex = visualIndex(newLogicalIndex);
|
|
+ auto &newSection = sectionItems[newVisualIndex];
|
|
+ newSection = item.section;
|
|
+
|
|
+ if (newSection.isHidden) {
|
|
+ // otherwise setSectionHidden will return without doing anything
|
|
+ newSection.isHidden = false;
|
|
+ q->setSectionHidden(newLogicalIndex, true);
|
|
}
|
|
}
|
|
+
|
|
+ recalcSectionStartPos();
|
|
+ length = headerLength();
|
|
+
|
|
+ if (stretchLastSection) {
|
|
+ // force rebuild of stretched section later on
|
|
+ lastSectionLogicalIdx = -1;
|
|
+ maybeRestorePrevLastSectionAndStretchLast();
|
|
+ }
|
|
}
|
|
|
|
/*!
|
|
diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h
|
|
index 8fc8b88aa5..c9c2cf8493 100644
|
|
--- a/src/widgets/itemviews/qheaderview_p.h
|
|
+++ b/src/widgets/itemviews/qheaderview_p.h
|
|
@@ -231,10 +231,6 @@ public:
|
|
: model->rowCount(root));
|
|
}
|
|
|
|
- inline bool modelIsEmpty() const {
|
|
- return (model->rowCount(root) == 0 || model->columnCount(root) == 0);
|
|
- }
|
|
-
|
|
inline void doDelayedResizeSections() {
|
|
if (!delayedResize.isActive())
|
|
delayedResize.start(0, q_func());
|
|
@@ -304,7 +300,6 @@ public:
|
|
QLabel *sectionIndicator;
|
|
#endif
|
|
QHeaderView::ResizeMode globalResizeMode;
|
|
- QList<QPersistentModelIndex> persistentHiddenSections;
|
|
mutable bool sectionStartposRecalc;
|
|
int resizeContentsPrecision;
|
|
// header sections
|
|
@@ -335,6 +330,11 @@ public:
|
|
};
|
|
|
|
QVector<SectionItem> sectionItems;
|
|
+ struct LayoutChangeItem {
|
|
+ QPersistentModelIndex index;
|
|
+ SectionItem section;
|
|
+ };
|
|
+ QVector<LayoutChangeItem> layoutChangePersistentSections;
|
|
|
|
void createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode);
|
|
void removeSectionsFromSectionItems(int start, int end);
|
|
@@ -388,6 +388,7 @@ public:
|
|
|
|
};
|
|
Q_DECLARE_TYPEINFO(QHeaderViewPrivate::SectionItem, Q_PRIMITIVE_TYPE);
|
|
+Q_DECLARE_TYPEINFO(QHeaderViewPrivate::LayoutChangeItem, Q_MOVABLE_TYPE);
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
|
|
index 90019a1798..6dae2cf8e4 100644
|
|
--- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
|
|
+++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
|
|
@@ -2251,10 +2251,6 @@ void tst_QHeaderView::QTBUG6058_reset()
|
|
|
|
void tst_QHeaderView::QTBUG7833_sectionClicked()
|
|
{
|
|
-
|
|
-
|
|
-
|
|
-
|
|
QTableView tv;
|
|
QStandardItemModel *sim = new QStandardItemModel(&tv);
|
|
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv);
|
|
@@ -2278,11 +2274,20 @@ void tst_QHeaderView::QTBUG7833_sectionClicked()
|
|
tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
|
|
|
tv.setModel(proxyModel);
|
|
+ const int section4Size = tv.horizontalHeader()->sectionSize(4) + 1;
|
|
+ tv.horizontalHeader()->resizeSection(4, section4Size);
|
|
tv.setColumnHidden(5, true);
|
|
tv.setColumnHidden(6, true);
|
|
tv.horizontalHeader()->swapSections(8, 10);
|
|
tv.sortByColumn(1, Qt::AscendingOrder);
|
|
|
|
+ QCOMPARE(tv.isColumnHidden(5), true);
|
|
+ QCOMPARE(tv.isColumnHidden(6), true);
|
|
+ QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true);
|
|
+ QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10);
|
|
+ QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8);
|
|
+ QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size);
|
|
+
|
|
QSignalSpy clickedSpy(tv.horizontalHeader(), SIGNAL(sectionClicked(int)));
|
|
QSignalSpy pressedSpy(tv.horizontalHeader(), SIGNAL(sectionPressed(int)));
|
|
|
|
--
|
|
2.14.3
|
|
|