From 8905ff6592793051e67d61cf3ec0a9c0a91db8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Tue, 22 Oct 2024 17:35:08 +0200 Subject: [PATCH] app: enhance element uri handler Open the given dialog according to the type of property or uri handler supported --- src/app.rs | 127 +++++++++++++++++++++++++++++++++++---------- src/gps/element.rs | 60 +++++++++++++++++++-- src/graphbook.rs | 2 +- src/ui/dialog.rs | 30 ++++++++--- 4 files changed, 179 insertions(+), 40 deletions(-) diff --git a/src/app.rs b/src/app.rs index 23705d2..ee79881 100644 --- a/src/app.rs +++ b/src/app.rs @@ -448,20 +448,24 @@ impl GPSApp { let app_weak = self.downgrade(); self.connect_app_menu_action("open", move |_, _| { let app = upgrade_weak!(app_weak); - GPSUI::dialog::get_file_from_dialog(&app, false, move |app, filename| { - app.load_graph(&filename, false) - .unwrap_or_else(|_| GPS_ERROR!("Unable to open file {}", filename)); - }); + GPSUI::dialog::get_file_from_dialog( + &app, + GPSUI::dialog::FileDialogType::Open, + move |app, filename| { + app.load_graph(&filename, false) + .unwrap_or_else(|_| GPS_ERROR!("Unable to open file {}", filename)); + }, + ); }); let app_weak = self.downgrade(); self.connect_app_menu_action("open_pipeline", move |_, _| { let app = upgrade_weak!(app_weak); GPSUI::dialog::create_input_dialog( + &app, "Enter pipeline description with gst-launch format", "description", &Settings::recent_pipeline_description(), - &app, move |app, pipeline_desc| { app.load_pipeline(&pipeline_desc).unwrap_or_else(|_| { GPS_ERROR!("Unable to open pipeline description {}", pipeline_desc) @@ -475,12 +479,16 @@ impl GPSApp { let app = upgrade_weak!(app_weak); let gt = graphbook::current_graphtab(&app); if gt.undefined() { - GPSUI::dialog::get_file_from_dialog(&app, true, move |app, filename| { - GPS_DEBUG!("Save file {}", filename); - app.save_graph(&filename) - .unwrap_or_else(|_| GPS_ERROR!("Unable to save file to {}", filename)); - graphbook::current_graphtab_set_filename(&app, filename.as_str()); - }); + GPSUI::dialog::get_file_from_dialog( + &app, + GPSUI::dialog::FileDialogType::Save, + move |app, filename| { + GPS_DEBUG!("Save file {}", filename); + app.save_graph(&filename) + .unwrap_or_else(|_| GPS_ERROR!("Unable to save file to {}", filename)); + graphbook::current_graphtab_set_filename(&app, filename.as_str()); + }, + ); } else if gt.modified() { let filename = gt.filename(); app.save_graph(&filename) @@ -492,12 +500,16 @@ impl GPSApp { let app_weak = self.downgrade(); self.connect_app_menu_action("save_as", move |_, _| { let app = upgrade_weak!(app_weak); - GPSUI::dialog::get_file_from_dialog(&app, true, move |app, filename| { - GPS_DEBUG!("Save file {}", filename); - app.save_graph(&filename) - .unwrap_or_else(|_| GPS_ERROR!("Unable to save file to {}", filename)); - graphbook::current_graphtab_set_filename(&app, filename.as_str()); - }); + GPSUI::dialog::get_file_from_dialog( + &app, + GPSUI::dialog::FileDialogType::Save, + move |app, filename| { + GPS_DEBUG!("Save file {}", filename); + app.save_graph(&filename) + .unwrap_or_else(|_| GPS_ERROR!("Unable to save file to {}", filename)); + graphbook::current_graphtab_set_filename(&app, filename.as_str()); + }, + ); }); let app_weak = self.downgrade(); @@ -589,15 +601,78 @@ impl GPSApp { .graphview() .create_node(element_name, GPS::ElementInfo::element_type(element_name)); let node_id = node.id(); - if GPS::ElementInfo::element_is_uri_src_handler(element_name) { - GPSUI::dialog::get_file_from_dialog(self, false, move |app, filename| { - GPS_DEBUG!("Open file {}", filename); - let mut properties: HashMap = HashMap::new(); - properties.insert(String::from("location"), filename); - if let Some(node) = graphbook::current_graphtab(&app).graphview().node(node_id) { - node.update_properties(&properties); - } - }); + if let Some((prop_name, file_chooser)) = + GPS::ElementInfo::element_is_uri_src_handler(element_name) + { + if file_chooser { + GPSUI::dialog::get_file_from_dialog( + self, + GPSUI::dialog::FileDialogType::OpenAll, + move |app, filename| { + GPS_DEBUG!("Open file {}", filename); + let mut properties: HashMap = HashMap::new(); + properties.insert(prop_name.clone(), filename); + if let Some(node) = + graphbook::current_graphtab(&app).graphview().node(node_id) + { + node.update_properties(&properties); + } + }, + ); + } else { + GPSUI::dialog::create_input_dialog( + self, + "Enter uri", + "uri", + "", + move |app, uri| { + GPS_DEBUG!("Open uri {}", uri); + let mut properties: HashMap = HashMap::new(); + properties.insert(String::from("uri"), uri); + if let Some(node) = + graphbook::current_graphtab(&app).graphview().node(node_id) + { + node.update_properties(&properties); + } + }, + ); + } + } else if let Some((prop_name, file_chooser)) = + GPS::ElementInfo::element_is_uri_sink_handler(element_name) + { + if file_chooser { + GPSUI::dialog::get_file_from_dialog( + self, + GPSUI::dialog::FileDialogType::SaveAll, + move |app, filename| { + GPS_DEBUG!("Save file {}", filename); + let mut properties: HashMap = HashMap::new(); + properties.insert(prop_name.clone(), filename); + if let Some(node) = + graphbook::current_graphtab(&app).graphview().node(node_id) + { + node.update_properties(&properties); + } + }, + ); + } else { + GPSUI::dialog::create_input_dialog( + self, + "Enter uri", + "uri", + "", + move |app, uri| { + GPS_DEBUG!("Save uri {}", uri); + let mut properties: HashMap = HashMap::new(); + properties.insert(String::from("uri"), uri); + if let Some(node) = + graphbook::current_graphtab(&app).graphview().node(node_id) + { + node.update_properties(&properties); + } + }, + ); + } } graphbook::current_graphtab(self).graphview().add_node(node); for input in inputs { diff --git a/src/gps/element.rs b/src/gps/element.rs index f335ca4..28fefb9 100644 --- a/src/gps/element.rs +++ b/src/gps/element.rs @@ -237,9 +237,17 @@ impl ElementInfo { ElementInfo::element_properties(&element) } - pub fn element_is_uri_src_handler(element_name: &str) -> bool { - let feature = ElementInfo::element_feature(element_name).expect("Unable to get feature"); + pub fn element_has_property(element: &gst::Element, property_name: &str) -> bool { + let properties = ElementInfo::element_properties(element) + .unwrap_or_else(|_| panic!("Couldn't get properties for {}", element.name())); + properties.keys().any(|name| name == property_name) + } + + pub fn element_is_uri_src_handler(element_name: &str) -> Option<(String, bool)> { + let feature: gst::PluginFeature = + ElementInfo::element_feature(element_name).expect("Unable to get feature"); + let mut file_chooser = false; let factory = feature .downcast::() .expect("Unable to get the factory from the feature"); @@ -247,10 +255,52 @@ impl ElementInfo { .create() .build() .expect("Unable to create an element from the feature"); - match element.dynamic_cast::() { - Ok(uri_handler) => uri_handler.uri_type() == gst::URIType::Src, - Err(_e) => false, + if let Ok(uri_handler) = element.clone().dynamic_cast::() { + let search_strings = ["file", "pushfile"]; + file_chooser = search_strings + .iter() + .any(|s| uri_handler.protocols().contains(&glib::GString::from(*s))); } + + if element.is::() || ElementInfo::element_type(element_name) == NodeType::Source { + if ElementInfo::element_has_property(&element, "uri") { + return Some((String::from("uri"), file_chooser)); + } + if ElementInfo::element_has_property(&element, "location") { + return Some((String::from("location"), file_chooser)); + } + } + + None + } + + pub fn element_is_uri_sink_handler(element_name: &str) -> Option<(String, bool)> { + let feature = ElementInfo::element_feature(element_name).expect("Unable to get feature"); + let mut file_chooser = false; + let factory = feature + .downcast::() + .expect("Unable to get the factory from the feature"); + let element = factory + .create() + .build() + .expect("Unable to create an element from the feature"); + + if let Ok(uri_handler) = element.clone().dynamic_cast::() { + file_chooser = uri_handler + .protocols() + .contains(&glib::GString::from("file")) + } + + if ElementInfo::element_type(element_name) == NodeType::Sink { + if ElementInfo::element_has_property(&element, "uri") { + return Some((String::from("uri"), file_chooser)); + } + if ElementInfo::element_has_property(&element, "location") { + return Some((String::from("location"), file_chooser)); + } + } + + None } pub fn element_supports_new_pad_request( diff --git a/src/graphbook.rs b/src/graphbook.rs index 44a7e99..14042ba 100644 --- a/src/graphbook.rs +++ b/src/graphbook.rs @@ -534,10 +534,10 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) { GPS_TRACE!("link double clicked id={}", link_id); let link = current_graphtab(&app).graphview().link(link_id).unwrap(); GPSUI::dialog::create_input_dialog( + &app, "Enter caps filter description", "description", &link.name(), - &app, move |app, link_desc| { current_graphtab(&app) .graphview() diff --git a/src/ui/dialog.rs b/src/ui/dialog.rs index 850a663..3c94b33 100644 --- a/src/ui/dialog.rs +++ b/src/ui/dialog.rs @@ -12,6 +12,14 @@ use gtk::glib; use gtk::prelude::*; use gtk::{ApplicationWindow, FileChooserAction, FileChooserDialog, FileFilter, ResponseType}; +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FileDialogType { + Save, + Open, + OpenAll, + SaveAll, +} + pub fn create_dialog( name: &str, app: &GPSApp, @@ -50,10 +58,10 @@ pub fn create_dialog( } pub fn create_input_dialog( + app: &GPSApp, dialog_name: &str, input_name: &str, default_value: &str, - app: &GPSApp, f: F, ) { let dialog = gtk::Dialog::with_buttons( @@ -104,12 +112,16 @@ pub fn create_input_dialog( dialog.show(); } -pub fn get_file_from_dialog(app: &GPSApp, save: bool, f: F) { +pub fn get_file_from_dialog( + app: &GPSApp, + dlg_type: FileDialogType, + f: F, +) { let mut message = "Open file"; let mut ok_button = "Open"; let cancel_button = "Cancel"; let mut action = FileChooserAction::Open; - if save { + if dlg_type == FileDialogType::Save || dlg_type == FileDialogType::SaveAll { message = "Save file"; ok_button = "Save"; action = FileChooserAction::Save; @@ -127,13 +139,15 @@ pub fn get_file_from_dialog(app: &GPSApp, save: (cancel_button, ResponseType::Cancel), ], ); - if save { + if dlg_type == FileDialogType::Save { file_chooser.set_current_name("untitled.gps"); } - let filter = FileFilter::new(); - filter.add_pattern("*.gps"); - filter.set_name(Some("GPS Files (*.gps)")); - file_chooser.add_filter(&filter); + if dlg_type == FileDialogType::Open { + let filter = FileFilter::new(); + filter.add_pattern("*.gps"); + filter.set_name(Some("GPS Files (*.gps)")); + file_chooser.add_filter(&filter); + } let app_weak = app.downgrade(); file_chooser.connect_response(move |d: &FileChooserDialog, response: ResponseType| {