diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 73c448362ac..3b4f8911e07 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -1234,6 +1234,14 @@ void QHeaderView::setSectionResizeMode(ResizeMode mode) initializeSections(); d->stretchSections = (mode == Stretch ? count() : 0); d->contentsSections = (mode == ResizeToContents ? count() : 0); + + if (d->noSectionMemoryUsage() && (mode == Stretch || mode == ResizeToContents)) { + // Stretch can/could *_maybe_* in the future be used to switch back to low memory mode + // (if no sections are moved or swapped), but for now we simply instantly switch + // to normal memory usage on auto resize. + d->switchToFlexibleModeWithSectionMemoryUsage(); + } + d->setGlobalHeaderResizeMode(mode); if (d->hasAutoResizeSections()) d->doDelayedResizeSections(); // section sizes may change as a result of the new mode diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 230ed47b39f..f1a54a27f8a 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -237,6 +238,7 @@ private slots: void normalMemoryUsageOnHide(); void storeRestoreLowMemoryMode(); void setSectionResizeModeWithSectionWillTakeMemory(); + void setModelWithAutoSizeWillSwitchToMemoryMode(); void setDefaultSectionSizeRespectsColumnWidth(); @@ -3854,6 +3856,110 @@ void tst_QHeaderView::setSectionResizeModeWithSectionWillTakeMemory() QVERIFY(!tv2.hasLowMemoryUsage()); } +class SpecialResizeModeTestDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + SpecialResizeModeTestDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) + {} + QSize sizeHint(const QStyleOptionViewItem &/*option*/, const QModelIndex &/*index*/) const override + { + return QSize(m_cellWidth, m_cellWidth); + } + int cellWidth() const { return m_cellWidth; } + void setCellWidth(int width) { m_cellWidth = width; } + +private: + int m_cellWidth{100}; +}; + +class SpecialResizeModeTestModel : public QAbstractTableModel +{ +public: + SpecialResizeModeTestModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {} + int rowCount(const QModelIndex & = {}) const override { return 105; } + int columnCount(const QModelIndex & = {}) const override { return 15; } + + QVariant data(const QModelIndex &i, int role) const override + { + return (role == Qt::DisplayRole) ? QString("R: %1, C: %2").arg(i.row()).arg(i.column()) : QVariant(); + } + + QVariant headerData(int /*section*/, Qt::Orientation /*orientation*/, int role = Qt::DisplayRole) const override + { + return (role == Qt::SizeHintRole) ? QSize(1, 1) : QVariant(); + } +}; + +// Custom table view that sets the cell sizes based on a property +class SpecialResizeModeTableView : public QTableView +{ + Q_OBJECT +public: + SpecialResizeModeTableView(QWidget *parent = nullptr) : QTableView(parent) + { + QHeaderView *hHeader = horizontalHeader(); + QHeaderView *vHeader = verticalHeader(); + // Hide the headers, otherwise it appears their size will be used + hHeader->hide(); + vHeader->hide(); + hHeader->setSectionResizeMode(QHeaderView::ResizeToContents); + vHeader->setSectionResizeMode(QHeaderView::ResizeToContents); + hHeader->setMinimumSectionSize(1); + vHeader->setMinimumSectionSize(1); + + setItemDelegate(&delegate_); + } + + int cellWidth() const { return delegate_.cellWidth(); } + void setCellWidth(int width) + { + delegate_.setCellWidth(width); + scheduleDelayedItemsLayout(); + } + + // The following are overridden for optimization purposes but not relevant to the example + int sizeHintForRow(int) const override { return cellWidth(); } + int sizeHintForColumn(int) const override { return cellWidth(); } + + QSize sizeHint() const override + { + return QSize(720, 480); // Fixed size for the example + } + +private: + SpecialResizeModeTestDelegate delegate_; +}; + +void tst_QHeaderView::setModelWithAutoSizeWillSwitchToMemoryMode() +{ + SpecialResizeModeTableView v; + const int defaultWidth = 20; + + QByteArray emptyState = v.horizontalHeader()->saveState(); + v.horizontalHeader()->setDefaultSectionSize(defaultWidth); + v.horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + + v.show(); + QVERIFY(QTest::qWaitForWindowExposed(&v)); + + auto *model = new SpecialResizeModeTestModel(&v); + v.setModel(model); + const int headerLength = v.horizontalHeader()->length(); + const int unexpectedLength = defaultWidth * model->columnCount(); + // The length of the header is not the default section size times sections. + // If it fails we like to see this. + QVERIFY(headerLength != unexpectedLength); + // A secondary test is that obviously the header length is the bigger one. + QCOMPARE_GT(headerLength, unexpectedLength); + // and finally we should have switched memory model. + QByteArray nonEmptyState = v.horizontalHeader()->saveState(); + const int delta = model->columnCount() * 8; + // even with delta help the nonEmptyState should now be bigger. + QCOMPARE_GT(nonEmptyState.size(), emptyState.size() + delta); +} + void tst_QHeaderView::setDefaultSectionSizeRespectsColumnWidth() { QTreeWidget tree;