From 3e59a88e8968c6cdac788926bec34c259146b6a8 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 29 Jul 2018 21:31:57 +0200 Subject: [PATCH] QAbstractScrollArea: fix sizeHint when widget is not visible QTable/QTreeView did not follow the documentation and returned their needed size with scrollbars within viewportSizeHint(). Then sizeHint() also took the size of the scrollbars into account when the policy was set to ScrollBarAlwaysOn. This lead to different results when the widget was shown/hidden and/or the scrollbar was visible or not. Fix it by only adding the additional size when the scrollbars are really visible. Also use header->isHidden() instead of isVisible() in QTreeView the same way it is done in QTableView. [ChangeLog][QtWidgets][QAbstractScrollArea] QTableView/QTreeView are now reporting their viewportSizeHint() correctly taking into account its scroll bars visibility and visibilityPolicy. Task-number: QTBUG-69120 Change-Id: If50959a9f7429275e3e33122644c978fb64972ba Reviewed-by: Samuel Gaist Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qtableview.cpp | 2 - src/widgets/itemviews/qtreeview.cpp | 6 +-- src/widgets/widgets/qabstractscrollarea.cpp | 6 ++- .../qtablewidget/tst_qtablewidget.cpp | 52 +++++++++++++++++++ .../itemviews/qtreewidget/tst_qtreewidget.cpp | 46 ++++++++++++++++ 5 files changed, 103 insertions(+), 9 deletions(-) diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index e7edd08d2a..32bbef07e9 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1111,8 +1111,6 @@ QSize QTableView::viewportSizeHint() const Q_D(const QTableView); QSize result( (d->verticalHeader->isHidden() ? 0 : d->verticalHeader->width()) + d->horizontalHeader->length(), (d->horizontalHeader->isHidden() ? 0 : d->horizontalHeader->height()) + d->verticalHeader->length()); - result += QSize(verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0, - horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0); return result; } diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 920e3b346b..2be126ebc6 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -2686,11 +2686,7 @@ QSize QTreeView::viewportSizeHint() const QSize result = QSize(d->header->length(), deepestRect.bottom() + 1); // add size for header - result += QSize(0, d->header->isVisible() ? d->header->height() : 0); - - // add size for scrollbars - result += QSize(verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0, - horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0); + result += QSize(0, d->header->isHidden() ? 0 : d->header->height()); return result; } diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp index 598d173144..fd5d7d8069 100644 --- a/src/widgets/widgets/qabstractscrollarea.cpp +++ b/src/widgets/widgets/qabstractscrollarea.cpp @@ -1604,8 +1604,10 @@ QSize QAbstractScrollArea::sizeHint() const if (!d->sizeHint.isValid() || d->sizeAdjustPolicy == QAbstractScrollArea::AdjustToContents) { const int f = 2 * d->frameWidth; const QSize frame( f, f ); - const QSize scrollbars(d->vbarpolicy == Qt::ScrollBarAlwaysOn ? d->vbar->sizeHint().width() : 0, - d->hbarpolicy == Qt::ScrollBarAlwaysOn ? d->hbar->sizeHint().height() : 0); + const bool vbarHidden = d->vbar->isHidden() || d->vbarpolicy == Qt::ScrollBarAlwaysOff; + const bool hbarHidden = d->hbar->isHidden() || d->hbarpolicy == Qt::ScrollBarAlwaysOff; + const QSize scrollbars(vbarHidden ? 0 : d->vbar->sizeHint().width(), + hbarHidden ? 0 : d->hbar->sizeHint().height()); d->sizeHint = frame + scrollbars + viewportSizeHint(); } return d->sizeHint; diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp index 510fe5659d..e7b40f5f24 100644 --- a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp @@ -83,6 +83,8 @@ private slots: void setItemData(); void cellWidget(); void cellWidgetGeometry(); + void sizeHint_data(); + void sizeHint(); void task231094(); void task219380_removeLastRow(); void task262056_sortDuplicate(); @@ -1450,6 +1452,56 @@ void tst_QTableWidget::cellWidgetGeometry() QCOMPARE(tw.visualItemRect(item).top(), le->geometry().top()); } +void tst_QTableWidget::sizeHint_data() +{ + QTest::addColumn("scrollBarPolicy"); + QTest::addColumn("viewSize"); + QTest::newRow("ScrollBarAlwaysOn") << static_cast(Qt::ScrollBarAlwaysOn) << QSize(); + QTest::newRow("ScrollBarAlwaysOff") << static_cast(Qt::ScrollBarAlwaysOff) << QSize(); + // make sure the scrollbars are shown by resizing the view to 40x40 + QTest::newRow("ScrollBarAsNeeded (40x40)") << static_cast(Qt::ScrollBarAsNeeded) << QSize(40, 40); + QTest::newRow("ScrollBarAsNeeded (1000x1000)") << static_cast(Qt::ScrollBarAsNeeded) << QSize(1000, 1000); +} + +void tst_QTableWidget::sizeHint() +{ + QFETCH(int, scrollBarPolicy); + QFETCH(QSize, viewSize); + + QTableWidget view(2, 2); + view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + view.setVerticalScrollBarPolicy(static_cast(scrollBarPolicy)); + view.setHorizontalScrollBarPolicy(static_cast(scrollBarPolicy)); + for (int r = 0 ; r < view.rowCount(); ++r) + for (int c = 0 ; c < view.columnCount(); ++c) + view.setItem(r, c, new QTableWidgetItem(QString("%1/%2").arg(r).arg(c))); + + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + if (viewSize.isValid()) { + view.resize(viewSize); + view.setColumnWidth(0, 100); + view.setRowHeight(0, 100); + QTRY_COMPARE(view.size(), viewSize); + } + + auto sizeHint = view.sizeHint(); + view.hide(); + QCOMPARE(view.sizeHint(), sizeHint); + + view.horizontalHeader()->hide(); + view.show(); + sizeHint = view.sizeHint(); + view.hide(); + QCOMPARE(view.sizeHint(), sizeHint); + + view.verticalHeader()->hide(); + view.show(); + sizeHint = view.sizeHint(); + view.hide(); + QCOMPARE(view.sizeHint(), sizeHint); +} + void tst_QTableWidget::task231094() { QTableWidget tw(5, 3); diff --git a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp index 4a6244826e..c5ccbc0d0b 100644 --- a/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp +++ b/tests/auto/widgets/itemviews/qtreewidget/tst_qtreewidget.cpp @@ -115,6 +115,8 @@ private slots: void changeDataWithSorting(); void changeDataWithStableSorting_data(); void changeDataWithStableSorting(); + void sizeHint_data(); + void sizeHint(); void sortedIndexOfChild_data(); void sortedIndexOfChild(); @@ -2621,6 +2623,50 @@ void tst_QTreeWidget::changeDataWithStableSorting() QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0); } +void tst_QTreeWidget::sizeHint_data() +{ + QTest::addColumn("scrollBarPolicy"); + QTest::addColumn("viewSize"); + QTest::newRow("ScrollBarAlwaysOn") << static_cast(Qt::ScrollBarAlwaysOn) << QSize(); + QTest::newRow("ScrollBarAlwaysOff") << static_cast(Qt::ScrollBarAlwaysOff) << QSize(); + // make sure the scrollbars are shown by resizing the view to 40x40 + QTest::newRow("ScrollBarAsNeeded (40x40)") << static_cast(Qt::ScrollBarAsNeeded) << QSize(40, 40); + QTest::newRow("ScrollBarAsNeeded (1000x1000)") << static_cast(Qt::ScrollBarAsNeeded) << QSize(1000, 1000); +} + +void tst_QTreeWidget::sizeHint() +{ + QFETCH(int, scrollBarPolicy); + QFETCH(QSize, viewSize); + + QTreeWidget view; + view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + view.setVerticalScrollBarPolicy(static_cast(scrollBarPolicy)); + view.setHorizontalScrollBarPolicy(static_cast(scrollBarPolicy)); + view.setColumnCount(2); + for (int i = 0 ; i < view.columnCount(); ++i) + view.addTopLevelItem(new QTreeWidgetItem(QStringList{"foo","bar"})); + + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + if (viewSize.isValid()) { + view.resize(viewSize); + view.setColumnWidth(0, 100); + QTRY_COMPARE(view.size(), viewSize); + } + + auto sizeHint = view.sizeHint(); + view.hide(); + QCOMPARE(view.sizeHint(), sizeHint); + + view.header()->hide(); + view.show(); + sizeHint = view.sizeHint(); + view.hide(); + QCOMPARE(view.sizeHint(), sizeHint); +} + void tst_QTreeWidget::itemOperatorLessThan() { QTreeWidget tw;