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 12 months 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)]
pub struct DuplicatesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -163,6 +165,8 @@ pub struct DuplicatesArgs {
#[derive(Debug, clap::Args)]
pub struct EmptyFoldersArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -180,6 +184,8 @@ pub struct EmptyFoldersArgs {
#[derive(Debug, clap::Args)]
pub struct BiggestFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -205,6 +211,8 @@ pub struct BiggestFilesArgs {
#[derive(Debug, clap::Args)]
pub struct EmptyFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -226,6 +234,8 @@ pub struct EmptyFilesArgs {
#[derive(Debug, clap::Args)]
pub struct TemporaryArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -245,6 +255,8 @@ pub struct TemporaryArgs {
#[derive(Debug, clap::Args)]
pub struct SimilarImagesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -313,6 +325,8 @@ pub struct SimilarImagesArgs {
#[derive(Debug, clap::Args)]
pub struct SameMusicArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -359,6 +373,8 @@ pub struct SameMusicArgs {
#[derive(Debug, clap::Args)]
pub struct InvalidSymlinksArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -380,6 +396,8 @@ pub struct InvalidSymlinksArgs {
#[derive(Debug, clap::Args)]
pub struct BrokenFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -401,6 +419,8 @@ pub struct BrokenFilesArgs {
#[derive(Debug, clap::Args)]
pub struct SimilarVideosArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -449,6 +469,8 @@ pub struct SimilarVideosArgs {
#[derive(Debug, clap::Args)]
pub struct BadExtensionsArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
@ -517,6 +539,12 @@ pub struct NotRecursive {
pub not_recursive: bool,
}
#[derive(Debug, clap::Args)]
pub struct ThreadNumber {
#[clap(short = 'T', long, default_value = "0", help = "Limits thread number, 0(default) will use all available threads")]
pub thread_number: usize,
}
#[cfg(target_family = "unix")]
#[derive(Debug, clap::Args)]
pub struct ExcludeOtherFilesystems {

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

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

@ -14,7 +14,7 @@ use humansize::BINARY;
use rayon::prelude::*;
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, split_path};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -55,6 +55,7 @@ impl Info {
/// Struct with required information's to work
pub struct BigFile {
tool_type: ToolType,
text_messages: Messages,
information: Info,
big_files: Vec<(u64, FileEntry)>,
@ -72,6 +73,7 @@ impl BigFile {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::BigFile,
text_messages: Default::default(),
information: Info::new(),
big_files: Default::default(),
@ -148,7 +150,8 @@ impl BigFile {
folders_to_check.push(id.clone());
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None);
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None, self.tool_type);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {

@ -21,7 +21,7 @@ use crate::common::{
check_folder_children, create_crash_message, open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, PDF_FILES_EXTENSIONS,
};
use crate::common::{AUDIO_FILES_EXTENSIONS, IMAGE_RS_BROKEN_FILES_EXTENSIONS, ZIP_FILES_EXTENSIONS};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -78,6 +78,7 @@ impl Info {
}
pub struct BrokenFiles {
tool_type: ToolType,
text_messages: Messages,
information: Info,
files_to_check: BTreeMap<String, FileEntry>,
@ -99,6 +100,7 @@ impl BrokenFiles {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::BrokenFiles,
text_messages: Messages::new(),
information: Info::new(),
recursive_search: true,
@ -200,7 +202,8 @@ impl BrokenFiles {
folders_to_check.push(id.clone());
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None);
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None, self.tool_type);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -436,7 +439,7 @@ impl BrokenFiles {
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None);
prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None, self.tool_type);
let mut vec_file_entry: Vec<FileEntry> = non_cached_files_to_check
.into_par_iter()

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

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

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

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

@ -7,7 +7,7 @@ use std::path::PathBuf;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData};
use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
@ -15,6 +15,8 @@ use crate::common_traits::{DebugPrint, PrintResults, SaveResults};
/// Struct to store most basics info about all folder
pub struct EmptyFolder {
#[allow(dead_code)]
tool_type: ToolType,
information: Info,
delete_folders: bool,
text_messages: Messages,
@ -43,6 +45,7 @@ impl EmptyFolder {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::EmptyFolders,
information: Default::default(),
delete_folders: false,
text_messages: Messages::new(),

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

@ -25,7 +25,7 @@ use symphonia::core::probe::Hint;
use crate::common::{create_crash_message, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, AUDIO_FILES_EXTENSIONS};
use crate::common::{filter_reference_folders_generic, open_cache_folder};
use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData};
use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -108,6 +108,7 @@ impl Info {
/// Struct with required information's to work
pub struct SameMusic {
tool_type: ToolType,
text_messages: Messages,
information: Info,
music_to_check: HashMap<String, MusicEntry>,
@ -138,6 +139,7 @@ impl SameMusic {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::SameMusic,
text_messages: Messages::new(),
information: Info::new(),
recursive_search: true,
@ -415,7 +417,7 @@ impl SameMusic {
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache(false);
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) =
prepare_thread_handler_common(progress_sender, 1, 3, non_cached_files_to_check.len(), self.check_type);
prepare_thread_handler_common(progress_sender, 1, 3, non_cached_files_to_check.len(), self.check_type, self.tool_type);
let configuration = &self.hash_preset_config;
// Clean for duplicate files
@ -461,7 +463,7 @@ impl SameMusic {
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache(true);
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) =
prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), self.check_type);
prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), self.check_type, self.tool_type);
// Clean for duplicate files
let mut vec_file_entry = non_cached_files_to_check
@ -502,7 +504,7 @@ impl SameMusic {
fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 2, 2, self.music_to_check.len(), self.check_type);
prepare_thread_handler_common(progress_sender, 2, 2, self.music_to_check.len(), self.check_type, self.tool_type);
let mut old_duplicates: Vec<Vec<MusicEntry>> = vec![self.music_entries.clone()];
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 {
let groups_to_check = max(self.duplicated_music_entries.len(), self.duplicated_music_entries_referenced.len());
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) =
prepare_thread_handler_common(progress_sender, 3, 3, groups_to_check, self.check_type);
prepare_thread_handler_common(progress_sender, 3, 3, groups_to_check, self.check_type, self.tool_type);
// TODO is ther a way to just run iterator and not collect any info?
if !self.duplicated_music_entries.is_empty() {
@ -726,7 +728,7 @@ impl SameMusic {
fn check_for_duplicate_fingerprints(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let (base_files, files_to_compare) = self.split_fingerprints_to_check();
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 2, 3, base_files.len(), self.check_type);
prepare_thread_handler_common(progress_sender, 2, 3, base_files.len(), self.check_type, self.tool_type);
let Some(duplicated_music_entries) = self.compare_fingerprints(stop_receiver, &atomic_counter, base_files, &files_to_compare) else {
send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle);

@ -25,7 +25,7 @@ use crate::common::{
check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, prepare_thread_handler_common,
send_info_and_wait_for_ending_all_threads, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS,
};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -85,6 +85,7 @@ impl bk_tree::Metric<ImHash> for Hamming {
/// Struct to store most basics info about all folder
pub struct SimilarImages {
tool_type: ToolType,
information: Info,
text_messages: Messages,
directories: Directories,
@ -131,6 +132,7 @@ impl SimilarImages {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::SimilarImages,
information: Default::default(),
text_messages: Messages::new(),
directories: Directories::new(),
@ -300,7 +302,8 @@ impl SimilarImages {
folders_to_check.push(id.clone());
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 2, 0, CheckingMethod::None);
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 0, 2, 0, CheckingMethod::None, self.tool_type);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -435,7 +438,7 @@ impl SimilarImages {
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.hash_images_load_cache();
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) =
prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), CheckingMethod::None);
prepare_thread_handler_common(progress_sender, 1, 2, non_cached_files_to_check.len(), CheckingMethod::None, self.tool_type);
let mut vec_file_entry: Vec<(FileEntry, ImHash)> = non_cached_files_to_check
.into_par_iter()
@ -816,7 +819,7 @@ impl SimilarImages {
}
} else {
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) =
prepare_thread_handler_common(progress_sender, 2, 2, all_hashes.len(), CheckingMethod::None);
prepare_thread_handler_common(progress_sender, 2, 2, all_hashes.len(), CheckingMethod::None, self.tool_type);
// Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes

@ -18,7 +18,7 @@ use vid_dup_finder_lib::{NormalizedTolerance, VideoHash};
use crate::common::open_cache_folder;
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, VIDEO_FILES_EXTENSIONS};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -60,6 +60,7 @@ impl bk_tree::Metric<Vec<u8>> for Hamming {
/// Struct to store most basics info about all folder
pub struct SimilarVideos {
tool_type: ToolType,
information: Info,
text_messages: Messages,
directories: Directories,
@ -101,6 +102,7 @@ impl SimilarVideos {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::SimilarVideos,
information: Default::default(),
text_messages: Messages::new(),
directories: Directories::new(),
@ -261,7 +263,8 @@ impl SimilarVideos {
folders_to_check.push(id.clone());
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None);
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 0, 1, 0, CheckingMethod::None, self.tool_type);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -390,7 +393,7 @@ impl SimilarVideos {
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache_at_start();
let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) =
prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None);
prepare_thread_handler_common(progress_sender, 1, 1, non_cached_files_to_check.len(), CheckingMethod::None, self.tool_type);
let mut vec_file_entry: Vec<FileEntry> = non_cached_files_to_check
.par_iter()

@ -11,7 +11,7 @@ use futures::channel::mpsc::UnboundedSender;
use rayon::prelude::*;
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
@ -60,6 +60,7 @@ impl Info {
/// Struct with required information's to work
pub struct Temporary {
tool_type: ToolType,
text_messages: Messages,
information: Info,
temporary_files: Vec<FileEntry>,
@ -74,6 +75,7 @@ impl Temporary {
#[must_use]
pub fn new() -> Self {
Self {
tool_type: ToolType::TemporaryFiles,
text_messages: Messages::new(),
information: Info::new(),
recursive_search: true,
@ -149,7 +151,8 @@ impl Temporary {
folders_to_check.push(id.clone());
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None);
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None, self.tool_type);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {

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

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

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

@ -378,14 +378,34 @@ pub fn get_notebook_enum_from_tree_view(tree_view: &TreeView) -> NotebookMainEnu
}
}
}
pub fn get_tree_view_name_from_notebook_enum(notebook_enum: NotebookMainEnum) -> &'static str {
match notebook_enum {
NotebookMainEnum::Duplicate => "tree_view_duplicate_finder",
NotebookMainEnum::EmptyDirectories => "tree_view_empty_folder_finder",
NotebookMainEnum::EmptyFiles => "tree_view_empty_files_finder",
NotebookMainEnum::Temporary => "tree_view_temporary_files_finder",
NotebookMainEnum::BigFiles => "tree_view_big_files_finder",
NotebookMainEnum::SimilarImages => "tree_view_similar_images_finder",
NotebookMainEnum::SimilarVideos => "tree_view_similar_videos_finder",
NotebookMainEnum::SameMusic => "tree_view_same_music_finder",
NotebookMainEnum::Symlinks => "tree_view_invalid_symlinks",
NotebookMainEnum::BrokenFiles => "tree_view_broken_files",
NotebookMainEnum::BadExtensions => "tree_view_bad_extensions",
}
}
pub fn get_notebook_upper_enum_from_tree_view(tree_view: &TreeView) -> NotebookUpperEnum {
match (*tree_view).widget_name().to_string().as_str() {
"tree_view_upper_included_directories" => NotebookUpperEnum::IncludedDirectories,
"tree_view_upper_excluded_directories" => NotebookUpperEnum::ExcludedDirectories,
e => {
panic!("{}", e)
}
e => panic!("{}", e),
}
}
pub fn get_tree_view_name_from_notebook_upper_enum(notebook_upper_enum: NotebookUpperEnum) -> &'static str {
match notebook_upper_enum {
NotebookUpperEnum::IncludedDirectories => "tree_view_upper_included_directories",
NotebookUpperEnum::ExcludedDirectories => "tree_view_upper_excluded_directories",
_ => panic!(),
}
}
@ -789,15 +809,46 @@ pub fn scale_step_function(scale: &Scale, _scroll_type: ScrollType, value: f64)
#[cfg(test)]
mod test {
use glib::types::Type;
use glib::Value;
use gtk4::prelude::*;
use gtk4::Orientation;
use gtk4::{Orientation, TreeView};
use image::DynamicImage;
use crate::help_functions::{
change_dimension_to_krotka, check_if_list_store_column_have_all_same_values, check_if_value_is_in_list_store, get_all_boxes_from_widget, get_all_direct_children,
get_max_file_name, get_pixbuf_from_dynamic_image,
get_max_file_name, get_pixbuf_from_dynamic_image, get_string_from_list_store,
};
#[gtk4::test]
fn test_get_string_from_list_store() {
let columns_types: &[Type] = &[Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let tree_view = TreeView::with_model(&list_store);
let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &"test"), (0, &"test2"), (0, &"test3")];
for i in values_to_add {
list_store.set(&list_store.append(), &[*i]);
}
assert_eq!(
get_string_from_list_store(&tree_view, 0, None),
vec!["test".to_string(), "test2".to_string(), "test3".to_string()]
);
let columns_types: &[Type] = &[Type::BOOL, Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let tree_view = TreeView::with_model(&list_store);
let values_to_add: &[&[(u32, &dyn ToValue)]] = &[
&[(0, &Into::<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]
fn test_check_if_list_store_column_have_all_same_values() {
let columns_types: &[Type] = &[Type::BOOL];

@ -6,7 +6,7 @@ use gdk4::gdk_pixbuf::Pixbuf;
use glib::types::Type;
use gtk4::gdk_pixbuf::InterpType;
use gtk4::prelude::*;
use gtk4::{CheckButton, Image, SelectionMode, TextView, TreeView};
use gtk4::{CheckButton, Image, ScrolledWindow, SelectionMode, TextView, TreeModel, TreePath, TreeSelection, TreeView};
#[cfg(feature = "heif")]
use czkawka_core::common::get_dynamic_image_from_heic;
@ -24,7 +24,7 @@ use crate::help_combo_box::{
use crate::help_functions::*;
use crate::language_functions::LANGUAGES_ALL;
use crate::localizer_core::generate_translation_hashmap;
use crate::notebook_enums::NotebookMainEnum;
use crate::notebook_enums::{NotebookMainEnum, NotebookUpperEnum};
use crate::notebook_info::NOTEBOOKS_INFO;
use crate::opening_selecting_records::*;
@ -91,208 +91,104 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
// Set step increment
{
let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone();
scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[0][5] as f64); // This defaults to value of minimal size of hash 8
scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[0][5] as f64);
scale_similarity_similar_images.adjustment().set_step_increment(1_f64);
scale_set_min_max_values(&scale_similarity_similar_images, 0_f64, SIMILAR_VALUES[0][5] as f64, 15_f64, Some(1_f64));
}
// Set step increment
{
let scale_similarity_similar_videos = gui_data.main_notebook.scale_similarity_similar_videos.clone();
scale_similarity_similar_videos.set_range(0_f64, MAX_TOLERANCE as f64); // This defaults to value of minimal size of hash 8
scale_similarity_similar_videos.set_value(15_f64);
scale_similarity_similar_videos.set_fill_level(MAX_TOLERANCE as f64);
scale_similarity_similar_videos.adjustment().set_step_increment(1_f64);
scale_set_min_max_values(&scale_similarity_similar_videos, 0_f64, MAX_TOLERANCE as f64, 15_f64, Some(1_f64));
}
// Set Main Scrolled Window Treeviews
{
// Duplicate Files
{
let scrolled_window = gui_data.main_notebook.scrolled_window_duplicate_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_duplicate_finder.clone();
let image_preview = gui_data.main_notebook.image_preview_duplicates.clone();
image_preview.hide();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Duplicate as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
tree_view.selection().set_select_function(select_function_duplicates);
create_tree_view_duplicates(&tree_view);
tree_view.set_widget_name("tree_view_duplicate_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Empty Folders
{
let scrolled_window = gui_data.main_notebook.scrolled_window_empty_folder_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_empty_folder_finder.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::EmptyDirectories as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_empty_folders(&tree_view);
tree_view.set_widget_name("tree_view_empty_folder_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Empty Files
{
let scrolled_window = gui_data.main_notebook.scrolled_window_empty_files_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_empty_files_finder.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::EmptyFiles as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_empty_files(&tree_view);
tree_view.set_widget_name("tree_view_empty_files_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Temporary Files
{
let scrolled_window = gui_data.main_notebook.scrolled_window_temporary_files_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_temporary_files_finder.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Temporary as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_temporary_files(&tree_view);
tree_view.set_widget_name("tree_view_temporary_files_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Big Files
{
let scrolled_window = gui_data.main_notebook.scrolled_window_big_files_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_big_files_finder.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BigFiles as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_big_files(&tree_view);
tree_view.set_widget_name("tree_view_big_files_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Similar Images
{
let scrolled_window = gui_data.main_notebook.scrolled_window_similar_images_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_similar_images_finder.clone();
let image_preview = gui_data.main_notebook.image_preview_similar_images.clone();
image_preview.hide();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::SimilarImages as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
tree_view.selection().set_select_function(select_function_similar_images);
create_tree_view_similar_images(&tree_view);
tree_view.set_widget_name("tree_view_similar_images_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Similar Videos
{
let scrolled_window = gui_data.main_notebook.scrolled_window_similar_videos_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_similar_videos_finder.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::SimilarVideos as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
tree_view.selection().set_select_function(select_function_similar_videos);
create_tree_view_similar_videos(&tree_view);
tree_view.set_widget_name("tree_view_similar_videos_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Same Music
{
let scrolled_window = gui_data.main_notebook.scrolled_window_same_music_finder.clone();
let tree_view = gui_data.main_notebook.tree_view_same_music_finder.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::SameMusic as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
tree_view.selection().set_select_function(select_function_same_music);
create_tree_view_same_music(&tree_view);
tree_view.set_widget_name("tree_view_same_music_finder");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Invalid Symlinks
{
let scrolled_window = gui_data.main_notebook.scrolled_window_invalid_symlinks.clone();
let tree_view = gui_data.main_notebook.tree_view_invalid_symlinks.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::Symlinks as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_invalid_symlinks(&tree_view);
tree_view.set_widget_name("tree_view_invalid_symlinks");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Broken Files
{
let scrolled_window = gui_data.main_notebook.scrolled_window_broken_files.clone();
let tree_view = gui_data.main_notebook.tree_view_broken_files.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BrokenFiles as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_broken_files(&tree_view);
tree_view.set_widget_name("tree_view_broken_files");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
// Bad Extensions
{
let scrolled_window = gui_data.main_notebook.scrolled_window_bad_extensions.clone();
let tree_view = gui_data.main_notebook.tree_view_bad_extensions.clone();
let list_store: gtk4::ListStore = gtk4::ListStore::new(NOTEBOOKS_INFO[NotebookMainEnum::BadExtensions as usize].columns_types);
tree_view.set_model(Some(&list_store));
tree_view.selection().set_mode(SelectionMode::Multiple);
create_tree_view_broken_files(&tree_view);
tree_view.set_widget_name("tree_view_bad_extensions");
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
}
create_column_types(
&gui_data.main_notebook.scrolled_window_duplicate_finder,
&gui_data.main_notebook.tree_view_duplicate_finder,
NotebookMainEnum::Duplicate,
Some(select_function_duplicates),
create_tree_view_duplicates,
Some(&gui_data.main_notebook.image_preview_duplicates),
);
create_column_types(
&gui_data.main_notebook.scrolled_window_similar_images_finder,
&gui_data.main_notebook.tree_view_similar_images_finder,
NotebookMainEnum::SimilarImages,
Some(select_function_similar_images),
create_tree_view_similar_images,
Some(&gui_data.main_notebook.image_preview_similar_images),
);
create_column_types(
&gui_data.main_notebook.scrolled_window_similar_videos_finder,
&gui_data.main_notebook.tree_view_similar_videos_finder,
NotebookMainEnum::SimilarVideos,
Some(select_function_similar_videos),
create_tree_view_similar_videos,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_same_music_finder,
&gui_data.main_notebook.tree_view_same_music_finder,
NotebookMainEnum::SameMusic,
Some(select_function_same_music),
create_tree_view_same_music,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_empty_folder_finder,
&gui_data.main_notebook.tree_view_empty_folder_finder,
NotebookMainEnum::EmptyDirectories,
None,
create_tree_view_empty_folders,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_empty_files_finder,
&gui_data.main_notebook.tree_view_empty_files_finder,
NotebookMainEnum::EmptyFiles,
None,
create_tree_view_empty_files,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_temporary_files_finder,
&gui_data.main_notebook.tree_view_temporary_files_finder,
NotebookMainEnum::Temporary,
None,
create_tree_view_temporary_files,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_big_files_finder,
&gui_data.main_notebook.tree_view_big_files_finder,
NotebookMainEnum::BigFiles,
None,
create_tree_view_big_files,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_invalid_symlinks,
&gui_data.main_notebook.tree_view_invalid_symlinks,
NotebookMainEnum::Symlinks,
None,
create_tree_view_invalid_symlinks,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_broken_files,
&gui_data.main_notebook.tree_view_broken_files,
NotebookMainEnum::BrokenFiles,
None,
create_tree_view_broken_files,
None,
);
create_column_types(
&gui_data.main_notebook.scrolled_window_bad_extensions,
&gui_data.main_notebook.tree_view_bad_extensions,
NotebookMainEnum::BadExtensions,
None,
create_tree_view_bad_extensions,
None,
);
}
}
@ -316,7 +212,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
create_tree_view_included_directories(&tree_view);
tree_view.set_widget_name("tree_view_upper_included_directories");
tree_view.set_widget_name(get_tree_view_name_from_notebook_upper_enum(NotebookUpperEnum::IncludedDirectories));
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
@ -350,7 +246,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
create_tree_view_excluded_directories(&tree_view);
tree_view.set_widget_name("tree_view_upper_excluded_directories");
tree_view.set_widget_name(get_tree_view_name_from_notebook_upper_enum(NotebookUpperEnum::ExcludedDirectories));
scrolled_window.set_child(Some(&tree_view));
scrolled_window.show();
@ -387,6 +283,32 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
connect_event_mouse(gui_data);
}
fn create_column_types(
scrolled_window: &ScrolledWindow,
tree_view: &TreeView,
notebook_enum: NotebookMainEnum,
select_function: Option<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) {
// GTK 4
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);
// Futures progress report
let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (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();
let (progress_sender, progress_receiver): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
initialize_gui(&mut gui_data);
validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup
@ -117,21 +107,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) {
connect_button_delete(&gui_data);
connect_button_save(&gui_data);
connect_button_search(
&gui_data,
glib_stop_sender,
futures_sender_duplicate_files,
futures_sender_empty_files,
futures_sender_empty_folder,
futures_sender_big_file,
futures_sender_same_music,
futures_sender_similar_images,
futures_sender_similar_videos,
futures_sender_temporary,
futures_sender_invalid_symlinks,
futures_sender_broken_files,
futures_sender_bad_extensions,
);
connect_button_search(&gui_data, glib_stop_sender, progress_sender);
connect_button_select(&gui_data);
connect_button_sort(&gui_data);
connect_button_stop(&gui_data);
@ -145,20 +121,7 @@ fn build_ui(application: &Application, arguments: &[OsString]) {
connect_popover_select(&gui_data);
connect_popover_sort(&gui_data);
connect_compute_results(&gui_data, glib_stop_receiver);
connect_progress_window(
&gui_data,
futures_receiver_duplicate_files,
futures_receiver_empty_files,
futures_receiver_empty_folder,
futures_receiver_big_files,
futures_receiver_same_music,
futures_receiver_similar_images,
futures_receiver_similar_videos,
futures_receiver_temporary,
futures_receiver_invalid_symlinks,
futures_receiver_broken_files,
futures_receiver_bad_extensions,
);
connect_progress_window(&gui_data, progress_receiver);
connect_show_hide_ui(&gui_data);
connect_settings(&gui_data);
connect_button_about(&gui_data);

Loading…
Cancel
Save