diff options
| author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-12-15 16:14:22 +0200 |
|---|---|---|
| committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-12-15 16:14:22 +0200 |
| commit | b58ec3b086518da5aa573f99426235854c23e35f (patch) | |
| tree | 861a9935d8f1cdba2fdca546836a351736dbddbf /src/qmlmodels/qqmldelegatemodel.cpp | |
| parent | 4826f86e274f1b29bd769e6790824f9e62a40f62 (diff) | |
| parent | 22032227d16c39211e2ebceef97d21f4d89c7c87 (diff) | |
Merge tag 'v6.5.8-lts-lgpl' into 6.56.5
Qt 6.5.8-lts-lgpl release
Diffstat (limited to 'src/qmlmodels/qqmldelegatemodel.cpp')
| -rw-r--r-- | src/qmlmodels/qqmldelegatemodel.cpp | 81 |
1 files changed, 38 insertions, 43 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index 13965d316b..97d1ce60cb 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -3,6 +3,8 @@ #include "qqmldelegatemodel_p_p.h" +#include <QtCore/private/qabstractitemmodel_p.h> + #include <QtQml/qqmlinfo.h> #include <private/qqmlabstractdelegatecomponent_p.h> @@ -167,7 +169,6 @@ QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt) , m_transaction(false) , m_incubatorCleanupScheduled(false) , m_waitingToFetchMore(false) - , m_maybeResetRoleNames(false) , m_cacheItems(nullptr) , m_items(nullptr) , m_persistedItems(nullptr) @@ -372,8 +373,6 @@ void QQmlDelegateModelPrivate::connectToAbstractItemModel() QObject::connect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset); qmlobject_connect(aim, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), q, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); - QObject::connect(aim, &QAbstractItemModel::modelReset, q, &QQmlDelegateModel::handleModelReset); - QObject::connect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged); } void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel() @@ -403,8 +402,6 @@ void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel() QObject::disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset); QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), q, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); - QObject::disconnect(aim, &QAbstractItemModel::modelReset, q, &QQmlDelegateModel::handleModelReset); - QObject::disconnect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged); } void QQmlDelegateModel::setModel(const QVariant &model) @@ -428,6 +425,21 @@ void QQmlDelegateModel::setModel(const QVariant &model) _q_itemsInserted(0, d->adaptorModelCount()); d->requestMoreIfNecessary(); } + + // Since 837c2f18cd223707e7cedb213257b0158ea07146, we connect to modelAboutToBeReset + // rather than modelReset so that we can handle role name changes. _q_modelAboutToBeReset + // now connects modelReset to handleModelReset with a single shot connection instead. + // However, it's possible for user code to begin the reset before connectToAbstractItemModel is called + // (QTBUG-125053), in which case we connect to modelReset too late and handleModelReset is never called, + // resulting in delegates not being created in certain cases. + // So, we check at the earliest point we can if the model is in the process of being reset, + // and if so, connect modelReset to handleModelReset. + if (d->m_adaptorModel.adaptsAim()) { + auto *aim = d->m_adaptorModel.aim(); + auto *aimPrivate = QAbstractItemModelPrivate::get(aim); + if (aimPrivate->resetting) + QObject::connect(aim, &QAbstractItemModel::modelReset, this, &QQmlDelegateModel::handleModelReset, Qt::SingleShotConnection); + } } /*! @@ -1856,28 +1868,28 @@ void QQmlDelegateModelPrivate::emitChanges() void QQmlDelegateModel::_q_modelAboutToBeReset() { - /* - roleNames are generally guaranteed to be stable (given that QAIM has no - change signal for them), except that resetting the model is allowed to - invalidate them (QTBUG-32132). DelegateModel must take this into account by - snapshotting the current roleNames before the model is reset. - Afterwards, if we detect that roleNames has changed, we throw the - current model set up away and rebuild everything from scratch – it is - unlikely that a more efficient implementation would be worth it. - - If we detect no changes, we simply use the existing logic to handle the - model reset. - - This (role name resetting) logic relies on the fact that - modelAboutToBeReset must be followed by a modelReset signal before any - further modelAboutToBeReset can occur. However, it's possible for user - code to begin the reset before connectToAbstractItemModel is called - (QTBUG-125053), in which case we don't attempt to reset the role names. - */ Q_D(QQmlDelegateModel); - Q_ASSERT(!d->m_maybeResetRoleNames); - d->m_maybeResetRoleNames = true; - d->m_roleNamesBeforeReset = d->m_adaptorModel.aim()->roleNames(); + if (!d->m_adaptorModel.adaptsAim()) + return; + auto aim = d->m_adaptorModel.aim(); + auto oldRoleNames = aim->roleNames(); + // this relies on the fact that modelAboutToBeReset must be followed + // by a modelReset signal before any further modelAboutToBeReset can occur + QObject::connect(aim, &QAbstractItemModel::modelReset, this, [this, d, oldRoleNames, aim](){ + if (!d->m_adaptorModel.adaptsAim() || d->m_adaptorModel.aim() != aim) + return; + if (oldRoleNames == aim->roleNames()) { + // if the rolenames stayed the same (most common case), then we don't have + // to throw away all the setup that we did + handleModelReset(); + } else { + // If they did change, we give up and just start from scratch via setMode + setModel(QVariant::fromValue(model())); + // but we still have to call handleModelReset, otherwise views will + // not refresh + handleModelReset(); + } + }, Qt::SingleShotConnection); } void QQmlDelegateModel::handleModelReset() @@ -1887,23 +1899,6 @@ void QQmlDelegateModel::handleModelReset() return; int oldCount = d->m_count; - - if (d->m_maybeResetRoleNames) { - auto aim = d->m_adaptorModel.aim(); - if (!d->m_adaptorModel.adaptsAim() || d->m_adaptorModel.aim() != aim) - return; - - // If the role names stayed the same (most common case), then we don't have - // to throw away all the setup that we did. - // If they did change, we give up and just start from scratch via setModel. - // We do this before handling the reset to ensure that views refresh. - if (aim->roleNames() != d->m_roleNamesBeforeReset) - setModel(QVariant::fromValue(model())); - - d->m_maybeResetRoleNames = false; - d->m_roleNamesBeforeReset.clear(); - } - d->m_adaptorModel.rootIndex = QModelIndex(); if (d->m_complete) { |
