QListView: fix AdjustToContents (sizeAdjustPolicy)

Unlike an acceptable effect in QTableView + QTreeView
setAdjustPolicy(QAbstractScrollArea::AdjustToContents)
unfortunately didn't work for QListViews (and QListWidget).

This patch corrects QListViews AdjustToContents
behavior.

[ChangeLog][QtWidgets][QListView] A more correct implementation
of QListView::viewportSizeHint has been made. That
implies that setting the sizeAdjustPolicy to AdjustToContent
on QListView and QListWidget will now cause the view to
size after the contents and avoid scrollbars.

Pick-to: 6.2
Task-number: QTBUG-58749
Change-Id: I1675115f2348e2fcf0b2c39b451ef337e10eb872
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Thorbjørn Lund Martsum 2017-09-01 20:45:27 +02:00
parent 0e92ec9728
commit 7502598ef5
2 changed files with 83 additions and 1 deletions

View File

@ -3487,7 +3487,47 @@ int QListView::visualIndex(const QModelIndex &index) const
*/
QSize QListView::viewportSizeHint() const
{
return QAbstractItemView::viewportSizeHint();
Q_D(const QListView);
// We don't have a nice simple size hint for invalid or wrapping list views.
if (!d->model)
return QAbstractItemView::viewportSizeHint();
const int rc = d->model->rowCount();
if (rc == 0 || isWrapping())
return QAbstractItemView::viewportSizeHint();
QStyleOptionViewItem option;
initViewItemOption(&option);
if (uniformItemSizes()) {
QSize sz = d->cachedItemSize;
if (!sz.isValid()) {
QModelIndex idx = d->model->index(0, d->column, d->root);
sz = d->itemSize(option, idx);
}
sz.setHeight(rc * sz.height());
return sz;
}
// Using AdjustToContents with a high number of rows will normally not make sense, so we limit
// this to default 1000 (that is btw the default for QHeaderView::resizeContentsPrecision())
// (By setting the property _q_resizeContentPrecision the user can however override this).
int maximumRows = 1000;
const QVariant userOverrideValue = property("_q_resizeContentPrecision");
if (userOverrideValue.isValid() && userOverrideValue.toInt() > 0) {
maximumRows = userOverrideValue.toInt();
}
const int rowCount = qMin(rc, maximumRows);
int h = 0;
int w = 0;
for (int row = 0; row < rowCount; ++row) {
QModelIndex idx = d->model->index(row, d->column, d->root);
QSize itemSize = d->itemSize(option, idx);
h += itemSize.height();
w = qMax(w, itemSize.width());
}
return QSize(w, h);
}
QT_END_NAMESPACE

View File

@ -38,6 +38,8 @@
#include <QTimer>
#include <QtMath>
#include <QProxyStyle>
#include <QVBoxLayout>
#include <QDialog>
#include <QtTest/private/qtesthelpers_p.h>
#include <QtWidgets/private/qlistview_p.h>
@ -166,6 +168,7 @@ private slots:
void taskQTBUG_39902_mutualScrollBars();
void horizontalScrollingByVerticalWheelEvents();
void taskQTBUG_7232_AllowUserToControlSingleStep();
void taskQTBUG_58749_adjustToContent();
void taskQTBUG_51086_skippingIndexesInSelectedIndexes();
void taskQTBUG_47694_indexOutOfBoundBatchLayout();
void itemAlignment();
@ -2527,6 +2530,45 @@ void tst_QListView::taskQTBUG_7232_AllowUserToControlSingleStep()
QCOMPARE(hStep1, lv.horizontalScrollBar()->singleStep());
}
void tst_QListView::taskQTBUG_58749_adjustToContent()
{
QStandardItemModel model;
model.setRowCount(20);
model.setColumnCount(1);
const QString rowStr = QStringLiteral("Row number txt:");
for (int u = 0; u < model.rowCount(); ++u)
model.setData(model.index(u, 0), rowStr + QString::number(u));
QDialog w; // It really should work for QWidget, too, but sometimes an event (like move)
// is needed to get the resize triggered.
QVBoxLayout *l = new QVBoxLayout(&w);
l->setSizeConstraint(QLayout::SetFixedSize);
auto *view = new QListView;
view->setModel(&model);
view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
l->addWidget(view);
l->setSizeConstraint(QLayout::SetFixedSize);
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
const QString longText = "Here we have a row text that is somewhat longer ...";
QFontMetrics fm(w.font(), &w);
QRect r = fm.boundingRect(model.data(model.index(0, 0)).toString());
const int longTextWidth = fm.horizontalAdvance(longText);
QVERIFY(w.height() > r.height() * model.rowCount());
// We have a width longer than the width for the given index data.
QVERIFY(w.width() > r.width());
// but ... the width should not have a width matching the much longer text.
QVERIFY(w.width() < longTextWidth);
// use the long text and make sure the width is adjusted.
model.setData(model.index(0, 0), longText);
QApplication::processEvents();
QVERIFY(w.width() > longTextWidth);
QVERIFY(view->width() >= longTextWidth);
}
void tst_QListView::taskQTBUG_51086_skippingIndexesInSelectedIndexes()
{
QStandardItemModel data(10, 1);