From 9a6d1dfbd2073f0228dbf7da6db66ddd12a6e7f5 Mon Sep 17 00:00:00 2001 From: Zoe Forbes Date: Mon, 9 Feb 2026 18:40:18 -0600 Subject: [PATCH 1/3] fix: use Gui.Document.Modified instead of App.Document.Modified (#13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App.Document has no 'Modified' attribute — it only exists on Gui.Document. This caused every Silo save to fail with: Silo save failed: 'App.Document' object has no attribute 'Modified' The save itself succeeded but the modified flag was never cleared, so the document always appeared unsaved. --- freecad/silo_origin.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freecad/silo_origin.py b/freecad/silo_origin.py index e839551..5efe09c 100644 --- a/freecad/silo_origin.py +++ b/freecad/silo_origin.py @@ -392,8 +392,10 @@ class SiloOrigin: obj.SiloPartNumber, str(file_path), properties, comment="" ) - # Clear modified flag - doc.Modified = False + # Clear modified flag (Modified is on Gui.Document, not App.Document) + gui_doc = FreeCADGui.getDocument(doc.Name) + if gui_doc: + gui_doc.Modified = False return True except Exception as e: From 7cf5867a7ac16375fbffc69aeba8af436dec7523 Mon Sep 17 00:00:00 2001 From: Zoe Forbes Date: Mon, 9 Feb 2026 18:40:18 -0600 Subject: [PATCH 2/3] fix: use Gui.Document.Modified instead of App.Document.Modified (#13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App.Document has no 'Modified' attribute — it only exists on Gui.Document. This caused every Silo save to fail with: Silo save failed: 'App.Document' object has no attribute 'Modified' The save itself succeeded but the modified flag was never cleared, so the document always appeared unsaved. --- freecad/silo_origin.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freecad/silo_origin.py b/freecad/silo_origin.py index e839551..5efe09c 100644 --- a/freecad/silo_origin.py +++ b/freecad/silo_origin.py @@ -392,8 +392,10 @@ class SiloOrigin: obj.SiloPartNumber, str(file_path), properties, comment="" ) - # Clear modified flag - doc.Modified = False + # Clear modified flag (Modified is on Gui.Document, not App.Document) + gui_doc = FreeCADGui.getDocument(doc.Name) + if gui_doc: + gui_doc.Modified = False return True except Exception as e: From ab801601c95c337619c4335b3b3e320d15eac2ae Mon Sep 17 00:00:00 2001 From: Zoe Forbes Date: Tue, 10 Feb 2026 19:00:13 -0600 Subject: [PATCH 3/3] fix: save Modified attribute and SSE retry reset - silo_origin.py: use Gui.Document.Modified instead of App.Document.Modified (re-applies fix from #13 that was lost in rebase) - silo_origin.py: add traceback logging to saveDocument error handler - silo_commands.py: reset SSE retry counter after connections lasting >30s so transient disconnects don't permanently kill the listener --- freecad/silo_commands.py | 11 +++++++++-- freecad/silo_origin.py | 9 +++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/freecad/silo_commands.py b/freecad/silo_commands.py index a2398aa..c056568 100644 --- a/freecad/silo_commands.py +++ b/freecad/silo_commands.py @@ -2350,23 +2350,30 @@ class SiloEventListener(QtCore.QThread): # -- thread entry ------------------------------------------------------- def run(self): + import time + retries = 0 last_error = "" while not self._stop_flag: + t0 = time.monotonic() try: self._listen() # _listen returns normally only on clean EOF / stop if self._stop_flag: return - retries += 1 last_error = "connection closed" except _SSEUnsupported: self.connection_status.emit("unsupported", 0, "") return except Exception as exc: - retries += 1 last_error = str(exc) or "unknown error" + # Reset retries if the connection was up for a while + elapsed = time.monotonic() - t0 + if elapsed > 30: + retries = 0 + retries += 1 + if retries > self._MAX_RETRIES: self.connection_status.emit("gave_up", retries - 1, last_error) return diff --git a/freecad/silo_origin.py b/freecad/silo_origin.py index e839551..131b0d0 100644 --- a/freecad/silo_origin.py +++ b/freecad/silo_origin.py @@ -392,12 +392,17 @@ class SiloOrigin: obj.SiloPartNumber, str(file_path), properties, comment="" ) - # Clear modified flag - doc.Modified = False + # Clear modified flag (Modified is on Gui.Document, not App.Document) + gui_doc = FreeCADGui.getDocument(doc.Name) + if gui_doc: + gui_doc.Modified = False return True except Exception as e: + import traceback + FreeCAD.Console.PrintError(f"Silo save failed: {e}\n") + FreeCAD.Console.PrintError(traceback.format_exc()) return False def saveDocumentAs(self, doc, newIdentity: str) -> bool: