1
0
Fork 0
mirror of synced 2024-04-29 01:52:39 +12:00

Similar images improvements: (#97)

Headers without data
By default only checking for High Similarity(faster search)
This commit is contained in:
Rafał Mikrut 2020-11-07 16:26:40 +01:00 committed by GitHub
parent 5d4f4db8c1
commit 110d6015bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 162 additions and 291 deletions

View file

@ -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},
};

View file

@ -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");

View file

@ -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!();
}
}
}
}

View file

@ -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>

View file

@ -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

View file

@ -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];

View file

@ -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();

View file

@ -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::*;

View file

@ -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: &gtk::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: &gtk::TreeSelection, tree_mod
true
}
pub fn select_function_similar_images(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::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: &gtk::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: &gtk::ScrolledWindow) -> TreeView {
let tree_view = scrolled_window.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap();
tree_view
}

View file

@ -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);