diff options
Diffstat (limited to 'src/Authoring/Studio/Application/ProjectFile.cpp')
-rw-r--r-- | src/Authoring/Studio/Application/ProjectFile.cpp | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp index ecf5a065..af80556d 100644 --- a/src/Authoring/Studio/Application/ProjectFile.cpp +++ b/src/Authoring/Studio/Application/ProjectFile.cpp @@ -43,6 +43,8 @@ #include <QtCore/qdiriterator.h> #include <QtCore/qsavefile.h> #include <QtCore/qtimer.h> +#include <QtCore/qrandom.h> +#include <QtWidgets/qmessagebox.h> ProjectFile::ProjectFile() { @@ -928,3 +930,609 @@ ProjectFile::getDiBindingtypesFromSubpresentations() const return map; } + +// load variant data from uia to m_variantsDef +void ProjectFile::loadVariants() +{ + if (!m_fileInfo.exists()) + return; + + QFile file(getProjectFilePath()); + if (!file.open(QFile::Text | QFile::ReadOnly)) { + qWarning() << file.errorString(); + return; + } + + m_variantsDef.clear(); + + QXmlStreamReader reader(&file); + reader.setNamespaceProcessing(false); + + 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); + } else if (reader.name() == QLatin1String("variant")) { + m_variantsDef.last().m_tags.append(reader.attributes().value( + QLatin1String("id")).toString()); + } else if (m_variantsDef.length() > 0) { + break; + } + } + } +} + +// Add a new tag to a variants group +void ProjectFile::addVariantTag(const QString &group, const QString &newTag) +{ + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + QDomElement newTagElem = domDoc.createElement(QStringLiteral("variant")); + newTagElem.setAttribute(QStringLiteral("id"), newTag); + + QDomNodeList groupsElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("variants")) + .elementsByTagName(QStringLiteral("variantgroup")); + + // update and save the uia + for (int i = 0; i < groupsElems.count(); ++i) { + QDomElement gElem = groupsElems.at(i).toElement(); + if (gElem.attribute(QStringLiteral("id")) == group) { + gElem.appendChild(newTagElem); + StudioUtils::commitDomDocumentSave(file, domDoc); + break; + } + } + + // update m_variantsDef + for (auto &v : m_variantsDef) { + if (v.m_title == group) { + v.m_tags.append(newTag); + break; + } + } +} + +// Add a new group, it is assumes that the new group name is unique +void ProjectFile::addVariantGroup(const QString &newGroup) +{ + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + QDomElement variantsElem = domDoc.documentElement() + .firstChildElement(QStringLiteral("variants")); + + if (variantsElem.isNull()) { + QDomElement newVariantsElem = domDoc.createElement(QStringLiteral("variants")); + domDoc.documentElement().appendChild(newVariantsElem); + variantsElem = newVariantsElem; + } + + // generate random semi-bright color + int r = 0x555555 + QRandomGenerator::global()->generate() % 0x555555; // 0x555555 = 0xffffff / 3 + QString newColor = QLatin1Char('#') + QString::number(r, 16); + + QDomElement newGroupElem = domDoc.createElement(QStringLiteral("variantgroup")); + newGroupElem.setAttribute(QStringLiteral("id"), newGroup); + newGroupElem.setAttribute(QStringLiteral("color"), newColor); + variantsElem.appendChild(newGroupElem); + StudioUtils::commitDomDocumentSave(file, domDoc); + + // update m_variantsDef + VariantGroup g; + g.m_title = newGroup; + g.m_color = newColor; + m_variantsDef.append(g); +} + +void ProjectFile::renameVariantTag(const QString &group, const QString &oldTag, + const QString &newTag) +{ + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + // rename the tag in all uip files + QDomNodeList presElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("assets")) + .elementsByTagName(QStringLiteral("presentation")); + for (int i = 0; i < presElems.count(); ++i) { + QString pPath = m_fileInfo.path() + QLatin1Char('/') + + presElems.at(i).toElement().attribute(QStringLiteral("src")); + renameTagInUip(pPath, group, oldTag, newTag); + } + + // update and save the uia + QDomNodeList groupsElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("variants")) + .elementsByTagName(QStringLiteral("variantgroup")); + + bool renamed = false; + for (int i = 0; i < groupsElems.count(); ++i) { + QDomElement gElem = groupsElems.at(i).toElement(); + if (gElem.attribute(QStringLiteral("id")) == group) { + QDomNodeList tagsElems = gElem.childNodes(); + for (int j = 0; j < tagsElems.count(); ++j) { + QDomElement tElem = tagsElems.at(j).toElement(); + if (tElem.attribute(QStringLiteral("id")) == oldTag) { + tElem.setAttribute(QStringLiteral("id"), newTag); + StudioUtils::commitDomDocumentSave(file, domDoc); + renamed = true; + break; + } + } + if (renamed) + break; + } + } + + // update m_variantsDef + renamed = false; + for (auto &g : m_variantsDef) { + if (g.m_title == group) { + for (auto &t : g.m_tags) { + if (t == oldTag) { + t = newTag; + renamed = true; + break; + } + } + if (renamed) + break; + } + } +} + +// rename a variant group, newGroup is assumed to be unique +void ProjectFile::renameVariantGroup(const QString &oldGroup, const QString &newGroup) +{ + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + // rename the group in all uip files + QDomNodeList presElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("assets")) + .elementsByTagName(QStringLiteral("presentation")); + for (int i = 0; i < presElems.count(); ++i) { + QString pPath = m_fileInfo.path() + QLatin1Char('/') + + presElems.at(i).toElement().attribute(QStringLiteral("src")); + renameGroupInUip(pPath, oldGroup, newGroup); + } + + // update and save the uia + QDomNodeList groupsElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("variants")) + .elementsByTagName(QStringLiteral("variantgroup")); + + for (int i = 0; i < groupsElems.count(); ++i) { + QDomElement gElem = groupsElems.at(i).toElement(); + if (gElem.attribute(QStringLiteral("id")) == oldGroup) { + gElem.setAttribute(QStringLiteral("id"), newGroup); + StudioUtils::commitDomDocumentSave(file, domDoc); + break; + } + } + + // update m_variantsDef + for (auto &g : m_variantsDef) { + if (g.m_title == oldGroup) { + g.m_title = newGroup; + break; + } + } +} + +void ProjectFile::deleteVariantGroup(const QString &group) +{ + CDoc *doc = g_StudioApp.GetCore()->GetDoc(); + + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + // check if group is in use in other presentations in the porject + int inUseIdx = -1; // index of first presentation that has the group in-use + QDomNodeList presElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("assets")) + .elementsByTagName(QStringLiteral("presentation")); + 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)) { + inUseIdx = i; + break; + } + } + + // check that the group is in use in the current doc (could be set in the property but not saved + if (inUseIdx == -1) { + auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); + int instance = doc->GetSelectedInstance(); + auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge(); + + if (instance != 0 && bridge->IsLayerInstance(instance)) { + int property = propertySystem->GetAggregateInstancePropertyByName(instance, + L"variants"); + qt3dsdm::SValue sValue; + if (propertySystem->GetInstancePropertyValue(instance, property, sValue)) { + QString val = QString::fromWCharArray( + qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)->GetData()); + if (val.contains(group + QLatin1Char(':'))) { + // this big value will trigger the in-use warning, but will skip updaing the + // uips which is not needed. + inUseIdx = 9999; + } + } + } + } + + if (inUseIdx != -1) { + QMessageBox box; + box.setWindowTitle(tr("Group tags in use")); + box.setText(tr("Some tags in the Group '%1' are in use in the project, are you sure you" + " want to delete the group?").arg(group)); + box.setIcon(QMessageBox::Warning); + box.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + box.setButtonText(QMessageBox::Yes, QStringLiteral("Delete")); + switch (box.exec()) { + case QMessageBox::Yes: + // delete the group from all uips that use it + for (int i = inUseIdx; i < presElems.count(); ++i) { + QString pPath = m_fileInfo.path() + QLatin1Char('/') + + presElems.at(i).toElement().attribute(QStringLiteral("src")); + 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. + + // TODO: implement + } + break; + + default: + // abort deletion + return; + } + } + + // delete the group from current doc, if exists + deleteGroupFromUip(doc->GetDocumentPath(), group); + + 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(); + if (gElem.attribute(QStringLiteral("id")) == group) { + variantsElem.removeChild(gElem); + StudioUtils::commitDomDocumentSave(file, domDoc); + deleted = true; + break; + } + } + + // update m_variantsDef + for (auto &g : m_variantsDef) { + if (g.m_title == group) { + m_variantsDef.erase(&g); + break; + } + } +} + +void ProjectFile::changeVariantGroupColor(const QString &group, const QString &newColor) +{ + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + // update and save the uia + QDomNodeList groupsElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("variants")) + .elementsByTagName(QStringLiteral("variantgroup")); + + for (int i = 0; i < groupsElems.count(); ++i) { + QDomElement gElem = groupsElems.at(i).toElement(); + if (gElem.attribute(QStringLiteral("id")) == group) { + gElem.setAttribute(QStringLiteral("color"), newColor); + StudioUtils::commitDomDocumentSave(file, domDoc); + break; + } + } + + // update m_variantsDef + for (auto &g : m_variantsDef) { + if (g.m_title == group) { + g.m_color = newColor; + break; + } + } +} + +bool ProjectFile::tagExistsInUip(const QString &src, const QString &group, const QString &tag) const +{ + QFile file(src); + if (!file.open(QFile::Text | QFile::ReadOnly)) { + qWarning() << file.errorString(); + return false; + } + + QXmlStreamReader reader(&file); + reader.setNamespaceProcessing(false); + + while (!reader.atEnd()) { + if (reader.readNextStartElement()) { + if (reader.name() == QLatin1String("Layer") + && reader.attributes().hasAttribute(QLatin1String("variants"))) { + QStringRef v = reader.attributes().value(QLatin1String("variants")); + if (v.contains(group + QLatin1Char(':') + tag)) + return true; + } else if (reader.name() == QLatin1String("Logic")) { + break; + } + } + } + + return false; +} + +bool ProjectFile::groupExistsInUip(const QString &src, const QString &group) const +{ + QFile file(src); + if (!file.open(QFile::Text | QFile::ReadOnly)) { + qWarning() << file.errorString(); + return false; + } + + QXmlStreamReader reader(&file); + reader.setNamespaceProcessing(false); + + while (!reader.atEnd()) { + if (reader.readNextStartElement()) { + if (reader.name() == QLatin1String("Layer") + && reader.attributes().hasAttribute(QLatin1String("variants"))) { + QStringRef v = reader.attributes().value(QLatin1String("variants")); + if (v.contains(group + QLatin1Char(':'))) + return true; + } else if (reader.name() == QLatin1String("Logic")) { + break; + } + } + } + + return false; +} + +// renames a tag (if exists) in all layers in a uip file +void ProjectFile::renameTagInUip(const QString &src, const QString &group, const QString &tag, + const QString &newName) +{ + QDomDocument domDoc; + QSaveFile file(src); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + QDomNodeList layerElems = domDoc.documentElement() + .elementsByTagName(QStringLiteral("Layer")); + bool needSave = false; + for (int i = 0; i < layerElems.count(); ++i) { + QDomElement lElem = layerElems.at(i).toElement(); + if (lElem.hasAttribute(QStringLiteral("variants"))) { + QStringList tagPairs = lElem.attribute(QStringLiteral("variants")) + .split(QLatin1Char(',')); + QString tagFrom = group + QLatin1Char(':') + tag; + QString tagTo = group + QLatin1Char(':') + newName; + + if (tagPairs.contains(tagFrom)) { + tagPairs.replaceInStrings(tagFrom, tagTo); + lElem.setAttribute(QStringLiteral("variants"), tagPairs.join(QLatin1Char(','))); + needSave = true; + } + } + } + + if (needSave) + StudioUtils::commitDomDocumentSave(file, domDoc); +} + +void ProjectFile::renameGroupInUip(const QString &src, const QString &group, const QString &newName) +{ + QDomDocument domDoc; + QSaveFile file(src); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + QDomNodeList layerElems = domDoc.documentElement() + .elementsByTagName(QStringLiteral("Layer")); + bool needSave = false; + for (int i = 0; i < layerElems.count(); ++i) { + QDomElement lElem = layerElems.at(i).toElement(); + if (lElem.hasAttribute(QStringLiteral("variants"))) { + QString variants = lElem.attribute(QStringLiteral("variants")); + if (variants.contains(group + QLatin1Char(':'))) { + variants.replace(group + QLatin1Char(':'), newName + QLatin1Char(':')); + lElem.setAttribute(QStringLiteral("variants"), variants); + needSave = true; + } + } + } + + if (needSave) + StudioUtils::commitDomDocumentSave(file, domDoc); +} + +// deletes a tag (if exists) from all layers in a uip file +void ProjectFile::deleteTagFromUip(const QString &src, const QString &group, const QString &tag) +{ + QDomDocument domDoc; + QSaveFile file(src); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + QDomNodeList layerElems = domDoc.documentElement() + .elementsByTagName(QStringLiteral("Layer")); + bool needSave = false; + for (int i = 0; i < layerElems.count(); ++i) { + QDomElement lElem = layerElems.at(i).toElement(); + if (lElem.hasAttribute(QStringLiteral("variants"))) { + QStringList tagPairs = lElem.attribute(QStringLiteral("variants")) + .split(QLatin1Char(',')); + QString tagPair = group + QLatin1Char(':') + tag; + if (tagPairs.contains(tagPair)) { + tagPairs.removeOne(tagPair); + lElem.setAttribute(QStringLiteral("variants"), tagPairs.join(QLatin1Char(','))); + needSave = true; + } + } + } + + if (needSave) + StudioUtils::commitDomDocumentSave(file, domDoc); +} + +// deletes a group (if exists) from all layers in a uip file +void ProjectFile::deleteGroupFromUip(const QString &src, const QString &group) +{ + QDomDocument domDoc; + QSaveFile file(src); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + QDomNodeList layerElems = domDoc.documentElement() + .elementsByTagName(QStringLiteral("Layer")); + bool needSave = false; + 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"))) { + QString val = lElem.attribute(QStringLiteral("variants")); + if (rgx.indexIn(val) != -1) { + val.replace(rgx, ""); + lElem.setAttribute(QStringLiteral("variants"), val); + needSave = true; + } + } + } + + if (needSave) + StudioUtils::commitDomDocumentSave(file, domDoc); +} + +bool ProjectFile::isVariantGroupUnique(const QString &group) const +{ + for (auto &g : qAsConst(m_variantsDef)) { + if (g.m_title == group) + return false; + } + + return true; +} + +bool ProjectFile::isVariantTagUnique(const QString &group, const QString &tag) const +{ + for (auto &g : qAsConst(m_variantsDef)) { + if (g.m_title == group) + return !g.m_tags.contains(tag); + } + + return true; +} + +void ProjectFile::deleteVariantTag(const QString &group, const QString &tag) +{ + QDomDocument domDoc; + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; + + // check if tag is in use in other presentations in the porject + int inUseIdx = -1; // list of presentations that has the tag in use + QDomNodeList presElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("assets")) + .elementsByTagName(QStringLiteral("presentation")); + for (int i = 0; i < presElems.count(); ++i) { + QString pPath = m_fileInfo.path() + QLatin1Char('/') + + presElems.at(i).toElement().attribute(QStringLiteral("src")); + if (pPath != g_StudioApp.GetCore()->GetDoc()->GetDocumentPath() + && tagExistsInUip(pPath, group, tag)) { + inUseIdx = i; + break; + } + } + + if (inUseIdx != -1) { + QMessageBox box; + box.setWindowTitle(tr("Tag in use")); + box.setText(tr("The tag '%1' is in use in another presentation, are you sure you want to" + " delete it?").arg(tag)); + box.setIcon(QMessageBox::Warning); + box.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + box.setButtonText(QMessageBox::Yes, QStringLiteral("Delete")); + switch (box.exec()) { + case QMessageBox::Yes: + // delete the tag from all uips that use it + for (int i = inUseIdx; i < presElems.count(); ++i) { + QString pPath = m_fileInfo.path() + QLatin1Char('/') + + presElems.at(i).toElement().attribute(QStringLiteral("src")); + if (pPath != g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()) + deleteTagFromUip(pPath, group, tag); + } + break; + + default: + // abort deletion + return; + } + } + + // delete the tag from current doc, if exists + deleteTagFromUip(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath(), group, tag); + + QDomNodeList groupsElems = domDoc.documentElement() + .firstChildElement(QStringLiteral("variants")) + .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(); + if (gElem.attribute(QStringLiteral("id")) == group) { + QDomNodeList tagsElems = gElem.childNodes(); + for (int j = 0; j < tagsElems.count(); ++j) { + QDomElement tElem = tagsElems.at(j).toElement(); + if (tElem.attribute(QStringLiteral("id")) == tag) { + gElem.removeChild(tElem); + StudioUtils::commitDomDocumentSave(file, domDoc); + deleted = true; + break; + } + } + if (deleted) + break; + } + } + + // update m_variantsDef + for (auto &g : m_variantsDef) { + if (g.m_title == group) { + g.m_tags.removeOne(tag); + break; + } + } +} |