From 582e5417ac11445acd6ab4505a7e792993d7d7c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Wed, 10 May 2023 21:27:41 +0200 Subject: [PATCH] Unify progress data (#972) * Unify progress data code * Do not increment in threads values every time when finding file/folder(works quite good, may works bad with folders with ~several thousands of files) * Partial changes * Simplify creating tree_view * Allow setting thread number in CLI * Simplified code and add tests with help of copilot --- czkawka_cli/src/commands.rs | 28 + czkawka_cli/src/main.rs | 37 +- czkawka_core/src/bad_extensions.rs | 7 +- czkawka_core/src/big_file.rs | 7 +- czkawka_core/src/broken_files.rs | 9 +- czkawka_core/src/common.rs | 4 +- czkawka_core/src/common_dir_traversal.rs | 44 +- czkawka_core/src/duplicate.rs | 16 +- czkawka_core/src/empty_files.rs | 5 +- czkawka_core/src/empty_folder.rs | 5 +- czkawka_core/src/invalid_symlinks.rs | 5 +- czkawka_core/src/same_music.rs | 14 +- czkawka_core/src/similar_images.rs | 11 +- czkawka_core/src/similar_videos.rs | 9 +- czkawka_core/src/temporary.rs | 7 +- .../connect_things/connect_button_search.rs | 38 +- .../connect_things/connect_progress_window.rs | 452 +++++----- czkawka_gui/src/create_tree_view.rs | 824 ++++-------------- czkawka_gui/src/help_functions.rs | 61 +- czkawka_gui/src/initialize_gui.rs | 318 +++---- czkawka_gui/src/main.rs | 43 +- 21 files changed, 728 insertions(+), 1216 deletions(-) diff --git a/czkawka_cli/src/commands.rs b/czkawka_cli/src/commands.rs index 0e907b7..946b0a7 100644 --- a/czkawka_cli/src/commands.rs +++ b/czkawka_cli/src/commands.rs @@ -85,6 +85,8 @@ pub enum Commands { #[derive(Debug, clap::Args)] pub struct DuplicatesArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -163,6 +165,8 @@ pub struct DuplicatesArgs { #[derive(Debug, clap::Args)] pub struct EmptyFoldersArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -180,6 +184,8 @@ pub struct EmptyFoldersArgs { #[derive(Debug, clap::Args)] pub struct BiggestFilesArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -205,6 +211,8 @@ pub struct BiggestFilesArgs { #[derive(Debug, clap::Args)] pub struct EmptyFilesArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -226,6 +234,8 @@ pub struct EmptyFilesArgs { #[derive(Debug, clap::Args)] pub struct TemporaryArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -245,6 +255,8 @@ pub struct TemporaryArgs { #[derive(Debug, clap::Args)] pub struct SimilarImagesArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -313,6 +325,8 @@ pub struct SimilarImagesArgs { #[derive(Debug, clap::Args)] pub struct SameMusicArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -359,6 +373,8 @@ pub struct SameMusicArgs { #[derive(Debug, clap::Args)] pub struct InvalidSymlinksArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -380,6 +396,8 @@ pub struct InvalidSymlinksArgs { #[derive(Debug, clap::Args)] pub struct BrokenFilesArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -401,6 +419,8 @@ pub struct BrokenFilesArgs { #[derive(Debug, clap::Args)] pub struct SimilarVideosArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -449,6 +469,8 @@ pub struct SimilarVideosArgs { #[derive(Debug, clap::Args)] pub struct BadExtensionsArgs { + #[clap(flatten)] + pub thread_number: ThreadNumber, #[clap(flatten)] pub directories: Directories, #[clap(flatten)] @@ -517,6 +539,12 @@ pub struct NotRecursive { pub not_recursive: bool, } +#[derive(Debug, clap::Args)] +pub struct ThreadNumber { + #[clap(short = 'T', long, default_value = "0", help = "Limits thread number, 0(default) will use all available threads")] + pub thread_number: usize, +} + #[cfg(target_family = "unix")] #[derive(Debug, clap::Args)] pub struct ExcludeOtherFilesystems { diff --git a/czkawka_cli/src/main.rs b/czkawka_cli/src/main.rs index 8f81e92..30c9fe4 100644 --- a/czkawka_cli/src/main.rs +++ b/czkawka_cli/src/main.rs @@ -6,7 +6,7 @@ use clap::Parser; use commands::Commands; use czkawka_core::big_file::SearchMode; -use czkawka_core::common::{get_number_of_threads, set_default_number_of_threads}; +use czkawka_core::common::set_number_of_threads; #[allow(unused_imports)] // It is used in release for print_results(). use czkawka_core::common_traits::*; use czkawka_core::similar_images::test_image_conversion_speed; @@ -34,8 +34,6 @@ mod commands; fn main() { let command = Args::parse().command; - set_default_number_of_threads(); - println!("Set thread number to {}", get_number_of_threads()); #[cfg(debug_assertions)] println!("{command:?}"); @@ -59,6 +57,7 @@ fn main() { fn duplicates(duplicates: DuplicatesArgs) { let DuplicatesArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -78,6 +77,8 @@ fn duplicates(duplicates: DuplicatesArgs) { case_sensitive_name_comparison, } = duplicates; + set_number_of_threads(thread_number.thread_number); + let mut df = DuplicateFinder::new(); df.set_included_directory(directories.directories); @@ -113,6 +114,7 @@ fn duplicates(duplicates: DuplicatesArgs) { fn empty_folders(empty_folders: EmptyFoldersArgs) { let EmptyFoldersArgs { + thread_number, directories, delete_folders, file_to_save, @@ -122,6 +124,8 @@ fn empty_folders(empty_folders: EmptyFoldersArgs) { exclude_other_filesystems, } = empty_folders; + set_number_of_threads(thread_number.thread_number); + let mut ef = EmptyFolder::new(); ef.set_included_directory(directories.directories); @@ -147,6 +151,7 @@ fn empty_folders(empty_folders: EmptyFoldersArgs) { fn biggest_files(biggest_files: BiggestFilesArgs) { let BiggestFilesArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -160,6 +165,8 @@ fn biggest_files(biggest_files: BiggestFilesArgs) { smallest_mode, } = biggest_files; + set_number_of_threads(thread_number.thread_number); + let mut bf = BigFile::new(); bf.set_included_directory(directories.directories); @@ -193,6 +200,7 @@ fn biggest_files(biggest_files: BiggestFilesArgs) { fn empty_files(empty_files: EmptyFilesArgs) { let EmptyFilesArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -204,6 +212,8 @@ fn empty_files(empty_files: EmptyFilesArgs) { exclude_other_filesystems, } = empty_files; + set_number_of_threads(thread_number.thread_number); + let mut ef = EmptyFiles::new(); ef.set_included_directory(directories.directories); @@ -234,6 +244,7 @@ fn empty_files(empty_files: EmptyFilesArgs) { fn temporary(temporary: TemporaryArgs) { let TemporaryArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -244,6 +255,8 @@ fn temporary(temporary: TemporaryArgs) { not_recursive, } = temporary; + set_number_of_threads(thread_number.thread_number); + let mut tf = Temporary::new(); tf.set_included_directory(directories.directories); @@ -273,6 +286,7 @@ fn temporary(temporary: TemporaryArgs) { fn similar_images(similar_images: SimilarImagesArgs) { let SimilarImagesArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -288,6 +302,8 @@ fn similar_images(similar_images: SimilarImagesArgs) { hash_size, } = similar_images; + set_number_of_threads(thread_number.thread_number); + let mut sf = SimilarImages::new(); sf.set_included_directory(directories.directories); @@ -320,6 +336,7 @@ fn similar_images(similar_images: SimilarImagesArgs) { fn same_music(same_music: SameMusicArgs) { let SameMusicArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -333,6 +350,8 @@ fn same_music(same_music: SameMusicArgs) { music_similarity, } = same_music; + set_number_of_threads(thread_number.thread_number); + let mut mf = SameMusic::new(); mf.set_included_directory(directories.directories); @@ -365,6 +384,7 @@ fn same_music(same_music: SameMusicArgs) { fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) { let InvalidSymlinksArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -376,6 +396,8 @@ fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) { delete_files, } = invalid_symlinks; + set_number_of_threads(thread_number.thread_number); + let mut ifs = InvalidSymlinks::new(); ifs.set_included_directory(directories.directories); @@ -405,6 +427,7 @@ fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) { fn broken_files(broken_files: BrokenFilesArgs) { let BrokenFilesArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -416,6 +439,8 @@ fn broken_files(broken_files: BrokenFilesArgs) { exclude_other_filesystems, } = broken_files; + set_number_of_threads(thread_number.thread_number); + let mut br = BrokenFiles::new(); br.set_included_directory(directories.directories); @@ -446,6 +471,7 @@ fn broken_files(broken_files: BrokenFilesArgs) { fn similar_videos(similar_videos: SimilarVideosArgs) { let SimilarVideosArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -459,6 +485,8 @@ fn similar_videos(similar_videos: SimilarVideosArgs) { allowed_extensions, } = similar_videos; + set_number_of_threads(thread_number.thread_number); + let mut vr = SimilarVideos::new(); vr.set_included_directory(directories.directories); @@ -488,6 +516,7 @@ fn similar_videos(similar_videos: SimilarVideosArgs) { fn bad_extensions(bad_extensions: BadExtensionsArgs) { let BadExtensionsArgs { + thread_number, directories, excluded_directories, excluded_items, @@ -498,6 +527,8 @@ fn bad_extensions(bad_extensions: BadExtensionsArgs) { allowed_extensions, } = bad_extensions; + set_number_of_threads(thread_number.thread_number); + let mut be = BadExtensions::new(); be.set_included_directory(directories.directories); diff --git a/czkawka_core/src/bad_extensions.rs b/czkawka_core/src/bad_extensions.rs index 13f4c4e..a3f7968 100644 --- a/czkawka_core/src/bad_extensions.rs +++ b/czkawka_core/src/bad_extensions.rs @@ -13,7 +13,7 @@ use mime_guess::get_mime_extensions; use rayon::prelude::*; use crate::common::{prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; -use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData}; +use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -124,6 +124,7 @@ const WORKAROUNDS: &[(&str, &str)] = &[ ("xml", "vbox"), // VirtualBox ("xml", "vbox-prev"), // VirtualBox ("xml", "vcproj"), // VisualStudio + ("xml", "vcxproj"), // VisualStudio ("xml", "xba"), // Libreoffice ("xml", "xcd"), // Libreoffice files ("zip", "apk"), // Android apk @@ -172,6 +173,7 @@ impl Info { } pub struct BadExtensions { + tool_type: ToolType, text_messages: Messages, information: Info, files_to_check: Vec, @@ -191,6 +193,7 @@ impl BadExtensions { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::BadExtensions, text_messages: Messages::new(), information: Info::new(), recursive_search: true, @@ -314,7 +317,7 @@ impl BadExtensions { fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 1, self.files_to_check.len(), CheckingMethod::None); + prepare_thread_handler_common(progress_sender, 1, 1, self.files_to_check.len(), CheckingMethod::None, self.tool_type); let files_to_check = mem::take(&mut self.files_to_check); diff --git a/czkawka_core/src/big_file.rs b/czkawka_core/src/big_file.rs index efba79b..7a1c975 100644 --- a/czkawka_core/src/big_file.rs +++ b/czkawka_core/src/big_file.rs @@ -14,7 +14,7 @@ use humansize::BINARY; use rayon::prelude::*; use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, split_path}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -55,6 +55,7 @@ impl Info { /// Struct with required information's to work pub struct BigFile { + tool_type: ToolType, text_messages: Messages, information: Info, big_files: Vec<(u64, FileEntry)>, @@ -72,6 +73,7 @@ impl BigFile { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::BigFile, text_messages: Default::default(), information: Info::new(), big_files: Default::default(), @@ -148,7 +150,8 @@ impl BigFile { folders_to_check.push(id.clone()); } - let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None); + let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = + prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None, self.tool_type); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index 9be3e23..0ca48a3 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -21,7 +21,7 @@ use crate::common::{ check_folder_children, create_crash_message, open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, PDF_FILES_EXTENSIONS, }; use crate::common::{AUDIO_FILES_EXTENSIONS, IMAGE_RS_BROKEN_FILES_EXTENSIONS, ZIP_FILES_EXTENSIONS}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -78,6 +78,7 @@ impl Info { } pub struct BrokenFiles { + tool_type: ToolType, text_messages: Messages, information: Info, files_to_check: BTreeMap, @@ -99,6 +100,7 @@ impl BrokenFiles { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::BrokenFiles, text_messages: Messages::new(), information: Info::new(), recursive_search: true, @@ -200,7 +202,8 @@ impl BrokenFiles { folders_to_check.push(id.clone()); } - let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None); + let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = + prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None, self.tool_type); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -436,7 +439,7 @@ impl BrokenFiles { } let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None); + prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None, self.tool_type); let mut vec_file_entry: Vec = non_cached_files_to_check .into_par_iter() diff --git a/czkawka_core/src/common.rs b/czkawka_core/src/common.rs index 2768e02..36de405 100644 --- a/czkawka_core/src/common.rs +++ b/czkawka_core/src/common.rs @@ -19,7 +19,7 @@ use libheif_rs::{ColorSpace, HeifContext, RgbChroma}; // #[cfg(feature = "heif")] // use libheif_rs::LibHeif; -use crate::common_dir_traversal::{CheckingMethod, ProgressData}; +use crate::common_dir_traversal::{CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_items::ExcludedItems; use crate::common_traits::ResultEntry; @@ -392,6 +392,7 @@ pub fn prepare_thread_handler_common( max_stage: u8, max_value: usize, checking_method: CheckingMethod, + tool_type: ToolType, ) -> (JoinHandle<()>, Arc, Arc, AtomicBool) { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); @@ -408,6 +409,7 @@ pub fn prepare_thread_handler_common( max_stage, entries_checked: atomic_counter.load(Ordering::Relaxed), entries_to_check: max_value, + tool_type, }) .unwrap(); if !progress_thread_run.load(Ordering::Relaxed) { diff --git a/czkawka_core/src/common_dir_traversal.rs b/czkawka_core/src/common_dir_traversal.rs index e084284..6567ac8 100644 --- a/czkawka_core/src/common_dir_traversal.rs +++ b/czkawka_core/src/common_dir_traversal.rs @@ -3,7 +3,6 @@ use std::fs; use std::fs::{DirEntry, Metadata, ReadDir}; use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; - use std::time::UNIX_EPOCH; use crossbeam_channel::Receiver; @@ -25,6 +24,23 @@ pub struct ProgressData { pub max_stage: u8, pub entries_checked: usize, pub entries_to_check: usize, + pub tool_type: ToolType, +} + +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +pub enum ToolType { + Duplicate, + EmptyFolders, + EmptyFiles, + InvalidSymlinks, + BrokenFiles, + BadExtensions, + BigFile, + SameMusic, + SimilarImages, + SimilarVideos, + TemporaryFiles, + None, } #[derive(PartialEq, Eq, Clone, Debug, Copy)] @@ -118,6 +134,7 @@ pub struct DirTraversalBuilder<'a, 'b, F> { directories: Option, excluded_items: Option, allowed_extensions: Option, + tool_type: ToolType, } pub struct DirTraversal<'a, 'b, F> { @@ -133,6 +150,7 @@ pub struct DirTraversal<'a, 'b, F> { maximal_file_size: u64, checking_method: CheckingMethod, max_stage: u8, + tool_type: ToolType, collect: Collect, } @@ -159,6 +177,7 @@ impl<'a, 'b> DirTraversalBuilder<'a, 'b, ()> { directories: None, allowed_extensions: None, excluded_items: None, + tool_type: ToolType::BadExtensions, } } } @@ -236,6 +255,12 @@ impl<'a, 'b, F> DirTraversalBuilder<'a, 'b, F> { self } + #[must_use] + pub fn tool_type(mut self, tool_type: ToolType) -> Self { + self.tool_type = tool_type; + self + } + #[cfg(target_family = "unix")] #[must_use] pub fn exclude_other_filesystems(mut self, exclude_other_filesystems: bool) -> Self { @@ -264,6 +289,7 @@ impl<'a, 'b, F> DirTraversalBuilder<'a, 'b, F> { collect: self.collect, checking_method: self.checking_method, max_stage: self.max_stage, + tool_type: self.tool_type, } } @@ -282,6 +308,7 @@ impl<'a, 'b, F> DirTraversalBuilder<'a, 'b, F> { excluded_items: self.excluded_items.expect("could not build"), allowed_extensions: self.allowed_extensions.unwrap_or_default(), recursive_search: self.recursive_search, + tool_type: self.tool_type, } } } @@ -339,7 +366,7 @@ where folders_to_check.extend(self.root_dirs); let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = - prepare_thread_handler_common(self.progress_sender, 0, self.max_stage, 0, self.checking_method); + prepare_thread_handler_common(self.progress_sender, 0, self.max_stage, 0, self.checking_method, self.tool_type); let DirTraversal { collect, @@ -372,6 +399,7 @@ where return (dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list); }; + let mut counter = 0; // Check every sub folder/file/link etc. 'dir: for entry in read_dir { let Some((entry_data, metadata)) = common_get_entry_data_metadata(&entry, &mut warnings, current_folder) else { @@ -383,7 +411,7 @@ where process_dir_in_file_symlink_mode(recursive_search, current_folder, entry_data, &directories, &mut dir_result, &mut warnings, &excluded_items); } (EntryType::Dir, Collect::EmptyFolders) => { - atomic_counter.fetch_add(1, Ordering::Relaxed); + counter += 1; process_dir_in_dir_mode( &metadata, current_folder, @@ -397,7 +425,7 @@ where ); } (EntryType::File, Collect::Files) => { - atomic_counter.fetch_add(1, Ordering::Relaxed); + counter += 1; process_file_in_file_mode( &metadata, entry_data, @@ -424,10 +452,10 @@ where set_as_not_empty_folder_list.push(current_folder.clone()); } (EntryType::File, Collect::InvalidSymlinks) => { - atomic_counter.fetch_add(1, Ordering::Relaxed); + counter += 1; } (EntryType::Symlink, Collect::InvalidSymlinks) => { - atomic_counter.fetch_add(1, Ordering::Relaxed); + counter += 1; process_symlink_in_symlink_mode( &metadata, entry_data, @@ -444,6 +472,10 @@ where } } } + if counter > 0 { + // Do not increase counter one by one in threads, because usually it + atomic_counter.fetch_add(counter, Ordering::Relaxed); + } (dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list) }) .collect(); diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index fa6e88a..b83ca7a 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -21,7 +21,7 @@ use rayon::prelude::*; use xxhash_rust::xxh3::Xxh3; use crate::common::{open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; -use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData}; +use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -81,6 +81,7 @@ impl Info { } pub struct DuplicateFinder { + tool_type: ToolType, text_messages: Messages, information: Info, files_with_identical_names: BTreeMap>, // File Size, File Entry @@ -116,6 +117,7 @@ impl DuplicateFinder { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::Duplicate, text_messages: Messages::new(), information: Info::new(), files_with_identical_names: Default::default(), @@ -675,8 +677,14 @@ impl DuplicateFinder { pre_checked_map: &mut BTreeMap>, ) -> Option<()> { let check_type = self.hash_type; - let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 2, self.files_with_identical_size.values().map(Vec::len).sum(), self.check_method); + let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common( + progress_sender, + 1, + 2, + self.files_with_identical_size.values().map(Vec::len).sum(), + self.check_method, + self.tool_type, + ); let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.prehash_load_cache_at_start(); @@ -831,7 +839,7 @@ impl DuplicateFinder { let check_type = self.hash_type; let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 2, 2, pre_checked_map.values().map(Vec::len).sum(), self.check_method); + prepare_thread_handler_common(progress_sender, 2, 2, pre_checked_map.values().map(Vec::len).sum(), self.check_method, self.tool_type); ///////////////////////////////////////////////////////////////////////////// HASHING START { diff --git a/czkawka_core/src/empty_files.rs b/czkawka_core/src/empty_files.rs index 2b49cfa..910f840 100644 --- a/czkawka_core/src/empty_files.rs +++ b/czkawka_core/src/empty_files.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use crossbeam_channel::Receiver; use futures::channel::mpsc::UnboundedSender; -use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData}; +use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -35,6 +35,8 @@ impl Info { /// Struct with required information's to work pub struct EmptyFiles { + #[allow(dead_code)] + tool_type: ToolType, text_messages: Messages, information: Info, empty_files: Vec, @@ -50,6 +52,7 @@ impl EmptyFiles { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::EmptyFiles, text_messages: Messages::new(), information: Info::new(), recursive_search: true, diff --git a/czkawka_core/src/empty_folder.rs b/czkawka_core/src/empty_folder.rs index 431298d..7ce276e 100644 --- a/czkawka_core/src/empty_folder.rs +++ b/czkawka_core/src/empty_folder.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use crossbeam_channel::Receiver; use futures::channel::mpsc::UnboundedSender; -use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData}; +use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_items::ExcludedItems; use crate::common_messages::Messages; @@ -15,6 +15,8 @@ use crate::common_traits::{DebugPrint, PrintResults, SaveResults}; /// Struct to store most basics info about all folder pub struct EmptyFolder { + #[allow(dead_code)] + tool_type: ToolType, information: Info, delete_folders: bool, text_messages: Messages, @@ -43,6 +45,7 @@ impl EmptyFolder { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::EmptyFolders, information: Default::default(), delete_folders: false, text_messages: Messages::new(), diff --git a/czkawka_core/src/invalid_symlinks.rs b/czkawka_core/src/invalid_symlinks.rs index 0dedf43..5813940 100644 --- a/czkawka_core/src/invalid_symlinks.rs +++ b/czkawka_core/src/invalid_symlinks.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use crossbeam_channel::Receiver; use futures::channel::mpsc::UnboundedSender; -use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, ErrorType, FileEntry, ProgressData}; +use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, ErrorType, FileEntry, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -35,6 +35,8 @@ impl Info { /// Struct with required information's to work pub struct InvalidSymlinks { + #[allow(dead_code)] + tool_type: ToolType, text_messages: Messages, information: Info, invalid_symlinks: Vec, @@ -50,6 +52,7 @@ impl InvalidSymlinks { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::InvalidSymlinks, text_messages: Messages::new(), information: Info::new(), recursive_search: true, diff --git a/czkawka_core/src/same_music.rs b/czkawka_core/src/same_music.rs index 974fc98..6c031a9 100644 --- a/czkawka_core/src/same_music.rs +++ b/czkawka_core/src/same_music.rs @@ -25,7 +25,7 @@ use symphonia::core::probe::Hint; use crate::common::{create_crash_message, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, AUDIO_FILES_EXTENSIONS}; use crate::common::{filter_reference_folders_generic, open_cache_folder}; -use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData}; +use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -108,6 +108,7 @@ impl Info { /// Struct with required information's to work pub struct SameMusic { + tool_type: ToolType, text_messages: Messages, information: Info, music_to_check: HashMap, @@ -138,6 +139,7 @@ impl SameMusic { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::SameMusic, text_messages: Messages::new(), information: Info::new(), recursive_search: true, @@ -415,7 +417,7 @@ impl SameMusic { let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache(false); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 3, non_cached_files_to_check.len(), self.check_type); + prepare_thread_handler_common(progress_sender, 1, 3, non_cached_files_to_check.len(), self.check_type, self.tool_type); let configuration = &self.hash_preset_config; // Clean for duplicate files @@ -461,7 +463,7 @@ impl SameMusic { let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache(true); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), self.check_type); + prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), self.check_type, self.tool_type); // Clean for duplicate files let mut vec_file_entry = non_cached_files_to_check @@ -502,7 +504,7 @@ impl SameMusic { fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = - prepare_thread_handler_common(progress_sender, 2, 2, self.music_to_check.len(), self.check_type); + prepare_thread_handler_common(progress_sender, 2, 2, self.music_to_check.len(), self.check_type, self.tool_type); let mut old_duplicates: Vec> = vec![self.music_entries.clone()]; let mut new_duplicates: Vec> = Vec::new(); @@ -601,7 +603,7 @@ impl SameMusic { fn read_tags_to_files_similar_by_content(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let groups_to_check = max(self.duplicated_music_entries.len(), self.duplicated_music_entries_referenced.len()); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 3, 3, groups_to_check, self.check_type); + prepare_thread_handler_common(progress_sender, 3, 3, groups_to_check, self.check_type, self.tool_type); // TODO is ther a way to just run iterator and not collect any info? if !self.duplicated_music_entries.is_empty() { @@ -726,7 +728,7 @@ impl SameMusic { fn check_for_duplicate_fingerprints(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let (base_files, files_to_compare) = self.split_fingerprints_to_check(); let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = - prepare_thread_handler_common(progress_sender, 2, 3, base_files.len(), self.check_type); + prepare_thread_handler_common(progress_sender, 2, 3, base_files.len(), self.check_type, self.tool_type); let Some(duplicated_music_entries) = self.compare_fingerprints(stop_receiver, &atomic_counter, base_files, &files_to_compare) else { send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index f9b8aa8..29dcdcb 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -25,7 +25,7 @@ use crate::common::{ check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, }; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -85,6 +85,7 @@ impl bk_tree::Metric for Hamming { /// Struct to store most basics info about all folder pub struct SimilarImages { + tool_type: ToolType, information: Info, text_messages: Messages, directories: Directories, @@ -131,6 +132,7 @@ impl SimilarImages { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::SimilarImages, information: Default::default(), text_messages: Messages::new(), directories: Directories::new(), @@ -300,7 +302,8 @@ impl SimilarImages { folders_to_check.push(id.clone()); } - let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 2, 0, CheckingMethod::None); + let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = + prepare_thread_handler_common(progress_sender, 0, 2, 0, CheckingMethod::None, self.tool_type); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -435,7 +438,7 @@ impl SimilarImages { let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.hash_images_load_cache(); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), CheckingMethod::None); + prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), CheckingMethod::None, self.tool_type); let mut vec_file_entry: Vec<(FileEntry, ImHash)> = non_cached_files_to_check .into_par_iter() @@ -816,7 +819,7 @@ impl SimilarImages { } } else { let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 2, 2, all_hashes.len(), CheckingMethod::None); + prepare_thread_handler_common(progress_sender, 2, 2, all_hashes.len(), CheckingMethod::None, self.tool_type); // Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes diff --git a/czkawka_core/src/similar_videos.rs b/czkawka_core/src/similar_videos.rs index 366a180..c81879a 100644 --- a/czkawka_core/src/similar_videos.rs +++ b/czkawka_core/src/similar_videos.rs @@ -18,7 +18,7 @@ use vid_dup_finder_lib::{NormalizedTolerance, VideoHash}; use crate::common::open_cache_folder; use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, VIDEO_FILES_EXTENSIONS}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -60,6 +60,7 @@ impl bk_tree::Metric> for Hamming { /// Struct to store most basics info about all folder pub struct SimilarVideos { + tool_type: ToolType, information: Info, text_messages: Messages, directories: Directories, @@ -101,6 +102,7 @@ impl SimilarVideos { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::SimilarVideos, information: Default::default(), text_messages: Messages::new(), directories: Directories::new(), @@ -261,7 +263,8 @@ impl SimilarVideos { folders_to_check.push(id.clone()); } - let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None); + let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = + prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None, self.tool_type); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -390,7 +393,7 @@ impl SimilarVideos { let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache_at_start(); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None); + prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None, self.tool_type); let mut vec_file_entry: Vec = non_cached_files_to_check .par_iter() diff --git a/czkawka_core/src/temporary.rs b/czkawka_core/src/temporary.rs index a0c9674..a0c3294 100644 --- a/czkawka_core/src/temporary.rs +++ b/czkawka_core/src/temporary.rs @@ -11,7 +11,7 @@ use futures::channel::mpsc::UnboundedSender; use rayon::prelude::*; use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; use crate::common_items::ExcludedItems; use crate::common_messages::Messages; @@ -60,6 +60,7 @@ impl Info { /// Struct with required information's to work pub struct Temporary { + tool_type: ToolType, text_messages: Messages, information: Info, temporary_files: Vec, @@ -74,6 +75,7 @@ impl Temporary { #[must_use] pub fn new() -> Self { Self { + tool_type: ToolType::TemporaryFiles, text_messages: Messages::new(), information: Info::new(), recursive_search: true, @@ -149,7 +151,8 @@ impl Temporary { folders_to_check.push(id.clone()); } - let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None); + let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = + prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None, self.tool_type); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { diff --git a/czkawka_gui/src/connect_things/connect_button_search.rs b/czkawka_gui/src/connect_things/connect_button_search.rs index 41e9d83..1286dc6 100644 --- a/czkawka_gui/src/connect_things/connect_button_search.rs +++ b/czkawka_gui/src/connect_things/connect_button_search.rs @@ -33,21 +33,7 @@ use crate::taskbar_progress::tbp_flags::TBPF_NOPROGRESS; use crate::{flg, DEFAULT_MAXIMAL_FILE_SIZE, DEFAULT_MINIMAL_CACHE_SIZE, DEFAULT_MINIMAL_FILE_SIZE}; #[allow(clippy::too_many_arguments)] -pub fn connect_button_search( - gui_data: &GuiData, - glib_stop_sender: Sender, - futures_sender_duplicate_files: UnboundedSender, - futures_sender_empty_files: UnboundedSender, - futures_sender_empty_folder: UnboundedSender, - futures_sender_big_file: UnboundedSender, - futures_sender_same_music: UnboundedSender, - futures_sender_similar_images: UnboundedSender, - futures_sender_similar_videos: UnboundedSender, - futures_sender_temporary: UnboundedSender, - futures_sender_invalid_symlinks: UnboundedSender, - futures_sender_broken_files: UnboundedSender, - futures_sender_bad_extensions: UnboundedSender, -) { +pub fn connect_button_search(gui_data: &GuiData, glib_stop_sender: Sender, progress_sender: UnboundedSender) { let buttons_array = gui_data.bottom_buttons.buttons_array.clone(); let buttons_search_clone = gui_data.bottom_buttons.buttons_search.clone(); let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone(); @@ -109,7 +95,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_duplicate_files.clone(), + progress_sender.clone(), ), NotebookMainEnum::EmptyFiles => empty_files_search( &gui_data, @@ -117,7 +103,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_empty_files.clone(), + progress_sender.clone(), ), NotebookMainEnum::EmptyDirectories => empty_directories_search( &gui_data, @@ -125,7 +111,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_empty_folder.clone(), + progress_sender.clone(), ), NotebookMainEnum::BigFiles => big_files_search( &gui_data, @@ -133,7 +119,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_big_file.clone(), + progress_sender.clone(), ), NotebookMainEnum::Temporary => temporary_files_search( &gui_data, @@ -141,7 +127,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_temporary.clone(), + progress_sender.clone(), ), NotebookMainEnum::SimilarImages => similar_image_search( &gui_data, @@ -149,7 +135,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_similar_images.clone(), + progress_sender.clone(), ), NotebookMainEnum::SimilarVideos => similar_video_search( &gui_data, @@ -157,7 +143,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_similar_videos.clone(), + progress_sender.clone(), ), NotebookMainEnum::SameMusic => same_music_search( &gui_data, @@ -165,7 +151,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_same_music.clone(), + progress_sender.clone(), &show_dialog, ), NotebookMainEnum::Symlinks => bad_symlinks_search( @@ -174,7 +160,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_invalid_symlinks.clone(), + progress_sender.clone(), ), NotebookMainEnum::BrokenFiles => broken_files_search( &gui_data, @@ -182,7 +168,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_broken_files.clone(), + progress_sender.clone(), &show_dialog, ), NotebookMainEnum::BadExtensions => bad_extensions_search( @@ -191,7 +177,7 @@ pub fn connect_button_search( stop_receiver, glib_stop_sender, &grid_progress_stages, - futures_sender_bad_extensions.clone(), + progress_sender.clone(), ), } diff --git a/czkawka_gui/src/connect_things/connect_progress_window.rs b/czkawka_gui/src/connect_things/connect_progress_window.rs index b4111eb..f6f3a24 100644 --- a/czkawka_gui/src/connect_things/connect_progress_window.rs +++ b/czkawka_gui/src/connect_things/connect_progress_window.rs @@ -10,7 +10,7 @@ use gtk4::ProgressBar; use common_dir_traversal::CheckingMethod; use czkawka_core::common_dir_traversal; -use czkawka_core::common_dir_traversal::ProgressData; +use czkawka_core::common_dir_traversal::{ProgressData, ToolType}; use crate::flg; use crate::gui_structs::gui_data::GuiData; @@ -19,304 +19,256 @@ use crate::taskbar_progress::tbp_flags::TBPF_INDETERMINATE; use crate::taskbar_progress::TaskbarProgress; #[allow(clippy::too_many_arguments)] -pub fn connect_progress_window( - gui_data: &GuiData, - futures_receiver_duplicate_files: UnboundedReceiver, - futures_receiver_empty_files: UnboundedReceiver, - futures_receiver_empty_folder: UnboundedReceiver, - futures_receiver_big_files: UnboundedReceiver, - futures_receiver_same_music: UnboundedReceiver, - futures_receiver_similar_images: UnboundedReceiver, - futures_receiver_similar_videos: UnboundedReceiver, - futures_receiver_temporary: UnboundedReceiver, - futures_receiver_invalid_symlinks: UnboundedReceiver, - futures_receiver_broken_files: UnboundedReceiver, - futures_receiver_bad_extensions: UnboundedReceiver, -) { +pub fn connect_progress_window(gui_data: &GuiData, mut progress_receiver: UnboundedReceiver) { let main_context = MainContext::default(); let _guard = main_context.acquire().unwrap(); - process_bar_duplicates(gui_data, &main_context, futures_receiver_duplicate_files); - process_bar_empty_files(gui_data, &main_context, futures_receiver_empty_files); - process_bar_empty_folder(gui_data, &main_context, futures_receiver_empty_folder); - process_bar_big_files(gui_data, &main_context, futures_receiver_big_files); - process_bar_same_music(gui_data, &main_context, futures_receiver_same_music); - process_bar_similar_images(gui_data, &main_context, futures_receiver_similar_images); - process_bar_similar_videos(gui_data, &main_context, futures_receiver_similar_videos); - process_bar_temporary(gui_data, &main_context, futures_receiver_temporary); - process_bar_invalid_symlinks(gui_data, &main_context, futures_receiver_invalid_symlinks); - process_bar_broken_files(gui_data, &main_context, futures_receiver_broken_files); - process_bar_bad_extensions(gui_data, &main_context, futures_receiver_bad_extensions); -} -fn process_bar_empty_files(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_empty_files: UnboundedReceiver) { - let label_stage = gui_data.progress_window.label_stage.clone(); - let taskbar_state = gui_data.taskbar_state.clone(); + let gui_data = gui_data.clone(); let future = async move { - while let Some(item) = futures_receiver_empty_files.next().await { - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + while let Some(item) = progress_receiver.next().await { + match item.tool_type { + ToolType::Duplicate => process_bar_duplicates(&gui_data, &item), + ToolType::EmptyFiles => process_bar_empty_files(&gui_data, &item), + ToolType::EmptyFolders => process_bar_empty_folder(&gui_data, &item), + ToolType::BigFile => process_bar_big_files(&gui_data, &item), + ToolType::SameMusic => process_bar_same_music(&gui_data, &item), + ToolType::SimilarImages => process_bar_similar_images(&gui_data, &item), + ToolType::SimilarVideos => process_bar_similar_videos(&gui_data, &item), + ToolType::TemporaryFiles => process_bar_temporary(&gui_data, &item), + ToolType::InvalidSymlinks => process_bar_invalid_symlinks(&gui_data, &item), + ToolType::BrokenFiles => process_bar_broken_files(&gui_data, &item), + ToolType::BadExtensions => process_bar_bad_extensions(&gui_data, &item), + ToolType::None => panic!(), + } } }; main_context.spawn_local(future); } -fn process_bar_empty_folder(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_empty_folder: UnboundedReceiver) { +fn process_bar_empty_files(gui_data: &GuiData, item: &ProgressData) { let label_stage = gui_data.progress_window.label_stage.clone(); let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_empty_folder.next().await { - label_stage.set_text(&flg!( - "progress_scanning_empty_folders", - generate_translation_hashmap(vec![("folder_number", item.entries_checked.to_string())]) - )); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - }; - main_context.spawn_local(future); -} -fn process_bar_big_files(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_big_files: UnboundedReceiver) { - let label_stage = gui_data.progress_window.label_stage.clone(); - let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_big_files.next().await { - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - }; - main_context.spawn_local(future); -} -fn process_bar_same_music(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_same_music: UnboundedReceiver) { - let label_stage = gui_data.progress_window.label_stage.clone(); - let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); - let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); - let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_same_music.next().await { - match item.current_stage { - 0 => { - progress_bar_current_stage.hide(); - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - 1 => { - progress_bar_current_stage.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - match item.checking_method { - CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(&item))), - CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content", progress_ratio_tm(&item))), - _ => panic!(), - } - } - 2 => { - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - - match item.checking_method { - CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags_end", progress_ratio_tm(&item))), - CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content_end", progress_ratio_tm(&item))), - _ => panic!(), - } - } - 3 => { - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - - match item.checking_method { - CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(&item))), - _ => panic!(), - } - } - _ => panic!(), - } - } - }; - main_context.spawn_local(future); + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } -fn process_bar_similar_images(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_similar_images: UnboundedReceiver) { +fn process_bar_empty_folder(gui_data: &GuiData, item: &ProgressData) { + let label_stage = gui_data.progress_window.label_stage.clone(); + let taskbar_state = gui_data.taskbar_state.clone(); + + label_stage.set_text(&flg!( + "progress_scanning_empty_folders", + generate_translation_hashmap(vec![("folder_number", item.entries_checked.to_string())]) + )); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); +} +fn process_bar_big_files(gui_data: &GuiData, item: &ProgressData) { + let label_stage = gui_data.progress_window.label_stage.clone(); + let taskbar_state = gui_data.taskbar_state.clone(); + + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); +} +fn process_bar_same_music(gui_data: &GuiData, item: &ProgressData) { let label_stage = gui_data.progress_window.label_stage.clone(); let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_similar_images.next().await { - match item.current_stage { - 0 => { - progress_bar_current_stage.hide(); - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - 1 => { - progress_bar_current_stage.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_scanning_image", progress_ratio_tm(&item))); - } - 2 => { - progress_bar_current_stage.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_comparing_image_hashes", progress_ratio_tm(&item))); - } - _ => panic!(), - } - } - }; - main_context.spawn_local(future); -} -fn process_bar_similar_videos(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_similar_videos: UnboundedReceiver) { - let label_stage = gui_data.progress_window.label_stage.clone(); - let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); - let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); - let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_similar_videos.next().await { - match item.current_stage { - 0 => { - progress_bar_current_stage.hide(); - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - 1 => { - progress_bar_current_stage.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_scanning_video", progress_ratio_tm(&item))); - } - _ => panic!(), - } - } - }; - main_context.spawn_local(future); -} -fn process_bar_temporary(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_temporary: UnboundedReceiver) { - let label_stage = gui_data.progress_window.label_stage.clone(); - let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_temporary.next().await { - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); + + match item.current_stage { + 0 => { + progress_bar_current_stage.hide(); + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } - }; - main_context.spawn_local(future); + 1 => { + progress_bar_current_stage.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + + match item.checking_method { + CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(item))), + CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content", progress_ratio_tm(item))), + _ => panic!(), + } + } + 2 => { + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + + match item.checking_method { + CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags_end", progress_ratio_tm(item))), + CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content_end", progress_ratio_tm(item))), + _ => panic!(), + } + } + 3 => { + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + + match item.checking_method { + CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(item))), + _ => panic!(), + } + } + _ => panic!(), + } } -fn process_bar_invalid_symlinks(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_invalid_symlinks: UnboundedReceiver) { +fn process_bar_similar_images(gui_data: &GuiData, item: &ProgressData) { let label_stage = gui_data.progress_window.label_stage.clone(); + let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); + let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_invalid_symlinks.next().await { - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); + + match item.current_stage { + 0 => { + progress_bar_current_stage.hide(); + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } - }; - main_context.spawn_local(future); + 1 => { + progress_bar_current_stage.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + label_stage.set_text(&flg!("progress_scanning_image", progress_ratio_tm(item))); + } + 2 => { + progress_bar_current_stage.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + label_stage.set_text(&flg!("progress_comparing_image_hashes", progress_ratio_tm(item))); + } + _ => panic!(), + } } -fn process_bar_broken_files(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_broken_files: UnboundedReceiver) { +fn process_bar_similar_videos(gui_data: &GuiData, item: &ProgressData) { let label_stage = gui_data.progress_window.label_stage.clone(); let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_broken_files.next().await { - match item.current_stage { - 0 => { - progress_bar_current_stage.hide(); - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - 1 => { - progress_bar_current_stage.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_scanning_broken_files", progress_ratio_tm(&item))); - } - _ => panic!(), - } + + match item.current_stage { + 0 => { + progress_bar_current_stage.hide(); + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } - }; - main_context.spawn_local(future); + 1 => { + progress_bar_current_stage.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + label_stage.set_text(&flg!("progress_scanning_video", progress_ratio_tm(item))); + } + _ => panic!(), + } } -fn process_bar_bad_extensions(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_bad_extensions: UnboundedReceiver) { +fn process_bar_temporary(gui_data: &GuiData, item: &ProgressData) { + let label_stage = gui_data.progress_window.label_stage.clone(); + let taskbar_state = gui_data.taskbar_state.clone(); + + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); +} +fn process_bar_invalid_symlinks(gui_data: &GuiData, item: &ProgressData) { + let label_stage = gui_data.progress_window.label_stage.clone(); + let taskbar_state = gui_data.taskbar_state.clone(); + + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); +} +fn process_bar_broken_files(gui_data: &GuiData, item: &ProgressData) { let label_stage = gui_data.progress_window.label_stage.clone(); let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_bad_extensions.next().await { - match item.current_stage { - 0 => { - progress_bar_current_stage.hide(); - label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - 1 => { - progress_bar_current_stage.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_scanning_extension_of_files", progress_ratio_tm(&item))); - } - _ => panic!(), - } + + match item.current_stage { + 0 => { + progress_bar_current_stage.hide(); + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } - }; - main_context.spawn_local(future); + 1 => { + progress_bar_current_stage.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + label_stage.set_text(&flg!("progress_scanning_broken_files", progress_ratio_tm(item))); + } + _ => panic!(), + } } -fn process_bar_duplicates(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_duplicate_files: UnboundedReceiver) { +fn process_bar_bad_extensions(gui_data: &GuiData, item: &ProgressData) { + let label_stage = gui_data.progress_window.label_stage.clone(); + let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); + let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); + let taskbar_state = gui_data.taskbar_state.clone(); + + match item.current_stage { + 0 => { + progress_bar_current_stage.hide(); + label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + } + 1 => { + progress_bar_current_stage.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + label_stage.set_text(&flg!("progress_scanning_extension_of_files", progress_ratio_tm(item))); + } + _ => panic!(), + } +} +fn process_bar_duplicates(gui_data: &GuiData, item: &ProgressData) { let label_stage = gui_data.progress_window.label_stage.clone(); let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone(); let taskbar_state = gui_data.taskbar_state.clone(); - let future = async move { - while let Some(item) = futures_receiver_duplicate_files.next().await { - match item.checking_method { - CheckingMethod::Hash => { - label_stage.show(); - match item.current_stage { - // Checking Size - 0 => { - progress_bar_current_stage.hide(); - // progress_bar_all_stages.hide(); - progress_bar_all_stages.set_fraction(0 as f64); - label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); - } - // Hash - first 1KB file - 1 => { - progress_bar_current_stage.show(); - // progress_bar_all_stages.show(); - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_analyzed_partial_hash", progress_ratio_tm(&item))); - } - // Hash - normal hash - 2 => { - common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_analyzed_full_hash", progress_ratio_tm(&item))); - } - _ => { - panic!("Not available current_stage"); - } - } - } - CheckingMethod::Name => { - label_stage.show(); - grid_progress_stages.hide(); - - label_stage.set_text(&flg!("progress_scanning_name", file_number_tm(&item))); + match item.checking_method { + CheckingMethod::Hash => { + label_stage.show(); + match item.current_stage { + // Checking Size + 0 => { + progress_bar_current_stage.hide(); + // progress_bar_all_stages.hide(); + progress_bar_all_stages.set_fraction(0 as f64); + label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } - CheckingMethod::SizeName => { - label_stage.show(); - grid_progress_stages.hide(); + // Hash - first 1KB file + 1 => { + progress_bar_current_stage.show(); + // progress_bar_all_stages.show(); + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); - label_stage.set_text(&flg!("progress_scanning_size_name", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + label_stage.set_text(&flg!("progress_analyzed_partial_hash", progress_ratio_tm(item))); } - CheckingMethod::Size => { - label_stage.show(); - grid_progress_stages.hide(); - - label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(&item))); - taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + // Hash - normal hash + 2 => { + common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); + label_stage.set_text(&flg!("progress_analyzed_full_hash", progress_ratio_tm(item))); } - _ => panic!(), - }; + _ => { + panic!("Not available current_stage"); + } + } } + CheckingMethod::Name => { + label_stage.show(); + grid_progress_stages.hide(); + + label_stage.set_text(&flg!("progress_scanning_name", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + } + CheckingMethod::SizeName => { + label_stage.show(); + grid_progress_stages.hide(); + + label_stage.set_text(&flg!("progress_scanning_size_name", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + } + CheckingMethod::Size => { + label_stage.show(); + grid_progress_stages.hide(); + + label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(item))); + taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); + } + _ => panic!(), }; - main_context.spawn_local(future); } fn common_set_data(item: &ProgressData, progress_bar_all_stages: &ProgressBar, progress_bar_current_stage: &ProgressBar, taskbar_state: &Rc>) { diff --git a/czkawka_gui/src/create_tree_view.rs b/czkawka_gui/src/create_tree_view.rs index f093bdd..b724d6e 100644 --- a/czkawka_gui/src/create_tree_view.rs +++ b/czkawka_gui/src/create_tree_view.rs @@ -1,5 +1,5 @@ use gtk4::prelude::*; -use gtk4::{CellRendererText, CellRendererToggle, TreeView, TreeViewColumn}; +use gtk4::{CellRendererText, CellRendererToggle, ListStore, TreeView, TreeViewColumn}; use crate::help_functions::*; @@ -8,726 +8,234 @@ use crate::help_functions::*; pub fn create_tree_view_included_directories(tree_view: &TreeView) { let model = get_list_store(tree_view); - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.set_title("Folders to check"); - column.pack_start(&renderer, true); - column.add_attribute(&renderer, "text", ColumnsIncludedDirectory::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsIncludedDirectory::ReferenceButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsIncludedDirectory::ReferenceButton as u32, &fixed.to_value()); - }); - renderer.set_activatable(true); - let column = TreeViewColumn::new(); - column.set_title("Reference folder"); - column.pack_start(&renderer, true); - column.add_attribute(&renderer, "active", ColumnsIncludedDirectory::ReferenceButton as i32); - tree_view.append_column(&column); + create_default_column(tree_view, ColumnsIncludedDirectory::Path as i32, None, None); + create_default_selection_button_column(tree_view, ColumnsIncludedDirectory::ReferenceButton as i32, model, None); } pub fn create_tree_view_excluded_directories(tree_view: &TreeView) { - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.add_attribute(&renderer, "text", ColumnsExcludedDirectory::Path as i32); - tree_view.append_column(&column); - tree_view.set_headers_visible(false); + create_default_column(tree_view, ColumnsExcludedDirectory::Path as i32, None, None); } pub fn create_tree_view_duplicates(tree_view: &TreeView) { - let model = get_list_store(tree_view); - - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsDuplicates::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsDuplicates::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "activatable", ColumnsDuplicates::ActivatableSelectButton as i32); - column.add_attribute(&renderer, "active", ColumnsDuplicates::SelectionButton as i32); - column.add_attribute(&renderer, "cell-background", ColumnsDuplicates::Color as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Size"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsDuplicates::Size as i32); - column.add_attribute(&renderer, "background", ColumnsDuplicates::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsDuplicates::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsDuplicates::Name as i32); - column.add_attribute(&renderer, "background", ColumnsDuplicates::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsDuplicates::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsDuplicates::Path as i32); - column.add_attribute(&renderer, "background", ColumnsDuplicates::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsDuplicates::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsDuplicates::Modification as i32); - column.add_attribute(&renderer, "background", ColumnsDuplicates::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsDuplicates::TextColor as i32); - tree_view.append_column(&column); - tree_view.set_vexpand(true); + + let model = get_list_store(tree_view); + let columns_colors = (ColumnsDuplicates::Color as i32, ColumnsDuplicates::TextColor as i32); + let activatable_colors = (ColumnsDuplicates::ActivatableSelectButton as i32, ColumnsDuplicates::Color as i32); + + create_default_selection_button_column(tree_view, ColumnsDuplicates::SelectionButton as i32, model, Some(activatable_colors)); + + create_default_column(tree_view, ColumnsDuplicates::Size as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsDuplicates::Name as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsDuplicates::Path as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsDuplicates::Modification as i32, None, Some(columns_colors)); } pub fn create_tree_view_empty_folders(tree_view: &TreeView) { + tree_view.set_vexpand(true); + let model = get_list_store(tree_view); - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsEmptyFolders::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsEmptyFolders::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "active", ColumnsEmptyFolders::SelectionButton as i32); - tree_view.append_column(&column); + create_default_selection_button_column(tree_view, ColumnsEmptyFolders::SelectionButton as i32, model, None); - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Folder Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsEmptyFolders::Name as i32); - column.set_sort_column_id(ColumnsEmptyFolders::Name as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsEmptyFolders::Path as i32); - column.set_sort_column_id(ColumnsEmptyFolders::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsEmptyFolders::Modification as i32); - column.set_sort_column_id(ColumnsEmptyFolders::ModificationAsSecs as i32); - tree_view.append_column(&column); - - tree_view.set_vexpand(true); + create_default_column(tree_view, ColumnsEmptyFolders::Name as i32, None, None); + create_default_column(tree_view, ColumnsEmptyFolders::Path as i32, None, None); + create_default_column( + tree_view, + ColumnsEmptyFolders::Modification as i32, + Some(ColumnsEmptyFolders::ModificationAsSecs as i32), + None, + ); } pub fn create_tree_view_big_files(tree_view: &TreeView) { + tree_view.set_vexpand(true); + let model = get_list_store(tree_view); - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsBigFiles::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsBigFiles::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "active", ColumnsBigFiles::SelectionButton as i32); - tree_view.append_column(&column); + create_default_selection_button_column(tree_view, ColumnsBigFiles::SelectionButton as i32, model, None); - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Size"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBigFiles::Size as i32); - column.set_sort_column_id(ColumnsBigFiles::SizeAsBytes as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBigFiles::Name as i32); - column.set_sort_column_id(ColumnsBigFiles::Name as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBigFiles::Path as i32); - column.set_sort_column_id(ColumnsBigFiles::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBigFiles::Modification as i32); - column.set_sort_column_id(ColumnsBigFiles::ModificationAsSecs as i32); - tree_view.append_column(&column); - - tree_view.set_vexpand(true); + create_default_column(tree_view, ColumnsBigFiles::Size as i32, None, None); + create_default_column(tree_view, ColumnsBigFiles::Name as i32, None, None); + create_default_column(tree_view, ColumnsBigFiles::Path as i32, None, None); + create_default_column(tree_view, ColumnsBigFiles::Modification as i32, Some(ColumnsBigFiles::ModificationAsSecs as i32), None); } pub fn create_tree_view_temporary_files(tree_view: &TreeView) { + tree_view.set_vexpand(true); + let model = get_list_store(tree_view); - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsTemporaryFiles::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsTemporaryFiles::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "active", ColumnsTemporaryFiles::SelectionButton as i32); - tree_view.append_column(&column); + create_default_selection_button_column(tree_view, ColumnsTemporaryFiles::SelectionButton as i32, model, None); - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsTemporaryFiles::Name as i32); - column.set_sort_column_id(ColumnsTemporaryFiles::Name as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsTemporaryFiles::Path as i32); - column.set_sort_column_id(ColumnsTemporaryFiles::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsTemporaryFiles::Modification as i32); - column.set_sort_column_id(ColumnsTemporaryFiles::ModificationAsSecs as i32); - tree_view.append_column(&column); - - tree_view.set_vexpand(true); + create_default_column(tree_view, ColumnsTemporaryFiles::Name as i32, None, None); + create_default_column(tree_view, ColumnsTemporaryFiles::Path as i32, None, None); + create_default_column( + tree_view, + ColumnsTemporaryFiles::Modification as i32, + Some(ColumnsTemporaryFiles::ModificationAsSecs as i32), + None, + ); } pub fn create_tree_view_empty_files(tree_view: &TreeView) { + tree_view.set_vexpand(true); + let model = get_list_store(tree_view); - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsEmptyFiles::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsEmptyFiles::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "active", ColumnsEmptyFiles::SelectionButton as i32); - tree_view.append_column(&column); + create_default_selection_button_column(tree_view, ColumnsEmptyFiles::SelectionButton as i32, model, None); - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsEmptyFiles::Name as i32); - column.set_sort_column_id(ColumnsEmptyFiles::Name as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsEmptyFiles::Path as i32); - column.set_sort_column_id(ColumnsEmptyFiles::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsEmptyFiles::Modification as i32); - column.set_sort_column_id(ColumnsEmptyFiles::ModificationAsSecs as i32); - tree_view.append_column(&column); - - tree_view.set_vexpand(true); + create_default_column(tree_view, ColumnsEmptyFiles::Name as i32, None, None); + create_default_column(tree_view, ColumnsEmptyFiles::Path as i32, None, None); + create_default_column(tree_view, ColumnsEmptyFiles::Modification as i32, Some(ColumnsEmptyFiles::ModificationAsSecs as i32), None); } pub fn create_tree_view_similar_images(tree_view: &TreeView) { - let model = get_list_store(tree_view); - - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsSimilarImages::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsSimilarImages::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "activatable", ColumnsSimilarImages::ActivatableSelectButton as i32); - column.add_attribute(&renderer, "active", ColumnsSimilarImages::SelectionButton as i32); - column.add_attribute(&renderer, "cell-background", ColumnsSimilarImages::Color as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Similarity"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarImages::Similarity as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarImages::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarImages::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Size"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarImages::Size as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarImages::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarImages::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Dimensions"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarImages::Dimensions as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarImages::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarImages::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarImages::Name as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarImages::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarImages::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarImages::Path as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarImages::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarImages::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarImages::Modification as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarImages::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarImages::TextColor as i32); - tree_view.append_column(&column); - tree_view.set_vexpand(true); + + let model = get_list_store(tree_view); + let columns_colors = (ColumnsSimilarImages::Color as i32, ColumnsSimilarImages::TextColor as i32); + let activatable_colors = (ColumnsSimilarImages::ActivatableSelectButton as i32, ColumnsSimilarImages::Color as i32); + + create_default_selection_button_column(tree_view, ColumnsSimilarImages::SelectionButton as i32, model, Some(activatable_colors)); + + create_default_column(tree_view, ColumnsSimilarImages::Similarity as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarImages::Size as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarImages::Dimensions as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarImages::Name as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarImages::Path as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarImages::Modification as i32, None, Some(columns_colors)); } pub fn create_tree_view_similar_videos(tree_view: &TreeView) { - let model = get_list_store(tree_view); - - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsSimilarVideos::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsSimilarVideos::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "activatable", ColumnsSimilarVideos::ActivatableSelectButton as i32); - column.add_attribute(&renderer, "active", ColumnsSimilarVideos::SelectionButton as i32); - column.add_attribute(&renderer, "cell-background", ColumnsSimilarVideos::Color as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Size"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Size as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Name as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Path as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Modification as i32); - column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); - tree_view.append_column(&column); - tree_view.set_vexpand(true); + + let model = get_list_store(tree_view); + let columns_colors = (ColumnsSimilarVideos::Color as i32, ColumnsSimilarVideos::TextColor as i32); + let activatable_colors = (ColumnsSimilarVideos::ActivatableSelectButton as i32, ColumnsSimilarVideos::Color as i32); + + create_default_selection_button_column(tree_view, ColumnsSimilarVideos::SelectionButton as i32, model, Some(activatable_colors)); + + create_default_column(tree_view, ColumnsSimilarVideos::Size as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarVideos::Name as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarVideos::Path as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSimilarVideos::Modification as i32, None, Some(columns_colors)); } pub fn create_tree_view_same_music(tree_view: &TreeView) { - let model = get_list_store(tree_view); - - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsSameMusic::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsSameMusic::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "activatable", ColumnsSameMusic::ActivatableSelectButton as i32); - column.add_attribute(&renderer, "active", ColumnsSameMusic::SelectionButton as i32); - column.add_attribute(&renderer, "cell-background", ColumnsSameMusic::Color as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Size"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Size as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Name as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Title"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Title as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Artist"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Artist as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Year"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Year as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Bitrate"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Bitrate as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Length"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Length as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Genre"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Genre as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Path as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsSameMusic::Modification as i32); - column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); - column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); - tree_view.append_column(&column); - tree_view.set_vexpand(true); + + let model = get_list_store(tree_view); + let columns_colors = (ColumnsSameMusic::Color as i32, ColumnsSameMusic::TextColor as i32); + let activatable_colors = (ColumnsSameMusic::ActivatableSelectButton as i32, ColumnsSameMusic::Color as i32); + + create_default_selection_button_column(tree_view, ColumnsSameMusic::SelectionButton as i32, model, Some(activatable_colors)); + + create_default_column(tree_view, ColumnsSameMusic::Size as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Name as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Title as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Artist as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Year as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Bitrate as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Length as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Genre as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Path as i32, None, Some(columns_colors)); + create_default_column(tree_view, ColumnsSameMusic::Modification as i32, None, Some(columns_colors)); } pub fn create_tree_view_invalid_symlinks(tree_view: &TreeView) { + tree_view.set_vexpand(true); + let model = get_list_store(tree_view); - let renderer = CellRendererToggle::new(); - renderer.connect_toggled(move |_r, path| { - let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsInvalidSymlinks::SelectionButton as i32); - fixed = !fixed; - model.set_value(&iter, ColumnsInvalidSymlinks::SelectionButton as u32, &fixed.to_value()); - }); - let column = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_resizable(false); - column.set_fixed_width(30); - column.add_attribute(&renderer, "active", ColumnsInvalidSymlinks::SelectionButton as i32); - tree_view.append_column(&column); + create_default_selection_button_column(tree_view, ColumnsInvalidSymlinks::SelectionButton as i32, model, None); - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Symlink File Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsInvalidSymlinks::Name as i32); - column.set_sort_column_id(ColumnsInvalidSymlinks::Name as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Symlink Folder"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsInvalidSymlinks::Path as i32); - column.set_sort_column_id(ColumnsInvalidSymlinks::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Destination Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsInvalidSymlinks::DestinationPath as i32); - column.set_sort_column_id(ColumnsInvalidSymlinks::DestinationPath as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Type of Error"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsInvalidSymlinks::TypeOfError as i32); - column.set_sort_column_id(ColumnsInvalidSymlinks::TypeOfError as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsInvalidSymlinks::Modification as i32); - column.set_sort_column_id(ColumnsInvalidSymlinks::ModificationAsSecs as i32); - tree_view.append_column(&column); - - tree_view.set_vexpand(true); + create_default_column(tree_view, ColumnsInvalidSymlinks::Name as i32, None, None); + create_default_column(tree_view, ColumnsInvalidSymlinks::Path as i32, None, None); + create_default_column(tree_view, ColumnsInvalidSymlinks::DestinationPath as i32, None, None); + create_default_column(tree_view, ColumnsInvalidSymlinks::TypeOfError as i32, None, None); + create_default_column( + tree_view, + ColumnsInvalidSymlinks::Modification as i32, + Some(ColumnsInvalidSymlinks::ModificationAsSecs as i32), + None, + ); } pub fn create_tree_view_broken_files(tree_view: &TreeView) { + tree_view.set_vexpand(true); + let model = get_list_store(tree_view); + create_default_selection_button_column(tree_view, ColumnsBrokenFiles::SelectionButton as i32, model, None); + + create_default_column(tree_view, ColumnsBrokenFiles::Name as i32, None, None); + create_default_column(tree_view, ColumnsBrokenFiles::Path as i32, None, None); + create_default_column(tree_view, ColumnsBrokenFiles::ErrorType as i32, None, None); + create_default_column( + tree_view, + ColumnsBrokenFiles::Modification as i32, + Some(ColumnsBrokenFiles::ModificationAsSecs as i32), + None, + ); +} + +pub fn create_tree_view_bad_extensions(tree_view: &TreeView) { + tree_view.set_vexpand(true); + + let model = get_list_store(tree_view); + + create_default_selection_button_column(tree_view, ColumnsBadExtensions::SelectionButton as i32, model, None); + + create_default_column(tree_view, ColumnsBadExtensions::Name as i32, None, None); + create_default_column(tree_view, ColumnsBadExtensions::Path as i32, None, None); + create_default_column(tree_view, ColumnsBadExtensions::CurrentExtension as i32, None, None); + create_default_column(tree_view, ColumnsBadExtensions::ValidExtensions as i32, None, None); +} + +fn create_default_selection_button_column( + tree_view: &TreeView, + column_id: i32, + model: ListStore, + activatable_color_columns: Option<(i32, i32)>, +) -> (CellRendererToggle, TreeViewColumn) { let renderer = CellRendererToggle::new(); renderer.connect_toggled(move |_r, path| { let iter = model.iter(&path).unwrap(); - let mut fixed = model.get::(&iter, ColumnsBrokenFiles::SelectionButton as i32); + let mut fixed = model.get::(&iter, column_id); fixed = !fixed; - model.set_value(&iter, ColumnsBrokenFiles::SelectionButton as u32, &fixed.to_value()); + model.set_value(&iter, column_id as u32, &fixed.to_value()); }); let column = TreeViewColumn::new(); column.pack_start(&renderer, true); column.set_resizable(false); column.set_fixed_width(30); - column.add_attribute(&renderer, "active", ColumnsBrokenFiles::SelectionButton as i32); + column.add_attribute(&renderer, "active", column_id); + if let Some(activatable_color_columns) = activatable_color_columns { + column.add_attribute(&renderer, "activatable", activatable_color_columns.0); + column.add_attribute(&renderer, "cell-background", activatable_color_columns.1); + } tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Name"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBrokenFiles::Name as i32); - column.set_sort_column_id(ColumnsBrokenFiles::Name as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Path"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBrokenFiles::Path as i32); - column.set_sort_column_id(ColumnsBrokenFiles::Path as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("ErrorType"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBrokenFiles::ErrorType as i32); - column.set_sort_column_id(ColumnsBrokenFiles::ErrorType as i32); - tree_view.append_column(&column); - - let renderer = CellRendererText::new(); - let column: TreeViewColumn = TreeViewColumn::new(); - column.pack_start(&renderer, true); - column.set_title("Modification Date"); - column.set_resizable(true); - column.set_min_width(50); - column.add_attribute(&renderer, "text", ColumnsBrokenFiles::Modification as i32); - column.set_sort_column_id(ColumnsBrokenFiles::ModificationAsSecs as i32); - tree_view.append_column(&column); - - tree_view.set_vexpand(true); + (renderer, column) +} + +fn create_default_column(tree_view: &TreeView, column_id: i32, sort_column_id: Option, colors_columns_id: Option<(i32, i32)>) -> (CellRendererText, TreeViewColumn) { + let renderer = CellRendererText::new(); + let column: TreeViewColumn = TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.set_resizable(true); + column.set_min_width(50); + column.add_attribute(&renderer, "text", column_id); + if let Some(sort_column_id) = sort_column_id { + column.set_sort_column_id(sort_column_id); + } else { + column.set_sort_column_id(column_id); + } + if let Some(colors_columns_id) = colors_columns_id { + column.add_attribute(&renderer, "background", colors_columns_id.0); + column.add_attribute(&renderer, "foreground", colors_columns_id.1); + } + tree_view.append_column(&column); + (renderer, column) } diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index a134492..6e132c8 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -378,14 +378,34 @@ pub fn get_notebook_enum_from_tree_view(tree_view: &TreeView) -> NotebookMainEnu } } } +pub fn get_tree_view_name_from_notebook_enum(notebook_enum: NotebookMainEnum) -> &'static str { + match notebook_enum { + NotebookMainEnum::Duplicate => "tree_view_duplicate_finder", + NotebookMainEnum::EmptyDirectories => "tree_view_empty_folder_finder", + NotebookMainEnum::EmptyFiles => "tree_view_empty_files_finder", + NotebookMainEnum::Temporary => "tree_view_temporary_files_finder", + NotebookMainEnum::BigFiles => "tree_view_big_files_finder", + NotebookMainEnum::SimilarImages => "tree_view_similar_images_finder", + NotebookMainEnum::SimilarVideos => "tree_view_similar_videos_finder", + NotebookMainEnum::SameMusic => "tree_view_same_music_finder", + NotebookMainEnum::Symlinks => "tree_view_invalid_symlinks", + NotebookMainEnum::BrokenFiles => "tree_view_broken_files", + NotebookMainEnum::BadExtensions => "tree_view_bad_extensions", + } +} pub fn get_notebook_upper_enum_from_tree_view(tree_view: &TreeView) -> NotebookUpperEnum { match (*tree_view).widget_name().to_string().as_str() { "tree_view_upper_included_directories" => NotebookUpperEnum::IncludedDirectories, "tree_view_upper_excluded_directories" => NotebookUpperEnum::ExcludedDirectories, - e => { - panic!("{}", e) - } + e => panic!("{}", e), + } +} +pub fn get_tree_view_name_from_notebook_upper_enum(notebook_upper_enum: NotebookUpperEnum) -> &'static str { + match notebook_upper_enum { + NotebookUpperEnum::IncludedDirectories => "tree_view_upper_included_directories", + NotebookUpperEnum::ExcludedDirectories => "tree_view_upper_excluded_directories", + _ => panic!(), } } @@ -789,15 +809,46 @@ pub fn scale_step_function(scale: &Scale, _scroll_type: ScrollType, value: f64) #[cfg(test)] mod test { use glib::types::Type; + use glib::Value; use gtk4::prelude::*; - use gtk4::Orientation; + use gtk4::{Orientation, TreeView}; use image::DynamicImage; use crate::help_functions::{ change_dimension_to_krotka, check_if_list_store_column_have_all_same_values, check_if_value_is_in_list_store, get_all_boxes_from_widget, get_all_direct_children, - get_max_file_name, get_pixbuf_from_dynamic_image, + get_max_file_name, get_pixbuf_from_dynamic_image, get_string_from_list_store, }; + #[gtk4::test] + fn test_get_string_from_list_store() { + let columns_types: &[Type] = &[Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + let tree_view = TreeView::with_model(&list_store); + + let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &"test"), (0, &"test2"), (0, &"test3")]; + for i in values_to_add { + list_store.set(&list_store.append(), &[*i]); + } + assert_eq!( + get_string_from_list_store(&tree_view, 0, None), + vec!["test".to_string(), "test2".to_string(), "test3".to_string()] + ); + + let columns_types: &[Type] = &[Type::BOOL, Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + let tree_view = TreeView::with_model(&list_store); + + let values_to_add: &[&[(u32, &dyn ToValue)]] = &[ + &[(0, &Into::::into(true)), (1, &Into::::into("test"))], + &[(0, &Into::::into(true)), (1, &Into::::into("test2"))], + &[(0, &Into::::into(false)), (1, &Into::::into("test3"))], + ]; + for i in values_to_add { + list_store.set(&list_store.append(), i); + } + assert_eq!(get_string_from_list_store(&tree_view, 1, Some(0)), vec!["test".to_string(), "test2".to_string()]); + } + #[gtk4::test] fn test_check_if_list_store_column_have_all_same_values() { let columns_types: &[Type] = &[Type::BOOL]; diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index 527d180..4aa19b6 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -6,7 +6,7 @@ use gdk4::gdk_pixbuf::Pixbuf; use glib::types::Type; use gtk4::gdk_pixbuf::InterpType; use gtk4::prelude::*; -use gtk4::{CheckButton, Image, SelectionMode, TextView, TreeView}; +use gtk4::{CheckButton, Image, ScrolledWindow, SelectionMode, TextView, TreeModel, TreePath, TreeSelection, TreeView}; #[cfg(feature = "heif")] use czkawka_core::common::get_dynamic_image_from_heic; @@ -24,7 +24,7 @@ use crate::help_combo_box::{ use crate::help_functions::*; use crate::language_functions::LANGUAGES_ALL; use crate::localizer_core::generate_translation_hashmap; -use crate::notebook_enums::NotebookMainEnum; +use crate::notebook_enums::{NotebookMainEnum, NotebookUpperEnum}; use crate::notebook_info::NOTEBOOKS_INFO; use crate::opening_selecting_records::*; @@ -91,208 +91,104 @@ pub fn initialize_gui(gui_data: &mut GuiData) { // Set step increment { let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); - scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[0][5] as f64); // This defaults to value of minimal size of hash 8 - scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[0][5] as f64); - scale_similarity_similar_images.adjustment().set_step_increment(1_f64); + scale_set_min_max_values(&scale_similarity_similar_images, 0_f64, SIMILAR_VALUES[0][5] as f64, 15_f64, Some(1_f64)); } // Set step increment { let scale_similarity_similar_videos = gui_data.main_notebook.scale_similarity_similar_videos.clone(); - scale_similarity_similar_videos.set_range(0_f64, MAX_TOLERANCE as f64); // This defaults to value of minimal size of hash 8 - scale_similarity_similar_videos.set_value(15_f64); - scale_similarity_similar_videos.set_fill_level(MAX_TOLERANCE as f64); - scale_similarity_similar_videos.adjustment().set_step_increment(1_f64); + scale_set_min_max_values(&scale_similarity_similar_videos, 0_f64, MAX_TOLERANCE as f64, 15_f64, Some(1_f64)); } // Set Main Scrolled Window Treeviews { - // Duplicate Files - { - let scrolled_window = gui_data.main_notebook.scrolled_window_duplicate_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_duplicate_finder.clone(); - - let image_preview = gui_data.main_notebook.image_preview_duplicates.clone(); - image_preview.hide(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Duplicate as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - tree_view.selection().set_select_function(select_function_duplicates); - - create_tree_view_duplicates(&tree_view); - - tree_view.set_widget_name("tree_view_duplicate_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Empty Folders - { - let scrolled_window = gui_data.main_notebook.scrolled_window_empty_folder_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_empty_folder_finder.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::EmptyDirectories as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_empty_folders(&tree_view); - - tree_view.set_widget_name("tree_view_empty_folder_finder"); - - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Empty Files - { - let scrolled_window = gui_data.main_notebook.scrolled_window_empty_files_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_empty_files_finder.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::EmptyFiles as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_empty_files(&tree_view); - - tree_view.set_widget_name("tree_view_empty_files_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Temporary Files - { - let scrolled_window = gui_data.main_notebook.scrolled_window_temporary_files_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_temporary_files_finder.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Temporary as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_temporary_files(&tree_view); - - tree_view.set_widget_name("tree_view_temporary_files_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Big Files - { - let scrolled_window = gui_data.main_notebook.scrolled_window_big_files_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_big_files_finder.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BigFiles as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_big_files(&tree_view); - - tree_view.set_widget_name("tree_view_big_files_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Similar Images - { - let scrolled_window = gui_data.main_notebook.scrolled_window_similar_images_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_similar_images_finder.clone(); - - let image_preview = gui_data.main_notebook.image_preview_similar_images.clone(); - image_preview.hide(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::SimilarImages as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - tree_view.selection().set_select_function(select_function_similar_images); - - create_tree_view_similar_images(&tree_view); - - tree_view.set_widget_name("tree_view_similar_images_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Similar Videos - { - let scrolled_window = gui_data.main_notebook.scrolled_window_similar_videos_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_similar_videos_finder.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::SimilarVideos as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - tree_view.selection().set_select_function(select_function_similar_videos); - - create_tree_view_similar_videos(&tree_view); - - tree_view.set_widget_name("tree_view_similar_videos_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Same Music - { - let scrolled_window = gui_data.main_notebook.scrolled_window_same_music_finder.clone(); - let tree_view = gui_data.main_notebook.tree_view_same_music_finder.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::SameMusic as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - tree_view.selection().set_select_function(select_function_same_music); - - create_tree_view_same_music(&tree_view); - - tree_view.set_widget_name("tree_view_same_music_finder"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Invalid Symlinks - { - let scrolled_window = gui_data.main_notebook.scrolled_window_invalid_symlinks.clone(); - let tree_view = gui_data.main_notebook.tree_view_invalid_symlinks.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Symlinks as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_invalid_symlinks(&tree_view); - - tree_view.set_widget_name("tree_view_invalid_symlinks"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Broken Files - { - let scrolled_window = gui_data.main_notebook.scrolled_window_broken_files.clone(); - let tree_view = gui_data.main_notebook.tree_view_broken_files.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BrokenFiles as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_broken_files(&tree_view); - - tree_view.set_widget_name("tree_view_broken_files"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } - // Bad Extensions - { - let scrolled_window = gui_data.main_notebook.scrolled_window_bad_extensions.clone(); - let tree_view = gui_data.main_notebook.tree_view_bad_extensions.clone(); - - let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BadExtensions as usize].columns_types); - - tree_view.set_model(Some(&list_store)); - tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_broken_files(&tree_view); - - tree_view.set_widget_name("tree_view_bad_extensions"); - scrolled_window.set_child(Some(&tree_view)); - scrolled_window.show(); - } + create_column_types( + &gui_data.main_notebook.scrolled_window_duplicate_finder, + &gui_data.main_notebook.tree_view_duplicate_finder, + NotebookMainEnum::Duplicate, + Some(select_function_duplicates), + create_tree_view_duplicates, + Some(&gui_data.main_notebook.image_preview_duplicates), + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_similar_images_finder, + &gui_data.main_notebook.tree_view_similar_images_finder, + NotebookMainEnum::SimilarImages, + Some(select_function_similar_images), + create_tree_view_similar_images, + Some(&gui_data.main_notebook.image_preview_similar_images), + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_similar_videos_finder, + &gui_data.main_notebook.tree_view_similar_videos_finder, + NotebookMainEnum::SimilarVideos, + Some(select_function_similar_videos), + create_tree_view_similar_videos, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_same_music_finder, + &gui_data.main_notebook.tree_view_same_music_finder, + NotebookMainEnum::SameMusic, + Some(select_function_same_music), + create_tree_view_same_music, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_empty_folder_finder, + &gui_data.main_notebook.tree_view_empty_folder_finder, + NotebookMainEnum::EmptyDirectories, + None, + create_tree_view_empty_folders, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_empty_files_finder, + &gui_data.main_notebook.tree_view_empty_files_finder, + NotebookMainEnum::EmptyFiles, + None, + create_tree_view_empty_files, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_temporary_files_finder, + &gui_data.main_notebook.tree_view_temporary_files_finder, + NotebookMainEnum::Temporary, + None, + create_tree_view_temporary_files, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_big_files_finder, + &gui_data.main_notebook.tree_view_big_files_finder, + NotebookMainEnum::BigFiles, + None, + create_tree_view_big_files, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_invalid_symlinks, + &gui_data.main_notebook.tree_view_invalid_symlinks, + NotebookMainEnum::Symlinks, + None, + create_tree_view_invalid_symlinks, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_broken_files, + &gui_data.main_notebook.tree_view_broken_files, + NotebookMainEnum::BrokenFiles, + None, + create_tree_view_broken_files, + None, + ); + create_column_types( + &gui_data.main_notebook.scrolled_window_bad_extensions, + &gui_data.main_notebook.tree_view_bad_extensions, + NotebookMainEnum::BadExtensions, + None, + create_tree_view_bad_extensions, + None, + ); } } @@ -316,7 +212,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_included_directories(&tree_view); - tree_view.set_widget_name("tree_view_upper_included_directories"); + tree_view.set_widget_name(get_tree_view_name_from_notebook_upper_enum(NotebookUpperEnum::IncludedDirectories)); scrolled_window.set_child(Some(&tree_view)); scrolled_window.show(); @@ -350,7 +246,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_excluded_directories(&tree_view); - tree_view.set_widget_name("tree_view_upper_excluded_directories"); + tree_view.set_widget_name(get_tree_view_name_from_notebook_upper_enum(NotebookUpperEnum::ExcludedDirectories)); scrolled_window.set_child(Some(&tree_view)); scrolled_window.show(); @@ -387,6 +283,32 @@ pub fn initialize_gui(gui_data: &mut GuiData) { connect_event_mouse(gui_data); } +fn create_column_types( + scrolled_window: &ScrolledWindow, + tree_view: &TreeView, + notebook_enum: NotebookMainEnum, + select_function: Option bool>, + create_tree_view_func: fn(&TreeView), + image_preview: Option<&Image>, +) { + if let Some(image_preview) = image_preview { + image_preview.hide(); + } + let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[notebook_enum as usize].columns_types); + + tree_view.set_model(Some(&list_store)); + tree_view.selection().set_mode(SelectionMode::Multiple); + if let Some(select_function) = select_function { + tree_view.selection().set_select_function(select_function); + } + + create_tree_view_func(tree_view); + + tree_view.set_widget_name(get_tree_view_name_from_notebook_enum(notebook_enum)); + scrolled_window.set_child(Some(tree_view)); + scrolled_window.show(); +} + fn connect_event_mouse(gui_data: &GuiData) { // GTK 4 for gc in [ diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index 6c4c5d7..b93e38c 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -84,17 +84,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) { let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); // Futures progress report - let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_empty_files, futures_receiver_empty_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_empty_folder, futures_receiver_empty_folder): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_big_file, futures_receiver_big_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_same_music, futures_receiver_same_music): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_similar_images, futures_receiver_similar_images): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_similar_videos, futures_receiver_similar_videos): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_temporary, futures_receiver_temporary): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_broken_files, futures_receiver_broken_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); - let (futures_sender_bad_extensions, futures_receiver_bad_extensions): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (progress_sender, progress_receiver): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); initialize_gui(&mut gui_data); validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup @@ -117,21 +107,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) { connect_button_delete(&gui_data); connect_button_save(&gui_data); - connect_button_search( - &gui_data, - glib_stop_sender, - futures_sender_duplicate_files, - futures_sender_empty_files, - futures_sender_empty_folder, - futures_sender_big_file, - futures_sender_same_music, - futures_sender_similar_images, - futures_sender_similar_videos, - futures_sender_temporary, - futures_sender_invalid_symlinks, - futures_sender_broken_files, - futures_sender_bad_extensions, - ); + connect_button_search(&gui_data, glib_stop_sender, progress_sender); connect_button_select(&gui_data); connect_button_sort(&gui_data); connect_button_stop(&gui_data); @@ -145,20 +121,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) { connect_popover_select(&gui_data); connect_popover_sort(&gui_data); connect_compute_results(&gui_data, glib_stop_receiver); - connect_progress_window( - &gui_data, - futures_receiver_duplicate_files, - futures_receiver_empty_files, - futures_receiver_empty_folder, - futures_receiver_big_files, - futures_receiver_same_music, - futures_receiver_similar_images, - futures_receiver_similar_videos, - futures_receiver_temporary, - futures_receiver_invalid_symlinks, - futures_receiver_broken_files, - futures_receiver_bad_extensions, - ); + connect_progress_window(&gui_data, progress_receiver); connect_show_hide_ui(&gui_data); connect_settings(&gui_data); connect_button_about(&gui_data);