Widgets/Itemviews: use pmf-style connect in QTableView

Replace all connect() calls with pmf-style connection syntax. This also
means that we have to properly disconnect everything in the ctor to not
trigger an assertion in QtPrivate::assertObjectType().

Task-number: QTBUG-117698
Change-Id: Ifd6a55080a803b3aba2e35b9679a5194ff3f633c
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Christian Ehrlicher 2023-09-24 19:39:33 +02:00
parent 2203dec57b
commit 3e144bdc74
2 changed files with 97 additions and 62 deletions

View File

@ -595,10 +595,26 @@ void QTableViewPrivate::init()
#if QT_CONFIG(abstractbutton) #if QT_CONFIG(abstractbutton)
cornerWidget = new QTableCornerButton(q); cornerWidget = new QTableCornerButton(q);
cornerWidget->setFocusPolicy(Qt::NoFocus); cornerWidget->setFocusPolicy(Qt::NoFocus);
QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll())); cornerWidgetConnection = QObject::connect(
cornerWidget, &QTableCornerButton::clicked,
q, &QTableView::reset);
#endif #endif
} }
void QTableViewPrivate::clearConnections()
{
for (const QMetaObject::Connection &connection : modelConnections)
QObject::disconnect(connection);
for (const QMetaObject::Connection &connection : verHeaderConnections)
QObject::disconnect(connection);
for (const QMetaObject::Connection &connection : horHeaderConnections)
QObject::disconnect(connection);
for (const QMetaObject::Connection &connection : dynHorHeaderConnections)
QObject::disconnect(connection);
QObject::disconnect(selectionmodelConnection);
QObject::disconnect(cornerWidgetConnection);
}
/*! /*!
\internal \internal
Trims away indices that are hidden in the treeview due to hidden horizontal or vertical sections. Trims away indices that are hidden in the treeview due to hidden horizontal or vertical sections.
@ -1222,6 +1238,8 @@ QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent)
*/ */
QTableView::~QTableView() QTableView::~QTableView()
{ {
Q_D(QTableView);
d->clearConnections();
} }
/*! /*!
@ -1245,28 +1263,23 @@ void QTableView::setModel(QAbstractItemModel *model)
return; return;
//let's disconnect from the old model //let's disconnect from the old model
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), for (const QMetaObject::Connection &connection : d->modelConnections)
this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int))); disconnect(connection);
disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
} }
if (d->selectionModel) { // support row editing if (d->selectionModel) { // support row editing
disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), disconnect(d->selectionmodelConnection);
d->model, SLOT(submit()));
} }
if (model) { //and connect to the new one if (model) { //and connect to the new one
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), d->modelConnections = {
this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int))); QObjectPrivate::connect(model, &QAbstractItemModel::rowsInserted,
connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, &QTableViewPrivate::_q_updateSpanInsertedRows),
this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int))); QObjectPrivate::connect(model, &QAbstractItemModel::columnsInserted,
connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, &QTableViewPrivate::_q_updateSpanInsertedColumns),
this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int))); QObjectPrivate::connect(model, &QAbstractItemModel::rowsRemoved,
connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, &QTableViewPrivate::_q_updateSpanRemovedRows),
this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int))); QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved,
d, &QTableViewPrivate::_q_updateSpanRemovedColumns)
};
} }
d->verticalHeader->setModel(model); d->verticalHeader->setModel(model);
d->horizontalHeader->setModel(model); d->horizontalHeader->setModel(model);
@ -1308,8 +1321,7 @@ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
Q_ASSERT(selectionModel); Q_ASSERT(selectionModel);
if (d->selectionModel) { if (d->selectionModel) {
// support row editing // support row editing
disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), disconnect(d->selectionmodelConnection);
d->model, SLOT(submit()));
} }
d->verticalHeader->setSelectionModel(selectionModel); d->verticalHeader->setSelectionModel(selectionModel);
@ -1318,8 +1330,9 @@ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
if (d->selectionModel) { if (d->selectionModel) {
// support row editing // support row editing
connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), d->selectionmodelConnection =
d->model, SLOT(submit())); connect(d->selectionModel, &QItemSelectionModel::currentRowChanged,
d->model, &QAbstractItemModel::submit);
} }
} }
@ -1356,6 +1369,8 @@ void QTableView::setHorizontalHeader(QHeaderView *header)
if (!header || header == d->horizontalHeader) if (!header || header == d->horizontalHeader)
return; return;
for (const QMetaObject::Connection &connection : d->horHeaderConnections)
disconnect(connection);
if (d->horizontalHeader && d->horizontalHeader->parent() == this) if (d->horizontalHeader && d->horizontalHeader->parent() == this)
delete d->horizontalHeader; delete d->horizontalHeader;
d->horizontalHeader = header; d->horizontalHeader = header;
@ -1367,18 +1382,18 @@ void QTableView::setHorizontalHeader(QHeaderView *header)
d->horizontalHeader->setSelectionModel(d->selectionModel); d->horizontalHeader->setSelectionModel(d->selectionModel);
} }
connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)), d->horHeaderConnections = {
this, SLOT(columnResized(int,int,int))); connect(d->horizontalHeader,&QHeaderView::sectionResized,
connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)), this, &QTableView::columnResized),
this, SLOT(columnMoved(int,int,int))); connect(d->horizontalHeader, &QHeaderView::sectionMoved,
connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)), this, &QTableView::columnMoved),
this, SLOT(columnCountChanged(int,int))); connect(d->horizontalHeader, &QHeaderView::sectionCountChanged,
connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int))); this, &QTableView::columnCountChanged),
connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int))); connect(d->horizontalHeader, &QHeaderView::sectionHandleDoubleClicked,
connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)), this, &QTableView::resizeColumnToContents),
this, SLOT(resizeColumnToContents(int))); connect(d->horizontalHeader, &QHeaderView::geometriesChanged,
connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries())); this, &QTableView::updateGeometries),
};
//update the sorting enabled states on the new header //update the sorting enabled states on the new header
setSortingEnabled(d->sortingEnabled); setSortingEnabled(d->sortingEnabled);
} }
@ -1394,6 +1409,8 @@ void QTableView::setVerticalHeader(QHeaderView *header)
if (!header || header == d->verticalHeader) if (!header || header == d->verticalHeader)
return; return;
for (const QMetaObject::Connection &connection : d->verHeaderConnections)
disconnect(connection);
if (d->verticalHeader && d->verticalHeader->parent() == this) if (d->verticalHeader && d->verticalHeader->parent() == this)
delete d->verticalHeader; delete d->verticalHeader;
d->verticalHeader = header; d->verticalHeader = header;
@ -1405,17 +1422,22 @@ void QTableView::setVerticalHeader(QHeaderView *header)
d->verticalHeader->setSelectionModel(d->selectionModel); d->verticalHeader->setSelectionModel(d->selectionModel);
} }
connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)), d->verHeaderConnections = {
this, SLOT(rowResized(int,int,int))); connect(d->verticalHeader, &QHeaderView::sectionResized,
connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)), this, &QTableView::rowResized),
this, SLOT(rowMoved(int,int,int))); connect(d->verticalHeader, &QHeaderView::sectionMoved,
connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)), this, &QTableView::rowMoved),
this, SLOT(rowCountChanged(int,int))); connect(d->verticalHeader, &QHeaderView::sectionCountChanged,
connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int))); this, &QTableView::rowCountChanged),
connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int))); connect(d->verticalHeader, &QHeaderView::sectionPressed,
connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)), this, &QTableView::selectRow),
this, SLOT(resizeRowToContents(int))); connect(d->verticalHeader, &QHeaderView::sectionHandleDoubleClicked,
connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries())); this, &QTableView::resizeRowToContents),
connect(d->verticalHeader, &QHeaderView::geometriesChanged,
this, &QTableView::updateGeometries),
QObjectPrivate::connect(d->verticalHeader, &QHeaderView::sectionEntered,
d, &QTableViewPrivate::_q_selectRow)
};
} }
/*! /*!
@ -2707,24 +2729,25 @@ void QTableView::setSortingEnabled(bool enable)
{ {
Q_D(QTableView); Q_D(QTableView);
horizontalHeader()->setSortIndicatorShown(enable); horizontalHeader()->setSortIndicatorShown(enable);
for (const QMetaObject::Connection &connection : d->dynHorHeaderConnections)
disconnect(connection);
d->dynHorHeaderConnections.clear();
if (enable) { if (enable) {
disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
this, SLOT(_q_selectColumn(int)));
disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
this, SLOT(selectColumn(int)));
//sortByColumn has to be called before we connect or set the sortingEnabled flag //sortByColumn has to be called before we connect or set the sortingEnabled flag
// because otherwise it will not call sort on the model. // because otherwise it will not call sort on the model.
sortByColumn(horizontalHeader()->sortIndicatorSection(), sortByColumn(d->horizontalHeader->sortIndicatorSection(),
horizontalHeader()->sortIndicatorOrder()); d->horizontalHeader->sortIndicatorOrder());
connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), d->dynHorHeaderConnections = {
this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection); QObjectPrivate::connect(d->horizontalHeader, &QHeaderView::sortIndicatorChanged,
d, &QTableViewPrivate::_q_sortIndicatorChanged)
};
} else { } else {
connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), d->dynHorHeaderConnections = {
this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection); connect(d->horizontalHeader, &QHeaderView::sectionPressed,
connect(horizontalHeader(), SIGNAL(sectionPressed(int)), this, &QTableView::selectColumn),
this, SLOT(selectColumn(int)), Qt::UniqueConnection); QObjectPrivate::connect(d->horizontalHeader, &QHeaderView::sectionEntered,
disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), d, &QTableViewPrivate::_q_selectColumn)
this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder))); };
} }
d->sortingEnabled = enable; d->sortingEnabled = enable;
} }

View File

@ -25,7 +25,9 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include "private/qabstractitemview_p.h" #include "private/qabstractitemview_p.h"
#include <array>
#include <list> #include <list>
#include <vector>
QT_REQUIRE_CONFIG(tableview); QT_REQUIRE_CONFIG(tableview);
@ -96,7 +98,9 @@ private:
Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_RELOCATABLE_TYPE); Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_RELOCATABLE_TYPE);
#if QT_CONFIG(abstractbutton)
class QTableCornerButton;
#endif
class Q_AUTOTEST_EXPORT QTableViewPrivate : public QAbstractItemViewPrivate class Q_AUTOTEST_EXPORT QTableViewPrivate : public QAbstractItemViewPrivate
{ {
Q_DECLARE_PUBLIC(QTableView) Q_DECLARE_PUBLIC(QTableView)
@ -114,6 +118,7 @@ public:
#endif #endif
} }
void init(); void init();
void clearConnections();
void trimHiddenSelections(QItemSelectionRange *range) const; void trimHiddenSelections(QItemSelectionRange *range) const;
QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override; QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override;
@ -159,8 +164,15 @@ public:
QHeaderView *horizontalHeader; QHeaderView *horizontalHeader;
QHeaderView *verticalHeader; QHeaderView *verticalHeader;
#if QT_CONFIG(abstractbutton) #if QT_CONFIG(abstractbutton)
QWidget *cornerWidget; QTableCornerButton *cornerWidget;
QMetaObject::Connection cornerWidgetConnection;
#endif #endif
QMetaObject::Connection selectionmodelConnection;
std::array<QMetaObject::Connection, 4> modelConnections;
std::array<QMetaObject::Connection, 7> verHeaderConnections;
std::array<QMetaObject::Connection, 5> horHeaderConnections;
std::vector<QMetaObject::Connection> dynHorHeaderConnections;
bool sortingEnabled; bool sortingEnabled;
bool geometryRecursionBlock; bool geometryRecursionBlock;
QPoint visualCursor; // (Row,column) cell coordinates to track through span navigation. QPoint visualCursor; // (Row,column) cell coordinates to track through span navigation.