diff --git a/src/app/browser/window.rs b/src/app/browser/window.rs index d13014e7..69909a7c 100644 --- a/src/app/browser/window.rs +++ b/src/app/browser/window.rs @@ -126,6 +126,13 @@ impl Window { } }); + action.open.on_activate({ + let tab = tab.clone(); + move |position, request| { + tab.open(position, &request, true); + } + }); + // Init struct Self { action, tab, g_box } } diff --git a/src/app/browser/window/action/open.rs b/src/app/browser/window/action/open.rs index f1a39256..98649d12 100644 --- a/src/app/browser/window/action/open.rs +++ b/src/app/browser/window/action/open.rs @@ -1,8 +1,9 @@ use gtk::{ - gio::SimpleAction, - glib::uuid_string_random, + gio::{Cancellable, SimpleAction}, + glib::SignalHandlerId, prelude::{ActionExt, ToVariant}, }; +use std::cell::RefCell; // Defaults @@ -11,6 +12,7 @@ const DEFAULT_STATE: i32 = -1; /// [SimpleAction](https://docs.gtk.org/gio/class.SimpleAction.html) wrapper for `Open` action pub struct Open { + cancellable: RefCell, pub simple_action: SimpleAction, } @@ -26,8 +28,9 @@ impl Open { /// Create new `Self` pub fn new() -> Self { Self { + cancellable: RefCell::new(Cancellable::new()), simple_action: SimpleAction::new_stateful( - &uuid_string_random(), + >k::glib::uuid_string_random(), None, &DEFAULT_STATE.to_variant(), ), @@ -48,11 +51,16 @@ impl Open { ) } - // Events + // Actions + + /// Formatted action connector for external implementation + pub fn on_activate(&self, callback: impl Fn(Option, String) + 'static) -> SignalHandlerId { + use gtk::{prelude::FileExt, FileDialog, Window}; + use std::rc::Rc; + + let cancellable = self.cancellable(); + let callback = Rc::new(callback); - /// Define callback function for - /// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal - pub fn connect_activate(&self, callback: impl Fn(Option) + 'static) { self.simple_action.connect_activate(move |this, _| { let state = this .state() @@ -60,11 +68,37 @@ impl Open { .get::() .expect("Parameter type does not match `i32`"); - callback(if state == DEFAULT_STATE { - None - } else { - Some(state) - }) - }); + FileDialog::builder() + .build() + .open(Window::NONE, Some(&cancellable), { + let callback = callback.clone(); + move |result| { + if let Ok(file) = result { + callback( + if state == DEFAULT_STATE { + None + } else { + Some(state) + }, + format!("file://{}", file.path().unwrap().to_str().unwrap()), + ) + } + } + }); + }) + } + + // Tools + + /// Gent new `Cancellable` by cancel previous one + fn cancellable(&self) -> Cancellable { + use gtk::prelude::CancellableExt; + + let cancellable = self.cancellable.replace(Cancellable::new()); + if !cancellable.is_cancelled() { + cancellable.cancel(); + } + + self.cancellable.borrow().clone() } } diff --git a/src/app/browser/window/tab.rs b/src/app/browser/window/tab.rs index fe19d51d..5f1b4bc5 100644 --- a/src/app/browser/window/tab.rs +++ b/src/app/browser/window/tab.rs @@ -303,6 +303,12 @@ impl Tab { } } + pub fn open(&self, page_position: Option, request: &str, is_snap_history: bool) { + if let Some(item) = self.item(page_position) { + item.action.load.activate(Some(request), is_snap_history); + } + } + pub fn clean( &self, transaction: &Transaction,