From a5aea2006dc9da0f479add30560dd09119b8dd55 Mon Sep 17 00:00:00 2001 From: Tom Poole Date: Mon, 20 Apr 2020 15:08:59 +0100 Subject: [PATCH] Projucer: Only updated saved state on content change --- .../Projucer/Source/Project/jucer_Project.cpp | 79 +++++++++++-------- .../Projucer/Source/Project/jucer_Project.h | 12 +-- .../ProjectSaving/jucer_ProjectSaver.cpp | 37 ++------- .../Source/Utility/Helpers/jucer_PresetIDs.h | 1 - 4 files changed, 59 insertions(+), 70 deletions(-) diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 8ee156d26c..1466f37b7c 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -39,18 +39,15 @@ void Project::ProjectFileModificationPoller::reset() void Project::ProjectFileModificationPoller::timerCallback() { - if (project.hasProjectBeenModified()) + if (project.updateCachedFileState() && ! showingWarning) { - if (! showingWarning) - { - project.addProjectMessage (ProjectMessages::Ids::jucerFileModified, - { { "Keep", [this] { keepProject(); } }, - { "Re-load from disk", [this] { reloadProjectFromDisk(); } }, - { "Ignore", [this] { reset(); } } }); + project.addProjectMessage (ProjectMessages::Ids::jucerFileModified, + { { "Save current state", [this] { resaveProject(); } }, + { "Re-load from disk", [this] { reloadProjectFromDisk(); } }, + { "Ignore", [this] { reset(); } } }); - stopTimer(); - showingWarning = true; - } + stopTimer(); + showingWarning = true; } } @@ -73,7 +70,7 @@ void Project::ProjectFileModificationPoller::reloadProjectFromDisk() }); } -void Project::ProjectFileModificationPoller::keepProject() +void Project::ProjectFileModificationPoller::resaveProject() { project.saveProject(); reset(); @@ -95,7 +92,7 @@ Project::Project (const File& f) initialiseAudioPluginValues(); setChangedFlag (false); - modificationTime = getFile().getLastModificationTime(); + updateCachedFileState(); auto& app = ProjucerApplication::getApp(); @@ -166,7 +163,6 @@ void Project::updateCompanyNameDependencies() void Project::updateProjectSettings() { - projectRoot.setProperty (Ids::jucerVersion, ProjectInfo::versionString, nullptr); projectRoot.setProperty (Ids::name, getDocumentTitle(), nullptr); } @@ -952,7 +948,7 @@ void Project::saveAndMoveTemporaryProject (bool openInIDE) auto newDirectory = newParentDirectory.getChildFile (tempDirectory.getFileName()); auto oldJucerFileName = getFile().getFileName(); - saveProjectRootToFile(); + writeProjectFile(); tempDirectory.copyDirectoryTo (newDirectory); tempDirectory.deleteRecursively(); @@ -973,19 +969,6 @@ void Project::saveAndMoveTemporaryProject (bool openInIDE) } } -bool Project::saveProjectRootToFile() -{ - if (auto xml = projectRoot.createXml()) - { - MemoryOutputStream mo; - xml->writeTo (mo, {}); - return build_tools::overwriteFileWithNewDataIfDifferent (getFile(), mo); - } - - jassertfalse; - return false; -} - //============================================================================== void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& property) { @@ -1058,12 +1041,46 @@ void Project::valueTreeChildOrderChanged (ValueTree&, int, int) } //============================================================================== -bool Project::hasProjectBeenModified() +String Project::serialiseProjectXml (std::unique_ptr xml) const { - auto oldModificationTime = modificationTime; - modificationTime = getFile().getLastModificationTime(); + if (xml == nullptr) + return {}; - return (modificationTime.toMilliseconds() > (oldModificationTime.toMilliseconds() + 1000LL)); + XmlElement::TextFormat format; + format.newLineChars = getProjectLineFeed().toRawUTF8(); + return xml->toString (format); +} + +bool Project::updateCachedFileState() +{ + auto lastModificationTime = getFile().getLastModificationTime(); + + if (lastModificationTime <= cachedFileState.first) + return false; + + cachedFileState.first = lastModificationTime; + + auto serialisedFileContent = serialiseProjectXml (XmlDocument (getFile()).getDocumentElement()); + + if (serialisedFileContent == cachedFileState.second) + return false; + + cachedFileState.second = serialisedFileContent; + return true; +} + +void Project::writeProjectFile() +{ + updateCachedFileState(); + + auto newSerialisedXml = serialiseProjectXml (getProjectRoot().createXml()); + jassert (newSerialisedXml.isNotEmpty()); + + if (newSerialisedXml != cachedFileState.second) + { + getFile().replaceWithText (newSerialisedXml); + cachedFileState = { getFile().getLastModificationTime(), newSerialisedXml }; + } } //============================================================================== diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index 0092a5b61d..64cdb55576 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -475,8 +475,8 @@ public: static const char* projectFileExtension; //============================================================================== - bool hasProjectBeenModified(); - void updateModificationTime() { modificationTime = getFile().getLastModificationTime(); } + bool updateCachedFileState(); + void writeProjectFile(); //============================================================================== String getUniqueTargetFolderSuffixForExporter (const String& exporterName, const String& baseTargetFolder); @@ -513,7 +513,7 @@ private: void timerCallback() override; void reset(); - void keepProject(); + void resaveProject(); void reloadProjectFromDisk(); Project& project; @@ -556,15 +556,15 @@ private: void updatePluginCategories(); //============================================================================== - File tempDirectory = {}; + File tempDirectory; + std::pair cachedFileState; void saveAndMoveTemporaryProject (bool openInIDE); - bool saveProjectRootToFile(); + String serialiseProjectXml (std::unique_ptr) const; //============================================================================== friend class Item; bool isSaving = false; - Time modificationTime; StringPairArray parsedPreprocessorDefs; //============================================================================== diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp index e334ae21b2..821272e910 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.cpp @@ -50,7 +50,7 @@ Result ProjectSaver::saveResourcesOnly() { writeBinaryDataFiles(); - if (errors.size() > 0) + if (! errors.isEmpty()) return Result::fail (errors[0]); return Result::ok(); @@ -69,7 +69,7 @@ Result ProjectSaver::saveContentNeededForLiveBuild() { auto modules = getModules(); - if (errors.size() == 0) + if (errors.isEmpty()) { saveBasicProjectItems (modules, loadUserContentFromAppConfig()); return Result::ok(); @@ -275,13 +275,8 @@ Result ProjectSaver::saveProject (ProjectExporter* specifiedExporterToSave) auto oldProjectFile = project.getFile(); auto modules = getModules(); - if (errors.size() == 0) + if (errors.isEmpty()) { - writeMainProjectFile(); - project.updateModificationTime(); - - auto projectRootHash = project.getProjectRoot().toXmlString().hashCode(); - if (project.isAudioPluginProject()) { if (project.shouldBuildUnityPlugin()) @@ -292,12 +287,7 @@ Result ProjectSaver::saveProject (ProjectExporter* specifiedExporterToSave) writeProjects (modules, specifiedExporterToSave); runPostExportScript(); - // if the project root has changed after writing the other files then re-save it - if (project.getProjectRoot().toXmlString().hashCode() != projectRootHash) - { - writeMainProjectFile(); - project.updateModificationTime(); - } + project.writeProjectFile(); if (generatedCodeFolder.exists()) { @@ -305,7 +295,7 @@ Result ProjectSaver::saveProject (ProjectExporter* specifiedExporterToSave) deleteUnwantedFilesIn (generatedCodeFolder); } - if (errors.size() == 0) + if (errors.isEmpty()) return Result::ok(); } @@ -314,23 +304,6 @@ Result ProjectSaver::saveProject (ProjectExporter* specifiedExporterToSave) } //============================================================================== -void ProjectSaver::writeMainProjectFile() -{ - if (auto xml = project.getProjectRoot().createXml()) - { - XmlElement::TextFormat format; - format.newLineChars = projectLineFeed.toRawUTF8(); - - MemoryOutputStream mo (8192); - xml->writeTo (mo, format); - replaceFileIfDifferent (project.getFile(), mo); - } - else - { - addError ("Failed to write main project file: " + project.getFile().getFullPathName()); - } -} - static void writeAutoGenWarningComment (OutputStream& out) { out << "/*" << newLine << newLine diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h index 3d18610554..06edec0cb6 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h @@ -142,7 +142,6 @@ namespace Ids DECLARE_ID (msvcModuleDefinitionFile); DECLARE_ID (bigIcon); DECLARE_ID (smallIcon); - DECLARE_ID (jucerVersion); DECLARE_ID (prebuildCommand); DECLARE_ID (postbuildCommand); DECLARE_ID (generateManifest);