From db404fea64074b353b2f1766dffd26aa24bdbd50 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 19 Jun 2017 16:35:52 +0200 Subject: QListView: Fix viewport size when checking scroll bar visibility Subtract the viewport margins from the contentsRect in QCommonListViewBase::updateHorizontal/VerticalScrollBar(). This affects list views in icon mode and list mode / ScrollPerPixel. Task-number: QTBUG-61383 Change-Id: I6f2f7951ac9344ac21cef1eba061780d130e2467 Reviewed-by: David Faure --- src/widgets/itemviews/qlistview.cpp | 9 ++- src/widgets/itemviews/qlistview_p.h | 1 + .../widgets/itemviews/qlistview/tst_qlistview.cpp | 83 +++++++++++++++++++--- 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 93b2b0b5e0..396d84de9c 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1871,6 +1871,11 @@ void QCommonListViewBase::paintDragDrop(QPainter *painter) } #endif +QSize QListModeViewBase::viewportSize(const QAbstractItemView *v) +{ + return v->contentsRect().marginsRemoved(v->viewportMargins()).size(); +} + void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step) { horizontalScrollBar()->d_func()->itemviewChangeSingleStep(step.width() + spacing()); @@ -1883,7 +1888,7 @@ void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step) const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded && qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded; - const QSize viewportSize = qq->contentsRect().size(); + const QSize viewportSize = QListModeViewBase::viewportSize(qq); bool verticalWantsToShow = contentsSize.height() > viewportSize.height(); bool horizontalWantsToShow; @@ -1913,7 +1918,7 @@ void QCommonListViewBase::updateVerticalScrollBar(const QSize &step) const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded && qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded; - const QSize viewportSize = qq->contentsRect().size(); + const QSize viewportSize = QListModeViewBase::viewportSize(qq); bool horizontalWantsToShow = contentsSize.width() > viewportSize.width(); bool verticalWantsToShow; diff --git a/src/widgets/itemviews/qlistview_p.h b/src/widgets/itemviews/qlistview_p.h index 47effcdfd9..5b674b3eca 100644 --- a/src/widgets/itemviews/qlistview_p.h +++ b/src/widgets/itemviews/qlistview_p.h @@ -225,6 +225,7 @@ public: QRect mapToViewport(const QRect &rect) const override; int horizontalOffset() const override; int verticalOffset() const override; + inline static QSize viewportSize(const QAbstractItemView *v); void updateHorizontalScrollBar(const QSize &step) override; void updateVerticalScrollBar(const QSize &step) override; diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp index a89f8f3c8a..b9785c35ac 100644 --- a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp +++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp @@ -60,6 +60,10 @@ static inline HWND getHWNDForWidget(const QWidget *widget) } #endif // Q_OS_WIN +Q_DECLARE_METATYPE(QAbstractItemView::ScrollMode) +Q_DECLARE_METATYPE(QMargins) +Q_DECLARE_METATYPE(QSize) + // Make a widget frameless to prevent size constraints of title bars // from interfering (Windows). static inline void setFrameless(QWidget *w) @@ -902,10 +906,11 @@ class PublicListView : public QListView class TestDelegate : public QItemDelegate { public: - TestDelegate(QObject *parent) : QItemDelegate(parent), m_sizeHint(50,50) {} + explicit TestDelegate(QObject *parent, const QSize &sizeHint = QSize(50,50)) + : QItemDelegate(parent), m_sizeHint(sizeHint) {} QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return m_sizeHint; } - QSize m_sizeHint; + const QSize m_sizeHint; }; typedef QList IntList; @@ -1250,9 +1255,7 @@ void tst_QListView::scrollBarRanges() lv.setModel(&model); lv.resize(250, 130); - TestDelegate *delegate = new TestDelegate(&lv); - delegate->m_sizeHint = QSize(100, rowHeight); - lv.setItemDelegate(delegate); + lv.setItemDelegate(new TestDelegate(&lv, QSize(100, rowHeight))); topLevel.show(); for (int h = 30; h <= 210; ++h) { @@ -1268,14 +1271,18 @@ void tst_QListView::scrollBarAsNeeded_data() { QTest::addColumn("size"); QTest::addColumn("itemCount"); + QTest::addColumn("verticalScrollMode"); + QTest::addColumn("viewportMargins"); + QTest::addColumn("delegateSize"); QTest::addColumn("flow"); QTest::addColumn("horizontalScrollBarVisible"); QTest::addColumn("verticalScrollBarVisible"); - QTest::newRow("TopToBottom, count:0") << QSize(200, 100) << 0 + << QListView::ScrollPerItem + << QMargins() << QSize() << int(QListView::TopToBottom) << false << false; @@ -1283,6 +1290,8 @@ void tst_QListView::scrollBarAsNeeded_data() QTest::newRow("TopToBottom, count:1") << QSize(200, 100) << 1 + << QListView::ScrollPerItem + << QMargins() << QSize() << int(QListView::TopToBottom) << false << false; @@ -1290,13 +1299,46 @@ void tst_QListView::scrollBarAsNeeded_data() QTest::newRow("TopToBottom, count:20") << QSize(200, 100) << 20 + << QListView::ScrollPerItem + << QMargins() << QSize() + << int(QListView::TopToBottom) + << false + << true; + + QTest::newRow("TopToBottom, fixed size, count:4") + << QSize(200, 200) + << 4 + << QListView::ScrollPerPixel + << QMargins() << QSize(40, 40) + << int(QListView::TopToBottom) + << false + << false; + + // QTBUG-61383, vertical case: take viewport margins into account + QTest::newRow("TopToBottom, fixed size, vertical margins, count:4") + << QSize(200, 200) + << 4 + << QListView::ScrollPerPixel + << QMargins(0, 50, 0, 50) << QSize(40, 40) << int(QListView::TopToBottom) << false << true; + // QTBUG-61383, horizontal case: take viewport margins into account + QTest::newRow("TopToBottom, fixed size, horizontal margins, count:4") + << QSize(200, 200) + << 4 + << QListView::ScrollPerPixel + << QMargins(50, 0, 50, 0) << QSize(120, 40) + << int(QListView::TopToBottom) + << true + << false; + QTest::newRow("LeftToRight, count:0") << QSize(200, 100) << 0 + << QListView::ScrollPerItem + << QMargins() << QSize() << int(QListView::LeftToRight) << false << false; @@ -1304,6 +1346,8 @@ void tst_QListView::scrollBarAsNeeded_data() QTest::newRow("LeftToRight, count:1") << QSize(200, 100) << 1 + << QListView::ScrollPerItem + << QMargins() << QSize() << int(QListView::LeftToRight) << false << false; @@ -1311,17 +1355,31 @@ void tst_QListView::scrollBarAsNeeded_data() QTest::newRow("LeftToRight, count:20") << QSize(200, 100) << 20 + << QListView::ScrollPerItem + << QMargins() << QSize() << int(QListView::LeftToRight) << true << false; } + +class ScrollBarTestListView : public QListView +{ + public: + explicit ScrollBarTestListView(QWidget *p) : QListView(p) {} + + using QAbstractScrollArea::setViewportMargins; +}; + void tst_QListView::scrollBarAsNeeded() { QFETCH(QSize, size); QFETCH(int, itemCount); + QFETCH(QAbstractItemView::ScrollMode, verticalScrollMode); + QFETCH(QMargins, viewportMargins); + QFETCH(QSize, delegateSize); QFETCH(int, flow); QFETCH(bool, horizontalScrollBarVisible); QFETCH(bool, verticalScrollBarVisible); @@ -1330,10 +1388,17 @@ void tst_QListView::scrollBarAsNeeded() const int rowCounts[3] = {0, 1, 20}; QWidget topLevel; - QListView lv(&topLevel); + topLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QStringLiteral("::") + + QLatin1String(QTest::currentDataTag())); + ScrollBarTestListView lv(&topLevel); lv.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); lv.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + lv.setVerticalScrollMode(verticalScrollMode); + lv.setViewportMargins(viewportMargins); lv.setFlow((QListView::Flow)flow); + if (!delegateSize.isEmpty()) + lv.setItemDelegate(new TestDelegate(&lv, delegateSize)); + QStringListModel model(&lv); lv.setModel(&model); lv.resize(size); @@ -2380,9 +2445,7 @@ void tst_QListView::horizontalScrollingByVerticalWheelEvents() QListView lv; lv.setWrapping(true); - TestDelegate *delegate = new TestDelegate(&lv); - delegate->m_sizeHint = QSize(100, 100); - lv.setItemDelegate(delegate); + lv.setItemDelegate(new TestDelegate(&lv, QSize(100, 100))); QtTestModel model; model.colCount = 1; -- cgit v1.2.3