diff --git a/czkawka_cli/src/main.rs b/czkawka_cli/src/main.rs index 9fc54ea..199d6bc 100644 --- a/czkawka_cli/src/main.rs +++ b/czkawka_cli/src/main.rs @@ -11,7 +11,7 @@ use czkawka_core::{ empty_files::{self, EmptyFiles}, empty_folder::EmptyFolder, same_music::SameMusic, - similar_files::SimilarImages, + similar_images::SimilarImages, temporary::{self, Temporary}, zeroed::{self, ZeroedFiles}, }; diff --git a/czkawka_core/src/lib.rs b/czkawka_core/src/lib.rs index 130ef37..787ab80 100644 --- a/czkawka_core/src/lib.rs +++ b/czkawka_core/src/lib.rs @@ -14,7 +14,7 @@ pub mod common_items; pub mod common_messages; pub mod common_traits; pub mod same_music; -pub mod similar_files; +pub mod similar_images; pub mod zeroed; pub const CZKAWKA_VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/czkawka_core/src/similar_files.rs b/czkawka_core/src/similar_images.rs similarity index 78% rename from czkawka_core/src/similar_files.rs rename to czkawka_core/src/similar_images.rs index 051254b..a7c724f 100644 --- a/czkawka_core/src/similar_files.rs +++ b/czkawka_core/src/similar_images.rs @@ -32,11 +32,6 @@ pub struct FileEntry { pub modified_date: u64, pub similarity: Similarity, } -#[derive(Clone)] -pub struct StructSimilar { - pub base_image: FileEntry, - pub similar_images: Vec, -} /// Type to store for each entry in the similarity BK-tree. type Node = [u8; 8]; @@ -57,11 +52,12 @@ pub struct SimilarImages { directories: Directories, excluded_items: ExcludedItems, bktree: BKTree, - similar_vectors: Vec, + similar_vectors: Vec>, recursive_search: bool, minimal_file_size: u64, image_hashes: HashMap>, // Hashmap with image hashes and Vector with names of files stopped_search: bool, + similarity: Similarity, } /// Info struck with helpful information's about results @@ -98,6 +94,7 @@ impl SimilarImages { minimal_file_size: 1024 * 16, // 16 KB should be enough to exclude too small images from search image_hashes: Default::default(), stopped_search: false, + similarity: Similarity::High, } } @@ -109,7 +106,7 @@ impl SimilarImages { &self.text_messages } - pub const fn get_similar_images(&self) -> &Vec { + pub const fn get_similar_images(&self) -> &Vec> { &self.similar_vectors } @@ -127,6 +124,9 @@ impl SimilarImages { t => t, }; } + pub fn set_similarity(&mut self, similarity: Similarity) { + self.similarity = similarity; + } /// Public function used by CLI to search for empty folders pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>) { @@ -135,6 +135,10 @@ impl SimilarImages { self.stopped_search = true; return; } + if !self.sort_images(stop_receiver) { + self.stopped_search = true; + return; + } // if self.delete_folders { // self.delete_empty_folders(); // } @@ -275,37 +279,51 @@ impl SimilarImages { } } } + Common::print_time(start_time, SystemTime::now(), "check_for_similar_images".to_string()); + true + } + fn sort_images(&mut self, stop_receiver: Option<&Receiver<()>>) -> bool { let hash_map_modification = SystemTime::now(); - let mut new_vector: Vec = Vec::new(); + //let hash_map_modification = SystemTime::now(); + let similarity: u64 = match self.similarity { + Similarity::VeryHigh => 0, + Similarity::High => 1, + Similarity::Medium => 2, + Similarity::Small => 3, + _ => panic!("0-3 similarity levels are allowed, check if not added more."), + }; + + // TODO + // Now is A is similar to B with VeryHigh and C with Medium + // And D is similar with C with High + // And Similarity is set to Medium(or lower) + // And A is checked before D + // Then C is shown that is similar group A, not D + + let mut new_vector: Vec> = Vec::new(); + let mut hashes_to_check = self.image_hashes.clone(); for (hash, vec_file_entry) in &self.image_hashes { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { return false; } - let vector_with_found_similar_hashes = self.bktree.find(hash, 3).collect::>(); + let vector_with_found_similar_hashes = self.bktree.find(hash, similarity).collect::>(); if vector_with_found_similar_hashes.len() == 1 && vec_file_entry.len() == 1 { - // Exists only 1 unique picture, so there is no need to use it + // This one picture doesn't have similar pictures, so there is no go continue; } - let mut vec_similarity_struct: Vec = Vec::new(); - - for file_entry in vec_file_entry.iter() { - let similar_struct = StructSimilar { - base_image: file_entry.clone(), - similar_images: vec_file_entry - .iter() - .filter(|x| x.path != file_entry.path) - .map(|x| { - let mut y = x.clone(); - y.similarity = Similarity::VeryHigh; - y - }) - .collect::>(), - }; - vec_similarity_struct.push(similar_struct); - } + let mut vector_of_similar_images: Vec = vec_file_entry + .iter() + .map(|fe| FileEntry { + path: fe.path.clone(), + size: fe.size, + dimensions: fe.dimensions.clone(), + modified_date: fe.modified_date, + similarity: Similarity::VeryHigh, + }) + .collect(); for (similarity, similar_hash) in vector_with_found_similar_hashes.iter() { if *similarity == 0 && hash == *similar_hash { @@ -315,31 +333,34 @@ impl SimilarImages { panic!("I'm not sure if same hash can have distance > 0"); } - for file_entry in self.image_hashes.get(*similar_hash).unwrap() { - let mut file_entry = file_entry.clone(); - file_entry.similarity = match similarity { - 0 => Similarity::VeryHigh, - 1 => Similarity::High, - 2 => Similarity::Medium, - 3 => Similarity::Small, - _ => panic!("0-3 similarity levels are allowed, check if not added more."), - }; - for similarity_struct in vec_similarity_struct.iter_mut() { - similarity_struct.similar_images.push(file_entry.clone()); - } + if let Some(vec_file_entry) = hashes_to_check.get(*similar_hash) { + vector_of_similar_images.append( + &mut (vec_file_entry + .iter() + .map(|fe| FileEntry { + path: fe.path.clone(), + size: fe.size, + dimensions: fe.dimensions.clone(), + modified_date: fe.modified_date, + similarity: match similarity { + 0 => Similarity::VeryHigh, + 1 => Similarity::High, + 2 => Similarity::Medium, + 3 => Similarity::Small, + _ => panic!("0-3 similarity levels are allowed, check if not added more."), + }, + }) + .collect::>()), + ); + hashes_to_check.remove(*similar_hash); } } - for similarity_struct in vec_similarity_struct.iter_mut() { - similarity_struct.similar_images.sort_by(|x, y| y.similarity.cmp(&x.similarity)); - } - new_vector.append(&mut vec_similarity_struct); + new_vector.push((*vector_of_similar_images).to_owned()); } self.similar_vectors = new_vector; - #[allow(clippy::blocks_in_if_conditions)] - Common::print_time(hash_map_modification, SystemTime::now(), "hash_map_modification(internal)".to_string()); - Common::print_time(start_time, SystemTime::now(), "check_for_similar_images".to_string()); + Common::print_time(hash_map_modification, SystemTime::now(), "sort_images".to_string()); true } @@ -413,13 +434,13 @@ impl SaveResults for SimilarImages { if !self.similar_vectors.is_empty() { write!(file, "{} images which have similar friends\n\n", self.similar_vectors.len()).unwrap(); - for struct_similar in self.similar_vectors.iter() { - writeln!(file, "Image {:?} have {} similar images", struct_similar.base_image.path, struct_similar.similar_images.len()).unwrap(); - for similar_picture in struct_similar.similar_images.iter() { - writeln!(file, "{:?} - Similarity Level: {}", similar_picture.path, get_string_from_similarity(&similar_picture.similarity)).unwrap(); - } - writeln!(file).unwrap(); - } + // for struct_similar in self.similar_vectors.iter() { + // writeln!(file, "Image {:?} have {} similar images", struct_similar.base_image.path, struct_similar.similar_images.len()).unwrap(); + // for similar_picture in struct_similar.similar_images.iter() { + // writeln!(file, "{:?} - Similarity Level: {}", similar_picture.path, get_string_from_similarity(&similar_picture.similarity)).unwrap(); + // } + // writeln!(file).unwrap(); + // } } else { write!(file, "Not found any similar images.").unwrap(); } @@ -432,6 +453,19 @@ impl PrintResults for SimilarImages { fn print_results(&self) { if !self.similar_vectors.is_empty() { println!("Found {} images which have similar friends", self.similar_vectors.len()); + + for vec_file_entry in &self.similar_vectors { + for file_entry in vec_file_entry { + println!( + "{} - {} - {} - {}", + file_entry.path.display(), + file_entry.dimensions, + file_entry.size.file_size(options::BINARY).unwrap(), + get_string_from_similarity(&file_entry.similarity) + ); + } + println!(); + } } } } diff --git a/czkawka_gui/czkawka.glade b/czkawka_gui/czkawka.glade index ea4d541..3ba7b16 100644 --- a/czkawka_gui/czkawka.glade +++ b/czkawka_gui/czkawka.glade @@ -135,8 +135,8 @@ Author: RafaƂ Mikrut False - 1000 - 700 + 1100 + 800 True diff --git a/czkawka_gui/src/connect_button_search.rs b/czkawka_gui/src/connect_button_search.rs index 4638005..f787878 100644 --- a/czkawka_gui/src/connect_button_search.rs +++ b/czkawka_gui/src/connect_button_search.rs @@ -8,7 +8,7 @@ use czkawka_core::duplicate::DuplicateFinder; use czkawka_core::empty_files::EmptyFiles; use czkawka_core::empty_folder::EmptyFolder; use czkawka_core::same_music::{MusicSimilarity, SameMusic}; -use czkawka_core::similar_files::SimilarImages; +use czkawka_core::similar_images::SimilarImages; use czkawka_core::temporary::Temporary; use czkawka_core::zeroed::ZeroedFiles; use glib::Sender; @@ -42,6 +42,14 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { let check_button_music_album_artist: gtk::CheckButton = gui_data.check_button_music_album_artist.clone(); let check_button_music_year: gtk::CheckButton = gui_data.check_button_music_year.clone(); let shared_buttons = gui_data.shared_buttons.clone(); + let scrolled_window_main_empty_folder_finder = gui_data.scrolled_window_main_empty_folder_finder.clone(); + let scrolled_window_main_empty_files_finder = gui_data.scrolled_window_main_empty_files_finder.clone(); + let scrolled_window_big_files_finder = gui_data.scrolled_window_big_files_finder.clone(); + let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone(); + let scrolled_window_main_temporary_files_finder = gui_data.scrolled_window_main_temporary_files_finder.clone(); + let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone(); + let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone(); + let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone(); buttons_search_clone.connect_clicked(move |_| { let included_directories = get_string_from_list_store(&scrolled_window_included_directories); @@ -59,6 +67,8 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() { "notebook_main_duplicate_finder_label" => { + get_list_store(&scrolled_window_duplicate_finder).clear(); + let check_method; if radio_button_name.get_active() { check_method = duplicate::CheckingMethod::Name; @@ -93,6 +103,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }); } "scrolled_window_main_empty_folder_finder" => { + get_list_store(&scrolled_window_main_empty_folder_finder).clear(); let sender = sender.clone(); let receiver_stop = stop_receiver.clone(); @@ -107,6 +118,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }); } "scrolled_window_main_empty_files_finder" => { + get_list_store(&scrolled_window_main_empty_files_finder).clear(); let sender = sender.clone(); let receiver_stop = stop_receiver.clone(); @@ -124,6 +136,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }); } "scrolled_window_main_temporary_files_finder" => { + get_list_store(&scrolled_window_main_temporary_files_finder).clear(); let sender = sender.clone(); let receiver_stop = stop_receiver.clone(); @@ -140,6 +153,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }); } "notebook_big_main_file_finder" => { + get_list_store(&scrolled_window_big_files_finder).clear(); let numbers_of_files_to_check = match entry_big_files_number.get_text().as_str().parse::() { Ok(t) => t, Err(_) => 50, // By default @@ -163,6 +177,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { } "notebook_main_similar_images_finder_label" => { + get_list_store(&scrolled_window_similar_images_finder).clear(); let sender = sender.clone(); let receiver_stop = stop_receiver.clone(); @@ -185,6 +200,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }); } "notebook_main_zeroed_files_finder" => { + get_list_store(&scrolled_window_zeroed_files_finder).clear(); let sender = sender.clone(); let receiver_stop = stop_receiver.clone(); @@ -202,6 +218,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }); } "notebook_main_same_music_finder" => { + get_list_store(&scrolled_window_same_music_finder).clear(); let minimal_file_size = match entry_same_music_minimal_size.get_text().as_str().parse::() { Ok(t) => t, Err(_) => 1024, // By default diff --git a/czkawka_gui/src/connect_compute_results.rs b/czkawka_gui/src/connect_compute_results.rs index 45e78b7..185102d 100644 --- a/czkawka_gui/src/connect_compute_results.rs +++ b/czkawka_gui/src/connect_compute_results.rs @@ -46,20 +46,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::Duplicates(df) => { if df.get_stopped_search() { entry_info.set_text("Searching for duplicated was stopped by user"); - - //Also clear list - scrolled_window_duplicate_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = df.get_information(); let text_messages = df.get_text_messages(); @@ -96,18 +82,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // 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 list_store = get_list_store(&scrolled_window_duplicate_finder); let col_indices = [0, 1, 2, 3, 4, 5]; @@ -223,20 +198,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::EmptyFolders(ef) => { if ef.get_stopped_search() { entry_info.set_text("Searching for empty folders was stopped by user"); - - //Also clear list - scrolled_window_main_empty_folder_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = ef.get_information(); let text_messages = ef.get_text_messages(); @@ -247,18 +208,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // 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 list_store = get_list_store(&scrolled_window_main_empty_folder_finder); let col_indices = [0, 1, 2]; @@ -290,20 +240,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::EmptyFiles(vf) => { if vf.get_stopped_search() { entry_info.set_text("Searching for empty files was stopped by user"); - - //Also clear list - scrolled_window_main_empty_files_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = vf.get_information(); let text_messages = vf.get_text_messages(); @@ -314,18 +250,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // 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 list_store = get_list_store(&scrolled_window_main_empty_files_finder); let col_indices = [0, 1, 2]; @@ -357,20 +282,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::BigFiles(bf) => { if bf.get_stopped_search() { entry_info.set_text("Searching for big files was stopped by user"); - - //Also clear list - scrolled_window_duplicate_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = bf.get_information(); let text_messages = bf.get_text_messages(); @@ -381,18 +292,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // 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 list_store = get_list_store(&scrolled_window_big_files_finder); let col_indices = [0, 1, 2, 3]; @@ -431,20 +331,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::Temporary(tf) => { if tf.get_stopped_search() { entry_info.set_text("Searching for temporary files was stopped by user"); - - //Also clear list - scrolled_window_duplicate_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = tf.get_information(); let text_messages = tf.get_text_messages(); @@ -455,18 +341,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // 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 list_store = get_list_store(&scrolled_window_main_temporary_files_finder); let col_indices = [0, 1, 2]; @@ -498,20 +373,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::SimilarImages(sf) => { if sf.get_stopped_search() { entry_info.set_text("Searching for duplicated was stopped by user"); - - //Also clear list - scrolled_window_similar_images_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { //let information = sf.get_information(); let text_messages = sf.get_text_messages(); @@ -522,48 +383,36 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // Create GUI { - let list_store = scrolled_window_similar_images_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); + let list_store = get_list_store(&scrolled_window_similar_images_finder); let col_indices = [0, 1, 2, 3, 4, 5, 6, 7]; let vec_struct_similar = sf.get_similar_images(); - for struct_similar in vec_struct_similar.iter() { + for vec_file_entry in vec_struct_similar.iter() { // Header - let (directory, file) = split_path(&struct_similar.base_image.path); let values: [&dyn ToValue; 8] = [ - &(get_text_from_similarity(&struct_similar.base_image.similarity).to_string()), - &struct_similar.base_image.size.file_size(options::BINARY).unwrap(), - &struct_similar.base_image.dimensions, - &file, - &directory, - &(NaiveDateTime::from_timestamp(struct_similar.base_image.modified_date as i64, 0).to_string()), + &"".to_string(), + &"".to_string(), + &"".to_string(), + &"".to_string(), + &"".to_string(), + &"".to_string(), &(HEADER_ROW_COLOR.to_string()), &(TEXT_COLOR.to_string()), ]; list_store.set(&list_store.append(), &col_indices, &values); // Meat - for similar_images in &struct_similar.similar_images { - let (directory, file) = split_path(&similar_images.path); + for file_entry in vec_file_entry.iter() { + let (directory, file) = split_path(&file_entry.path); let values: [&dyn ToValue; 8] = [ - &(get_text_from_similarity(&similar_images.similarity).to_string()), - &similar_images.size.file_size(options::BINARY).unwrap(), - &similar_images.dimensions, + &(get_text_from_similarity(&file_entry.similarity).to_string()), + &file_entry.size.file_size(options::BINARY).unwrap(), + &file_entry.dimensions, &file, &directory, - &(NaiveDateTime::from_timestamp(similar_images.modified_date as i64, 0).to_string()), + &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()), &(MAIN_ROW_COLOR.to_string()), &(TEXT_COLOR.to_string()), ]; @@ -592,20 +441,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::ZeroedFiles(zf) => { if zf.get_stopped_search() { entry_info.set_text("Searching for zeroed files was stopped by user"); - - //Also clear list - scrolled_window_zeroed_files_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = zf.get_information(); let text_messages = zf.get_text_messages(); @@ -616,18 +451,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // Create GUI { - let list_store = scrolled_window_zeroed_files_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); + let list_store = get_list_store(&scrolled_window_zeroed_files_finder); let col_indices = [0, 1, 2, 3]; @@ -664,20 +488,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) Message::SameMusic(mf) => { if mf.get_stopped_search() { entry_info.set_text("Searching for empty files was stopped by user"); - - //Also clear list - scrolled_window_same_music_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap() - .clear(); } else { let information = mf.get_information(); let text_messages = mf.get_text_messages(); @@ -688,18 +498,7 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver) // Create GUI { - let list_store = scrolled_window_same_music_finder - .get_children() - .get(0) - .unwrap() - .clone() - .downcast::() - .unwrap() - .get_model() - .unwrap() - .downcast::() - .unwrap(); - list_store.clear(); + let list_store = get_list_store(&scrolled_window_same_music_finder); let col_indices = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; diff --git a/czkawka_gui/src/connect_popover_duplicate.rs b/czkawka_gui/src/connect_popover_duplicate.rs index 5355b11..7adae2c 100644 --- a/czkawka_gui/src/connect_popover_duplicate.rs +++ b/czkawka_gui/src/connect_popover_duplicate.rs @@ -11,7 +11,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone(); let popover_select = gui_data.popover_select.clone(); buttons_popover_select_all.connect_clicked(move |_| { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); selection.select_all(); @@ -25,7 +25,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let buttons_popover_unselect_all = gui_data.buttons_popover_unselect_all.clone(); let popover_select = gui_data.popover_select.clone(); buttons_popover_unselect_all.connect_clicked(move |_| { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); selection.unselect_all(); @@ -39,7 +39,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let popover_select = gui_data.popover_select.clone(); let buttons_popover_reverse = gui_data.buttons_popover_reverse.clone(); buttons_popover_reverse.connect_clicked(move |_| { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); let (vector_tree_path, tree_model) = selection.get_selected_rows(); @@ -79,7 +79,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let popover_select = gui_data.popover_select.clone(); let buttons_popover_select_all_except_oldest = gui_data.buttons_popover_select_all_except_oldest.clone(); buttons_popover_select_all_except_oldest.connect_clicked(move |_| { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); let tree_model = tree_view.get_model().unwrap(); @@ -141,7 +141,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let popover_select = gui_data.popover_select.clone(); let buttons_popover_select_all_except_newest = gui_data.buttons_popover_select_all_except_newest.clone(); buttons_popover_select_all_except_newest.connect_clicked(move |_| { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); let tree_model = tree_view.get_model().unwrap(); @@ -203,7 +203,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let popover_select = gui_data.popover_select.clone(); let buttons_popover_select_one_oldest = gui_data.buttons_popover_select_one_oldest.clone(); buttons_popover_select_one_oldest.connect_clicked(move |_| { - let tree_view = scrolled_window_duplicate_finder.get_children().get(0).unwrap().clone().downcast::().unwrap(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); let tree_model = tree_view.get_model().unwrap(); @@ -264,7 +264,7 @@ pub fn connect_popover_duplicate(gui_data: &GuiData) { let buttons_popover_select_one_newest = gui_data.buttons_popover_select_one_newest.clone(); let popover_select = gui_data.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(); + let tree_view = get_tree_view(&scrolled_window_duplicate_finder); let selection = tree_view.get_selection(); let tree_model = tree_view.get_model().unwrap(); diff --git a/czkawka_gui/src/gui_data.rs b/czkawka_gui/src/gui_data.rs index 8d2be38..df1fefd 100644 --- a/czkawka_gui/src/gui_data.rs +++ b/czkawka_gui/src/gui_data.rs @@ -6,7 +6,7 @@ use czkawka_core::duplicate::DuplicateFinder; use czkawka_core::empty_files::EmptyFiles; use czkawka_core::empty_folder::EmptyFolder; use czkawka_core::same_music::SameMusic; -use czkawka_core::similar_files::SimilarImages; +use czkawka_core::similar_images::SimilarImages; use czkawka_core::temporary::Temporary; use czkawka_core::zeroed::ZeroedFiles; use gtk::prelude::*; diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index e2afeb9..8f8ad02 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -4,10 +4,11 @@ use czkawka_core::duplicate::DuplicateFinder; use czkawka_core::empty_files::EmptyFiles; use czkawka_core::empty_folder::EmptyFolder; use czkawka_core::same_music::SameMusic; -use czkawka_core::similar_files::{SimilarImages, Similarity}; +use czkawka_core::similar_images::{SimilarImages, Similarity}; use czkawka_core::temporary::Temporary; use czkawka_core::zeroed::ZeroedFiles; use gtk::prelude::*; +use gtk::{ListStore, TreeView}; use std::collections::HashMap; use std::path::Path; @@ -96,8 +97,7 @@ pub const HEADER_ROW_COLOR: &str = "#272727"; //pub const HEADER_ROW_COLOR: &str = "#010101"; // TEST pub fn get_string_from_list_store(scrolled_window: >k::ScrolledWindow) -> String { - let tree_view: gtk::TreeView = scrolled_window.get_children().get(0).unwrap().clone().downcast::().unwrap(); - let list_store: gtk::ListStore = tree_view.get_model().unwrap().downcast::().unwrap(); + let list_store: gtk::ListStore = get_list_store(&scrolled_window); let mut first: bool = true; let mut return_string: String = "".to_string(); @@ -182,6 +182,15 @@ pub fn select_function_same_music(_tree_selection: >k::TreeSelection, tree_mod true } +pub fn select_function_similar_images(_tree_selection: >k::TreeSelection, tree_model: >k::TreeModel, tree_path: >k::TreePath, _is_path_currently_selected: bool) -> bool { + let color = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsSimilarImages::Color as i32).get::().unwrap().unwrap(); + + if color == HEADER_ROW_COLOR { + return false; + } + + true +} pub fn set_buttons(hashmap: &mut HashMap, buttons_array: &[gtk::Button], button_names: &[String]) { for (index, button) in buttons_array.iter().enumerate() { @@ -217,3 +226,14 @@ pub fn get_text_from_similarity(similarity: &Similarity) -> &str { Similarity::VeryHigh => "Very High", } } + +pub fn get_list_store(scrolled_window: >k::ScrolledWindow) -> ListStore { + let list_store = scrolled_window.get_children().get(0).unwrap().clone().downcast::().unwrap().get_model().unwrap().downcast::().unwrap(); + + list_store +} +pub fn get_tree_view(scrolled_window: >k::ScrolledWindow) -> TreeView { + let tree_view = scrolled_window.get_children().get(0).unwrap().clone().downcast::().unwrap(); + + tree_view +} diff --git a/czkawka_gui/src/startup_configuration.rs b/czkawka_gui/src/startup_configuration.rs index bd0fb03..d05dae5 100644 --- a/czkawka_gui/src/startup_configuration.rs +++ b/czkawka_gui/src/startup_configuration.rs @@ -148,6 +148,7 @@ pub fn startup_configuration(gui_data: &GuiData) { let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store); tree_view.get_selection().set_mode(SelectionMode::Multiple); + tree_view.get_selection().set_select_function(Some(Box::new(select_function_similar_images))); create_tree_view_similar_images(&mut tree_view);