aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldelegatemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels/qqmldelegatemodel.cpp')
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp81
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) {