diff --git a/src/components/editor/mod.rs b/src/components/editor/mod.rs index dceee0c..7766264 100644 --- a/src/components/editor/mod.rs +++ b/src/components/editor/mod.rs @@ -3,9 +3,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ pub mod imp; +use gio::Cancellable; use gtk::prelude::*; use gtk::subclass::prelude::*; -use sourceview::{prelude::*, Buffer, FileExt as SourceFileExt, FileLoader, LanguageManager}; +use sourceview::{ + prelude::*, Buffer, FileExt as SourceFileExt, FileLoader, FileSaver, LanguageManager, +}; glib::wrapper! { pub struct EchidnaCoreEditor(ObjectSubclass) @@ -85,4 +88,50 @@ impl EchidnaCoreEditor { pub fn file(&self) -> sourceview::File { self.property("file").expect("Could not get property 'file' of EchidnaCoreEditor").get::().expect("Could not get property 'file' of EchidnaCoreEditor because its type is not IsA") } + + pub fn save_file(&self, save_as: Option<&gio::File>) -> Result<(), &str> { + let window_imp = self.to_imp(); + let buffer = self.to_imp().sourceview.buffer().downcast::(); + + match buffer { + Ok(buffer) => { + let cancellable = Cancellable::new(); + let mut file_saver: Option = None; + let result: Result<(), &str> = match save_as { + Some(file) => { + file_saver = Some(FileSaver::with_target(&buffer, &self.file(), file)); + Ok(()) + } + None => match self.file().location() { + Some(_) => { + file_saver = Some(FileSaver::new(&buffer, &self.file())); + Ok(()) + } + None => Err("The file location must exist. Please do \"Save As\""), + }, + }; + + match result { + Err(result) => Err(result), + Ok(_) => { + file_saver.unwrap().save_async( + glib::Priority::default(), + Some(&cancellable), + |_, _| {}, + |result| { + if result.is_err() { + panic!(format!( + "Found an error while saving the file:\n{}", + result.err().expect("No error") + )) + } + }, + ); + Ok(()) + } + } + } + Err(_) => Err("Can't downcast the buffer to GtkSourceBuffer."), + } + } } diff --git a/src/components/window/file.rs b/src/components/window/file.rs index a9e06e6..4ff4404 100644 --- a/src/components/window/file.rs +++ b/src/components/window/file.rs @@ -2,20 +2,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::lib::prelude::*; - use crate::components::editor::EchidnaCoreEditor; -use gio::Cancellable; -use glib::{clone, Priority}; +use crate::lib::prelude::*; +use glib::clone; use gtk::{ prelude::*, subclass::prelude::*, FileChooserAction, FileChooserNative, Label, ResponseType, }; -use sourceview::{prelude::*, Buffer, File, FileSaver}; +use sourceview::{File, FileExt as SourceFileExt}; pub trait FileImplementedEditor { fn action_open_file(&self); fn open_file(notebook: >k::Notebook, file: gio::File); fn action_save_file_as(&self); + fn action_save_file(&self); } impl FileImplementedEditor for super::EchidnaWindow { @@ -77,7 +76,6 @@ impl FileImplementedEditor for super::EchidnaWindow { ))), ); } - fn action_save_file_as(&self) { let dialog = FileChooserNative::new( Some("Save File As"), @@ -95,44 +93,24 @@ impl FileImplementedEditor for super::EchidnaWindow { move |dialog, response| { if response == ResponseType::Accept { let file = dialog.file().expect(""); - let window_imp = window.to_imp(); - let page: EchidnaCoreEditor; - - match window_imp.notebook - .nth_page( - Some(window_imp.notebook - .current_page() - .expect( - "No tabs is the current tab, probably all tabs closed. No files to save" - ) - ) - ).expect( - "Couldn't get the page of the current index. Try again." - ).downcast::() { - Ok(res) => page = res, - Err(e) => panic!("We got an error when trying to downcast the current tab page into EchidnaCoreEditor:\n{}", e) - } - - let buffer: Buffer = page.to_imp().sourceview.buffer().downcast().expect("Could not downcast the editor's buffer to GtkSourceBuffer."); - let cancellable = Cancellable::new(); - - let file_saver = FileSaver::with_target( - &buffer, - &page.file(), &file); - file_saver.save_async( - Priority::default(), - Some(&cancellable), - |_, _| {}, - |result| { - if result.is_err() { - panic!("Found an error while saving the file:\n{}", result.err().expect("No error")) - } - }); - - } + let tab: EchidnaCoreEditor = window.get_current_tab().expect("error"); + tab.save_file(Some(&file)); + } dialog.destroy(); })); } + + fn action_save_file(&self) { + let page: EchidnaCoreEditor = self + .get_current_tab() + .expect("Can't find the current tab because there are no tabs."); + match page.file().location() { + Some(_) => { + page.save_file(None); + } + None => self.action_save_file_as(), + } + } } diff --git a/src/components/window/menubar.rs b/src/components/window/menubar.rs index f51f47f..da81ac0 100644 --- a/src/components/window/menubar.rs +++ b/src/components/window/menubar.rs @@ -122,5 +122,16 @@ impl MenubarImplementedEditor for EchidnaWindow { window.action_save_file_as(); })); } + { + let action_save = SimpleAction::new("save", None); + + self.add_action(&action_save); + + action_save.connect_activate(clone!(@weak self as window => + move |_, _| { + window.action_save_file(); + } + )); + } } } diff --git a/src/components/window/mod.rs b/src/components/window/mod.rs index 40ed731..d692722 100644 --- a/src/components/window/mod.rs +++ b/src/components/window/mod.rs @@ -6,7 +6,7 @@ pub mod file; pub mod imp; pub mod menubar; -use glib::object::IsA; +use glib::object::{Cast, IsA}; use gtk::subclass::prelude::*; glib::wrapper! { @@ -28,4 +28,25 @@ impl EchidnaWindow { pub fn to_imp(&self) -> &imp::EchidnaWindow { imp::EchidnaWindow::from_instance(self) } + + pub fn get_current_tab>(&self) -> Result { + let window_imp = self.to_imp(); + let nth = window_imp.notebook.current_page(); + + match nth { + None => Err("No tabs are currently opened, maybe there are no tabs."), + Some(nth) => { + let page = window_imp + .notebook + .nth_page(Some(nth)) + .expect("Couldn't get the page of the current index."); + + match page.downcast::() + { + Ok(page) => Ok(page), + Err(e) => Err("Cannot downcast to type parameter A. Maybe it's not in the type you are looking for."), + } + } + } + } }