diff --git a/TODO.md b/TODO.md index 3b82bff..3302626 100644 --- a/TODO.md +++ b/TODO.md @@ -9,7 +9,7 @@ TODO: - [x] Create connection between element - [] Control the connection between element - [x] unable to connect in and in out and out - - [] unable to connnec element with incompatible caps. + - [] unable to connect element with incompatible caps. - [x] unable to connect a port which is already connected - [x] create contextual menu on pad or element - [] upclass the element @@ -22,7 +22,7 @@ TODO: - [] check that a node accept to create a port on request (input/output) - [x] select nodes/links with a Trait Selectable - [x] be able to remove a link by selecting it -- [] Connect the logs to the window +- [x] Connect the logs to the window - [] Create a window for the video output - [] Add multiple graphviews with tabs. @@ -30,7 +30,7 @@ TODO: - [x] crash with x11 on contextual menu - [] check that element exists before creating it on file load. -- [] open multiple times dialog (About) prevent to close it. +- [x] open multiple times dialog (About) prevent to close it. ## Code cleanup diff --git a/src/app.rs b/src/app.rs index 3b0819b..f2402d9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -31,9 +31,11 @@ use std::collections::HashMap; use std::rc::{Rc, Weak}; use std::{error, ops}; +use crate::logger; use crate::pipeline::{Pipeline, PipelineState}; use crate::plugindialogs; use crate::settings::Settings; +use crate::{GPS_DEBUG, GPS_ERROR}; use crate::graphmanager::{GraphView, Node, PortDirection}; @@ -189,6 +191,39 @@ impl GPSApp { dialog.set_resizable(false); dialog.show(); } + fn reset_logger_list(&self, logger_list: &TreeView) { + let model = ListStore::new(&[String::static_type()]); + logger_list.set_model(Some(&model)); + } + + fn setup_logger_list(&self) { + let logger_list: TreeView = self + .builder + .object("logger_list") + .expect("Couldn't get window"); + let column = TreeViewColumn::new(); + let cell = CellRendererText::new(); + + column.pack_start(&cell, true); + // Association of the view's column with the model's `id` column. + column.add_attribute(&cell, "text", 0); + column.set_title(""); + logger_list.append_column(&column); + self.reset_logger_list(&logger_list); + } + + fn add_to_logger_list(&self, log_entry: String) { + let logger_list: TreeView = self + .builder + .object("logger_list") + .expect("Couldn't get window"); + if let Some(model) = logger_list.model() { + let list_store = model + .dynamic_cast::() + .expect("Could not cast to ListStore"); + list_store.insert_with_values(None, &[(0, &log_entry)]); + } + } fn reset_favorite_list(&self, favorite_list: &TreeView) { let model = ListStore::new(&[String::static_type()]); @@ -222,7 +257,7 @@ impl GPSApp { .get(&iter, 0) .get::() .expect("Treeview selection, column 1"); - println!("{}", element_name); + GPS_DEBUG!("{}", element_name); app.add_new_element(&element_name); } }); @@ -239,7 +274,7 @@ impl GPSApp { .get(&iter, 0) .get::() .expect("Treeview selection, column 1"); - println!("{}", element_name); + GPS_DEBUG!("{}", element_name); let point = graphene::Point::new(x as f32,y as f32); @@ -292,6 +327,7 @@ impl GPSApp { } } } + pub fn display_plugin_list(app: &GPSApp) { let elements = Pipeline::elements_list().expect("Unable to obtain element's list"); plugindialogs::display_plugin_list(app, &elements); @@ -321,7 +357,7 @@ impl GPSApp { let app = upgrade_weak!(app_weak); GPSApp::get_file_from_dialog(&app, false, move |app, filename| { - println!("Open file {}", filename); + //logger::print_log(format!("Open file {}", filename)); app.load_graph(&filename).expect("Unable to open file"); }); })); @@ -336,7 +372,7 @@ impl GPSApp { let app = upgrade_weak!(app_weak); GPSApp::get_file_from_dialog(&app, true, move |app, filename| { - println!("Save file {}", filename); + GPS_DEBUG!("Save file {}", filename); app.save_graph(&filename).expect("Unable to save file"); }); })); @@ -373,6 +409,7 @@ impl GPSApp { move |_, _| { let app = upgrade_weak!(app_weak); app.clear_graph(); + GPS_ERROR!("clear graph"); } }); application.add_action(&action); @@ -538,7 +575,7 @@ impl GPSApp { // add an action to delete link let action = gio::SimpleAction::new("port.delete-link", None); action.connect_activate(glib::clone!(@weak pop_menu => move |_,_| { - println!("port.delete-link port {} node {}", port_id, node_id); + GPS_DEBUG!("port.delete-link port {} node {}", port_id, node_id); pop_menu.unparent(); })); application.add_action(&action); @@ -580,7 +617,7 @@ impl GPSApp { let app_weak = app.downgrade(); action.connect_activate(glib::clone!(@weak pop_menu => move |_,_| { let app = upgrade_weak!(app_weak); - println!("node.delete {}", node_id); + GPS_DEBUG!("node.delete {}", node_id); let node = app.graphview.borrow().node(&node_id).unwrap(); app.add_to_favorite_list(node.name()); pop_menu.unparent(); @@ -590,7 +627,7 @@ impl GPSApp { let app_weak = app.downgrade(); action.connect_activate(glib::clone!(@weak pop_menu => move |_,_| { let app = upgrade_weak!(app_weak); - println!("node.delete {}", node_id); + GPS_DEBUG!("node.delete {}", node_id); app.graphview.borrow_mut().remove_node(node_id); pop_menu.unparent(); })); @@ -600,7 +637,7 @@ impl GPSApp { let app_weak = app.downgrade(); action.connect_activate(glib::clone!(@weak pop_menu => move |_,_| { let app = upgrade_weak!(app_weak); - println!("node.request-pad-input {}", node_id); + GPS_DEBUG!("node.request-pad-input {}", node_id); let mut node = app.graphview.borrow_mut().node(&node_id).unwrap(); let port_id = app.graphview.borrow().next_port_id(); node.add_port(port_id, "in", PortDirection::Input); @@ -612,7 +649,7 @@ impl GPSApp { let app_weak = app.downgrade(); action.connect_activate(glib::clone!(@weak pop_menu => move |_,_| { let app = upgrade_weak!(app_weak); - println!("node.request-pad-output {}", node_id); + GPS_DEBUG!("node.request-pad-output {}", node_id); let mut node = app.graphview.borrow_mut().node(&node_id).unwrap(); let port_id = app.graphview.borrow_mut().next_port_id(); node.add_port(port_id, "out", PortDirection::Output); @@ -622,7 +659,7 @@ impl GPSApp { let action = gio::SimpleAction::new("node.properties", None); action.connect_activate(glib::clone!(@weak pop_menu => move |_,_| { - println!("node.properties {}", node_id); + GPS_DEBUG!("node.properties {}", node_id); let node = app.graphview.borrow().node(&node_id).unwrap(); plugindialogs::display_plugin_properties(&app, &node.name(), node_id); pop_menu.unparent(); @@ -638,6 +675,17 @@ impl GPSApp { // Setup the favorite list self.setup_favorite_list(); + + // Setup the logger to get messages into the TreeView + let (ready_tx, ready_rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + let app_weak = self.downgrade(); + logger::init_logger(ready_tx, logger::LogLevel::Debug); + self.setup_logger_list(); + let _ = ready_rx.attach(None, move |msg: String| { + let app = upgrade_weak!(app_weak, glib::Continue(false)); + app.add_to_logger_list(msg); + glib::Continue(true) + }); } // Downgrade to a weak reference @@ -654,7 +702,7 @@ impl GPSApp { let pads = Pipeline::pads(element_name, false); if Pipeline::element_is_uri_src_handler(element_name) { GPSApp::get_file_from_dialog(self, false, move |app, filename| { - println!("Open file {}", filename); + GPS_DEBUG!("Open file {}", filename); let node = app.graphview.borrow().node(&node_id).unwrap(); let mut properties: HashMap = HashMap::new(); properties.insert(String::from("location"), filename); diff --git a/src/gps.ui b/src/gps.ui index f4eded6..d8104eb 100644 --- a/src/gps.ui +++ b/src/gps.ui @@ -270,7 +270,7 @@ end - + diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..aaa421c --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,97 @@ +use glib::Sender; +use gtk::glib; +use once_cell::sync::Lazy; +use once_cell::sync::OnceCell; +use std::cell::RefCell; +use std::fmt; +use std::sync::{Arc, Mutex}; + +#[derive(Default)] +struct Logger { + pub log_sender: OnceCell>>>>, + pub log_level: OnceCell, +} + +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum LogLevel { + Error, + _Warning, + Info, + _Log, + Debug, +} +impl fmt::Display for LogLevel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +#[macro_export] +macro_rules! GPS_ERROR ( + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + logger::print_log(logger::LogLevel::Error, format_args!($($arg)*).to_string()); + }) +); + +#[macro_export] +macro_rules! GPS_WARN ( + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + logger::print_log(logger::LogLevel::Warning, format_args!($($arg)*).to_string()); + }) +); + +#[macro_export] +macro_rules! GPS_INFO ( + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + logger::print_log(logger::LogLevel::Info, format_args!($($arg)*).to_string()); + }) +); + +#[macro_export] +macro_rules! GPS_LOG ( + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + logger::print_log(logger::LogLevel::Log, format_args!($($arg)*).to_string()); + }) +); + +#[macro_export] +macro_rules! GPS_DEBUG ( + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + logger::print_log(logger::LogLevel::Debug, format_args!($($arg)*).to_string()); + }) +); + +static LOGGER: Lazy = Lazy::new(Logger::default); + +pub fn init_logger(sender: Sender, log_level: LogLevel) { + LOGGER + .log_sender + .set(Arc::new(Mutex::new(RefCell::new(sender)))) + .expect("init logger should be called once"); + let _ = LOGGER.log_level.set(log_level); +} + +pub fn print_log(log_level: LogLevel, msg: String) { + if log_level + <= *LOGGER + .log_level + .get() + .expect("Logger should be initialized before calling print_log") + { + let mut sender = LOGGER + .log_sender + .get() + .expect("Logger should be initialized before calling print_log") + .lock() + .expect("guarded"); + + if let Err(e) = sender.get_mut().send(format!("{}:{}", log_level, msg)) { + println!("Error: {}", e) + }; + } +} diff --git a/src/main.rs b/src/main.rs index 45eac1c..b575a0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,8 @@ mod macros; mod app; mod common; mod graphmanager; +#[macro_use] +mod logger; mod pipeline; mod plugindialogs; mod settings; diff --git a/src/pipeline.rs b/src/pipeline.rs index fbffacb..ab1fd32 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -18,6 +18,9 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::app::GPSApp; use crate::graphmanager::{GraphView, Node, NodeType, PortDirection}; +use crate::logger; +use crate::GPS_INFO; + use gst::prelude::*; use gstreamer as gst; use std::cell::{Cell, RefCell}; @@ -95,7 +98,7 @@ impl Pipeline { } pub fn create_pipeline(&self, description: &str) -> Result<(), Box> { - println!("Creating pipeline {}", description); + GPS_INFO!("Creating pipeline {}", description); /* create playbin */ @@ -335,7 +338,7 @@ impl Pipeline { let params = element.class().list_properties(); for param in params { - println!("Property_name {}", param.name()); + GPS_INFO!("Property_name {}", param.name()); if (param.flags() & glib::ParamFlags::READABLE) == glib::ParamFlags::READABLE || (param.flags() & glib::ParamFlags::READWRITE) == glib::ParamFlags::READWRITE { @@ -345,7 +348,7 @@ impl Pipeline { } else if let Some(value) = Pipeline::value_as_str(param.default_value()) { properties_list.insert(String::from(param.name()), value); } else { - println!("Unable to add property_name {}", param.name()); + GPS_INFO!("Unable to add property_name {}", param.name()); } } Ok(properties_list) diff --git a/src/settings.rs b/src/settings.rs index 1da93c9..31e33da 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; use crate::common; +use crate::logger; #[derive(Debug, Serialize, Deserialize, Default)] pub struct Settings { @@ -18,7 +19,7 @@ impl Settings { if let Some(parent_dir) = s.parent() { if !parent_dir.exists() { if let Err(e) = create_dir_all(parent_dir) { - println!( + GPS_ERROR!( "Error while trying to build settings snapshot_directory '{}': {}", parent_dir.display(), e @@ -64,7 +65,7 @@ impl Settings { Settings::settings_file_exist(); let s = Settings::get_settings_file_path(); if let Err(e) = serde_any::to_file(&s, settings) { - println!("Error while trying to save file: {} {}", s.display(), e); + GPS_ERROR!("Error while trying to save file: {} {}", s.display(), e); } } @@ -75,7 +76,7 @@ impl Settings { match serde_any::from_file::(&s) { Ok(s) => s, Err(e) => { - println!("Error while opening '{}': {}", s.display(), e); + GPS_ERROR!("Error while opening '{}': {}", s.display(), e); Settings::default() } }