From 2eb396b83de6582a8f34fb387c37057006cc74f1 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 23 May 2024 11:33:45 +0300 Subject: [PATCH] QmlDesigner: Allow adding imported 3D components to content library Fixes: QDS-12784 Change-Id: I87edf8f6c14fabb066c85e8536c91b58e439e5d0 Reviewed-by: Marco Bubke Reviewed-by: Ali Kianian Reviewed-by: Miikka Heikkinen --- .../contentlibraryusermodel.cpp | 3 +- .../contentlibrary/contentlibraryview.cpp | 84 ++++++++++++++++--- .../contentlibrary/contentlibraryview.h | 1 + .../qmldesigner/designercore/uniquename.cpp | 3 + .../qmldesigner/designercore/uniquename.h | 3 +- .../tests/unittests/model/uniquename-test.cpp | 9 ++ 6 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp index cfe1fcde830..f0d7506e286 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp @@ -312,8 +312,7 @@ QPair ContentLibraryUserModel::getUniqueLibItemNames(const QSt itemIcons.append(QFileInfo(obj.value("icon").toString()).baseName()); } - QString baseQml = defaultName.trimmed(); - baseQml.remove(' '); + QString baseQml = UniqueName::generateId(defaultName); baseQml[0] = baseQml.at(0).toUpper(); baseQml.prepend("My"); diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index 0dbc3a4da71..b9f8d175863 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -23,8 +23,9 @@ #include #include #include -#include +#include #include +#include #include @@ -367,7 +368,10 @@ void ContentLibraryView::customNotification(const AbstractView *view, } else if (identifier == "add_assets_to_content_lib") { addLibAssets(data.first().toStringList()); } else if (identifier == "add_3d_to_content_lib") { - addLib3DItem(nodeList.first()); + if (nodeList.first().isComponent()) + addLib3DComponent(nodeList.first()); + else + addLib3DItem(nodeList.first()); } } @@ -663,6 +667,67 @@ void ContentLibraryView::addLibAssets(const QStringList &paths) m_widget->userModel()->addTextures(pathsInBundle); } +void ContentLibraryView::addLib3DComponent(const ModelNode &node) +{ + auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); + + // TODO: check component with existing name and show a confirmation dialog + QString compBaseName = node.simplifiedTypeName(); + QString compFileName = compBaseName + ".qml"; + + Utils::FilePath compDir = DocumentManager::currentProjectDirPath() + .pathAppended(compUtils.import3dTypePath() + '/' + compBaseName); + + auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/"); + + // generate and save icon + UniqueName::generateId(compBaseName); + QString iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png"); + QString fullIconPath = bundlePath.pathAppended(iconPath).toString(); + genAndSaveIcon(compDir.pathAppended(compFileName).path(), fullIconPath); + + const Utils::FilePaths sourceFiles = compDir.dirEntries({{}, QDir::Files, QDirIterator::Subdirectories}); + const QStringList ignoreList {"_importdata.json", "qmldir", compBaseName + ".hints"}; + QStringList filesList; // 3D component's assets (dependencies) + + for (const Utils::FilePath &sourcePath : sourceFiles) { + Utils::FilePath relativePath = sourcePath.relativePathFrom(compDir); + if (ignoreList.contains(sourcePath.fileName()) || relativePath.startsWith("source scene")) + continue; + + Utils::FilePath targetPath = bundlePath.pathAppended(relativePath.path()); + targetPath.parentDir().ensureWritableDir(); + + // copy item from project to user bundle + auto result = sourcePath.copyFile(targetPath); + if (!result) + qWarning() << __FUNCTION__ << result.error(); + + if (sourcePath.fileName() != compFileName) // skip component file (only collect dependencies) + filesList.append(relativePath.path()); + } + + // add the item to the bundle json + QJsonObject &jsonRef = m_widget->userModel()->bundleJson3DObjectRef(); + QJsonArray itemsArr = jsonRef.value("items").toArray(); + itemsArr.append(QJsonObject { + {"name", node.simplifiedTypeName()}, + {"qml", compFileName}, + {"icon", iconPath}, + {"files", QJsonArray::fromStringList(filesList)} + }); + + jsonRef["items"] = itemsArr; + + auto result = bundlePath.pathAppended("user_3d_bundle.json") + .writeFileContents(QJsonDocument(jsonRef).toJson()); + if (!result) + qWarning() << __FUNCTION__ << result.error(); + + m_widget->userModel()->add3DItem(compBaseName, compFileName, QUrl::fromLocalFile(fullIconPath), + filesList); +} + void ContentLibraryView::addLib3DItem(const ModelNode &node) { auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/"); @@ -682,16 +747,13 @@ void ContentLibraryView::addLib3DItem(const ModelNode &node) // add the item to the bundle json QJsonObject &jsonRef = m_widget->userModel()->bundleJson3DObjectRef(); QJsonArray itemsArr = jsonRef.value("items").toArray(); - QJsonObject itemObj; - itemObj.insert("name", name); - itemObj.insert("qml", qml); - itemObj.insert("icon", iconPath); - QJsonArray filesArr; - for (const QString &assetPath : depAssets) - filesArr.append(assetPath); - itemObj.insert("files", filesArr); + itemsArr.append(QJsonObject { + {"name", name}, + {"qml", qml}, + {"icon", iconPath}, + {"files", QJsonArray::fromStringList(depAssets)} + }); - itemsArr.append(itemObj); jsonRef["items"] = itemsArr; auto result = bundlePath.pathAppended("user_3d_bundle.json") diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h index 2041cc37a11..914a8b8ea00 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h @@ -57,6 +57,7 @@ private: void updateBundlesQuick3DVersion(); void addLibMaterial(const ModelNode &node, const QPixmap &iconPixmap); void addLibAssets(const QStringList &paths); + void addLib3DComponent(const ModelNode &node); void addLib3DItem(const ModelNode &node); void genAndSaveIcon(const QString &qmlPath, const QString &iconPath); QStringList writeLibItemQml(const ModelNode &node, const QString &qml); diff --git a/src/plugins/qmldesigner/designercore/uniquename.cpp b/src/plugins/qmldesigner/designercore/uniquename.cpp index 06121b326a1..d7506164dbe 100644 --- a/src/plugins/qmldesigner/designercore/uniquename.cpp +++ b/src/plugins/qmldesigner/designercore/uniquename.cpp @@ -156,6 +156,9 @@ QString generateId(const QString &id, std::function predi if (newId.at(0).isDigit() || std::binary_search(std::begin(keywords), std::end(keywords), newId)) newId.prepend('_'); + if (!predicate) + return newId; + return UniqueName::generate(newId, predicate); } diff --git a/src/plugins/qmldesigner/designercore/uniquename.h b/src/plugins/qmldesigner/designercore/uniquename.h index d264233ddd6..85927c45147 100644 --- a/src/plugins/qmldesigner/designercore/uniquename.h +++ b/src/plugins/qmldesigner/designercore/uniquename.h @@ -11,6 +11,7 @@ namespace QmlDesigner::UniqueName { QString generate(const QString &name, std::function predicate); QString generatePath(const QString &path); -QMLDESIGNERCORE_EXPORT QString generateId(const QString &id, std::function predicate); +QMLDESIGNERCORE_EXPORT QString generateId(const QString &id, + std::function predicate = {}); } // namespace QmlDesigner::UniqueName diff --git a/tests/unit/tests/unittests/model/uniquename-test.cpp b/tests/unit/tests/unittests/model/uniquename-test.cpp index a6fe4560903..ca32972b6df 100644 --- a/tests/unit/tests/unittests/model/uniquename-test.cpp +++ b/tests/unit/tests/unittests/model/uniquename-test.cpp @@ -21,6 +21,15 @@ TEST(UniqueName, generate_returns_same_input_if_predicate_returns_false) ASSERT_THAT(uniqueName, "abc"); } +TEST(UniqueName, generateId_returns_properly_formatted_id_when_predicate_is_not_provided) +{ + QString id = " A bc d _"; + + QString uniqueId = UniqueName::generateId(id); + + ASSERT_THAT(uniqueId, "aBcD_"); +} + TEST(UniqueName, generateId_returns_properly_formatted_id) { auto pred = [] (const QString &id) -> bool {