diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-11-30 15:00:28 +0200 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-12-03 08:53:16 +0000 |
commit | 821ca83228ff5d5ed2b770e1d122f94a7da7c831 (patch) | |
tree | 8a4de7d2b39004fdb73f50f095f6782fe3858070 | |
parent | 4e40714dee6cf4fee908d8651989a19b010ad5f6 (diff) |
Import data inputs when importing a presentation
Data inputs used by imported presentations are copied from source
project. Duplicate inputs are ignored.
Task-number: QT3DS-2742
Change-Id: Ia0162f3f91c78b35888e235b764985e09160498d
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Janne Kangas <janne.kangas@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
6 files changed, 129 insertions, 39 deletions
diff --git a/src/Authoring/Studio/Application/PresentationFile.cpp b/src/Authoring/Studio/Application/PresentationFile.cpp index deef4c24..21260213 100644 --- a/src/Authoring/Studio/Application/PresentationFile.cpp +++ b/src/Authoring/Studio/Application/PresentationFile.cpp @@ -273,7 +273,8 @@ QString PresentationFile::findProjectFile(const QString &uipPath) void PresentationFile::getSourcePaths(const QFileInfo &uipSrc, const QFileInfo &uipTarget, QHash<QString, QString> &outPathMap, QString &outProjPathSrc, - QHash<QString, QString> &outPresentationNodes) + QHash<QString, QString> &outPresentationNodes, + QSet<QString> &outDataInputs) { QDomDocument domDoc; if (!StudioUtils::readFileToDomDocument(uipTarget.filePath(), domDoc)) @@ -337,10 +338,29 @@ void PresentationFile::getSourcePaths(const QFileInfo &uipSrc, const QFileInfo & } } + std::function<void(const QDomElement &, bool)> parseDataInput; + parseDataInput = [&](const QDomElement &elem, bool parseChildren) { + const QString ctrlAtt = elem.attribute(QStringLiteral("controlledproperty")); + if (!ctrlAtt.isEmpty()) { + const QStringList dataInputs = ctrlAtt.split(QLatin1Char('$')); + for (auto &di : dataInputs) { + if (!di.isEmpty()) + outDataInputs.insert(di.left(di.indexOf(QLatin1Char(' ')))); + } + } + if (parseChildren) { + const QDomNodeList children = elem.childNodes(); + for (int i = 0; i < children.count(); ++i) + parseDataInput(children.at(i).toElement(), true); + } + }; + // mesh files for group imports, materials, and effects are found under <Graph> QDomElement graphElement = domDoc.documentElement().firstChild() .firstChildElement(QStringLiteral("Graph")); + parseDataInput(graphElement, true); + QDomNodeList modelElems = graphElement.elementsByTagName(QStringLiteral("Model")); for (int i = 0; i < modelElems.count(); ++i) { QDomElement elem = modelElems.at(i).toElement(); @@ -475,6 +495,8 @@ void PresentationFile::getSourcePaths(const QFileInfo &uipSrc, const QFileInfo & } } } + + parseDataInput(elem, false); } }; diff --git a/src/Authoring/Studio/Application/PresentationFile.h b/src/Authoring/Studio/Application/PresentationFile.h index 146149f5..5ff13221 100644 --- a/src/Authoring/Studio/Application/PresentationFile.h +++ b/src/Authoring/Studio/Application/PresentationFile.h @@ -44,7 +44,8 @@ class PresentationFile public: static void getSourcePaths(const QFileInfo &uipSrc, const QFileInfo &uipTarget, QHash<QString, QString> &outPathMap, QString &outRootPath, - QHash<QString, QString> &outPresentationNodes); + QHash<QString, QString> &outPresentationNodes, + QSet<QString> &outDataInputs); static void updatePresentationId(const QString &url, const QString &oldId, const QString &newId); static void renameMaterial(const QString &uipPath, const QString &oldName, diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp index 4b433f06..617659e2 100644 --- a/src/Authoring/Studio/Application/ProjectFile.cpp +++ b/src/Authoring/Studio/Application/ProjectFile.cpp @@ -41,7 +41,6 @@ #include "StudioUtils.h" #include "Dispatch.h" #include <QtCore/qdiriterator.h> -#include <QtXml/qdom.h> #include <QtCore/qsavefile.h> #include <QtCore/qtimer.h> @@ -464,6 +463,58 @@ QString ProjectFile::createPreview() return {}; } +void ProjectFile::parseDataInputElem(const QDomElement &elem, + QMap<QString, CDataInputDialogItem *> &dataInputs) +{ + if (elem.nodeName() == QLatin1String("dataInput")) { + CDataInputDialogItem *item = new CDataInputDialogItem(); + item->name = elem.attribute(QStringLiteral("name")); + QString type = elem.attribute(QStringLiteral("type")); + if (type == QLatin1String("Ranged Number")) { + item->type = EDataType::DataTypeRangedNumber; + item->minValue = elem.attribute(QStringLiteral("min")).toFloat(); + item->maxValue = elem.attribute(QStringLiteral("max")).toFloat(); + } else if (type == QLatin1String("String")) { + item->type = EDataType::DataTypeString; + } else if (type == QLatin1String("Float")) { + item->type = EDataType::DataTypeFloat; + } else if (type == QLatin1String("Boolean")) { + item->type = EDataType::DataTypeBoolean; + } else if (type == QLatin1String("Vector3")) { + item->type = EDataType::DataTypeVector3; + } else if (type == QLatin1String("Vector2")) { + item->type = EDataType::DataTypeVector2; + } else if (type == QLatin1String("Variant")) { + item->type = EDataType::DataTypeVariant; + } +#ifdef DATAINPUT_EVALUATOR_ENABLED + else if (type == QLatin1String("Evaluator")) { + item->type = EDataType::DataTypeEvaluator; + item->valueString = elem.attribute(QStringLiteral("evaluator")); + } +#endif + dataInputs.insert(item->name, item); + } +} + +void ProjectFile::loadDataInputs(const QString &projFile, + QMap<QString, CDataInputDialogItem *> &dataInputs) +{ + QFileInfo fi(projFile); + if (fi.exists()) { + QDomDocument doc; + if (!StudioUtils::readFileToDomDocument(projFile, doc)) + return; + QDomElement assetsElem = doc.documentElement().firstChildElement(QStringLiteral("assets")); + if (!assetsElem.isNull()) { + for (QDomElement p = assetsElem.firstChild().toElement(); !p.isNull(); + p = p.nextSibling().toElement()) { + parseDataInputElem(p, dataInputs); + } + } + } +} + void ProjectFile::loadSubpresentationsAndDatainputs( QVector<SubPresentationRecord> &subpresentations, QMap<QString, CDataInputDialogItem *> &datainputs) @@ -496,34 +547,8 @@ void ProjectFile::loadSubpresentationsAndDatainputs( argsOrSrc = p.attribute(QStringLiteral("args")); subpresentations.push_back( SubPresentationRecord(p.nodeName(), p.attribute("id"), argsOrSrc)); - } else if (p.nodeName() == QLatin1String("dataInput")) { - CDataInputDialogItem *item = new CDataInputDialogItem(); - item->name = p.attribute(QStringLiteral("name")); - QString type = p.attribute(QStringLiteral("type")); - if (type == QLatin1String("Ranged Number")) { - item->type = EDataType::DataTypeRangedNumber; - item->minValue = p.attribute(QStringLiteral("min")).toFloat(); - item->maxValue = p.attribute(QStringLiteral("max")).toFloat(); - } else if (type == QLatin1String("String")) { - item->type = EDataType::DataTypeString; - } else if (type == QLatin1String("Float")) { - item->type = EDataType::DataTypeFloat; - } else if (type == QLatin1String("Boolean")) { - item->type = EDataType::DataTypeBoolean; - } else if (type == QLatin1String("Vector3")) { - item->type = EDataType::DataTypeVector3; - } else if (type == QLatin1String("Vector2")) { - item->type = EDataType::DataTypeVector2; - } else if (type == QLatin1String("Variant")) { - item->type = EDataType::DataTypeVariant; - } -#ifdef DATAINPUT_EVALUATOR_ENABLED - else if (type == QLatin1String("Evaluator")) { - item->type = EDataType::DataTypeEvaluator; - item->valueString = p.attribute(QStringLiteral("evaluator")); - } -#endif - datainputs.insert(item->name, item); + } else { + parseDataInputElem(p, datainputs); } } } diff --git a/src/Authoring/Studio/Application/ProjectFile.h b/src/Authoring/Studio/Application/ProjectFile.h index df9e435a..0ea0244e 100644 --- a/src/Authoring/Studio/Application/ProjectFile.h +++ b/src/Authoring/Studio/Application/ProjectFile.h @@ -30,6 +30,7 @@ #define PROJECTFILE_H #include "Qt3DSFileTools.h" +#include <QtXml/qdom.h> namespace Q3DStudio { class CFilePath; @@ -48,6 +49,10 @@ public: void create(const QString &uiaPath); void ensureProjectFile(); void initProjectFile(const QString &presPath); + static void parseDataInputElem(const QDomElement &elem, + QMap<QString, CDataInputDialogItem *> &dataInputs); + static void loadDataInputs(const QString &projFile, + QMap<QString, CDataInputDialogItem *> &dataInputs); void loadSubpresentationsAndDatainputs( QVector<SubPresentationRecord> &subpresentations, QMap<QString, CDataInputDialogItem *> &datainputs); diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp index 587cb084..24d24f1b 100644 --- a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp +++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp @@ -317,8 +317,9 @@ void ProjectFileSystemModel::updateProjectReferences() // asset files QString dummyStr; QHash<QString, QString> dummyMap; + QSet<QString> dummySet; PresentationFile::getSourcePaths(fi, fi, importPathMap, - dummyStr, dummyMap); + dummyStr, dummyMap, dummySet); addReferencesFromImportMap(); } else { // qml-stream QQmlApplicationEngine qmlEngine; @@ -670,6 +671,7 @@ void ProjectFileSystemModel::importUrls(const QList<QUrl> &urls, int row, bool a // List of all files that have been copied by this import. Used to avoid duplicate imports // due to some of the imported files also being assets used by other imported files. QStringList importedFiles; + QMap<QString, CDataInputDialogItem *> importedDataInputs; int overrideChoice = QMessageBox::NoButton; for (const auto &url : urls) { @@ -686,7 +688,8 @@ void ProjectFileSystemModel::importUrls(const QList<QUrl> &urls, int row, bool a } if (sortedDir.exists()) { - importUrl(sortedDir, url, presentationNodes, importedFiles, overrideChoice); + importUrl(sortedDir, url, presentationNodes, importedFiles, importedDataInputs, + overrideChoice); expandPaths << sortedDir.path(); } } @@ -694,6 +697,24 @@ void ProjectFileSystemModel::importUrls(const QList<QUrl> &urls, int row, bool a // Batch update all imported presentation nodes g_StudioApp.GetCore()->getProjectFile().addPresentationNodes(presentationNodes); + // Add new data inputs that are missing from project's data inputs. Duplicates are ignored, + // even if they are different type. + QMapIterator<QString, CDataInputDialogItem *> diIt(importedDataInputs); + bool addedDi = false; + while (diIt.hasNext()) { + diIt.next(); + if (!g_StudioApp.m_dataInputDialogItems.contains(diIt.key())) { + g_StudioApp.m_dataInputDialogItems.insert(diIt.key(), diIt.value()); + addedDi = true; + } else { + delete diIt.value(); + } + } + if (addedDi) { + g_StudioApp.saveDataInputsToProjectFile(); + g_StudioApp.checkDeletedDatainputs(); // Updates externalPresBoundTypes + } + for (const QString &expandPath : qAsConst(expandPaths)) { int expandRow = rowForPath(expandPath); if (expandRow >= 0 && !m_items[expandRow].expanded) @@ -711,11 +732,13 @@ void ProjectFileSystemModel::importUrls(const QList<QUrl> &urls, int row, bool a * is presentation id. * @param outImportedFiles List of absolute source paths of the dependent assets that are imported * in the same import context. + * @param outDataInputs Map of data inputs that are in use in this import context. * @param outOverrideChoice The copy skip/override choice used in this import context. */ void ProjectFileSystemModel::importUrl(QDir &targetDir, const QUrl &url, QHash<QString, QString> &outPresentationNodes, QStringList &outImportedFiles, + QMap<QString, CDataInputDialogItem *> &outDataInputs, int &outOverrideChoice) const { using namespace Q3DStudio; @@ -801,8 +824,16 @@ void ProjectFileSystemModel::importUrl(QDir &targetDir, const QUrl &url, = doc->GetCore()->getProjectFile().getRelativeFilePathTo(destPath); if (!outPresentationNodes.contains(presPath)) outPresentationNodes.insert(presPath, {}); + QSet<QString> dataInputs; importPresentationAssets(fileInfo, QFileInfo(destPath), outPresentationNodes, - outImportedFiles, outOverrideChoice); + outImportedFiles, dataInputs, outOverrideChoice); + const QString projFile = PresentationFile::findProjectFile(fileInfo.absoluteFilePath()); + QMap<QString, CDataInputDialogItem *> allDataInputs; + ProjectFile::loadDataInputs(projFile, allDataInputs); + for (auto &di : dataInputs) { + if (allDataInputs.contains(di)) + outDataInputs.insert(di, allDataInputs[di]); + } } else if (qmlRoot && isQmlStream) { // importing a qml stream const QString presPath = doc->GetCore()->getProjectFile().getRelativeFilePathTo(destPath); @@ -853,17 +884,19 @@ void ProjectFileSystemModel::importUrl(QDir &targetDir, const QUrl &url, * recursive calls * @param outImportedFiles list of absolute source paths of the dependent assets that are imported * in the same import context. + * @param outDataInputs set of data input identifiers that are in use by this presentation and its + * subpresentations. * @param outOverrideChoice The copy skip/override choice used in this import context. */ void ProjectFileSystemModel::importPresentationAssets( const QFileInfo &uipSrc, const QFileInfo &uipTarget, QHash<QString, QString> &outPresentationNodes, QStringList &outImportedFiles, - int &outOverrideChoice) const + QSet<QString> &outDataInputs, int &outOverrideChoice) const { QHash<QString, QString> importPathMap; QString projPathSrc; // project absolute path for the source uip PresentationFile::getSourcePaths(uipSrc, uipTarget, importPathMap, projPathSrc, - outPresentationNodes); + outPresentationNodes, outDataInputs); const QDir projDir(g_StudioApp.GetCore()->getProjectFile().getProjectPath()); const QDir uipSrcDir = uipSrc.dir(); const QDir uipTargetDir = uipTarget.dir(); @@ -883,7 +916,8 @@ void ProjectFileSystemModel::importPresentationAssets( if (path.endsWith(QLatin1String(".uip"))) { // recursively load any uip asset's assets importPresentationAssets(QFileInfo(srcAssetPath), QFileInfo(targetAssetPath), - outPresentationNodes, outImportedFiles, outOverrideChoice); + outPresentationNodes, outImportedFiles, outDataInputs, + outOverrideChoice); // update the path in outPresentationNodes to be correctly relative in target project const QString subId = outPresentationNodes.take(path); diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h index 9ff909f3..f8786345 100644 --- a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h +++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h @@ -42,6 +42,7 @@ #include <QtQml/qqmlapplicationengine.h> QT_FORWARD_DECLARE_CLASS(QFileSystemModel) +class CDataInputDialogItem; class ProjectFileSystemModel : public QAbstractListModel { @@ -105,10 +106,12 @@ private: bool hasVisibleChildren(const QModelIndex &modelIndex) const; void importUrl(QDir &targetDir, const QUrl &url, QHash<QString, QString> &outPresentationNodes, - QStringList &outImportedFiles, int &outOverrideChoice) const; + QStringList &outImportedFiles, + QMap<QString, CDataInputDialogItem *> &outDataInputs, + int &outOverrideChoice) const; void importPresentationAssets(const QFileInfo &uipSrc, const QFileInfo &uipTarget, QHash<QString, QString> &outPresentationNodes, - QStringList &outImportedFiles, + QStringList &outImportedFiles, QSet<QString> &outDataInputs, int &outOverrideChoice) const; void modelRowsInserted(const QModelIndex &parent, int start, int end); |