diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-10-17 14:47:21 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-10-19 10:19:09 +0000 |
commit | 3cbc990590ac915d73454addc1be06dbefe7e109 (patch) | |
tree | 5b2e732baaa0a41921d1bc99e24de090bc379792 | |
parent | 745c7eb9e734d9e9670b4c25c97f04749c83180a (diff) |
Use QSaveFile when writing various files
Using QSaveFile ensures existing content is not lost if something
goes wrong between clearing the file and writing to it.
Task-number: QT3DS-2471
Change-Id: I7065416b311753785b7498eb56f828105182fc09
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Jere Tuliniemi <jere.tuliniemi@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r-- | src/Authoring/Common/Code/_Win32/Preferences.cpp | 6 | ||||
-rw-r--r-- | src/Authoring/Common/Common.pro | 1 | ||||
-rw-r--r-- | src/Authoring/Studio/Application/PresentationFile.cpp | 39 | ||||
-rw-r--r-- | src/Authoring/Studio/Application/ProjectFile.cpp | 134 | ||||
-rw-r--r-- | src/Authoring/Studio/Application/StudioApp.cpp | 15 | ||||
-rw-r--r-- | src/Authoring/Studio/Utils/StudioUtils.cpp | 45 | ||||
-rw-r--r-- | src/Authoring/Studio/Utils/StudioUtils.h | 11 |
7 files changed, 131 insertions, 120 deletions
diff --git a/src/Authoring/Common/Code/_Win32/Preferences.cpp b/src/Authoring/Common/Code/_Win32/Preferences.cpp index 2dc0159f..0adb1268 100644 --- a/src/Authoring/Common/Code/_Win32/Preferences.cpp +++ b/src/Authoring/Common/Code/_Win32/Preferences.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "Preferences.h" +#include "StudioUtils.h" #include <QtCore/qdir.h> #include <QtCore/qsavefile.h> @@ -42,9 +43,8 @@ void CPreferences::save() { if (!m_PreferencesFile.isEmpty() && !m_domDoc.isNull()) { QSaveFile file(m_PreferencesFile); - file.open(QIODevice::WriteOnly); - if (file.write(m_domDoc.toByteArray(4)) != -1) - file.commit(); + if (StudioUtils::openTextSave(file)) + StudioUtils::commitDomDocumentSave(file, m_domDoc); } } diff --git a/src/Authoring/Common/Common.pro b/src/Authoring/Common/Common.pro index c3ce78f7..805329ed 100644 --- a/src/Authoring/Common/Common.pro +++ b/src/Authoring/Common/Common.pro @@ -26,6 +26,7 @@ INCLUDEPATH += \ ../Client/Code/Core/Utility \ ../QT3DSDM \ ../QT3DSDM/Systems \ + ../Studio/Utils \ ../../Runtime/Source/Qt3DSFoundation/Include \ ../../Runtime/Source/Qt3DSFoundation/Include/foundation \ ../../3rdparty/EASTL/UnknownVersion/include \ diff --git a/src/Authoring/Studio/Application/PresentationFile.cpp b/src/Authoring/Studio/Application/PresentationFile.cpp index 86abae83..41fff72a 100644 --- a/src/Authoring/Studio/Application/PresentationFile.cpp +++ b/src/Authoring/Studio/Application/PresentationFile.cpp @@ -32,12 +32,14 @@ #include "StudioApp.h" #include "Core.h" #include "Doc.h" +#include "StudioUtils.h" #include "IDocumentReader.h" #include <QtCore/qfile.h> +#include <QtCore/qsavefile.h> #include <QtXml/qdom.h> #include <QtCore/qfileinfo.h> #include <QtCore/qdiriterator.h> -#include <qxmlstream.h> +#include <QtCore/qxmlstream.h> #include <QtCore/qlist.h> // This class provides utility static methods for working with presentation files (.uip). Old uip @@ -78,13 +80,10 @@ QSize PresentationFile::readSize(const QString &uipPath) void PresentationFile::updatePresentationId(const QString &uipPath, const QString &oldId, const QString &newId) { - QFile file(uipPath); - if (!file.open(QFile::Text | QIODevice::ReadWrite)) { - qWarning() << file.errorString(); - return; - } QDomDocument domDoc; - domDoc.setContent(&file); + QSaveFile file(uipPath); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; QDomElement rootElem = domDoc.documentElement(); QDomNodeList addNodes = rootElem.elementsByTagName(QStringLiteral("Add")); @@ -104,10 +103,8 @@ void PresentationFile::updatePresentationId(const QString &uipPath, const QStrin } } - if (updated) { - file.resize(0); - file.write(domDoc.toByteArray(4)); - } + if (updated) + StudioUtils::commitDomDocumentSave(file, domDoc); } /** @@ -151,15 +148,9 @@ void PresentationFile::getSourcePaths(const QFileInfo &uipSrc, const QFileInfo & QString &outProjPathSrc, QHash<QString, QString> &outPresentationNodes) { - QFile file(uipTarget.filePath()); - file.open(QFile::Text | QFile::ReadOnly); - if (!file.isOpen()) { - qWarning() << file.errorString(); - return; - } - QDomDocument domDoc; - domDoc.setContent(&file); + if (!StudioUtils::readFileToDomDocument(uipTarget.filePath(), domDoc)) + return; QVector<SubPresentationRecord> subpresentations; QString uiaPath = findProjectFile(uipSrc.filePath()); @@ -306,16 +297,10 @@ bool PresentationFile::getDataInputBindings(const SubPresentationRecord &subpres QList<QString> ctrldPropList; QString spPath(g_StudioApp.getRenderableAbsolutePath(subpresentation.m_id)); - QFile file(spPath); - - file.open(QFile::Text | QFile::ReadOnly); - if (!file.isOpen()) { - qWarning() << file.errorString(); - return false; - } QDomDocument domDoc; - domDoc.setContent(&file); + if (!StudioUtils::readFileToDomDocument(spPath, domDoc)) + return false; // search <Graph> QDomElement graphElem = domDoc.documentElement().firstChild() diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp index 101f3c75..397d9376 100644 --- a/src/Authoring/Studio/Application/ProjectFile.cpp +++ b/src/Authoring/Studio/Application/ProjectFile.cpp @@ -37,8 +37,10 @@ #include "Doc.h" #include "PresentationFile.h" #include "IStudioRenderer.h" +#include "StudioUtils.h" #include <QtCore/qdiriterator.h> #include <QtXml/qdom.h> +#include <QtCore/qsavefile.h> ProjectFile::ProjectFile() { @@ -96,11 +98,10 @@ void ProjectFile::addPresentationNodes(const QHash<QString, QString> &nodeList) { ensureProjectFile(); - // open the uia file - QFile file(getProjectFilePath()); - file.open(QIODevice::ReadWrite); QDomDocument doc; - doc.setContent(&file); + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, doc)) + return; QDomElement rootElem = doc.documentElement(); QDomElement assetsElem = rootElem.firstChildElement(QStringLiteral("assets")); @@ -164,11 +165,8 @@ void ProjectFile::addPresentationNodes(const QHash<QString, QString> &nodeList) } } - if (initial || changesList.size() > 0) { - file.resize(0); - file.write(doc.toByteArray(4)); - } - file.close(); + if (initial || changesList.size() > 0) + StudioUtils::commitDomDocumentSave(file, doc); if (changesList.size() > 0) { g_StudioApp.getRenderer().RegisterSubpresentations(g_StudioApp.m_subpresentations); @@ -182,14 +180,12 @@ void ProjectFile::addPresentationNodes(const QHash<QString, QString> &nodeList) } // Get the src attribute (relative path) to the initial presentation in a uia file, if no initial -// presentation exists, the first one is returned. +// presentation exists, the first one is returned. Returns empty string if file cannot be read. QString ProjectFile::getInitialPresentationSrc(const QString &uiaPath) { - QFile file(uiaPath); - file.open(QIODevice::ReadOnly); QDomDocument domDoc; - domDoc.setContent(&file); - file.close(); + if (!StudioUtils::readFileToDomDocument(uiaPath, domDoc)) + return {}; QString firstPresentationSrc; QDomElement assetsElem = domDoc.documentElement().firstChildElement(QStringLiteral("assets")); @@ -233,10 +229,10 @@ void ProjectFile::writePresentationId(const QString &id, const QString &src) if (theSrc == doc->getRelativePath()) doc->setPresentationId(id); - QFile file(getProjectFilePath()); - file.open(QIODevice::ReadWrite); QDomDocument domDoc; - domDoc.setContent(&file); + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; QDomElement assetsElem = domDoc.documentElement().firstChildElement(QStringLiteral("assets")); QDomNodeList pqNodes = isQml ? assetsElem.elementsByTagName(QStringLiteral("presentation-qml")) @@ -262,16 +258,11 @@ void ProjectFile::writePresentationId(const QString &id, const QString &src) } if (!src.isEmpty() && oldId.isEmpty()) { // new presentation, add it - // overwrite the uia file - file.resize(0); - file.write(domDoc.toByteArray(4)); - file.close(); + StudioUtils::commitDomDocumentSave(file, domDoc); QDir projectDir(getProjectPath()); addPresentationNode(QDir::cleanPath(projectDir.absoluteFilePath(theSrc)), theId); } else if (!oldId.isEmpty()) { // the presentation id changed - // overwrite the uia file - file.resize(0); - file.write(domDoc.toByteArray(4)); + StudioUtils::commitDomDocumentSave(file, domDoc); // update m_subpresentations auto *sp = std::find_if(g_StudioApp.m_subpresentations.begin(), @@ -332,8 +323,7 @@ void ProjectFile::updateDocPresentationId() return; QFile file(getProjectFilePath()); - file.open(QFile::Text | QFile::ReadOnly); - if (!file.isOpen()) { + if (!file.open(QFile::Text | QFile::ReadOnly)) { qWarning() << file.errorString(); return; } @@ -377,8 +367,8 @@ QString ProjectFile::getPresentationId(const QString &src) const // create the project .uia file void ProjectFile::create(const QString &uiaPath) { - QDomDocument doc; - doc.setContent(QStringLiteral("<?xml version=\"1.0\" encoding=\"utf-8\"?>" + QDomDocument domDoc; + domDoc.setContent(QStringLiteral("<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<application xmlns=\"http://qt.io/qt3dstudio/uia\">" "<statemachine ref=\"#logic\">" "<visual-states>" @@ -391,13 +381,11 @@ void ProjectFile::create(const QString &uiaPath) "</statemachine>" "</application>")); - QFile file(uiaPath); - file.open(QIODevice::WriteOnly); - file.resize(0); - file.write(doc.toByteArray(4)); - file.close(); - - m_fileInfo.setFile(uiaPath); + QSaveFile file(uiaPath); + if (StudioUtils::openTextSave(file)) { + StudioUtils::commitDomDocumentSave(file, domDoc); + m_fileInfo.setFile(uiaPath); + } } /** @@ -429,31 +417,28 @@ QString ProjectFile::createPreview() QFile::remove(prvPath); if (QFile::copy(getProjectFilePath(), prvPath)) { - QFile file(prvPath); - file.open(QIODevice::ReadWrite); QDomDocument domDoc; - domDoc.setContent(&file); - - QDomElement assetsElem = domDoc.documentElement() - .firstChildElement(QStringLiteral("assets")); - assetsElem.setAttribute(QStringLiteral("initial"), doc->getPresentationId()); - - if (doc->IsModified()) { - // Set the preview uip path in the uia file - QDomNodeList pNodes = assetsElem.elementsByTagName(QStringLiteral("presentation")); - for (int i = 0; i < pNodes.count(); ++i) { - QDomElement pElem = pNodes.at(i).toElement(); - if (pElem.attribute(QStringLiteral("id")) == doc->getPresentationId()) { - QString src = QDir(getProjectPath()).relativeFilePath(uipPrvPath); - pElem.setAttribute(QStringLiteral("src"), src); - break; + QSaveFile file(prvPath); + if (StudioUtils::openDomDocumentSave(file, domDoc)) { + QDomElement assetsElem = domDoc.documentElement() + .firstChildElement(QStringLiteral("assets")); + assetsElem.setAttribute(QStringLiteral("initial"), doc->getPresentationId()); + + if (doc->IsModified()) { + // Set the preview uip path in the uia file + QDomNodeList pNodes = assetsElem.elementsByTagName(QStringLiteral("presentation")); + for (int i = 0; i < pNodes.count(); ++i) { + QDomElement pElem = pNodes.at(i).toElement(); + if (pElem.attribute(QStringLiteral("id")) == doc->getPresentationId()) { + QString src = QDir(getProjectPath()).relativeFilePath(uipPrvPath); + pElem.setAttribute(QStringLiteral("src"), src); + break; + } } } + StudioUtils::commitDomDocumentSave(file, domDoc); } - file.resize(0); - file.write(domDoc.toByteArray(4)); - return prvPath; } else { qWarning() << "Couldn't clone project file"; @@ -472,14 +457,12 @@ void ProjectFile::loadSubpresentationsAndDatainputs( subpresentations.clear(); datainputs.clear(); - QFile file(getProjectFilePath()); - file.open(QIODevice::ReadOnly); - QDomDocument doc; - doc.setContent(&file); - file.close(); - m_initialPresentation = g_StudioApp.GetCore()->GetDoc()->getPresentationId(); + QDomDocument doc; + if (!StudioUtils::readFileToDomDocument(getProjectFilePath(), doc)) + return; + QDomElement assetsElem = doc.documentElement().firstChildElement(QStringLiteral("assets")); if (!assetsElem.isNull()) { QString initial = assetsElem.attribute(QStringLiteral("initial")); @@ -560,11 +543,10 @@ QString ProjectFile::ensureUniquePresentationId(const QString &id) const if (!m_fileInfo.exists()) return id; - QFile file(m_fileInfo.filePath()); - file.open(QIODevice::ReadOnly); QDomDocument doc; - doc.setContent(&file); - file.close(); + if (!StudioUtils::readFileToDomDocument(m_fileInfo.filePath(), doc)) + return id; + QString newId = id; QDomElement assetsElem = doc.documentElement().firstChildElement(QStringLiteral("assets")); if (!assetsElem.isNull()) { @@ -628,8 +610,7 @@ void ProjectFile::getPresentations(const QString &inUiaPath, const QString &excludePresentationSrc) { QFile file(inUiaPath); - file.open(QFile::Text | QFile::ReadOnly); - if (!file.isOpen()) { + if (!file.open(QFile::Text | QFile::ReadOnly)) { qWarning() << file.errorString(); return; } @@ -665,10 +646,10 @@ void ProjectFile::setInitialPresentation(const QString &initialId) ensureProjectFile(); - QFile file(getProjectFilePath()); - file.open(QIODevice::ReadWrite); QDomDocument domDoc; - domDoc.setContent(&file); + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return; QDomElement assetsElem = domDoc.documentElement().firstChildElement(QStringLiteral("assets")); @@ -676,9 +657,7 @@ void ProjectFile::setInitialPresentation(const QString &initialId) != m_initialPresentation) { assetsElem.setAttribute(QStringLiteral("initial"), m_initialPresentation); - // Rewrite project file - file.resize(0); - file.write(domDoc.toByteArray(4)); + StudioUtils::commitDomDocumentSave(file, domDoc); } } } @@ -703,10 +682,10 @@ bool ProjectFile::renamePresentationFile(const QString &oldName, const QString & g_StudioApp.m_qmlStreamMap.insert(fullNewPath, true); } - QFile file(getProjectFilePath()); - file.open(QIODevice::ReadWrite); QDomDocument domDoc; - domDoc.setContent(&file); + QSaveFile file(getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, domDoc)) + return false; QDomElement assetsElem = domDoc.documentElement().firstChildElement(QStringLiteral("assets")); @@ -738,8 +717,7 @@ bool ProjectFile::renamePresentationFile(const QString &oldName, const QString & doc->SetDocumentPath(fullNewPath); } - file.resize(0); - file.write(domDoc.toByteArray(4)); + StudioUtils::commitDomDocumentSave(file, domDoc); Q_EMIT assetNameChanged(); break; diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp index 1d1c1fad..416d54be 100644 --- a/src/Authoring/Studio/Application/StudioApp.cpp +++ b/src/Authoring/Studio/Application/StudioApp.cpp @@ -46,6 +46,7 @@ #include <QtGui/qsurfaceformat.h> #include <QtCore/qfileinfo.h> #include <QtCore/qurl.h> +#include <QtCore/qsavefile.h> #include <QtGui/qopenglcontext.h> #include <QtWidgets/qaction.h> #include <QtCore/qstandardpaths.h> @@ -1705,12 +1706,12 @@ bool CStudioApp::OnLoadDocument(const QString &inDocument, bool inShowStartupDia void CStudioApp::saveDataInputsToProjectFile() { - // open the uia file m_core->getProjectFile().ensureProjectFile(); - QFile file(m_core->getProjectFile().getProjectFilePath()); - file.open(QIODevice::ReadWrite); + QDomDocument doc; - doc.setContent(&file); + QSaveFile file(m_core->getProjectFile().getProjectFilePath()); + if (!StudioUtils::openDomDocumentSave(file, doc)) + return; QDomElement assetsNode = doc.documentElement().firstChildElement(QStringLiteral("assets")); @@ -1753,11 +1754,7 @@ void CStudioApp::saveDataInputsToProjectFile() #endif assetsNode.appendChild(diNode); } - - // write the uia file - file.resize(0); - file.write(doc.toByteArray(4)); - file.close(); + StudioUtils::commitDomDocumentSave(file, doc); } } diff --git a/src/Authoring/Studio/Utils/StudioUtils.cpp b/src/Authoring/Studio/Utils/StudioUtils.cpp index b2c35963..7553d0b2 100644 --- a/src/Authoring/Studio/Utils/StudioUtils.cpp +++ b/src/Authoring/Studio/Utils/StudioUtils.cpp @@ -73,3 +73,48 @@ qreal StudioUtils::devicePixelRatio() return pixelRatio; } + +// Reads the contents of a text file into QDomDocument +bool StudioUtils::readFileToDomDocument(const QString &filePath, QDomDocument &domDoc) +{ + QFile file(filePath); + if (!file.open(QFile::Text | QIODevice::ReadOnly)) { + qWarning() << __FUNCTION__ << file.errorString(); + return false; + } + + return domDoc.setContent(&file); +} + +// Opens a text file for saving and reads its contents into QDomDocument +bool StudioUtils::openDomDocumentSave(QSaveFile &file, QDomDocument &domDoc) +{ + if (!readFileToDomDocument(file.fileName(), domDoc)) + return false; + if (!file.open(QFile::Text | QIODevice::WriteOnly)) { + qWarning() << __FUNCTION__ << file.errorString(); + return false; + } + return true; +} + +// Saves contents of a QDomDocument into a previously opened text file +bool StudioUtils::commitDomDocumentSave(QSaveFile &file, const QDomDocument &domDoc) +{ + // Overwrites entire file + if (file.resize(0) && file.write(domDoc.toByteArray(4)) != -1 && file.commit()) + return true; + + qWarning() << __FUNCTION__ << file.errorString(); + return false; +} + +// Opens text file for saving without reading its contents +bool StudioUtils::openTextSave(QSaveFile &file) +{ + if (!file.open(QFile::Text | QIODevice::WriteOnly)) { + qWarning() << __FUNCTION__ << file.errorString(); + return false; + } + return true; +} diff --git a/src/Authoring/Studio/Utils/StudioUtils.h b/src/Authoring/Studio/Utils/StudioUtils.h index 9874ecf9..27922878 100644 --- a/src/Authoring/Studio/Utils/StudioUtils.h +++ b/src/Authoring/Studio/Utils/StudioUtils.h @@ -30,18 +30,23 @@ #ifndef INCLUDED_STUDIO_UTILS_H #define INCLUDED_STUDIO_UTILS_H -#include <QtCore/qstring.h> +#include <QtXml/qdom.h> +#include <QtCore/qsavefile.h> +#include <QtCore/qxmlstream.h> class StudioUtils { public: static QString resourceImagePath(); static QString resourceImageUrl(); - static QString resourcePath(); - static QString qmlImportPath(); static qreal devicePixelRatio(); + + static bool readFileToDomDocument(const QString &filePath, QDomDocument &domDoc); + static bool openDomDocumentSave(QSaveFile &file, QDomDocument &domDoc); + static bool commitDomDocumentSave(QSaveFile &file, const QDomDocument &domDoc); + static bool openTextSave(QSaveFile &file); }; #endif // INCLUDED_STUDIO_UTILS_H |