From 8c1140e40d653bc48980ac6a3d5b5e60a64cb3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Thu, 11 Mar 2021 14:31:59 +0100 Subject: [PATCH] Allow to put files to trash instead fully remove them (#284) --- Cargo.lock | 26 +++++++++---- czkawka_gui/Cargo.toml | 3 ++ czkawka_gui/czkawka.glade | 15 ++++++++ czkawka_gui/src/connect_button_delete.rs | 48 +++++++++++++++++++----- czkawka_gui/src/gui_settings.rs | 3 ++ czkawka_gui/src/saving_loading.rs | 24 ++++++++++++ 6 files changed, 102 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe8ff66..2618d28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,9 +230,9 @@ checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" [[package]] name = "byteorder" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" @@ -599,6 +599,7 @@ dependencies = [ "humansize", "image", "open", + "trash", "winapi", ] @@ -1654,9 +1655,9 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "open" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2033f93630dd4b04768ecf5e16bcd3002a89e1e1dbef375bf290dd67e2b7a4d" +checksum = "a7e9f1bdf15cd1f5a00cc9002a733a6ee6d0ff562491852d59652471c4a389f7" dependencies = [ "which", "winapi", @@ -2298,9 +2299,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" +checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" dependencies = [ "proc-macro2", "quote", @@ -2475,6 +2476,15 @@ dependencies = [ "strength_reduce", ] +[[package]] +name = "trash" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90df96afb154814e214f37eac04920c66886fd95962f22febb4d537b0dacd512" +dependencies = [ + "winapi", +] + [[package]] name = "typenum" version = "1.12.0" @@ -2745,9 +2755,9 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b92e16d90ed01ad0736f1123137630b5bcef5f5bafee62468283e027c1c85d" +checksum = "e575e15bedf6e57b5c2d763ffc6c3c760143466cbd09d762d539680ab5992ded" [[package]] name = "zip" diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index 4efeef4..4b114f8 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -31,6 +31,9 @@ open = "1.4.0" # To get image preview image = "0.23.12" +# Move files to trash +trash = "1.3.0" + [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_core", "windef", "winerror", "wtypesbase", "winuser"] } diff --git a/czkawka_gui/czkawka.glade b/czkawka_gui/czkawka.glade index d996d0c..5d7d048 100644 --- a/czkawka_gui/czkawka.glade +++ b/czkawka_gui/czkawka.glade @@ -2554,6 +2554,21 @@ This program is free to use and will always be. True True + + False + True + 5 + + + + + Move deleted files to trash + True + True + False + True + True + False True diff --git a/czkawka_gui/src/connect_button_delete.rs b/czkawka_gui/src/connect_button_delete.rs index b7ab831..8e4ccae 100644 --- a/czkawka_gui/src/connect_button_delete.rs +++ b/czkawka_gui/src/connect_button_delete.rs @@ -225,6 +225,7 @@ pub fn check_if_deleting_all_files_in_group(tree_view: >k::TreeView, column_co pub fn empty_folder_remover(tree_view: >k::TreeView, column_file_name: i32, column_path: i32, gui_data: &GuiData) { let text_view_errors = gui_data.text_view_errors.clone(); + let use_trash = gui_data.settings.check_button_settings_use_trash.clone().get_active(); let selection = tree_view.get_selection(); @@ -290,11 +291,20 @@ pub fn empty_folder_remover(tree_view: >k::TreeView, column_file_name: i32, co } if !error_happened { - match fs::remove_dir_all(format!("{}/{}", path, name)) { - Ok(_) => { - list_store.remove(&list_store.get_iter(tree_path).unwrap()); + if !use_trash { + match fs::remove_dir_all(format!("{}/{}", path, name)) { + Ok(_) => { + list_store.remove(&list_store.get_iter(tree_path).unwrap()); + } + Err(_) => error_happened = true, + } + } else { + match trash::delete(format!("{}/{}", path, name)) { + Ok(_) => { + list_store.remove(&list_store.get_iter(tree_path).unwrap()); + } + Err(_) => error_happened = true, } - Err(_) => error_happened = true, } } if error_happened { @@ -308,6 +318,7 @@ pub fn empty_folder_remover(tree_view: >k::TreeView, column_file_name: i32, co pub fn basic_remove(tree_view: >k::TreeView, column_file_name: i32, column_path: i32, gui_data: &GuiData) { let text_view_errors = gui_data.text_view_errors.clone(); + let use_trash = gui_data.settings.check_button_settings_use_trash.clone().get_active(); let selection = tree_view.get_selection(); @@ -324,11 +335,20 @@ pub fn basic_remove(tree_view: >k::TreeView, column_file_name: i32, column_pat let name = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), column_file_name).get::().unwrap().unwrap(); let path = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), column_path).get::().unwrap().unwrap(); - match fs::remove_file(format!("{}/{}", path, name)) { - Ok(_) => { - list_store.remove(&list_store.get_iter(tree_path).unwrap()); + if !use_trash { + match fs::remove_file(format!("{}/{}", path, name)) { + Ok(_) => { + list_store.remove(&list_store.get_iter(tree_path).unwrap()); + } + Err(_) => messages += format!("Failed to remove file {}/{} because file doesn't exists or you don't have permissions.\n", path, name).as_str(), + } + } else { + match trash::delete(format!("{}/{}", path, name)) { + Ok(_) => { + list_store.remove(&list_store.get_iter(tree_path).unwrap()); + } + Err(_) => messages += format!("Failed to remove file {}/{} because file doesn't exists or you don't have permissions.\n", path, name).as_str(), } - Err(_) => messages += format!("Failed to remove file {}/{} because file doesn't exists or you don't have permissions.\n", path, name).as_str(), } } @@ -339,6 +359,7 @@ pub fn basic_remove(tree_view: >k::TreeView, column_file_name: i32, column_pat // Remove all occurrences - remove every element which have same path and name as even non selected ones pub fn tree_remove(tree_view: >k::TreeView, column_file_name: i32, column_path: i32, column_color: i32, gui_data: &GuiData) { let text_view_errors = gui_data.text_view_errors.clone(); + let use_trash = gui_data.settings.check_button_settings_use_trash.clone().get_active(); let selection = tree_view.get_selection(); @@ -369,13 +390,22 @@ pub fn tree_remove(tree_view: >k::TreeView, column_file_name: i32, column_path vec_file_name.sort(); vec_file_name.dedup(); for file_name in vec_file_name { - if fs::remove_file(format!("{}/{}", path.clone(), file_name.clone())).is_err() { + if !use_trash { + if fs::remove_file(format!("{}/{}", path.clone(), file_name.clone())).is_err() { + messages += format!( + "Failed to remove file {}/{}. It is possible that you already deleted it, because similar images shows all possible file doesn't exists or you don't have permissions.\n", + path, file_name + ) + .as_str() + } + } else if trash::delete(format!("{}/{}", path.clone(), file_name.clone())).is_err() { messages += format!( "Failed to remove file {}/{}. It is possible that you already deleted it, because similar images shows all possible file doesn't exists or you don't have permissions.\n", path, file_name ) .as_str() } + vec_path_to_delete.push((path.clone(), file_name.clone())); } } diff --git a/czkawka_gui/src/gui_settings.rs b/czkawka_gui/src/gui_settings.rs index 5801ba1..2a6926f 100644 --- a/czkawka_gui/src/gui_settings.rs +++ b/czkawka_gui/src/gui_settings.rs @@ -11,6 +11,7 @@ pub struct GUISettings { pub check_button_settings_confirm_group_deletion: gtk::CheckButton, pub check_button_settings_show_text_view: gtk::CheckButton, pub check_button_settings_use_cache: gtk::CheckButton, + pub check_button_settings_use_trash: gtk::CheckButton, // Duplicates pub check_button_settings_hide_hard_links: gtk::CheckButton, @@ -35,6 +36,7 @@ impl GUISettings { let check_button_settings_confirm_group_deletion: gtk::CheckButton = builder.get_object("check_button_settings_confirm_group_deletion").unwrap(); let check_button_settings_show_text_view: gtk::CheckButton = builder.get_object("check_button_settings_show_text_view").unwrap(); let check_button_settings_use_cache: gtk::CheckButton = builder.get_object("check_button_settings_use_cache").unwrap(); + let check_button_settings_use_trash: gtk::CheckButton = builder.get_object("check_button_settings_use_trash").unwrap(); // Duplicates let check_button_settings_hide_hard_links: gtk::CheckButton = builder.get_object("check_button_settings_hide_hard_links").unwrap(); @@ -60,6 +62,7 @@ impl GUISettings { check_button_settings_show_preview_similar_images, check_button_settings_hide_hard_links, check_button_settings_use_cache, + check_button_settings_use_trash, } } } diff --git a/czkawka_gui/src/saving_loading.rs b/czkawka_gui/src/saving_loading.rs index 01b6832..3f885db 100644 --- a/czkawka_gui/src/saving_loading.rs +++ b/czkawka_gui/src/saving_loading.rs @@ -126,6 +126,11 @@ pub fn save_configuration(gui_data: &GuiData, manual_execution: bool) { data_to_save.push("--use_cache:".to_string()); let check_button_settings_use_cache = gui_data.settings.check_button_settings_use_cache.clone(); data_to_save.push(check_button_settings_use_cache.get_active().to_string()); + + //// Delete to trash + data_to_save.push("--use_trash:".to_string()); + let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); + data_to_save.push(check_button_settings_use_trash.get_active().to_string()); } // Creating/Opening config file @@ -176,6 +181,7 @@ enum TypeOfLoadedData { BottomTextPanel, HideHardLinks, UseCache, + UseTrash, } pub fn load_configuration(gui_data: &GuiData, manual_execution: bool) { @@ -221,6 +227,7 @@ pub fn load_configuration(gui_data: &GuiData, manual_execution: bool) { let mut bottom_text_panel: bool = true; let mut hide_hard_links: bool = true; let mut use_cache: bool = true; + let mut use_trash: bool = false; let mut current_type = TypeOfLoadedData::None; for (line_number, line) in loaded_data.replace("\r\n", "\n").split('\n').enumerate() { @@ -252,6 +259,8 @@ pub fn load_configuration(gui_data: &GuiData, manual_execution: bool) { current_type = TypeOfLoadedData::HideHardLinks; } else if line.starts_with("--use_cache") { current_type = TypeOfLoadedData::UseCache; + } else if line.starts_with("--use_trash") { + current_type = TypeOfLoadedData::UseTrash; } else if line.starts_with("--") { current_type = TypeOfLoadedData::None; add_text_to_text_view( @@ -382,6 +391,19 @@ pub fn load_configuration(gui_data: &GuiData, manual_execution: bool) { ); } } + TypeOfLoadedData::UseTrash => { + let line = line.to_lowercase(); + if line == "1" || line == "true" { + use_trash = true; + } else if line == "0" || line == "false" { + use_trash = false; + } else { + add_text_to_text_view( + &text_view_errors, + format!("Found invalid data in line {} \"{}\" isn't proper value(0/1/true/false) when loading file {:?}", line_number, line, config_file).as_str(), + ); + } + } } } } @@ -435,6 +457,7 @@ pub fn load_configuration(gui_data: &GuiData, manual_execution: bool) { } gui_data.settings.check_button_settings_hide_hard_links.set_active(hide_hard_links); gui_data.settings.check_button_settings_use_cache.set_active(use_cache); + gui_data.settings.check_button_settings_use_trash.set_active(use_trash); } else { gui_data.settings.check_button_settings_load_at_start.set_active(false); } @@ -517,6 +540,7 @@ pub fn reset_configuration(gui_data: &GuiData, manual_clearing: bool) { gui_data.settings.check_button_settings_show_text_view.set_active(true); gui_data.settings.check_button_settings_hide_hard_links.set_active(true); gui_data.settings.check_button_settings_use_cache.set_active(true); + gui_data.settings.check_button_settings_use_trash.set_active(false); } if manual_clearing { add_text_to_text_view(&text_view_errors, "Current configuration was cleared.");