diff --git a/Cargo.lock b/Cargo.lock
index 9326399..a961a24 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -20,12 +20,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-[[package]]
-name = "bumpalo"
-version = "3.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
-
[[package]]
name = "cairo-rs"
version = "0.14.7"
@@ -68,12 +62,6 @@ dependencies = [
"smallvec",
]
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
[[package]]
name = "echidna"
version = "0.1.0"
@@ -87,7 +75,6 @@ dependencies = [
"serde",
"serde_json",
"sourceview5",
- "webbrowser",
]
[[package]]
@@ -438,36 +425,12 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
-[[package]]
-name = "js-sys"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
[[package]]
name = "libc"
version = "0.2.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
-[[package]]
-name = "log"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "memoffset"
version = "0.6.4"
@@ -843,87 +806,6 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
-dependencies = [
- "bumpalo",
- "lazy_static",
- "log",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
-
-[[package]]
-name = "web-sys"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "webbrowser"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a"
-dependencies = [
- "web-sys",
- "widestring",
- "winapi",
-]
-
-[[package]]
-name = "widestring"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
-
[[package]]
name = "winapi"
version = "0.3.9"
diff --git a/Cargo.toml b/Cargo.toml
index 65a0203..3265340 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "echidna"
version = "0.1.0"
-edition = "2018"
+edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -14,5 +14,4 @@ serde = { version = "^1.0.130", features = ["derive"] }
relative-path = "^1.5.0"
gdk = { version = "^0.3.0", package = "gdk4"}
sourceview = { package = "sourceview5", version = "^0.1.0", git = "https://github.com/EchidnaHQ/sourceview" }
-webbrowser = { version = "^0.5.5" }
once_cell = "1"
\ No newline at end of file
diff --git a/clippy.toml b/clippy.toml
deleted file mode 100644
index 171c603..0000000
--- a/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-"clippy::style" = "deny"
\ No newline at end of file
diff --git a/src/components/editor/editor.ui b/src/components/editor/editor.ui
index fa23e83..7b02782 100644
--- a/src/components/editor/editor.ui
+++ b/src/components/editor/editor.ui
@@ -15,10 +15,11 @@
diff --git a/src/components/editor/mod.rs b/src/components/editor/mod.rs
index dc218b9..2524e4c 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)
@@ -21,57 +24,59 @@ impl EchidnaCoreEditor {
// Without cloning it, for some reasons the Rust compiler complains about &this.to_imp().sourceview not being IsA
this_imp.minimap.set_view(&this_imp.sourceview.clone());
- if file.is_some() {
- let file = file.unwrap();
- let file_location = file
- .location()
- .expect("file is required to have a location");
+ match file {
+ Some(file) => {
+ let file_location = file
+ .location()
+ .expect("file is required to have a location");
- this.set_property("file", &file)
- .expect("Could not set the 'file' property of EchidnaCoreEditor");
+ this.set_property("file", &file)
+ .expect("Could not set the 'file' property of EchidnaCoreEditor");
- let cancellable = gio::Cancellable::new();
- let filepath = file_location.path().expect("No filepath");
- let info = file_location
- .query_info("*", gio::FileQueryInfoFlags::NONE, Some(&cancellable))
- .expect("Could not query the info for file");
+ let cancellable = gio::Cancellable::new();
+ let filepath = file_location.path().expect("No filepath");
+ let info = file_location
+ .query_info("*", gio::FileQueryInfoFlags::NONE, Some(&cancellable))
+ .expect("Could not query the info for file");
- let content_type = info
- .content_type()
- .expect(format!("It does not seem like {:?} has a type", filepath).as_str());
- {
- println!(
- "Opened {} and found its content type is {}.",
- "file",
- content_type.to_string()
- );
- let buffer = this_imp.sourceview.buffer().downcast::().expect("Cannot downcast the sourceview's buffer. Maybe the sourceview's buffer is not IsA.");
- let language_manager = LanguageManager::new();
- let language = language_manager.guess_language(
- Some(&info.name().to_str().expect(
- "Could not open the file because its name is not supported by Unicode.",
- )),
- None,
- );
+ let content_type = info
+ .content_type()
+ .expect(format!("It does not seem like {:?} has a type", filepath).as_str());
+ {
+ println!(
+ "Opened {} and found its content type is {}.",
+ "file",
+ content_type.to_string()
+ );
+ let buffer = this_imp.sourceview.buffer().downcast::().expect("Cannot downcast the sourceview's buffer. Maybe the sourceview's buffer is not IsA.");
+ let language_manager = LanguageManager::new();
+ let language = language_manager.guess_language(
+ Some(&info.name().to_str().expect(
+ "Could not open the file because its name is not supported by Unicode.",
+ )),
+ None,
+ );
- match language {
- Some(lang) => buffer.set_language(Some(&lang)),
- None => {}
- }
+ match language {
+ Some(lang) => buffer.set_language(Some(&lang)),
+ None => {}
+ }
- let file_loader: FileLoader = FileLoader::new(&buffer, &file);
+ let file_loader: FileLoader = FileLoader::new(&buffer, &file);
- file_loader.load_async(
+ file_loader.load_async(
glib::Priority::default(),
Some(&cancellable),
|_, _| {},
|result| {
if result.is_err() {
- panic!(result.err());
+ panic!("Found an error when loading the file into the text editor's buffer. {:#?}", result.err());
}
},
);
+ }
}
+ None => {}
}
this
}
@@ -83,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!(
+ "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/mod.rs b/src/components/mod.rs
index 1cd3fdb..5353e5a 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -5,11 +5,13 @@
pub mod app;
pub mod editor;
pub mod sidebar;
+pub mod tab_label;
pub mod window;
pub use app::EchidnaEditor;
pub use editor::EchidnaCoreEditor;
pub use sidebar::EchidnaSidebar;
+pub use tab_label::TabLabel;
pub use window::EchidnaWindow;
pub mod prelude {
diff --git a/src/components/sidebar/mod.rs b/src/components/sidebar/mod.rs
index 7aa464a..a7c145b 100644
--- a/src/components/sidebar/mod.rs
+++ b/src/components/sidebar/mod.rs
@@ -15,3 +15,9 @@ impl EchidnaSidebar {
glib::Object::new(&[]).expect("Failed to create 'EchidnaSidebar' component.")
}
}
+
+impl Default for EchidnaSidebar {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/src/components/sidebar/sidebar.ui b/src/components/sidebar/sidebar.ui
index e8f5b90..372a406 100644
--- a/src/components/sidebar/sidebar.ui
+++ b/src/components/sidebar/sidebar.ui
@@ -6,67 +6,71 @@
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
-->
\ No newline at end of file
diff --git a/src/components/tab_label/imp.rs b/src/components/tab_label/imp.rs
new file mode 100644
index 0000000..1765d20
--- /dev/null
+++ b/src/components/tab_label/imp.rs
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk::CompositeTemplate;
+
+#[derive(Default, CompositeTemplate)]
+#[template(file = "./tab-label.ui")]
+pub struct TabLabel {
+ #[template_child]
+ pub button: TemplateChild,
+}
+
+#[glib::object_subclass]
+impl ObjectSubclass for TabLabel {
+ const NAME: &'static str = "TabLabel";
+ type Type = super::TabLabel;
+ type ParentType = gtk::Box;
+
+ fn class_init(klass: &mut Self::Class) {
+ Self::bind_template(klass);
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+}
+
+impl ObjectImpl for TabLabel {}
+impl WidgetImpl for TabLabel {}
+impl BoxImpl for TabLabel {}
+
+impl BuildableImpl for TabLabel {
+ fn add_child(
+ &self,
+ buildable: &Self::Type,
+ _builder: >k::Builder,
+ child: &glib::Object,
+ _type_: Option<&str>,
+ ) {
+ buildable.prepend(child.downcast_ref::().unwrap());
+ }
+}
diff --git a/src/components/tab_label/mod.rs b/src/components/tab_label/mod.rs
new file mode 100644
index 0000000..e47b028
--- /dev/null
+++ b/src/components/tab_label/mod.rs
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+pub mod imp;
+use glib::IsA;
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+
+glib::wrapper! {
+ pub struct TabLabel(ObjectSubclass)
+ @extends gtk::Box, gtk::Widget,
+ @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
+}
+
+impl TabLabel {
+ pub fn new>(tab_label: Option<&U>) -> Self {
+ let this: Self = glib::Object::new(&[]).expect("Failed to create 'TabLabel' component.");
+
+ match tab_label {
+ Some(tab_label) => this.prepend(tab_label),
+ None => {}
+ }
+ this
+ }
+
+ pub fn to_imp(&self) -> &imp::TabLabel {
+ imp::TabLabel::from_instance(self)
+ }
+}
diff --git a/src/components/tab_label/tab-label.ui b/src/components/tab_label/tab-label.ui
new file mode 100644
index 0000000..a383977
--- /dev/null
+++ b/src/components/tab_label/tab-label.ui
@@ -0,0 +1,17 @@
+
+
+
+
+
+ GTK_ORIENTATION_HORIZONTAL
+
+
+ 0
+ window-close-symbolic
+
+
+
+
\ No newline at end of file
diff --git a/src/components/window/file.rs b/src/components/window/file.rs
index 2d25670..71e655c 100644
--- a/src/components/window/file.rs
+++ b/src/components/window/file.rs
@@ -4,18 +4,18 @@
use crate::components::editor::EchidnaCoreEditor;
use crate::lib::prelude::*;
-use gio::Cancellable;
-use glib::{clone, Priority};
+use glib::clone;
use gtk::{
- prelude::*, subclass::prelude::*, FileChooserAction, FileChooserDialog, Label, ResponseType,
+ 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_new_file(&self);
+ fn action_save_file(&self);
}
impl FileImplementedEditor for super::EchidnaWindow {
@@ -36,14 +36,12 @@ impl FileImplementedEditor for super::EchidnaWindow {
Perhaps some of the last points should not be implemented in this function but rather in another function that keeps track of every files.
*/
fn action_open_file(&self) {
- let dialog: FileChooserDialog = FileChooserDialog::new(
+ let dialog = FileChooserNative::new(
Some("Open a file"),
Some(self),
FileChooserAction::Open,
- &[
- ("Cancel", ResponseType::Cancel),
- ("Open", ResponseType::Accept),
- ],
+ Some("Open"),
+ Some("Cancel"),
);
dialog.set_visible(true);
@@ -69,7 +67,7 @@ impl FileImplementedEditor for super::EchidnaWindow {
notebook.prepend_closable_page(
&editor_page,
Some(&Label::new(Some(
- &file_location
+ file_location
.path()
.expect("The file's path is missing")
.file_name()
@@ -79,16 +77,13 @@ impl FileImplementedEditor for super::EchidnaWindow {
))),
);
}
-
fn action_save_file_as(&self) {
- let dialog = FileChooserDialog::new(
+ let dialog = FileChooserNative::new(
Some("Save File As"),
Some(self),
FileChooserAction::Save,
- &[
- ("Cancel", ResponseType::Cancel),
- ("Save", ResponseType::Accept),
- ],
+ Some("Open"),
+ Some("Cancel"),
);
dialog.set_current_name("untitled");
@@ -99,41 +94,9 @@ 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!(format!("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!(format!("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();
@@ -147,4 +110,16 @@ impl FileImplementedEditor for super::EchidnaWindow {
.notebook
.prepend_closable_page(&editor_page, Some(>k::Label::new(Some(&"Untitled"))));
}
+
+ 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 1cf13db..ed080aa 100644
--- a/src/components/window/menubar.rs
+++ b/src/components/window/menubar.rs
@@ -67,7 +67,7 @@ impl MenubarImplementedEditor for EchidnaWindow {
about_dialog.set_license_type(gtk::License::Mpl20);
about_dialog.set_program_name(Some("Echidna Code Editor"));
- about_dialog.set_website(Some("https://github.com/EchidnaHQ/Echidna"));
+ about_dialog.set_website(Some("https://gitlab.com/EchidnaHQ/Echidna"));
about_dialog.set_authors(&["FortressValkriye"]);
about_dialog.set_copyright(Some("Made with by ❤️ Echidna contributors"));
about_dialog.set_visible(true);
@@ -78,18 +78,20 @@ impl MenubarImplementedEditor for EchidnaWindow {
app.add_action(&act_report_issue);
- act_report_issue.connect_activate(|_action, _variant| {
- webbrowser::open("https://github.com/EchidnaHQ/Echidna/issues/new");
- });
+ act_report_issue.connect_activate(clone!(@weak self as win =>
+ move |_action, _variant| {
+ gtk::show_uri(Some(&win), "https://github.com/EchidnaHQ/Echidna/issues/new", gdk::CURRENT_TIME);
+ }));
}
{
let act_search_feature_requests = SimpleAction::new("search-feature-requests", None);
app.add_action(&act_search_feature_requests);
- act_search_feature_requests.connect_activate(|_action, _variant| {
- webbrowser::open("https://github.com/EchidnaHQ/Echidna/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement");
- });
+ act_search_feature_requests.connect_activate(clone!(@weak self as win =>
+ move |_action, _variant| {
+ gtk::show_uri(Some(&win), "https://github.com/EchidnaHQ/Echidna/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement", gdk::CURRENT_TIME);
+ }));
}
{
let act_window_close = SimpleAction::new("close", None);
@@ -130,5 +132,16 @@ impl MenubarImplementedEditor for EchidnaWindow {
window.action_new_file();
}));
}
+ {
+ 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."),
+ }
+ }
+ }
+ }
}
diff --git a/src/components/window/workspace.rs b/src/components/window/workspace.rs
index 9cc5c6c..7df8a13 100644
--- a/src/components/window/workspace.rs
+++ b/src/components/window/workspace.rs
@@ -9,7 +9,7 @@ use glib::clone;
use glib::subclass::types::ObjectSubclassExt;
use glib::types::Type;
use gtk::prelude::*;
-use gtk::{ApplicationWindow, FileChooserAction, FileChooserDialog, ResponseType, TreeStore};
+use gtk::{ApplicationWindow, FileChooserAction, FileChooserNative, ResponseType, TreeStore};
use relative_path::RelativePath;
use serde::{Deserialize, Serialize};
use std::path::Path;
@@ -46,14 +46,12 @@ impl WorkspaceImplementedEditor for EchidnaEditor {
_action: &SimpleAction,
_variant: Option<&glib::Variant>,
) {
- let dialog: FileChooserDialog = FileChooserDialog::new(
+ let dialog = FileChooserNative::new(
Some("Open a file"),
Some(&window),
FileChooserAction::Open,
- &[
- ("Cancel", ResponseType::Cancel),
- ("Open", ResponseType::Accept),
- ],
+ Some("Open"),
+ Some("Cancel"),
);
dialog.set_visible(true);
dialog.connect_response(clone!(@weak window, @weak app =>
@@ -78,7 +76,7 @@ impl WorkspaceImplementedEditor for EchidnaEditor {
*
* Basically, this is just the same as Open Folder, but it's many folders.
*
- * - Open a FileChooserDialog, set to only view .code-workspace files.
+ * - Open a FileChooserNative, set to only view .code-workspace files.
* - If the user pressed cancel, destroy the dialog. If the user opened a .code-workspace file:
* - Get the workspace file, load and parse its content, .code-workspace files are in JSON with comments. But JSON only should be fine, for now.
* - Iterate over folders listed in the workspace file.
@@ -125,31 +123,30 @@ impl WorkspaceImplementedEditor for EchidnaEditor {
self.open_folder(folder);
}
}
-}
-/**
- *
- *
- */
-fn recursive_add_files_into_tree_store(&self, parent_file: File, tree: &TreeStore) {
- let child_enumerate_cancellable = Cancellable::new();
- let child_files = parent_file
- .enumerate_children(
- "*",
- FileQueryInfoFlags::NONE,
- Some(&child_enumerate_cancellable),
- )
- .expect(
- format!(
- "Could not look up the children files of {:?} because:\n{:#?}",
- filepath
+ /**
+ *
+ *
+ */
+ fn recursive_add_files_into_tree_store(&self, parent_file: File, tree: &TreeStore) {
+ let child_enumerate_cancellable = Cancellable::new();
+ let child_files = parent_file
+ .enumerate_children(
+ "*",
+ FileQueryInfoFlags::NONE,
+ Some(&child_enumerate_cancellable),
)
- .as_str(),
- );
- let filepath = &parent_file
- .path()
- .expect("Could not get the file path of the file.");
-
+ .expect(
+ format!(
+ "Could not look up the children files of {:?} because:\n{:#?}",
+ filepath
+ )
+ .as_str(),
+ );
+ let filepath = &parent_file
+ .path()
+ .expect("Could not get the file path of the file.");
+
for file_iter in files {
let file_info = file_iter.expect();
let file = parent_file.child(file_info.name());
diff --git a/src/lib/closeable_tab.rs b/src/lib/closeable_tab.rs
index 85900df..ad3f17c 100644
--- a/src/lib/closeable_tab.rs
+++ b/src/lib/closeable_tab.rs
@@ -2,8 +2,9 @@
* 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::components::tab_label::TabLabel;
use glib::IsA;
-use gtk::{prelude::*, Box, Button, Widget};
+use gtk::{prelude::*, Widget};
pub trait ClosableTabImplementedNotebook {
fn prepend_closable_page, U: IsA>(
@@ -16,39 +17,24 @@ pub trait ClosableTabImplementedNotebook {
child: &T,
tab_label: Option<&U>,
) -> u32;
-
- fn create_closable_tab>(tab_label: Option<&U>) -> (Box, Button);
}
impl ClosableTabImplementedNotebook for gtk::Notebook {
- fn create_closable_tab>(tab_label: Option<&U>) -> (Box, Button) {
- let tab = Box::new(gtk::Orientation::Horizontal, 5);
- if tab_label.is_some() {
- tab.append(tab_label.unwrap());
- }
-
- let button = gtk::Button::new();
-
- button.set_icon_name("window-close-symbolic");
- button.set_has_frame(false);
-
- tab.append(&button);
-
- (tab, button)
- }
-
fn prepend_closable_page, U: IsA>(
&self,
child: &T,
tab_label: Option<&U>,
) -> u32 {
- let (tab, button) = &Self::create_closable_tab(tab_label);
- let page = self.prepend_page(child, Some(tab));
+ let tab_label_widget = TabLabel::new(tab_label);
+ let page = self.prepend_page(child, Some(&tab_label_widget));
- button.connect_clicked(glib::clone!(@weak self as notebook =>
- move |_| {
- notebook.remove_page(Some(page));
- }));
+ tab_label_widget
+ .to_imp()
+ .button
+ .connect_clicked(glib::clone!(@weak self as notebook =>
+ move |_| {
+ notebook.remove_page(Some(page));
+ }));
page
}
@@ -58,13 +44,16 @@ impl ClosableTabImplementedNotebook for gtk::Notebook {
child: &T,
tab_label: Option<&U>,
) -> u32 {
- let (tab, button) = &Self::create_closable_tab(tab_label);
- let page = self.append_page(child, Some(tab));
+ let tab_label_widget = TabLabel::new(tab_label);
+ let page = self.append_page(child, Some(&tab_label_widget));
- button.connect_clicked(glib::clone!(@weak self as notebook =>
- move |_| {
- notebook.remove_page(Some(page));
- }));
+ tab_label_widget
+ .to_imp()
+ .button
+ .connect_clicked(glib::clone!(@weak self as notebook =>
+ move |_| {
+ notebook.remove_page(Some(page));
+ }));
page
}