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
pull/973/head
Rafał Mikrut 1 year ago committed by GitHub
parent 78d00eeb99
commit 582e5417ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -85,6 +85,8 @@ pub enum Commands {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct DuplicatesArgs { pub struct DuplicatesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -163,6 +165,8 @@ pub struct DuplicatesArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct EmptyFoldersArgs { pub struct EmptyFoldersArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -180,6 +184,8 @@ pub struct EmptyFoldersArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct BiggestFilesArgs { pub struct BiggestFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -205,6 +211,8 @@ pub struct BiggestFilesArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct EmptyFilesArgs { pub struct EmptyFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -226,6 +234,8 @@ pub struct EmptyFilesArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct TemporaryArgs { pub struct TemporaryArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -245,6 +255,8 @@ pub struct TemporaryArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct SimilarImagesArgs { pub struct SimilarImagesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -313,6 +325,8 @@ pub struct SimilarImagesArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct SameMusicArgs { pub struct SameMusicArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -359,6 +373,8 @@ pub struct SameMusicArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct InvalidSymlinksArgs { pub struct InvalidSymlinksArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -380,6 +396,8 @@ pub struct InvalidSymlinksArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct BrokenFilesArgs { pub struct BrokenFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -401,6 +419,8 @@ pub struct BrokenFilesArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct SimilarVideosArgs { pub struct SimilarVideosArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -449,6 +469,8 @@ pub struct SimilarVideosArgs {
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct BadExtensionsArgs { pub struct BadExtensionsArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)] #[clap(flatten)]
pub directories: Directories, pub directories: Directories,
#[clap(flatten)] #[clap(flatten)]
@ -517,6 +539,12 @@ pub struct NotRecursive {
pub not_recursive: bool, 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")] #[cfg(target_family = "unix")]
#[derive(Debug, clap::Args)] #[derive(Debug, clap::Args)]
pub struct ExcludeOtherFilesystems { pub struct ExcludeOtherFilesystems {

@ -6,7 +6,7 @@ use clap::Parser;
use commands::Commands; use commands::Commands;
use czkawka_core::big_file::SearchMode; 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(). #[allow(unused_imports)] // It is used in release for print_results().
use czkawka_core::common_traits::*; use czkawka_core::common_traits::*;
use czkawka_core::similar_images::test_image_conversion_speed; use czkawka_core::similar_images::test_image_conversion_speed;
@ -34,8 +34,6 @@ mod commands;
fn main() { fn main() {
let command = Args::parse().command; let command = Args::parse().command;
set_default_number_of_threads();
println!("Set thread number to {}", get_number_of_threads());
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{command:?}"); println!("{command:?}");
@ -59,6 +57,7 @@ fn main() {
fn duplicates(duplicates: DuplicatesArgs) { fn duplicates(duplicates: DuplicatesArgs) {
let DuplicatesArgs { let DuplicatesArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -78,6 +77,8 @@ fn duplicates(duplicates: DuplicatesArgs) {
case_sensitive_name_comparison, case_sensitive_name_comparison,
} = duplicates; } = duplicates;
set_number_of_threads(thread_number.thread_number);
let mut df = DuplicateFinder::new(); let mut df = DuplicateFinder::new();
df.set_included_directory(directories.directories); df.set_included_directory(directories.directories);
@ -113,6 +114,7 @@ fn duplicates(duplicates: DuplicatesArgs) {
fn empty_folders(empty_folders: EmptyFoldersArgs) { fn empty_folders(empty_folders: EmptyFoldersArgs) {
let EmptyFoldersArgs { let EmptyFoldersArgs {
thread_number,
directories, directories,
delete_folders, delete_folders,
file_to_save, file_to_save,
@ -122,6 +124,8 @@ fn empty_folders(empty_folders: EmptyFoldersArgs) {
exclude_other_filesystems, exclude_other_filesystems,
} = empty_folders; } = empty_folders;
set_number_of_threads(thread_number.thread_number);
let mut ef = EmptyFolder::new(); let mut ef = EmptyFolder::new();
ef.set_included_directory(directories.directories); ef.set_included_directory(directories.directories);
@ -147,6 +151,7 @@ fn empty_folders(empty_folders: EmptyFoldersArgs) {
fn biggest_files(biggest_files: BiggestFilesArgs) { fn biggest_files(biggest_files: BiggestFilesArgs) {
let BiggestFilesArgs { let BiggestFilesArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -160,6 +165,8 @@ fn biggest_files(biggest_files: BiggestFilesArgs) {
smallest_mode, smallest_mode,
} = biggest_files; } = biggest_files;
set_number_of_threads(thread_number.thread_number);
let mut bf = BigFile::new(); let mut bf = BigFile::new();
bf.set_included_directory(directories.directories); bf.set_included_directory(directories.directories);
@ -193,6 +200,7 @@ fn biggest_files(biggest_files: BiggestFilesArgs) {
fn empty_files(empty_files: EmptyFilesArgs) { fn empty_files(empty_files: EmptyFilesArgs) {
let EmptyFilesArgs { let EmptyFilesArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -204,6 +212,8 @@ fn empty_files(empty_files: EmptyFilesArgs) {
exclude_other_filesystems, exclude_other_filesystems,
} = empty_files; } = empty_files;
set_number_of_threads(thread_number.thread_number);
let mut ef = EmptyFiles::new(); let mut ef = EmptyFiles::new();
ef.set_included_directory(directories.directories); ef.set_included_directory(directories.directories);
@ -234,6 +244,7 @@ fn empty_files(empty_files: EmptyFilesArgs) {
fn temporary(temporary: TemporaryArgs) { fn temporary(temporary: TemporaryArgs) {
let TemporaryArgs { let TemporaryArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -244,6 +255,8 @@ fn temporary(temporary: TemporaryArgs) {
not_recursive, not_recursive,
} = temporary; } = temporary;
set_number_of_threads(thread_number.thread_number);
let mut tf = Temporary::new(); let mut tf = Temporary::new();
tf.set_included_directory(directories.directories); tf.set_included_directory(directories.directories);
@ -273,6 +286,7 @@ fn temporary(temporary: TemporaryArgs) {
fn similar_images(similar_images: SimilarImagesArgs) { fn similar_images(similar_images: SimilarImagesArgs) {
let SimilarImagesArgs { let SimilarImagesArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -288,6 +302,8 @@ fn similar_images(similar_images: SimilarImagesArgs) {
hash_size, hash_size,
} = similar_images; } = similar_images;
set_number_of_threads(thread_number.thread_number);
let mut sf = SimilarImages::new(); let mut sf = SimilarImages::new();
sf.set_included_directory(directories.directories); sf.set_included_directory(directories.directories);
@ -320,6 +336,7 @@ fn similar_images(similar_images: SimilarImagesArgs) {
fn same_music(same_music: SameMusicArgs) { fn same_music(same_music: SameMusicArgs) {
let SameMusicArgs { let SameMusicArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -333,6 +350,8 @@ fn same_music(same_music: SameMusicArgs) {
music_similarity, music_similarity,
} = same_music; } = same_music;
set_number_of_threads(thread_number.thread_number);
let mut mf = SameMusic::new(); let mut mf = SameMusic::new();
mf.set_included_directory(directories.directories); mf.set_included_directory(directories.directories);
@ -365,6 +384,7 @@ fn same_music(same_music: SameMusicArgs) {
fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) { fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) {
let InvalidSymlinksArgs { let InvalidSymlinksArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -376,6 +396,8 @@ fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) {
delete_files, delete_files,
} = invalid_symlinks; } = invalid_symlinks;
set_number_of_threads(thread_number.thread_number);
let mut ifs = InvalidSymlinks::new(); let mut ifs = InvalidSymlinks::new();
ifs.set_included_directory(directories.directories); ifs.set_included_directory(directories.directories);
@ -405,6 +427,7 @@ fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) {
fn broken_files(broken_files: BrokenFilesArgs) { fn broken_files(broken_files: BrokenFilesArgs) {
let BrokenFilesArgs { let BrokenFilesArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -416,6 +439,8 @@ fn broken_files(broken_files: BrokenFilesArgs) {
exclude_other_filesystems, exclude_other_filesystems,
} = broken_files; } = broken_files;
set_number_of_threads(thread_number.thread_number);
let mut br = BrokenFiles::new(); let mut br = BrokenFiles::new();
br.set_included_directory(directories.directories); br.set_included_directory(directories.directories);
@ -446,6 +471,7 @@ fn broken_files(broken_files: BrokenFilesArgs) {
fn similar_videos(similar_videos: SimilarVideosArgs) { fn similar_videos(similar_videos: SimilarVideosArgs) {
let SimilarVideosArgs { let SimilarVideosArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -459,6 +485,8 @@ fn similar_videos(similar_videos: SimilarVideosArgs) {
allowed_extensions, allowed_extensions,
} = similar_videos; } = similar_videos;
set_number_of_threads(thread_number.thread_number);
let mut vr = SimilarVideos::new(); let mut vr = SimilarVideos::new();
vr.set_included_directory(directories.directories); vr.set_included_directory(directories.directories);
@ -488,6 +516,7 @@ fn similar_videos(similar_videos: SimilarVideosArgs) {
fn bad_extensions(bad_extensions: BadExtensionsArgs) { fn bad_extensions(bad_extensions: BadExtensionsArgs) {
let BadExtensionsArgs { let BadExtensionsArgs {
thread_number,
directories, directories,
excluded_directories, excluded_directories,
excluded_items, excluded_items,
@ -498,6 +527,8 @@ fn bad_extensions(bad_extensions: BadExtensionsArgs) {
allowed_extensions, allowed_extensions,
} = bad_extensions; } = bad_extensions;
set_number_of_threads(thread_number.thread_number);
let mut be = BadExtensions::new(); let mut be = BadExtensions::new();
be.set_included_directory(directories.directories); be.set_included_directory(directories.directories);

@ -13,7 +13,7 @@ use mime_guess::get_mime_extensions;
use rayon::prelude::*; use rayon::prelude::*;
use crate::common::{prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; 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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -124,6 +124,7 @@ const WORKAROUNDS: &[(&str, &str)] = &[
("xml", "vbox"), // VirtualBox ("xml", "vbox"), // VirtualBox
("xml", "vbox-prev"), // VirtualBox ("xml", "vbox-prev"), // VirtualBox
("xml", "vcproj"), // VisualStudio ("xml", "vcproj"), // VisualStudio
("xml", "vcxproj"), // VisualStudio
("xml", "xba"), // Libreoffice ("xml", "xba"), // Libreoffice
("xml", "xcd"), // Libreoffice files ("xml", "xcd"), // Libreoffice files
("zip", "apk"), // Android apk ("zip", "apk"), // Android apk
@ -172,6 +173,7 @@ impl Info {
} }
pub struct BadExtensions { pub struct BadExtensions {
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
files_to_check: Vec<FileEntry>, files_to_check: Vec<FileEntry>,
@ -191,6 +193,7 @@ impl BadExtensions {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::BadExtensions,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
recursive_search: true, 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<ProgressData>>) -> bool { fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = 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); let files_to_check = mem::take(&mut self.files_to_check);

@ -14,7 +14,7 @@ use humansize::BINARY;
use rayon::prelude::*; 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::{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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -55,6 +55,7 @@ impl Info {
/// Struct with required information's to work /// Struct with required information's to work
pub struct BigFile { pub struct BigFile {
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
big_files: Vec<(u64, FileEntry)>, big_files: Vec<(u64, FileEntry)>,
@ -72,6 +73,7 @@ impl BigFile {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::BigFile,
text_messages: Default::default(), text_messages: Default::default(),
information: Info::new(), information: Info::new(),
big_files: Default::default(), big_files: Default::default(),
@ -148,7 +150,8 @@ impl BigFile {
folders_to_check.push(id.clone()); 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() { while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {

@ -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, 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::{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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -78,6 +78,7 @@ impl Info {
} }
pub struct BrokenFiles { pub struct BrokenFiles {
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
files_to_check: BTreeMap<String, FileEntry>, files_to_check: BTreeMap<String, FileEntry>,
@ -99,6 +100,7 @@ impl BrokenFiles {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::BrokenFiles,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
recursive_search: true, recursive_search: true,
@ -200,7 +202,8 @@ impl BrokenFiles {
folders_to_check.push(id.clone()); 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() { while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { 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) = 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<FileEntry> = non_cached_files_to_check let mut vec_file_entry: Vec<FileEntry> = non_cached_files_to_check
.into_par_iter() .into_par_iter()

@ -19,7 +19,7 @@ use libheif_rs::{ColorSpace, HeifContext, RgbChroma};
// #[cfg(feature = "heif")] // #[cfg(feature = "heif")]
// use libheif_rs::LibHeif; // 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_directory::Directories;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
use crate::common_traits::ResultEntry; use crate::common_traits::ResultEntry;
@ -392,6 +392,7 @@ pub fn prepare_thread_handler_common(
max_stage: u8, max_stage: u8,
max_value: usize, max_value: usize,
checking_method: CheckingMethod, checking_method: CheckingMethod,
tool_type: ToolType,
) -> (JoinHandle<()>, Arc<AtomicBool>, Arc<AtomicUsize>, AtomicBool) { ) -> (JoinHandle<()>, Arc<AtomicBool>, Arc<AtomicUsize>, AtomicBool) {
let progress_thread_run = Arc::new(AtomicBool::new(true)); let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0)); let atomic_counter = Arc::new(AtomicUsize::new(0));
@ -408,6 +409,7 @@ pub fn prepare_thread_handler_common(
max_stage, max_stage,
entries_checked: atomic_counter.load(Ordering::Relaxed), entries_checked: atomic_counter.load(Ordering::Relaxed),
entries_to_check: max_value, entries_to_check: max_value,
tool_type,
}) })
.unwrap(); .unwrap();
if !progress_thread_run.load(Ordering::Relaxed) { if !progress_thread_run.load(Ordering::Relaxed) {

@ -3,7 +3,6 @@ use std::fs;
use std::fs::{DirEntry, Metadata, ReadDir}; use std::fs::{DirEntry, Metadata, ReadDir};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::time::UNIX_EPOCH; use std::time::UNIX_EPOCH;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
@ -25,6 +24,23 @@ pub struct ProgressData {
pub max_stage: u8, pub max_stage: u8,
pub entries_checked: usize, pub entries_checked: usize,
pub entries_to_check: 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)] #[derive(PartialEq, Eq, Clone, Debug, Copy)]
@ -118,6 +134,7 @@ pub struct DirTraversalBuilder<'a, 'b, F> {
directories: Option<Directories>, directories: Option<Directories>,
excluded_items: Option<ExcludedItems>, excluded_items: Option<ExcludedItems>,
allowed_extensions: Option<Extensions>, allowed_extensions: Option<Extensions>,
tool_type: ToolType,
} }
pub struct DirTraversal<'a, 'b, F> { pub struct DirTraversal<'a, 'b, F> {
@ -133,6 +150,7 @@ pub struct DirTraversal<'a, 'b, F> {
maximal_file_size: u64, maximal_file_size: u64,
checking_method: CheckingMethod, checking_method: CheckingMethod,
max_stage: u8, max_stage: u8,
tool_type: ToolType,
collect: Collect, collect: Collect,
} }
@ -159,6 +177,7 @@ impl<'a, 'b> DirTraversalBuilder<'a, 'b, ()> {
directories: None, directories: None,
allowed_extensions: None, allowed_extensions: None,
excluded_items: None, excluded_items: None,
tool_type: ToolType::BadExtensions,
} }
} }
} }
@ -236,6 +255,12 @@ impl<'a, 'b, F> DirTraversalBuilder<'a, 'b, F> {
self self
} }
#[must_use]
pub fn tool_type(mut self, tool_type: ToolType) -> Self {
self.tool_type = tool_type;
self
}
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
#[must_use] #[must_use]
pub fn exclude_other_filesystems(mut self, exclude_other_filesystems: bool) -> Self { 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, collect: self.collect,
checking_method: self.checking_method, checking_method: self.checking_method,
max_stage: self.max_stage, 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"), excluded_items: self.excluded_items.expect("could not build"),
allowed_extensions: self.allowed_extensions.unwrap_or_default(), allowed_extensions: self.allowed_extensions.unwrap_or_default(),
recursive_search: self.recursive_search, recursive_search: self.recursive_search,
tool_type: self.tool_type,
} }
} }
} }
@ -339,7 +366,7 @@ where
folders_to_check.extend(self.root_dirs); folders_to_check.extend(self.root_dirs);
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = 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 { let DirTraversal {
collect, collect,
@ -372,6 +399,7 @@ where
return (dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list); 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. // Check every sub folder/file/link etc.
'dir: for entry in read_dir { 'dir: for entry in read_dir {
let Some((entry_data, metadata)) = common_get_entry_data_metadata(&entry, &mut warnings, current_folder) else { 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); process_dir_in_file_symlink_mode(recursive_search, current_folder, entry_data, &directories, &mut dir_result, &mut warnings, &excluded_items);
} }
(EntryType::Dir, Collect::EmptyFolders) => { (EntryType::Dir, Collect::EmptyFolders) => {
atomic_counter.fetch_add(1, Ordering::Relaxed); counter += 1;
process_dir_in_dir_mode( process_dir_in_dir_mode(
&metadata, &metadata,
current_folder, current_folder,
@ -397,7 +425,7 @@ where
); );
} }
(EntryType::File, Collect::Files) => { (EntryType::File, Collect::Files) => {
atomic_counter.fetch_add(1, Ordering::Relaxed); counter += 1;
process_file_in_file_mode( process_file_in_file_mode(
&metadata, &metadata,
entry_data, entry_data,
@ -424,10 +452,10 @@ where
set_as_not_empty_folder_list.push(current_folder.clone()); set_as_not_empty_folder_list.push(current_folder.clone());
} }
(EntryType::File, Collect::InvalidSymlinks) => { (EntryType::File, Collect::InvalidSymlinks) => {
atomic_counter.fetch_add(1, Ordering::Relaxed); counter += 1;
} }
(EntryType::Symlink, Collect::InvalidSymlinks) => { (EntryType::Symlink, Collect::InvalidSymlinks) => {
atomic_counter.fetch_add(1, Ordering::Relaxed); counter += 1;
process_symlink_in_symlink_mode( process_symlink_in_symlink_mode(
&metadata, &metadata,
entry_data, 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) (dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list)
}) })
.collect(); .collect();

@ -21,7 +21,7 @@ use rayon::prelude::*;
use xxhash_rust::xxh3::Xxh3; 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::{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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -81,6 +81,7 @@ impl Info {
} }
pub struct DuplicateFinder { pub struct DuplicateFinder {
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
files_with_identical_names: BTreeMap<String, Vec<FileEntry>>, // File Size, File Entry files_with_identical_names: BTreeMap<String, Vec<FileEntry>>, // File Size, File Entry
@ -116,6 +117,7 @@ impl DuplicateFinder {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::Duplicate,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
files_with_identical_names: Default::default(), files_with_identical_names: Default::default(),
@ -675,8 +677,14 @@ impl DuplicateFinder {
pre_checked_map: &mut BTreeMap<u64, Vec<FileEntry>>, pre_checked_map: &mut BTreeMap<u64, Vec<FileEntry>>,
) -> Option<()> { ) -> Option<()> {
let check_type = self.hash_type; let check_type = self.hash_type;
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common(
prepare_thread_handler_common(progress_sender, 1, 2, self.files_with_identical_size.values().map(Vec::len).sum(), self.check_method); 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(); 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 check_type = self.hash_type;
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = 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 ///////////////////////////////////////////////////////////////////////////// HASHING START
{ {

@ -7,7 +7,7 @@ use std::path::PathBuf;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender; 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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -35,6 +35,8 @@ impl Info {
/// Struct with required information's to work /// Struct with required information's to work
pub struct EmptyFiles { pub struct EmptyFiles {
#[allow(dead_code)]
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
empty_files: Vec<FileEntry>, empty_files: Vec<FileEntry>,
@ -50,6 +52,7 @@ impl EmptyFiles {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::EmptyFiles,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
recursive_search: true, recursive_search: true,

@ -7,7 +7,7 @@ use std::path::PathBuf;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender; 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_directory::Directories;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
use crate::common_messages::Messages; 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 /// Struct to store most basics info about all folder
pub struct EmptyFolder { pub struct EmptyFolder {
#[allow(dead_code)]
tool_type: ToolType,
information: Info, information: Info,
delete_folders: bool, delete_folders: bool,
text_messages: Messages, text_messages: Messages,
@ -43,6 +45,7 @@ impl EmptyFolder {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::EmptyFolders,
information: Default::default(), information: Default::default(),
delete_folders: false, delete_folders: false,
text_messages: Messages::new(), text_messages: Messages::new(),

@ -7,7 +7,7 @@ use std::path::PathBuf;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender; 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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -35,6 +35,8 @@ impl Info {
/// Struct with required information's to work /// Struct with required information's to work
pub struct InvalidSymlinks { pub struct InvalidSymlinks {
#[allow(dead_code)]
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
invalid_symlinks: Vec<FileEntry>, invalid_symlinks: Vec<FileEntry>,
@ -50,6 +52,7 @@ impl InvalidSymlinks {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::InvalidSymlinks,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
recursive_search: true, recursive_search: true,

@ -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::{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::{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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -108,6 +108,7 @@ impl Info {
/// Struct with required information's to work /// Struct with required information's to work
pub struct SameMusic { pub struct SameMusic {
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
music_to_check: HashMap<String, MusicEntry>, music_to_check: HashMap<String, MusicEntry>,
@ -138,6 +139,7 @@ impl SameMusic {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::SameMusic,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
recursive_search: true, 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 (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) = 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; let configuration = &self.hash_preset_config;
// Clean for duplicate files // 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 (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) = 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 // Clean for duplicate files
let mut vec_file_entry = non_cached_files_to_check 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<ProgressData>>) -> bool { fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = 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<MusicEntry>> = vec![self.music_entries.clone()]; let mut old_duplicates: Vec<Vec<MusicEntry>> = vec![self.music_entries.clone()];
let mut new_duplicates: Vec<Vec<MusicEntry>> = Vec::new(); let mut new_duplicates: Vec<Vec<MusicEntry>> = 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<ProgressData>>) -> bool { fn read_tags_to_files_similar_by_content(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let groups_to_check = max(self.duplicated_music_entries.len(), self.duplicated_music_entries_referenced.len()); 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) = 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? // TODO is ther a way to just run iterator and not collect any info?
if !self.duplicated_music_entries.is_empty() { 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<ProgressData>>) -> bool { fn check_for_duplicate_fingerprints(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let (base_files, files_to_compare) = self.split_fingerprints_to_check(); let (base_files, files_to_compare) = self.split_fingerprints_to_check();
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = 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 { 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); send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle);

@ -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, 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, 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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -85,6 +85,7 @@ impl bk_tree::Metric<ImHash> for Hamming {
/// Struct to store most basics info about all folder /// Struct to store most basics info about all folder
pub struct SimilarImages { pub struct SimilarImages {
tool_type: ToolType,
information: Info, information: Info,
text_messages: Messages, text_messages: Messages,
directories: Directories, directories: Directories,
@ -131,6 +132,7 @@ impl SimilarImages {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::SimilarImages,
information: Default::default(), information: Default::default(),
text_messages: Messages::new(), text_messages: Messages::new(),
directories: Directories::new(), directories: Directories::new(),
@ -300,7 +302,8 @@ impl SimilarImages {
folders_to_check.push(id.clone()); 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() { while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { 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 (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) = 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 let mut vec_file_entry: Vec<(FileEntry, ImHash)> = non_cached_files_to_check
.into_par_iter() .into_par_iter()
@ -816,7 +819,7 @@ impl SimilarImages {
} }
} else { } else {
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = 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 // Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes

@ -18,7 +18,7 @@ use vid_dup_finder_lib::{NormalizedTolerance, VideoHash};
use crate::common::open_cache_folder; 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::{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_directory::Directories;
use crate::common_extensions::Extensions; use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
@ -60,6 +60,7 @@ impl bk_tree::Metric<Vec<u8>> for Hamming {
/// Struct to store most basics info about all folder /// Struct to store most basics info about all folder
pub struct SimilarVideos { pub struct SimilarVideos {
tool_type: ToolType,
information: Info, information: Info,
text_messages: Messages, text_messages: Messages,
directories: Directories, directories: Directories,
@ -101,6 +102,7 @@ impl SimilarVideos {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::SimilarVideos,
information: Default::default(), information: Default::default(),
text_messages: Messages::new(), text_messages: Messages::new(),
directories: Directories::new(), directories: Directories::new(),
@ -261,7 +263,8 @@ impl SimilarVideos {
folders_to_check.push(id.clone()); 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() { while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { 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 (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) = 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<FileEntry> = non_cached_files_to_check let mut vec_file_entry: Vec<FileEntry> = non_cached_files_to_check
.par_iter() .par_iter()

@ -11,7 +11,7 @@ use futures::channel::mpsc::UnboundedSender;
use rayon::prelude::*; use rayon::prelude::*;
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; 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_directory::Directories;
use crate::common_items::ExcludedItems; use crate::common_items::ExcludedItems;
use crate::common_messages::Messages; use crate::common_messages::Messages;
@ -60,6 +60,7 @@ impl Info {
/// Struct with required information's to work /// Struct with required information's to work
pub struct Temporary { pub struct Temporary {
tool_type: ToolType,
text_messages: Messages, text_messages: Messages,
information: Info, information: Info,
temporary_files: Vec<FileEntry>, temporary_files: Vec<FileEntry>,
@ -74,6 +75,7 @@ impl Temporary {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tool_type: ToolType::TemporaryFiles,
text_messages: Messages::new(), text_messages: Messages::new(),
information: Info::new(), information: Info::new(),
recursive_search: true, recursive_search: true,
@ -149,7 +151,8 @@ impl Temporary {
folders_to_check.push(id.clone()); 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() { while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {

@ -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}; use crate::{flg, DEFAULT_MAXIMAL_FILE_SIZE, DEFAULT_MINIMAL_CACHE_SIZE, DEFAULT_MINIMAL_FILE_SIZE};
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn connect_button_search( pub fn connect_button_search(gui_data: &GuiData, glib_stop_sender: Sender<Message>, progress_sender: UnboundedSender<ProgressData>) {
gui_data: &GuiData,
glib_stop_sender: Sender<Message>,
futures_sender_duplicate_files: UnboundedSender<ProgressData>,
futures_sender_empty_files: UnboundedSender<ProgressData>,
futures_sender_empty_folder: UnboundedSender<ProgressData>,
futures_sender_big_file: UnboundedSender<ProgressData>,
futures_sender_same_music: UnboundedSender<ProgressData>,
futures_sender_similar_images: UnboundedSender<ProgressData>,
futures_sender_similar_videos: UnboundedSender<ProgressData>,
futures_sender_temporary: UnboundedSender<ProgressData>,
futures_sender_invalid_symlinks: UnboundedSender<ProgressData>,
futures_sender_broken_files: UnboundedSender<ProgressData>,
futures_sender_bad_extensions: UnboundedSender<ProgressData>,
) {
let buttons_array = gui_data.bottom_buttons.buttons_array.clone(); let buttons_array = gui_data.bottom_buttons.buttons_array.clone();
let buttons_search_clone = gui_data.bottom_buttons.buttons_search.clone(); let buttons_search_clone = gui_data.bottom_buttons.buttons_search.clone();
let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone(); let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone();
@ -109,7 +95,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_duplicate_files.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::EmptyFiles => empty_files_search( NotebookMainEnum::EmptyFiles => empty_files_search(
&gui_data, &gui_data,
@ -117,7 +103,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_empty_files.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::EmptyDirectories => empty_directories_search( NotebookMainEnum::EmptyDirectories => empty_directories_search(
&gui_data, &gui_data,
@ -125,7 +111,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_empty_folder.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::BigFiles => big_files_search( NotebookMainEnum::BigFiles => big_files_search(
&gui_data, &gui_data,
@ -133,7 +119,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_big_file.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::Temporary => temporary_files_search( NotebookMainEnum::Temporary => temporary_files_search(
&gui_data, &gui_data,
@ -141,7 +127,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_temporary.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::SimilarImages => similar_image_search( NotebookMainEnum::SimilarImages => similar_image_search(
&gui_data, &gui_data,
@ -149,7 +135,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_similar_images.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::SimilarVideos => similar_video_search( NotebookMainEnum::SimilarVideos => similar_video_search(
&gui_data, &gui_data,
@ -157,7 +143,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_similar_videos.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::SameMusic => same_music_search( NotebookMainEnum::SameMusic => same_music_search(
&gui_data, &gui_data,
@ -165,7 +151,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_same_music.clone(), progress_sender.clone(),
&show_dialog, &show_dialog,
), ),
NotebookMainEnum::Symlinks => bad_symlinks_search( NotebookMainEnum::Symlinks => bad_symlinks_search(
@ -174,7 +160,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_invalid_symlinks.clone(), progress_sender.clone(),
), ),
NotebookMainEnum::BrokenFiles => broken_files_search( NotebookMainEnum::BrokenFiles => broken_files_search(
&gui_data, &gui_data,
@ -182,7 +168,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_broken_files.clone(), progress_sender.clone(),
&show_dialog, &show_dialog,
), ),
NotebookMainEnum::BadExtensions => bad_extensions_search( NotebookMainEnum::BadExtensions => bad_extensions_search(
@ -191,7 +177,7 @@ pub fn connect_button_search(
stop_receiver, stop_receiver,
glib_stop_sender, glib_stop_sender,
&grid_progress_stages, &grid_progress_stages,
futures_sender_bad_extensions.clone(), progress_sender.clone(),
), ),
} }

@ -10,7 +10,7 @@ use gtk4::ProgressBar;
use common_dir_traversal::CheckingMethod; use common_dir_traversal::CheckingMethod;
use czkawka_core::common_dir_traversal; 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::flg;
use crate::gui_structs::gui_data::GuiData; use crate::gui_structs::gui_data::GuiData;
@ -19,304 +19,256 @@ use crate::taskbar_progress::tbp_flags::TBPF_INDETERMINATE;
use crate::taskbar_progress::TaskbarProgress; use crate::taskbar_progress::TaskbarProgress;
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn connect_progress_window( pub fn connect_progress_window(gui_data: &GuiData, mut progress_receiver: UnboundedReceiver<ProgressData>) {
gui_data: &GuiData,
futures_receiver_duplicate_files: UnboundedReceiver<ProgressData>,
futures_receiver_empty_files: UnboundedReceiver<ProgressData>,
futures_receiver_empty_folder: UnboundedReceiver<ProgressData>,
futures_receiver_big_files: UnboundedReceiver<ProgressData>,
futures_receiver_same_music: UnboundedReceiver<ProgressData>,
futures_receiver_similar_images: UnboundedReceiver<ProgressData>,
futures_receiver_similar_videos: UnboundedReceiver<ProgressData>,
futures_receiver_temporary: UnboundedReceiver<ProgressData>,
futures_receiver_invalid_symlinks: UnboundedReceiver<ProgressData>,
futures_receiver_broken_files: UnboundedReceiver<ProgressData>,
futures_receiver_bad_extensions: UnboundedReceiver<ProgressData>,
) {
let main_context = MainContext::default(); let main_context = MainContext::default();
let _guard = main_context.acquire().unwrap(); let _guard = main_context.acquire().unwrap();
process_bar_duplicates(gui_data, &main_context, futures_receiver_duplicate_files); let gui_data = gui_data.clone();
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<ProgressData>) {
let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
let future = async move { let future = async move {
while let Some(item) = futures_receiver_empty_files.next().await { while let Some(item) = progress_receiver.next().await {
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); match item.tool_type {
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); 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); main_context.spawn_local(future);
} }
fn process_bar_empty_folder(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_empty_folder: UnboundedReceiver<ProgressData>) { fn process_bar_empty_files(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.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_general_file", file_number_tm(item)));
label_stage.set_text(&flg!( taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
"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<ProgressData>) { fn process_bar_empty_folder(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.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!(
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); "progress_scanning_empty_folders",
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); 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_same_music(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_same_music: UnboundedReceiver<ProgressData>) { 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 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_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 progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.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 { match item.current_stage {
CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(&item))), 0 => {
CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content", progress_ratio_tm(&item))), progress_bar_current_stage.hide();
_ => panic!(), label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
} taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
} }
2 => { 1 => {
common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
match item.checking_method { match item.checking_method {
CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags_end", progress_ratio_tm(&item))), 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_end", progress_ratio_tm(&item))), CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content", progress_ratio_tm(item))),
_ => panic!(), _ => panic!(),
} }
} }
3 => { 2 => {
common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
match item.checking_method { match item.checking_method {
CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(&item))), CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags_end", progress_ratio_tm(item))),
_ => panic!(), CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content_end", progress_ratio_tm(item))),
}
}
_ => panic!(), _ => panic!(),
} }
} }
}; 3 => {
main_context.spawn_local(future); 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_similar_images(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_similar_images: UnboundedReceiver<ProgressData>) { fn process_bar_similar_images(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); 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_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 progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.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 {
match item.current_stage { 0 => {
0 => { progress_bar_current_stage.hide();
progress_bar_current_stage.hide(); label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
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!(),
}
} }
}; 1 => {
main_context.spawn_local(future); 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_similar_videos(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_similar_videos: UnboundedReceiver<ProgressData>) { fn process_bar_similar_videos(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); 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_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 progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.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 {
match item.current_stage { 0 => {
0 => { progress_bar_current_stage.hide();
progress_bar_current_stage.hide(); label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
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!(),
}
} }
}; 1 => {
main_context.spawn_local(future); 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_temporary(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_temporary: UnboundedReceiver<ProgressData>) { fn process_bar_temporary(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.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)));
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
};
main_context.spawn_local(future);
} }
fn process_bar_invalid_symlinks(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_invalid_symlinks: UnboundedReceiver<ProgressData>) { fn process_bar_invalid_symlinks(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.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)));
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();
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); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
} }
}; 1 => {
main_context.spawn_local(future); 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_broken_files(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_broken_files: UnboundedReceiver<ProgressData>) { fn process_bar_bad_extensions(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); 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_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 progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.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 {
match item.current_stage { 0 => {
0 => { progress_bar_current_stage.hide();
progress_bar_current_stage.hide(); label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
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!(),
}
} }
}; 1 => {
main_context.spawn_local(future); 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_bad_extensions(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_bad_extensions: UnboundedReceiver<ProgressData>) { fn process_bar_duplicates(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone(); 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_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 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 taskbar_state = gui_data.taskbar_state.clone();
let future = async move {
while let Some(item) = futures_receiver_bad_extensions.next().await { match item.checking_method {
CheckingMethod::Hash => {
label_stage.show();
match item.current_stage { match item.current_stage {
// Checking Size
0 => { 0 => {
progress_bar_current_stage.hide(); progress_bar_current_stage.hide();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(&item))); // 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); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
} }
// Hash - first 1KB file
1 => { 1 => {
progress_bar_current_stage.show(); progress_bar_current_stage.show();
common_set_data(&item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state); // progress_bar_all_stages.show();
label_stage.set_text(&flg!("progress_scanning_extension_of_files", progress_ratio_tm(&item))); 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");
} }
_ => panic!(),
} }
} }
}; CheckingMethod::Name => {
main_context.spawn_local(future); label_stage.show();
} grid_progress_stages.hide();
fn process_bar_duplicates(gui_data: &GuiData, main_context: &MainContext, mut futures_receiver_duplicate_files: UnboundedReceiver<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))); label_stage.set_text(&flg!("progress_scanning_name", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
} }
CheckingMethod::SizeName => { CheckingMethod::SizeName => {
label_stage.show(); label_stage.show();
grid_progress_stages.hide(); grid_progress_stages.hide();
label_stage.set_text(&flg!("progress_scanning_size_name", file_number_tm(&item))); label_stage.set_text(&flg!("progress_scanning_size_name", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
} }
CheckingMethod::Size => { CheckingMethod::Size => {
label_stage.show(); label_stage.show();
grid_progress_stages.hide(); grid_progress_stages.hide();
label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(&item))); label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
_ => panic!(),
};
} }
_ => 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<RefCell<TaskbarProgress>>) { fn common_set_data(item: &ProgressData, progress_bar_all_stages: &ProgressBar, progress_bar_current_stage: &ProgressBar, taskbar_state: &Rc<RefCell<TaskbarProgress>>) {

@ -1,5 +1,5 @@
use gtk4::prelude::*; use gtk4::prelude::*;
use gtk4::{CellRendererText, CellRendererToggle, TreeView, TreeViewColumn}; use gtk4::{CellRendererText, CellRendererToggle, ListStore, TreeView, TreeViewColumn};
use crate::help_functions::*; use crate::help_functions::*;
@ -8,726 +8,234 @@ use crate::help_functions::*;
pub fn create_tree_view_included_directories(tree_view: &TreeView) { pub fn create_tree_view_included_directories(tree_view: &TreeView) {
let model = get_list_store(tree_view); let model = get_list_store(tree_view);
let renderer = CellRendererText::new(); create_default_column(tree_view, ColumnsIncludedDirectory::Path as i32, None, None);
let column: TreeViewColumn = TreeViewColumn::new(); create_default_selection_button_column(tree_view, ColumnsIncludedDirectory::ReferenceButton as i32, model, None);
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::<bool>(&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);
} }
pub fn create_tree_view_excluded_directories(tree_view: &TreeView) { 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); 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) { 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::<bool>(&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); tree_view.set_vexpand(true);
}
pub fn create_tree_view_empty_folders(tree_view: &TreeView) {
let model = get_list_store(tree_view); 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);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsDuplicates::SelectionButton as i32, model, Some(activatable_colors));
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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);
let renderer = CellRendererText::new(); create_default_column(tree_view, ColumnsDuplicates::Size as i32, None, Some(columns_colors));
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsDuplicates::Name as i32, None, Some(columns_colors));
column.pack_start(&renderer, true); create_default_column(tree_view, ColumnsDuplicates::Path as i32, None, Some(columns_colors));
column.set_title("Folder Name"); create_default_column(tree_view, ColumnsDuplicates::Modification as i32, None, Some(columns_colors));
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);
pub fn create_tree_view_empty_folders(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_big_files(tree_view: &TreeView) {
let model = get_list_store(tree_view); let model = get_list_store(tree_view);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsEmptyFolders::SelectionButton as i32, model, None);
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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);
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(); create_default_column(tree_view, ColumnsEmptyFolders::Name as i32, None, None);
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsEmptyFolders::Path as i32, None, None);
column.pack_start(&renderer, true); create_default_column(
column.set_title("Modification Date"); tree_view,
column.set_resizable(true); ColumnsEmptyFolders::Modification as i32,
column.set_min_width(50); Some(ColumnsEmptyFolders::ModificationAsSecs as i32),
column.add_attribute(&renderer, "text", ColumnsBigFiles::Modification as i32); None,
column.set_sort_column_id(ColumnsBigFiles::ModificationAsSecs as i32); );
tree_view.append_column(&column); }
pub fn create_tree_view_big_files(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_temporary_files(tree_view: &TreeView) {
let model = get_list_store(tree_view); let model = get_list_store(tree_view);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsBigFiles::SelectionButton as i32, model, None);
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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);
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(); create_default_column(tree_view, ColumnsBigFiles::Size as i32, None, None);
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsBigFiles::Name as i32, None, None);
column.pack_start(&renderer, true); create_default_column(tree_view, ColumnsBigFiles::Path as i32, None, None);
column.set_title("Path"); create_default_column(tree_view, ColumnsBigFiles::Modification as i32, Some(ColumnsBigFiles::ModificationAsSecs as i32), None);
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);
pub fn create_tree_view_temporary_files(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_empty_files(tree_view: &TreeView) {
let model = get_list_store(tree_view); let model = get_list_store(tree_view);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsTemporaryFiles::SelectionButton as i32, model, None);
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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);
let renderer = CellRendererText::new(); create_default_column(tree_view, ColumnsTemporaryFiles::Name as i32, None, None);
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsTemporaryFiles::Path as i32, None, None);
column.pack_start(&renderer, true); create_default_column(
column.set_title("File Name"); tree_view,
column.set_resizable(true); ColumnsTemporaryFiles::Modification as i32,
column.set_min_width(50); Some(ColumnsTemporaryFiles::ModificationAsSecs as i32),
column.add_attribute(&renderer, "text", ColumnsEmptyFiles::Name as i32); None,
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);
pub fn create_tree_view_empty_files(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_similar_images(tree_view: &TreeView) {
let model = get_list_store(tree_view); let model = get_list_store(tree_view);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsEmptyFiles::SelectionButton as i32, model, None);
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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(); create_default_column(tree_view, ColumnsEmptyFiles::Name as i32, None, None);
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsEmptyFiles::Path as i32, None, None);
column.pack_start(&renderer, true); create_default_column(tree_view, ColumnsEmptyFiles::Modification as i32, Some(ColumnsEmptyFiles::ModificationAsSecs as i32), None);
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);
pub fn create_tree_view_similar_images(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_similar_videos(tree_view: &TreeView) {
let model = get_list_store(tree_view); 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);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsSimilarImages::SelectionButton as i32, model, Some(activatable_colors));
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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(); create_default_column(tree_view, ColumnsSimilarImages::Similarity as i32, None, Some(columns_colors));
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsSimilarImages::Size as i32, None, Some(columns_colors));
column.pack_start(&renderer, true); create_default_column(tree_view, ColumnsSimilarImages::Dimensions as i32, None, Some(columns_colors));
column.set_title("Size"); create_default_column(tree_view, ColumnsSimilarImages::Name as i32, None, Some(columns_colors));
column.set_resizable(true); create_default_column(tree_view, ColumnsSimilarImages::Path as i32, None, Some(columns_colors));
column.set_min_width(50); create_default_column(tree_view, ColumnsSimilarImages::Modification as i32, None, Some(columns_colors));
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);
pub fn create_tree_view_similar_videos(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_same_music(tree_view: &TreeView) {
let model = get_list_store(tree_view); 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);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsSimilarVideos::SelectionButton as i32, model, Some(activatable_colors));
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&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(); create_default_column(tree_view, ColumnsSimilarVideos::Size as i32, None, Some(columns_colors));
let column: TreeViewColumn = TreeViewColumn::new(); create_default_column(tree_view, ColumnsSimilarVideos::Name as i32, None, Some(columns_colors));
column.pack_start(&renderer, true); create_default_column(tree_view, ColumnsSimilarVideos::Path as i32, None, Some(columns_colors));
column.set_title("File Name"); create_default_column(tree_view, ColumnsSimilarVideos::Modification as i32, None, Some(columns_colors));
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(); pub fn create_tree_view_same_music(tree_view: &TreeView) {
let column: TreeViewColumn = TreeViewColumn::new(); tree_view.set_vexpand(true);
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 model = get_list_store(tree_view);
let column: TreeViewColumn = TreeViewColumn::new(); let columns_colors = (ColumnsSameMusic::Color as i32, ColumnsSameMusic::TextColor as i32);
column.pack_start(&renderer, true); let activatable_colors = (ColumnsSameMusic::ActivatableSelectButton as i32, ColumnsSameMusic::Color as i32);
column.set_title("Length");
column.set_resizable(true); create_default_selection_button_column(tree_view, ColumnsSameMusic::SelectionButton as i32, model, Some(activatable_colors));
column.set_min_width(50);
column.add_attribute(&renderer, "text", ColumnsSameMusic::Length as i32); create_default_column(tree_view, ColumnsSameMusic::Size as i32, None, Some(columns_colors));
column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); create_default_column(tree_view, ColumnsSameMusic::Name as i32, None, Some(columns_colors));
column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); create_default_column(tree_view, ColumnsSameMusic::Title as i32, None, Some(columns_colors));
tree_view.append_column(&column); 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));
}
let renderer = CellRendererText::new(); pub fn create_tree_view_invalid_symlinks(tree_view: &TreeView) {
let column: TreeViewColumn = TreeViewColumn::new(); tree_view.set_vexpand(true);
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 model = get_list_store(tree_view);
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(); create_default_selection_button_column(tree_view, ColumnsInvalidSymlinks::SelectionButton as i32, model, None);
let column: TreeViewColumn = TreeViewColumn::new();
column.pack_start(&renderer, true); create_default_column(tree_view, ColumnsInvalidSymlinks::Name as i32, None, None);
column.set_title("Modification Date"); create_default_column(tree_view, ColumnsInvalidSymlinks::Path as i32, None, None);
column.set_resizable(true); create_default_column(tree_view, ColumnsInvalidSymlinks::DestinationPath as i32, None, None);
column.set_min_width(50); create_default_column(tree_view, ColumnsInvalidSymlinks::TypeOfError as i32, None, None);
column.add_attribute(&renderer, "text", ColumnsSameMusic::Modification as i32); create_default_column(
column.add_attribute(&renderer, "background", ColumnsSameMusic::Color as i32); tree_view,
column.add_attribute(&renderer, "foreground", ColumnsSameMusic::TextColor as i32); ColumnsInvalidSymlinks::Modification as i32,
tree_view.append_column(&column); Some(ColumnsInvalidSymlinks::ModificationAsSecs as i32),
None,
);
}
pub fn create_tree_view_broken_files(tree_view: &TreeView) {
tree_view.set_vexpand(true); tree_view.set_vexpand(true);
}
pub fn create_tree_view_invalid_symlinks(tree_view: &TreeView) {
let model = get_list_store(tree_view); let model = get_list_store(tree_view);
let renderer = CellRendererToggle::new(); create_default_selection_button_column(tree_view, ColumnsBrokenFiles::SelectionButton as i32, model, None);
renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap(); create_default_column(tree_view, ColumnsBrokenFiles::Name as i32, None, None);
let mut fixed = model.get::<bool>(&iter, ColumnsInvalidSymlinks::SelectionButton as i32); create_default_column(tree_view, ColumnsBrokenFiles::Path as i32, None, None);
fixed = !fixed; create_default_column(tree_view, ColumnsBrokenFiles::ErrorType as i32, None, None);
model.set_value(&iter, ColumnsInvalidSymlinks::SelectionButton as u32, &fixed.to_value()); create_default_column(
}); tree_view,
let column = TreeViewColumn::new(); ColumnsBrokenFiles::Modification as i32,
column.pack_start(&renderer, true); Some(ColumnsBrokenFiles::ModificationAsSecs as i32),
column.set_resizable(false); None,
column.set_fixed_width(30); );
column.add_attribute(&renderer, "active", ColumnsInvalidSymlinks::SelectionButton 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 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(); pub fn create_tree_view_bad_extensions(tree_view: &TreeView) {
let column: TreeViewColumn = TreeViewColumn::new(); tree_view.set_vexpand(true);
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 model = get_list_store(tree_view);
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(); create_default_selection_button_column(tree_view, ColumnsBadExtensions::SelectionButton as i32, model, None);
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, 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);
} }
pub fn create_tree_view_broken_files(tree_view: &TreeView) { fn create_default_selection_button_column(
let model = get_list_store(tree_view); tree_view: &TreeView,
column_id: i32,
model: ListStore,
activatable_color_columns: Option<(i32, i32)>,
) -> (CellRendererToggle, TreeViewColumn) {
let renderer = CellRendererToggle::new(); let renderer = CellRendererToggle::new();
renderer.connect_toggled(move |_r, path| { renderer.connect_toggled(move |_r, path| {
let iter = model.iter(&path).unwrap(); let iter = model.iter(&path).unwrap();
let mut fixed = model.get::<bool>(&iter, ColumnsBrokenFiles::SelectionButton as i32); let mut fixed = model.get::<bool>(&iter, column_id);
fixed = !fixed; 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(); let column = TreeViewColumn::new();
column.pack_start(&renderer, true); column.pack_start(&renderer, true);
column.set_resizable(false); column.set_resizable(false);
column.set_fixed_width(30); column.set_fixed_width(30);
column.add_attribute(&renderer, "active", ColumnsBrokenFiles::SelectionButton as i32); column.add_attribute(&renderer, "active", column_id);
tree_view.append_column(&column); if let Some(activatable_color_columns) = activatable_color_columns {
column.add_attribute(&renderer, "activatable", activatable_color_columns.0);
let renderer = CellRendererText::new(); column.add_attribute(&renderer, "cell-background", activatable_color_columns.1);
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); tree_view.append_column(&column);
(renderer, column)
}
fn create_default_column(tree_view: &TreeView, column_id: i32, sort_column_id: Option<i32>, colors_columns_id: Option<(i32, i32)>) -> (CellRendererText, TreeViewColumn) {
let renderer = CellRendererText::new(); let renderer = CellRendererText::new();
let column: TreeViewColumn = TreeViewColumn::new(); let column: TreeViewColumn = TreeViewColumn::new();
column.pack_start(&renderer, true); column.pack_start(&renderer, true);
column.set_title("Modification Date");
column.set_resizable(true); column.set_resizable(true);
column.set_min_width(50); column.set_min_width(50);
column.add_attribute(&renderer, "text", ColumnsBrokenFiles::Modification as i32); column.add_attribute(&renderer, "text", column_id);
column.set_sort_column_id(ColumnsBrokenFiles::ModificationAsSecs as i32); 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); tree_view.append_column(&column);
(renderer, column)
tree_view.set_vexpand(true);
} }

@ -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 { pub fn get_notebook_upper_enum_from_tree_view(tree_view: &TreeView) -> NotebookUpperEnum {
match (*tree_view).widget_name().to_string().as_str() { match (*tree_view).widget_name().to_string().as_str() {
"tree_view_upper_included_directories" => NotebookUpperEnum::IncludedDirectories, "tree_view_upper_included_directories" => NotebookUpperEnum::IncludedDirectories,
"tree_view_upper_excluded_directories" => NotebookUpperEnum::ExcludedDirectories, "tree_view_upper_excluded_directories" => NotebookUpperEnum::ExcludedDirectories,
e => { e => panic!("{}", 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)] #[cfg(test)]
mod test { mod test {
use glib::types::Type; use glib::types::Type;
use glib::Value;
use gtk4::prelude::*; use gtk4::prelude::*;
use gtk4::Orientation; use gtk4::{Orientation, TreeView};
use image::DynamicImage; use image::DynamicImage;
use crate::help_functions::{ 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, 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::<Value>::into(true)), (1, &Into::<Value>::into("test"))],
&[(0, &Into::<Value>::into(true)), (1, &Into::<Value>::into("test2"))],
&[(0, &Into::<Value>::into(false)), (1, &Into::<Value>::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] #[gtk4::test]
fn test_check_if_list_store_column_have_all_same_values() { fn test_check_if_list_store_column_have_all_same_values() {
let columns_types: &[Type] = &[Type::BOOL]; let columns_types: &[Type] = &[Type::BOOL];

@ -6,7 +6,7 @@ use gdk4::gdk_pixbuf::Pixbuf;
use glib::types::Type; use glib::types::Type;
use gtk4::gdk_pixbuf::InterpType; use gtk4::gdk_pixbuf::InterpType;
use gtk4::prelude::*; use gtk4::prelude::*;
use gtk4::{CheckButton, Image, SelectionMode, TextView, TreeView}; use gtk4::{CheckButton, Image, ScrolledWindow, SelectionMode, TextView, TreeModel, TreePath, TreeSelection, TreeView};
#[cfg(feature = "heif")] #[cfg(feature = "heif")]
use czkawka_core::common::get_dynamic_image_from_heic; use czkawka_core::common::get_dynamic_image_from_heic;
@ -24,7 +24,7 @@ use crate::help_combo_box::{
use crate::help_functions::*; use crate::help_functions::*;
use crate::language_functions::LANGUAGES_ALL; use crate::language_functions::LANGUAGES_ALL;
use crate::localizer_core::generate_translation_hashmap; 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::notebook_info::NOTEBOOKS_INFO;
use crate::opening_selecting_records::*; use crate::opening_selecting_records::*;
@ -91,208 +91,104 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
// Set step increment // Set step increment
{ {
let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); 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_set_min_max_values(&scale_similarity_similar_images, 0_f64, SIMILAR_VALUES[0][5] as f64, 15_f64, Some(1_f64));
scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[0][5] as f64);
scale_similarity_similar_images.adjustment().set_step_increment(1_f64);
} }
// Set step increment // Set step increment
{ {
let scale_similarity_similar_videos = gui_data.main_notebook.scale_similarity_similar_videos.clone(); 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_set_min_max_values(&scale_similarity_similar_videos, 0_f64, MAX_TOLERANCE as f64, 15_f64, Some(1_f64));
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);
} }
// Set Main Scrolled Window Treeviews // Set Main Scrolled Window Treeviews
{ {
// Duplicate Files create_column_types(
{ &gui_data.main_notebook.scrolled_window_duplicate_finder,
let scrolled_window = gui_data.main_notebook.scrolled_window_duplicate_finder.clone(); &gui_data.main_notebook.tree_view_duplicate_finder,
let tree_view = gui_data.main_notebook.tree_view_duplicate_finder.clone(); NotebookMainEnum::Duplicate,
Some(select_function_duplicates),
let image_preview = gui_data.main_notebook.image_preview_duplicates.clone(); create_tree_view_duplicates,
image_preview.hide(); Some(&gui_data.main_notebook.image_preview_duplicates),
);
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Duplicate as usize].columns_types); create_column_types(
&gui_data.main_notebook.scrolled_window_similar_images_finder,
tree_view.set_model(Some(&list_store)); &gui_data.main_notebook.tree_view_similar_images_finder,
tree_view.selection().set_mode(SelectionMode::Multiple); NotebookMainEnum::SimilarImages,
tree_view.selection().set_select_function(select_function_duplicates); Some(select_function_similar_images),
create_tree_view_similar_images,
create_tree_view_duplicates(&tree_view); Some(&gui_data.main_notebook.image_preview_similar_images),
);
tree_view.set_widget_name("tree_view_duplicate_finder"); create_column_types(
scrolled_window.set_child(Some(&tree_view)); &gui_data.main_notebook.scrolled_window_similar_videos_finder,
scrolled_window.show(); &gui_data.main_notebook.tree_view_similar_videos_finder,
} NotebookMainEnum::SimilarVideos,
// Empty Folders Some(select_function_similar_videos),
{ create_tree_view_similar_videos,
let scrolled_window = gui_data.main_notebook.scrolled_window_empty_folder_finder.clone(); None,
let tree_view = gui_data.main_notebook.tree_view_empty_folder_finder.clone(); );
create_column_types(
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::EmptyDirectories as usize].columns_types); &gui_data.main_notebook.scrolled_window_same_music_finder,
&gui_data.main_notebook.tree_view_same_music_finder,
tree_view.set_model(Some(&list_store)); NotebookMainEnum::SameMusic,
tree_view.selection().set_mode(SelectionMode::Multiple); Some(select_function_same_music),
create_tree_view_same_music,
create_tree_view_empty_folders(&tree_view); None,
);
tree_view.set_widget_name("tree_view_empty_folder_finder"); create_column_types(
&gui_data.main_notebook.scrolled_window_empty_folder_finder,
scrolled_window.set_child(Some(&tree_view)); &gui_data.main_notebook.tree_view_empty_folder_finder,
scrolled_window.show(); NotebookMainEnum::EmptyDirectories,
} None,
// Empty Files create_tree_view_empty_folders,
{ None,
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(); create_column_types(
&gui_data.main_notebook.scrolled_window_empty_files_finder,
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::EmptyFiles as usize].columns_types); &gui_data.main_notebook.tree_view_empty_files_finder,
NotebookMainEnum::EmptyFiles,
tree_view.set_model(Some(&list_store)); None,
tree_view.selection().set_mode(SelectionMode::Multiple); create_tree_view_empty_files,
None,
create_tree_view_empty_files(&tree_view); );
create_column_types(
tree_view.set_widget_name("tree_view_empty_files_finder"); &gui_data.main_notebook.scrolled_window_temporary_files_finder,
scrolled_window.set_child(Some(&tree_view)); &gui_data.main_notebook.tree_view_temporary_files_finder,
scrolled_window.show(); NotebookMainEnum::Temporary,
} None,
// Temporary Files create_tree_view_temporary_files,
{ None,
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(); create_column_types(
&gui_data.main_notebook.scrolled_window_big_files_finder,
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Temporary as usize].columns_types); &gui_data.main_notebook.tree_view_big_files_finder,
NotebookMainEnum::BigFiles,
tree_view.set_model(Some(&list_store)); None,
tree_view.selection().set_mode(SelectionMode::Multiple); create_tree_view_big_files,
None,
create_tree_view_temporary_files(&tree_view); );
create_column_types(
tree_view.set_widget_name("tree_view_temporary_files_finder"); &gui_data.main_notebook.scrolled_window_invalid_symlinks,
scrolled_window.set_child(Some(&tree_view)); &gui_data.main_notebook.tree_view_invalid_symlinks,
scrolled_window.show(); NotebookMainEnum::Symlinks,
} None,
// Big Files create_tree_view_invalid_symlinks,
{ None,
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(); create_column_types(
&gui_data.main_notebook.scrolled_window_broken_files,
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BigFiles as usize].columns_types); &gui_data.main_notebook.tree_view_broken_files,
NotebookMainEnum::BrokenFiles,
tree_view.set_model(Some(&list_store)); None,
tree_view.selection().set_mode(SelectionMode::Multiple); create_tree_view_broken_files,
None,
create_tree_view_big_files(&tree_view); );
create_column_types(
tree_view.set_widget_name("tree_view_big_files_finder"); &gui_data.main_notebook.scrolled_window_bad_extensions,
scrolled_window.set_child(Some(&tree_view)); &gui_data.main_notebook.tree_view_bad_extensions,
scrolled_window.show(); NotebookMainEnum::BadExtensions,
} None,
// Similar Images create_tree_view_bad_extensions,
{ None,
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();
}
} }
} }
@ -316,7 +212,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
create_tree_view_included_directories(&tree_view); 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.set_child(Some(&tree_view));
scrolled_window.show(); scrolled_window.show();
@ -350,7 +246,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
create_tree_view_excluded_directories(&tree_view); 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.set_child(Some(&tree_view));
scrolled_window.show(); scrolled_window.show();
@ -387,6 +283,32 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
connect_event_mouse(gui_data); connect_event_mouse(gui_data);
} }
fn create_column_types(
scrolled_window: &ScrolledWindow,
tree_view: &TreeView,
notebook_enum: NotebookMainEnum,
select_function: Option<fn(&TreeSelection, &TreeModel, &TreePath, bool) -> 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) { fn connect_event_mouse(gui_data: &GuiData) {
// GTK 4 // GTK 4
for gc in [ for gc in [

@ -84,17 +84,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) {
let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
// Futures progress report // Futures progress report
let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded(); let (progress_sender, progress_receiver): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_empty_files, futures_receiver_empty_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_empty_folder, futures_receiver_empty_folder): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_big_file, futures_receiver_big_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_same_music, futures_receiver_same_music): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_similar_images, futures_receiver_similar_images): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_similar_videos, futures_receiver_similar_videos): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_temporary, futures_receiver_temporary): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_broken_files, futures_receiver_broken_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_bad_extensions, futures_receiver_bad_extensions): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
initialize_gui(&mut gui_data); initialize_gui(&mut gui_data);
validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup 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_delete(&gui_data);
connect_button_save(&gui_data); connect_button_save(&gui_data);
connect_button_search( connect_button_search(&gui_data, glib_stop_sender, progress_sender);
&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_select(&gui_data); connect_button_select(&gui_data);
connect_button_sort(&gui_data); connect_button_sort(&gui_data);
connect_button_stop(&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_select(&gui_data);
connect_popover_sort(&gui_data); connect_popover_sort(&gui_data);
connect_compute_results(&gui_data, glib_stop_receiver); connect_compute_results(&gui_data, glib_stop_receiver);
connect_progress_window( connect_progress_window(&gui_data, progress_receiver);
&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_show_hide_ui(&gui_data); connect_show_hide_ui(&gui_data);
connect_settings(&gui_data); connect_settings(&gui_data);
connect_button_about(&gui_data); connect_button_about(&gui_data);

Loading…
Cancel
Save