edit_window: Add "Replace Original" option

This commit is contained in:
Sophie Herold 2025-01-15 21:45:13 +01:00
parent 01c25a8865
commit 84e58f28df
3 changed files with 156 additions and 43 deletions

View file

@ -40,6 +40,8 @@ mod imp {
toolbar_view: TemplateChild<adw::ToolbarView>,
#[template_child]
cancel: TemplateChild<gtk::Button>,
#[template_child]
done: TemplateChild<gtk::MenuButton>,
#[property(get, construct_only)]
original_image: OnceCell<LpImage>,
@ -60,7 +62,15 @@ mod imp {
glib::spawn_future_local(glib::clone!(
#[weak]
obj,
async move { obj.imp().save_image().await }
async move { obj.imp().save_copy().await }
));
});
klass.install_action("edit.save-overwrite", None, |obj, _, _| {
glib::spawn_future_local(glib::clone!(
#[weak]
obj,
async move { obj.imp().save_overwrite().await }
));
});
}
@ -87,6 +97,15 @@ mod imp {
obj.window().show_image();
}
));
glib::spawn_future_local(glib::clone!(
#[weak]
obj,
async move {
let can_trash = obj.original_image().can_trash().await;
obj.action_set_enabled("edit.save-overwrite", can_trash);
}
));
}
}
@ -94,8 +113,9 @@ mod imp {
impl BinImpl for LpEditWindow {}
impl LpEditWindow {
async fn save_image(&self) {
async fn save_copy(&self) {
let obj = self.obj();
self.done.popdown();
if let Some(current_file) = obj.original_image().file() {
let file_dialog = gtk::FileDialog::new();
@ -107,6 +127,65 @@ mod imp {
log::error!("{}", err);
}
Ok(new_file) => {
self.save(current_file, new_file).await;
}
}
}
}
async fn save_overwrite(&self) {
let obj = self.obj();
self.done.popdown();
if let Some(current_file) = obj.original_image().file() {
if let Some(current_path) = current_file.path() {
if let Some(mut file_stem) = current_path.file_stem().map(|x| x.to_os_string())
{
let mut tmp_path = current_path.clone();
file_stem.push(".tmp");
if let Some(ext) = current_path.extension() {
file_stem.push(".");
file_stem.push(ext);
}
tmp_path.set_file_name(file_stem);
let new_file = gio::File::for_path(&tmp_path);
let written = self.save(current_file.clone(), new_file.clone()).await;
if written {
if let Err(err) =
current_file.trash_future(glib::Priority::DEFAULT).await
{
obj.window().show_error(
&gettext("Failed to save image."),
&format!("Failed to move image {current_path:?} to trash and therefore couldn't save image: {err}"),
ErrorType::General,
);
} else if let Err(err) = new_file
.move_future(
&current_file,
gio::FileCopyFlags::NONE,
glib::Priority::DEFAULT,
)
.0
.await
{
obj.window().show_error(
&gettext("Failed to save image."),
&format!(
"Failed to move image image to {current_path:?}: {err} move {:?} to {:?}", new_file.path().unwrap(), current_file.path().unwrap()
),
ErrorType::General,
);
}
}
}
}
}
}
async fn save(&self, current_file: gio::File, new_file: gio::File) -> bool {
let obj = self.obj();
let editor = glycin::Editor::new(current_file);
if let Some(operations) = obj.operations() {
log::debug!("Computing edited image.");
@ -116,9 +195,7 @@ mod imp {
log::warn!("Failed to edit image: {err}");
obj.window().show_error(
&gettext("Failed to edit image."),
&format!(
"Failed to edit image:\n\n{err}\n\n{operations:#?}"
),
&format!("Failed to edit image:\n\n{err}\n\n{operations:#?}"),
ErrorType::General,
)
}
@ -147,15 +224,16 @@ mod imp {
&format!("Failed to write file:\n\n{err:?}"),
ErrorType::General,
);
} else {
return true;
}
}
}
}
}
}
}
}
}
false
}
}
}

View file

@ -16,7 +16,7 @@
</object>
</child>
<child type="end">
<object class="GtkMenuButton" id="save">
<object class="GtkMenuButton" id="done">
<property name="label" translatable="true">_Done</property>
<property name="use-underline">true</property>
<property name="popover">
@ -57,12 +57,13 @@
</child>
<child>
<object class="GtkListBoxRow" id="save_overwrite">
<property name="action-name">edit.save-overwrite</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">_Replace Original…</property>
<property name="label" translatable="yes">_Replace Original</property>
<property name="use-underline">true</property>
<property name="xalign">0</property>
<property name="mnemonic-widget">save_overwrite</property>

View file

@ -115,4 +115,38 @@ impl LpImage {
self.imp().untransformed_dimensions()
}
}
pub async fn can_trash(&self) -> bool {
let Some(file) = self.file() else {
return false;
};
if file.path().is_none() {
// The trash portal only supports fds anyway
return false;
}
let file_info = file
.query_info_future(
gio::FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
gio::FileQueryInfoFlags::NONE,
glib::Priority::DEFAULT,
)
.await;
match file_info {
Err(err) => {
log::error!(
"Failed to obtain CAN_TRASH attribute for '{}': {err}",
file.uri()
);
// Assume we can't trash if we don't have any infos
false
}
Ok(file_info) => {
file_info.has_attribute(gio::FILE_ATTRIBUTE_ACCESS_CAN_TRASH)
&& file_info.boolean(gio::FILE_ATTRIBUTE_ACCESS_CAN_TRASH)
}
}
}
}