QmlDesigner: Implement "duplicate material" feature

Fixes: QDS-7013
Change-Id: I28a11dbd9d6586631c0edcf8003e551917eaac98
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Mahmoud Badri
2022-05-25 21:42:15 +03:00
parent e2f20ddcd5
commit 0b51afe21d
7 changed files with 81 additions and 46 deletions

View File

@@ -102,6 +102,12 @@ Item {
onTriggered: materialBrowserModel.applyToSelected(currentMaterial.materialInternalId, true) onTriggered: materialBrowserModel.applyToSelected(currentMaterial.materialInternalId, true)
} }
StudioControls.MenuItem {
text: qsTr("Duplicate")
enabled: currentMaterial
onTriggered: materialBrowserModel.duplicateMaterial(currentMaterialIdx)
}
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Rename") text: qsTr("Rename")
enabled: currentMaterial enabled: currentMaterial
@@ -116,7 +122,7 @@ Item {
text: qsTr("Delete") text: qsTr("Delete")
enabled: currentMaterial enabled: currentMaterial
onTriggered: materialBrowserModel.deleteMaterial(currentMaterial.materialInternalId) onTriggered: materialBrowserModel.deleteMaterial(currentMaterialIdx)
} }
StudioControls.MenuSeparator {} StudioControls.MenuSeparator {}

View File

@@ -246,11 +246,14 @@ void MaterialBrowserModel::selectMaterial(int idx, bool force)
} }
} }
void MaterialBrowserModel::deleteMaterial(qint32 internalId) void MaterialBrowserModel::duplicateMaterial(int idx)
{ {
int idx = m_materialIndexHash.value(internalId); emit duplicateMaterialTriggered(m_materialList.at(idx));
if (isValidIndex(idx)) }
m_materialList[idx].destroy();
void MaterialBrowserModel::deleteMaterial(int idx)
{
m_materialList[idx].destroy();
} }
void MaterialBrowserModel::renameMaterial(int idx, const QString &newName) void MaterialBrowserModel::renameMaterial(int idx, const QString &newName)

View File

@@ -68,6 +68,7 @@ public:
void resetModel(); void resetModel();
Q_INVOKABLE void selectMaterial(int idx, bool force = false); Q_INVOKABLE void selectMaterial(int idx, bool force = false);
Q_INVOKABLE void duplicateMaterial(int idx);
Q_INVOKABLE void deleteMaterial(int idx); Q_INVOKABLE void deleteMaterial(int idx);
Q_INVOKABLE void renameMaterial(int idx, const QString &newName); Q_INVOKABLE void renameMaterial(int idx, const QString &newName);
Q_INVOKABLE void addNewMaterial(); Q_INVOKABLE void addNewMaterial();
@@ -82,6 +83,7 @@ signals:
void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName); void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName);
void applyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false); void applyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false);
void addNewMaterialTriggered(); void addNewMaterialTriggered();
void duplicateMaterialTriggered(const QmlDesigner::ModelNode &material);
private: private:
bool isMaterialVisible(int idx) const; bool isMaterialVisible(int idx) const;

View File

