diff options
author | Thomas Hartmann <thomas.hartmann@qt.io> | 2022-02-09 13:37:05 +0100 |
---|---|---|
committer | Thomas Hartmann <thomas.hartmann@qt.io> | 2022-02-09 17:49:59 +0000 |
commit | cea31a2c4f16a8cdba279b2834cc3f795b22cf13 (patch) | |
tree | 694e914bb9cabfc48f3ffb918efe70773e781253 | |
parent | 3bd96e7e739a3a8decc2f0b1fc9832b7acf5d64d (diff) |
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>
3 files changed, 141 insertions, 4 deletions
diff --git a/src/plugins/qmldesigner/designercore/include/modelcache.h b/src/plugins/qmldesigner/designercore/include/modelcache.h new file mode 100644 index 0000000000..bd4704294d --- /dev/null +++ b/src/plugins/qmldesigner/designercore/include/modelcache.h @@ -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 diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index e29498e143..48ecd4119f 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -27,6 +27,7 @@ #include "qmldesignercorelib_global.h" #include "abstractview.h" +#include "modelcache.h" #include <modelnode.h> #include <nodeinstance.h> @@ -232,11 +233,29 @@ private: // functions PropertyChangeFlags flags); 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; NodeInstance m_rootNodeInstance; NodeInstance m_activeStateInstance; QHash<ModelNode, NodeInstance> m_nodeInstanceHash; + ModelCache<NodeInstanceCacheData> m_nodeInstanceCache; QHash<ModelNode, QImage> m_statePreviewImage; ConnectionManagerInterface &m_connectionManager; std::unique_ptr<NodeInstanceServerProxy> m_nodeInstanceServer; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 5b83b63795..48391fe4b9 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -265,6 +265,9 @@ void NodeInstanceView::modelAboutToBeDetached(Model * model) { m_connectionManager.setCrashCallback({}); + m_nodeInstanceCache.insert(model, + NodeInstanceCacheData(m_nodeInstanceHash, m_statePreviewImage)); + removeAllInstanceNodeRelationships(); if (m_nodeInstanceServer) { m_nodeInstanceServer->clearScene(createClearSceneCommand()); @@ -935,10 +938,16 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() QList<ModelNode> nodeList = allModelNodes(); QList<NodeInstance> instanceList; - for (const ModelNode &node : std::as_const(nodeList)) { - NodeInstance instance = loadNode(node); - if (!isSkippedNode(node)) - instanceList.append(instance); + Utils::optional oldNodeInstanceHash = m_nodeInstanceCache.take(model()); + if (oldNodeInstanceHash + && oldNodeInstanceHash->instances.value(rootModelNode()).isValid()) { + 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); @@ -1942,4 +1951,32 @@ void NodeInstanceView::maybeResetOnPropertyChange(const PropertyName &name, cons 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 |