mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-17 19:34:13 +02:00
Tell a second person who has a project open, and open it read-only
Two people opening the same project on a shared drive could both edit it, and the last save silently wiped the other's work. A project now has a hidden lock file beside it (.~plant.qetz.lock, small JSON: user, host, process, version, since, heartbeat). Opening a project another live session holds shows who has it, since when and how long ago they were last active, and offers Open read-only (default), Open anyway, or Cancel. - The lock is made with an exclusive create, refreshed every minute and deleted when the project closes. It is not a QLockFile: that treats any lock from another machine as stale after 30 s. Here only a lock made on this machine by a process that no longer exists is taken silently. - A folder the lock cannot be made in, or the setting turned off (Settings > General > Projects), opens as before. - Save As and .qet saved as .qetz move the lock to the new file, and refuse a file someone else has open. A project opened read-only for another's lock does not save over that file. - --resave and --set-titleblock refuse a file someone has open unless given --ignore-lock; the read-only verbs never look at locks and headless runs never take one. A script's qet.save() refuses the same way. Checked: 17 new unit tests (5 go red when stale detection and the exclusive create are broken), full ctest 107/107, the dialog and both choices in the GUI under Xvfb, and --resave refused/allowed from the command line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2729,6 +2729,10 @@ QETResult QETProject::write()
|
||||
if (m_file_path.isEmpty())
|
||||
return(QString("unable to save project to file: no filepath was specified"));
|
||||
|
||||
//Another session holds this file: it was opened read-only for that
|
||||
if (!m_locked_out_path.isEmpty() && m_locked_out_path == m_file_path)
|
||||
return(tr("%1 was opened read-only because someone else has it open. Use Save As to keep your changes in another file.").arg(m_file_path));
|
||||
|
||||
//A project read from a .qet is saved as a .qetz beside it; the
|
||||
//.qet stays as it was (stage D1). If the .qetz cannot be written
|
||||
//(a read-only folder), the project stays the .qet it was.
|
||||
@@ -2783,6 +2787,17 @@ QETResult QETProject::write()
|
||||
if (isReadOnly())
|
||||
setReadOnly(false);
|
||||
|
||||
//The file may be a new one (Save As, a .qet saved as .qetz): the lock
|
||||
//follows it. A project that had none (new, or opened read-only for
|
||||
//another's lock) takes one now. Never stops the save: it is done.
|
||||
if (ProjectLock::mayTake()) {
|
||||
if (!m_lock) m_lock = std::make_unique<ProjectLock>();
|
||||
if (!m_lock->isHeld() || m_lock->projectPath() != m_file_path) {
|
||||
if (m_lock->isHeld()) m_lock->moveTo(m_file_path);
|
||||
else m_lock->acquire(m_file_path);
|
||||
}
|
||||
}
|
||||
|
||||
//title block variables should be updated after file save dialog is confirmed, before file is saved.
|
||||
m_project_properties.addValue("saveddate", QLocale::system().toString(QDate::currentDate(), QLocale::ShortFormat));
|
||||
m_project_properties.addValue("saveddate-us", QDate::currentDate().toString("yyyy-MM-dd"));
|
||||
@@ -2807,6 +2822,27 @@ bool QETProject::isReadOnly() const
|
||||
return(m_read_only && read_only_file_path_ == m_file_path);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::setLock
|
||||
Hand the lock sidecar taken for this project's file to the project: it
|
||||
is released when the project is closed.
|
||||
*/
|
||||
void QETProject::setLock(std::unique_ptr<ProjectLock> lock)
|
||||
{
|
||||
m_lock = std::move(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::setOpenedReadOnlyByLock
|
||||
Open this project read-only because another session has it: write()
|
||||
does not write to this file (Save As to another file is allowed).
|
||||
*/
|
||||
void QETProject::setOpenedReadOnlyByLock(bool by_lock)
|
||||
{
|
||||
m_locked_out_path = by_lock ? m_file_path : QString();
|
||||
if (by_lock) setReadOnly(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETProject::setReadOnly
|
||||
Set this project to read only if read_only = true
|
||||
|
||||
Reference in New Issue
Block a user