aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmltableinstancemodel.cpp
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2019-09-12 14:14:05 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2019-12-04 01:34:07 +0100
commit4b58d69d56c5876a1b1d71ce6a96b4c6c81a833f (patch)
tree094a0240be7462a2768084985d49f2f58a294ab1 /src/qmlmodels/qqmltableinstancemodel.cpp
parentaf9a96ca10e72517a7e8aa1ada7ec2d635e2a9ff (diff)
QQmlTableInstanceModel: factor out reuse pool
Factor out the reuse pool logic in TableInstanceModel into a separate class, so that we can share it with the upcoming implementation for recycling items in QQmlDelegateModel. Change-Id: If8f700b7a0208bac7d1cb1de087792e2c3a9b512 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/qmlmodels/qqmltableinstancemodel.cpp')
-rw-r--r--src/qmlmodels/qqmltableinstancemodel.cpp93
1 files changed, 11 insertions, 82 deletions
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp
index 1af93e87d8..b4d1e61e31 100644
--- a/src/qmlmodels/qqmltableinstancemodel.cpp
+++ b/src/qmlmodels/qqmltableinstancemodel.cpp
@@ -141,7 +141,7 @@ QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
return nullptr;
// Check if the pool contains an item that can be reused
- modelItem = takeFromReusableItemsPool(delegate);
+ modelItem = m_reusableItemsPool.takeItem(delegate, index);
if (modelItem) {
reuseItem(modelItem, index);
m_modelItems.insert(index, modelItem);
@@ -225,16 +225,21 @@ QQmlInstanceModel::ReleaseFlags QQmlTableInstanceModel::release(QObject *object,
m_modelItems.remove(modelItem->index);
if (reusable == Reusable) {
- insertIntoReusableItemsPool(modelItem);
+ m_reusableItemsPool.insertItem(modelItem);
+ emit itemPooled(modelItem->index, modelItem->object);
return QQmlInstanceModel::Pooled;
}
// The item is not reused or referenced by anyone, so just delete it
- modelItem->destroyObject();
- emit destroyingItem(object);
+ destroyModelItem(modelItem);
+ return QQmlInstanceModel::Destroyed;
+}
+void QQmlTableInstanceModel::destroyModelItem(QQmlDelegateModelItem *modelItem)
+{
+ emit destroyingItem(modelItem->object);
+ modelItem->destroyObject();
delete modelItem;
- return QQmlInstanceModel::Destroyed;
}
void QQmlTableInstanceModel::cancel(int index)
@@ -257,85 +262,9 @@ void QQmlTableInstanceModel::cancel(int index)
delete modelItem;
}
-void QQmlTableInstanceModel::insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem)
-{
- // Currently, the only way for a view to reuse items is to call QQmlTableInstanceModel::release()
- // with the second argument explicitly set to QQmlTableInstanceModel::Reusable. If the released
- // item is no longer referenced, it will be added to the pool. Reusing of items can be specified
- // per item, in case certain items cannot be recycled.
- // A QQmlDelegateModelItem knows which delegate its object was created from. So when we are
- // about to create a new item, we first check if the pool contains an item based on the same
- // delegate from before. If so, we take it out of the pool (instead of creating a new item), and
- // update all its context-, and attached properties.
- // When a view is recycling items, it should call QQmlTableInstanceModel::drainReusableItemsPool()
- // regularly. As there is currently no logic to 'hibernate' items in the pool, they are only
- // meant to rest there for a short while, ideally only from the time e.g a row is unloaded
- // on one side of the view, and until a new row is loaded on the opposite side. In-between
- // this time, the application will see the item as fully functional and 'alive' (just not
- // visible on screen). Since this time is supposed to be short, we don't take any action to
- // notify the application about it, since we don't want to trigger any bindings that can
- // disturb performance.
- // A recommended time for calling drainReusableItemsPool() is each time a view has finished
- // loading e.g a new row or column. If there are more items in the pool after that, it means
- // that the view most likely doesn't need them anytime soon. Those items should be destroyed to
- // not consume resources.
- // Depending on if a view is a list or a table, it can sometimes be performant to keep
- // items in the pool for a bit longer than one "row out/row in" cycle. E.g for a table, if the
- // number of visible rows in a view is much larger than the number of visible columns.
- // In that case, if you flick out a row, and then flick in a column, you would throw away a lot
- // of items in the pool if completely draining it. The reason is that unloading a row places more
- // items in the pool than what ends up being recycled when loading a new column. And then, when you
- // next flick in a new row, you would need to load all those drained items again from scratch. For
- // that reason, you can specify a maxPoolTime to the drainReusableItemsPool() that allows you to keep
- // items in the pool for a bit longer, effectively keeping more items in circulation.
- // A recommended maxPoolTime would be equal to the number of dimenstions in the view, which
- // means 1 for a list view and 2 for a table view. If you specify 0, all items will be drained.
- Q_ASSERT(!modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- Q_ASSERT(modelItem->object);
-
- modelItem->poolTime = 0;
- m_reusableItemsPool.append(modelItem);
- emit itemPooled(modelItem->index, modelItem->object);
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::takeFromReusableItemsPool(const QQmlComponent *delegate)
-{
- // Find the oldest item in the pool that was made from the same delegate as
- // the given argument, remove it from the pool, and return it.
- if (m_reusableItemsPool.isEmpty())
- return nullptr;
-
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
- if ((*it)->delegate != delegate)
- continue;
- auto modelItem = *it;
- m_reusableItemsPool.erase(it);
- return modelItem;
- }
-
- return nullptr;
-}
-
void QQmlTableInstanceModel::drainReusableItemsPool(int maxPoolTime)
{
- // Rather than releasing all pooled items upon a call to this function, each
- // item has a poolTime. The poolTime specifies for how many loading cycles an item
- // has been resting in the pool. And for each invocation of this function, poolTime
- // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
- // from the pool and released. This way, the view can tweak a bit for how long
- // items should stay in "circulation", even if they are not recycled right away.
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
- auto modelItem = *it;
- modelItem->poolTime++;
- if (modelItem->poolTime <= maxPoolTime) {
- ++it;
- } else {
- it = m_reusableItemsPool.erase(it);
- release(modelItem->object, NotReusable);
- }
- }
+ m_reusableItemsPool.drain(maxPoolTime, [=](QQmlDelegateModelItem *modelItem){ destroyModelItem(modelItem); });
}
void QQmlTableInstanceModel::reuseItem(QQmlDelegateModelItem *item, int newModelIndex)