Similar images improvements: (#97)
Headers without data By default only checking for High Similarity(faster search)
This commit is contained in:
parent
5d4f4db8c1
commit
110d6015bc
|
@ -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},
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<FileEntry>,
|
||||
}
|
||||
|
||||
/// 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<Node, Hamming>,
|
||||
similar_vectors: Vec<StructSimilar>,
|
||||
similar_vectors: Vec<Vec<FileEntry>>,
|
||||
recursive_search: bool,
|
||||
minimal_file_size: u64,
|
||||
image_hashes: HashMap<Node, Vec<FileEntry>>, // 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<StructSimilar> {
|
||||
pub const fn get_similar_images(&self) -> &Vec<Vec<FileEntry>> {
|
||||
&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<StructSimilar> = 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<FileEntry>> = 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::<Vec<_>>();
|
||||
let vector_with_found_similar_hashes = self.bktree.find(hash, similarity).collect::<Vec<_>>();
|
||||
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<StructSimilar> = 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<FileEntry>>(),
|
||||
};
|
||||
vec_similarity_struct.push(similar_struct);
|
||||
}
|
||||
let mut vector_of_similar_images: Vec<FileEntry> = 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::<Vec<_>>()),
|
||||
);
|
||||
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!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -135,8 +135,8 @@ Author: Rafał Mikrut
|
|||
</object>
|
||||
<object class="GtkWindow" id="window_main">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="default_width">1000</property>
|
||||
<property name="default_height">700</property>
|
||||
<property name="default_width">1100</property>
|
||||
<property name="default_height">800</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
|
|
|
@ -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<Message>) {
|
|||
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<Message>) {
|
|||
|
||||
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<Message>) {
|
|||
});
|
||||
}
|
||||
"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<Message>) {
|
|||
});
|
||||
}
|
||||
"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<Message>) {
|
|||
});
|
||||
}
|
||||
"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<Message>) {
|
|||
});
|
||||
}
|
||||
"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::<usize>() {
|
||||
Ok(t) => t,
|
||||
Err(_) => 50, // By default
|
||||
|
@ -163,6 +177,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender<Message>) {
|
|||
}
|
||||
|
||||
"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<Message>) {
|
|||
});
|
||||
}
|
||||
"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<Message>) {
|
|||
});
|
||||
}
|
||||
"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::<u64>() {
|
||||
Ok(t) => t,
|
||||
Err(_) => 1024, // By default
|
||||
|
|
|
@ -46,20 +46,6 @@ pub fn connect_compute_results(gui_data: &GuiData, receiver: Receiver<Message>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_duplicate_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_main_empty_folder_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_main_empty_files_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_big_files_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_main_temporary_files_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_similar_images_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_zeroed_files_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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>)
|
|||
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::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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<Message>)
|
|||
|
||||
// Create GUI
|
||||
{
|
||||
let list_store = scrolled_window_same_music_finder
|
||||
.get_children()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.downcast::<gtk::TreeView>()
|
||||
.unwrap()
|
||||
.get_model()
|
||||
.unwrap()
|
||||
.downcast::<gtk::ListStore>()
|
||||
.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];
|
||||
|
||||
|
|
|
@ -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::<gtk::TreeView>().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::<gtk::TreeView>().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::<gtk::TreeView>().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::<gtk::TreeView>().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::<gtk::TreeView>().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::<gtk::TreeView>().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::<gtk::TreeView>().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();
|
||||
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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::<gtk::TreeView>().unwrap();
|
||||
let list_store: gtk::ListStore = tree_view.get_model().unwrap().downcast::<gtk::ListStore>().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::<String>().unwrap().unwrap();
|
||||
|
||||
if color == HEADER_ROW_COLOR {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_buttons(hashmap: &mut HashMap<String, bool>, 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::<gtk::TreeView>().unwrap().get_model().unwrap().downcast::<gtk::ListStore>().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::<gtk::TreeView>().unwrap();
|
||||
|
||||
tree_view
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue