From 70c4acae67c1f65a8e1ea2111cffd067991f1c03 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 22 Sep 2022 15:04:04 +0300 Subject: [PATCH] QmlDesigner: Avoid duplicate bundle material instance creation When apply a material from the material bundle directly to a model in the 3D scene, check frist if there is an existing material that has no properties set, if so apply it instead of creating a new instance. Also few tweaks. Change-Id: I4ddadfd84442164b671645af5e4f5d9e8dcb7cb0 Reviewed-by: Miikka Heikkinen --- .../materialbrowser/bundlematerial.cpp | 8 +- .../materialbrowser/bundlematerial.h | 5 + .../materialbrowserbundlemodel.cpp | 20 ++- .../materialbrowser/materialbrowserview.cpp | 160 ++++++++++++------ .../materialbrowser/materialbrowserview.h | 5 +- 5 files changed, 136 insertions(+), 62 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp index 75549945f41..b5bc19e785c 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp @@ -30,9 +30,10 @@ namespace QmlDesigner { BundleMaterial::BundleMaterial(QObject *parent, const QString &name, const QString &qml, + const TypeName &type, const QUrl &icon, const QStringList &files) - : QObject(parent), m_name(name), m_qml(qml), m_icon(icon), m_files(files) {} + : QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files) {} bool BundleMaterial::filter(const QString &searchText) { @@ -54,6 +55,11 @@ QString BundleMaterial::qml() const return m_qml; } +TypeName BundleMaterial::type() const +{ + return m_type; +} + QStringList BundleMaterial::files() const { return m_files; diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h index 04f4ae26568..ae74a13d75c 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h +++ b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h @@ -25,6 +25,8 @@ #pragma once +#include "qmldesignercorelib_global.h" + #include #include #include @@ -43,6 +45,7 @@ public: BundleMaterial(QObject *parent, const QString &name, const QString &qml, + const TypeName &type, const QUrl &icon, const QStringList &files); @@ -50,6 +53,7 @@ public: QUrl icon() const; QString qml() const; + TypeName type() const; QStringList files() const; bool visible() const; @@ -59,6 +63,7 @@ signals: private: QString m_name; QString m_qml; + TypeName m_type; QUrl m_icon; QStringList m_files; diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp index 452093aba08..4e70008f1ab 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp @@ -28,6 +28,7 @@ #include "bundleimporter.h" #include "bundlematerial.h" #include "bundlematerialcategory.h" +#include "qmldesignerconstants.h" #include "utils/qtcassert.h" #include @@ -121,6 +122,8 @@ void MaterialBrowserBundleModel::loadMaterialBundle() m_matBundleExists = true; + const QString bundleId = m_matBundleObj.value("id").toString(); + const QJsonObject catsObj = m_matBundleObj.value("categories").toObject(); const QStringList categories = catsObj.keys(); for (const QString &cat : categories) { @@ -136,8 +139,14 @@ void MaterialBrowserBundleModel::loadMaterialBundle() for (const auto /*QJson{Const,}ValueRef*/ &asset : assetsArr) files.append(asset.toString()); - auto bundleMat = new BundleMaterial(category, mat, matObj.value("qml").toString(), - QUrl::fromLocalFile(matBundleDir.filePath(matObj.value("icon").toString())), files); + QUrl icon = QUrl::fromLocalFile(matBundleDir.filePath(matObj.value("icon").toString())); + QString qml = matObj.value("qml").toString(); + TypeName type = QLatin1String("%1.%2.%3").arg( + QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), + bundleId, + qml.chopped(4)).toLatin1(); // chopped(4): remove .qml + + auto bundleMat = new BundleMaterial(category, mat, qml, type, icon, files); category->addBundleMaterial(bundleMat); } @@ -149,7 +158,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle() for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr) sharedFiles.append(file.toString()); - m_importer = new Internal::BundleImporter(matBundleDir.path(), "MaterialBundle", sharedFiles); + m_importer = new Internal::BundleImporter(matBundleDir.path(), bundleId, sharedFiles); connect(m_importer, &Internal::BundleImporter::importFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) { if (metaInfo.isValid()) emit addBundleMaterialToProjectRequested(metaInfo); @@ -223,7 +232,10 @@ void MaterialBrowserBundleModel::applyToSelected(BundleMaterial *mat, bool add) void MaterialBrowserBundleModel::addMaterial(BundleMaterial *mat) { - m_importer->importComponent(mat->qml(), mat->files()); + QString err = m_importer->importComponent(mat->qml(), mat->files()); + + if (!err.isEmpty()) + qWarning() << __FUNCTION__ << err; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 7a4da256e53..db460eabbb4 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -129,70 +129,23 @@ WidgetInfo MaterialBrowserView::widgetInfo() MaterialBrowserBundleModel *matBrowserBundleModel = m_widget->materialBrowserBundleModel().data(); connect(matBrowserBundleModel, &MaterialBrowserBundleModel::applyToSelectedTriggered, this, - [&] (BundleMaterial *material, bool add) { + [&] (BundleMaterial *bundleMat, bool add) { if (!m_selectedModel.isValid()) return; m_bundleMaterialDropTarget = m_selectedModel; m_bundleMaterialAddToSelected = add; - m_widget->materialBrowserBundleModel()->addMaterial(material); + + ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type()); + if (defaultMat.isValid()) + applyBundleMaterialToDropTarget(defaultMat); + else + m_widget->materialBrowserBundleModel()->addMaterial(bundleMat); }); connect(matBrowserBundleModel, &MaterialBrowserBundleModel::addBundleMaterialToProjectRequested, this, [&] (const QmlDesigner::NodeMetaInfo &metaInfo) { - ModelNode matLib = materialLibraryNode(); - if (!matLib.isValid()) - return; - - executeInTransaction("MaterialBrowserView::widgetInfo", [&] { - ModelNode newMatNode = createModelNode(metaInfo.typeName(), metaInfo.majorVersion(), - metaInfo.minorVersion()); - matLib.defaultNodeListProperty().reparentHere(newMatNode); - - static QRegularExpression rgx("([A-Z])([a-z]*)"); - QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed(); - QString newId = model()->generateIdFromName(newName, "material"); - newMatNode.setIdWithRefactoring(newId); - - VariantProperty objNameProp = newMatNode.variantProperty("objectName"); - objNameProp.setValue(newName); - - if (m_bundleMaterialDropTarget.isValid()) { - QmlObjectNode qmlObjNode(m_bundleMaterialDropTarget); - if (m_bundleMaterialAddToSelected) { - // TODO: unify this logic as it exist elsewhere also - auto expToList = [](const QString &exp) { - QString copy = exp; - copy = copy.remove("[").remove("]"); - - QStringList tmp = copy.split(',', Qt::SkipEmptyParts); - for (QString &str : tmp) - str = str.trimmed(); - - return tmp; - }; - - auto listToExp = [](QStringList &stringList) { - if (stringList.size() > 1) - return QString("[" + stringList.join(",") + "]"); - - if (stringList.size() == 1) - return stringList.first(); - - return QString(); - }; - QStringList matList = expToList(qmlObjNode.expression("materials")); - matList.append(newMatNode.id()); - QString updatedExp = listToExp(matList); - qmlObjNode.setBindingProperty("materials", updatedExp); - } else { - qmlObjNode.setBindingProperty("materials", newMatNode.id()); - } - m_bundleMaterialDropTarget = {}; - } - - m_bundleMaterialAddToSelected = false; - }); + applyBundleMaterialToDropTarget({}, metaInfo); }); } @@ -203,6 +156,72 @@ WidgetInfo MaterialBrowserView::widgetInfo() tr("Material Browser")); } +void MaterialBrowserView::applyBundleMaterialToDropTarget(const ModelNode &bundleMat, + const NodeMetaInfo &metaInfo) +{ + if (!bundleMat.isValid() && !metaInfo.isValid()) + return; + + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return; + + executeInTransaction("MaterialBrowserView::applyBundleMaterialToDropTarget", [&] { + ModelNode newMatNode; + if (metaInfo.isValid()) { + newMatNode = createModelNode(metaInfo.typeName(), metaInfo.majorVersion(), + metaInfo.minorVersion()); + matLib.defaultNodeListProperty().reparentHere(newMatNode); + + static QRegularExpression rgx("([A-Z])([a-z]*)"); + QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed(); + QString newId = model()->generateIdFromName(newName, "material"); + newMatNode.setIdWithRefactoring(newId); + + VariantProperty objNameProp = newMatNode.variantProperty("objectName"); + objNameProp.setValue(newName); + } else { + newMatNode = bundleMat; + } + + if (m_bundleMaterialDropTarget.isValid()) { + QmlObjectNode qmlObjNode(m_bundleMaterialDropTarget); + if (m_bundleMaterialAddToSelected) { + // TODO: unify this logic as it exist elsewhere also + auto expToList = [](const QString &exp) { + QString copy = exp; + copy = copy.remove("[").remove("]"); + + QStringList tmp = copy.split(',', Qt::SkipEmptyParts); + for (QString &str : tmp) + str = str.trimmed(); + + return tmp; + }; + + auto listToExp = [](QStringList &stringList) { + if (stringList.size() > 1) + return QString("[" + stringList.join(",") + "]"); + + if (stringList.size() == 1) + return stringList.first(); + + return QString(); + }; + QStringList matList = expToList(qmlObjNode.expression("materials")); + matList.append(newMatNode.id()); + QString updatedExp = listToExp(matList); + qmlObjNode.setBindingProperty("materials", updatedExp); + } else { + qmlObjNode.setBindingProperty("materials", newMatNode.id()); + } + + m_bundleMaterialDropTarget = {}; + m_bundleMaterialAddToSelected = false; + } + }); +} + void MaterialBrowserView::modelAttached(Model *model) { AbstractView::modelAttached(model); @@ -382,6 +401,28 @@ void QmlDesigner::MaterialBrowserView::loadPropertyGroups() m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath); } +ModelNode MaterialBrowserView::getBundleMaterialDefaultInstance(const TypeName &type) +{ + const QList materials = m_widget->materialBrowserModel()->materials(); + for (const ModelNode &mat : materials) { + if (mat.type() == type) { + bool isDefault = true; + const QList props = mat.properties(); + for (const AbstractProperty &prop : props) { + if (prop.name() != "objectName") { + isDefault = false; + break; + } + } + + if (isDefault) + return mat; + } + } + + return {}; +} + void MaterialBrowserView::importsChanged(const QList &addedImports, const QList &removedImports) { Q_UNUSED(addedImports) @@ -420,7 +461,14 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt m_widget->materialBrowserModel()->deleteSelectedMaterial(); } else if (identifier == "drop_bundle_material") { m_bundleMaterialDropTarget = nodeList.first(); - m_widget->materialBrowserBundleModel()->addMaterial(m_draggedBundleMaterial); + + + ModelNode defaultMat = getBundleMaterialDefaultInstance(m_draggedBundleMaterial->type()); + if (defaultMat.isValid()) + applyBundleMaterialToDropTarget(defaultMat); + else + m_widget->materialBrowserBundleModel()->addMaterial(m_draggedBundleMaterial); + m_draggedBundleMaterial = nullptr; } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index 09f2c99033c..d1a4c85db6d 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -25,7 +25,8 @@ #pragma once -#include +#include "abstractview.h" +#include "nodemetainfo.h" #include @@ -67,6 +68,8 @@ private: void refreshModel(bool updateImages); bool isMaterial(const ModelNode &node) const; void loadPropertyGroups(); + void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {}); + ModelNode getBundleMaterialDefaultInstance(const TypeName &type); QPointer m_widget; ModelNode m_bundleMaterialDropTarget;