From be30afdac6a200058f32723a37b554ef776b44ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Wed, 7 Oct 2020 22:22:39 +0200 Subject: [PATCH] Add support for searching in other thread (#51) --- czkawka_core/src/duplicate.rs | 4 + czkawka_gui/src/help_functions.rs | 26 + czkawka_gui/src/main.rs | 925 +++++++++++++++--------------- 3 files changed, 507 insertions(+), 448 deletions(-) diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index db7fdaa..5ba7f02 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -125,6 +125,10 @@ impl DuplicateFinder { self.debug_print(); } + pub fn get_check_method(&self) -> &CheckingMethod { + &self.check_method + } + pub fn get_files_sorted_by_size(&self) -> &BTreeMap> { &self.files_with_identical_size } diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index 899a3cd..8e91c81 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -1,6 +1,7 @@ use czkawka_core::common_messages::Messages; use gtk::prelude::*; use gtk::TreeViewColumn; +use std::collections::HashMap; pub enum ColumnsDuplicates { // Columns for duplicate treeview @@ -299,3 +300,28 @@ pub fn select_function_3column(_tree_selection: >k::TreeSelection, tree_model: true } + +pub fn set_buttons(hashmap: &mut HashMap, buttons_array: &[gtk::Button], button_names: &[&str]) { + for (index, button) in buttons_array.iter().enumerate() { + if *hashmap.get_mut(button_names[index]).unwrap() { + button.show(); + } else { + button.hide(); + } + } +} +// pub fn hide_all_buttons(buttons_array: &[gtk::Button]) { +// for button in buttons_array { +// button.hide(); +// } +// } + +pub fn hide_all_buttons_except(except_name: &str, buttons_array: &[gtk::Button], button_names: &[&str]) { + for (index, button) in buttons_array.iter().enumerate() { + if except_name == button_names[index] { + button.show(); + } else { + button.hide(); + } + } +} diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index 0e0ad36..13aa9bc 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -18,7 +18,7 @@ use gtk::{Builder, SelectionMode, TreeIter, TreeView}; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; -use std::{env, fs, process}; +use std::{env, fs, process, thread}; fn main() { let mut exit_program_after_initialization: bool = false; @@ -114,6 +114,17 @@ fn main() { let buttons_delete: gtk::Button = builder.get_object("buttons_delete").unwrap(); let buttons_save: gtk::Button = builder.get_object("buttons_save").unwrap(); + let buttons_names = ["search", "stop", "resume", "pause", "select", "delete", "save"]; + let buttons_array = [ + buttons_search.clone(), + buttons_stop.clone(), + buttons_resume.clone(), + buttons_pause.clone(), + buttons_select.clone(), + buttons_delete.clone(), + buttons_save.clone(), + ]; + let buttons_add_included_directory: gtk::Button = builder.get_object("buttons_add_included_directory").unwrap(); let buttons_remove_included_directory: gtk::Button = builder.get_object("buttons_remove_included_directory").unwrap(); let buttons_add_excluded_directory: gtk::Button = builder.get_object("buttons_add_excluded_directory").unwrap(); @@ -172,6 +183,18 @@ fn main() { let scrolled_window_included_directories: gtk::ScrolledWindow = builder.get_object("scrolled_window_included_directories").unwrap(); let scrolled_window_excluded_directories: gtk::ScrolledWindow = builder.get_object("scrolled_window_excluded_directories").unwrap(); + //// Threads + // Messages + enum Message { + Duplicates(DuplicateFinder), + EmptyFolders(EmptyFolder), + EmptyFiles(EmptyFiles), + BigFiles(BigFile), + Temporary(Temporary), + } + // Sender/Reciver + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + //// Setup default look for { entry_info.set_text("Duplicated Files"); @@ -323,10 +346,7 @@ fn main() { { let shared_buttons = shared_buttons.clone(); - let buttons_search = buttons_search.clone(); - let buttons_select = buttons_select.clone(); - let buttons_delete = buttons_delete.clone(); - let buttons_save = buttons_save.clone(); + let buttons_array = buttons_array.clone(); let notebook_main_children_names = notebook_main_children_names.clone(); @@ -349,43 +369,7 @@ fn main() { } }; // Buttons - { - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("search").unwrap() { - buttons_search.show(); - } else { - buttons_search.hide(); - } - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("stop").unwrap() { - buttons_stop.show(); - } else { - buttons_stop.hide(); - } - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("resume").unwrap() { - buttons_resume.show(); - } else { - buttons_resume.hide(); - } - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("pause").unwrap() { - buttons_pause.show(); - } else { - buttons_pause.hide(); - } - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("select").unwrap() { - buttons_select.show(); - } else { - buttons_select.hide(); - } - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("delete").unwrap() { - buttons_delete.show(); - } else { - buttons_delete.hide(); - } - if *shared_buttons.borrow_mut().get_mut(page).unwrap().get_mut("save").unwrap() { - buttons_save.show(); - } else { - buttons_save.hide(); - } - } + 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"]; @@ -420,32 +404,29 @@ fn main() { assert!(notebook_main_children_names.contains(&"notebook_big_main_file_finder".to_string())); // Search button { - let buttons_delete = buttons_delete.clone(); - let buttons_save = buttons_save.clone(); - let buttons_select = buttons_select.clone(); let entry_info = entry_info.clone(); let notebook_main_children_names = notebook_main_children_names.clone(); let notebook_main = notebook_main.clone(); - let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone(); - let scrolled_window_main_empty_folder_finder = scrolled_window_main_empty_folder_finder.clone(); - let scrolled_window_main_empty_files_finder = scrolled_window_main_empty_files_finder.clone(); - let scrolled_window_main_temporary_files_finder = scrolled_window_main_temporary_files_finder.clone(); - let scrolled_window_big_files_finder = scrolled_window_big_files_finder.clone(); let scrolled_window_included_directories = scrolled_window_included_directories.clone(); let scrolled_window_excluded_directories = scrolled_window_excluded_directories.clone(); - let text_view_errors = text_view_errors.clone(); - let shared_duplication_state = shared_duplication_state.clone(); - let shared_empty_folders_state = shared_empty_folders_state.clone(); - let shared_empty_files_state = shared_empty_files_state.clone(); - let shared_temporary_files_state = shared_temporary_files_state.clone(); - let shared_big_files_state = shared_big_files_state.clone(); - let shared_buttons = shared_buttons.clone(); - buttons_search.connect_clicked(move |_| { + let buttons_search_clone = buttons_search.clone(); + let buttons_array = buttons_array.clone(); + buttons_search_clone.connect_clicked(move |_| { + let included_directories = get_string_from_list_store(&scrolled_window_included_directories); + let excluded_directories = get_string_from_list_store(&scrolled_window_excluded_directories); + let recursive_search = check_button_recursive.get_active(); + let excluded_items = entry_excluded_items.get_text().as_str().to_string(); + let allowed_extensions = entry_allowed_extensions.get_text().as_str().to_string(); + + hide_all_buttons_except("stop", &buttons_array, &buttons_names); // TODO Stop should do something + + // Disable main notebook from any iteraction until search will end + notebook_main.set_sensitive(false); + + entry_info.set_text("Searching data, please wait..."); + match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() { "notebook_main_duplicate_finder_label" => { - // Find duplicates - - let mut df = DuplicateFinder::new(); let check_method; if radio_button_size.get_active() { check_method = duplicate::CheckingMethod::Size; @@ -456,409 +437,92 @@ fn main() { } else { panic!("No radio button is pressed"); } - { - df.set_included_directory(get_string_from_list_store(&scrolled_window_included_directories)); - df.set_excluded_directory(get_string_from_list_store(&scrolled_window_excluded_directories)); - df.set_recursive_search(check_button_recursive.get_active()); - df.set_excluded_items(entry_excluded_items.get_text().as_str().to_string()); - df.set_allowed_extensions(entry_allowed_extensions.get_text().as_str().to_string()); - df.set_minimal_file_size(match entry_duplicate_minimal_size.get_text().as_str().parse::() { - Ok(t) => t, - Err(_) => 1024, // By default - }); - df.set_check_method(check_method.clone()); - df.set_delete_method(duplicate::DeleteMethod::None); + let minimal_file_size = match entry_duplicate_minimal_size.get_text().as_str().parse::() { + Ok(t) => t, + Err(_) => 1024, // By default + }; + let delete_method = duplicate::DeleteMethod::None; + + let sender = sender.clone(); + + // Find duplicates + thread::spawn(move || { + let mut df = DuplicateFinder::new(); + df.set_included_directory(included_directories); + df.set_excluded_directory(excluded_directories); + df.set_recursive_search(recursive_search); + df.set_excluded_items(excluded_items); + df.set_allowed_extensions(allowed_extensions); + df.set_minimal_file_size(minimal_file_size); + df.set_check_method(check_method); + df.set_delete_method(delete_method); df.find_duplicates(); - } - let information = df.get_information(); - let text_messages = df.get_text_messages(); - - let duplicates_number: usize; - let duplicates_size: u64; - let duplicates_group: usize; - - match check_method { - CheckingMethod::Hash | CheckingMethod::HashMB => { - duplicates_number = information.number_of_duplicated_files_by_hash; - duplicates_size = information.lost_space_by_hash; - duplicates_group = information.number_of_groups_by_hash; - } - CheckingMethod::Size => { - duplicates_number = information.number_of_duplicated_files_by_size; - duplicates_size = information.lost_space_by_size; - duplicates_group = information.number_of_groups_by_size; - } - CheckingMethod::None => { - panic!(); - } - } - - entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str()); - - // Create GUI - { - let list_store = scrolled_window_duplicate_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); - - let col_indices = [0, 1, 2, 3, 4, 5]; - - match check_method { - CheckingMethod::Hash | CheckingMethod::HashMB => { - let btreemap = df.get_files_sorted_by_hash(); - - for (size, vectors_vector) in btreemap.iter().rev() { - for vector in vectors_vector { - let values: [&dyn ToValue; 6] = [ - &(vector.len().to_string() + " x " + size.to_string().as_str()), - &(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)), - &"".to_string(), // No text in 3 column - &(0), // Not used here - &(HEADER_ROW_COLOR.to_string()), - &(TEXT_COLOR.to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); - for entry in vector { - let path = &entry.path; - let index = path.rfind('/').unwrap(); - - let values: [&dyn ToValue; 6] = [ - &(path[index + 1..].to_string()), - &(path[..index].to_string()), - &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()), - &(entry.modified_date), - &(MAIN_ROW_COLOR.to_string()), - &(TEXT_COLOR.to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); - } - } - } - } - CheckingMethod::Size => { - let btreemap = df.get_files_sorted_by_size(); - - for (size, vector) in btreemap.iter().rev() { - let values: [&dyn ToValue; 6] = [ - &(vector.len().to_string() + " x " + size.to_string().as_str()), - &(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)), - &"".to_string(), // No text in 3 column - &(0), // Not used here - &(HEADER_ROW_COLOR.to_string()), - &(TEXT_COLOR.to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); - for entry in vector { - let path = &entry.path; - let index = path.rfind('/').unwrap(); - - let values: [&dyn ToValue; 6] = [ - &(path[index + 1..].to_string()), - &(path[..index].to_string()), - &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()), - &(entry.modified_date), - &(MAIN_ROW_COLOR.to_string()), - &(TEXT_COLOR.to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); - } - } - } - CheckingMethod::None => { - panic!(); - } - } - - print_text_messages_to_text_view(&text_messages, &text_view_errors); - } - - // Set state - { - *shared_duplication_state.borrow_mut() = df; - - if duplicates_size > 0 { - buttons_save.show(); - buttons_delete.show(); - buttons_select.show(); - *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = true; - *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = true; - *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = true; - } else { - buttons_save.hide(); - buttons_delete.hide(); - buttons_select.hide(); - *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = false; - *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = false; - *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = false; - } - } + let _ = sender.send(Message::Duplicates(df)); + }); } "scrolled_window_main_empty_folder_finder" => { + let sender = sender.clone(); + // Find empty folders - let mut ef = EmptyFolder::new(); - - ef.set_included_directory(get_string_from_list_store(&scrolled_window_included_directories)); - ef.set_delete_folder(false); - ef.find_empty_folders(); - - let information = ef.get_information(); - let text_messages = ef.get_text_messages(); - - let empty_folder_number: usize = information.number_of_empty_folders; - - entry_info.set_text(format!("Found {} empty folders.", empty_folder_number).as_str()); - - // Create GUI - { - let list_store = scrolled_window_main_empty_folder_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); - - let col_indices = [0, 1, 2]; - - let hashmap = ef.get_empty_folder_list(); - - for (name, entry) in hashmap { - let name: String = name[..(name.len() - 1)].to_string(); - let index = name.rfind('/').unwrap(); - let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string())]; - list_store.set(&list_store.append(), &col_indices, &values); - } - print_text_messages_to_text_view(&text_messages, &text_view_errors); - } - - // Set state - { - *shared_empty_folders_state.borrow_mut() = ef; - - if empty_folder_number > 0 { - buttons_save.show(); - buttons_delete.show(); - *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = true; - *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = true; - } else { - buttons_save.hide(); - buttons_delete.hide(); - *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = false; - *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = false; - } - } + thread::spawn(move || { + let mut ef = EmptyFolder::new(); + ef.set_included_directory(included_directories); + ef.set_delete_folder(false); + ef.find_empty_folders(); + let _ = sender.send(Message::EmptyFolders(ef)); + }); } "scrolled_window_main_empty_files_finder" => { + let sender = sender.clone(); + // Find empty files - let mut vf = EmptyFiles::new(); + thread::spawn(move || { + let mut vf = EmptyFiles::new(); - vf.set_included_directory(get_string_from_list_store(&scrolled_window_included_directories)); - vf.set_excluded_directory(get_string_from_list_store(&scrolled_window_excluded_directories)); - vf.set_recursive_search(check_button_recursive.get_active()); - vf.set_excluded_items(entry_excluded_items.get_text().as_str().to_string()); - vf.set_allowed_extensions(entry_allowed_extensions.get_text().as_str().to_string()); - vf.find_empty_files(); - - let information = vf.get_information(); - let text_messages = vf.get_text_messages(); - - let empty_files_number: usize = information.number_of_empty_files; - - entry_info.set_text(format!("Found {} empty files.", empty_files_number).as_str()); - - // Create GUI - { - let list_store = scrolled_window_main_empty_files_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); - - let col_indices = [0, 1, 2]; - - let vector = vf.get_empty_files(); - - for file_entry in vector { - let name: String = file_entry.path.to_string(); - let index = name.rfind('/').unwrap(); - let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())]; - list_store.set(&list_store.append(), &col_indices, &values); - } - print_text_messages_to_text_view(&text_messages, &text_view_errors); - } - - // Set state - { - *shared_empty_files_state.borrow_mut() = vf; - - if empty_files_number > 0 { - buttons_save.show(); - buttons_delete.show(); - *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = true; - *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = true; - } else { - buttons_save.hide(); - buttons_delete.hide(); - *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = false; - *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = false; - } - } + vf.set_included_directory(included_directories); + vf.set_excluded_directory(excluded_directories); + vf.set_recursive_search(recursive_search); + vf.set_excluded_items(excluded_items); + vf.set_allowed_extensions(allowed_extensions); + vf.find_empty_files(); + let _ = sender.send(Message::EmptyFiles(vf)); + }); } "scrolled_window_main_temporary_files_finder" => { + let sender = sender.clone(); + // Find temporary files - let mut tf = Temporary::new(); + thread::spawn(move || { + let mut tf = Temporary::new(); - tf.set_included_directory(get_string_from_list_store(&scrolled_window_included_directories)); - tf.set_excluded_directory(get_string_from_list_store(&scrolled_window_excluded_directories)); - tf.set_recursive_search(check_button_recursive.get_active()); - tf.set_excluded_items(entry_excluded_items.get_text().as_str().to_string()); - tf.find_temporary_files(); - - let information = tf.get_information(); - let text_messages = tf.get_text_messages(); - - let temporary_files_number: usize = information.number_of_temporary_files; - - entry_info.set_text(format!("Found {} temporary files.", temporary_files_number).as_str()); - - // Create GUI - { - let list_store = scrolled_window_main_temporary_files_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); - - let col_indices = [0, 1, 2]; - - let vector = tf.get_temporary_files(); - - for file_entry in vector { - let name: String = file_entry.path.to_string(); - let index = name.rfind('/').unwrap(); - let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())]; - list_store.set(&list_store.append(), &col_indices, &values); - } - print_text_messages_to_text_view(&text_messages, &text_view_errors); - } - - // Set state - { - *shared_temporary_files_state.borrow_mut() = tf; - - if temporary_files_number > 0 { - buttons_save.show(); - buttons_delete.show(); - *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = true; - *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = true; - } else { - buttons_save.hide(); - buttons_delete.hide(); - *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = false; - *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = false; - } - } + tf.set_included_directory(included_directories); + tf.set_excluded_directory(excluded_directories); + tf.set_recursive_search(recursive_search); + tf.set_excluded_items(excluded_items); + tf.find_temporary_files(); + let _ = sender.send(Message::Temporary(tf)); + }); } "notebook_big_main_file_finder" => { - // Find temporary files - let mut bf = BigFile::new(); - - bf.set_included_directory(get_string_from_list_store(&scrolled_window_included_directories)); - bf.set_excluded_directory(get_string_from_list_store(&scrolled_window_excluded_directories)); - bf.set_recursive_search(check_button_recursive.get_active()); - bf.set_excluded_items(entry_excluded_items.get_text().as_str().to_string()); - bf.set_number_of_files_to_check(match entry_big_files_number.get_text().as_str().parse::() { + let numbers_of_files_to_check = match entry_big_files_number.get_text().as_str().parse::() { Ok(t) => t, Err(_) => 50, // By default + }; + + let sender = sender.clone(); + + // Find big files + thread::spawn(move || { + let mut bf = BigFile::new(); + + bf.set_included_directory(included_directories); + bf.set_excluded_directory(excluded_directories); + bf.set_recursive_search(recursive_search); + bf.set_excluded_items(excluded_items); + bf.set_number_of_files_to_check(numbers_of_files_to_check); + bf.find_big_files(); + let _ = sender.send(Message::BigFiles(bf)); }); - bf.find_big_files(); - - let information = bf.get_information(); - let text_messages = bf.get_text_messages(); - - let biggest_files_number: usize = information.number_of_real_files; - - entry_info.set_text(format!("Found {} biggest files.", biggest_files_number).as_str()); - - // Create GUI - { - let list_store = scrolled_window_big_files_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); - - let col_indices = [0, 1, 2, 3]; - - let btreemap = bf.get_big_files(); - - for (size, vector) in btreemap.iter().rev() { - for file_entry in vector { - let name: String = file_entry.path.to_string(); - let index = name.rfind('/').unwrap(); - let values: [&dyn ToValue; 4] = [ - &(format!("{} ({} bytes)", size.file_size(options::BINARY).unwrap(), size)), - &(name[index + 1..].to_string()), - &(name[..index].to_string()), - &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); - } - } - print_text_messages_to_text_view(&text_messages, &text_view_errors); - } - - // Set state - { - *shared_big_files_state.borrow_mut() = bf; - - if biggest_files_number > 0 { - buttons_save.show(); - buttons_delete.show(); - *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = true; - *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = true; - } else { - buttons_save.hide(); - buttons_delete.hide(); - *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = false; - *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = false; - } - } } e => panic!("Not existent {}", e), } @@ -867,9 +531,14 @@ fn main() { // Delete button { let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone(); + let text_view_errors = text_view_errors.clone(); let notebook_main_children_names = notebook_main_children_names.clone(); let notebook_main = notebook_main.clone(); let window_main = window_main.clone(); + let scrolled_window_main_empty_folder_finder = scrolled_window_main_empty_folder_finder.clone(); + let scrolled_window_big_files_finder = scrolled_window_big_files_finder.clone(); + let scrolled_window_main_empty_files_finder = scrolled_window_main_empty_files_finder.clone(); + let scrolled_window_main_temporary_files_finder = scrolled_window_main_temporary_files_finder.clone(); buttons_delete.connect_clicked(move |_| { if *shared_confirmation_dialog_delete_dialog_showing_state.borrow_mut() { @@ -1072,7 +741,15 @@ fn main() { } // Save button { + let shared_buttons = shared_buttons.clone(); let buttons_save_clone = buttons_save.clone(); + let entry_info = entry_info.clone(); + let shared_duplication_state = shared_duplication_state.clone(); + let shared_empty_folders_state = shared_empty_folders_state.clone(); + let shared_big_files_state = shared_big_files_state.clone(); + let shared_temporary_files_state = shared_temporary_files_state.clone(); + let shared_empty_files_state = shared_empty_files_state.clone(); + let notebook_main = notebook_main.clone(); buttons_save_clone.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() { "notebook_main_duplicate_finder_label" => { let file_name = "results_duplicates.txt"; @@ -1394,7 +1071,7 @@ fn main() { } // All one newest { - // let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone(); + let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone(); // let popover_select = popover_select.clone(); buttons_popover_select_one_newest.connect_clicked(move |_| { let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); @@ -1546,6 +1223,358 @@ fn main() { } } + // Wait for ending of search: + // Unblock left notebook bar + // Show proper buttons + receiver.attach(None, move |msg| { + buttons_search.show(); + buttons_stop.hide(); + + // Restore clickability to main notebook + notebook_main.set_sensitive(true); + + match msg { + Message::Duplicates(df) => { + let information = df.get_information(); + let text_messages = df.get_text_messages(); + + let duplicates_number: usize; + let duplicates_size: u64; + let duplicates_group: usize; + + match df.get_check_method() { + CheckingMethod::Hash | CheckingMethod::HashMB => { + duplicates_number = information.number_of_duplicated_files_by_hash; + duplicates_size = information.lost_space_by_hash; + duplicates_group = information.number_of_groups_by_hash; + } + CheckingMethod::Size => { + duplicates_number = information.number_of_duplicated_files_by_size; + duplicates_size = information.lost_space_by_size; + duplicates_group = information.number_of_groups_by_size; + } + CheckingMethod::None => { + panic!(); + } + } + + entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str()); + + // Create GUI + { + let list_store = scrolled_window_duplicate_finder + .get_children() + .get(0) + .unwrap() + .clone() + .downcast::() + .unwrap() + .get_model() + .unwrap() + .downcast::() + .unwrap(); + list_store.clear(); + + let col_indices = [0, 1, 2, 3, 4, 5]; + + match df.get_check_method() { + CheckingMethod::Hash | CheckingMethod::HashMB => { + let btreemap = df.get_files_sorted_by_hash(); + + for (size, vectors_vector) in btreemap.iter().rev() { + for vector in vectors_vector { + let values: [&dyn ToValue; 6] = [ + &(vector.len().to_string() + " x " + size.to_string().as_str()), + &(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)), + &"".to_string(), // No text in 3 column + &(0), // Not used here + &(HEADER_ROW_COLOR.to_string()), + &(TEXT_COLOR.to_string()), + ]; + list_store.set(&list_store.append(), &col_indices, &values); + for entry in vector { + let path = &entry.path; + let index = path.rfind('/').unwrap(); + + let values: [&dyn ToValue; 6] = [ + &(path[index + 1..].to_string()), + &(path[..index].to_string()), + &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()), + &(entry.modified_date), + &(MAIN_ROW_COLOR.to_string()), + &(TEXT_COLOR.to_string()), + ]; + list_store.set(&list_store.append(), &col_indices, &values); + } + } + } + } + CheckingMethod::Size => { + let btreemap = df.get_files_sorted_by_size(); + + for (size, vector) in btreemap.iter().rev() { + let values: [&dyn ToValue; 6] = [ + &(vector.len().to_string() + " x " + size.to_string().as_str()), + &(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)), + &"".to_string(), // No text in 3 column + &(0), // Not used here + &(HEADER_ROW_COLOR.to_string()), + &(TEXT_COLOR.to_string()), + ]; + list_store.set(&list_store.append(), &col_indices, &values); + for entry in vector { + let path = &entry.path; + let index = path.rfind('/').unwrap(); + + let values: [&dyn ToValue; 6] = [ + &(path[index + 1..].to_string()), + &(path[..index].to_string()), + &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()), + &(entry.modified_date), + &(MAIN_ROW_COLOR.to_string()), + &(TEXT_COLOR.to_string()), + ]; + list_store.set(&list_store.append(), &col_indices, &values); + } + } + } + CheckingMethod::None => { + panic!(); + } + } + + print_text_messages_to_text_view(&text_messages, &text_view_errors); + } + + // Set state + { + *shared_duplication_state.borrow_mut() = df; + + if duplicates_size > 0 { + *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = true; + *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = true; + *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = true; + } else { + *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("save").unwrap() = false; + *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("delete").unwrap() = false; + *shared_buttons.borrow_mut().get_mut("duplicate").unwrap().get_mut("select").unwrap() = false; + } + set_buttons(&mut *shared_buttons.borrow_mut().get_mut("duplicate").unwrap(), &buttons_array, &buttons_names); + } + } + Message::EmptyFolders(ef) => { + let information = ef.get_information(); + let text_messages = ef.get_text_messages(); + + let empty_folder_number: usize = information.number_of_empty_folders; + + entry_info.set_text(format!("Found {} empty folders.", empty_folder_number).as_str()); + + // Create GUI + { + let list_store = scrolled_window_main_empty_folder_finder + .get_children() + .get(0) + .unwrap() + .clone() + .downcast::() + .unwrap() + .get_model() + .unwrap() + .downcast::() + .unwrap(); + list_store.clear(); + + let col_indices = [0, 1, 2]; + + let hashmap = ef.get_empty_folder_list(); + + for (name, entry) in hashmap { + let name: String = name[..(name.len() - 1)].to_string(); + let index = name.rfind('/').unwrap(); + let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string())]; + list_store.set(&list_store.append(), &col_indices, &values); + } + print_text_messages_to_text_view(&text_messages, &text_view_errors); + } + + // Set state + { + *shared_empty_folders_state.borrow_mut() = ef; + + if empty_folder_number > 0 { + *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = true; + *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = true; + } else { + *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("save").unwrap() = false; + *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap().get_mut("delete").unwrap() = false; + } + set_buttons(&mut *shared_buttons.borrow_mut().get_mut("empty_folder").unwrap(), &buttons_array, &buttons_names); + } + } + Message::EmptyFiles(vf) => { + let information = vf.get_information(); + let text_messages = vf.get_text_messages(); + + let empty_files_number: usize = information.number_of_empty_files; + + entry_info.set_text(format!("Found {} empty files.", empty_files_number).as_str()); + + // Create GUI + { + let list_store = scrolled_window_main_empty_files_finder + .get_children() + .get(0) + .unwrap() + .clone() + .downcast::() + .unwrap() + .get_model() + .unwrap() + .downcast::() + .unwrap(); + list_store.clear(); + + let col_indices = [0, 1, 2]; + + let vector = vf.get_empty_files(); + + for file_entry in vector { + let name: String = file_entry.path.to_string(); + let index = name.rfind('/').unwrap(); + let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())]; + list_store.set(&list_store.append(), &col_indices, &values); + } + print_text_messages_to_text_view(&text_messages, &text_view_errors); + } + + // Set state + { + *shared_empty_files_state.borrow_mut() = vf; + + if empty_files_number > 0 { + *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = true; + *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = true; + } else { + *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("save").unwrap() = false; + *shared_buttons.borrow_mut().get_mut("empty_file").unwrap().get_mut("delete").unwrap() = false; + } + set_buttons(&mut *shared_buttons.borrow_mut().get_mut("empty_file").unwrap(), &buttons_array, &buttons_names); + } + } + Message::BigFiles(bf) => { + let information = bf.get_information(); + let text_messages = bf.get_text_messages(); + + let biggest_files_number: usize = information.number_of_real_files; + + entry_info.set_text(format!("Found {} biggest files.", biggest_files_number).as_str()); + + // Create GUI + { + let list_store = scrolled_window_big_files_finder + .get_children() + .get(0) + .unwrap() + .clone() + .downcast::() + .unwrap() + .get_model() + .unwrap() + .downcast::() + .unwrap(); + list_store.clear(); + + let col_indices = [0, 1, 2, 3]; + + let btreemap = bf.get_big_files(); + + for (size, vector) in btreemap.iter().rev() { + for file_entry in vector { + let name: String = file_entry.path.to_string(); + let index = name.rfind('/').unwrap(); + let values: [&dyn ToValue; 4] = [ + &(format!("{} ({} bytes)", size.file_size(options::BINARY).unwrap(), size)), + &(name[index + 1..].to_string()), + &(name[..index].to_string()), + &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()), + ]; + list_store.set(&list_store.append(), &col_indices, &values); + } + } + print_text_messages_to_text_view(&text_messages, &text_view_errors); + } + + // Set state + { + *shared_big_files_state.borrow_mut() = bf; + + if biggest_files_number > 0 { + *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = true; + *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = true; + } else { + *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = false; + *shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("delete").unwrap() = false; + } + set_buttons(&mut *shared_buttons.borrow_mut().get_mut("big_file").unwrap(), &buttons_array, &buttons_names); + } + } + Message::Temporary(tf) => { + let information = tf.get_information(); + let text_messages = tf.get_text_messages(); + + let temporary_files_number: usize = information.number_of_temporary_files; + + entry_info.set_text(format!("Found {} temporary files.", temporary_files_number).as_str()); + + // Create GUI + { + let list_store = scrolled_window_main_temporary_files_finder + .get_children() + .get(0) + .unwrap() + .clone() + .downcast::() + .unwrap() + .get_model() + .unwrap() + .downcast::() + .unwrap(); + list_store.clear(); + + let col_indices = [0, 1, 2]; + + let vector = tf.get_temporary_files(); + + for file_entry in vector { + let name: String = file_entry.path.to_string(); + let index = name.rfind('/').unwrap(); + let values: [&dyn ToValue; 3] = [&(name[index + 1..].to_string()), &(name[..index].to_string()), &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())]; + list_store.set(&list_store.append(), &col_indices, &values); + } + print_text_messages_to_text_view(&text_messages, &text_view_errors); + } + + // Set state + { + *shared_temporary_files_state.borrow_mut() = tf; + + if temporary_files_number > 0 { + *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = true; + *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = true; + } else { + *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("save").unwrap() = false; + *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap().get_mut("delete").unwrap() = false; + } + set_buttons(&mut *shared_buttons.borrow_mut().get_mut("temporary_file").unwrap(), &buttons_array, &buttons_names); + } + } + } + // Returning false here would close the receiver + // and have senders fail + glib::Continue(true) + }); + // Quit the program when X in main window was clicked window_main.connect_delete_event(|_, _| { gtk::main_quit();