diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp index c04a6661656..86c9d53b41c 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp @@ -96,6 +96,11 @@ AssetExportDialog::AssetExportDialog(const Utils::FilePath &exportPath, m_exportAssetsCheck->setChecked(true); optionsLayout->addWidget(m_exportAssetsCheck); + m_perComponentExportCheck = new QCheckBox(tr("Export components separately"), this); + m_perComponentExportCheck->setChecked(false); + optionsLayout->addWidget(m_perComponentExportCheck); + optionsLayout->addStretch(); + m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false); m_ui->stackedWidget->addWidget(m_filesView); @@ -149,7 +154,8 @@ void AssetExportDialog::onExport() m_exportLogs->clear(); m_assetExporter.exportQml(m_filePathModel.files(), m_ui->exportPath->fileName(), - m_exportAssetsCheck->isChecked()); + m_exportAssetsCheck->isChecked(), + m_perComponentExportCheck->isChecked()); } void AssetExportDialog::onExportStateChanged(AssetExporter::ParsingState newState) diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.h b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.h index 197a91b5ab1..6d7f1ff4e5b 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.h @@ -74,6 +74,7 @@ private: std::unique_ptr m_ui; QPushButton *m_exportBtn = nullptr; QCheckBox *m_exportAssetsCheck = nullptr; + QCheckBox *m_perComponentExportCheck = nullptr; QListView *m_filesView = nullptr; QPlainTextEdit *m_exportLogs = nullptr; Utils::OutputFormatter *m_outputFormatter = nullptr; diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index bef733b27b7..856ff32390d 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -115,15 +115,20 @@ AssetExporter::~AssetExporter() } void AssetExporter::exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath, - bool exportAssets) + bool exportAssets, bool perComponentExport) { - ExportNotification::addInfo(tr("Exporting metadata at %1. Export assets: ") + m_perComponentExport = perComponentExport; + ExportNotification::addInfo(tr("Export root directory: %1.\nExporting assets: %2") .arg(exportPath.toUserOutput()) .arg(exportAssets? tr("Yes") : tr("No"))); + + if (m_perComponentExport) + ExportNotification::addInfo(tr("Each component is exported separately")); + notifyProgress(0.0); m_exportFiles = qmlFiles; m_totalFileCount = m_exportFiles.count(); - m_components = QJsonArray(); + m_components.clear(); m_exportPath = exportPath; m_currentState.change(ParsingState::Parsing); triggerLoadNextFile(); @@ -149,22 +154,26 @@ bool AssetExporter::isBusy() const m_currentState == AssetExporter::ParsingState::WritingJson; } -Utils::FilePath AssetExporter::exportAsset(const QmlObjectNode &node, const QString &uuid) +Utils::FilePath AssetExporter::exportAsset(const QmlObjectNode &node, const Component *component, + const QString &uuid) { if (m_cancelled) return {}; - Utils::FilePath assetPath = m_exportPath.pathAppended(QString("assets/%1.png").arg(uuid)); + const Utils::FilePath assetExportDir = m_perComponentExport ? componentExportDir(component) : + m_exportPath; + const QString fileName = uuid + ".png"; + const Utils::FilePath assetPath = assetExportDir.pathAppended("assets").pathAppended(fileName); if (m_assetDumper) m_assetDumper->dumpAsset(node.toQmlItemNode().instanceRenderPixmap(), assetPath); + return assetPath; } void AssetExporter::exportComponent(const ModelNode &rootNode) { qCDebug(loggerInfo) << "Exporting component" << rootNode.id(); - Component exporter(*this, rootNode); - exporter.exportComponent(); - m_components.append(exporter.json()); + m_components.push_back(make_unique(*this, rootNode)); + m_components.back()->exportComponent(); } void AssetExporter::notifyLoadError(AssetExporterView::LoadState state) @@ -212,6 +221,11 @@ void AssetExporter::onQmlFileLoaded() triggerLoadNextFile(); } +Utils::FilePath AssetExporter::componentExportDir(const Component *component) const +{ + return m_exportPath.pathAppended(component->name()); +} + QByteArray AssetExporter::generateUuid(const ModelNode &node) { QByteArray uuid; @@ -252,26 +266,48 @@ void AssetExporter::writeMetadata() const return; } - auto const startupProject = ProjectExplorer::SessionManager::startupProject(); - QTC_ASSERT(startupProject, return); - const QString projectName = startupProject->displayName(); - Utils::FilePath metadataPath = m_exportPath.pathAppended(projectName + ".metadata"); - ExportNotification::addInfo(tr("Writing metadata to file %1."). - arg(metadataPath.toUserOutput())); - makeParentPath(metadataPath); - m_currentState.change(ParsingState::WritingJson); - QJsonObject jsonRoot; // TODO: Write plugin info to root - jsonRoot.insert("artboards", m_components); - QJsonDocument doc(jsonRoot); - if (doc.isNull() || doc.isEmpty()) { - ExportNotification::addError(tr("Empty JSON document.")); - } else { - Utils::FileSaver saver(metadataPath.toString(), QIODevice::Text); + + auto writeFile = [](const Utils::FilePath &path, const QJsonArray &artboards) { + if (!makeParentPath(path)) { + ExportNotification::addError(tr("Writing metadata failed. Cannot create file %1"). + arg(path.toString())); + return; + } + + ExportNotification::addInfo(tr("Writing metadata to file %1.").arg(path.toUserOutput())); + + QJsonObject jsonRoot; // TODO: Write plugin info to root + jsonRoot.insert("artboards", artboards); + QJsonDocument doc(jsonRoot); + if (doc.isNull() || doc.isEmpty()) { + ExportNotification::addError(tr("Empty JSON document.")); + return; + } + + Utils::FileSaver saver(path.toString(), QIODevice::Text); saver.write(doc.toJson(QJsonDocument::Indented)); if (!saver.finalize()) { ExportNotification::addError(tr("Writing metadata failed. %1"). arg(saver.errorString())); } + }; + + m_currentState.change(ParsingState::WritingJson); + + auto const startupProject = ProjectExplorer::SessionManager::startupProject(); + QTC_ASSERT(startupProject, return); + const QString projectName = startupProject->displayName(); + + if (m_perComponentExport) { + for (auto &component : m_components) { + const Utils::FilePath path = componentExportDir(component.get()); + writeFile(path.pathAppended(component->name() + ".metadata"), {component->json()}); + } + } else { + QJsonArray artboards; + std::transform(m_components.cbegin(), m_components.cend(), back_inserter(artboards), + [](const unique_ptr &c) {return c->json(); }); + writeFile(m_exportPath.pathAppended(projectName + ".metadata"), artboards); } notifyProgress(1.0); ExportNotification::addInfo(tr("Export finished.")); diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h index 01b125167be..cd5b302e166 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h @@ -43,6 +43,7 @@ class Project; namespace QmlDesigner { class AssetDumper; +class Component; class AssetExporter : public QObject { @@ -65,12 +66,13 @@ public: ~AssetExporter(); void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath, - bool exportAssets = false); + bool exportAssets, bool perComponentExport); void cancel(); bool isBusy() const; - Utils::FilePath exportAsset(const QmlObjectNode& node, const QString &uuid); + Utils::FilePath exportAsset(const QmlObjectNode& node, const Component *component, + const QString &uuid); QByteArray generateUuid(const ModelNode &node); signals: @@ -87,6 +89,7 @@ private: void loadNextFile(); void onQmlFileLoaded(); + Utils::FilePath componentExportDir(const Component *component) const; private: mutable class State { @@ -102,7 +105,8 @@ private: Utils::FilePaths m_exportFiles; unsigned int m_totalFileCount = 0; Utils::FilePath m_exportPath; - QJsonArray m_components; + bool m_perComponentExport = false; + std::vector> m_components; QSet m_usedHashes; std::unique_ptr m_assetDumper; bool m_cancelled = false; diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp index 59ab72aad1d..a84cfe72c3e 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp @@ -64,7 +64,9 @@ Component::Component(AssetExporter &exporter, const ModelNode &rootNode): m_exporter(exporter), m_rootNode(rootNode) { - + m_name = m_rootNode.id(); + if (m_name.isEmpty()) + m_name = QString::fromUtf8(m_rootNode.type()); } QJsonObject Component::json() const @@ -88,6 +90,11 @@ void Component::exportComponent() addImports(); } +const QString &Component::name() const +{ + return m_name; +} + ModelNodeParser *Component::createNodeParser(const ModelNode &node) const { QByteArrayList lineage = populateLineage(node); diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h index 5e29e10bf0d..3f2fa6ee8a9 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h @@ -75,6 +75,7 @@ public: Component(AssetExporter& exporter, const ModelNode &rootNode); void exportComponent(); + const QString &name() const; QJsonObject json() const; AssetExporter &exporter(); @@ -92,6 +93,7 @@ private: private: AssetExporter& m_exporter; const ModelNode &m_rootNode; + QString m_name; QJsonObject m_json; static std::vector> m_readers; }; diff --git a/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp b/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp index 85b8f11c1ef..b498efbd35a 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp @@ -54,7 +54,7 @@ QJsonObject AssetNodeParser::json(Component &component) const { QJsonObject jsonObject = ItemNodeParser::json(component); - Utils::FilePath assetPath = component.exporter().exportAsset(objectNode(), uuid()); + Utils::FilePath assetPath = component.exporter().exportAsset(objectNode(), &component, uuid()); QJsonObject assetData; assetData.insert(AssetPathTag, assetPath.toString());