diff options
Diffstat (limited to 'src/qmlmodels/qqmldelegatemodel.cpp')
| -rw-r--r-- | src/qmlmodels/qqmldelegatemodel.cpp | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index ec75a5775c..13965d316b 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -167,6 +167,7 @@ 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) @@ -371,6 +372,8 @@ 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() @@ -400,6 +403,8 @@ 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) @@ -1851,24 +1856,28 @@ void QQmlDelegateModelPrivate::emitChanges() void QQmlDelegateModel::_q_modelAboutToBeReset() { - auto aim = static_cast<QAbstractItemModel *>(sender()); - 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, [&, oldRoleNames](){ - auto aim = static_cast<QAbstractItemModel *>(sender()); - 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); + /* + 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(); } void QQmlDelegateModel::handleModelReset() @@ -1878,6 +1887,23 @@ 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) { |
