diff --git a/meshroom/core/graph.py b/meshroom/core/graph.py index a2039e72f1..2b789f96a2 100644 --- a/meshroom/core/graph.py +++ b/meshroom/core/graph.py @@ -223,6 +223,7 @@ def __init__(self, name, parent=None): self._compatibilityNodes = DictModel(keyAttrName='name', parent=self) self.cacheDir = meshroom.core.defaultCacheFolder self._filepath = '' + self._fileDateVersion = 0 self.header = {} def clear(self): @@ -267,6 +268,8 @@ def load(self, filepath, setupProjectFile=True, importProject=False, publishOutp if not isinstance(graphData, dict): raise RuntimeError('loadGraph error: Graph is not a dict. File: {}'.format(filepath)) + + self._fileDateVersion = os.path.getmtime(filepath) self.header = fileData.get(Graph.IO.Keys.Header, {}) nodesVersions = self.header.get(Graph.IO.Keys.NodesVersions, {}) @@ -1539,6 +1542,18 @@ def cacheDir(self, value): self.updateStatusFromCache(force=True) self.cacheDirChanged.emit() + @property + def fileDateVersion(self): + return self._fileDateVersion + + @fileDateVersion.setter + def fileDateVersion(self, value): + self._fileDateVersion = value + + @Slot(str, result=float) + def getFileDateVersionFromPath(self, value): + return os.path.getmtime(value) + def setVerbose(self, v): with GraphModification(self): for node in self._nodes: @@ -1553,6 +1568,7 @@ def setVerbose(self, v): filepathChanged = Signal() filepath = Property(str, lambda self: self._filepath, notify=filepathChanged) fileReleaseVersion = Property(str, lambda self: self.header.get(Graph.IO.Keys.ReleaseVersion, "0.0"), notify=filepathChanged) + fileDateVersion = Property(float, fileDateVersion.fget, fileDateVersion.fset, notify=filepathChanged) cacheDirChanged = Signal() cacheDir = Property(str, cacheDir.fget, cacheDir.fset, notify=cacheDirChanged) updated = Signal() diff --git a/meshroom/ui/qml/main.qml b/meshroom/ui/qml/main.qml index fb707e3b35..a896d6dd6e 100644 --- a/meshroom/ui/qml/main.qml +++ b/meshroom/ui/qml/main.qml @@ -368,6 +368,36 @@ ApplicationWindow { onDiscarded: close() onAccepted: saveAsAction.trigger() } + + MessageDialog { + id: fileModifiedDialog + + canCopy: false + icon.text: MaterialIcons.warning + parent: Overlay.overlay + preset: "Warning" + title: "File Modified" + text: "The file has been modified by another instance." + detailedText: "Do you want to overwrite the file?" + + // Add a reload file button next to the save button + footer: DialogButtonBox { + position: DialogButtonBox.Footer + standardButtons: Dialog.Save | Dialog.Cancel + + Button { + text: "Reload File" + + onClicked: { + _reconstruction.loadUrl(_reconstruction.graph.filepath) + fileModifiedDialog.close() + } + } + } + + onAccepted: _reconstruction.save() + onDiscarded: close() + } } FileDialog { @@ -715,7 +745,14 @@ ApplicationWindow { enabled: _reconstruction ? (_reconstruction.graph && !_reconstruction.graph.filepath) || !_reconstruction.undoStack.clean : false onTriggered: { if (_reconstruction.graph.filepath) { - _reconstruction.save() + // get current time date + var date = _reconstruction.graph.getFileDateVersionFromPath(_reconstruction.graph.filepath) + + // check if the file has been modified by another instance + if (_reconstruction.graph.fileDateVersion !== date) { + fileModifiedDialog.open() + } else + _reconstruction.save() } else { initFileDialogFolder(saveFileDialog) saveFileDialog.open() diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index 951267da16..afb1e2f45b 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -509,6 +509,8 @@ def load(self, filepath, setupProjectFile=True, publishOutputs=False): "Data might have been lost in the process.", "Open it with the corresponding version of Meshroom to recover your data." )) + + self.graph.fileDateVersion = os.path.getmtime(filepath) return status except FileNotFoundError as e: self.error.emit(