forked from qt-creator/qt-creator
QmlDesigner: Add cache for instances
When detaching the NodeInstanceView from a model we insert all instances for this model into a cache. The cache currently takes a maximum of 20 models. If the model is reattached we use the existing instances, instead of creating new ones. We also recycle the state previews. Outdated data will be overridden by new data once the puppet is sending the respective commands. Task-number: QDS-6121 Change-Id: I15b5628afc5579ba8a03dca23ba5809e55022f3d Reviewed-by: Marco Bubke <marco.bubke@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
81
src/plugins/qmldesigner/designercore/include/modelcache.h
Normal file
81
src/plugins/qmldesigner/designercore/include/modelcache.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qmldesignercorelib_global.h>
|
||||||
|
|
||||||
|
#include <model.h>
|
||||||
|
|
||||||
|
#include <utils/optional.h>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
template<class DataType>
|
||||||
|
class ModelCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelCache(int max = 20)
|
||||||
|
: m_maxEntries(max)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void insert(Model *model, const DataType &data)
|
||||||
|
{
|
||||||
|
QObject::connect(model, &Model::destroyed, [this](QObject *o) {
|
||||||
|
QObject *deletedModel = o;
|
||||||
|
|
||||||
|
if (deletedModel) {
|
||||||
|
m_content.remove(deletedModel);
|
||||||
|
m_queue.removeAll(deletedModel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_content.insert(model, data);
|
||||||
|
if (!m_queue.contains(model))
|
||||||
|
m_queue.append(model);
|
||||||
|
if (m_queue.length() > m_maxEntries) {
|
||||||
|
QObject *first = m_queue.takeFirst();
|
||||||
|
m_content.remove(first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::optional<DataType> take(Model *model)
|
||||||
|
{
|
||||||
|
if (!m_content.contains(model))
|
||||||
|
return {};
|
||||||
|
m_queue.removeOne(model);
|
||||||
|
return m_content.take(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QObject *, DataType> m_content;
|
||||||
|
QQueue<QObject *> m_queue;
|
||||||
|
int m_maxEntries = 20;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "qmldesignercorelib_global.h"
|
#include "qmldesignercorelib_global.h"
|
||||||
#include "abstractview.h"
|
#include "abstractview.h"
|
||||||
|
#include "modelcache.h"
|
||||||
|
|
||||||
#include <modelnode.h>
|
#include <modelnode.h>
|
||||||
#include <nodeinstance.h>
|
#include <nodeinstance.h>
|
||||||
@@ -232,11 +233,29 @@ private: // functions
|
|||||||
PropertyChangeFlags flags);
|
PropertyChangeFlags flags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct NodeInstanceCacheData
|
||||||
|
{
|
||||||
|
NodeInstanceCacheData(const QHash<ModelNode, NodeInstance> &i,
|
||||||
|
const QHash<ModelNode, QImage> &p)
|
||||||
|
: instances(i)
|
||||||
|
, previewImages(p)
|
||||||
|
{}
|
||||||
|
|
||||||
|
NodeInstanceCacheData() = default;
|
||||||
|
|
||||||
|
QHash<ModelNode, NodeInstance> instances;
|
||||||
|
QHash<ModelNode, QImage> previewImages;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<NodeInstance> loadInstancesFromCache(const QList<ModelNode> &nodeList,
|
||||||
|
const NodeInstanceCacheData &cache);
|
||||||
|
|
||||||
QHash<QString, ModelNodePreviewImageData> m_imageDataMap;
|
QHash<QString, ModelNodePreviewImageData> m_imageDataMap;
|
||||||
|
|
||||||
NodeInstance m_rootNodeInstance;
|
NodeInstance m_rootNodeInstance;
|
||||||
NodeInstance m_activeStateInstance;
|
NodeInstance m_activeStateInstance;
|
||||||
QHash<ModelNode, NodeInstance> m_nodeInstanceHash;
|
QHash<ModelNode, NodeInstance> m_nodeInstanceHash;
|
||||||
|
ModelCache<NodeInstanceCacheData> m_nodeInstanceCache;
|
||||||
QHash<ModelNode, QImage> m_statePreviewImage;
|
QHash<ModelNode, QImage> m_statePreviewImage;
|
||||||
ConnectionManagerInterface &m_connectionManager;
|
ConnectionManagerInterface &m_connectionManager;
|
||||||
std::unique_ptr<NodeInstanceServerProxy> m_nodeInstanceServer;
|
std::unique_ptr<NodeInstanceServerProxy> m_nodeInstanceServer;
|
||||||
|
@@ -265,6 +265,9 @@ void NodeInstanceView::modelAboutToBeDetached(Model * model)
|
|||||||
{
|
{
|
||||||
m_connectionManager.setCrashCallback({});
|
m_connectionManager.setCrashCallback({});
|
||||||
|
|
||||||
|
m_nodeInstanceCache.insert(model,
|
||||||
|
NodeInstanceCacheData(m_nodeInstanceHash, m_statePreviewImage));
|
||||||
|
|
||||||
removeAllInstanceNodeRelationships();
|
removeAllInstanceNodeRelationships();
|
||||||
if (m_nodeInstanceServer) {
|
if (m_nodeInstanceServer) {
|
||||||
m_nodeInstanceServer->clearScene(createClearSceneCommand());
|
m_nodeInstanceServer->clearScene(createClearSceneCommand());
|
||||||
@@ -935,10 +938,16 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
|
|||||||
QList<ModelNode> nodeList = allModelNodes();
|
QList<ModelNode> nodeList = allModelNodes();
|
||||||
QList<NodeInstance> instanceList;
|
QList<NodeInstance> instanceList;
|
||||||
|
|
||||||
for (const ModelNode &node : std::as_const(nodeList)) {
|
Utils::optional oldNodeInstanceHash = m_nodeInstanceCache.take(model());
|
||||||
NodeInstance instance = loadNode(node);
|
if (oldNodeInstanceHash
|
||||||
if (!isSkippedNode(node))
|
&& oldNodeInstanceHash->instances.value(rootModelNode()).isValid()) {
|
||||||
instanceList.append(instance);
|
instanceList = loadInstancesFromCache(nodeList, oldNodeInstanceHash.value());
|
||||||
|
} else {
|
||||||
|
for (const ModelNode &node : std::as_const(nodeList)) {
|
||||||
|
NodeInstance instance = loadNode(node);
|
||||||
|
if (!isSkippedNode(node))
|
||||||
|
instanceList.append(instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeList = filterNodesForSkipItems(nodeList);
|
nodeList = filterNodesForSkipItems(nodeList);
|
||||||
@@ -1942,4 +1951,32 @@ void NodeInstanceView::maybeResetOnPropertyChange(const PropertyName &name, cons
|
|||||||
resetPuppet();
|
resetPuppet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<NodeInstance> NodeInstanceView::loadInstancesFromCache(const QList<ModelNode> &nodeList,
|
||||||
|
const NodeInstanceCacheData &cache)
|
||||||
|
{
|
||||||
|
QList<NodeInstance> instanceList;
|
||||||
|
|
||||||
|
auto previews = cache.previewImages;
|
||||||
|
auto iterator = previews.begin();
|
||||||
|
while (iterator != previews.end()) {
|
||||||
|
if (iterator.key().isValid())
|
||||||
|
m_statePreviewImage.insert(iterator.key(), iterator.value());
|
||||||
|
iterator++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ModelNode &node : std::as_const(nodeList)) {
|
||||||
|
NodeInstance instance = cache.instances.value(node);
|
||||||
|
if (instance.isValid())
|
||||||
|
insertInstanceRelationships(instance);
|
||||||
|
else
|
||||||
|
instance = loadNode(node);
|
||||||
|
|
||||||
|
if (node.isRootNode())
|
||||||
|
m_rootNodeInstance = instance;
|
||||||
|
if (!isSkippedNode(node))
|
||||||
|
instanceList.append(instanceForModelNode(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
return instanceList;
|
||||||
}
|
}
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
Reference in New Issue
Block a user