aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner/components/componentcore
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2020-09-10 16:02:31 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2020-09-16 07:00:06 +0000
commit90d9cb36f3ae756fe08ddfbf74756ada62df6918 (patch)
tree9b277ed53e957412923756eadb3c7530a44b23f9 /src/plugins/qmldesigner/components/componentcore
parentf849bd110552571f985ae691677d7c44b8affd82 (diff)
QmlDesigner: Add navigator preview tooltip for materials
Request 3D preview image for material instances from puppet to show on tooltip. Support for effect previews is also done, but handler for it is not registered, as effects cannot be shared between windows due to issue QTBUG-86616. Also refactored the preview image support out of navigator to make it more accessible by other components. Change-Id: Ie08ba218f929660c2e43d39578997a5a1a883efd Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Diffstat (limited to 'src/plugins/qmldesigner/components/componentcore')
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp66
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.h31
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp107
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h7
4 files changed, 210 insertions, 1 deletions
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index d9cc152181..89151b7ea6 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -194,6 +194,54 @@ void DesignerActionManager::registerAddResourceHandler(const AddResourceHandler
m_addResourceHandler.append(handler);
}
+QHash<TypeName, ModelNodePreviewImageHandler> DesignerActionManager::modelNodePreviewHandlers() const
+{
+ return m_modelNodePreviewImageHandlers;
+}
+
+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
+ for (const auto &handler : qAsConst(m_modelNodePreviewImageHandlers)) {
+ if (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;
+ }
+ if (!op)
+ m_noModelNodePreviewImageHandlers.insert(node.type());
+ }
+ return op;
+}
+
class VisiblityModelNodeAction : public ModelNodeContextMenuAction
{
public:
@@ -1309,6 +1357,24 @@ void DesignerActionManager::createDefaultAddResourceHandler()
ModelNodeOperations::addFontToProject));
}
+void DesignerActionManager::createDefaultModelNodePreviewImageHandlers()
+{
+ registerModelNodePreviewHandler(
+ ModelNodePreviewImageHandler("QtQuick.Image",
+ ModelNodeOperations::previewImageDataForImageNode));
+ registerModelNodePreviewHandler(
+ ModelNodePreviewImageHandler("QtQuick3D.Texture",
+ ModelNodeOperations::previewImageDataForImageNode));
+ registerModelNodePreviewHandler(
+ ModelNodePreviewImageHandler("QtQuick3D.Material",
+ ModelNodeOperations::previewImageDataFor3DNode));
+
+ // TODO - Disabled until QTBUG-86616 is fixed
+// registerModelNodePreviewHandler(
+// ModelNodePreviewImageHandler("QtQuick3D.Effect",
+// ModelNodeOperations::previewImageDataFor3DNode));
+}
+
void DesignerActionManager::addDesignerAction(ActionInterface *newAction)
{
m_designerActions.append(QSharedPointer<ActionInterface>(newAction));
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
index dd61140d19..13d964c866 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
@@ -27,11 +27,13 @@
#include <qmldesignercorelib_global.h>
#include "actioninterface.h"
+#include "modelnode.h"
#include <coreplugin/actionmanager/command.h>
#include <utils/styledbar.h>
#include <QToolBar>
+#include <QImage>
QT_BEGIN_NAMESPACE
class QGraphicsItem;
@@ -42,7 +44,8 @@ namespace QmlDesigner {
class DesignerActionManagerView;
-using AddResourceOperation = std::function<bool (const QStringList&, const QString&)>;
+using AddResourceOperation = std::function<bool (const QStringList &, const QString &)>;
+using ModelNodePreviewImageOperation = std::function<QVariant (const ModelNode &)>;
struct AddResourceHandler
{
@@ -64,6 +67,23 @@ public:
int piority;
};
+struct ModelNodePreviewImageHandler
+{
+public:
+ ModelNodePreviewImageHandler(const TypeName &t,
+ ModelNodePreviewImageOperation op,
+ int prio = 0)
+ : type(t)
+ , operation(op)
+ , priority(prio)
+ {
+ }
+
+ TypeName type;
+ ModelNodePreviewImageOperation operation = nullptr;
+ int priority = 0;
+};
+
class DesignerActionToolBar : public Utils::StyledBar
{
public:
@@ -87,6 +107,8 @@ public:
void createDefaultDesignerActions();
void createDefaultAddResourceHandler();
+ void createDefaultModelNodePreviewImageHandlers();
+
DesignerActionManagerView *view();
DesignerActionToolBar *createToolBar(QWidget *parent = nullptr) const;
@@ -102,6 +124,11 @@ public:
QList<AddResourceHandler> addResourceHandler() const;
void registerAddResourceHandler(const AddResourceHandler &handler);
+ QHash<TypeName, ModelNodePreviewImageHandler> modelNodePreviewHandlers() const;
+ void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler);
+ bool hasModelNodePreviewHandler(const ModelNode &node) const;
+ ModelNodePreviewImageOperation modelNodePreviewOperation(const ModelNode &node) const;
+
private:
void addTransitionEffectAction(const TypeName &typeName);
void addCustomTransitionEffectAction();
@@ -109,6 +136,8 @@ private:
QList<QSharedPointer<ActionInterface> > m_designerActions;
DesignerActionManagerView *m_designerActionManagerView;
QList<AddResourceHandler> m_addResourceHandler;
+ QMultiHash<TypeName, ModelNodePreviewImageHandler> m_modelNodePreviewImageHandlers;
+ mutable QSet<TypeName> m_noModelNodePreviewImageHandlers;
};
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 7453807a83..129917dba1 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -46,6 +46,8 @@
#include <nodelistproperty.h>
#include <nodeproperty.h>
#include <signalhandlerproperty.h>
+#include <qmldesignerconstants.h>
+#include <nodeinstanceview.h>
#include <componentcore_constants.h>
#include <stylesheetmerger.h>
@@ -78,6 +80,7 @@
#include <QFileDialog>
#include <QPushButton>
#include <QGridLayout>
+#include <QImage>
#include <algorithm>
#include <functional>
@@ -1518,6 +1521,110 @@ void removeGroup(const SelectionContext &selectionContext)
});
}
+struct ImageData {
+ QDateTime time;
+ QImage image;
+ QString type;
+ QString id;
+ QString info;
+};
+static QHash<QString, QHash<QString, ImageData>> imageDataMap;
+
+static QVariant imageDataToVariant(const ImageData &imageData)
+{
+ if (!imageData.image.isNull()) {
+ QVariantMap map;
+ map.insert("type", imageData.type);
+ map.insert("image", QVariant::fromValue<QImage>(imageData.image));
+ map.insert("id", imageData.id);
+ map.insert("info", imageData.info);
+ return map;
+ }
+ return {};
+}
+
+QVariant previewImageDataForImageNode(const ModelNode &modelNode)
+{
+ // Images on file system can be cached globally as they are found by absolute paths
+ QHash<QString, ImageData> &localDataMap = imageDataMap[{}];
+
+ VariantProperty prop = modelNode.variantProperty("source");
+ QString imageSource = prop.value().toString();
+ QFileInfo imageFi(imageSource);
+ if (imageFi.isRelative())
+ imageSource = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo().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 previewImageDataFor3DNode(const ModelNode &modelNode)
+{
+ QFileInfo docFi = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo();
+ QHash<QString, ImageData> &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);
+ }
+ modelNode.model()->nodeInstanceView()->requestModelNodePreviewImage(modelNode);
+
+ return imageDataToVariant(imageData);
+}
+
+void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image)
+{
+ QFileInfo docFi = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo();
+ QString docPath = docFi.absoluteFilePath();
+ if (imageDataMap.contains(docPath)) {
+ QHash<QString, ImageData> &localDataMap = imageDataMap[docPath];
+ if (localDataMap.contains(modelNode.id()))
+ localDataMap[modelNode.id()].image = image;
+ }
+}
+
} // namespace ModelNodeOperations
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
index 96dedf352a..e23e29d75a 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
@@ -27,6 +27,8 @@
#include "selectioncontext.h"
+QT_FORWARD_DECLARE_CLASS(QImage)
+
namespace QmlDesigner {
namespace ModelNodeOperations {
@@ -84,5 +86,10 @@ void selectFlowEffect(const SelectionContext &selectionContext);
void mergeWithTemplate(const SelectionContext &selectionContext);
void removeGroup(const SelectionContext &selectionContext);
+// ModelNodePreviewImageOperations
+QVariant previewImageDataFor3DNode(const ModelNode &modelNode);
+QVariant previewImageDataForImageNode(const ModelNode &modelNode);
+void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image);
+
} // namespace ModelNodeOperationso
} //QmlDesigner