feat(io): autosave to .sv$ recovery files (SAVETIME command) (#205)
A periodic subscription (every SAVETIME minutes — default 10, 0 disables) writes a <name>.sv$ recovery copy of each dirty, already-saved drawing at its own DWG version. Non-destructive: it never touches the original file or the dirty flag, and skips unsaved (path-less) tabs. The SAVETIME command sets/queries the interval and persists it. Recovery files (.sv$ and .bak) open through the normal Open dialog — the loader detects DWG vs DXF from the leading magic bytes, and a "Backup / Autosave" filter lists them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
54186309b2
commit
02d2764e45
7 changed files with 93 additions and 6 deletions
|
|
@ -42,6 +42,7 @@ impl OpenCADStudio {
|
|||
texteditmode: self.texteditmode,
|
||||
backup_on_save: self.backup_on_save,
|
||||
file_assoc_enabled: self.file_assoc_enabled,
|
||||
savetime_min: self.savetime_min,
|
||||
bg_color: self.default_bg_color.map(f4_to_u3),
|
||||
paper_bg_color: self.default_paper_bg_color.map(f4_to_u3),
|
||||
}
|
||||
|
|
@ -62,6 +63,7 @@ impl OpenCADStudio {
|
|||
self.texteditmode = s.texteditmode;
|
||||
self.backup_on_save = s.backup_on_save;
|
||||
self.file_assoc_enabled = s.file_assoc_enabled;
|
||||
self.savetime_min = s.savetime_min;
|
||||
self.default_bg_color = s.bg_color.map(u3_to_f4);
|
||||
self.default_paper_bg_color = s.paper_bg_color.map(u3_to_f4);
|
||||
// Push the restored background onto every drawing tab that exists now
|
||||
|
|
@ -675,6 +677,41 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
|
|||
self.on_save_dialog_confirm()
|
||||
}
|
||||
|
||||
/// Periodic autosave (SAVETIME): write a `.sv$` recovery copy for every
|
||||
/// dirty tab that has a path, at the document's own DWG version. Best-effort
|
||||
/// and non-destructive — it never touches the original file or the dirty
|
||||
/// flag, and skips unsaved (path-less) tabs.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(super) fn on_autosave(&mut self) -> Task<Message> {
|
||||
let mut n = 0;
|
||||
for i in 0..self.tabs.len() {
|
||||
if !self.tabs[i].dirty {
|
||||
continue;
|
||||
}
|
||||
let Some(path) = self.tabs[i].current_path.clone() else {
|
||||
continue;
|
||||
};
|
||||
let version = self.tabs[i].scene.document.version;
|
||||
if let Ok(bytes) =
|
||||
crate::io::save_to_bytes(&self.tabs[i].scene.document, "dwg", version)
|
||||
{
|
||||
if std::fs::write(path.with_extension("sv$"), bytes).is_ok() {
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
self.command_line
|
||||
.push_output(&format!("Autosaved {n} drawing(s) to .sv$"));
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(super) fn on_autosave(&mut self) -> Task<Message> {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
pub(super) fn on_page_setup_commit(&mut self) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
let layout_name = self.tabs[i].scene.current_layout.clone();
|
||||
|
|
|
|||
|
|
@ -2540,6 +2540,7 @@ impl OpenCADStudio {
|
|||
self.active_modal = Some(crate::app::ModalKind::SaveDialog);
|
||||
Task::none()
|
||||
}
|
||||
Message::AutoSave => self.on_autosave(),
|
||||
|
||||
Message::UnsavedPickedSavePath(Some(path)) => {
|
||||
self.on_unsaved_picked_save_path_some(path)
|
||||
|
|
|
|||
Loading…
Reference in a new issue