AssetExport: Enable generating multiple metadata files

Task-number: QDS-3357
Change-Id: Icc591d61d149ff92b6c415434e2a7574103802ae
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
(cherry picked from commit f1268a9f86)
This commit is contained in:
Vikas Pachdha
2021-01-06 10:51:57 +01:00
parent a42d252054
commit 0061c9479f
7 changed files with 85 additions and 29 deletions

View File

@@ -96,6 +96,11 @@ AssetExportDialog::AssetExportDialog(const Utils::FilePath &exportPath,
m_exportAssetsCheck->setChecked(true); m_exportAssetsCheck->setChecked(true);
optionsLayout->addWidget(m_exportAssetsCheck); 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->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
m_ui->stackedWidget->addWidget(m_filesView); m_ui->stackedWidget->addWidget(m_filesView);
@@ -149,7 +154,8 @@ void AssetExportDialog::onExport()
m_exportLogs->clear(); m_exportLogs->clear();
m_assetExporter.exportQml(m_filePathModel.files(), m_ui->exportPath->fileName(), 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) void AssetExportDialog::onExportStateChanged(AssetExporter::ParsingState newState)

View File

@@ -74,6 +74,7 @@ private:
std::unique_ptr<Ui::AssetExportDialog> m_ui; std::unique_ptr<Ui::AssetExportDialog> m_ui;
QPushButton *m_exportBtn = nullptr; QPushButton *m_exportBtn = nullptr;
QCheckBox *m_exportAssetsCheck = nullptr; QCheckBox *m_exportAssetsCheck = nullptr;
QCheckBox *m_perComponentExportCheck = nullptr;
QListView *m_filesView = nullptr; QListView *m_filesView = nullptr;
QPlainTextEdit *m_exportLogs = nullptr; QPlainTextEdit *m_exportLogs = nullptr;
Utils::OutputFormatter *m_outputFormatter = nullptr; Utils::OutputFormatter *m_outputFormatter = nullptr;

View File

@@ -115,15 +115,20 @@ AssetExporter::~AssetExporter()
} }
void AssetExporter::exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath, 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(exportPath.toUserOutput())
.arg(exportAssets? tr("Yes") : tr("No"))); .arg(exportAssets? tr("Yes") : tr("No")));
if (m_perComponentExport)
ExportNotification::addInfo(tr("Each component is exported separately"));
notifyProgress(0.0); notifyProgress(0.0);
m_exportFiles = qmlFiles; m_exportFiles = qmlFiles;
m_totalFileCount = m_exportFiles.count(); m_totalFileCount = m_exportFiles.count();
m_components = QJsonArray(); m_components.clear();
m_exportPath = exportPath; m_exportPath = exportPath;
m_currentState.change(ParsingState::Parsing); m_currentState.change(ParsingState::Parsing);
triggerLoadNextFile(); triggerLoadNextFile();
@@ -149,22 +154,26 @@ bool AssetExporter::isBusy() const
m_currentState == AssetExporter::ParsingState::WritingJson; 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) if (m_cancelled)
return {}; 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) if (m_assetDumper)
m_assetDumper->dumpAsset(node.toQmlItemNode().instanceRenderPixmap(), assetPath); m_assetDumper->dumpAsset(node.toQmlItemNode().instanceRenderPixmap(), assetPath);
return assetPath; return assetPath;
} }
void AssetExporter::exportComponent(const ModelNode &rootNode) void AssetExporter::exportComponent(const ModelNode &rootNode)
{ {
qCDebug(loggerInfo) << "Exporting component" << rootNode.id(); qCDebug(loggerInfo) << "Exporting component" << rootNode.id();
Component exporter(*this, rootNode); m_components.push_back(make_unique<Component>(*this, rootNode));
exporter.exportComponent(); m_components.back()->exportComponent();
m_components.append(exporter.json());
} }
void AssetExporter::notifyLoadError(AssetExporterView::LoadState state) void AssetExporter::notifyLoadError(AssetExporterView::LoadState state)
@@ -212,6 +221,11 @@ void AssetExporter::onQmlFileLoaded()
triggerLoadNextFile(); triggerLoadNextFile();
} }
Utils::FilePath AssetExporter::componentExportDir(const Component *component) const
{
return m_exportPath.pathAppended(component->name());
}
QByteArray AssetExporter::generateUuid(const ModelNode &node) QByteArray AssetExporter::generateUuid(const ModelNode &node)
{ {
QByteArray uuid; QByteArray uuid;
@@ -252,26 +266,48 @@ void AssetExporter::writeMetadata() const
return; return;
} }
auto const startupProject = ProjectExplorer::SessionManager::startupProject();
QTC_ASSERT(startupProject, return); auto writeFile = [](const Utils::FilePath &path, const QJsonArray &artboards) {
const QString projectName = startupProject->displayName(); if (!makeParentPath(path)) {
Utils::FilePath metadataPath = m_exportPath.pathAppended(projectName + ".metadata"); ExportNotification::addError(tr("Writing metadata failed. Cannot create file %1").
ExportNotification::addInfo(tr("Writing metadata to file %1."). arg(path.toString()));
arg(metadataPath.toUserOutput())); return;
makeParentPath(metadataPath); }
m_currentState.change(ParsingState::WritingJson);
ExportNotification::addInfo(tr("Writing metadata to file %1.").arg(path.toUserOutput()));
QJsonObject jsonRoot; // TODO: Write plugin info to root QJsonObject jsonRoot; // TODO: Write plugin info to root
jsonRoot.insert("artboards", m_components); jsonRoot.insert("artboards", artboards);
QJsonDocument doc(jsonRoot); QJsonDocument doc(jsonRoot);
if (doc.isNull() || doc.isEmpty()) { if (doc.isNull() || doc.isEmpty()) {
ExportNotification::addError(tr("Empty JSON document.")); ExportNotification::addError(tr("Empty JSON document."));
} else { return;
Utils::FileSaver saver(metadataPath.toString(), QIODevice::Text); }
Utils::FileSaver saver(path.toString(), QIODevice::Text);
saver.write(doc.toJson(QJsonDocument::Indented)); saver.write(doc.toJson(QJsonDocument::Indented));
if (!saver.finalize()) { if (!saver.finalize()) {
ExportNotification::addError(tr("Writing metadata failed. %1"). ExportNotification::addError(tr("Writing metadata failed. %1").
arg(saver.errorString())); 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<Component> &c) {return c->json(); });
writeFile(m_exportPath.pathAppended(projectName + ".metadata"), artboards);
} }
notifyProgress(1.0); notifyProgress(1.0);
ExportNotification::addInfo(tr("Export finished.")); ExportNotification::addInfo(tr("Export finished."));

View File

@@ -43,6 +43,7 @@ class Project;
namespace QmlDesigner { namespace QmlDesigner {
class AssetDumper; class AssetDumper;
class Component;
class AssetExporter : public QObject class AssetExporter : public QObject
{ {
@@ -65,12 +66,13 @@ public:
~AssetExporter(); ~AssetExporter();
void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath, void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath,
bool exportAssets = false); bool exportAssets, bool perComponentExport);
void cancel(); void cancel();
bool isBusy() const; 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); QByteArray generateUuid(const ModelNode &node);
signals: signals:
@@ -87,6 +89,7 @@ private:
void loadNextFile(); void loadNextFile();
void onQmlFileLoaded(); void onQmlFileLoaded();
Utils::FilePath componentExportDir(const Component *component) const;
private: private:
mutable class State { mutable class State {
@@ -102,7 +105,8 @@ private:
Utils::FilePaths m_exportFiles; Utils::FilePaths m_exportFiles;
unsigned int m_totalFileCount = 0; unsigned int m_totalFileCount = 0;
Utils::FilePath m_exportPath; Utils::FilePath m_exportPath;
QJsonArray m_components; bool m_perComponentExport = false;
std::vector<std::unique_ptr<Component>> m_components;
QSet<QByteArray> m_usedHashes; QSet<QByteArray> m_usedHashes;
std::unique_ptr<AssetDumper> m_assetDumper; std::unique_ptr<AssetDumper> m_assetDumper;
bool m_cancelled = false; bool m_cancelled = false;

View File

@@ -64,7 +64,9 @@ Component::Component(AssetExporter &exporter, const ModelNode &rootNode):
m_exporter(exporter), m_exporter(exporter),
m_rootNode(rootNode) m_rootNode(rootNode)
{ {
m_name = m_rootNode.id();
if (m_name.isEmpty())
m_name = QString::fromUtf8(m_rootNode.type());
} }
QJsonObject Component::json() const QJsonObject Component::json() const
@@ -88,6 +90,11 @@ void Component::exportComponent()
addImports(); addImports();
} }
const QString &Component::name() const
{
return m_name;
}
ModelNodeParser *Component::createNodeParser(const ModelNode &node) const ModelNodeParser *Component::createNodeParser(const ModelNode &node) const
{ {
QByteArrayList lineage = populateLineage(node); QByteArrayList lineage = populateLineage(node);

View File

@@ -75,6 +75,7 @@ public:
Component(AssetExporter& exporter, const ModelNode &rootNode); Component(AssetExporter& exporter, const ModelNode &rootNode);
void exportComponent(); void exportComponent();
const QString &name() const;
QJsonObject json() const; QJsonObject json() const;
AssetExporter &exporter(); AssetExporter &exporter();
@@ -92,6 +93,7 @@ private:
private: private:
AssetExporter& m_exporter; AssetExporter& m_exporter;
const ModelNode &m_rootNode; const ModelNode &m_rootNode;
QString m_name;
QJsonObject m_json; QJsonObject m_json;
static std::vector<std::unique_ptr<Internal::NodeParserCreatorBase>> m_readers; static std::vector<std::unique_ptr<Internal::NodeParserCreatorBase>> m_readers;
}; };

View File

@@ -54,7 +54,7 @@ QJsonObject AssetNodeParser::json(Component &component) const
{ {
QJsonObject jsonObject = ItemNodeParser::json(component); QJsonObject jsonObject = ItemNodeParser::json(component);
Utils::FilePath assetPath = component.exporter().exportAsset(objectNode(), uuid()); Utils::FilePath assetPath = component.exporter().exportAsset(objectNode(), &component, uuid());
QJsonObject assetData; QJsonObject assetData;
assetData.insert(AssetPathTag, assetPath.toString()); assetData.insert(AssetPathTag, assetPath.toString());