From 059d179d9b3021aabfe12890c4a10abb08e92960 Mon Sep 17 00:00:00 2001 From: Andre Rummler Date: Fri, 18 Sep 2026 18:28:48 +0200 Subject: [PATCH] Fix: a) Project stayed in modified state even after undoing all changes. b) Saving the project deleted the undo stack. --- sources/projectview.cpp | 5 ++++- sources/qetdiagrameditor.cpp | 2 +- sources/qetproject.cpp | 4 +++- sources/qetproject.h | 21 ++++++++++++++++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/sources/projectview.cpp b/sources/projectview.cpp index 768fb816b..7f44b6913 100644 --- a/sources/projectview.cpp +++ b/sources/projectview.cpp @@ -726,7 +726,10 @@ QETResult ProjectView::doSave() // write to file QETResult result = m_project -> write(); updateWindowTitle(); - project()->undoStack()->clear(); + // This marks the stack's current index as the new "saved" point (so isClean()/cleanChanged() correctly + // resume tracking unsaved changes from here) without discarding the undo history. Edits made before this save + // stay undoable for the rest of the session. + project()->undoStack()->setClean(); return(result); } diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index d1a4be91b..596663a3a 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -2840,7 +2840,7 @@ void QETDiagramEditor::updateWindowModifiedState() setWindowTitle(QString("%1[*] - %2").arg( project->pathNameTitle(), tr("QElectroTech", "window title"))); - setWindowModified(project->projectOptionsWereModified()); + setWindowModified(project->projectWasModified()); } else { setWindowTitle(tr("QElectroTech", "window title")); setWindowModified(false); diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index 18afbdde6..6d0601b94 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -534,7 +534,9 @@ QString QETProject::pathNameTitle() const ) ).arg(final_title); } - if (m_modified) { + // Same condition as projectWasModified(): project-options changeg (m_modified) OR the undo stack sitting away from + // its clean index. + if (m_modified || !m_undo_stack->isClean()) { final_title = QString( tr( "%1 [modifié]", diff --git a/sources/qetproject.h b/sources/qetproject.h index 91339c8ee..e898a65e6 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -252,7 +252,26 @@ class QETProject : public QObject void updateDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *, const QString &); void removeDiagramsTitleBlockTemplate(TitleBlockTemplatesCollection *, const QString &); void usedTitleBlockTemplateChanged(const QString &); - void undoStackChanged (bool a) {if (!a) setModified(true);} + /* Deliberately does NOT touch m_modified: m_modified / + * setModified() track project-OPTIONS changes only (see + * projectOptionsWereModified()), which have no undo + * entry and so must stay set until an explicit write(). + * Diagram-content changes are tracked by the undo + * stack's own clean index instead, and projectWasModified() + * already ORs the two together -- that combined value is + * what actually answers "does this project have unsaved + * changes", so re-derive and broadcast it here on every + * clean/dirty transition (covering, in particular, an + * Undo that walks the stack back to its clean index). + * Latching m_modified itself to the undo stack's dirty + * state, the way this slot did before, is a one-way trap: + * cleanChanged(true) would never come back through here + * to un-set it, so a plain content edit stayed marked as + * unsaved even after being fully undone. */ + void undoStackChanged (bool /*a*/) { + emit projectModified(this, projectWasModified()); + emit projectInformationsChanged(this); + } private: void readProjectXml(QDomDocument &xml_project);