From 6f516223a55777e9b06fdae997f90a6c58589393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= Date: Tue, 29 Sep 2020 21:17:58 +0200 Subject: [PATCH] Added logic to radio buttons to select method of duplicate finder --- czkawka_gui/czkawka.glade | 14 +- czkawka_gui/src/main.rs | 474 ++++++++++++++++++++------------------ 2 files changed, 257 insertions(+), 231 deletions(-) diff --git a/czkawka_gui/czkawka.glade b/czkawka_gui/czkawka.glade index 935a654..a52341a 100644 --- a/czkawka_gui/czkawka.glade +++ b/czkawka_gui/czkawka.glade @@ -185,7 +185,7 @@ Author: Rafał Mikrut 1 True - + True True True @@ -236,7 +236,7 @@ Author: Rafał Mikrut - + True True True @@ -350,7 +350,7 @@ Author: Rafał Mikrut 1 True - + True True True @@ -401,7 +401,7 @@ Author: Rafał Mikrut - + True True True @@ -774,8 +774,8 @@ Author: Rafał Mikrut True True False - True True + radio_button_hash False @@ -789,9 +789,8 @@ Author: Rafał Mikrut True True False - True True - radio_button_size + radio_button_hash False @@ -807,7 +806,6 @@ Author: Rafał Mikrut False True True - radio_button_size False diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index 03eeddb..76132f3 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -83,6 +83,11 @@ 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_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(); + // let buttons_remove_excluded_directory: gtk::Button =builder.get_object("buttons_remove_excluded_directory").unwrap(); + // Not used buttons for now buttons_stop.hide(); buttons_resume.hide(); @@ -92,6 +97,11 @@ fn main() { //// Check Buttons let check_button_recursive: gtk::CheckButton = builder.get_object("check_button_recursive").unwrap(); + //// Radio Buttons + let radio_button_size: gtk::RadioButton = builder.get_object("radio_button_size").unwrap(); + let radio_button_hashmb: gtk::RadioButton = builder.get_object("radio_button_hashmb").unwrap(); + let radio_button_hash: gtk::RadioButton = builder.get_object("radio_button_hash").unwrap(); + //// Notebooks let notebook_chooser_tool: gtk::Notebook = builder.get_object("notebook_chooser_tool").unwrap(); let mut notebook_chooser_tool_children_names: Vec = Vec::new(); @@ -275,88 +285,124 @@ fn main() { }); } - // Connect Buttons + //// Connect Buttons - assert!(notebook_chooser_tool_children_names.contains(&"notebook_duplicate_finder_label".to_string())); - assert!(notebook_chooser_tool_children_names.contains(&"scrolled_window_empty_folder_finder".to_string())); - // Search button + // Down notepad { - let buttons_delete = buttons_delete.clone(); - let notebook_chooser_tool_children_names = notebook_chooser_tool_children_names.clone(); - let notebook_chooser_tool = notebook_chooser_tool.clone(); - let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone(); - let scrolled_window_empty_folder_finder = scrolled_window_empty_folder_finder.clone(); - let text_view_errors = text_view_errors.clone(); - buttons_search.connect_clicked(move |_| { - match notebook_chooser_tool_children_names.get(notebook_chooser_tool.get_current_page().unwrap() as usize).unwrap().as_str() { - "notebook_duplicate_finder_label" => { - // Find duplicates - // TODO Change to proper value + assert!(notebook_chooser_tool_children_names.contains(&"notebook_duplicate_finder_label".to_string())); + assert!(notebook_chooser_tool_children_names.contains(&"scrolled_window_empty_folder_finder".to_string())); + // Search button + { + let buttons_delete = buttons_delete.clone(); + let notebook_chooser_tool_children_names = notebook_chooser_tool_children_names.clone(); + let notebook_chooser_tool = notebook_chooser_tool.clone(); + let scrolled_window_duplicate_finder = scrolled_window_duplicate_finder.clone(); + let scrolled_window_empty_folder_finder = scrolled_window_empty_folder_finder.clone(); + let text_view_errors = text_view_errors.clone(); + buttons_search.connect_clicked(move |_| { + match notebook_chooser_tool_children_names.get(notebook_chooser_tool.get_current_page().unwrap() as usize).unwrap().as_str() { + "notebook_duplicate_finder_label" => { + // Find duplicates - let mut df = DuplicateFinder::new(); - let check_method = duplicate::CheckingMethod::Hash; // TODO - { - 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_min_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()); // TODO - df.set_delete_method(duplicate::DeleteMethod::None); - 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; + let mut df = DuplicateFinder::new(); + let check_method; + if radio_button_size.get_active() { + check_method = duplicate::CheckingMethod::Size; + } else if radio_button_hashmb.get_active() { + check_method = duplicate::CheckingMethod::HashMB; + } else if radio_button_hash.get_active() { + check_method = duplicate::CheckingMethod::Hash; + } else { + panic!("No radio button is pressed"); } - 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; + { + 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_min_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); + df.find_duplicates(); } - CheckingMethod::None => { - panic!(); - } - } + let information = df.get_information(); + let text_messages = df.get_text_messages(); - 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]; + let duplicates_number: usize; + let duplicates_size: u64; + let duplicates_group: usize; match check_method { CheckingMethod::Hash | CheckingMethod::HashMB => { - let btreemap = df.get_files_sorted_by_hash(); + 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!(); + } + } - for (size, vectors_vector) in btreemap.iter().rev() { - for vector in vectors_vector { + 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]; + + 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; 4] = [ + &(vector.len().to_string() + " x " + size.to_string().as_str()), + &("(".to_string() + ((vector.len() - 1) as u64 * *size as u64).to_string().as_str() + ")"), + &"Bytes lost".to_string(), + &(HEADER_ROW_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; 4] = [ + &(path[index + 1..].to_string()), + &(path[..index].to_string()), + &(NaiveDateTime::from_timestamp(entry.modified_date.duration_since(UNIX_EPOCH).expect("Invalid file date").as_secs() as i64, 0).to_string()), + &(MAIN_ROW_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; 4] = [ &(vector.len().to_string() + " x " + size.to_string().as_str()), &("(".to_string() + ((vector.len() - 1) as u64 * *size as u64).to_string().as_str() + ")"), @@ -378,180 +424,162 @@ fn main() { } } } - } - CheckingMethod::Size => { - let btreemap = df.get_files_sorted_by_size(); - - for (size, vector) in btreemap.iter().rev() { - let values: [&dyn ToValue; 3] = [ - &(vector.len().to_string() + " x " + size.to_string().as_str()), - &("(".to_string() + ((vector.len() - 1) as u64 * *size as u64).to_string().as_str() + ")"), - &"Bytes lost".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; 3] = [ - &(path[index + 1..].to_string()), - &(path[..index].to_string()), - &(NaiveDateTime::from_timestamp(entry.modified_date.duration_since(UNIX_EPOCH).expect("Invalid file date").as_secs() as i64, 0).to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); - } + CheckingMethod::None => { + panic!(); } } - 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(); + *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; + } else { + buttons_save.hide(); + buttons_delete.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; } } - - print_text_messages_to_text_view(&text_messages, &text_view_errors); } + "scrolled_window_empty_folder_finder" => { + // Find empty folders + // TODO Change to proper value + let mut ef = EmptyFolder::new(); - // Set state - { - *shared_duplication_state.borrow_mut() = df; + ef.set_included_directory("/home/rafal/Pulpit".to_string()); + ef.set_delete_folder(false); + ef.find_empty_folders(); - if duplicates_size > 0 { - buttons_save.show(); - buttons_delete.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; - } else { - buttons_save.hide(); - buttons_delete.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; + 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_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, 3]; + + 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; 4] = [ + &(name[index + 1..].to_string()), + &(name[..index].to_string()), + &(NaiveDateTime::from_timestamp(entry.modified_date.duration_since(UNIX_EPOCH).expect("Invalid file date").as_secs() as i64, 0).to_string()), + &(MAIN_ROW_COLOR.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; + } } } + e => panic!("Not existent {}", e), + } + }); + } + // Delete button + { + buttons_delete.connect_clicked(move |_| match notebook_chooser_tool_children_names.get(notebook_chooser_tool.get_current_page().unwrap() as usize).unwrap().as_str() { + "notebook_duplicate_finder_label" => { + let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let selection = tree_view.get_selection(); + + let (selection_rows, tree_model) = selection.get_selected_rows(); + let list_store = tree_model.clone().downcast::().unwrap(); + + // let new_tree_model = TreeModel::new(); // TODO - maybe create new model when inserting a new data, because this seems to be not optimal when using thousands of rows + + let mut messages: String = "".to_string(); + + // Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data + for tree_path in selection_rows.iter().rev() { + let name = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Name as i32).get::().unwrap().unwrap(); + let path = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Path as i32).get::().unwrap().unwrap(); + + if fs::remove_file(format!("{}/{}", path, name)).is_err() { + messages += format!("Failed to remove file {}/{} because file doesn't exists or you don't have permissions.\n", path, name).as_str() + } + list_store.remove(&list_store.get_iter(&tree_path).unwrap()); + } + + text_view_errors.get_buffer().unwrap().set_text(messages.as_str()); + selection.unselect_all(); } "scrolled_window_empty_folder_finder" => { - // Find empty folders - // TODO Change to proper value - let mut ef = EmptyFolder::new(); + let tree_view = scrolled_window_empty_folder_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let selection = tree_view.get_selection(); - ef.set_included_directory("/home/rafal/Pulpit".to_string()); - ef.set_delete_folder(false); - ef.find_empty_folders(); + let (selection_rows, tree_model) = selection.get_selected_rows(); + let list_store = tree_model.clone().downcast::().unwrap(); - let information = ef.get_information(); - let text_messages = ef.get_text_messages(); + // let new_tree_model = TreeModel::new(); // TODO - maybe create new model when inserting a new data, because this seems to be not optimal when using thousands of rows - let empty_folder_number: usize = information.number_of_empty_folders; + let mut messages: String = "".to_string(); - entry_info.set_text(format!("Found {} empty folders.", empty_folder_number).as_str()); + // Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data + for tree_path in selection_rows.iter().rev() { + let name = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Name as i32).get::().unwrap().unwrap(); + let path = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Path as i32).get::().unwrap().unwrap(); - // Create GUI - { - let list_store = scrolled_window_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, 3]; - - 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; 4] = [ - &(name[index + 1..].to_string()), - &(name[..index].to_string()), - &(NaiveDateTime::from_timestamp(entry.modified_date.duration_since(UNIX_EPOCH).expect("Invalid file date").as_secs() as i64, 0).to_string()), - &(MAIN_ROW_COLOR.to_string()), - ]; - list_store.set(&list_store.append(), &col_indices, &values); + if fs::remove_dir(format!("{}/{}", path, name)).is_err() { + messages += format!("Failed to folder {}/{} due lack of permissions, selected dir is not empty or doesn't exists.\n", path, name).as_str() } - print_text_messages_to_text_view(&text_messages, &text_view_errors); + list_store.remove(&list_store.get_iter(&tree_path).unwrap()); } - // 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; - } - } + text_view_errors.get_buffer().unwrap().set_text(messages.as_str()); + selection.unselect_all(); } e => panic!("Not existent {}", e), - } - }); + }); + } } - // Delete button + // Upper Notepad { - buttons_delete.connect_clicked(move |_| match notebook_chooser_tool_children_names.get(notebook_chooser_tool.get_current_page().unwrap() as usize).unwrap().as_str() { - "notebook_duplicate_finder_label" => { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); - let selection = tree_view.get_selection(); - - let (selection_rows, tree_model) = selection.get_selected_rows(); - let list_store = tree_model.clone().downcast::().unwrap(); - - // let new_tree_model = TreeModel::new(); // TODO - maybe create new model when inserting a new data, because this seems to be not optimal when using thousands of rows - - let mut messages: String = "".to_string(); - - // Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data - for tree_path in selection_rows.iter().rev() { - let name = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Name as i32).get::().unwrap().unwrap(); - let path = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Path as i32).get::().unwrap().unwrap(); - - if fs::remove_file(format!("{}/{}", path, name)).is_err() { - messages += format!("Failed to remove file {}/{} because file doesn't exists or you don't have permissions.\n", path, name).as_str() - } - list_store.remove(&list_store.get_iter(&tree_path).unwrap()); - } - - text_view_errors.get_buffer().unwrap().set_text(messages.as_str()); - selection.unselect_all(); - } - "scrolled_window_empty_folder_finder" => { - let tree_view = scrolled_window_empty_folder_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); - let selection = tree_view.get_selection(); - - let (selection_rows, tree_model) = selection.get_selected_rows(); - let list_store = tree_model.clone().downcast::().unwrap(); - - // let new_tree_model = TreeModel::new(); // TODO - maybe create new model when inserting a new data, because this seems to be not optimal when using thousands of rows - - let mut messages: String = "".to_string(); - - // Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data - for tree_path in selection_rows.iter().rev() { - let name = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Name as i32).get::().unwrap().unwrap(); - let path = tree_model.get_value(&tree_model.get_iter(&tree_path).unwrap(), Columns3Default::Path as i32).get::().unwrap().unwrap(); - - if fs::remove_dir(format!("{}/{}", path, name)).is_err() { - messages += format!("Failed to folder {}/{} due lack of permissions, selected dir is not empty or doesn't exists.\n", path, name).as_str() - } - list_store.remove(&list_store.get_iter(&tree_path).unwrap()); - } - - text_view_errors.get_buffer().unwrap().set_text(messages.as_str()); - selection.unselect_all(); - } - e => panic!("Not existent {}", e), - }); + // Add excluded directory + {} } }