From 8287fb63ef654dc60fe13890c90ddc54e3634c4e Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 17 Mar 2025 16:09:07 +0100 Subject: [PATCH] QConcatenateTablesProxyModel: cache roleNames() The return value of this function only changes when models are added or removed, and some users call this function often (an earlier version of QGenericItemModel did, possibly QML does?), so cache the result of the function instead of re-creating the QHash on every call. Use QAbstractItemModelPrivate::defaultRoleNames() so we don't need an instance to get the base class' contents. Amend the comment in QAIM::roleNames() asking to keep the two in sync. Amends 5ffb9d7ae6d60fb370b79f8222dab7d7e628fa4f. [ChangeLog][Important Behavior Changes][QtCore][QConcatenateTablesProxyModel] The roleNames property is only updated (lazily) on addSourceModel() and removeSourceModel() now (was: on every call of the function). If your source models change their roleNames() dynamically, you need to call invalidateRoleNamesCache() manually when they do. Change-Id: I32edc93ff9ff7b252ca04f0d61b54b2244d0be48 Reviewed-by: Volker Hilsheimer (cherry picked from commit f3256e059f4e675f6e8d0cda710c3f979d84bc2b) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/itemmodels/qabstractitemmodel.cpp | 1 + .../qconcatenatetablesproxymodel.cpp | 26 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 98b4fbf3f77..70441ab19b1 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -2657,6 +2657,7 @@ QHash QAbstractItemModel::roleNames() const { // if the return value ever becomes dependent on *this, also change the following overrides: // - QFileSystemModel + // - QConcatenateTablesProxyModel return QAbstractItemModelPrivate::defaultRoleNames(); } diff --git a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp index db1e041137f..a328a229f96 100644 --- a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp +++ b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp @@ -61,6 +61,7 @@ public: ConnArray connections; }; QList m_models; + mutable QHash m_roleNames; QList::const_iterator findSourceModel(const QAbstractItemModel *m) const { @@ -77,6 +78,9 @@ public: // for columns{AboutToBe,}{Inserted,Removed} int m_newColumnCount; + mutable uint m_roleNamesDirty : 1; + uint m_reserved : 31; + // for layoutAboutToBeChanged/layoutChanged QList layoutChangePersistentIndexes; QList layoutChangeProxyIndexes; @@ -85,7 +89,9 @@ public: QConcatenateTablesProxyModelPrivate::QConcatenateTablesProxyModelPrivate() : m_rowCount(0), m_columnCount(0), - m_newColumnCount(0) + m_newColumnCount(0), + m_roleNamesDirty(true), + m_reserved(0) { } @@ -507,6 +513,12 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelReset, d, &QConcatenateTablesProxyModelPrivate::slotModelReset), }); + if (!d->m_roleNamesDirty) { + // do update immediately, since append() is a simple update: + const auto newRoleNames = sourceModel->roleNames(); + for (const auto &[k, v] : newRoleNames.asKeyValueRange()) + d->m_roleNames.insert_or_assign(k, v); + } if (newRows > 0) endInsertRows(); @@ -533,6 +545,7 @@ void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceM if (rowsRemoved > 0) beginRemoveRows(QModelIndex(), rowsPrior, rowsPrior + rowsRemoved - 1); d->m_models.erase(it); + d->m_roleNamesDirty = true; d->m_rowCount -= rowsRemoved; if (rowsRemoved > 0) endRemoveRows(); @@ -551,10 +564,13 @@ void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceM QHash QConcatenateTablesProxyModel::roleNames() const { Q_D(const QConcatenateTablesProxyModel); - QHash ret = QAbstractItemModel::roleNames(); - for (const auto &[model, _] : d->m_models) - ret.insert(model->roleNames()); - return ret; + if (d->m_roleNamesDirty) { + d->m_roleNames = QAbstractItemModelPrivate::defaultRoleNames(); + for (const auto &[model, _] : d->m_models) + d->m_roleNames.insert(model->roleNames()); + d->m_roleNamesDirty = false; + } + return d->m_roleNames; } void QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeInserted(const QModelIndex &parent,