Skip to content

Commit 3adfcbf

Browse files
committed
QHeaderView: properly restore section data after layoutChanged()
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>
1 parent 5a05348 commit 3adfcbf

File tree

3 files changed

+82
-30
lines changed

3 files changed

+82
-30
lines changed

src/widgets/itemviews/qheaderview.cpp

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ void QHeaderView::setModel(QAbstractItemModel *model)
351351
if (model == this->model())
352352
return;
353353
Q_D(QHeaderView);
354-
d->persistentHiddenSections.clear();
354+
d->layoutChangePersistentSections.clear();
355355
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
356356
if (d->orientation == Qt::Horizontal) {
357357
QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
@@ -2072,40 +2072,86 @@ void QHeaderViewPrivate::_q_layoutAboutToBeChanged()
20722072
|| model->columnCount(root) == 0)
20732073
return;
20742074

2075-
if (hiddenSectionSize.count() == 0)
2076-
return;
2075+
layoutChangePersistentSections.clear();
2076+
layoutChangePersistentSections.reserve(std::min(10, sectionItems.count()));
2077+
// after layoutChanged another section can be last stretched section
2078+
if (stretchLastSection) {
2079+
const int visual = visualIndex(lastSectionLogicalIdx);
2080+
sectionItems[visual].size = lastSectionSize;
2081+
}
2082+
for (int i = 0; i < sectionItems.size(); ++i) {
2083+
const auto &s = sectionItems.at(i);
2084+
// only add if the section is not default and not visually moved
2085+
if (s.size == defaultSectionSize && !s.isHidden && s.resizeMode == globalResizeMode)
2086+
continue;
20772087

2078-
for (int i = 0; i < sectionItems.count(); ++i)
2079-
if (isVisualIndexHidden(i)) // ### note that we are using column or row 0
2080-
persistentHiddenSections.append(orientation == Qt::Horizontal
2081-
? model->index(0, logicalIndex(i), root)
2082-
: model->index(logicalIndex(i), 0, root));
2088+
// ### note that we are using column or row 0
2089+
layoutChangePersistentSections.append({orientation == Qt::Horizontal
2090+
? model->index(0, logicalIndex(i), root)
2091+
: model->index(logicalIndex(i), 0, root),
2092+
s});
2093+
2094+
if (layoutChangePersistentSections.size() > 1000)
2095+
break;
2096+
}
20832097
}
20842098

