From e08866a1da8ae5c78de71036078e63457fb6f203 Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Fri, 19 Jul 2024 23:19:34 +0200 Subject: [PATCH] image: Use enum for specific errors --- src/decoder.rs | 46 +++++++++++++++++++++---- src/widgets/error_details.rs | 1 - src/widgets/image.rs | 6 ++-- src/widgets/image/loading.rs | 20 ++++++----- src/widgets/image_page.rs | 65 +++++++++++++++++++++--------------- src/widgets/image_view.rs | 40 +++++++++++----------- 6 files changed, 112 insertions(+), 66 deletions(-) diff --git a/src/decoder.rs b/src/decoder.rs index 6130b24..96187b2 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -55,14 +55,42 @@ pub enum DecoderUpdate { Dimensions, /// Metadata available Metadata(Box), - /// Image format not supported or unknown - UnsupportedFormat, /// New image data available, redraw Redraw, /// Start animation Animated, + SpecificError(DecoderError), /// And error occurred during decoding - Error(anyhow::Error), + GenericError(anyhow::Error), +} + +#[derive(glib::Enum, Debug, Clone, Copy, Default, PartialEq, Eq)] +#[enum_type(name = "LpDecoderError")] +//#[enum_dynamic(lazy_registration = true)] +#[repr(i32)] +pub enum DecoderError { + /// Image format not supported or unknown + UnsupportedFormat, + /// No glycin-loaders installed + NoLoadersConfigured, + #[default] + None, +} + +impl DecoderError { + pub fn is_err(self) -> bool { + matches!(self, Self::None) + } + + pub fn is_ok(self) -> bool { + !matches!(self, Self::None) + } +} + +impl glib::value::ToValueOptional for DecoderError { + fn to_value_optional(s: Option<&Self>) -> glib::Value { + s.unwrap_or(&Self::None).into() + } } impl UpdateSender { @@ -87,9 +115,15 @@ impl UpdateSender { if let Err(err) = result { if err.unsupported_format().is_some() { - update_sender.send(DecoderUpdate::UnsupportedFormat); + update_sender.send(DecoderUpdate::SpecificError( + DecoderError::UnsupportedFormat, + )); + } else if matches!(err.error(), glycin::Error::NoLoadersConfigured(_)) { + update_sender.send(DecoderUpdate::SpecificError( + DecoderError::NoLoadersConfigured, + )); } - update_sender.send(DecoderUpdate::Error(err.into())); + update_sender.send(DecoderUpdate::GenericError(err.into())); } }) } @@ -153,7 +187,7 @@ impl Decoder { pub fn request(&self, tile_request: TileRequest) { if let FormatDecoder::Svg(svg) = &self.decoder { if let Err(err) = svg.request(tile_request) { - self.update_sender.send(DecoderUpdate::Error(err)); + self.update_sender.send(DecoderUpdate::GenericError(err)); } } } diff --git a/src/widgets/error_details.rs b/src/widgets/error_details.rs index 72cc76b..5661dac 100644 --- a/src/widgets/error_details.rs +++ b/src/widgets/error_details.rs @@ -98,4 +98,3 @@ impl LpErrorDetails { obj } } - diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 9286ca2..a4d4c54 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -132,6 +132,8 @@ pub enum FitMode { } mod imp { + use decoder::DecoderError; + use super::*; use crate::decoder::tiling::SharedFrameBuffer; use crate::editing; @@ -145,8 +147,8 @@ mod imp { pub(super) queued_reload: RefCell>, #[property(get)] pub(super) is_deleted: Cell, - #[property(get)] - pub(super) is_unsupported: Cell, + #[property(get, builder(DecoderError::None))] + pub(super) specific_error: Cell, /// Set to true when image is ready for displaying #[property(get)] pub(super) is_loaded: Cell, diff --git a/src/widgets/image/loading.rs b/src/widgets/image/loading.rs index 5ff03dc..ab69387 100644 --- a/src/widgets/image/loading.rs +++ b/src/widgets/image/loading.rs @@ -16,6 +16,8 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +use decoder::DecoderError; + use super::*; impl imp::LpImage { @@ -110,7 +112,7 @@ impl imp::LpImage { )); } } - DecoderUpdate::Error(err) => { + DecoderUpdate::GenericError(err) => { self.set_error(Some(err)); } DecoderUpdate::Animated => { @@ -128,8 +130,8 @@ impl imp::LpImage { self.tick_callback.replace(Some(callback_id)); } } - DecoderUpdate::UnsupportedFormat => { - self.set_unsupported(true); + DecoderUpdate::SpecificError(err) => { + self.set_specific_error(err); } } } @@ -248,13 +250,13 @@ impl imp::LpImage { } } - fn set_unsupported(&self, is_unsupported: bool) { + fn set_specific_error(&self, error: DecoderError) { let obj = self.obj(); - if obj.is_unsupported() != is_unsupported { - self.is_unsupported.set(true); - obj.notify_is_unsupported(); + if obj.specific_error() != error { + self.specific_error.set(error); + obj.notify_specific_error(); - if is_unsupported { + if error.is_err() { self.set_loaded(false); } } @@ -269,7 +271,7 @@ impl imp::LpImage { if is_loaded { self.set_error(None); - self.set_unsupported(false); + self.set_specific_error(DecoderError::None); } } } diff --git a/src/widgets/image_page.rs b/src/widgets/image_page.rs index d760abd..e6a478d 100644 --- a/src/widgets/image_page.rs +++ b/src/widgets/image_page.rs @@ -27,6 +27,7 @@ use gtk::prelude::*; use gtk::CompositeTemplate; use super::LpErrorDetails; +use crate::decoder::DecoderError; use crate::deps::*; use crate::util::gettext::*; use crate::widgets::LpImage; @@ -209,37 +210,47 @@ impl LpImagePage { let imp = self.imp(); let image = self.image(); - if image.is_unsupported() { - let message = if glycin::Loader::supported_mime_types().await.is_empty() { - // Translators: {} is replace with a version number - gettext_f( - "No image loaders available. Maybe the “glycin-loaders” package with compatibility version “{}+” is not installed.", - [ format!("{}+", glycin::COMPAT_VERSION)]) - } else { - let mime_type = image.metadata().mime_type().unwrap_or_default(); - let content_type = gio::content_type_from_mime_type(&mime_type).unwrap_or_default(); - let description = gio::content_type_get_description(&content_type).to_string(); - - if glycin::Loader::DEFAULT_MIME_TYPES.contains(&mime_type.as_str()) { - // Translators: The first occurance of {} is replace with a description of the - // format and the second with an id (mime-type) of the format. - gettext_f( - "The image format “{} ({})” is known but not installed.", - [&description, &mime_type], - ) - } else { - // Translators: The first occurance of {} is replace with a description of the - // format and the second with an id (mime-type) of the format. - gettext_f( - "Unknown image format “{} ({}).”", - [&description, &mime_type], - ) - } - }; + if image.specific_error() == DecoderError::NoLoadersConfigured { + // Translators: {} is replaced with a version number + let message = gettext_f( + "No image loaders available. Maybe the “glycin-loaders” package with compatibility version “{}” is not installed.", + [ format!("{}+", glycin::COMPAT_VERSION)]); imp.error_page.set_description(Some(&message)); + imp.stack.set_visible_child(&*imp.error_page); imp.error_more_info.set_visible(false); + } else if image.specific_error() == DecoderError::UnsupportedFormat { + let mime_type = image.metadata().mime_type().unwrap_or_default(); + let content_type = gio::content_type_from_mime_type(&mime_type).unwrap_or_default(); + let description = gio::content_type_get_description(&content_type).to_string(); + let message = if glycin::Loader::DEFAULT_MIME_TYPES.contains(&mime_type.as_str()) { + // Translators: The first occurance of {} is replace with a description of the + // format and the second with an id (mime-type) of the format. + gettext_f( + "The image format “{} ({})” is known but not installed.", + [&description, &mime_type], + ) + } else { + // Translators: The first occurance of {} is replace with a description of the + // format and the second with an id (mime-type) of the format. + gettext_f( + "Unknown image format “{} ({}).”", + [&description, &mime_type], + ) + }; + + if let Some(err) = image.error() { + imp.error_more_info.connect_clicked(glib::clone!( + #[weak(rename_to = obj)] + self, + move |_| { + LpErrorDetails::new(&obj.root().unwrap(), &err); + } + )); + } + + imp.error_page.set_description(Some(&message)); imp.stack.set_visible_child(&*imp.error_page); } else if let Some(err) = image.error() { imp.error_more_info.connect_clicked(glib::clone!( diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index 6b75436..e08a6a0 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -41,6 +41,7 @@ use glib::translate::IntoGlib; use glib::{clone, Properties}; use gtk::CompositeTemplate; +use crate::decoder::DecoderError; use crate::deps::*; use crate::file_model::LpFileModel; use crate::util::gettext::*; @@ -535,31 +536,28 @@ impl LpImageView { fn new_image_page(&self, file: &gio::File) -> LpImagePage { let page = LpImagePage::from_file(file); - page.image().connect_notify_local( - Some("is-unsupported"), - glib::clone!( - #[weak(rename_to = obj)] - self, - move |image, _| { - if image.is_unsupported() { - if obj.current_image().as_ref() == Some(image) { - log::debug!( - "Image format unsupported but not removing since current image" - ); - return; - } + page.image().connect_specific_error_notify(glib::clone!( + #[weak(rename_to = obj)] + self, + move |image| { + if image.specific_error() == DecoderError::UnsupportedFormat { + if obj.current_image().as_ref() == Some(image) { + log::debug!( + "Image format unsupported but not removing since current image" + ); + return; + } - if let Some(file) = image.file() { - log::debug!("Removing image with unsupported format {:?}", file.uri()); - obj.model().remove(&file); - if let Some(current_file) = obj.current_file() { - obj.update_sliding_view(¤t_file); - } + if let Some(file) = image.file() { + log::debug!("Removing image with unsupported format {:?}", file.uri()); + obj.model().remove(&file); + if let Some(current_file) = obj.current_file() { + obj.update_sliding_view(¤t_file); } } } - ), - ); + } + )); page }