From 31ec38dba5efb731b0769a2d3e4d0232d9ba6e22 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 22 Sep 2020 11:30:05 +0300 Subject: [PATCH] QmlDesigner: Add navigator tooltip for 3D Components with Node root This enables showing preview tooltip for all imported 3D models. Also moved the preview image handling out of the model and into NodeInstanceView, where it fits more naturally. Change-Id: I48135d06aa8d9313525dae618e22692563da78fd Fixes: QDS-2807 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../requestmodelnodepreviewimagecommand.cpp | 13 +- .../requestmodelnodepreviewimagecommand.h | 4 +- .../mockfiles/ModelNode3DImageView.qml | 17 ++- .../qml/qmlpuppet/mockfiles/ModelNodeView.qml | 2 +- .../qml/qmlpuppet/mockfiles/NodeNodeView.qml | 96 ++++++++++++++ .../qt5informationnodeinstanceserver.cpp | 87 ++++++++----- .../qt5informationnodeinstanceserver.h | 4 +- share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc | 1 + .../componentcore/designeractionmanager.cpp | 33 ++--- .../componentcore/designeractionmanager.h | 4 +- .../componentcore/modelnodeoperations.cpp | 5 +- .../qmldesigner/designercore/include/model.h | 3 - .../designercore/include/nodeinstanceview.h | 5 + .../instances/nodeinstanceview.cpp | 117 ++++++++++++++++- .../qmldesigner/designercore/model/model.cpp | 118 ------------------ .../qmldesigner/designercore/model/model_p.h | 4 - 16 files changed, 324 insertions(+), 189 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/NodeNodeView.qml diff --git a/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.cpp index c29ec216c83..17f3a65a136 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.cpp @@ -32,9 +32,10 @@ namespace QmlDesigner { RequestModelNodePreviewImageCommand::RequestModelNodePreviewImageCommand() = default; -RequestModelNodePreviewImageCommand::RequestModelNodePreviewImageCommand(qint32 id, const QSize &size) +RequestModelNodePreviewImageCommand::RequestModelNodePreviewImageCommand(qint32 id, const QSize &size, const QString &componentPath) : m_instanceId(id) , m_size(size) + , m_componentPath(componentPath) { } @@ -48,10 +49,16 @@ QSize QmlDesigner::RequestModelNodePreviewImageCommand::size() const return m_size; } +QString RequestModelNodePreviewImageCommand::componentPath() const +{ + return m_componentPath; +} + QDataStream &operator<<(QDataStream &out, const RequestModelNodePreviewImageCommand &command) { out << int(command.instanceId()); out << command.size(); + out << command.componentPath(); return out; } @@ -60,6 +67,7 @@ QDataStream &operator>>(QDataStream &in, RequestModelNodePreviewImageCommand &co { in >> command.m_instanceId; in >> command.m_size; + in >> command.m_componentPath; return in; } @@ -67,7 +75,8 @@ QDebug operator <<(QDebug debug, const RequestModelNodePreviewImageCommand &comm { return debug.nospace() << "RequestModelNodePreviewImageCommand(" << "instanceId: " << command.instanceId() << ", " - << "size: " << command.size() << ")"; + << "size: " << command.size() << ", " + << "componentPath: " << command.componentPath() << ")"; } } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.h b/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.h index f18055695b9..14ebe6156ff 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/requestmodelnodepreviewimagecommand.h @@ -40,14 +40,16 @@ class RequestModelNodePreviewImageCommand public: RequestModelNodePreviewImageCommand(); - explicit RequestModelNodePreviewImageCommand(qint32 id, const QSize &size); + explicit RequestModelNodePreviewImageCommand(qint32 id, const QSize &size, const QString &componentPath); qint32 instanceId() const; QSize size() const; + QString componentPath() const; private: qint32 m_instanceId; QSize m_size; + QString m_componentPath; }; QDataStream &operator<<(QDataStream &out, const RequestModelNodePreviewImageCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml index 44580a0b302..277bc8431f9 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNode3DImageView.qml @@ -41,6 +41,7 @@ Item { property var materialViewComponent property var effectViewComponent property var modelViewComponent + property var nodeViewComponent property bool ready: false @@ -65,6 +66,8 @@ Item { createViewForEffect(obj); else if (obj instanceof Model) createViewForModel(obj); + else if (obj instanceof Node) + createViewForNode(obj); previewObject = obj; } @@ -99,10 +102,20 @@ Item { view = modelViewComponent.createObject(viewRect, {"sourceModel": model}); } + function createViewForNode(node) + { + if (!nodeViewComponent) + nodeViewComponent = Qt.createComponent("NodeNodeView.qml"); + + // Always recreate the view to ensure node is up to date + if (nodeViewComponent.status === Component.Ready) + view = nodeViewComponent.createObject(viewRect, {"importScene": node}); + } + function afterRender() { - if (previewObject instanceof Model) { - view.fitModel(); + if (previewObject instanceof Node) { + view.fitToViewPort(); ready = view.ready; } else { ready = true; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNodeView.qml index 1379a27a057..dc10f441e1c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ModelNodeView.qml @@ -36,7 +36,7 @@ View3D { property real prevZoomFactor: -1 property Model sourceModel - function fitModel() + function fitToViewPort() { cameraControl.focusObject(model, theCamera.eulerRotation, true, false); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/NodeNodeView.qml new file mode 100644 index 00000000000..b41c74af54e --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/NodeNodeView.qml @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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. +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick3D 1.15 + +View3D { + id: root + anchors.fill: parent + environment: sceneEnv + camera: theCamera + + property bool ready: false + property bool first: true + property real prevZoomFactor: -1 + + function fitToViewPort() + { + if (first) { + first = false; + selectionBox.targetNode = root.importScene; + } else { + cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false); + + if (cameraControl._zoomFactor < 0.1) { + root.importScene.scale = root.importScene.scale.times(10); + } else if (cameraControl._zoomFactor > 10) { + root.importScene.scale = root.importScene.scale.times(0.1); + } else { + // We need one more render after zoom factor change, so only set ready when zoom factor + // or scaling hasn't changed from the previous frame + ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); + prevZoomFactor = cameraControl._zoomFactor; + selectionBox.visible = false; + } + } + } + + SceneEnvironment { + id: sceneEnv + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } + + SelectionBox { + id: selectionBox + view3D: root + geometryName: "NodeNodeViewSB" + } + + EditCameraController { + id: cameraControl + camera: theCamera + anchors.fill: parent + view3d: root + ignoreToolState: true + } + + DirectionalLight { + eulerRotation.x: -30 + eulerRotation.y: -30 + } + + PerspectiveCamera { + id: theCamera + z: 600 + y: 600 + x: 600 + eulerRotation.x: -45 + eulerRotation.y: -45 + clipFar: 10000 + clipNear: 1 + } +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 05f86ae4d34..8b6fe9f5829 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -533,37 +533,60 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() if (!m_ModelNode3DImageViewContentItem) m_ModelNode3DImageViewContentItem = getContentItemForRendering(m_ModelNode3DImageViewRootItem); - ServerNodeInstance instance = instanceForId(m_modelNodelPreviewImageCommand.instanceId()); - QObject *instanceObj = instance.internalObject(); - QSize renderSize = m_modelNodelPreviewImageCommand.size() * 2; - QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "createViewForObject", - Q_ARG(QVariant, objectToVariant(instanceObj)), - Q_ARG(QVariant, QVariant::fromValue(renderSize.width())), - Q_ARG(QVariant, QVariant::fromValue(renderSize.height()))); - - QImage renderImage; - bool ready = false; - int count = 0; // Ensure we don't ever get stuck in an infinite loop - while (!ready && ++count < 10) { - updateNodesRecursive(m_ModelNode3DImageViewContentItem); - - // Fake render loop signaling to update things like QML items as 3D textures - m_ModelNode3DImageView->beforeSynchronizing(); - m_ModelNode3DImageView->beforeRendering(); - - QSizeF size = qobject_cast(m_ModelNode3DImageViewContentItem)->size(); - QRectF renderRect(QPointF(0., 0.), size); - renderImage = designerSupport()->renderImageForItem(m_ModelNode3DImageViewContentItem, - renderRect, size.toSize()); - m_ModelNode3DImageView->afterRendering(); - - QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "afterRender"); - ready = QQmlProperty::read(m_ModelNode3DImageViewRootItem, "ready").value(); - } - QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "destroyView"); - // Key number is selected so that it is unlikely to conflict other ImageContainer use. - auto imgContainer = ImageContainer(m_modelNodelPreviewImageCommand.instanceId(), renderImage, 2100000001); + auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001); + QImage renderImage; + if (m_modelNodePreviewImageCache.contains(m_modelNodePreviewImageCommand.componentPath())) { + renderImage = m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()]; + } else { + QObject *instanceObj = nullptr; + if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()) { + QQmlComponent *component = new QQmlComponent(engine()); + component->loadUrl(QUrl::fromLocalFile(m_modelNodePreviewImageCommand.componentPath())); + instanceObj = qobject_cast(component->create()); + if (!instanceObj) { + qWarning() << "Could not create preview component: " << component->errors(); + nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::RenderModelNodePreviewImage, + QVariant::fromValue(imgContainer)}); + return; + } + } else { + ServerNodeInstance instance = instanceForId(m_modelNodePreviewImageCommand.instanceId()); + instanceObj = instance.internalObject(); + } + QSize renderSize = m_modelNodePreviewImageCommand.size() * 2; + + QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "createViewForObject", + Q_ARG(QVariant, objectToVariant(instanceObj)), + Q_ARG(QVariant, QVariant::fromValue(renderSize.width())), + Q_ARG(QVariant, QVariant::fromValue(renderSize.height()))); + + bool ready = false; + int count = 0; // Ensure we don't ever get stuck in an infinite loop + while (!ready && ++count < 10) { + updateNodesRecursive(m_ModelNode3DImageViewContentItem); + + // Fake render loop signaling to update things like QML items as 3D textures + m_ModelNode3DImageView->beforeSynchronizing(); + m_ModelNode3DImageView->beforeRendering(); + + QSizeF size = qobject_cast(m_ModelNode3DImageViewContentItem)->size(); + QRectF renderRect(QPointF(0., 0.), size); + renderImage = designerSupport()->renderImageForItem(m_ModelNode3DImageViewContentItem, + renderRect, size.toSize()); + m_ModelNode3DImageView->afterRendering(); + + QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "afterRender"); + ready = QQmlProperty::read(m_ModelNode3DImageViewRootItem, "ready").value(); + } + QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "destroyView"); + if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()) { + // If component changes, puppet will need a reset anyway, so we can cache the image + m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), renderImage); + } + } + + imgContainer.setImage(renderImage); // send the rendered image to creator process nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::RenderModelNodePreviewImage, @@ -1319,9 +1342,9 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c void Qt5InformationNodeInstanceServer::requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command) { - m_modelNodelPreviewImageCommand = command; + m_modelNodePreviewImageCommand = command; - ServerNodeInstance instance = instanceForId(m_modelNodelPreviewImageCommand.instanceId()); + ServerNodeInstance instance = instanceForId(m_modelNodePreviewImageCommand.instanceId()); if (instance.isSubclassOf("QQuick3DObject")) renderModelNode3DImageView(); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index f85d974e0fa..fa073231ebc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -34,6 +34,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class QDragMoveEvent; @@ -126,7 +127,8 @@ private: QPointer m_ModelNode3DImageView; QQuickItem *m_ModelNode3DImageViewRootItem = nullptr; QQuickItem *m_ModelNode3DImageViewContentItem = nullptr; - RequestModelNodePreviewImageCommand m_modelNodelPreviewImageCommand; + RequestModelNodePreviewImageCommand m_modelNodePreviewImageCommand; + QHash m_modelNodePreviewImageCache; QSet m_view3Ds; QMultiHash m_3DSceneMap; // key: scene root, value: node QObject *m_active3DView = nullptr; diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index 9b01f0249db..adbf6f58e8e 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -44,6 +44,7 @@ mockfiles/MaterialNodeView.qml mockfiles/EffectNodeView.qml mockfiles/ModelNodeView.qml + mockfiles/NodeNodeView.qml mockfiles/meshes/arrow.mesh mockfiles/meshes/scalerod.mesh mockfiles/meshes/ring.mesh diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index b7a59274b23..55438be21db 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -207,42 +207,31 @@ QMultiHash DesignerActionManager::modelN void DesignerActionManager::registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler) { m_modelNodePreviewImageHandlers.insert(handler.type, handler); - - // Registering a new handler potentially invalidates no-handler set - m_noModelNodePreviewImageHandlers.clear(); } bool DesignerActionManager::hasModelNodePreviewHandler(const ModelNode &node) const { - if (m_modelNodePreviewImageHandlers.contains(node.type())) - return true; - - if (m_noModelNodePreviewImageHandlers.contains(node.type())) - return false; - - // Node may be a subclass of a registered type + const bool isComponent = node.isComponent(); for (const auto &handler : qAsConst(m_modelNodePreviewImageHandlers)) { - if (node.isSubclassOf(handler.type)) { + if ((isComponent || !handler.componentOnly) && node.isSubclassOf(handler.type)) { ModelNodePreviewImageHandler subClassHandler = handler; return true; } } - - m_noModelNodePreviewImageHandlers.insert(node.type()); return false; } ModelNodePreviewImageOperation DesignerActionManager::modelNodePreviewOperation(const ModelNode &node) const { ModelNodePreviewImageOperation op = nullptr; - if (!m_noModelNodePreviewImageHandlers.contains(node.type())) { - int prio = -1; - for (const auto &handler : qAsConst(m_modelNodePreviewImageHandlers)) { - if (node.isSubclassOf(handler.type) && handler.priority > prio) - op = handler.operation; + int prio = -1; + const bool isComponent = node.isComponent(); + for (const auto &handler : qAsConst(m_modelNodePreviewImageHandlers)) { + if ((isComponent || !handler.componentOnly) && handler.priority > prio + && node.isSubclassOf(handler.type)) { + op = handler.operation; + prio = handler.priority; } - if (!op) - m_noModelNodePreviewImageHandlers.insert(node.type()); } return op; } @@ -1415,6 +1404,10 @@ void DesignerActionManager::createDefaultModelNodePreviewImageHandlers() registerModelNodePreviewHandler( ModelNodePreviewImageHandler("QtQuick3D.Model", ModelNodeOperations::previewImageDataFor3DNode)); + registerModelNodePreviewHandler( + ModelNodePreviewImageHandler("QtQuick3D.Node", + ModelNodeOperations::previewImageDataFor3DNode, + true)); // TODO - Disabled until QTBUG-86616 is fixed // registerModelNodePreviewHandler( diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index b76d2faa6a5..7731b09e633 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -72,15 +72,18 @@ struct ModelNodePreviewImageHandler public: ModelNodePreviewImageHandler(const TypeName &t, ModelNodePreviewImageOperation op, + bool compOnly = false, int prio = 0) : type(t) , operation(op) + , componentOnly(compOnly) , priority(prio) { } TypeName type; ModelNodePreviewImageOperation operation = nullptr; + bool componentOnly = false; int priority = 0; }; @@ -137,7 +140,6 @@ private: DesignerActionManagerView *m_designerActionManagerView; QList m_addResourceHandler; QMultiHash m_modelNodePreviewImageHandlers; - mutable QSet m_noModelNodePreviewImageHandlers; }; } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index cf22a9bbcf1..04794c72f38 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1521,14 +1522,14 @@ void removeGroup(const SelectionContext &selectionContext) QVariant previewImageDataFor3DNode(const ModelNode &modelNode) { if (modelNode.isValid()) - return modelNode.model()->previewImageDataFor3DNode(modelNode); + return modelNode.model()->nodeInstanceView()->previewImageDataFor3DNode(modelNode); return {}; } QVariant previewImageDataForImageNode(const ModelNode &modelNode) { if (modelNode.isValid()) - return modelNode.model()->previewImageDataForImageNode(modelNode); + return modelNode.model()->nodeInstanceView()->previewImageDataForImageNode(modelNode); return {}; } diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index 5c6ac55d032..4d97eb8694e 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -118,9 +118,6 @@ public: QList selectedNodes(AbstractView *view) const; - QVariant previewImageDataFor3DNode(const ModelNode &modelNode); - QVariant previewImageDataForImageNode(const ModelNode &modelNode); - protected: Model(); diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 1372f47b3b7..fbb0a718f56 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -143,6 +143,9 @@ public: void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) override; + QVariant previewImageDataFor3DNode(const ModelNode &modelNode); + QVariant previewImageDataForImageNode(const ModelNode &modelNode); + protected: void timerEvent(QTimerEvent *event) override; @@ -201,6 +204,8 @@ private: // functions // puppet to creator command handlers void handlePuppetKeyPress(int key, Qt::KeyboardModifiers modifiers); + void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image); + private: NodeInstance m_rootNodeInstance; NodeInstance m_activeStateInstance; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index a7de6ae5de1..c55d6561c2b 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1495,7 +1495,7 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand auto node = modelNodeForInternalId(container.instanceId()); if (node.isValid()) { image.setDevicePixelRatio(2.); - emitModelNodelPreviewImageChanged(node, image); + updatePreviewImageForNode(node, image); } } } @@ -1527,11 +1527,15 @@ void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node) if (node.isValid()) { auto instance = instanceForModelNode(node); if (instance.isValid()) { + QString componentPath; + if (node.isComponent()) + componentPath = node.metaInfo().componentFileName(); m_nodeInstanceServer->requestModelNodePreviewImage( RequestModelNodePreviewImageCommand( instance.instanceId(), QSize(Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS, - Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS))); + Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS), + componentPath)); } } } @@ -1547,4 +1551,113 @@ void NodeInstanceView::timerEvent(QTimerEvent *event) restartProcess(); } +struct ImageData { + QDateTime time; + QImage image; + QString type; + QString id; + QString info; +}; +static QHash> imageDataMap; + +static QVariant imageDataToVariant(const ImageData &imageData) +{ + if (!imageData.image.isNull()) { + QVariantMap map; + map.insert("type", imageData.type); + map.insert("image", QVariant::fromValue(imageData.image)); + map.insert("id", imageData.id); + map.insert("info", imageData.info); + return map; + } + return {}; +} + +QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNode) +{ + if (!modelNode.isValid()) + return {}; + + // Images on file system can be cached globally as they are found by absolute paths + QHash &localDataMap = imageDataMap[{}]; + + VariantProperty prop = modelNode.variantProperty("source"); + QString imageSource = prop.value().toString(); + QFileInfo imageFi(imageSource); + if (imageFi.isRelative()) + imageSource = QFileInfo(modelNode.model()->fileUrl().toLocalFile()).dir().absoluteFilePath(imageSource); + + imageFi = QFileInfo(imageSource); + QDateTime modified = imageFi.lastModified(); + + ImageData imageData; + bool reload = true; + if (localDataMap.contains(imageSource)) { + imageData = localDataMap[imageSource]; + if (modified == imageData.time) + reload = false; + } + + if (reload) { + QImage originalImage; + originalImage.load(imageSource); + if (!originalImage.isNull()) { + imageData.image = originalImage.scaled(Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * 2, + Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * 2, + Qt::KeepAspectRatio); + imageData.image.setDevicePixelRatio(2.); + + double imgSize = double(imageFi.size()); + imageData.type = QStringLiteral("%1 (%2)").arg(QString::fromLatin1(modelNode.type())).arg(imageFi.suffix()); + imageData.id = modelNode.id(); + static QStringList units({QObject::tr("B"), QObject::tr("KB"), QObject::tr("MB"), QObject::tr("GB")}); + int unitIndex = 0; + while (imgSize > 1024. && unitIndex < units.size() - 1) { + ++unitIndex; + imgSize /= 1024.; + } + imageData.info = QStringLiteral("%1 x %2 (%3%4)").arg(originalImage.width()).arg(originalImage.height()) + .arg(QString::number(imgSize, 'g', 3)).arg(units[unitIndex]); + localDataMap.insert(imageSource, imageData); + } + } + + return imageDataToVariant(imageData); +} + +QVariant NodeInstanceView::previewImageDataFor3DNode(const ModelNode &modelNode) +{ + QFileInfo docFi = QFileInfo(modelNode.model()->fileUrl().toLocalFile()); + QHash &localDataMap = imageDataMap[docFi.absoluteFilePath()]; + ImageData imageData; + static const QImage placeHolder(":/navigator/icon/tooltip_placeholder.png"); + + // We need puppet to generate the image, which needs to be asynchronous. + // Until the image is ready, we show a placeholder + const QString id = modelNode.id(); + if (localDataMap.contains(id)) { + imageData = localDataMap[id]; + } else { + imageData.type = QString::fromLatin1(modelNode.type()); + imageData.id = id; + imageData.image = placeHolder; + localDataMap.insert(id, imageData); + } + requestModelNodePreviewImage(modelNode); + + return imageDataToVariant(imageData); +} + +void NodeInstanceView::updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image) +{ + QFileInfo docFi = QFileInfo(modelNode.model()->fileUrl().toLocalFile()); + QString docPath = docFi.absoluteFilePath(); + if (imageDataMap.contains(docPath)) { + QHash &localDataMap = imageDataMap[docPath]; + if (localDataMap.contains(modelNode.id())) + localDataMap[modelNode.id()].image = image; + } + emitModelNodelPreviewImageChanged(modelNode, image); +} + } diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index fc043da770b..e2ce604ba2b 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -26,7 +26,6 @@ #include "model.h" #include "model_p.h" #include -#include #include "internalnode_p.h" #include "invalidpropertyexception.h" #include "invalidargumentexception.h" @@ -286,111 +285,6 @@ void ModelPrivate::removeNodeFromModel(const InternalNodePointer &internalNodePo m_internalIdNodeHash.remove(internalNodePointer->internalId()); } -struct ImageData { - QDateTime time; - QImage image; - QString type; - QString id; - QString info; -}; -static QHash> imageDataMap; - -static QVariant imageDataToVariant(const ImageData &imageData) -{ - if (!imageData.image.isNull()) { - QVariantMap map; - map.insert("type", imageData.type); - map.insert("image", QVariant::fromValue(imageData.image)); - map.insert("id", imageData.id); - map.insert("info", imageData.info); - return map; - } - return {}; -} - -QVariant ModelPrivate::previewImageDataForImageNode(const ModelNode &modelNode) -{ - // Images on file system can be cached globally as they are found by absolute paths - QHash &localDataMap = imageDataMap[{}]; - - VariantProperty prop = modelNode.variantProperty("source"); - QString imageSource = prop.value().toString(); - QFileInfo imageFi(imageSource); - if (imageFi.isRelative()) - imageSource = QFileInfo(m_fileUrl.toLocalFile()).dir().absoluteFilePath(imageSource); - - imageFi = QFileInfo(imageSource); - QDateTime modified = imageFi.lastModified(); - - ImageData imageData; - bool reload = true; - if (localDataMap.contains(imageSource)) { - imageData = localDataMap[imageSource]; - if (modified == imageData.time) - reload = false; - } - - if (reload) { - QImage originalImage; - originalImage.load(imageSource); - if (!originalImage.isNull()) { - imageData.image = originalImage.scaled(Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * 2, - Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * 2, - Qt::KeepAspectRatio); - imageData.image.setDevicePixelRatio(2.); - - double imgSize = double(imageFi.size()); - imageData.type = QStringLiteral("%1 (%2)").arg(QString::fromLatin1(modelNode.type())).arg(imageFi.suffix()); - imageData.id = modelNode.id(); - static QStringList units({QObject::tr("B"), QObject::tr("KB"), QObject::tr("MB"), QObject::tr("GB")}); - int unitIndex = 0; - while (imgSize > 1024. && unitIndex < units.size() - 1) { - ++unitIndex; - imgSize /= 1024.; - } - imageData.info = QStringLiteral("%1 x %2 (%3%4)").arg(originalImage.width()).arg(originalImage.height()) - .arg(QString::number(imgSize, 'g', 3)).arg(units[unitIndex]); - localDataMap.insert(imageSource, imageData); - } - } - - return imageDataToVariant(imageData); -} - -QVariant ModelPrivate::previewImageDataFor3DNode(const ModelNode &modelNode) -{ - QFileInfo docFi = QFileInfo(m_fileUrl.toLocalFile()); - QHash &localDataMap = Internal::imageDataMap[docFi.absoluteFilePath()]; - Internal::ImageData imageData; - static const QImage placeHolder(":/navigator/icon/tooltip_placeholder.png"); - - // We need puppet to generate the image, which needs to be asynchronous. - // Until the image is ready, we show a placeholder - const QString id = modelNode.id(); - if (localDataMap.contains(id)) { - imageData = localDataMap[id]; - } else { - imageData.type = QString::fromLatin1(modelNode.type()); - imageData.id = id; - imageData.image = placeHolder; - localDataMap.insert(id, imageData); - } - modelNode.model()->nodeInstanceView()->requestModelNodePreviewImage(modelNode); - - return imageDataToVariant(imageData); -} - -void ModelPrivate::updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image) -{ - QFileInfo docFi = QFileInfo(m_fileUrl.toLocalFile()); - QString docPath = docFi.absoluteFilePath(); - if (imageDataMap.contains(docPath)) { - QHash &localDataMap = imageDataMap[docPath]; - if (localDataMap.contains(modelNode.id())) - localDataMap[modelNode.id()].image = image; - } -} - void ModelPrivate::removeAllSubNodes(const InternalNode::Pointer &internalNodePointer) { foreach (const InternalNodePointer &subNode, internalNodePointer->allSubNodes()) { @@ -808,8 +702,6 @@ void ModelPrivate::notifyUpdateActiveScene3D(const QVariantMap &sceneState) void ModelPrivate::notifyModelNodePreviewImageChanged(const ModelNode &node, const QImage &image) { - updatePreviewImageForNode(node, image); - for (const QPointer &view : qAsConst(m_viewList)) { Q_ASSERT(view != nullptr); view->modelNodePreviewImageChanged(node, image); @@ -2183,16 +2075,6 @@ QList Model::selectedNodes(AbstractView *view) const return d->toModelNodeList(d->selectedNodes(), view); } -QVariant Model::previewImageDataFor3DNode(const ModelNode &modelNode) -{ - return d->previewImageDataFor3DNode(modelNode); -} - -QVariant Model::previewImageDataForImageNode(const ModelNode &modelNode) -{ - return d->previewImageDataForImageNode(modelNode); -} - /*! \brief Returns the URL against which relative URLs within the model should be resolved. \return The base URL. diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index a406984d83a..2d6669aeb9e 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -243,10 +243,6 @@ private: //functions QVector toModelNodeVector(const QVector &internalNodeVector, AbstractView *view) const; QVector toInternalNodeVector(const QVector &internalNodeVector) const; - QVariant previewImageDataFor3DNode(const ModelNode &modelNode); - QVariant previewImageDataForImageNode(const ModelNode &modelNode); - void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image); - private: Model *m_q; MetaInfo m_metaInfo;