Adding in new functionality to open / open-with based off of MIME subclasses where needed
This commit is contained in:
parent
3e5b14dd23
commit
e3226d8dc2
2 changed files with 118 additions and 2 deletions
114
src/app.rs
114
src/app.rs
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic::iced::mouse::Event::CursorMoved;
|
||||
#[cfg(feature = "wayland")]
|
||||
use cosmic::iced::{
|
||||
event::wayland::{Event as WaylandEvent, OutputEvent, OverlapNotifyEvent},
|
||||
|
|
@ -57,6 +56,8 @@ use std::{
|
|||
sync::{Arc, Mutex},
|
||||
time::{self, Instant},
|
||||
};
|
||||
use cosmic::iced::mouse::Event::CursorMoved;
|
||||
use cosmic::widget::{Button, ListColumn};
|
||||
use tokio::sync::mpsc;
|
||||
use trash::TrashItem;
|
||||
#[cfg(feature = "wayland")]
|
||||
|
|
@ -75,6 +76,7 @@ use crate::{
|
|||
spawn_detached::spawn_detached,
|
||||
tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION},
|
||||
};
|
||||
use crate::mime_app::MimeApp;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Mode {
|
||||
|
|
@ -560,6 +562,7 @@ pub struct App {
|
|||
impl App {
|
||||
fn open_file(&mut self, path: &PathBuf) {
|
||||
let mime = mime_icon::mime_for_path(path);
|
||||
|
||||
if mime == "application/x-desktop" {
|
||||
// Try opening desktop application
|
||||
match freedesktop_entry_parser::parse_entry(path) {
|
||||
|
|
@ -627,6 +630,31 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
// loop through subclasses if available
|
||||
if let Some(mime_sub_classes) = mime_icon::parent_mime_types(&mime) {
|
||||
for sub_class in mime_sub_classes {
|
||||
for app in self.mime_app_cache.get(&sub_class) {
|
||||
let Some(mut command) = app.command(Some(path.clone().into())) else {
|
||||
continue;
|
||||
};
|
||||
match spawn_detached(&mut command) {
|
||||
Ok(()) => {
|
||||
let _ = recently_used_xbel::update_recently_used(
|
||||
path,
|
||||
App::APP_ID.to_string(),
|
||||
"cosmic-files".to_string(),
|
||||
None,
|
||||
);
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to open {:?} with {:?}: {}", path, app.id, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to using open crate
|
||||
match open::that_detached(path) {
|
||||
Ok(()) => {
|
||||
|
|
@ -2187,7 +2215,8 @@ impl Application for App {
|
|||
selected,
|
||||
..
|
||||
} => {
|
||||
if let Some(app) = self.mime_app_cache.get(&mime).get(selected) {
|
||||
let direct_apps = self.mime_app_cache.get(&mime);
|
||||
if let Some(app) = direct_apps.get(selected) {
|
||||
if let Some(mut command) = app.command(Some(path.clone().into())) {
|
||||
match spawn_detached(&mut command) {
|
||||
Ok(()) => {
|
||||
|
|
@ -2215,6 +2244,46 @@ impl Application for App {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut sub_class_index = selected - direct_apps.len();
|
||||
if let Some(sub_classes) = mime_icon::parent_mime_types(&mime) {
|
||||
for sub_class in sub_classes {
|
||||
let sub_class_apps = self.mime_app_cache.get(&sub_class);
|
||||
if let Some(app) = sub_class_apps.get(sub_class_index) {
|
||||
if let Some(mut command) = app.command(Some(path.clone().into())) {
|
||||
match spawn_detached(&mut command) {
|
||||
Ok(()) => {
|
||||
let _ = recently_used_xbel::update_recently_used(
|
||||
&path,
|
||||
App::APP_ID.to_string(),
|
||||
"cosmic-files".to_string(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
"failed to open {:?} with {:?}: {}",
|
||||
path,
|
||||
app.id,
|
||||
err
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!(
|
||||
"failed to open {:?} with {:?}: failed to get command",
|
||||
path,
|
||||
app.id
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sub_class_index -= sub_class_apps.len();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
DialogPage::RenameItem {
|
||||
from, parent, name, ..
|
||||
|
|
@ -4229,6 +4298,7 @@ impl Application for App {
|
|||
};
|
||||
|
||||
let mut column = widget::list_column();
|
||||
let mut open_index = 0;
|
||||
for (i, app) in self.mime_app_cache.get(mime).iter().enumerate() {
|
||||
column = column.add(
|
||||
widget::button::custom(
|
||||
|
|
@ -4260,8 +4330,48 @@ impl Application for App {
|
|||
.class(theme::Button::MenuItem)
|
||||
.on_press(Message::OpenWithSelection(i)),
|
||||
);
|
||||
open_index += 1;
|
||||
}
|
||||
|
||||
if let Some(sub_classes) = mime_icon::parent_mime_types(&mime) {
|
||||
for sub_class in sub_classes {
|
||||
for (i, app) in self.mime_app_cache.get(&sub_class).iter().enumerate() {
|
||||
column = column.add(
|
||||
widget::button::custom(
|
||||
widget::row::with_children(vec![
|
||||
widget::icon(app.icon.clone()).size(32).into(),
|
||||
if app.is_default {
|
||||
widget::text::body(fl!(
|
||||
"default-app",
|
||||
name = Some(app.name.as_str())
|
||||
))
|
||||
.into()
|
||||
} else {
|
||||
widget::text::body(app.name.to_string()).into()
|
||||
},
|
||||
widget::horizontal_space().into(),
|
||||
if *selected == open_index {
|
||||
widget::icon::from_name("checkbox-checked-symbolic")
|
||||
.size(16)
|
||||
.into()
|
||||
} else {
|
||||
widget::Space::with_width(Length::Fixed(16.0)).into()
|
||||
},
|
||||
])
|
||||
.spacing(space_s)
|
||||
.height(Length::Fixed(32.0))
|
||||
.align_y(Alignment::Center),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.class(theme::Button::MenuItem)
|
||||
.on_press(Message::OpenWithSelection(open_index)),
|
||||
);
|
||||
open_index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let mut dialog = widget::dialog()
|
||||
.title(fl!("open-with-title", name = name))
|
||||
.primary_action(
|
||||
|
|
|
|||
|
|
@ -73,3 +73,9 @@ pub fn mime_icon(mime: Mime, size: u16) -> icon::Handle {
|
|||
None => icon::from_name(FALLBACK_MIME_ICON).size(size).handle(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent_mime_types(mime: &Mime) -> Option<Vec<Mime>> {
|
||||
let mut mime_icon_cache = MIME_ICON_CACHE.lock().unwrap();
|
||||
|
||||
mime_icon_cache.shared_mime_info.get_parents_aliased(mime)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue