use super::{
autosave::{delete_autosaves_for, record_recent_native_file},
catalogue::CatalogueWriteBack,
remember_design_location,
};
use crate::{
EditorModel, MainWindow,
bridge::library::source::LibrarySource,
gui::{editor::state::EditorState, show_toast, tutorial_events::raise},
};
use indicatrix_editor::guide::viewing_events as events;
use indicatrix_vault::db::sqlite::Database;
use slint::ComponentHandle;
use std::{
cell::RefCell,
path::{Path, PathBuf},
rc::Rc,
sync::{Arc, Mutex},
};
pub(super) fn record_last_saved_path(ui: &MainWindow, path: &Path) {
let full = path.display().to_string();
let label = path
.file_name()
.map_or_else(|| full.clone(), |name| name.to_string_lossy().into_owned());
let model = ui.global::<EditorModel>();
model.set_last_saved_path(full.into());
model.set_last_saved_label(label.into());
}
pub(super) struct WriteNativeOutcome {
pub(super) native_path: PathBuf,
pub(super) asc_filename: String,
pub(super) paired: indicatrix_cut_core::native::PairedSave,
pub(super) catalogue: Result<(i64, CatalogueWriteBack), String>,
pub(super) snapshot_generation: u64,
}
pub(super) fn finish_save_native_success(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
outcome: WriteNativeOutcome,
db: &Arc<Mutex<Database>>,
source: &Arc<Mutex<LibrarySource>>,
) {
let WriteNativeOutcome {
native_path,
asc_filename,
paired,
catalogue,
snapshot_generation,
} = outcome;
delete_autosaves_for(Some(asc_filename.as_str()));
record_recent_native_file(ui, &native_path.display().to_string());
remember_design_location(Some(native_path.clone()), None);
let file_label = native_path.file_name().map_or_else(
|| asc_filename.clone(),
|name| name.to_string_lossy().into_owned(),
);
ui.set_loaded_design_name(file_label.into());
record_last_saved_path(ui, &native_path);
let schedule_name = asc_filename.clone();
{
let mut st = state.borrow_mut();
st.asc_filename = Some(asc_filename);
st.original_asc_text = Some(paired.asc_text);
st.saved_generation = snapshot_generation;
}
ui.global::<EditorModel>()
.set_is_dirty(state.borrow().is_dirty());
if let Some(reason) = &paired.draft_reason {
show_toast(
ui,
&format!(
"Saved '{}' as a draft ({reason}). Add a scale-reference tier to \
finish it.",
native_path.display()
),
"warning",
);
} else {
show_toast(
ui,
&format!("Saved '{}'.", native_path.display()),
"success",
);
}
raise(ui, events::DESIGN_SAVED);
report_catalogue_write_back(ui, state, db, source, Path::new(&schedule_name), catalogue);
super::notify_save_completed(ui, state);
}
fn report_catalogue_write_back(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
db: &Arc<Mutex<Database>>,
source: &Arc<Mutex<LibrarySource>>,
dest_path: &Path,
catalogue: Result<(i64, CatalogueWriteBack), String>,
) {
match catalogue {
Ok((_, CatalogueWriteBack::UrlCollision { existing_id, title })) => {
let file = dest_path.file_name().map_or_else(
|| dest_path.display().to_string(),
|name| name.to_string_lossy().into_owned(),
);
show_toast(
ui,
&format!(
"Saved to disk; the catalogue already holds a design named '{file}' \
(id {existing_id}, \"{title}\"), catalogue not updated. Import it \
explicitly to replace."
),
"warning",
);
}
Ok((id, catalogue_outcome)) => {
state.borrow_mut().source_entry_id = Some(id);
crate::gui::library::local::refresh_after_library_change(ui, db, source);
match catalogue_outcome {
CatalogueWriteBack::SourceRowGoneNewRowCreated => {
show_toast(
ui,
"This design's catalogue row no longer exists (it may have been \
deleted) -- saved as a new catalogue entry instead of updating it.",
"info",
);
}
CatalogueWriteBack::UpdatedExisting {
stale_cache_invalidation_failed: true,
} => {
show_toast(
ui,
"Saved, but this design's cached preview image and tilt curves in \
the library could not be cleared automatically -- they may still \
show the geometry from before this save. Re-export or recompute \
them if they look wrong.",
"warning",
);
}
CatalogueWriteBack::UpdatedExisting {
stale_cache_invalidation_failed: false,
}
| CatalogueWriteBack::NewRow
| CatalogueWriteBack::UrlCollision { .. } => {}
}
}
Err(message) => show_toast(ui, &format!("Catalogue not updated: {message}"), "error"),
}
}