20852099
void QHeaderViewPrivate::_q_layoutChanged()
20862100
{
20872101
Q_Q(QHeaderView);
20882102
viewport->update();
20892103

2090-
const auto hiddenSections = persistentHiddenSections;
2091-
persistentHiddenSections.clear();
2092-
2093-
clear();
2094-
q->initializeSections();
2095-
invalidateCachedSizeHint();
2104+
const auto oldPersistentSections = layoutChangePersistentSections;
2105+
layoutChangePersistentSections.clear();
20962106

2097-
if (modelIsEmpty()) {
2107+
const int newCount = modelSectionCount();
2108+
const int oldCount = sectionItems.size();
2109+
if (newCount == 0) {
2110+
clear();
2111+
if (oldCount != 0)
2112+
emit q->sectionCountChanged(oldCount, 0);
20982113
return;
20992114
}
21002115

2101-
for (const auto &index : hiddenSections) {
2102-
if (index.isValid()) {
2103-
const int logical = (orientation == Qt::Horizontal
2104-
? index.column()
2105-
: index.row());
2106-
q->setSectionHidden(logical, true);
2116+
// adjust section size
2117+
if (newCount != oldCount) {
2118+
const int min = qBound(0, oldCount, newCount - 1);
2119+
q->initializeSections(min, newCount - 1);
2120+
}
2121+
// reset sections
2122+
sectionItems.fill(SectionItem(defaultSectionSize, globalResizeMode), newCount);
2123+
2124+
// all hidden sections are in oldPersistentSections
2125+
hiddenSectionSize.clear();
2126+
2127+
for (const auto &item : oldPersistentSections) {
2128+
const auto &index = item.index;
2129+
if (!index.isValid())
2130+
continue;
2131+
2132+
const int newLogicalIndex = (orientation == Qt::Horizontal
2133+
? index.column()
2134+
: index.row());
2135+
// the new visualIndices are already adjusted / reset by initializeSections()
2136+
const int newVisualIndex = visualIndex(newLogicalIndex);
2137+
auto &newSection = sectionItems[newVisualIndex];
2138+
newSection = item.section;
2139+
2140+
if (newSection.isHidden) {
2141+
// otherwise setSectionHidden will return without doing anything
2142+
newSection.isHidden = false;
2143+
q->setSectionHidden(newLogicalIndex, true);
21072144
}
21082145
}
2146+
2147+
recalcSectionStartPos();
2148+
length = headerLength();
2149+
2150+
if (stretchLastSection) {
2151+
// force rebuild of stretched section later on
2152+
lastSectionLogicalIdx = -1;
2153+
maybeRestorePrevLastSectionAndStretchLast();
2154+
}
21092155
}
21102156

21112157
/*!

src/widgets/itemviews/qheaderview_p.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,6 @@ class QHeaderViewPrivate: public QAbstractItemViewPrivate
231231
: model->rowCount(root));
232232
}
233233

234-
inline bool modelIsEmpty() const {
235-
return (model->rowCount(root) == 0 || model->columnCount(root) == 0);
236-
}
237-
238234
inline void doDelayedResizeSections() {
239235
if (!delayedResize.isActive())
240236
delayedResize.start(0, q_func());
@@ -304,7 +300,6 @@ class QHeaderViewPrivate: public QAbstractItemViewPrivate
304300
QLabel *sectionIndicator;
305301
#endif
306302
QHeaderView::ResizeMode globalResizeMode;
307-
QList<QPersistentModelIndex> persistentHiddenSections;
308303
mutable bool sectionStartposRecalc;
309304
int resizeContentsPrecision;
310305
// header sections
@@ -335,6 +330,11 @@ class QHeaderViewPrivate: public QAbstractItemViewPrivate
335330
};
336331

337332
QVector<SectionItem> sectionItems;
333+
struct LayoutChangeItem {
334+
QPersistentModelIndex index;
335+
SectionItem section;
336+
};
337+
QVector<LayoutChangeItem> layoutChangePersistentSections;
338338

339339
void createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode);
340340
void removeSectionsFromSectionItems(int start, int end);
@@ -388,6 +388,7 @@ class QHeaderViewPrivate: public QAbstractItemViewPrivate
388388

389389
};
390390
Q_DECLARE_TYPEINFO(QHeaderViewPrivate::SectionItem, Q_PRIMITIVE_TYPE);
391+
Q_DECLARE_TYPEINFO(QHeaderViewPrivate::LayoutChangeItem, Q_MOVABLE_TYPE);
391392

392393
QT_END_NAMESPACE
393394

tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,10 +2251,6 @@ void tst_QHeaderView::QTBUG6058_reset()
22512251

22522252
void tst_QHeaderView::QTBUG7833_sectionClicked()
22532253
{
2254-
2255-
2256-
2257-
22582254
QTableView tv;
22592255
QStandardItemModel *sim = new QStandardItemModel(&tv);
22602256
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv);
@@ -2278,11 +2274,20 @@ void tst_QHeaderView::QTBUG7833_sectionClicked()
22782274
tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
22792275

22802276
tv.setModel(proxyModel);
2277+
const int section4Size = tv.horizontalHeader()->sectionSize(4) + 1;
2278+
tv.horizontalHeader()->resizeSection(4, section4Size);
22812279
tv.setColumnHidden(5, true);
22822280
tv.setColumnHidden(6, true);
22832281
tv.horizontalHeader()->swapSections(8, 10);
22842282
tv.sortByColumn(1, Qt::AscendingOrder);
22852283

2284+
QCOMPARE(tv.isColumnHidden(5), true);
2285+
QCOMPARE(tv.isColumnHidden(6), true);
2286+
QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true);
2287+
QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10);
2288+
QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8);
2289+
QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size);
2290+
22862291
QSignalSpy clickedSpy(tv.horizontalHeader(), SIGNAL(sectionClicked(int)));
22872292
QSignalSpy pressedSpy(tv.horizontalHeader(), SIGNAL(sectionPressed(int)));
22882293

0 commit comments

Comments
 (0)