summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2022-06-07 13:39:25 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2022-06-07 14:14:56 +0000
commit7269aafbd8a1fddb7d43f783ac20b4d97bbc20c5 (patch)
treeef602b89fc234e12fa5942151d98ec99345180e8
parentd2cc440c688540f85b7bd925625397511230f307 (diff)
downloadqt-creator-7269aafbd8a1fddb7d43f783ac20b4d97bbc20c5.tar.gz
QmlDesigner: Ensure material library is created when needed
Added material library accessor to AbstractView, which creates the material library and moves existing materials under it in case it doesn't yet exist. Also added material assignment function to AbstractView. The reason these were added to AbstractView instead of being handled e.g. via custom notification in material editor is that they need to be called from multiple different views in the same transaction that triggers the need of material library. Fixes: QDS-7081 Change-Id: If2bb884f87d04c9f3599c2342df66ef51ec238ee Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp43
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp15
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.h1
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp49
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp83
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractview.h3
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp92
9 files changed, 144 insertions, 145 deletions
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
index efb9e24c1c..02d798c1f6 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
@@ -186,42 +186,17 @@ void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e)
void Edit3DCanvas::dropEvent(QDropEvent *e)
{
- auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode();
- QTC_ASSERT(modelNode.isValid(), return);
-
- e->accept();
- m_parent->view()->setSelectedModelNode(modelNode);
-
- // if added node is a Model, assign it a material
- if (modelNode.isSubclassOf("QtQuick3D.Model")) {
- ModelNode matLib = m_parent->view()->modelNodeForId(Constants::MATERIAL_LIB_ID);
- QTC_ASSERT(matLib.isValid(), return);
-
- const QList<ModelNode> materials = matLib.directSubModelNodes();
- ModelNode material;
- if (materials.size() > 0) {
- for (const ModelNode &mat : materials) {
- if (mat.isSubclassOf("QtQuick3D.Material")) {
- material = mat;
- break;
- }
- }
- }
+ m_parent->view()->executeInTransaction(__FUNCTION__, [&] {
+ auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode();
+ QTC_ASSERT(modelNode.isValid(), return);
- // if no valid material, create a new default material
- if (!material.isValid()) {
- NodeMetaInfo metaInfo = m_parent->view()->model()->metaInfo("QtQuick3D.DefaultMaterial");
- material = m_parent->view()->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(),
- metaInfo.minorVersion());
- VariantProperty matNameProp = material.variantProperty("objectName");
- matNameProp.setValue("New Material");
- material.validId();
- matLib.defaultNodeListProperty().reparentHere(material);
- }
+ e->accept();
+ m_parent->view()->setSelectedModelNode(modelNode);
- BindingProperty modelMatsProp = modelNode.bindingProperty("materials");
- modelMatsProp.setExpression(material.id());
- }
+ // if added node is a Model, assign it a material
+ if (modelNode.isSubclassOf("QtQuick3D.Model"))
+ m_parent->view()->assignMaterialTo3dModel(modelNode);
+ });
}
void Edit3DCanvas::focusOutEvent(QFocusEvent *focusEvent)
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
index c4a64adf8f..819bf58b34 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
@@ -33,6 +33,8 @@
#include <rewritingexception.h>
#include "qmldesignerconstants.h"
+#include <utils/qtcassert.h>
+
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QLoggingCategory>
@@ -405,10 +407,23 @@ void DragTool::move(const QPointF &scenePosition, const QList<QGraphicsItem *> &
void DragTool::commitTransaction()
{
try {
+ handleView3dDrop();
m_rewriterTransaction.commit();
} catch (const RewritingException &e) {
e.showException();
}
}
+void DragTool::handleView3dDrop()
+{
+ // If a View3D is dropped, we need to assign material to the included model
+ for (const QmlItemNode &dragNode : qAsConst(m_dragNodes)) {
+ if (dragNode.modelNode().isSubclassOf("QtQuick3D.View3D")) {
+ const QList<ModelNode> models = dragNode.modelNode().subModelNodesOfType("QtQuick3D.Model");
+ QTC_ASSERT(models.size() == 1, return);
+ view()->assignMaterialTo3dModel(models.at(0));
+ }
+ }
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h
index 63d3de6e8f..bb6f562263 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.h
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h
@@ -90,6 +90,7 @@ protected:
void move(const QPointF &scenePos, const QList<QGraphicsItem *> &itemList);
void createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition, const QList<QGraphicsItem *> &itemList);
void commitTransaction();
+ void handleView3dDrop();
private:
MoveManipulator m_moveManipulator;
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index 29a74304d8..28c17d7561 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -78,47 +78,6 @@ MaterialEditorView::MaterialEditorView(QWidget *parent)
m_stackedWidget->setMinimumWidth(250);
}
-void MaterialEditorView::ensureMaterialLibraryNode()
-{
- if (!m_hasQuick3DImport)
- return;
-
- m_materialLibrary = modelNodeForId(Constants::MATERIAL_LIB_ID);
- if (m_materialLibrary.isValid())
- return;
-
- // create material library node
- TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" : "QtQuick.Item";
- NodeMetaInfo metaInfo = model()->metaInfo(nodeType);
- m_materialLibrary = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion());
-
- m_materialLibrary.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID);
- rootModelNode().defaultNodeListProperty().reparentHere(m_materialLibrary);
-
- const QList<ModelNode> materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material");
- if (materials.isEmpty())
- return;
-
- RewriterTransaction transaction = beginRewriterTransaction(
- "MaterialEditorView::ensureMaterialLibraryNode");
-
- try {
- // move all materials to under material library node
- for (const ModelNode &node : materials) {
- // if material has no name, set name to id
- QString matName = node.variantProperty("objectName").value().toString();
- if (matName.isEmpty()) {
- VariantProperty objNameProp = node.variantProperty("objectName");
- objNameProp.setValue(node.id());
- }
-
- m_materialLibrary.defaultNodeListProperty().reparentHere(node);
- }
- } catch (Exception &e) {
- e.showException();
- }
-}
-
MaterialEditorView::~MaterialEditorView()
{
qDeleteAll(m_qmlBackendHash);
@@ -447,15 +406,13 @@ void MaterialEditorView::handleToolBarAction(int action)
}
case MaterialEditorContextObject::AddNewMaterial: {
- ensureMaterialLibraryNode();
-
executeInTransaction("MaterialEditorView:handleToolBarAction", [&] {
NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial");
ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(),
metaInfo.minorVersion());
renameMaterial(newMatNode, "New Material");
- m_materialLibrary.defaultNodeListProperty().reparentHere(newMatNode);
+ materialLibraryNode().defaultNodeListProperty().reparentHere(newMatNode);
});
break;
}
@@ -759,8 +716,6 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
{
QTC_ASSERT(material.isValid(), return);
- ensureMaterialLibraryNode();
-
TypeName matType = material.type();
QmlObjectNode sourceMat(material);
@@ -786,7 +741,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
}
- m_materialLibrary.defaultNodeListProperty().reparentHere(duplicateMat);
+ materialLibraryNode().defaultNodeListProperty().reparentHere(duplicateMat);
});
}
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index 3e8632d26f..d9c9e4c1ba 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
@@ -99,7 +99,6 @@ private:
void highlightSupportedProperties(bool highlight = true);
QString generateIdFromName(const QString &name);
- void ensureMaterialLibraryNode();
void requestPreviewRender();
void applyMaterialToSelectedModels(const ModelNode &material, bool add = false);
@@ -115,7 +114,6 @@ private:
bool noValidSelection() const;
ModelNode m_selectedMaterial;
- ModelNode m_materialLibrary;
QShortcut *m_updateShortcut = nullptr;
int m_timerId = 0;
QStackedWidget *m_stackedWidget = nullptr;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index 0a92f81d93..d610014d5b 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -686,18 +686,31 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
bool validContainer = false;
ModelNode targetNode = targetProperty.parentModelNode();
- // don't allow dropping materials on any node but Models
- QString itemType = QString::fromLatin1(itemLibraryEntry.typeName());
- if (itemType.startsWith("QtQuick3D.") && itemType.endsWith("Material")
- && !targetNode.isSubclassOf("QtQuick3D.Model")) {
- return;
- }
-
QmlObjectNode newQmlObjectNode;
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryItemDrop", [&] {
newQmlObjectNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, QPointF(), targetProperty, false);
ModelNode newModelNode = newQmlObjectNode.modelNode();
if (newModelNode.isValid()) {
+ if (newModelNode.isSubclassOf("QtQuick3D.Material")) {
+ // Don't allow dropping materials on any node but Models
+ if (!targetNode.isSubclassOf("QtQuick3D.Model")) {
+ newQmlObjectNode.destroy();
+ return;
+ }
+ // We can't have material initially parented if material library is created in this
+ // same transaction (rewriter will not allow it for some reason)
+ ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID);
+ if (!matLib.isValid()) {
+ newQmlObjectNode.destroy();
+ newQmlObjectNode = QmlItemNode::createQmlObjectNode(
+ m_view, itemLibraryEntry, QPointF(), NodeAbstractProperty(), false);
+ newModelNode = newQmlObjectNode.modelNode();
+ if (!newModelNode.isValid())
+ return;
+ }
+ m_view->assignMaterialTo3dModel(targetNode, newModelNode);
+ }
+
ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded(
targetNode, newModelNode, Core::ICore::dialogParent());
if (dialog) {
@@ -734,28 +747,10 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
if (newModelNode.isSubclassOf("QtQuick3D.View3D")) {
const QList<ModelNode> models = newModelNode.subModelNodesOfType("QtQuick3D.Model");
-
QTC_ASSERT(models.size() == 1, return);
-
- assignMaterialToModel(models.at(0));
+ m_view->assignMaterialTo3dModel(models.at(0));
} else if (newModelNode.isSubclassOf("QtQuick3D.Model")) {
- assignMaterialToModel(newModelNode);
- }
-
- // dropping a material on a model
- if (newModelNode.isSubclassOf("QtQuick3D.Material")
- && targetNode.isSubclassOf("QtQuick3D.Model")) {
- // parent material to material library and assign it to target model
- ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID);
-
- QTC_ASSERT(matLib.isValid(), return);
-
- VariantProperty objName = newModelNode.variantProperty("objectName");
- objName.setValue("New Material");
- BindingProperty matsProp = targetNode.bindingProperty("materials");
- matsProp.setExpression(newModelNode.id());
- matLib.defaultNodeListProperty().reparentHere(newModelNode);
- return;
+ m_view->assignMaterialTo3dModel(newModelNode);
}
if (!validContainer) {
@@ -1089,40 +1084,6 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ
return {};
}
-// Add a material to a Quick3D.Model node
-void NavigatorTreeModel::assignMaterialToModel(const ModelNode &node)
-{
- ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID);
-
- QTC_ASSERT(matLib.isValid(), return);
- QTC_ASSERT(node.isSubclassOf("QtQuick3D.Model"), return);
-
- const QList<ModelNode> materials = matLib.directSubModelNodes();
- ModelNode material;
- if (materials.size() > 0) {
- for (const ModelNode &mat : materials) {
- if (mat.isSubclassOf("QtQuick3D.Material")) {
- material = mat;
- break;
- }
- }
- }
-
- // if no valid material, create a new default material
- if (!material.isValid()) {
- NodeMetaInfo metaInfo = m_view->model()->metaInfo("QtQuick3D.DefaultMaterial");
- material = m_view->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(),
- metaInfo.minorVersion());
- VariantProperty matNameProp = material.variantProperty("objectName");
- matNameProp.setValue("New Material");
- material.validId();
- matLib.defaultNodeListProperty().reparentHere(material);
- }
-
- BindingProperty modelMatsProp = node.bindingProperty("materials");
- modelMatsProp.setExpression(material.id());
-}
-
TypeName propertyType(const NodeAbstractProperty &property)
{
return property.parentModelNode().metaInfo().propertyTypeName(property.name());
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
index 0fcb7aab3e..9652981607 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
@@ -130,7 +130,6 @@ private:
bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp,
const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter);
ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath);
- void assignMaterialToModel(const ModelNode &node);
QList<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes);
void addImport(const QString &importName);
QList<ModelNode> filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const;
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index e37ed0fb4b..18380aadb1 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -259,6 +259,9 @@ public:
void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion);
+ ModelNode materialLibraryNode();
+ void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {});
+
NodeInstanceView *nodeInstanceView() const;
RewriterView *rewriterView() const;
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index 26040ba23d..86dab97031 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -31,6 +31,10 @@
#include "nodeinstanceview.h"
#include <qmlstate.h>
#include <qmltimeline.h>
+#include <qmldesignerconstants.h>
+#include <nodelistproperty.h>
+#include <variantproperty.h>
+#include <bindingproperty.h>
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
@@ -805,6 +809,94 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in
m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion);
}
+// Returns ModelNode for project's material library.
+// If the material library doesn't exist yet, it is created and all existing materials are moved
+// under material library.
+// This function should be called only form inside a transaction, as it potentially does many
+// changes to model.
+ModelNode AbstractView::materialLibraryNode()
+{
+ ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
+ if (matLib.isValid())
+ return matLib;
+
+ // Create material library node
+ TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node"
+ : "QtQuick.Item";
+ NodeMetaInfo metaInfo = model()->metaInfo(nodeType);
+ matLib = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion());
+
+ matLib.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID);
+ rootModelNode().defaultNodeListProperty().reparentHere(matLib);
+
+ const QList<ModelNode> materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material");
+ if (materials.isEmpty())
+ return matLib;
+
+ // Move all materials to under material library node
+ for (const ModelNode &node : materials) {
+ // If material has no name, set name to id
+ QString matName = node.variantProperty("objectName").value().toString();
+ if (matName.isEmpty()) {
+ VariantProperty objNameProp = node.variantProperty("objectName");
+ objNameProp.setValue(node.id());
+ }
+
+ matLib.defaultNodeListProperty().reparentHere(node);
+ }
+
+ return matLib;
+}
+
+// Assigns given material to a 3D model.
+// The assigned material is also inserted into material library if not already there.
+// If given material is not valid, first existing material from material library is used,
+// or if material library is empty, a new material is created.
+// This function should be called only from inside a transaction, as it potentially does many
+// changes to model.
+void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode)
+{
+ QTC_ASSERT(modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Model"), return);
+
+ ModelNode matLib = materialLibraryNode();
+ ModelNode newMaterialNode;
+
+ if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) {
+ newMaterialNode = materialNode;
+ } else {
+ const QList<ModelNode> materials = matLib.directSubModelNodes();
+ if (materials.size() > 0) {
+ for (const ModelNode &mat : materials) {
+ if (mat.isSubclassOf("QtQuick3D.Material")) {
+ newMaterialNode = mat;
+ break;
+ }
+ }
+ }
+
+ // if no valid material, create a new default material
+ if (!newMaterialNode.isValid()) {
+ NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial");
+ newMaterialNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(),
+ metaInfo.minorVersion());
+ newMaterialNode.validId();
+ }
+ }
+
+ QTC_ASSERT(newMaterialNode.isValid(), return);
+
+ VariantProperty matNameProp = newMaterialNode.variantProperty("objectName");
+ if (matNameProp.value().isNull())
+ matNameProp.setValue("New Material");
+
+ if (!newMaterialNode.hasParentProperty()
+ || newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) {
+ matLib.defaultNodeListProperty().reparentHere(newMaterialNode);
+ }
+ BindingProperty modelMatsProp = modelNode.bindingProperty("materials");
+ modelMatsProp.setExpression(newMaterialNode.id());
+}
+
ModelNode AbstractView::currentStateNode() const
{
if (model())