@@ -54,16 +54,33 @@ WidgetInfo MaterialBrowserView::widgetInfo()
{ {
if (m_widget.isNull()) { if (m_widget.isNull()) {
m_widget = new MaterialBrowserWidget; m_widget = new MaterialBrowserWidget;
connect(m_widget->materialBrowserModel().data(), SIGNAL(selectedIndexChanged(int)), MaterialBrowserModel *matBrowserModel = m_widget->materialBrowserModel().data();
this, SLOT(handleSelectedMaterialChanged(int)));
connect(m_widget->materialBrowserModel().data(), // custom notifications below are sent to the MaterialEditor
SIGNAL(applyToSelectedTriggered(const QmlDesigner::ModelNode &, bool)),
this, SLOT(handleApplyToSelectedTriggered(const QmlDesigner::ModelNode &, bool))); connect(matBrowserModel, &MaterialBrowserModel::selectedIndexChanged, this, [&] (int idx) {
connect(m_widget->materialBrowserModel().data(), ModelNode matNode = m_widget->materialBrowserModel()->materialAt(idx);
SIGNAL(renameMaterialTriggered(const QmlDesigner::ModelNode &, const QString &)), emitCustomNotification("selected_material_changed", {matNode}, {});
this, SLOT(handleRenameMaterial(const QmlDesigner::ModelNode &, const QString &))); });
connect(m_widget->materialBrowserModel().data(), SIGNAL(addNewMaterialTriggered()),
this, SLOT(handleAddNewMaterial())); connect(matBrowserModel, &MaterialBrowserModel::applyToSelectedTriggered, this,
[&] (const ModelNode &material, bool add) {
emitCustomNotification("apply_to_selected_triggered", {material}, {add});
});
connect(matBrowserModel, &MaterialBrowserModel::renameMaterialTriggered, this,
[&] (const ModelNode &material, const QString &newName) {
emitCustomNotification("rename_material", {material}, {newName});
});
connect(matBrowserModel, &MaterialBrowserModel::addNewMaterialTriggered, this, [&] {
emitCustomNotification("add_new_material");
});
connect(matBrowserModel, &MaterialBrowserModel::duplicateMaterialTriggered, this,
[&] (const ModelNode &material) {
emitCustomNotification("duplicate_material", {material});
});
} }
return createWidgetInfo(m_widget.data(), return createWidgetInfo(m_widget.data(),
@@ -240,29 +257,4 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt
} }
} }
void MaterialBrowserView::handleSelectedMaterialChanged(int idx)
{
ModelNode matNode = m_widget->materialBrowserModel()->materialAt(idx);
// to MaterialEditor...
emitCustomNotification("selected_material_changed", {matNode}, {});
}
void MaterialBrowserView::handleApplyToSelectedTriggered(const ModelNode &material, bool add)
{
// to MaterialEditor...
emitCustomNotification("apply_to_selected_triggered", {material}, {add});
}
void MaterialBrowserView::handleRenameMaterial(const ModelNode &material, const QString &newName)
{
// to MaterialEditor...
emitCustomNotification("rename_material", {material}, {newName});
}
void MaterialBrowserView::handleAddNewMaterial()
{
// to MaterialEditor...
emitCustomNotification("add_new_material");
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -68,12 +68,6 @@ private:
QPointer<MaterialBrowserWidget> m_widget; QPointer<MaterialBrowserWidget> m_widget;
bool m_hasQuick3DImport = false; bool m_hasQuick3DImport = false;
bool m_autoSelectModelMaterial = false; // TODO: wire this to some action bool m_autoSelectModelMaterial = false; // TODO: wire this to some action
private slots:
void handleSelectedMaterialChanged(int idx);
void handleApplyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false);
void handleRenameMaterial(const QmlDesigner::ModelNode &material, const QString &newName);
void handleAddNewMaterial();
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -745,6 +745,41 @@ void MaterialEditorView::renameMaterial(ModelNode &material, const QString &newN
}); });
} }
void MaterialEditorView::duplicateMaterial(const ModelNode &material)
{
QTC_ASSERT(material.isValid(), return);
ensureMaterialLibraryNode();
TypeName matType = material.type();
QmlObjectNode sourceMat(material);
executeInTransaction(__FUNCTION__, [&] {
// create the duplicate material
NodeMetaInfo metaInfo = model()->metaInfo(matType);
QmlObjectNode duplicateMat = createModelNode(matType, metaInfo.majorVersion(), metaInfo.minorVersion());
// set name and id
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
duplicateMat.modelNode().variantProperty("objectName").setValue(newName);
duplicateMat.modelNode().setIdWithoutRefactoring(generateIdFromName(newName));
// sync properties
const QList<AbstractProperty> props = material.properties();
for (const AbstractProperty &prop : props) {
if (prop.name() == "objectName")
continue;
if (prop.isVariantProperty())
duplicateMat.setVariantProperty(prop.name(), prop.toVariantProperty().value());
else if (prop.isBindingProperty())
duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
}
m_materialLibrary.defaultNodeListProperty().reparentHere(duplicateMat);
});
}
void MaterialEditorView::customNotification(const AbstractView *view, const QString &identifier, void MaterialEditorView::customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{ {
@@ -758,6 +793,8 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr
renameMaterial(m_selectedMaterial, data.first().toString()); renameMaterial(m_selectedMaterial, data.first().toString());
} else if (identifier == "add_new_material") { } else if (identifier == "add_new_material") {
handleToolBarAction(MaterialEditorContextObject::AddNewMaterial); handleToolBarAction(MaterialEditorContextObject::AddNewMaterial);
} else if (identifier == "duplicate_material") {
duplicateMaterial(nodeList.first());
} }
} }

View File

@@ -106,6 +106,7 @@ private:
void commitAuxValueToModel(const PropertyName &propertyName, const QVariant &value); void commitAuxValueToModel(const PropertyName &propertyName, const QVariant &value);
void removePropertyFromModel(const PropertyName &propertyName); void removePropertyFromModel(const PropertyName &propertyName);
void renameMaterial(ModelNode &material, const QString &newName); void renameMaterial(ModelNode &material, const QString &newName);
void duplicateMaterial(const ModelNode &material);
bool noValidSelection() const; bool noValidSelection() const;