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
+
+
+
+
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.");