Add similar images support for GUI (#69)
This commit is contained in:
parent
3dd203f246
commit
1178e145ae
|
@ -1,5 +1,9 @@
|
|||
## Version 1.1.1 -
|
||||
- Add test suite to PR
|
||||
- Replace String with PathBuf for paths [#59](https://github.com/qarmin/czkawka/pull/59)
|
||||
- Add test suite to PR [#65](https://github.com/qarmin/czkawka/pull/65)
|
||||
- Support for finding similar images to CLI [#66](https://github.com/qarmin/czkawka/pull/66)
|
||||
- Fix grammar-related errors and Ponglish expressions [#62](https://github.com/qarmin/czkawka/pull/62), [#63](https://github.com/qarmin/czkawka/pull/63)
|
||||
- Don't delete by default files in duplicate finder in CLI - [23f203](https://github.com/qarmin/czkawka/commit/23f203a061e254275c95ca23ca4f1a78bd941f02)
|
||||
|
||||
|
||||
|
||||
|
@ -19,6 +23,7 @@
|
|||
- Fixed crash with invalid file modification date [#33](https://github.com/qarmin/czkawka/issues/33)
|
||||
- Upper tabs can hide and show when this is necessary [#38](https://github.com/qarmin/czkawka/pull/38)
|
||||
- Fixed crash when file/folder name have non Unicode character [#44](https://github.com/qarmin/czkawka/issues/44)
|
||||
- Added support for finding similar pictures in GUI [#69](https://github.com/qarmin/czkawka/issues/69)
|
||||
|
||||
## Version 1.0.0 - 02.10.2020r
|
||||
- Added confirmation button to delete button
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Instruction
|
||||
|
||||
TODO
|
||||
## GUI
|
||||
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ Differences should be more visible when using slower CPU or faster disk.
|
|||
| Empty folders | X | X |
|
||||
| Temporary files | X | X |
|
||||
| Big files | X | |
|
||||
| Similar images | X | |
|
||||
| Installed packages | | X |
|
||||
| Invalid names | | X |
|
||||
| Names conflict | | X |
|
||||
|
|
|
@ -95,6 +95,10 @@ impl SimilarImages {
|
|||
&self.text_messages
|
||||
}
|
||||
|
||||
pub const fn get_similar_images(&self) -> &Vec<StructSimilar> {
|
||||
&self.similar_vectors
|
||||
}
|
||||
|
||||
pub const fn get_information(&self) -> &Info {
|
||||
&self.information
|
||||
}
|
||||
|
@ -259,6 +263,9 @@ impl SimilarImages {
|
|||
|
||||
let mut new_vector: Vec<StructSimilar> = Vec::new();
|
||||
for (string_hash, vec_file_entry) in &self.image_hashes {
|
||||
if rx.is_some() && rx.unwrap().try_recv().is_ok() {
|
||||
return false;
|
||||
}
|
||||
let vector_with_found_similar_hashes = self.bktree.find(string_hash.as_str(), 3).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
|
||||
|
|
|
@ -970,6 +970,84 @@ Author: Rafał Mikrut
|
|||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="notebook_main_similar_images_finder_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">8</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Minimal file size(in bytes)</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry_similar_images_minimal_size">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="max_length">15</property>
|
||||
<property name="text" translatable="yes">16384</property>
|
||||
<property name="caps_lock_warning">False</property>
|
||||
<property name="input_purpose">number</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window_similar_images_finder">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Similar Images</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">5</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use czkawka_core::common_messages::Messages;
|
||||
use czkawka_core::similar_files::Similarity;
|
||||
use gtk::prelude::*;
|
||||
use gtk::TreeViewColumn;
|
||||
use std::collections::HashMap;
|
||||
|
@ -39,6 +40,12 @@ pub enum ColumnsTemporaryFiles {
|
|||
Path,
|
||||
Modification,
|
||||
}
|
||||
pub enum ColumnsSimilarImages {
|
||||
Similarity = 0,
|
||||
Name,
|
||||
Path,
|
||||
Modification,
|
||||
}
|
||||
|
||||
pub const TEXT_COLOR: &str = "#ffffff";
|
||||
pub const MAIN_ROW_COLOR: &str = "#343434";
|
||||
|
@ -216,6 +223,46 @@ pub fn create_tree_view_empty_files(tree_view: &mut gtk::TreeView) {
|
|||
tree_view.set_vexpand(true);
|
||||
}
|
||||
|
||||
pub fn create_tree_view_similar_images(tree_view: &mut gtk::TreeView) {
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let name_column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
name_column.pack_start(&renderer, true);
|
||||
name_column.set_title("Similarity");
|
||||
name_column.set_resizable(true);
|
||||
name_column.set_min_width(50);
|
||||
name_column.add_attribute(&renderer, "text", ColumnsSimilarImages::Similarity as i32);
|
||||
|
||||
tree_view.append_column(&name_column);
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let name_column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
name_column.pack_start(&renderer, true);
|
||||
name_column.set_title("File Name");
|
||||
name_column.set_resizable(true);
|
||||
name_column.set_min_width(50);
|
||||
name_column.add_attribute(&renderer, "text", ColumnsSimilarImages::Name as i32);
|
||||
tree_view.append_column(&name_column);
|
||||
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let path_column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
path_column.pack_start(&renderer, true);
|
||||
path_column.set_title("Path");
|
||||
path_column.set_resizable(true);
|
||||
path_column.set_min_width(100);
|
||||
path_column.add_attribute(&renderer, "text", ColumnsSimilarImages::Path as i32);
|
||||
tree_view.append_column(&path_column);
|
||||
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let modification_date_column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
modification_date_column.pack_start(&renderer, true);
|
||||
modification_date_column.set_title("Modification Date");
|
||||
modification_date_column.set_resizable(true);
|
||||
modification_date_column.set_min_width(100);
|
||||
modification_date_column.add_attribute(&renderer, "text", ColumnsSimilarImages::Modification as i32);
|
||||
tree_view.append_column(&modification_date_column);
|
||||
|
||||
tree_view.set_vexpand(true);
|
||||
}
|
||||
|
||||
pub fn create_tree_view_directories(tree_view: &mut gtk::TreeView) {
|
||||
let renderer = gtk::CellRendererText::new();
|
||||
let name_column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||
|
@ -285,7 +332,7 @@ pub fn print_text_messages_to_text_view(text_messages: &Messages, text_view: >
|
|||
text_view.get_buffer().unwrap().set_text(messages.as_str());
|
||||
}
|
||||
|
||||
pub fn select_function_3column(_tree_selection: >k::TreeSelection, tree_model: >k::TreeModel, tree_path: >k::TreePath, _is_path_currently_selected: bool) -> bool {
|
||||
pub fn select_function_duplicates(_tree_selection: >k::TreeSelection, tree_model: >k::TreeModel, tree_path: >k::TreePath, _is_path_currently_selected: bool) -> bool {
|
||||
// let name = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(),ColumnsDuplicates::Name as i32).get::<String>().unwrap().unwrap();
|
||||
// let path = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsDuplicates::Path as i32).get::<String>().unwrap().unwrap();
|
||||
// let modification = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(),ColumnsDuplicates::Modification as i32).get::<String>().unwrap().unwrap();
|
||||
|
@ -297,6 +344,15 @@ pub fn select_function_3column(_tree_selection: >k::TreeSelection, tree_model:
|
|||
|
||||
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 path = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsSimilarImages::Path as i32).get::<String>().unwrap().unwrap();
|
||||
|
||||
if path.trim() == "" {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_buttons(hashmap: &mut HashMap<String, bool>, buttons_array: &[gtk::Button], button_names: &[&str]) {
|
||||
for (index, button) in buttons_array.iter().enumerate() {
|
||||
|
@ -322,3 +378,13 @@ pub fn hide_all_buttons_except(except_name: &str, buttons_array: &[gtk::Button],
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_text_from_similarity(similarity: &Similarity) -> &str {
|
||||
match similarity {
|
||||
Similarity::None => "Original",
|
||||
Similarity::Small => "Small",
|
||||
Similarity::Medium => "Medium",
|
||||
Similarity::High => "High",
|
||||
Similarity::VeryHigh => "Very High",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use czkawka_core::common_traits::SaveResults;
|
|||
use czkawka_core::duplicate::CheckingMethod;
|
||||
use czkawka_core::empty_files::EmptyFiles;
|
||||
use czkawka_core::empty_folder::EmptyFolder;
|
||||
use czkawka_core::similar_files::SimilarImages;
|
||||
use czkawka_core::temporary::Temporary;
|
||||
use duplicate::DuplicateFinder;
|
||||
use gtk::prelude::*;
|
||||
|
@ -61,7 +62,7 @@ fn main() {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// States
|
||||
let main_notebooks_labels = ["duplicate", "empty_folder", "empty_file", "temporary_file", "big_file"];
|
||||
let main_notebooks_labels = ["duplicate", "empty_folder", "empty_file", "temporary_file", "big_file", "similar_images"];
|
||||
let upper_notebooks_labels = [/*"general",*/ "included_directories", "excluded_directories", "excluded_items", "allowed_extensions"];
|
||||
let buttons_labels = ["search", "stop", "resume", "pause", "select", "delete", "save"];
|
||||
|
||||
|
@ -104,6 +105,7 @@ fn main() {
|
|||
let shared_empty_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(EmptyFiles::new()));
|
||||
let shared_temporary_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(Temporary::new()));
|
||||
let shared_big_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(BigFile::new()));
|
||||
let shared_similar_images_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SimilarImages::new()));
|
||||
|
||||
// State of confirmation dialogs
|
||||
let shared_confirmation_dialog_delete_dialog_showing_state: Rc<RefCell<_>> = Rc::new(RefCell::new(true));
|
||||
|
@ -111,6 +113,7 @@ fn main() {
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// GUI Entry
|
||||
let entry_similar_images_minimal_size: gtk::Entry = builder.get_object("entry_similar_images_minimal_size").unwrap();
|
||||
let entry_duplicate_minimal_size: gtk::Entry = builder.get_object("entry_duplicate_minimal_size").unwrap();
|
||||
let entry_allowed_extensions: gtk::Entry = builder.get_object("entry_allowed_extensions").unwrap();
|
||||
let entry_excluded_items: gtk::Entry = builder.get_object("entry_excluded_items").unwrap();
|
||||
|
@ -182,13 +185,13 @@ fn main() {
|
|||
let text_view_errors: gtk::TextView = builder.get_object("text_view_errors").unwrap();
|
||||
|
||||
//// Scrolled windows
|
||||
|
||||
// Main notebook
|
||||
let scrolled_window_duplicate_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_duplicate_finder").unwrap();
|
||||
let scrolled_window_main_empty_folder_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_main_empty_folder_finder").unwrap();
|
||||
let scrolled_window_main_empty_files_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_main_empty_files_finder").unwrap();
|
||||
let scrolled_window_main_temporary_files_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_main_temporary_files_finder").unwrap();
|
||||
let scrolled_window_big_files_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_big_files_finder").unwrap();
|
||||
let scrolled_window_similar_images_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_similar_images_finder").unwrap();
|
||||
|
||||
// Upper notebook
|
||||
let scrolled_window_included_directories: gtk::ScrolledWindow = builder.get_object("scrolled_window_included_directories").unwrap();
|
||||
|
@ -202,6 +205,7 @@ fn main() {
|
|||
EmptyFiles(EmptyFiles),
|
||||
BigFiles(BigFile),
|
||||
Temporary(Temporary),
|
||||
SimilarImages(SimilarImages),
|
||||
}
|
||||
|
||||
// Used for getting data from thread
|
||||
|
@ -240,7 +244,7 @@ fn main() {
|
|||
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_3column)));
|
||||
tree_view.get_selection().set_select_function(Some(Box::new(select_function_duplicates)));
|
||||
|
||||
create_tree_view_duplicates(&mut tree_view);
|
||||
|
||||
|
@ -303,6 +307,22 @@ fn main() {
|
|||
scrolled_window_big_files_finder.add(&tree_view);
|
||||
scrolled_window_big_files_finder.show_all();
|
||||
}
|
||||
// Similar Images
|
||||
{
|
||||
// TODO create maybe open button to support opening multiple files at once
|
||||
let col_types: [glib::types::Type; 4] = [glib::types::Type::String, glib::types::Type::String, glib::types::Type::String, glib::types::Type::String];
|
||||
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
||||
|
||||
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);
|
||||
|
||||
scrolled_window_similar_images_finder.add(&tree_view);
|
||||
scrolled_window_similar_images_finder.show_all();
|
||||
}
|
||||
}
|
||||
|
||||
// Set Included Directory
|
||||
|
@ -398,6 +418,7 @@ fn main() {
|
|||
"scrolled_window_main_empty_files_finder" => page = "empty_file",
|
||||
"scrolled_window_main_temporary_files_finder" => page = "temporary_file",
|
||||
"notebook_big_main_file_finder" => page = "big_file",
|
||||
"notebook_main_similar_images_finder_label" => page = "similar_images",
|
||||
e => {
|
||||
panic!("Not existent page {}", e);
|
||||
}
|
||||
|
@ -431,11 +452,6 @@ fn main() {
|
|||
|
||||
// Main buttons
|
||||
{
|
||||
assert!(notebook_main_children_names.contains(&"notebook_main_duplicate_finder_label".to_string()));
|
||||
assert!(notebook_main_children_names.contains(&"scrolled_window_main_empty_folder_finder".to_string()));
|
||||
assert!(notebook_main_children_names.contains(&"scrolled_window_main_empty_files_finder".to_string()));
|
||||
assert!(notebook_main_children_names.contains(&"scrolled_window_main_temporary_files_finder".to_string()));
|
||||
assert!(notebook_main_children_names.contains(&"notebook_big_main_file_finder".to_string()));
|
||||
// Search button
|
||||
{
|
||||
let entry_info = entry_info.clone();
|
||||
|
@ -457,7 +473,7 @@ fn main() {
|
|||
// Disable main notebook from any iteraction until search will end
|
||||
notebook_main.set_sensitive(false);
|
||||
|
||||
entry_info.set_text("Searching data, please wait...");
|
||||
entry_info.set_text("Searching data, it may take a while please wait...");
|
||||
|
||||
match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||
"notebook_main_duplicate_finder_label" => {
|
||||
|
@ -562,6 +578,29 @@ fn main() {
|
|||
let _ = sender.send(Message::BigFiles(bf));
|
||||
});
|
||||
}
|
||||
|
||||
"notebook_main_similar_images_finder_label" => {
|
||||
let sender = sender.clone();
|
||||
let receiver_stop = rx.clone();
|
||||
|
||||
let minimal_file_size = match entry_similar_images_minimal_size.get_text().as_str().parse::<u64>() {
|
||||
Ok(t) => t,
|
||||
Err(_) => 1024 * 16, // By default
|
||||
};
|
||||
|
||||
// Find similar images
|
||||
thread::spawn(move || {
|
||||
let mut sf = SimilarImages::new();
|
||||
|
||||
sf.set_included_directory(included_directories);
|
||||
sf.set_excluded_directory(excluded_directories);
|
||||
sf.set_recursive_search(recursive_search);
|
||||
sf.set_excluded_items(excluded_items);
|
||||
sf.set_minimal_file_size(minimal_file_size);
|
||||
sf.find_similar_images(Option::from(&receiver_stop));
|
||||
let _ = sender.send(Message::SimilarImages(sf));
|
||||
});
|
||||
}
|
||||
e => panic!("Not existent {}", e),
|
||||
}
|
||||
});
|
||||
|
@ -577,6 +616,7 @@ fn main() {
|
|||
let scrolled_window_big_files_finder = scrolled_window_big_files_finder.clone();
|
||||
let scrolled_window_main_empty_files_finder = scrolled_window_main_empty_files_finder.clone();
|
||||
let scrolled_window_main_temporary_files_finder = scrolled_window_main_temporary_files_finder.clone();
|
||||
let scrolled_window_similar_images_finder = scrolled_window_similar_images_finder.clone();
|
||||
|
||||
buttons_delete.connect_clicked(move |_| {
|
||||
if *shared_confirmation_dialog_delete_dialog_showing_state.borrow_mut() {
|
||||
|
@ -799,6 +839,39 @@ fn main() {
|
|||
text_view_errors.get_buffer().unwrap().set_text(messages.as_str());
|
||||
selection.unselect_all();
|
||||
}
|
||||
"notebook_main_similar_images_finder_label" => {
|
||||
let tree_view = scrolled_window_similar_images_finder.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap();
|
||||
let selection = tree_view.get_selection();
|
||||
|
||||
let (selection_rows, tree_model) = selection.get_selected_rows();
|
||||
let list_store = tree_model.clone().downcast::<gtk::ListStore>().unwrap();
|
||||
|
||||
// let new_tree_model = TreeModel::new(); // TODO - maybe create new model when inserting a new data, because this seems to be not optimal when using thousands of rows
|
||||
|
||||
let mut messages: String = "".to_string();
|
||||
|
||||
// Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data
|
||||
for tree_path in selection_rows.iter().rev() {
|
||||
let name = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsBigFiles::Name as i32).get::<String>().unwrap().unwrap();
|
||||
let path = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), ColumnsBigFiles::Path as i32).get::<String>().unwrap().unwrap();
|
||||
|
||||
match fs::remove_file(format!("{}/{}", path, name)) {
|
||||
Ok(_) => {
|
||||
list_store.remove(&list_store.get_iter(tree_path).unwrap());
|
||||
}
|
||||
Err(_) => {
|
||||
messages += format!(
|
||||
"Failed to remove file {}/{}. It is possible that you already deleted it, because similar images shows all possible file doesn't exists or you don't have permissions.\n",
|
||||
path, name
|
||||
)
|
||||
.as_str()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text_view_errors.get_buffer().unwrap().set_text(messages.as_str());
|
||||
selection.unselect_all();
|
||||
}
|
||||
e => panic!("Not existent {}", e),
|
||||
}
|
||||
});
|
||||
|
@ -815,18 +888,6 @@ fn main() {
|
|||
popover_select.set_relative_to(Some(&buttons_select));
|
||||
popover_select.popup();
|
||||
}
|
||||
"scrolled_window_main_empty_folder_finder" => {
|
||||
// Do nothing
|
||||
}
|
||||
"scrolled_window_main_empty_files_finder" => {
|
||||
// Do nothing
|
||||
}
|
||||
"scrolled_window_main_temporary_files_finder" => {
|
||||
// Do nothing
|
||||
}
|
||||
"notebook_big_main_file_finder" => {
|
||||
// Do nothing
|
||||
}
|
||||
e => panic!("Not existent {}", e),
|
||||
});
|
||||
}
|
||||
|
@ -840,6 +901,7 @@ fn main() {
|
|||
let shared_big_files_state = shared_big_files_state.clone();
|
||||
let shared_temporary_files_state = shared_temporary_files_state.clone();
|
||||
let shared_empty_files_state = shared_empty_files_state.clone();
|
||||
let shared_similar_images_state = shared_similar_images_state.clone();
|
||||
let notebook_main = notebook_main.clone();
|
||||
buttons_save_clone.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||
"notebook_main_duplicate_finder_label" => {
|
||||
|
@ -907,6 +969,19 @@ fn main() {
|
|||
*shared_buttons.borrow_mut().get_mut("big_file").unwrap().get_mut("save").unwrap() = false;
|
||||
}
|
||||
}
|
||||
"notebook_main_similar_images_finder_label" => {
|
||||
let file_name = "results_similar_images.txt";
|
||||
|
||||
let mut df = shared_similar_images_state.borrow_mut();
|
||||
df.save_results_to_file(file_name);
|
||||
|
||||
entry_info.set_text(format!("Saved results to file {}", file_name).as_str());
|
||||
// Set state
|
||||
{
|
||||
buttons_save.hide();
|
||||
*shared_buttons.borrow_mut().get_mut("similar_images").unwrap().get_mut("save").unwrap() = false;
|
||||
}
|
||||
}
|
||||
e => panic!("Not existent {}", e),
|
||||
});
|
||||
}
|
||||
|
@ -1745,6 +1820,97 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
Message::SimilarImages(sf) => {
|
||||
if sf.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 = sf.get_information();
|
||||
let text_messages = sf.get_text_messages();
|
||||
|
||||
let base_images_size = sf.get_similar_images().len();
|
||||
|
||||
entry_info.set_text(format!("Found similar pictures for {} images.", base_images_size).as_str());
|
||||
|
||||
// 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 col_indices = [0, 1, 2, 3];
|
||||
|
||||
let vec_struct_similar = sf.get_similar_images();
|
||||
|
||||
for (index, struct_similar) in vec_struct_similar.iter().enumerate() {
|
||||
// Empty at the beginning
|
||||
if index != 0 {
|
||||
let values: [&dyn ToValue; 4] = [&"".to_string(), &"".to_string(), &"".to_string(), &"".to_string()];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
// Header
|
||||
let (directory, file) = split_path(&struct_similar.base_image.path);
|
||||
let values: [&dyn ToValue; 4] = [
|
||||
&(get_text_from_similarity(&struct_similar.base_image.similarity).to_string()),
|
||||
&file,
|
||||
&directory,
|
||||
&(NaiveDateTime::from_timestamp(struct_similar.base_image.modified_date as i64, 0).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);
|
||||
let values: [&dyn ToValue; 4] = [
|
||||
&(get_text_from_similarity(&similar_images.similarity).to_string()),
|
||||
&file,
|
||||
&directory,
|
||||
&(NaiveDateTime::from_timestamp(similar_images.modified_date as i64, 0).to_string()),
|
||||
];
|
||||
list_store.set(&list_store.append(), &col_indices, &values);
|
||||
}
|
||||
}
|
||||
|
||||
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||
}
|
||||
|
||||
// Set state
|
||||
{
|
||||
*shared_similar_images_state.borrow_mut() = sf;
|
||||
|
||||
if base_images_size > 0 {
|
||||
*shared_buttons.borrow_mut().get_mut("similar_images").unwrap().get_mut("save").unwrap() = true;
|
||||
*shared_buttons.borrow_mut().get_mut("similar_images").unwrap().get_mut("delete").unwrap() = true;
|
||||
} else {
|
||||
*shared_buttons.borrow_mut().get_mut("similar_images").unwrap().get_mut("save").unwrap() = false;
|
||||
*shared_buttons.borrow_mut().get_mut("similar_images").unwrap().get_mut("delete").unwrap() = false;
|
||||
}
|
||||
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("similar_images").unwrap(), &buttons_array, &buttons_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Returning false here would close the receiver and have senders fail
|
||||
glib::Continue(true)
|
||||
|
|
Loading…
Reference in a new issue