diff options
author | Mahmoud Badri <mahmoud.badri@qt.io> | 2019-02-14 11:42:37 +0200 |
---|---|---|
committer | Mahmoud Badri <mahmoud.badri@qt.io> | 2019-02-18 17:58:33 +0000 |
commit | 6acfb03a5a3bcc8e49b24ba1611b78df2ba4981a (patch) | |
tree | decf1b42e26d881f1a600afb3110fd789255db96 | |
parent | 33764aa97c0f176d54c2e02817e533c0c0be6903 (diff) |
implement variants import and export features
Task-number: QT3DS-3047
Change-Id: Ifa7986c4a7ca7934cf903c005b9df19d9fb75924
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
7 files changed, 190 insertions, 54 deletions
diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp index dd8c8fa5..c4a09b8e 100644 --- a/src/Authoring/Studio/Application/ProjectFile.cpp +++ b/src/Authoring/Studio/Application/ProjectFile.cpp @@ -931,38 +931,94 @@ ProjectFile::getDiBindingtypesFromSubpresentations() const return map; } -// load variant data from uia to m_variantsDef -void ProjectFile::loadVariants() +/** + * Load variants data to m_variantsDef + * + * @param filePath the file path to load the variants from. If empty, variants are loaded from the + * project file and replace m_variantsDef. If a filePath is specified, the loaded + * variants are merged with m_variantsDef + */ +void ProjectFile::loadVariants(const QString &filePath) { if (!m_fileInfo.exists()) return; - QFile file(getProjectFilePath()); + bool isProj = filePath.isEmpty() || filePath == getProjectFilePath(); + QFile file(isProj ? getProjectFilePath() : filePath); if (!file.open(QFile::Text | QFile::ReadOnly)) { qWarning() << file.errorString(); return; } - m_variantsDef.clear(); + if (isProj) + m_variantsDef.clear(); QXmlStreamReader reader(&file); reader.setNamespaceProcessing(false); + VariantGroup *currentGroup = nullptr; while (!reader.atEnd()) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("variantgroup")) { - VariantGroup g; - g.m_title = reader.attributes().value(QLatin1String("id")).toString(); - g.m_color = reader.attributes().value(QLatin1String("color")).toString(); - m_variantsDef.append(g); + QString groupId = reader.attributes().value(QLatin1String("id")).toString(); + QString groupColor = reader.attributes().value(QLatin1String("color")).toString(); + auto it = std::find_if(m_variantsDef.begin(), m_variantsDef.end(), + [&](const VariantGroup &vg) -> bool { + return vg.m_title == groupId; + }); + + if (it != m_variantsDef.end()) { // group exists, override it + currentGroup = it; + } else { + VariantGroup g; + m_variantsDef.append(g); + currentGroup = &m_variantsDef.last(); + } + currentGroup->m_title = groupId; + currentGroup->m_color = groupColor; } else if (reader.name() == QLatin1String("variant")) { - m_variantsDef.last().m_tags.append(reader.attributes().value( - QLatin1String("id")).toString()); - } else if (m_variantsDef.length() > 0) { + if (currentGroup) { + QString tagId = reader.attributes().value(QLatin1String("id")).toString(); + if (!currentGroup->m_tags.contains(tagId)) + currentGroup->m_tags.append(tagId); + } else { + qWarning() << "Error parsing variant tags."; + } + } else if (currentGroup) { break; } } } + + if (!isProj) { + // if loading variants from a file, update the uia + QDomDocument domDoc; + QSaveFile fileProj(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(fileProj, domDoc)) + return; + + QDomElement vElem = domDoc.documentElement().firstChildElement(QStringLiteral("variants")); + if (!vElem.isNull()) + domDoc.documentElement().removeChild(vElem); + + vElem = domDoc.createElement(QStringLiteral("variants")); + domDoc.documentElement().appendChild(vElem); + + for (auto &g : qAsConst(m_variantsDef)) { + QDomElement gElem = domDoc.createElement(QStringLiteral("variantgroup")); + gElem.setAttribute(QStringLiteral("id"), g.m_title); + gElem.setAttribute(QStringLiteral("color"), g.m_color); + vElem.appendChild(gElem); + + for (auto &t : qAsConst(g.m_tags)) { + QDomElement tElem = domDoc.createElement(QStringLiteral("variant")); + tElem.setAttribute(QStringLiteral("id"), t); + gElem.appendChild(tElem); + } + } + + StudioUtils::commitDomDocumentSave(fileProj, domDoc); + } } // Add a new tag to a variants group @@ -991,9 +1047,9 @@ void ProjectFile::addVariantTag(const QString &group, const QString &newTag) } // update m_variantsDef - for (auto &v : m_variantsDef) { - if (v.m_title == group) { - v.m_tags.append(newTag); + for (auto &g : m_variantsDef) { + if (g.m_title == group) { + g.m_tags.append(newTag); break; } } @@ -1192,33 +1248,12 @@ void ProjectFile::deleteVariantGroup(const QString &group) for (int i = 0; i < presElems.count(); ++i) { QString pPath = m_fileInfo.path() + QLatin1Char('/') + presElems.at(i).toElement().attribute(QStringLiteral("src")); - if (groupExistsInUip(pPath, group)) { + if (pPath != doc->GetDocumentPath() && groupExistsInUip(pPath, group)) { inUseIdx = i; break; } } - // check that the group is in use in the current doc (could be set in the property but not saved) - auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); - auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge(); - int instance = doc->GetSelectedInstance(); - int property = propertySystem->GetAggregateInstancePropertyByName(instance, L"variants"); - QString propVal; - if (inUseIdx == -1) { - if (instance != 0 && bridge->IsLayerInstance(instance)) { - qt3dsdm::SValue sValue; - if (propertySystem->GetInstancePropertyValue(instance, property, sValue)) { - propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue) - ->GetData()); - if (propVal.contains(group + QLatin1Char(':'))) { - // this big value will trigger the in-use warning, but will skip updating the - // uips which is not needed. - inUseIdx = 9999; - } - } - } - } - if (inUseIdx != -1) { QMessageBox box; box.setWindowTitle(tr("Group tags in use")); @@ -1236,15 +1271,6 @@ void ProjectFile::deleteVariantGroup(const QString &group) if (pPath != doc->GetDocumentPath()) deleteGroupFromUip(pPath, group); } - if (inUseIdx == 9999) { - // property has the deleted group, need to update it, else the deleted group - // will be saved the uip if the user saves the presentation. - QRegExp rgx(group + ":\\w*,|," + group + ":\\w*"); - propVal.replace(rgx, {}); - qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>( - Q3DStudio::CString::fromQString(propVal)); - propertySystem->SetInstancePropertyValue(instance, property, sVal); - } break; default: @@ -1253,13 +1279,37 @@ void ProjectFile::deleteVariantGroup(const QString &group) } } - // delete the group from current doc, if exists + // delete the group from current uip, if exists deleteGroupFromUip(doc->GetDocumentPath(), group); + // delete the group from the property (if set) + auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); + auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge(); + int instance = doc->GetSelectedInstance(); + int property = propertySystem->GetAggregateInstancePropertyByName(instance, L"variants"); + QString propVal; + if (instance != 0 && bridge->IsLayerInstance(instance)) { + qt3dsdm::SValue sValue; + if (propertySystem->GetInstancePropertyValue(instance, property, sValue)) { + propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue) + ->GetData()); + if (propVal.contains(group + QLatin1Char(':'))) { + // property has the deleted group, need to update it, else the deleted group + // will be saved the uip if the user saves the presentation. + QRegExp rgx(group + ":\\w*,*|," + group + ":\\w*"); + propVal.replace(rgx, {}); + qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>( + Q3DStudio::CString::fromQString(propVal)); + propertySystem->SetInstancePropertyValue(instance, property, sVal); + } + } + } + + // update and save the uia QDomElement variantsElem = domDoc.documentElement() .firstChildElement(QStringLiteral("variants")); QDomNodeList groupsElems = variantsElem.elementsByTagName(QStringLiteral("variantgroup")); - // update and save the uia + bool deleted = false; for (int i = 0; i < groupsElems.count(); ++i) { QDomElement gElem = groupsElems.at(i).toElement(); @@ -1462,7 +1512,7 @@ void ProjectFile::deleteGroupFromUip(const QString &src, const QString &group) QDomNodeList layerElems = domDoc.documentElement() .elementsByTagName(QStringLiteral("Layer")); bool needSave = false; - QRegExp rgx(group + ":\\w*,|," + group + ":\\w*"); + QRegExp rgx(group + ":\\w*,*|," + group + ":\\w*"); for (int i = 0; i < layerElems.count(); ++i) { QDomElement lElem = layerElems.at(i).toElement(); if (lElem.hasAttribute(QStringLiteral("variants"))) { diff --git a/src/Authoring/Studio/Application/ProjectFile.h b/src/Authoring/Studio/Application/ProjectFile.h index 390ccb4c..6b138666 100644 --- a/src/Authoring/Studio/Application/ProjectFile.h +++ b/src/Authoring/Studio/Application/ProjectFile.h @@ -87,7 +87,7 @@ public: void deletePresentationFile(const QString &filePath); void renameMaterial(const QString &oldName, const QString &newName); bool duplicatePresentation(const QString &oldPres, const QString &newPres); - void loadVariants(); + void loadVariants(const QString &filePath = {}); void addVariantTag(const QString &group, const QString &newTag); void renameVariantTag(const QString &group, const QString &oldTag, const QString &newTag); void deleteVariantTag(const QString &group, const QString &tag); diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml index 623af241..4ccff8ee 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml @@ -1124,7 +1124,7 @@ Rectangle { height: 20 onClicked: { - // TODO: implement + _variantsGroupModel.importVariants() } } @@ -1136,7 +1136,7 @@ Rectangle { enabled: !_variantsGroupModel.variantsEmpty onClicked: { - // TODO: implement + _variantsGroupModel.exportVariants() } } } diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp index ac0cc2b5..87219554 100644 --- a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp @@ -35,6 +35,9 @@ #include "ClientDataModelBridge.h" #include "IDocumentEditor.h" #include "VariantTagDialog.h" +#include "StudioUtils.h" +#include "Dialogs.h" +#include <QtCore/qsavefile.h> VariantsGroupModel::VariantsGroupModel(QObject *parent) : QAbstractListModel(parent) @@ -65,9 +68,9 @@ void VariantsGroupModel::refresh() QString val = QString::fromWCharArray( qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)->GetData()); // TODO: remove qDebug when the variants work is fully done. - qDebug() << "\x1b[42m \x1b[1m" << __FUNCTION__ - << ", val=" << val - << "\x1b[m"; +// qDebug() << "\x1b[42m \x1b[1m" << __FUNCTION__ +// << ", val=" << val +// << "\x1b[m"; QHash<QString, QStringList> propTags; if (!val.isEmpty()) { const QStringList propTagsList = val.split(QChar(',')); @@ -161,6 +164,49 @@ void VariantsGroupModel::addNewTag(const QString &group) g_StudioApp.GetCore()->getProjectFile().addVariantTag(group, dlg.getNames().second); } +void VariantsGroupModel::importVariants() +{ + QString importFilePath = g_StudioApp.GetDialogs()->getImportVariantsDlg(); + + if (!importFilePath.isEmpty()) { + g_StudioApp.GetCore()->getProjectFile().loadVariants(importFilePath); + refresh(); + } +} + +void VariantsGroupModel::exportVariants() +{ + QString exportFilePath = g_StudioApp.GetDialogs()->getExportVariantsDlg(); + + if (exportFilePath.isEmpty()) + return; + + QDomDocument domDoc; + domDoc.appendChild(domDoc.createProcessingInstruction(QStringLiteral("xml"), + QStringLiteral("version=\"1.0\"" + " encoding=\"utf-8\""))); + + const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef(); + QDomElement vElem = domDoc.createElement(QStringLiteral("variants")); + domDoc.appendChild(vElem); + for (auto &g : variantsDef) { + QDomElement gElem = domDoc.createElement(QStringLiteral("variantgroup")); + gElem.setAttribute(QStringLiteral("id"), g.m_title); + gElem.setAttribute(QStringLiteral("color"), g.m_color); + vElem.appendChild(gElem); + + for (auto &t : qAsConst(g.m_tags)) { + QDomElement tElem = domDoc.createElement(QStringLiteral("variant"));; + tElem.setAttribute(QStringLiteral("id"), t); + gElem.appendChild(tElem); + } + } + + QSaveFile file(exportFilePath); + if (StudioUtils::openTextSave(file)) + StudioUtils::commitDomDocumentSave(file, domDoc); +} + void VariantsGroupModel::addNewGroup() { VariantTagDialog dlg(VariantTagDialog::AddGroup); diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h index fdebebfc..75a218f7 100644 --- a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h +++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h @@ -68,6 +68,8 @@ public: Q_INVOKABLE void setTagState(const QString &group, const QString &tag, bool selected); Q_INVOKABLE void addNewTag(const QString &group); Q_INVOKABLE void addNewGroup(); + Q_INVOKABLE void importVariants(); + Q_INVOKABLE void exportVariants(); protected: diff --git a/src/Authoring/Studio/Workspace/Dialogs.cpp b/src/Authoring/Studio/Workspace/Dialogs.cpp index 093f154d..96a6680a 100644 --- a/src/Authoring/Studio/Workspace/Dialogs.cpp +++ b/src/Authoring/Studio/Workspace/Dialogs.cpp @@ -1151,6 +1151,42 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject, return theFile; } +QString CDialogs::getImportVariantsDlg() +{ + QString docDir = QFileInfo(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()).absolutePath(); + + QFileDialog dlg; + dlg.setDirectory(docDir); + dlg.setWindowTitle(tr("Import variants")); + dlg.setDefaultSuffix(QStringLiteral(".variants")); + dlg.setNameFilters({tr("All supported files (*.variants *.uia)"), + tr("Variants files (*.variants)"), tr("Project files (*.uia)")}); + dlg.exec(); + + if (!dlg.selectedFiles().empty()) + return dlg.selectedFiles().front(); + + return {}; +} + +QString CDialogs::getExportVariantsDlg() +{ + QString docDir = QFileInfo(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()).absolutePath(); + + QFileDialog dlg; + dlg.setDirectory(docDir); + dlg.setAcceptMode(QFileDialog::AcceptSave); + dlg.setWindowTitle(tr("Export variants")); + dlg.setDefaultSuffix(QStringLiteral(".variants")); + dlg.setNameFilters({QObject::tr("Variants files (*.variants)")}); + dlg.exec(); + + if (!dlg.selectedFiles().empty()) + return dlg.selectedFiles().front(); + + return {}; +} + //============================================================================== /** * Prompt the user for a file to create. diff --git a/src/Authoring/Studio/Workspace/Dialogs.h b/src/Authoring/Studio/Workspace/Dialogs.h index 2579e61f..3f40bc50 100644 --- a/src/Authoring/Studio/Workspace/Dialogs.h +++ b/src/Authoring/Studio/Workspace/Dialogs.h @@ -137,6 +137,8 @@ public: bool isCopy = false); QString GetNewDocumentChoice(const QString &inInitialDirectory = {}, bool isProject = true); QString GetFileOpenChoice(const QString &inInitialDirectory = {}); + QString getExportVariantsDlg(); + QString getImportVariantsDlg(); void DisplayImportFailed(const QUrl &inURL, const QString &inDescription, bool inWarningsOnly); void DisplayLoadingPresentationFailed(const QFileInfo &loadFileInfo, |