QIdentityProxyModel: add setHandleSourceLayoutChanges(bool)

Some sub-classes have special handling of source model layout changes
(abbreviated as SMLC from here on out), they relied on disconnecting the
connections to the _q_*layout* slots in the private class using the SLOT
macro. This isn't possible any more after recent changes (and the method
were renamed to remove _q_ prefix).

Sub-classes resorting to using private API is a clear sign some
functionality is missing from the public API, so a cleaner solution for
this issue is adding this setter which enables sub-classes to tell
QIdentityProxyModel to leave handling of the SMLC to them. Thanks to
David Faure for the idea/solution.

[ChangeLog][QtCore][QIdentityProxyModel] Added
setHandleSourceLayoutChanges(bool) method to allow sub-classes to
indicate to QIdentityProxyModel that they will handle source model
layout changes on their own. Also added a getter,
isHandleSourceLayoutChanges().

Change-Id: I1de79dd693ce32a6e2df9a7c81dd4abdc5f00248
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Ahmad Samir 2023-09-06 20:51:15 +03:00
parent 1648d2d93a
commit 675b4f63fe
4 changed files with 79 additions and 4 deletions

View File

@ -335,16 +335,52 @@ void QIdentityProxyModel::setSourceModel(QAbstractItemModel* newSourceModel)
&QIdentityProxyModelPrivate::sourceDataChanged), &QIdentityProxyModelPrivate::sourceDataChanged),
QObjectPrivate::connect(m, &QAbstractItemModel::headerDataChanged, d, QObjectPrivate::connect(m, &QAbstractItemModel::headerDataChanged, d,
&QIdentityProxyModelPrivate::sourceHeaderDataChanged), &QIdentityProxyModelPrivate::sourceHeaderDataChanged),
QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged, d,
&QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged),
QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged, d,
&QIdentityProxyModelPrivate::sourceLayoutChanged),
}; };
if (d->m_handleLayoutChanges) {
d->m_sourceModelConnections.emplace_back(
QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged, d,
&QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged));
d->m_sourceModelConnections.emplace_back(
QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged, d,
&QIdentityProxyModelPrivate::sourceLayoutChanged));
}
} }
endResetModel(); endResetModel();
} }
/*!
\since 6.7
If \a b is \c true, this proxy model will handle the source model layout
changes (by connecting to \c QAbstractItemModel::layoutAboutToBeChanged
and \c QAbstractItemModel::layoutChanged singals).
The default is for this proxy model to handle the source model layout
changes.
In sub-classes of QIdentityProxyModel, it may be useful to set this to
\c false if you need to specially handle the source model layout changes.
\note Calling this method will only have an effect after calling setSourceModel().
*/
void QIdentityProxyModel::setHandleSourceLayoutChanges(bool b)
{
d_func()->m_handleLayoutChanges = b;
}
/*!
\since 6.7
Returns \c true if this proxy model handles the source model layout
changes, otherwise returns \c false.
*/
bool QIdentityProxyModel::isHandleSourceLayoutChanges() const
{
return d_func()->m_handleLayoutChanges;
}
void QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end) void QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
{ {
Q_ASSERT(parent.isValid() ? parent.model() == model : true); Q_ASSERT(parent.isValid() ? parent.model() == model : true);

View File

@ -44,8 +44,11 @@ public:
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override; bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) override; bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) override;
bool isHandleSourceLayoutChanges() const;
protected: protected:
QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent); QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent);
void setHandleSourceLayoutChanges(bool);
private: private:
Q_DECLARE_PRIVATE(QIdentityProxyModel) Q_DECLARE_PRIVATE(QIdentityProxyModel)

View File

@ -63,6 +63,7 @@ public:
void sourceModelReset(); void sourceModelReset();
private: private:
bool m_handleLayoutChanges = true;
QVarLengthArray<QMetaObject::Connection, 18> m_sourceModelConnections; QVarLengthArray<QMetaObject::Connection, 18> m_sourceModelConnections;
}; };

View File

@ -27,6 +27,16 @@ public:
const QModelIndex idx = index(0, 0, QModelIndex()); const QModelIndex idx = index(0, 0, QModelIndex());
Q_EMIT dataChanged(idx, idx, QList<int>() << 1); Q_EMIT dataChanged(idx, idx, QList<int>() << 1);
} }
// Workaround QObject::isSignalConnected() being a protected method
bool isConnected(const QMetaMethod &m) const { return isSignalConnected(m); }
};
class IdentityProxyModel : public QIdentityProxyModel
{
public:
// The name has to be different than the method from the base class
void setHandleSLC(bool b) { setHandleSourceLayoutChanges(b); }
}; };
class tst_QIdentityProxyModel : public QObject class tst_QIdentityProxyModel : public QObject
@ -53,6 +63,9 @@ private slots:
void persistIndexOnLayoutChange(); void persistIndexOnLayoutChange();
void createPersistentOnLayoutAboutToBeChanged(); void createPersistentOnLayoutAboutToBeChanged();
void testSetHandleLayoutChanges();
protected: protected:
void verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex()); void verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex());
@ -513,5 +526,27 @@ void tst_QIdentityProxyModel::createPersistentOnLayoutAboutToBeChanged() // QTBU
QCOMPARE(layoutChangedSpy.size(), 1); QCOMPARE(layoutChangedSpy.size(), 1);
} }
void tst_QIdentityProxyModel::testSetHandleLayoutChanges()
{
const std::array layoutSignals = {
QMetaMethod::fromSignal(&QAbstractItemModel::layoutChanged),
QMetaMethod::fromSignal(&QAbstractItemModel::layoutAboutToBeChanged),
};
DataChangedModel model;
IdentityProxyModel proxy;
proxy.setSourceModel(&model);
for (const auto &m : layoutSignals)
QVERIFY(model.isConnected(m)); // Connected by default
proxy.setSourceModel(nullptr);
// Disable handling (connecting to layotu signals) of source model layout changes
proxy.setHandleSLC(false);
proxy.setSourceModel(&model);
for (const auto &m : layoutSignals)
QVERIFY(!model.isConnected(m));
}
QTEST_MAIN(tst_QIdentityProxyModel) QTEST_MAIN(tst_QIdentityProxyModel)
#include "tst_qidentityproxymodel.moc" #include "tst_qidentityproxymodel.moc"