mirror of https://github.com/qarmin/czkawka
Add option to save file, store settings and load them (#108)
parent
a047380dbe
commit
6fab1a9368
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
@ -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 New Issue