mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-18 12:04:13 +02:00
Ask before saving over a project file someone else changed
Saving replaced the project file whatever had happened to it since it was opened. If another user, another program or a second QET had saved the same file in between (a shared drive, a copy synced from another PC), their work was lost without a word. QETProject now remembers the project file's size and modification time when it reads it and after each save of its own. Before writing, write() compares them with the file on disk and, if they differ, writes nothing and returns "someone else changed the file on disk at <time> since it was opened". - Interactive save (Ctrl+S, and the save on closing a project) asks: "Someone else changed <file> on disk at <time> since you opened it" with Save as a copy (opens Save As), Overwrite, or Cancel. - Scripts (--run), the command line, MCP and the autosave timer have no one to ask, so they keep the refusal (autosave logs it). Setting QET_OVERWRITE_CHANGED=1 makes a script overwrite on purpose. - A file that does not exist yet, and a Save As to another name, are not a conflict; after Save As the remembered state is the new file's. No change to what is written, so .qet and .qetz stay as they were. Evidence: new tst_changedondisk (unchanged file saves twice; a file written behind the open project is refused; the override overwrites; a Save As target is no conflict) fails on the changed-file case without the source change and passes with it. Full ctest 107/107. Physical check with qet-gui-dialog.sh: file modified behind the open project, Ctrl+S shows the three-button dialog. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgPFANhWgD66V3v9KVKV58
This commit is contained in:
+50
-2
@@ -268,7 +268,9 @@ bool ProjectView::tryClosing()
|
||||
QString filepath = askUserForFilePath();
|
||||
if (filepath.isEmpty()) return(false); // users may cancel the closing
|
||||
}
|
||||
QETResult result = m_project -> write();
|
||||
bool cancelled = false;
|
||||
QETResult result = writeProject(&cancelled);
|
||||
if (cancelled) return(false);
|
||||
updateWindowTitle();
|
||||
if (!result.isOk()) emit(errorEncountered(result.errorMessage()));
|
||||
return(result.isOk());
|
||||
@@ -753,6 +755,50 @@ QETResult ProjectView::saveCopyForOlderVersions()
|
||||
return(m_project->writeCopyForOlderVersions(path));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ProjectView::writeProject
|
||||
Write the project file. If the file was changed on disk since this QET
|
||||
read or wrote it, ask what to do first: a plain save would replace
|
||||
the other change.
|
||||
@param cancelled set to true if the user gave up, or chose to save a
|
||||
copy and did not complete it: nothing was saved to the project's file
|
||||
@return the result of the write
|
||||
*/
|
||||
QETResult ProjectView::writeProject(bool *cancelled)
|
||||
{
|
||||
*cancelled = false;
|
||||
QDateTime when;
|
||||
if (!m_project -> changedOnDisk(&when)) {
|
||||
return(m_project -> write());
|
||||
}
|
||||
|
||||
const QString name = QFileInfo(m_project -> writeTarget()).fileName();
|
||||
QMessageBox box(QMessageBox::Warning,
|
||||
tr("File changed on disk", "message box title"),
|
||||
tr("Someone else changed %1 on disk at %2 since you opened it.\n\n"
|
||||
"Saving over it would lose their changes.")
|
||||
.arg(name, QLocale::system().toString(when, QLocale::ShortFormat)),
|
||||
QMessageBox::NoButton, this);
|
||||
QPushButton *copy_button = box.addButton(tr("Save as a copy"), QMessageBox::AcceptRole);
|
||||
QPushButton *overwrite_button = box.addButton(tr("Overwrite"), QMessageBox::DestructiveRole);
|
||||
box.addButton(QMessageBox::Cancel);
|
||||
box.setDefaultButton(copy_button);
|
||||
box.setEscapeButton(QMessageBox::Cancel);
|
||||
box.exec();
|
||||
|
||||
if (box.clickedButton() == overwrite_button) {
|
||||
return(m_project -> write(true));
|
||||
}
|
||||
if (box.clickedButton() == copy_button) {
|
||||
QETResult result = saveAs();
|
||||
//The Save As dialog was cancelled: the project is still modified
|
||||
if (m_project -> projectWasModified()) *cancelled = true;
|
||||
return(result);
|
||||
}
|
||||
*cancelled = true;
|
||||
return(QETResult());
|
||||
}
|
||||
|
||||
/**
|
||||
Save project content, then write the project file. May
|
||||
call saveAs if no filepath was provided before.
|
||||
@@ -795,7 +841,9 @@ QETResult ProjectView::doSave()
|
||||
}
|
||||
|
||||
// write to file
|
||||
QETResult result = m_project -> write();
|
||||
bool cancelled = false;
|
||||
QETResult result = writeProject(&cancelled);
|
||||
if (cancelled) return(QETResult());
|
||||
updateWindowTitle();
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user