Add option to save file, store settings and load them (#108)
This commit is contained in:
parent
a047380dbe
commit
6fab1a9368
58
Cargo.lock
generated
58
Cargo.lock
generated
|
@ -23,9 +23,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.34"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
|
||||
checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
|
@ -239,9 +239,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
|
||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -438,6 +438,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"crossbeam-channel 0.4.4",
|
||||
"czkawka_core",
|
||||
"directories-next",
|
||||
"futures",
|
||||
"gdk",
|
||||
"gio",
|
||||
|
@ -511,6 +512,16 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "directories-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "3.0.1"
|
||||
|
@ -531,6 +542,17 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
|
@ -1099,15 +1121,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.80"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
|
||||
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.6.5"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0"
|
||||
checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi",
|
||||
|
@ -1474,9 +1496,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3741934be594d77de1c8461ebcbbe866f585ea616a9753aa78f2bdc69f0e4579"
|
||||
checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
@ -2020,18 +2042,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.117"
|
||||
version = "1.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
|
||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.117"
|
||||
version = "1.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
|
||||
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.7",
|
||||
|
@ -2040,9 +2062,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.59"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
|
||||
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -2063,9 +2085,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85"
|
||||
checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
|
||||
|
||||
[[package]]
|
||||
name = "spin_sleep"
|
||||
|
|
|
@ -16,6 +16,7 @@ But the most important thing for me was to learn Rust and create a program usefu
|
|||
## Features
|
||||
- Written in memory safe Rust
|
||||
- Amazingly fast - due using more or less advanced algorithms and multithreading support
|
||||
- Free, Open Source without ads
|
||||
- CLI frontend, very fast and powerful with rich help
|
||||
- GUI GTK frontend - uses modern GTK 3 and looks similar to FSlint
|
||||
- Light/Dark theme match the appearance of the system(Linux only)
|
||||
|
|
|
@ -17,10 +17,15 @@ glib = "0.10.1"
|
|||
humansize = "1"
|
||||
chrono = "0.4"
|
||||
|
||||
# Used for sending stop signal across threads
|
||||
crossbeam-channel = "0.4.4"
|
||||
|
||||
# To get informations about progress
|
||||
futures = "0.3.8"
|
||||
|
||||
# For saving/loading config files to specific directories
|
||||
directories-next = "2.0.0"
|
||||
|
||||
# For opening files
|
||||
open = "1.4.0"
|
||||
|
||||
|
|
|
@ -881,6 +881,104 @@ Author: Rafał Mikrut
|
|||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="notebook_upper_settings">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_start">5</property>
|
||||
<property name="margin_end">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="column_homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="check_button_settings_save_at_exit">
|
||||
<property name="label" translatable="yes">Save configuration at exit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button_settings_save_configuration">
|
||||
<property name="label" translatable="yes">Save current configuration</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button_settings_load_configuration">
|
||||
<property name="label" translatable="yes">Load configuration</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button_settings_reset_configuration">
|
||||
<property name="label" translatable="yes">Reset configuration</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="check_button_settings_load_at_start">
|
||||
<property name="label" translatable="yes">Load configuration at start</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Settings</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
|
|
@ -34,13 +34,12 @@ pub fn connect_notebook_tabs(gui_data: &GuiData) {
|
|||
set_buttons(&mut *shared_buttons.borrow_mut().get_mut(page).unwrap(), &buttons_array, &buttons_names);
|
||||
// Upper notebook
|
||||
{
|
||||
//let upper_notebooks_labels = [/*"general",*/"included_directories","excluded_directories","excluded_items","allowed_extensions"];
|
||||
let mut hashmap: HashMap<&str, &str> = Default::default();
|
||||
//hashmap.insert("notebook_upper_general","general");
|
||||
hashmap.insert("notebook_upper_included_directories", "included_directories");
|
||||
hashmap.insert("notebook_upper_excluded_directories", "excluded_directories");
|
||||
hashmap.insert("notebook_upper_excluded_items", "excluded_items");
|
||||
hashmap.insert("notebook_upper_allowed_extensions", "allowed_extensions");
|
||||
hashmap.insert("notebook_upper_settings", "settings");
|
||||
|
||||
for tab in ¬ebook_upper_children_names {
|
||||
let name = hashmap.get(tab.as_str()).unwrap().to_string();
|
||||
|
|
|
@ -2,7 +2,7 @@ extern crate gtk;
|
|||
use crate::gui_data::GuiData;
|
||||
use gtk::prelude::*;
|
||||
|
||||
pub fn connect_upper_notebook(gui_data: &GuiData) {
|
||||
pub fn connect_selection_of_directories(gui_data: &GuiData) {
|
||||
// Add included directory
|
||||
{
|
||||
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
31
czkawka_gui/src/connect_settings.rs
Normal file
31
czkawka_gui/src/connect_settings.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
extern crate gtk;
|
||||
use crate::gui_data::GuiData;
|
||||
use crate::saving_loading::{load_configuration, reset_configuration, save_configuration};
|
||||
use gtk::prelude::*;
|
||||
|
||||
pub fn connect_settings(gui_data: &GuiData) {
|
||||
// Connect save configuration button
|
||||
{
|
||||
let gui_data = gui_data.clone();
|
||||
let button_settings_save_configuration = gui_data.button_settings_save_configuration.clone();
|
||||
button_settings_save_configuration.connect_clicked(move |_| {
|
||||
save_configuration(&gui_data, true);
|
||||
});
|
||||
}
|
||||
// Connect load configuration button
|
||||
{
|
||||
let gui_data = gui_data.clone();
|
||||
let button_settings_load_configuration = gui_data.button_settings_load_configuration.clone();
|
||||
button_settings_load_configuration.connect_clicked(move |_| {
|
||||
load_configuration(&gui_data, true);
|
||||
});
|
||||
}
|
||||
// Connect reset configuration button
|
||||
{
|
||||
let gui_data = gui_data.clone();
|
||||
let button_settings_reset_configuration = gui_data.button_settings_reset_configuration.clone();
|
||||
button_settings_reset_configuration.connect_clicked(move |_| {
|
||||
reset_configuration(&gui_data, true);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ pub struct GuiData {
|
|||
|
||||
// States
|
||||
pub main_notebooks_labels: [String; 8],
|
||||
pub upper_notebooks_labels: [String; 4],
|
||||
pub upper_notebooks_labels: [String; 5],
|
||||
pub buttons_labels: [String; 4],
|
||||
// Buttons state
|
||||
pub shared_buttons: Rc<RefCell<HashMap<String, HashMap<String, bool>>>>,
|
||||
|
@ -145,6 +145,14 @@ pub struct GuiData {
|
|||
pub grid_progress_stages: gtk::Grid,
|
||||
|
||||
pub button_stop_in_dialog: gtk::Button,
|
||||
|
||||
//// Settings
|
||||
pub check_button_settings_save_at_exit: gtk::CheckButton,
|
||||
pub check_button_settings_load_at_start: gtk::CheckButton,
|
||||
|
||||
pub button_settings_save_configuration: gtk::Button,
|
||||
pub button_settings_load_configuration: gtk::Button,
|
||||
pub button_settings_reset_configuration: gtk::Button,
|
||||
//// Threads
|
||||
|
||||
// Used for sending stop signal to thread
|
||||
|
@ -176,10 +184,11 @@ impl GuiData {
|
|||
"same_music".to_string(),
|
||||
];
|
||||
let upper_notebooks_labels = [
|
||||
/*"general",*/ "included_directories".to_string(),
|
||||
"included_directories".to_string(),
|
||||
"excluded_directories".to_string(),
|
||||
"excluded_items".to_string(),
|
||||
"allowed_extensions".to_string(),
|
||||
"settings".to_string(),
|
||||
];
|
||||
let buttons_labels = ["search".to_string(), "select".to_string(), "delete".to_string(), "save".to_string()];
|
||||
|
||||
|
@ -337,6 +346,14 @@ impl GuiData {
|
|||
|
||||
let button_stop_in_dialog: gtk::Button = builder.get_object("button_stop_in_dialog").unwrap();
|
||||
|
||||
//// Settings
|
||||
let check_button_settings_save_at_exit: gtk::CheckButton = builder.get_object("check_button_settings_save_at_exit").unwrap();
|
||||
let check_button_settings_load_at_start: gtk::CheckButton = builder.get_object("check_button_settings_load_at_start").unwrap();
|
||||
|
||||
let button_settings_save_configuration: gtk::Button = builder.get_object("button_settings_save_configuration").unwrap();
|
||||
let button_settings_load_configuration: gtk::Button = builder.get_object("button_settings_load_configuration").unwrap();
|
||||
let button_settings_reset_configuration: gtk::Button = builder.get_object("button_settings_reset_configuration").unwrap();
|
||||
|
||||
//// Threads
|
||||
// Types of messages to send to main thread where gui can be draw.
|
||||
|
||||
|
@ -426,6 +443,11 @@ impl GuiData {
|
|||
label_stage,
|
||||
grid_progress_stages,
|
||||
button_stop_in_dialog,
|
||||
check_button_settings_save_at_exit,
|
||||
check_button_settings_load_at_start,
|
||||
button_settings_save_configuration,
|
||||
button_settings_load_configuration,
|
||||
button_settings_reset_configuration,
|
||||
stop_sender,
|
||||
stop_receiver,
|
||||
}
|
||||
|
|
|
@ -4,9 +4,8 @@ use crate::gui_data::*;
|
|||
use crate::help_functions::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{SelectionMode, TreeView};
|
||||
use std::env;
|
||||
|
||||
pub fn startup_configuration(gui_data: &GuiData) {
|
||||
pub fn initialize_gui(gui_data: &GuiData) {
|
||||
//// Setup default look(duplicate finder)
|
||||
{
|
||||
let entry_info = gui_data.entry_info.clone();
|
||||
|
@ -24,7 +23,6 @@ pub fn startup_configuration(gui_data: &GuiData) {
|
|||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
||||
let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone();
|
||||
let entry_excluded_items = gui_data.entry_excluded_items.clone();
|
||||
|
||||
entry_info.set_text("Duplicated Files");
|
||||
|
||||
|
@ -201,7 +199,7 @@ pub fn startup_configuration(gui_data: &GuiData) {
|
|||
|
||||
// Set Included Directory
|
||||
{
|
||||
let col_types: [glib::types::Type; 2] = [glib::types::Type::String, glib::types::Type::String];
|
||||
let col_types: [glib::types::Type; 1] = [glib::types::Type::String];
|
||||
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
||||
|
||||
let mut tree_view_included_directory: gtk::TreeView = TreeView::with_model(&list_store);
|
||||
|
@ -210,32 +208,12 @@ pub fn startup_configuration(gui_data: &GuiData) {
|
|||
|
||||
create_tree_view_directories(&mut tree_view_included_directory);
|
||||
|
||||
let col_indices = [0, 1];
|
||||
|
||||
let current_dir: String = match env::current_dir() {
|
||||
Ok(t) => t.to_str().unwrap().to_string(),
|
||||
Err(_) => {
|
||||
if cfg!(target_family = "unix") {
|
||||
println!("Failed to read current directory, setting /home instead");
|
||||
"/home".to_string()
|
||||
} else if cfg!(target_family = "windows") {
|
||||
println!("Failed to read current directory, setting C:\\ instead");
|
||||
"C:\\".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let values: [&dyn ToValue; 2] = [¤t_dir, &(MAIN_ROW_COLOR.to_string())];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
|
||||
scrolled_window_included_directories.add(&tree_view_included_directory);
|
||||
scrolled_window_included_directories.show_all();
|
||||
}
|
||||
// Set Excluded Directory
|
||||
{
|
||||
let col_types: [glib::types::Type; 2] = [glib::types::Type::String, glib::types::Type::String];
|
||||
let col_types: [glib::types::Type; 1] = [glib::types::Type::String];
|
||||
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
||||
|
||||
let mut tree_view_excluded_directory: gtk::TreeView = TreeView::with_model(&list_store);
|
||||
|
@ -244,26 +222,8 @@ pub fn startup_configuration(gui_data: &GuiData) {
|
|||
|
||||
create_tree_view_directories(&mut tree_view_excluded_directory);
|
||||
|
||||
let col_indices = [0, 1];
|
||||
|
||||
if cfg!(target_family = "unix") {
|
||||
for i in ["/proc", "/dev", "/sys", "/run", "/snap"].iter() {
|
||||
let values: [&dyn ToValue; 2] = [&i, &(MAIN_ROW_COLOR.to_string())];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
}
|
||||
|
||||
scrolled_window_excluded_directories.add(&tree_view_excluded_directory);
|
||||
scrolled_window_excluded_directories.show_all();
|
||||
}
|
||||
// Set Excluded Items
|
||||
{
|
||||
if cfg!(target_family = "unix") {
|
||||
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*/Trash/*");
|
||||
}
|
||||
if cfg!(target_family = "windows") {
|
||||
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*:/windows/*");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,12 +7,14 @@ mod connect_compute_results;
|
|||
mod connect_notebook_tabs;
|
||||
mod connect_popovers;
|
||||
mod connect_progress_window;
|
||||
mod connect_upper_notebook;
|
||||
mod connect_selection_of_directories;
|
||||
mod connect_settings;
|
||||
mod create_tree_view;
|
||||
mod double_click_opening;
|
||||
mod gui_data;
|
||||
mod help_functions;
|
||||
mod startup_configuration;
|
||||
mod initialize_gui;
|
||||
mod saving_loading;
|
||||
|
||||
use czkawka_core::*;
|
||||
|
||||
|
@ -26,9 +28,11 @@ use crate::connect_compute_results::*;
|
|||
use crate::connect_notebook_tabs::*;
|
||||
use crate::connect_popovers::*;
|
||||
use crate::connect_progress_window::*;
|
||||
use crate::connect_upper_notebook::*;
|
||||
use crate::connect_selection_of_directories::*;
|
||||
use crate::connect_settings::*;
|
||||
use crate::gui_data::*;
|
||||
use crate::startup_configuration::*;
|
||||
use crate::initialize_gui::*;
|
||||
use crate::saving_loading::{load_configuration, reset_configuration, save_configuration};
|
||||
use gtk::prelude::*;
|
||||
use std::{env, process};
|
||||
|
||||
|
@ -66,7 +70,10 @@ fn main() {
|
|||
let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::Sender<temporary::ProgressData>, futures::channel::mpsc::Receiver<temporary::ProgressData>) = futures::channel::mpsc::channel(20);
|
||||
let (futures_sender_zeroed, futures_receiver_zeroed): (futures::channel::mpsc::Sender<zeroed::ProgressData>, futures::channel::mpsc::Receiver<zeroed::ProgressData>) = futures::channel::mpsc::channel(20);
|
||||
|
||||
startup_configuration(&gui_data);
|
||||
initialize_gui(&gui_data);
|
||||
reset_configuration(&gui_data, false); // Fallback for invalid loading setting project
|
||||
load_configuration(&gui_data, false);
|
||||
|
||||
connect_button_delete(&gui_data);
|
||||
connect_button_save(&gui_data);
|
||||
connect_button_search(
|
||||
|
@ -84,7 +91,7 @@ fn main() {
|
|||
connect_button_select(&gui_data);
|
||||
connect_button_stop(&gui_data);
|
||||
connect_notebook_tabs(&gui_data);
|
||||
connect_upper_notebook(&gui_data);
|
||||
connect_selection_of_directories(&gui_data);
|
||||
connect_popovers(&gui_data);
|
||||
connect_compute_results(&gui_data, glib_stop_receiver);
|
||||
connect_progress_window(
|
||||
|
@ -98,12 +105,17 @@ fn main() {
|
|||
futures_receiver_temporary,
|
||||
futures_receiver_zeroed,
|
||||
);
|
||||
connect_settings(&gui_data);
|
||||
|
||||
// Quit the program when X in main window was clicked
|
||||
gui_data.window_main.connect_delete_event(|_, _| {
|
||||
{
|
||||
let window_main = gui_data.window_main.clone();
|
||||
window_main.connect_delete_event(move |_, _| {
|
||||
save_configuration(&gui_data, false); // Save configuration at exit
|
||||
gtk::main_quit();
|
||||
Inhibit(false)
|
||||
});
|
||||
}
|
||||
|
||||
// We start the gtk main loop.
|
||||
gtk::main();
|
||||
|
|
354
czkawka_gui/src/saving_loading.rs
Normal file
354
czkawka_gui/src/saving_loading.rs
Normal file
|
@ -0,0 +1,354 @@
|
|||
use crate::gui_data::*;
|
||||
use crate::help_functions::{get_list_store, ColumnsDirectory};
|
||||
use directories_next::ProjectDirs;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{EntryExt, GtkListStoreExt, ToggleButtonExt};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::{env, fs};
|
||||
|
||||
const SAVE_FILE_NAME: &str = "czkawka_gui_config.txt";
|
||||
|
||||
pub fn save_configuration(gui_data: &GuiData, manual_execution: bool) {
|
||||
let check_button_settings_save_at_exit = gui_data.check_button_settings_save_at_exit.clone();
|
||||
let text_view_errors = gui_data.text_view_errors.clone();
|
||||
|
||||
if !manual_execution && !check_button_settings_save_at_exit.get_active() {
|
||||
// When check button is deselected, not save configuration at exit
|
||||
return;
|
||||
}
|
||||
if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") {
|
||||
// Lin: /home/alice/.config/barapp
|
||||
// Win: C:\Users\Alice\AppData\Roaming\Foo Corp\Bar App\config
|
||||
// Mac: /Users/Alice/Library/Application Support/com.Foo-Corp.Bar-App
|
||||
|
||||
let config_dir = proj_dirs.config_dir();
|
||||
if config_dir.exists() {
|
||||
if !config_dir.is_dir() {
|
||||
text_view_errors
|
||||
.get_buffer()
|
||||
.unwrap()
|
||||
.set_text(format!("Cannot create save file inside {} because this isn't a folder.", config_dir.display()).as_str());
|
||||
return;
|
||||
}
|
||||
} else if fs::create_dir(config_dir).is_err() {
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Failed configuration to create configuration folder {}", config_dir.display()).as_str());
|
||||
return;
|
||||
}
|
||||
|
||||
let mut data_to_save: Vec<String> = Vec::new();
|
||||
|
||||
//// Included Directories
|
||||
data_to_save.push("--included_directories:".to_string());
|
||||
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
||||
let list_store = get_list_store(&scrolled_window_included_directories);
|
||||
if let Some(iter) = list_store.get_iter_first() {
|
||||
loop {
|
||||
data_to_save.push(list_store.get_value(&iter, ColumnsDirectory::Path as i32).get::<String>().unwrap().unwrap());
|
||||
if !list_store.iter_next(&iter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// Excluded Directories
|
||||
data_to_save.push("--excluded_directories:".to_string());
|
||||
let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone();
|
||||
let list_store = get_list_store(&scrolled_window_excluded_directories);
|
||||
if let Some(iter) = list_store.get_iter_first() {
|
||||
loop {
|
||||
data_to_save.push(list_store.get_value(&iter, ColumnsDirectory::Path as i32).get::<String>().unwrap().unwrap());
|
||||
if !list_store.iter_next(&iter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// Excluded Items
|
||||
data_to_save.push("--excluded_items:".to_string());
|
||||
let entry_excluded_items = gui_data.entry_excluded_items.clone();
|
||||
for item in entry_excluded_items.get_text().split(',') {
|
||||
if item.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
data_to_save.push(item.to_string());
|
||||
}
|
||||
|
||||
//// Allowed extensions
|
||||
data_to_save.push("--allowed_extensions:".to_string());
|
||||
let entry_allowed_extensions = gui_data.entry_allowed_extensions.clone();
|
||||
for extension in entry_allowed_extensions.get_text().split(',') {
|
||||
if extension.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
data_to_save.push(extension.to_string());
|
||||
}
|
||||
|
||||
//// Save at exit
|
||||
data_to_save.push("--save_at_exit:".to_string());
|
||||
let check_button_settings_save_at_exit = gui_data.check_button_settings_save_at_exit.clone();
|
||||
data_to_save.push(check_button_settings_save_at_exit.get_active().to_string());
|
||||
|
||||
//// Load at start
|
||||
data_to_save.push("--load_at_start:".to_string());
|
||||
let check_button_settings_load_at_start = gui_data.check_button_settings_load_at_start.clone();
|
||||
data_to_save.push(check_button_settings_load_at_start.get_active().to_string());
|
||||
|
||||
// Creating/Opening config file
|
||||
|
||||
let config_file = config_dir.join(Path::new(SAVE_FILE_NAME));
|
||||
|
||||
let mut config_file_handler = match File::create(&config_file) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Failed to create config file {}", config_file.display()).as_str());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for data in data_to_save {
|
||||
match writeln!(config_file_handler, "{}", data) {
|
||||
Ok(_) => {
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Saved configuration to file {}", config_file.display()).as_str());
|
||||
}
|
||||
Err(_) => {
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Failed to save configuration data to file {}", config_file.display()).as_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
text_view_errors.get_buffer().unwrap().set_text("Failed to get home directory, so can't save file.");
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeOfLoadedData {
|
||||
None,
|
||||
IncludedDirectories,
|
||||
ExcludedDirectories,
|
||||
ExcludedItems,
|
||||
AllowedExtensions,
|
||||
LoadingAtStart,
|
||||
SavingAtExit,
|
||||
}
|
||||
|
||||
pub fn load_configuration(gui_data: &GuiData, manual_execution: bool) {
|
||||
let text_view_errors = gui_data.text_view_errors.clone();
|
||||
if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") {
|
||||
// Lin: /home/alice/.config/barapp
|
||||
// Win: C:\Users\Alice\AppData\Roaming\Foo Corp\Bar App\config
|
||||
// Mac: /Users/Alice/Library/Application Support/com.Foo-Corp.Bar-App
|
||||
|
||||
let config_dir = proj_dirs.config_dir();
|
||||
let config_file = config_dir.join(Path::new(SAVE_FILE_NAME));
|
||||
if !config_file.exists() || !config_file.is_file() {
|
||||
if manual_execution {
|
||||
// Don't show errors when there is no configuration file when starting app
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Cannot load configuration from file {:?}.", config_file.display()).as_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Loading Data
|
||||
let loaded_data: String = match fs::read_to_string(&config_file) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Failed to read data from file {:?}.", config_file).as_str());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Parsing Data
|
||||
|
||||
let mut included_directories: Vec<String> = Vec::new();
|
||||
let mut excluded_directories: Vec<String> = Vec::new();
|
||||
let mut excluded_items: Vec<String> = Vec::new();
|
||||
let mut allowed_extensions: Vec<String> = Vec::new();
|
||||
let mut loading_at_start: bool = true;
|
||||
let mut saving_at_exit: bool = true;
|
||||
|
||||
let mut current_type = TypeOfLoadedData::None;
|
||||
for (line_number, line) in loaded_data.replace("\r\n", "\n").split('\n').enumerate() {
|
||||
let line: String = line.trim().to_string();
|
||||
if line.trim().is_empty() {
|
||||
continue; // Empty line, so we just skip it
|
||||
}
|
||||
if line.starts_with("--included_directories") {
|
||||
current_type = TypeOfLoadedData::IncludedDirectories;
|
||||
} else if line.starts_with("--excluded_directories") {
|
||||
current_type = TypeOfLoadedData::ExcludedDirectories;
|
||||
} else if line.starts_with("--excluded_items") {
|
||||
current_type = TypeOfLoadedData::ExcludedItems;
|
||||
} else if line.starts_with("--allowed_extensions") {
|
||||
current_type = TypeOfLoadedData::AllowedExtensions;
|
||||
} else if line.starts_with("--load_at_start") {
|
||||
current_type = TypeOfLoadedData::LoadingAtStart;
|
||||
} else if line.starts_with("--save_at_exit") {
|
||||
current_type = TypeOfLoadedData::SavingAtExit;
|
||||
} else {
|
||||
match current_type {
|
||||
TypeOfLoadedData::None => {
|
||||
text_view_errors
|
||||
.get_buffer()
|
||||
.unwrap()
|
||||
.set_text(format!("Found orphan data in line {} \"\"\"{}\"\"\" when loading file {:?}", line_number, line, config_file).as_str());
|
||||
return;
|
||||
}
|
||||
TypeOfLoadedData::IncludedDirectories => {
|
||||
included_directories.push(line);
|
||||
}
|
||||
TypeOfLoadedData::ExcludedDirectories => {
|
||||
excluded_directories.push(line);
|
||||
}
|
||||
TypeOfLoadedData::ExcludedItems => {
|
||||
excluded_items.push(line);
|
||||
}
|
||||
TypeOfLoadedData::AllowedExtensions => {
|
||||
allowed_extensions.push(line);
|
||||
}
|
||||
TypeOfLoadedData::LoadingAtStart => {
|
||||
let line = line.to_lowercase();
|
||||
if line == "1" || line == "true" {
|
||||
loading_at_start = true;
|
||||
} else if line == "0" || line == "false" {
|
||||
loading_at_start = false;
|
||||
} else {
|
||||
text_view_errors
|
||||
.get_buffer()
|
||||
.unwrap()
|
||||
.set_text(format!("Found invalid data in line {} \"\"\"{}\"\"\" isn't proper value(0/1/true/false) when loading file {:?}", line_number, line, config_file).as_str());
|
||||
}
|
||||
}
|
||||
TypeOfLoadedData::SavingAtExit => {
|
||||
let line = line.to_lowercase();
|
||||
if line == "1" || line == "true" {
|
||||
saving_at_exit = true;
|
||||
} else if line == "0" || line == "false" {
|
||||
saving_at_exit = false;
|
||||
} else {
|
||||
text_view_errors
|
||||
.get_buffer()
|
||||
.unwrap()
|
||||
.set_text(format!("Found invalid data in line {} \"\"\"{}\"\"\" isn't proper value(0/1/true/false) when loading file {:?}", line_number, line, config_file).as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setting data
|
||||
if manual_execution || loading_at_start {
|
||||
//// Included Directories
|
||||
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
||||
let list_store = get_list_store(&scrolled_window_included_directories);
|
||||
list_store.clear();
|
||||
|
||||
let col_indices = [0];
|
||||
|
||||
for directory in included_directories {
|
||||
let values: [&dyn ToValue; 1] = [&directory];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
|
||||
//// Exclude Directories
|
||||
let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone();
|
||||
let list_store = get_list_store(&scrolled_window_excluded_directories);
|
||||
list_store.clear();
|
||||
|
||||
let col_indices = [0];
|
||||
|
||||
for directory in excluded_directories {
|
||||
let values: [&dyn ToValue; 1] = [&directory];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
|
||||
//// Excluded Items
|
||||
let entry_excluded_items = gui_data.entry_excluded_items.clone();
|
||||
entry_excluded_items.set_text(excluded_items.iter().map(|e| e.to_string() + ",").collect::<String>().as_str());
|
||||
|
||||
//// Allowed extensions
|
||||
let entry_allowed_extensions = gui_data.entry_allowed_extensions.clone();
|
||||
entry_allowed_extensions.set_text(allowed_extensions.iter().map(|e| e.to_string() + ",").collect::<String>().as_str());
|
||||
|
||||
//// Buttons
|
||||
gui_data.check_button_settings_load_at_start.set_active(loading_at_start);
|
||||
gui_data.check_button_settings_save_at_exit.set_active(saving_at_exit);
|
||||
} else {
|
||||
gui_data.check_button_settings_load_at_start.set_active(false);
|
||||
}
|
||||
|
||||
if manual_execution {
|
||||
text_view_errors.get_buffer().unwrap().set_text(format!("Properly loaded configuration from file {:?}", config_file).as_str());
|
||||
}
|
||||
} else {
|
||||
text_view_errors.get_buffer().unwrap().set_text("Failed to get home directory, so can't load file.");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_configuration(gui_data: &GuiData, manual_clearing: bool) {
|
||||
// TODO Maybe add popup dialog to confirm resetting
|
||||
let text_view_errors = gui_data.text_view_errors.clone();
|
||||
// Resetting included directories
|
||||
{
|
||||
let col_indices = [0];
|
||||
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
||||
let list_store = get_list_store(&scrolled_window_included_directories);
|
||||
list_store.clear();
|
||||
|
||||
let current_dir: String = match env::current_dir() {
|
||||
Ok(t) => t.to_str().unwrap().to_string(),
|
||||
Err(_) => {
|
||||
if cfg!(target_family = "unix") {
|
||||
println!("Failed to read current directory, setting /home instead");
|
||||
"/home".to_string()
|
||||
} else if cfg!(target_family = "windows") {
|
||||
println!("Failed to read current directory, setting C:\\ instead");
|
||||
"C:\\".to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let values: [&dyn ToValue; 1] = [¤t_dir];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
// Resetting excluded directories
|
||||
{
|
||||
let col_indices = [0];
|
||||
let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone();
|
||||
let list_store = get_list_store(&scrolled_window_excluded_directories);
|
||||
list_store.clear();
|
||||
if cfg!(target_family = "unix") {
|
||||
for i in ["/proc", "/dev", "/sys", "/run", "/snap"].iter() {
|
||||
let values: [&dyn ToValue; 1] = [&i];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Resetting excluded items
|
||||
{
|
||||
let entry_excluded_items = gui_data.entry_excluded_items.clone();
|
||||
if cfg!(target_family = "unix") {
|
||||
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*/Trash/*");
|
||||
}
|
||||
if cfg!(target_family = "windows") {
|
||||
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*:/windows/*");
|
||||
}
|
||||
}
|
||||
// Resetting allowed extensions
|
||||
{
|
||||
let entry_allowed_extensions = gui_data.entry_allowed_extensions.clone();
|
||||
entry_allowed_extensions.set_text("");
|
||||
}
|
||||
|
||||
// Set settings
|
||||
{
|
||||
gui_data.check_button_settings_save_at_exit.set_active(true);
|
||||
gui_data.check_button_settings_load_at_start.set_active(true);
|
||||
}
|
||||
if manual_clearing {
|
||||
text_view_errors.get_buffer().unwrap().set_text("Current configuration was cleared.");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue