summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Application/ProjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Application/ProjectFile.cpp')
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.cpp608
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;
+ }
+ }
+}