image: Use enum for specific errors

This commit is contained in:
Sophie Herold 2024-07-19 23:19:34 +02:00
parent 134c488dbd
commit e08866a1da
6 changed files with 112 additions and 66 deletions

View file

@ -55,14 +55,42 @@ pub enum DecoderUpdate {
Dimensions, Dimensions,
/// Metadata available /// Metadata available
Metadata(Box<Metadata>), Metadata(Box<Metadata>),
/// Image format not supported or unknown
UnsupportedFormat,
/// New image data available, redraw /// New image data available, redraw
Redraw, Redraw,
/// Start animation /// Start animation
Animated, Animated,
SpecificError(DecoderError),
/// And error occurred during decoding /// 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 { impl UpdateSender {
@ -87,9 +115,15 @@ impl UpdateSender {
if let Err(err) = result { if let Err(err) = result {
if err.unsupported_format().is_some() { 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) { pub fn request(&self, tile_request: TileRequest) {
if let FormatDecoder::Svg(svg) = &self.decoder { if let FormatDecoder::Svg(svg) = &self.decoder {
if let Err(err) = svg.request(tile_request) { if let Err(err) = svg.request(tile_request) {
self.update_sender.send(DecoderUpdate::Error(err)); self.update_sender.send(DecoderUpdate::GenericError(err));
} }
} }
} }

View file

@ -98,4 +98,3 @@ impl LpErrorDetails {
obj obj
} }
} }

View file

@ -132,6 +132,8 @@ pub enum FitMode {
} }
mod imp { mod imp {
use decoder::DecoderError;
use super::*; use super::*;
use crate::decoder::tiling::SharedFrameBuffer; use crate::decoder::tiling::SharedFrameBuffer;
use crate::editing; use crate::editing;
@ -145,8 +147,8 @@ mod imp {
pub(super) queued_reload: RefCell<Option<gio::File>>, pub(super) queued_reload: RefCell<Option<gio::File>>,
#[property(get)] #[property(get)]
pub(super) is_deleted: Cell<bool>, pub(super) is_deleted: Cell<bool>,
#[property(get)] #[property(get, builder(DecoderError::None))]
pub(super) is_unsupported: Cell<bool>, pub(super) specific_error: Cell<DecoderError>,
/// Set to true when image is ready for displaying /// Set to true when image is ready for displaying
#[property(get)] #[property(get)]
pub(super) is_loaded: Cell<bool>, pub(super) is_loaded: Cell<bool>,

View file

@ -16,6 +16,8 @@
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use decoder::DecoderError;
use super::*; use super::*;
impl imp::LpImage { impl imp::LpImage {
@ -110,7 +112,7 @@ impl imp::LpImage {
)); ));
} }
} }
DecoderUpdate::Error(err) => { DecoderUpdate::GenericError(err) => {
self.set_error(Some(err)); self.set_error(Some(err));
} }
DecoderUpdate::Animated => { DecoderUpdate::Animated => {
@ -128,8 +130,8 @@ impl imp::LpImage {
self.tick_callback.replace(Some(callback_id)); self.tick_callback.replace(Some(callback_id));
} }
} }
DecoderUpdate::UnsupportedFormat => { DecoderUpdate::SpecificError(err) => {
self.set_unsupported(true); 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(); let obj = self.obj();
if obj.is_unsupported() != is_unsupported { if obj.specific_error() != error {
self.is_unsupported.set(true); self.specific_error.set(error);
obj.notify_is_unsupported(); obj.notify_specific_error();
if is_unsupported { if error.is_err() {
self.set_loaded(false); self.set_loaded(false);
} }
} }
@ -269,7 +271,7 @@ impl imp::LpImage {
if is_loaded { if is_loaded {
self.set_error(None); self.set_error(None);
self.set_unsupported(false); self.set_specific_error(DecoderError::None);
} }
} }
} }

View file

@ -27,6 +27,7 @@ use gtk::prelude::*;
use gtk::CompositeTemplate; use gtk::CompositeTemplate;
use super::LpErrorDetails; use super::LpErrorDetails;
use crate::decoder::DecoderError;
use crate::deps::*; use crate::deps::*;
use crate::util::gettext::*; use crate::util::gettext::*;
use crate::widgets::LpImage; use crate::widgets::LpImage;
@ -209,37 +210,47 @@ impl LpImagePage {
let imp = self.imp(); let imp = self.imp();
let image = self.image(); let image = self.image();
if image.is_unsupported() { if image.specific_error() == DecoderError::NoLoadersConfigured {
let message = if glycin::Loader::supported_mime_types().await.is_empty() { // Translators: {} is replaced with a version number
// Translators: {} is replace with a version number let message = gettext_f(
gettext_f( "No image loaders available. Maybe the “glycin-loaders” package with compatibility version “{}” is not installed.",
"No image loaders available. Maybe the “glycin-loaders” package with compatibility version “{}+” is not installed.", [ format!("{}+", glycin::COMPAT_VERSION)]);
[ 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],
)
}
};
imp.error_page.set_description(Some(&message)); imp.error_page.set_description(Some(&message));
imp.stack.set_visible_child(&*imp.error_page);
imp.error_more_info.set_visible(false); 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); imp.stack.set_visible_child(&*imp.error_page);
} else if let Some(err) = image.error() { } else if let Some(err) = image.error() {
imp.error_more_info.connect_clicked(glib::clone!( imp.error_more_info.connect_clicked(glib::clone!(

View file

@ -41,6 +41,7 @@ use glib::translate::IntoGlib;
use glib::{clone, Properties}; use glib::{clone, Properties};
use gtk::CompositeTemplate; use gtk::CompositeTemplate;
use crate::decoder::DecoderError;
use crate::deps::*; use crate::deps::*;
use crate::file_model::LpFileModel; use crate::file_model::LpFileModel;
use crate::util::gettext::*; use crate::util::gettext::*;
@ -535,31 +536,28 @@ impl LpImageView {
fn new_image_page(&self, file: &gio::File) -> LpImagePage { fn new_image_page(&self, file: &gio::File) -> LpImagePage {
let page = LpImagePage::from_file(file); let page = LpImagePage::from_file(file);
page.image().connect_notify_local( page.image().connect_specific_error_notify(glib::clone!(
Some("is-unsupported"), #[weak(rename_to = obj)]
glib::clone!( self,
#[weak(rename_to = obj)] move |image| {
self, if image.specific_error() == DecoderError::UnsupportedFormat {
move |image, _| { if obj.current_image().as_ref() == Some(image) {
if image.is_unsupported() { log::debug!(
if obj.current_image().as_ref() == Some(image) { "Image format unsupported but not removing since current image"
log::debug!( );
"Image format unsupported but not removing since current image" return;
); }
return;
}
if let Some(file) = image.file() { if let Some(file) = image.file() {
log::debug!("Removing image with unsupported format {:?}", file.uri()); log::debug!("Removing image with unsupported format {:?}", file.uri());
obj.model().remove(&file); obj.model().remove(&file);
if let Some(current_file) = obj.current_file() { if let Some(current_file) = obj.current_file() {
obj.update_sliding_view(&current_file); obj.update_sliding_view(&current_file);
}
} }
} }
} }
), }
); ));
page page
} }