Add support for checking for invalid symlinks (#124)
This commit is contained in:
parent
4a33ff7d86
commit
1d59199bb2
|
@ -147,6 +147,23 @@ pub enum Commands {
|
||||||
#[structopt(short, long, parse(try_from_str = parse_minimal_file_size), default_value = "1024", help = "Minimum size in bytes", long_help = "Minimum size of checked files in bytes, assigning bigger value may speed up searching")]
|
#[structopt(short, long, parse(try_from_str = parse_minimal_file_size), default_value = "1024", help = "Minimum size in bytes", long_help = "Minimum size of checked files in bytes, assigning bigger value may speed up searching")]
|
||||||
minimal_file_size: u64,
|
minimal_file_size: u64,
|
||||||
},
|
},
|
||||||
|
#[structopt(name = "symlinks", about = "Finds invalid symlinks", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka symlinks -d /home/kicikici/ /home/szczek -e /home/kicikici/jestempsem -x jpg -f results.txt")]
|
||||||
|
InvalidSymlinks {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
directories: Directories,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
excluded_directories: ExcludedDirectories,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
excluded_items: ExcludedItems,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
allowed_extensions: AllowedExtensions,
|
||||||
|
#[structopt(short = "D", long, help = "Delete found files")]
|
||||||
|
delete_files: bool,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
file_to_save: FileToSave,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
not_recursive: NotRecursive,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
|
@ -301,4 +318,5 @@ EXAMPLES:
|
||||||
{bin} temp -d /home/rafal/ -E */.git */tmp* *Pulpit -f results.txt -D
|
{bin} temp -d /home/rafal/ -E */.git */tmp* *Pulpit -f results.txt -D
|
||||||
{bin} image -d /home/rafal -e /home/rafal/Pulpit -f results.txt
|
{bin} image -d /home/rafal -e /home/rafal/Pulpit -f results.txt
|
||||||
{bin} zeroed -d /home/rafal -e /home/krzak -f results.txt"
|
{bin} zeroed -d /home/rafal -e /home/krzak -f results.txt"
|
||||||
{bin} music -d /home/rafal -e /home/rafal/Pulpit -z "artist,year, ARTISTALBUM, ALBUM___tiTlE" -f results.txt"#;
|
{bin} music -d /home/rafal -e /home/rafal/Pulpit -z "artist,year, ARTISTALBUM, ALBUM___tiTlE" -f results.txt
|
||||||
|
{bin} symlinks -d /home/kicikici/ /home/szczek -e /home/kicikici/jestempsem -x jpg -f results.txt"#;
|
||||||
|
|
|
@ -10,6 +10,8 @@ use czkawka_core::{
|
||||||
duplicate::DuplicateFinder,
|
duplicate::DuplicateFinder,
|
||||||
empty_files::{self, EmptyFiles},
|
empty_files::{self, EmptyFiles},
|
||||||
empty_folder::EmptyFolder,
|
empty_folder::EmptyFolder,
|
||||||
|
invalid_symlinks,
|
||||||
|
invalid_symlinks::InvalidSymlinks,
|
||||||
same_music::SameMusic,
|
same_music::SameMusic,
|
||||||
similar_images::SimilarImages,
|
similar_images::SimilarImages,
|
||||||
temporary::{self, Temporary},
|
temporary::{self, Temporary},
|
||||||
|
@ -296,5 +298,38 @@ fn main() {
|
||||||
mf.print_results();
|
mf.print_results();
|
||||||
mf.get_text_messages().print_messages();
|
mf.get_text_messages().print_messages();
|
||||||
}
|
}
|
||||||
|
Commands::InvalidSymlinks {
|
||||||
|
directories,
|
||||||
|
excluded_directories,
|
||||||
|
excluded_items,
|
||||||
|
allowed_extensions,
|
||||||
|
file_to_save,
|
||||||
|
not_recursive,
|
||||||
|
delete_files,
|
||||||
|
} => {
|
||||||
|
let mut ifs = InvalidSymlinks::new();
|
||||||
|
|
||||||
|
ifs.set_included_directory(path_list_to_str(directories.directories));
|
||||||
|
ifs.set_excluded_directory(path_list_to_str(excluded_directories.excluded_directories));
|
||||||
|
ifs.set_excluded_items(path_list_to_str(excluded_items.excluded_items));
|
||||||
|
ifs.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
|
||||||
|
ifs.set_recursive_search(!not_recursive.not_recursive);
|
||||||
|
if delete_files {
|
||||||
|
ifs.set_delete_method(invalid_symlinks::DeleteMethod::Delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifs.find_invalid_links(None, None);
|
||||||
|
|
||||||
|
if let Some(file_name) = file_to_save.file_name() {
|
||||||
|
if !ifs.save_results_to_file(file_name) {
|
||||||
|
ifs.get_text_messages().print_messages();
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))] // This will show too much probably unnecessary data to debug, comment line only if needed
|
||||||
|
ifs.print_results();
|
||||||
|
ifs.get_text_messages().print_messages();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
457
czkawka_core/src/invalid_symlinks.rs
Normal file
457
czkawka_core/src/invalid_symlinks.rs
Normal file
|
@ -0,0 +1,457 @@
|
||||||
|
use std::fs::{File, Metadata};
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
use std::{fs, thread};
|
||||||
|
|
||||||
|
use crate::common::Common;
|
||||||
|
use crate::common_directory::Directories;
|
||||||
|
use crate::common_extensions::Extensions;
|
||||||
|
use crate::common_items::ExcludedItems;
|
||||||
|
use crate::common_messages::Messages;
|
||||||
|
use crate::common_traits::*;
|
||||||
|
use crossbeam_channel::Receiver;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread::sleep;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ProgressData {
|
||||||
|
pub current_stage: u8,
|
||||||
|
pub max_stage: u8,
|
||||||
|
pub files_checked: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||||
|
pub enum DeleteMethod {
|
||||||
|
None,
|
||||||
|
Delete,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_NUMBER_OF_SYMLINK_JUMPS: i32 = 20;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ErrorType {
|
||||||
|
InfiniteRecursion,
|
||||||
|
NonExistentFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FileEntry {
|
||||||
|
pub symlink_path: PathBuf,
|
||||||
|
pub destination_path: PathBuf,
|
||||||
|
pub type_of_error: ErrorType,
|
||||||
|
pub modified_date: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Info struck with helpful information's about results
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Info {
|
||||||
|
pub number_of_checked_files: usize,
|
||||||
|
pub number_of_checked_folders: usize,
|
||||||
|
pub number_of_ignored_files: usize,
|
||||||
|
pub number_of_ignored_things: usize,
|
||||||
|
pub number_of_invalid_symlinks: usize,
|
||||||
|
pub number_of_removed_files: usize,
|
||||||
|
pub number_of_failed_to_remove_files: usize,
|
||||||
|
}
|
||||||
|
impl Info {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Struct with required information's to work
|
||||||
|
pub struct InvalidSymlinks {
|
||||||
|
text_messages: Messages,
|
||||||
|
information: Info,
|
||||||
|
invalid_symlinks: Vec<FileEntry>,
|
||||||
|
directories: Directories,
|
||||||
|
allowed_extensions: Extensions,
|
||||||
|
excluded_items: ExcludedItems,
|
||||||
|
recursive_search: bool,
|
||||||
|
delete_method: DeleteMethod,
|
||||||
|
stopped_search: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvalidSymlinks {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
text_messages: Messages::new(),
|
||||||
|
information: Info::new(),
|
||||||
|
recursive_search: true,
|
||||||
|
allowed_extensions: Extensions::new(),
|
||||||
|
directories: Directories::new(),
|
||||||
|
excluded_items: ExcludedItems::new(),
|
||||||
|
invalid_symlinks: vec![],
|
||||||
|
delete_method: DeleteMethod::None,
|
||||||
|
stopped_search: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_invalid_links(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::Sender<ProgressData>>) {
|
||||||
|
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
|
||||||
|
if !self.check_files(stop_receiver, progress_sender) {
|
||||||
|
self.stopped_search = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.delete_files();
|
||||||
|
self.debug_print();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_stopped_search(&self) -> bool {
|
||||||
|
self.stopped_search
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn get_invalid_symlinks(&self) -> &Vec<FileEntry> {
|
||||||
|
&self.invalid_symlinks
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn get_text_messages(&self) -> &Messages {
|
||||||
|
&self.text_messages
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn get_information(&self) -> &Info {
|
||||||
|
&self.information
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_delete_method(&mut self, delete_method: DeleteMethod) {
|
||||||
|
self.delete_method = delete_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_recursive_search(&mut self, recursive_search: bool) {
|
||||||
|
self.recursive_search = recursive_search;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_included_directory(&mut self, included_directory: String) -> bool {
|
||||||
|
self.directories.set_included_directory(included_directory, &mut self.text_messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_excluded_directory(&mut self, excluded_directory: String) {
|
||||||
|
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
||||||
|
}
|
||||||
|
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) {
|
||||||
|
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_excluded_items(&mut self, excluded_items: String) {
|
||||||
|
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check files for any with size == 0
|
||||||
|
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::Sender<ProgressData>>) -> bool {
|
||||||
|
let start_time: SystemTime = SystemTime::now();
|
||||||
|
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
|
||||||
|
|
||||||
|
// Add root folders for finding
|
||||||
|
for id in &self.directories.included_directories {
|
||||||
|
folders_to_check.push(id.clone());
|
||||||
|
}
|
||||||
|
self.information.number_of_checked_folders += folders_to_check.len();
|
||||||
|
|
||||||
|
//// PROGRESS THREAD START
|
||||||
|
const LOOP_DURATION: u32 = 200; //in ms
|
||||||
|
let progress_thread_run = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
let atomic_file_counter = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
|
let progress_thread_handle;
|
||||||
|
if let Some(progress_sender) = progress_sender {
|
||||||
|
let mut progress_send = progress_sender.clone();
|
||||||
|
let progress_thread_run = progress_thread_run.clone();
|
||||||
|
let atomic_file_counter = atomic_file_counter.clone();
|
||||||
|
progress_thread_handle = thread::spawn(move || loop {
|
||||||
|
progress_send
|
||||||
|
.try_send(ProgressData {
|
||||||
|
current_stage: 0,
|
||||||
|
max_stage: 0,
|
||||||
|
files_checked: atomic_file_counter.load(Ordering::Relaxed) as usize,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
if !progress_thread_run.load(Ordering::Relaxed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep(Duration::from_millis(LOOP_DURATION as u64));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
progress_thread_handle = thread::spawn(|| {});
|
||||||
|
}
|
||||||
|
//// PROGRESS THREAD END
|
||||||
|
|
||||||
|
while !folders_to_check.is_empty() {
|
||||||
|
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
|
||||||
|
// End thread which send info to gui
|
||||||
|
progress_thread_run.store(false, Ordering::Relaxed);
|
||||||
|
progress_thread_handle.join().unwrap();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let current_folder = folders_to_check.pop().unwrap();
|
||||||
|
|
||||||
|
// Read current dir, if permission are denied just go to next
|
||||||
|
let read_dir = match fs::read_dir(¤t_folder) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => {
|
||||||
|
self.text_messages.warnings.push(format!("Cannot open dir {}", current_folder.display()));
|
||||||
|
continue;
|
||||||
|
} // Permissions denied
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check every sub folder/file/link etc.
|
||||||
|
'dir: for entry in read_dir {
|
||||||
|
let entry_data = match entry {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => {
|
||||||
|
self.text_messages.warnings.push(format!("Cannot read entry in dir {}", current_folder.display()));
|
||||||
|
continue;
|
||||||
|
} //Permissions denied
|
||||||
|
};
|
||||||
|
let metadata: Metadata = match entry_data.metadata() {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => {
|
||||||
|
self.text_messages.warnings.push(format!("Cannot read metadata in dir {}", current_folder.display()));
|
||||||
|
continue;
|
||||||
|
} //Permissions denied
|
||||||
|
};
|
||||||
|
if metadata.is_dir() {
|
||||||
|
self.information.number_of_checked_folders += 1;
|
||||||
|
|
||||||
|
if !self.recursive_search {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_folder = current_folder.join(entry_data.file_name());
|
||||||
|
if self.directories.is_excluded(&next_folder) || self.excluded_items.is_excluded(&next_folder) {
|
||||||
|
continue 'dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
folders_to_check.push(next_folder);
|
||||||
|
} else if metadata.is_file() {
|
||||||
|
atomic_file_counter.fetch_add(1, Ordering::Relaxed);
|
||||||
|
} else if metadata.file_type().is_symlink() {
|
||||||
|
atomic_file_counter.fetch_add(1, Ordering::Relaxed);
|
||||||
|
let file_name_lowercase: String = match entry_data.file_name().into_string() {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => continue,
|
||||||
|
}
|
||||||
|
.to_lowercase();
|
||||||
|
|
||||||
|
// Checking allowed extensions
|
||||||
|
if !self.allowed_extensions.file_extensions.is_empty() {
|
||||||
|
let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str()));
|
||||||
|
if !allowed {
|
||||||
|
// Not an allowed extension, ignore it.
|
||||||
|
self.information.number_of_ignored_files += 1;
|
||||||
|
continue 'dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking files
|
||||||
|
let current_file_name = current_folder.join(entry_data.file_name());
|
||||||
|
if self.excluded_items.is_excluded(¤t_file_name) {
|
||||||
|
continue 'dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut destination_path = PathBuf::new();
|
||||||
|
let type_of_error;
|
||||||
|
|
||||||
|
match current_file_name.read_link() {
|
||||||
|
Ok(t) => {
|
||||||
|
destination_path.push(t);
|
||||||
|
let mut number_of_loop = 0;
|
||||||
|
let mut current_path = current_file_name.clone();
|
||||||
|
loop {
|
||||||
|
if number_of_loop == 0 && !current_path.exists() {
|
||||||
|
type_of_error = ErrorType::NonExistentFile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if number_of_loop == MAX_NUMBER_OF_SYMLINK_JUMPS {
|
||||||
|
type_of_error = ErrorType::InfiniteRecursion;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_path = match current_path.read_link() {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => {
|
||||||
|
// Looks that some next symlinks are broken, but we do nothing with it
|
||||||
|
continue 'dir;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
number_of_loop += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// Failed to load info about it
|
||||||
|
type_of_error = ErrorType::NonExistentFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating new file entry
|
||||||
|
let fe: FileEntry = FileEntry {
|
||||||
|
symlink_path: current_file_name.clone(),
|
||||||
|
destination_path,
|
||||||
|
type_of_error,
|
||||||
|
modified_date: match metadata.modified() {
|
||||||
|
Ok(t) => match t.duration_since(UNIX_EPOCH) {
|
||||||
|
Ok(d) => d.as_secs(),
|
||||||
|
Err(_) => {
|
||||||
|
self.text_messages.warnings.push(format!("File {} seems to be modified before Unix Epoch.", current_file_name.display()));
|
||||||
|
0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
self.text_messages.warnings.push(format!("Unable to get modification date from file {}", current_file_name.display()));
|
||||||
|
continue;
|
||||||
|
} // Permissions Denied
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Adding files to Vector
|
||||||
|
self.invalid_symlinks.push(fe);
|
||||||
|
|
||||||
|
self.information.number_of_checked_files += 1;
|
||||||
|
} else {
|
||||||
|
// Not sure what exactly this is
|
||||||
|
self.information.number_of_ignored_things += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.information.number_of_invalid_symlinks = self.invalid_symlinks.len();
|
||||||
|
// End thread which send info to gui
|
||||||
|
progress_thread_run.store(false, Ordering::Relaxed);
|
||||||
|
progress_thread_handle.join().unwrap();
|
||||||
|
|
||||||
|
Common::print_time(start_time, SystemTime::now(), "check_files_size".to_string());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function to delete files, from filed Vector
|
||||||
|
fn delete_files(&mut self) {
|
||||||
|
let start_time: SystemTime = SystemTime::now();
|
||||||
|
|
||||||
|
match self.delete_method {
|
||||||
|
DeleteMethod::Delete => {
|
||||||
|
for file_entry in &self.invalid_symlinks {
|
||||||
|
if fs::remove_file(file_entry.symlink_path.clone()).is_err() {
|
||||||
|
self.text_messages.warnings.push(file_entry.symlink_path.display().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeleteMethod::None => {
|
||||||
|
//Just do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::print_time(start_time, SystemTime::now(), "delete_files".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for InvalidSymlinks {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPrint for InvalidSymlinks {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
/// Debugging printing - only available on debug build
|
||||||
|
fn debug_print(&self) {
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!("---------------DEBUG PRINT---------------");
|
||||||
|
println!("### Information's");
|
||||||
|
|
||||||
|
println!("Errors size - {}", self.text_messages.errors.len());
|
||||||
|
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||||
|
println!("Messages size - {}", self.text_messages.messages.len());
|
||||||
|
println!("Number of checked files - {}", self.information.number_of_checked_files);
|
||||||
|
println!("Number of checked folders - {}", self.information.number_of_checked_folders);
|
||||||
|
println!("Number of ignored files - {}", self.information.number_of_ignored_files);
|
||||||
|
println!("Number of ignored things(like symbolic links) - {}", self.information.number_of_ignored_things);
|
||||||
|
println!("Number of removed files - {}", self.information.number_of_removed_files);
|
||||||
|
println!("Number of failed to remove files - {}", self.information.number_of_failed_to_remove_files);
|
||||||
|
|
||||||
|
println!("### Other");
|
||||||
|
|
||||||
|
println!("Invalid symlinks list size - {}", self.invalid_symlinks.len());
|
||||||
|
println!("Allowed extensions - {:?}", self.allowed_extensions.file_extensions);
|
||||||
|
println!("Excluded items - {:?}", self.excluded_items.items);
|
||||||
|
println!("Included directories - {:?}", self.directories.included_directories);
|
||||||
|
println!("Excluded directories - {:?}", self.directories.excluded_directories);
|
||||||
|
println!("Recursive search - {}", self.recursive_search.to_string());
|
||||||
|
println!("Delete Method - {:?}", self.delete_method);
|
||||||
|
println!("-----------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl SaveResults for InvalidSymlinks {
|
||||||
|
fn save_results_to_file(&mut self, file_name: &str) -> bool {
|
||||||
|
let start_time: SystemTime = SystemTime::now();
|
||||||
|
let file_name: String = match file_name {
|
||||||
|
"" => "results.txt".to_string(),
|
||||||
|
k => k.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut file = match File::create(&file_name) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => {
|
||||||
|
self.text_messages.errors.push(format!("Failed to create file {}", file_name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if writeln!(
|
||||||
|
file,
|
||||||
|
"Results of searching {:?} with excluded directories {:?} and excluded items {:?}",
|
||||||
|
self.directories.included_directories, self.directories.excluded_directories, self.excluded_items.items
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
self.text_messages.errors.push(format!("Failed to save results to file {}", file_name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.invalid_symlinks.is_empty() {
|
||||||
|
writeln!(file, "Found {} invalid symlinks.", self.information.number_of_invalid_symlinks).unwrap();
|
||||||
|
for file_entry in self.invalid_symlinks.iter() {
|
||||||
|
writeln!(
|
||||||
|
file,
|
||||||
|
"{}\t\t{}\t\t{}",
|
||||||
|
file_entry.symlink_path.display(),
|
||||||
|
file_entry.destination_path.display(),
|
||||||
|
match file_entry.type_of_error {
|
||||||
|
ErrorType::InfiniteRecursion => "Infinite Recursion",
|
||||||
|
ErrorType::NonExistentFile => "Non Existent File",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write!(file, "Not found any invalid symlinks.").unwrap();
|
||||||
|
}
|
||||||
|
Common::print_time(start_time, SystemTime::now(), "save_results_to_file".to_string());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PrintResults for InvalidSymlinks {
|
||||||
|
/// Print information's about duplicated entries
|
||||||
|
/// Only needed for CLI
|
||||||
|
fn print_results(&self) {
|
||||||
|
let start_time: SystemTime = SystemTime::now();
|
||||||
|
println!("Found {} invalid symlinks.\n", self.information.number_of_invalid_symlinks);
|
||||||
|
for file_entry in self.invalid_symlinks.iter() {
|
||||||
|
println!(
|
||||||
|
"{}\t\t{}\t\t{}",
|
||||||
|
file_entry.symlink_path.display(),
|
||||||
|
file_entry.destination_path.display(),
|
||||||
|
match file_entry.type_of_error {
|
||||||
|
ErrorType::InfiniteRecursion => "Infinite Recursion",
|
||||||
|
ErrorType::NonExistentFile => "Non Existent File",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::print_time(start_time, SystemTime::now(), "print_entries".to_string());
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ pub mod common_extensions;
|
||||||
pub mod common_items;
|
pub mod common_items;
|
||||||
pub mod common_messages;
|
pub mod common_messages;
|
||||||
pub mod common_traits;
|
pub mod common_traits;
|
||||||
|
pub mod invalid_symlinks;
|
||||||
pub mod same_music;
|
pub mod same_music;
|
||||||
pub mod similar_images;
|
pub mod similar_images;
|
||||||
pub mod zeroed;
|
pub mod zeroed;
|
||||||
|
|
|
@ -438,6 +438,66 @@ Author: Rafał Mikrut
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkPopover" id="popover_select_very_simple_list">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="buttons_popover_very_simple_list_select_all">
|
||||||
|
<property name="label" translatable="yes">Select All</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="buttons_popover_very_simple_list_unselect_all">
|
||||||
|
<property name="label" translatable="yes">Unselect All</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSeparator">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="buttons_popover_very_simple_list_reverse">
|
||||||
|
<property name="label" translatable="yes">Reverse Selection</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
<object class="GtkWindow" id="window_main">
|
<object class="GtkWindow" id="window_main">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="default_width">1100</property>
|
<property name="default_width">1100</property>
|
||||||
|
@ -1906,6 +1966,30 @@ Author: Rafał Mikrut
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolled_window_invalid_symlinks">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child type="tab">
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Invalid Symlinks</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">8</property>
|
||||||
|
<property name="tab_fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
|
|
|
@ -6,6 +6,8 @@ use std::collections::BTreeMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::Metadata;
|
use std::fs::Metadata;
|
||||||
|
|
||||||
|
// TODO add support for checking if really symlink doesn't point to correct directory/file
|
||||||
|
|
||||||
pub fn connect_button_delete(gui_data: &GuiData) {
|
pub fn connect_button_delete(gui_data: &GuiData) {
|
||||||
let gui_data = gui_data.clone();
|
let gui_data = gui_data.clone();
|
||||||
let buttons_delete = gui_data.buttons_delete.clone();
|
let buttons_delete = gui_data.buttons_delete.clone();
|
||||||
|
@ -20,6 +22,7 @@ pub fn connect_button_delete(gui_data: &GuiData) {
|
||||||
let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone();
|
let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone();
|
||||||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||||
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let check_button_settings_confirm_deletion = gui_data.check_button_settings_confirm_deletion.clone();
|
let check_button_settings_confirm_deletion = gui_data.check_button_settings_confirm_deletion.clone();
|
||||||
|
|
||||||
buttons_delete.connect_clicked(move |_| {
|
buttons_delete.connect_clicked(move |_| {
|
||||||
|
@ -80,6 +83,9 @@ pub fn connect_button_delete(gui_data: &GuiData) {
|
||||||
"notebook_main_same_music_finder" => {
|
"notebook_main_same_music_finder" => {
|
||||||
tree_remove(scrolled_window_same_music_finder.clone(), ColumnsSameMusic::Name as i32, ColumnsSameMusic::Path as i32, ColumnsSameMusic::Color as i32, &gui_data);
|
tree_remove(scrolled_window_same_music_finder.clone(), ColumnsSameMusic::Name as i32, ColumnsSameMusic::Path as i32, ColumnsSameMusic::Color as i32, &gui_data);
|
||||||
}
|
}
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
basic_remove_invalid_symlinks(scrolled_window_invalid_symlinks.clone(), ColumnsInvalidSymlinks::SymlinkPath as i32, &gui_data);
|
||||||
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -171,6 +177,38 @@ fn empty_folder_remover(scrolled_window: gtk::ScrolledWindow, column_file_name:
|
||||||
selection.unselect_all();
|
selection.unselect_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn basic_remove_invalid_symlinks(scrolled_window: gtk::ScrolledWindow, column_symlink_path: i32, gui_data: &GuiData) {
|
||||||
|
let text_view_errors = gui_data.text_view_errors.clone();
|
||||||
|
|
||||||
|
let tree_view = scrolled_window.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap();
|
||||||
|
let selection = tree_view.get_selection();
|
||||||
|
|
||||||
|
let (selection_rows, tree_model) = selection.get_selected_rows();
|
||||||
|
if selection_rows.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let list_store = tree_model.clone().downcast::<gtk::ListStore>().unwrap();
|
||||||
|
|
||||||
|
// let new_tree_model = TreeModel::new(); // TODO - maybe create new model when inserting a new data, because this seems to be not optimal when using thousands of rows
|
||||||
|
|
||||||
|
let mut messages: String = "".to_string();
|
||||||
|
|
||||||
|
// Must be deleted from end to start, because when deleting entries, TreePath(and also TreeIter) will points to invalid data
|
||||||
|
for tree_path in selection_rows.iter().rev() {
|
||||||
|
let symlink_path = tree_model.get_value(&tree_model.get_iter(tree_path).unwrap(), column_symlink_path).get::<String>().unwrap().unwrap();
|
||||||
|
|
||||||
|
match fs::remove_file(&symlink_path) {
|
||||||
|
Ok(_) => {
|
||||||
|
list_store.remove(&list_store.get_iter(tree_path).unwrap());
|
||||||
|
}
|
||||||
|
Err(_) => messages += format!("Failed to remove file {} because file doesn't exists or you don't have permissions.\n", symlink_path).as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text_view_errors.get_buffer().unwrap().set_text(messages.as_str());
|
||||||
|
selection.unselect_all();
|
||||||
|
}
|
||||||
|
|
||||||
fn basic_remove(scrolled_window: gtk::ScrolledWindow, column_file_name: i32, column_path: i32, gui_data: &GuiData) {
|
fn basic_remove(scrolled_window: gtk::ScrolledWindow, column_file_name: i32, column_path: i32, gui_data: &GuiData) {
|
||||||
let text_view_errors = gui_data.text_view_errors.clone();
|
let text_view_errors = gui_data.text_view_errors.clone();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ pub fn connect_button_save(gui_data: &GuiData) {
|
||||||
let shared_similar_images_state = gui_data.shared_similar_images_state.clone();
|
let shared_similar_images_state = gui_data.shared_similar_images_state.clone();
|
||||||
let shared_same_music_state = gui_data.shared_same_music_state.clone();
|
let shared_same_music_state = gui_data.shared_same_music_state.clone();
|
||||||
let shared_zeroed_files_state = gui_data.shared_zeroed_files_state.clone();
|
let shared_zeroed_files_state = gui_data.shared_zeroed_files_state.clone();
|
||||||
|
let shared_same_invalid_symlinks = gui_data.shared_same_invalid_symlinks.clone();
|
||||||
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
let notebook_main = gui_data.notebook_main.clone();
|
let notebook_main = gui_data.notebook_main.clone();
|
||||||
buttons_save.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
buttons_save.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
|
@ -73,6 +74,13 @@ pub fn connect_button_save(gui_data: &GuiData) {
|
||||||
|
|
||||||
post_save_things(file_name, "same_music", &gui_data);
|
post_save_things(file_name, "same_music", &gui_data);
|
||||||
}
|
}
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
let file_name = "results_invalid_symlinks.txt";
|
||||||
|
|
||||||
|
shared_same_invalid_symlinks.borrow_mut().save_results_to_file(file_name);
|
||||||
|
|
||||||
|
post_save_things(file_name, "invalid_symlinks", &gui_data);
|
||||||
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use czkawka_core::big_file::BigFile;
|
||||||
use czkawka_core::duplicate::DuplicateFinder;
|
use czkawka_core::duplicate::DuplicateFinder;
|
||||||
use czkawka_core::empty_files::EmptyFiles;
|
use czkawka_core::empty_files::EmptyFiles;
|
||||||
use czkawka_core::empty_folder::EmptyFolder;
|
use czkawka_core::empty_folder::EmptyFolder;
|
||||||
|
use czkawka_core::invalid_symlinks::InvalidSymlinks;
|
||||||
use czkawka_core::same_music::{MusicSimilarity, SameMusic};
|
use czkawka_core::same_music::{MusicSimilarity, SameMusic};
|
||||||
use czkawka_core::similar_images::SimilarImages;
|
use czkawka_core::similar_images::SimilarImages;
|
||||||
use czkawka_core::temporary::Temporary;
|
use czkawka_core::temporary::Temporary;
|
||||||
|
@ -14,6 +15,8 @@ use czkawka_core::zeroed::ZeroedFiles;
|
||||||
use glib::Sender;
|
use glib::Sender;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::WindowPosition;
|
use gtk::WindowPosition;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -28,6 +31,7 @@ pub fn connect_button_search(
|
||||||
futures_sender_similar_images: futures::channel::mpsc::Sender<similar_images::ProgressData>,
|
futures_sender_similar_images: futures::channel::mpsc::Sender<similar_images::ProgressData>,
|
||||||
futures_sender_temporary: futures::channel::mpsc::Sender<temporary::ProgressData>,
|
futures_sender_temporary: futures::channel::mpsc::Sender<temporary::ProgressData>,
|
||||||
futures_sender_zeroed: futures::channel::mpsc::Sender<zeroed::ProgressData>,
|
futures_sender_zeroed: futures::channel::mpsc::Sender<zeroed::ProgressData>,
|
||||||
|
futures_sender_invalid_symlinks: futures::channel::mpsc::Sender<invalid_symlinks::ProgressData>,
|
||||||
) {
|
) {
|
||||||
let entry_info = gui_data.entry_info.clone();
|
let entry_info = gui_data.entry_info.clone();
|
||||||
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
|
@ -68,6 +72,7 @@ pub fn connect_button_search(
|
||||||
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
||||||
let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone();
|
let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone();
|
||||||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let text_view_errors = gui_data.text_view_errors.clone();
|
let text_view_errors = gui_data.text_view_errors.clone();
|
||||||
let dialog_progress = gui_data.dialog_progress.clone();
|
let dialog_progress = gui_data.dialog_progress.clone();
|
||||||
let label_stage = gui_data.label_stage.clone();
|
let label_stage = gui_data.label_stage.clone();
|
||||||
|
@ -76,6 +81,8 @@ pub fn connect_button_search(
|
||||||
let progress_bar_all_stages = gui_data.progress_bar_all_stages.clone();
|
let progress_bar_all_stages = gui_data.progress_bar_all_stages.clone();
|
||||||
let image_preview_similar_images = gui_data.image_preview_similar_images.clone();
|
let image_preview_similar_images = gui_data.image_preview_similar_images.clone();
|
||||||
|
|
||||||
|
let show_dialog = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
buttons_search_clone.connect_clicked(move |_| {
|
buttons_search_clone.connect_clicked(move |_| {
|
||||||
let included_directories = get_string_from_list_store(&scrolled_window_included_directories);
|
let included_directories = get_string_from_list_store(&scrolled_window_included_directories);
|
||||||
let excluded_directories = get_string_from_list_store(&scrolled_window_excluded_directories);
|
let excluded_directories = get_string_from_list_store(&scrolled_window_excluded_directories);
|
||||||
|
@ -91,12 +98,14 @@ pub fn connect_button_search(
|
||||||
entry_info.set_text("Searching data, it may take a while, please wait...");
|
entry_info.set_text("Searching data, it may take a while, please wait...");
|
||||||
|
|
||||||
// Set dialog to center to current screen(it is impossible to center it to main window)
|
// Set dialog to center to current screen(it is impossible to center it to main window)
|
||||||
dialog_progress.set_position(WindowPosition::CenterOnParent);
|
dialog_progress.set_position(WindowPosition::CenterAlways);
|
||||||
|
|
||||||
// Resets progress bars
|
// Resets progress bars
|
||||||
progress_bar_all_stages.set_fraction(0 as f64);
|
progress_bar_all_stages.set_fraction(0 as f64);
|
||||||
progress_bar_current_stage.set_fraction(0 as f64);
|
progress_bar_current_stage.set_fraction(0 as f64);
|
||||||
|
|
||||||
|
reset_text_view(&text_view_errors);
|
||||||
|
|
||||||
match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
"notebook_main_duplicate_finder_label" => {
|
"notebook_main_duplicate_finder_label" => {
|
||||||
label_stage.show();
|
label_stage.show();
|
||||||
|
@ -104,7 +113,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_duplicate_finder).clear();
|
get_list_store(&scrolled_window_duplicate_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let check_method;
|
let check_method;
|
||||||
if radio_button_duplicates_name.get_active() {
|
if radio_button_duplicates_name.get_active() {
|
||||||
|
@ -147,7 +155,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_main_empty_files_finder).clear();
|
get_list_store(&scrolled_window_main_empty_files_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let glib_stop_sender = glib_stop_sender.clone();
|
let glib_stop_sender = glib_stop_sender.clone();
|
||||||
let stop_receiver = stop_receiver.clone();
|
let stop_receiver = stop_receiver.clone();
|
||||||
|
@ -172,7 +179,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_main_empty_folder_finder).clear();
|
get_list_store(&scrolled_window_main_empty_folder_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let glib_stop_sender = glib_stop_sender.clone();
|
let glib_stop_sender = glib_stop_sender.clone();
|
||||||
let stop_receiver = stop_receiver.clone();
|
let stop_receiver = stop_receiver.clone();
|
||||||
|
@ -194,7 +200,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_big_files_finder).clear();
|
get_list_store(&scrolled_window_big_files_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let numbers_of_files_to_check = match entry_big_files_number.get_text().as_str().parse::<usize>() {
|
let numbers_of_files_to_check = match entry_big_files_number.get_text().as_str().parse::<usize>() {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
|
@ -223,7 +228,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_main_temporary_files_finder).clear();
|
get_list_store(&scrolled_window_main_temporary_files_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let glib_stop_sender = glib_stop_sender.clone();
|
let glib_stop_sender = glib_stop_sender.clone();
|
||||||
let stop_receiver = stop_receiver.clone();
|
let stop_receiver = stop_receiver.clone();
|
||||||
|
@ -249,7 +253,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_similar_images_finder).clear();
|
get_list_store(&scrolled_window_similar_images_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let glib_stop_sender = glib_stop_sender.clone();
|
let glib_stop_sender = glib_stop_sender.clone();
|
||||||
let stop_receiver = stop_receiver.clone();
|
let stop_receiver = stop_receiver.clone();
|
||||||
|
@ -295,7 +298,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_zeroed_files_finder).clear();
|
get_list_store(&scrolled_window_zeroed_files_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let glib_stop_sender = glib_stop_sender.clone();
|
let glib_stop_sender = glib_stop_sender.clone();
|
||||||
let stop_receiver = stop_receiver.clone();
|
let stop_receiver = stop_receiver.clone();
|
||||||
|
@ -320,7 +322,6 @@ pub fn connect_button_search(
|
||||||
dialog_progress.resize(1, 1);
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
get_list_store(&scrolled_window_same_music_finder).clear();
|
get_list_store(&scrolled_window_same_music_finder).clear();
|
||||||
text_view_errors.get_buffer().unwrap().set_text("");
|
|
||||||
|
|
||||||
let minimal_file_size = match entry_same_music_minimal_size.get_text().as_str().parse::<u64>() {
|
let minimal_file_size = match entry_same_music_minimal_size.get_text().as_str().parse::<u64>() {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
|
@ -366,12 +367,37 @@ pub fn connect_button_search(
|
||||||
notebook_main.set_sensitive(true);
|
notebook_main.set_sensitive(true);
|
||||||
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("same_music").unwrap(), &buttons_array, &buttons_names);
|
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("same_music").unwrap(), &buttons_array, &buttons_names);
|
||||||
entry_info.set_text("ERROR: You must select at least one checkbox with music searching types.");
|
entry_info.set_text("ERROR: You must select at least one checkbox with music searching types.");
|
||||||
|
show_dialog.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
label_stage.show();
|
||||||
|
grid_progress_stages.hide();
|
||||||
|
dialog_progress.resize(1, 1);
|
||||||
|
|
||||||
|
get_list_store(&scrolled_window_invalid_symlinks).clear();
|
||||||
|
|
||||||
|
let glib_stop_sender = glib_stop_sender.clone();
|
||||||
|
let stop_receiver = stop_receiver.clone();
|
||||||
|
let futures_sender_invalid_symlinks = futures_sender_invalid_symlinks.clone();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut isf = InvalidSymlinks::new();
|
||||||
|
|
||||||
|
isf.set_included_directory(included_directories);
|
||||||
|
isf.set_excluded_directory(excluded_directories);
|
||||||
|
isf.set_recursive_search(recursive_search);
|
||||||
|
isf.set_excluded_items(excluded_items);
|
||||||
|
isf.find_invalid_links(Some(&stop_receiver), Some(&futures_sender_invalid_symlinks));
|
||||||
|
let _ = glib_stop_sender.send(Message::InvalidSymlinks(isf));
|
||||||
|
});
|
||||||
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show progress dialog
|
// Show progress dialog
|
||||||
dialog_progress.show();
|
if show_dialog.load(Ordering::Relaxed) {
|
||||||
|
dialog_progress.show();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub fn connect_button_select(gui_data: &GuiData) {
|
||||||
let buttons_select_clone = gui_data.buttons_select.clone();
|
let buttons_select_clone = gui_data.buttons_select.clone();
|
||||||
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
||||||
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
||||||
|
let popover_select_very_simple_list = gui_data.popover_select_very_simple_list.clone();
|
||||||
let buttons_select = gui_data.buttons_select.clone();
|
let buttons_select = gui_data.buttons_select.clone();
|
||||||
buttons_select_clone.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
buttons_select_clone.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
"notebook_main_duplicate_finder_label" | "notebook_main_same_music_finder" | "notebook_main_similar_images_finder_label" => {
|
"notebook_main_duplicate_finder_label" | "notebook_main_same_music_finder" | "notebook_main_similar_images_finder_label" => {
|
||||||
|
@ -18,6 +19,10 @@ pub fn connect_button_select(gui_data: &GuiData) {
|
||||||
popover_select_simple_list.set_relative_to(Some(&buttons_select));
|
popover_select_simple_list.set_relative_to(Some(&buttons_select));
|
||||||
popover_select_simple_list.popup();
|
popover_select_simple_list.popup();
|
||||||
}
|
}
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
popover_select_very_simple_list.set_relative_to(Some(&buttons_select));
|
||||||
|
popover_select_very_simple_list.popup();
|
||||||
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
let shared_empty_folders_state = gui_data.shared_empty_folders_state.clone();
|
let shared_empty_folders_state = gui_data.shared_empty_folders_state.clone();
|
||||||
let shared_empty_files_state = gui_data.shared_empty_files_state.clone();
|
let shared_empty_files_state = gui_data.shared_empty_files_state.clone();
|
||||||
let scrolled_window_big_files_finder = gui_data.scrolled_window_big_files_finder.clone();
|
let scrolled_window_big_files_finder = gui_data.scrolled_window_big_files_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let shared_big_files_state = gui_data.shared_big_files_state.clone();
|
let shared_big_files_state = gui_data.shared_big_files_state.clone();
|
||||||
|
let shared_same_invalid_symlinks = gui_data.shared_same_invalid_symlinks.clone();
|
||||||
let scrolled_window_main_temporary_files_finder = gui_data.scrolled_window_main_temporary_files_finder.clone();
|
let scrolled_window_main_temporary_files_finder = gui_data.scrolled_window_main_temporary_files_finder.clone();
|
||||||
let shared_temporary_files_state = gui_data.shared_temporary_files_state.clone();
|
let shared_temporary_files_state = gui_data.shared_temporary_files_state.clone();
|
||||||
let shared_similar_images_state = gui_data.shared_similar_images_state.clone();
|
let shared_similar_images_state = gui_data.shared_similar_images_state.clone();
|
||||||
|
@ -605,6 +607,54 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::InvalidSymlinks(ifs) => {
|
||||||
|
if ifs.get_stopped_search() {
|
||||||
|
entry_info.set_text("Searching for invalid symlink was stopped by user");
|
||||||
|
} else {
|
||||||
|
let information = ifs.get_information();
|
||||||
|
let text_messages = ifs.get_text_messages();
|
||||||
|
|
||||||
|
let invalid_symlinks: usize = information.number_of_invalid_symlinks;
|
||||||
|
|
||||||
|
entry_info.set_text(format!("Found {} invalid symlinks.", invalid_symlinks).as_str());
|
||||||
|
|
||||||
|
// Create GUI
|
||||||
|
{
|
||||||
|
let list_store = get_list_store(&scrolled_window_invalid_symlinks);
|
||||||
|
|
||||||
|
let col_indices = [0, 1, 2, 3];
|
||||||
|
|
||||||
|
let vector = ifs.get_invalid_symlinks();
|
||||||
|
|
||||||
|
for file_entry in vector {
|
||||||
|
let values: [&dyn ToValue; 4] = [
|
||||||
|
&file_entry.symlink_path.to_string_lossy().to_string(),
|
||||||
|
&file_entry.destination_path.to_string_lossy().to_string(),
|
||||||
|
&get_text_from_invalid_symlink_cause(&file_entry.type_of_error),
|
||||||
|
&(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &col_indices, &values);
|
||||||
|
}
|
||||||
|
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set state
|
||||||
|
{
|
||||||
|
*shared_same_invalid_symlinks.borrow_mut() = ifs;
|
||||||
|
|
||||||
|
if invalid_symlinks > 0 {
|
||||||
|
*shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap().get_mut("save").unwrap() = true;
|
||||||
|
*shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap().get_mut("delete").unwrap() = true;
|
||||||
|
*shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap().get_mut("select").unwrap() = true;
|
||||||
|
} else {
|
||||||
|
*shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap().get_mut("save").unwrap() = false;
|
||||||
|
*shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap().get_mut("delete").unwrap() = false;
|
||||||
|
*shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap().get_mut("select").unwrap() = false;
|
||||||
|
}
|
||||||
|
set_buttons(&mut *shared_buttons.borrow_mut().get_mut("invalid_symlinks").unwrap(), &buttons_array, &buttons_names);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Returning false here would close the receiver and have senders fail
|
// Returning false here would close the receiver and have senders fail
|
||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
|
|
|
@ -15,6 +15,16 @@ pub fn connect_notebook_tabs(gui_data: &GuiData) {
|
||||||
let notebook_upper = gui_data.notebook_upper.clone();
|
let notebook_upper = gui_data.notebook_upper.clone();
|
||||||
let notebook_upper_children_names = gui_data.notebook_upper_children_names.clone();
|
let notebook_upper_children_names = gui_data.notebook_upper_children_names.clone();
|
||||||
|
|
||||||
|
// TODO Remove this because disabling it doesn't works
|
||||||
|
// Remove on Windows last tab(Invalid symlinks) because is not available
|
||||||
|
// if cfg!(target_family = "windows") {
|
||||||
|
// for (index, widget) in notebook_main_clone.get_children().iter().enumerate() {
|
||||||
|
// if widget.get_buildable_name() == Some("scrolled_window_invalid_symlinks".to_string()) {
|
||||||
|
// notebook_main_clone.remove_page(Some(index as u32));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
notebook_main_clone.connect_switch_page(move |_, _, number| {
|
notebook_main_clone.connect_switch_page(move |_, _, number| {
|
||||||
let page: &str;
|
let page: &str;
|
||||||
match notebook_main_children_names.get(number as usize).unwrap().as_str() {
|
match notebook_main_children_names.get(number as usize).unwrap().as_str() {
|
||||||
|
@ -26,6 +36,7 @@ pub fn connect_notebook_tabs(gui_data: &GuiData) {
|
||||||
"notebook_main_similar_images_finder_label" => page = "similar_images",
|
"notebook_main_similar_images_finder_label" => page = "similar_images",
|
||||||
"notebook_main_zeroed_files_finder" => page = "zeroed_files",
|
"notebook_main_zeroed_files_finder" => page = "zeroed_files",
|
||||||
"notebook_main_same_music_finder" => page = "same_music",
|
"notebook_main_same_music_finder" => page = "same_music",
|
||||||
|
"scrolled_window_invalid_symlinks" => page = "invalid_symlinks",
|
||||||
e => {
|
e => {
|
||||||
panic!("Not existent page {}", e);
|
panic!("Not existent page {}", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -552,9 +552,12 @@ pub fn connect_select_all(gui_data: &GuiData) {
|
||||||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||||
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
||||||
let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone();
|
let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
||||||
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
||||||
|
let popover_select_very_simple_list = gui_data.popover_select_very_simple_list.clone();
|
||||||
let buttons_popover_simple_list_select_all = gui_data.buttons_popover_simple_list_select_all.clone();
|
let buttons_popover_simple_list_select_all = gui_data.buttons_popover_simple_list_select_all.clone();
|
||||||
|
let buttons_popover_very_simple_list_select_all = gui_data.buttons_popover_very_simple_list_select_all.clone();
|
||||||
let buttons_popover_duplicate_select_all = gui_data.buttons_popover_duplicate_select_all.clone();
|
let buttons_popover_duplicate_select_all = gui_data.buttons_popover_duplicate_select_all.clone();
|
||||||
buttons_popover_duplicate_select_all.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
buttons_popover_duplicate_select_all.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
"notebook_main_duplicate_finder_label" => {
|
"notebook_main_duplicate_finder_label" => {
|
||||||
|
@ -589,6 +592,15 @@ pub fn connect_select_all(gui_data: &GuiData) {
|
||||||
}
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
|
let notebook_main = gui_data.notebook_main.clone();
|
||||||
|
buttons_popover_very_simple_list_select_all.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
popover_select_all(&popover_select_very_simple_list, &scrolled_window_invalid_symlinks);
|
||||||
|
}
|
||||||
|
e => panic!("Not existent {}", e),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
pub fn connect_unselect_all(gui_data: &GuiData) {
|
pub fn connect_unselect_all(gui_data: &GuiData) {
|
||||||
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
|
@ -602,9 +614,12 @@ pub fn connect_unselect_all(gui_data: &GuiData) {
|
||||||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||||
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
||||||
let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone();
|
let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
||||||
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
||||||
|
let popover_select_very_simple_list = gui_data.popover_select_very_simple_list.clone();
|
||||||
let buttons_popover_simple_list_unselect_all = gui_data.buttons_popover_simple_list_unselect_all.clone();
|
let buttons_popover_simple_list_unselect_all = gui_data.buttons_popover_simple_list_unselect_all.clone();
|
||||||
|
let buttons_popover_very_simple_list_unselect_all = gui_data.buttons_popover_very_simple_list_unselect_all.clone();
|
||||||
let buttons_popover_duplicate_unselect_all = gui_data.buttons_popover_duplicate_unselect_all.clone();
|
let buttons_popover_duplicate_unselect_all = gui_data.buttons_popover_duplicate_unselect_all.clone();
|
||||||
buttons_popover_duplicate_unselect_all.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
buttons_popover_duplicate_unselect_all.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
"notebook_main_duplicate_finder_label" => {
|
"notebook_main_duplicate_finder_label" => {
|
||||||
|
@ -639,6 +654,15 @@ pub fn connect_unselect_all(gui_data: &GuiData) {
|
||||||
}
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
|
let notebook_main = gui_data.notebook_main.clone();
|
||||||
|
buttons_popover_very_simple_list_unselect_all.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
popover_unselect_all(&popover_select_very_simple_list, &scrolled_window_invalid_symlinks);
|
||||||
|
}
|
||||||
|
e => panic!("Not existent {}", e),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
pub fn connect_reverse(gui_data: &GuiData) {
|
pub fn connect_reverse(gui_data: &GuiData) {
|
||||||
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
|
@ -652,9 +676,12 @@ pub fn connect_reverse(gui_data: &GuiData) {
|
||||||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||||
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
||||||
let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone();
|
let scrolled_window_duplicate_finder = gui_data.scrolled_window_duplicate_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
let popover_select_duplicate = gui_data.popover_select_duplicate.clone();
|
||||||
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
let popover_select_simple_list = gui_data.popover_select_simple_list.clone();
|
||||||
|
let popover_select_very_simple_list = gui_data.popover_select_very_simple_list.clone();
|
||||||
let buttons_popover_simple_list_reverse = gui_data.buttons_popover_simple_list_reverse.clone();
|
let buttons_popover_simple_list_reverse = gui_data.buttons_popover_simple_list_reverse.clone();
|
||||||
|
let buttons_popover_very_simple_list_reverse = gui_data.buttons_popover_very_simple_list_reverse.clone();
|
||||||
let buttons_popover_duplicate_reverse = gui_data.buttons_popover_duplicate_reverse.clone();
|
let buttons_popover_duplicate_reverse = gui_data.buttons_popover_duplicate_reverse.clone();
|
||||||
buttons_popover_duplicate_reverse.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
buttons_popover_duplicate_reverse.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
"notebook_main_duplicate_finder_label" => {
|
"notebook_main_duplicate_finder_label" => {
|
||||||
|
@ -689,6 +716,15 @@ pub fn connect_reverse(gui_data: &GuiData) {
|
||||||
}
|
}
|
||||||
e => panic!("Not existent {}", e),
|
e => panic!("Not existent {}", e),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let notebook_main_children_names = gui_data.notebook_main_children_names.clone();
|
||||||
|
let notebook_main = gui_data.notebook_main.clone();
|
||||||
|
buttons_popover_very_simple_list_reverse.connect_clicked(move |_| match notebook_main_children_names.get(notebook_main.get_current_page().unwrap() as usize).unwrap().as_str() {
|
||||||
|
"scrolled_window_invalid_symlinks" => {
|
||||||
|
popover_reverse(&popover_select_very_simple_list, &scrolled_window_invalid_symlinks);
|
||||||
|
}
|
||||||
|
e => panic!("Not existent {}", e),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_all_except_oldest(gui_data: &GuiData) {
|
pub fn connect_all_except_oldest(gui_data: &GuiData) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::gui_data::GuiData;
|
use crate::gui_data::GuiData;
|
||||||
|
|
||||||
use czkawka_core::{big_file, duplicate, empty_files, empty_folder, same_music, similar_images, temporary, zeroed};
|
use czkawka_core::{big_file, duplicate, empty_files, empty_folder, invalid_symlinks, same_music, similar_images, temporary, zeroed};
|
||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gtk::{LabelExt, ProgressBarExt, WidgetExt};
|
use gtk::{LabelExt, ProgressBarExt, WidgetExt};
|
||||||
|
@ -16,6 +16,7 @@ pub fn connect_progress_window(
|
||||||
mut futures_receiver_similar_images: futures::channel::mpsc::Receiver<similar_images::ProgressData>,
|
mut futures_receiver_similar_images: futures::channel::mpsc::Receiver<similar_images::ProgressData>,
|
||||||
mut futures_receiver_temporary: futures::channel::mpsc::Receiver<temporary::ProgressData>,
|
mut futures_receiver_temporary: futures::channel::mpsc::Receiver<temporary::ProgressData>,
|
||||||
mut futures_receiver_zeroed: futures::channel::mpsc::Receiver<zeroed::ProgressData>,
|
mut futures_receiver_zeroed: futures::channel::mpsc::Receiver<zeroed::ProgressData>,
|
||||||
|
mut futures_receiver_invalid_symlinks: futures::channel::mpsc::Receiver<invalid_symlinks::ProgressData>,
|
||||||
) {
|
) {
|
||||||
let main_context = glib::MainContext::default();
|
let main_context = glib::MainContext::default();
|
||||||
|
|
||||||
|
@ -230,4 +231,14 @@ pub fn connect_progress_window(
|
||||||
};
|
};
|
||||||
main_context.spawn_local(future);
|
main_context.spawn_local(future);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// Invalid Symlinks
|
||||||
|
let label_stage = gui_data.label_stage.clone();
|
||||||
|
let future = async move {
|
||||||
|
while let Some(item) = futures_receiver_invalid_symlinks.next().await {
|
||||||
|
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
main_context.spawn_local(future);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -394,3 +394,43 @@ pub fn create_tree_view_same_music(tree_view: &mut gtk::TreeView) {
|
||||||
|
|
||||||
tree_view.set_vexpand(true);
|
tree_view.set_vexpand(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_tree_view_invalid_symlinks(tree_view: &mut gtk::TreeView) {
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||||
|
column.pack_start(&renderer, true);
|
||||||
|
column.set_title("Symlink Path");
|
||||||
|
column.set_resizable(true);
|
||||||
|
column.set_min_width(50);
|
||||||
|
column.add_attribute(&renderer, "text", ColumnsInvalidSymlinks::SymlinkPath as i32);
|
||||||
|
tree_view.append_column(&column);
|
||||||
|
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::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);
|
||||||
|
tree_view.append_column(&column);
|
||||||
|
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::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);
|
||||||
|
tree_view.append_column(&column);
|
||||||
|
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::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);
|
||||||
|
tree_view.append_column(&column);
|
||||||
|
|
||||||
|
tree_view.set_vexpand(true);
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use czkawka_core::big_file::BigFile;
|
||||||
use czkawka_core::duplicate::DuplicateFinder;
|
use czkawka_core::duplicate::DuplicateFinder;
|
||||||
use czkawka_core::empty_files::EmptyFiles;
|
use czkawka_core::empty_files::EmptyFiles;
|
||||||
use czkawka_core::empty_folder::EmptyFolder;
|
use czkawka_core::empty_folder::EmptyFolder;
|
||||||
|
use czkawka_core::invalid_symlinks::InvalidSymlinks;
|
||||||
use czkawka_core::same_music::SameMusic;
|
use czkawka_core::same_music::SameMusic;
|
||||||
use czkawka_core::similar_images::SimilarImages;
|
use czkawka_core::similar_images::SimilarImages;
|
||||||
use czkawka_core::temporary::Temporary;
|
use czkawka_core::temporary::Temporary;
|
||||||
|
@ -24,9 +25,10 @@ pub struct GuiData {
|
||||||
pub window_main: gtk::Window,
|
pub window_main: gtk::Window,
|
||||||
|
|
||||||
// States
|
// States
|
||||||
pub main_notebooks_labels: [String; 8],
|
pub main_notebooks_labels: [String; 9],
|
||||||
pub upper_notebooks_labels: [String; 5],
|
pub upper_notebooks_labels: [String; 5],
|
||||||
pub buttons_labels: [String; 5],
|
pub buttons_labels: [String; 5],
|
||||||
|
|
||||||
// Buttons state
|
// Buttons state
|
||||||
pub shared_buttons: Rc<RefCell<HashMap<String, HashMap<String, bool>>>>,
|
pub shared_buttons: Rc<RefCell<HashMap<String, HashMap<String, bool>>>>,
|
||||||
|
|
||||||
|
@ -42,6 +44,7 @@ pub struct GuiData {
|
||||||
pub shared_similar_images_state: Rc<RefCell<SimilarImages>>,
|
pub shared_similar_images_state: Rc<RefCell<SimilarImages>>,
|
||||||
pub shared_zeroed_files_state: Rc<RefCell<ZeroedFiles>>,
|
pub shared_zeroed_files_state: Rc<RefCell<ZeroedFiles>>,
|
||||||
pub shared_same_music_state: Rc<RefCell<SameMusic>>,
|
pub shared_same_music_state: Rc<RefCell<SameMusic>>,
|
||||||
|
pub shared_same_invalid_symlinks: Rc<RefCell<InvalidSymlinks>>,
|
||||||
|
|
||||||
//// GUI Entry
|
//// GUI Entry
|
||||||
pub entry_similar_images_minimal_size: gtk::Entry,
|
pub entry_similar_images_minimal_size: gtk::Entry,
|
||||||
|
@ -82,9 +85,14 @@ pub struct GuiData {
|
||||||
pub buttons_popover_simple_list_select_custom: gtk::Button,
|
pub buttons_popover_simple_list_select_custom: gtk::Button,
|
||||||
pub buttons_popover_simple_list_unselect_custom: gtk::Button,
|
pub buttons_popover_simple_list_unselect_custom: gtk::Button,
|
||||||
|
|
||||||
|
pub buttons_popover_very_simple_list_select_all: gtk::Button,
|
||||||
|
pub buttons_popover_very_simple_list_unselect_all: gtk::Button,
|
||||||
|
pub buttons_popover_very_simple_list_reverse: gtk::Button,
|
||||||
|
|
||||||
//// Popovers
|
//// Popovers
|
||||||
pub popover_select_duplicate: gtk::Popover,
|
pub popover_select_duplicate: gtk::Popover,
|
||||||
pub popover_select_simple_list: gtk::Popover,
|
pub popover_select_simple_list: gtk::Popover,
|
||||||
|
pub popover_select_very_simple_list: gtk::Popover,
|
||||||
|
|
||||||
//// Check Buttons
|
//// Check Buttons
|
||||||
pub check_button_recursive: gtk::CheckButton,
|
pub check_button_recursive: gtk::CheckButton,
|
||||||
|
@ -132,6 +140,7 @@ pub struct GuiData {
|
||||||
pub scrolled_window_similar_images_finder: gtk::ScrolledWindow,
|
pub scrolled_window_similar_images_finder: gtk::ScrolledWindow,
|
||||||
pub scrolled_window_zeroed_files_finder: gtk::ScrolledWindow,
|
pub scrolled_window_zeroed_files_finder: gtk::ScrolledWindow,
|
||||||
pub scrolled_window_same_music_finder: gtk::ScrolledWindow,
|
pub scrolled_window_same_music_finder: gtk::ScrolledWindow,
|
||||||
|
pub scrolled_window_invalid_symlinks: gtk::ScrolledWindow,
|
||||||
|
|
||||||
// Upper notebook
|
// Upper notebook
|
||||||
pub scrolled_window_included_directories: gtk::ScrolledWindow,
|
pub scrolled_window_included_directories: gtk::ScrolledWindow,
|
||||||
|
@ -191,6 +200,7 @@ impl GuiData {
|
||||||
"similar_images".to_string(),
|
"similar_images".to_string(),
|
||||||
"zeroed_files".to_string(),
|
"zeroed_files".to_string(),
|
||||||
"same_music".to_string(),
|
"same_music".to_string(),
|
||||||
|
"invalid_symlinks".to_string(),
|
||||||
];
|
];
|
||||||
let upper_notebooks_labels = [
|
let upper_notebooks_labels = [
|
||||||
"included_directories".to_string(),
|
"included_directories".to_string(),
|
||||||
|
@ -242,6 +252,7 @@ impl GuiData {
|
||||||
let shared_similar_images_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SimilarImages::new()));
|
let shared_similar_images_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SimilarImages::new()));
|
||||||
let shared_zeroed_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(ZeroedFiles::new()));
|
let shared_zeroed_files_state: Rc<RefCell<_>> = Rc::new(RefCell::new(ZeroedFiles::new()));
|
||||||
let shared_same_music_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SameMusic::new()));
|
let shared_same_music_state: Rc<RefCell<_>> = Rc::new(RefCell::new(SameMusic::new()));
|
||||||
|
let shared_same_invalid_symlinks: Rc<RefCell<_>> = Rc::new(RefCell::new(InvalidSymlinks::new()));
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -287,9 +298,14 @@ impl GuiData {
|
||||||
let buttons_popover_simple_list_select_custom: gtk::Button = builder.get_object("buttons_popover_simple_list_select_custom").unwrap();
|
let buttons_popover_simple_list_select_custom: gtk::Button = builder.get_object("buttons_popover_simple_list_select_custom").unwrap();
|
||||||
let buttons_popover_simple_list_unselect_custom: gtk::Button = builder.get_object("buttons_popover_simple_list_unselect_custom").unwrap();
|
let buttons_popover_simple_list_unselect_custom: gtk::Button = builder.get_object("buttons_popover_simple_list_unselect_custom").unwrap();
|
||||||
|
|
||||||
|
let buttons_popover_very_simple_list_select_all: gtk::Button = builder.get_object("buttons_popover_very_simple_list_select_all").unwrap();
|
||||||
|
let buttons_popover_very_simple_list_unselect_all: gtk::Button = builder.get_object("buttons_popover_very_simple_list_unselect_all").unwrap();
|
||||||
|
let buttons_popover_very_simple_list_reverse: gtk::Button = builder.get_object("buttons_popover_very_simple_list_reverse").unwrap();
|
||||||
|
|
||||||
//// Popovers
|
//// Popovers
|
||||||
let popover_select_duplicate: gtk::Popover = builder.get_object("popover_select_duplicate").unwrap();
|
let popover_select_duplicate: gtk::Popover = builder.get_object("popover_select_duplicate").unwrap();
|
||||||
let popover_select_simple_list: gtk::Popover = builder.get_object("popover_select_simple_list").unwrap();
|
let popover_select_simple_list: gtk::Popover = builder.get_object("popover_select_simple_list").unwrap();
|
||||||
|
let popover_select_very_simple_list: gtk::Popover = builder.get_object("popover_select_very_simple_list").unwrap();
|
||||||
|
|
||||||
//// Check Buttons
|
//// Check Buttons
|
||||||
let check_button_recursive: gtk::CheckButton = builder.get_object("check_button_recursive").unwrap();
|
let check_button_recursive: gtk::CheckButton = builder.get_object("check_button_recursive").unwrap();
|
||||||
|
@ -342,6 +358,7 @@ impl GuiData {
|
||||||
let scrolled_window_similar_images_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_similar_images_finder").unwrap();
|
let scrolled_window_similar_images_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_similar_images_finder").unwrap();
|
||||||
let scrolled_window_zeroed_files_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_zeroed_files_finder").unwrap();
|
let scrolled_window_zeroed_files_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_zeroed_files_finder").unwrap();
|
||||||
let scrolled_window_same_music_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_same_music_finder").unwrap();
|
let scrolled_window_same_music_finder: gtk::ScrolledWindow = builder.get_object("scrolled_window_same_music_finder").unwrap();
|
||||||
|
let scrolled_window_invalid_symlinks: gtk::ScrolledWindow = builder.get_object("scrolled_window_invalid_symlinks").unwrap();
|
||||||
|
|
||||||
// Upper notebook
|
// Upper notebook
|
||||||
let scrolled_window_included_directories: gtk::ScrolledWindow = builder.get_object("scrolled_window_included_directories").unwrap();
|
let scrolled_window_included_directories: gtk::ScrolledWindow = builder.get_object("scrolled_window_included_directories").unwrap();
|
||||||
|
@ -396,6 +413,7 @@ impl GuiData {
|
||||||
shared_similar_images_state,
|
shared_similar_images_state,
|
||||||
shared_zeroed_files_state,
|
shared_zeroed_files_state,
|
||||||
shared_same_music_state,
|
shared_same_music_state,
|
||||||
|
shared_same_invalid_symlinks,
|
||||||
entry_similar_images_minimal_size,
|
entry_similar_images_minimal_size,
|
||||||
entry_duplicate_minimal_size,
|
entry_duplicate_minimal_size,
|
||||||
entry_allowed_extensions,
|
entry_allowed_extensions,
|
||||||
|
@ -428,8 +446,12 @@ impl GuiData {
|
||||||
buttons_popover_simple_list_reverse,
|
buttons_popover_simple_list_reverse,
|
||||||
buttons_popover_simple_list_select_custom,
|
buttons_popover_simple_list_select_custom,
|
||||||
buttons_popover_simple_list_unselect_custom,
|
buttons_popover_simple_list_unselect_custom,
|
||||||
|
buttons_popover_very_simple_list_select_all,
|
||||||
|
buttons_popover_very_simple_list_unselect_all,
|
||||||
|
buttons_popover_very_simple_list_reverse,
|
||||||
popover_select_duplicate,
|
popover_select_duplicate,
|
||||||
popover_select_simple_list,
|
popover_select_simple_list,
|
||||||
|
popover_select_very_simple_list,
|
||||||
check_button_recursive,
|
check_button_recursive,
|
||||||
check_button_music_title,
|
check_button_music_title,
|
||||||
check_button_music_artist,
|
check_button_music_artist,
|
||||||
|
@ -460,6 +482,7 @@ impl GuiData {
|
||||||
scrolled_window_similar_images_finder,
|
scrolled_window_similar_images_finder,
|
||||||
scrolled_window_zeroed_files_finder,
|
scrolled_window_zeroed_files_finder,
|
||||||
scrolled_window_same_music_finder,
|
scrolled_window_same_music_finder,
|
||||||
|
scrolled_window_invalid_symlinks,
|
||||||
scrolled_window_included_directories,
|
scrolled_window_included_directories,
|
||||||
scrolled_window_excluded_directories,
|
scrolled_window_excluded_directories,
|
||||||
dialog_progress,
|
dialog_progress,
|
||||||
|
|
|
@ -3,6 +3,8 @@ use czkawka_core::common_messages::Messages;
|
||||||
use czkawka_core::duplicate::DuplicateFinder;
|
use czkawka_core::duplicate::DuplicateFinder;
|
||||||
use czkawka_core::empty_files::EmptyFiles;
|
use czkawka_core::empty_files::EmptyFiles;
|
||||||
use czkawka_core::empty_folder::EmptyFolder;
|
use czkawka_core::empty_folder::EmptyFolder;
|
||||||
|
use czkawka_core::invalid_symlinks;
|
||||||
|
use czkawka_core::invalid_symlinks::InvalidSymlinks;
|
||||||
use czkawka_core::same_music::SameMusic;
|
use czkawka_core::same_music::SameMusic;
|
||||||
use czkawka_core::similar_images::{SimilarImages, Similarity};
|
use czkawka_core::similar_images::{SimilarImages, Similarity};
|
||||||
use czkawka_core::temporary::Temporary;
|
use czkawka_core::temporary::Temporary;
|
||||||
|
@ -21,6 +23,7 @@ pub enum Message {
|
||||||
SimilarImages(SimilarImages),
|
SimilarImages(SimilarImages),
|
||||||
ZeroedFiles(ZeroedFiles),
|
ZeroedFiles(ZeroedFiles),
|
||||||
SameMusic(SameMusic),
|
SameMusic(SameMusic),
|
||||||
|
InvalidSymlinks(InvalidSymlinks),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ColumnsDuplicates {
|
pub enum ColumnsDuplicates {
|
||||||
|
@ -90,6 +93,12 @@ pub enum ColumnsSameMusic {
|
||||||
Color,
|
Color,
|
||||||
TextColor,
|
TextColor,
|
||||||
}
|
}
|
||||||
|
pub enum ColumnsInvalidSymlinks {
|
||||||
|
SymlinkPath = 0,
|
||||||
|
DestinationPath,
|
||||||
|
TypeOfError,
|
||||||
|
Modification,
|
||||||
|
}
|
||||||
|
|
||||||
pub const TEXT_COLOR: &str = "#ffffff";
|
pub const TEXT_COLOR: &str = "#ffffff";
|
||||||
pub const MAIN_ROW_COLOR: &str = "#343434";
|
pub const MAIN_ROW_COLOR: &str = "#343434";
|
||||||
|
@ -248,6 +257,13 @@ pub fn get_text_from_similarity(similarity: &Similarity) -> &str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_text_from_invalid_symlink_cause(error: &invalid_symlinks::ErrorType) -> &str {
|
||||||
|
match error {
|
||||||
|
invalid_symlinks::ErrorType::InfiniteRecursion => "Infinite recursion",
|
||||||
|
invalid_symlinks::ErrorType::NonExistentFile => "Non existent destination file",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_list_store(scrolled_window: >k::ScrolledWindow) -> ListStore {
|
pub fn get_list_store(scrolled_window: >k::ScrolledWindow) -> ListStore {
|
||||||
let list_store = scrolled_window.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap().get_model().unwrap().downcast::<gtk::ListStore>().unwrap();
|
let list_store = scrolled_window.get_children().get(0).unwrap().clone().downcast::<gtk::TreeView>().unwrap().get_model().unwrap().downcast::<gtk::ListStore>().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub fn initialize_gui(gui_data: &GuiData) {
|
||||||
let scrolled_window_big_files_finder = gui_data.scrolled_window_big_files_finder.clone();
|
let scrolled_window_big_files_finder = gui_data.scrolled_window_big_files_finder.clone();
|
||||||
let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone();
|
let scrolled_window_similar_images_finder = gui_data.scrolled_window_similar_images_finder.clone();
|
||||||
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
let scrolled_window_same_music_finder = gui_data.scrolled_window_same_music_finder.clone();
|
||||||
|
let scrolled_window_invalid_symlinks = gui_data.scrolled_window_invalid_symlinks.clone();
|
||||||
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
let scrolled_window_zeroed_files_finder = gui_data.scrolled_window_zeroed_files_finder.clone();
|
||||||
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
let scrolled_window_included_directories = gui_data.scrolled_window_included_directories.clone();
|
||||||
let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone();
|
let scrolled_window_excluded_directories = gui_data.scrolled_window_excluded_directories.clone();
|
||||||
|
@ -277,6 +278,20 @@ pub fn initialize_gui(gui_data: &GuiData) {
|
||||||
scrolled_window_same_music_finder.add(&tree_view);
|
scrolled_window_same_music_finder.add(&tree_view);
|
||||||
scrolled_window_same_music_finder.show_all();
|
scrolled_window_same_music_finder.show_all();
|
||||||
}
|
}
|
||||||
|
// Invalid Symlinks
|
||||||
|
{
|
||||||
|
let col_types: [glib::types::Type; 4] = [glib::types::Type::String, glib::types::Type::String, glib::types::Type::String, glib::types::Type::String];
|
||||||
|
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
||||||
|
|
||||||
|
let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
|
||||||
|
|
||||||
|
tree_view.get_selection().set_mode(SelectionMode::Multiple);
|
||||||
|
|
||||||
|
create_tree_view_invalid_symlinks(&mut tree_view);
|
||||||
|
|
||||||
|
scrolled_window_invalid_symlinks.add(&tree_view);
|
||||||
|
scrolled_window_invalid_symlinks.show_all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Included Directory
|
// Set Included Directory
|
||||||
|
|
|
@ -76,6 +76,7 @@ fn main() {
|
||||||
let (futures_sender_similar_images, futures_receiver_similar_images): (futures::channel::mpsc::Sender<similar_images::ProgressData>, futures::channel::mpsc::Receiver<similar_images::ProgressData>) = futures::channel::mpsc::channel(20);
|
let (futures_sender_similar_images, futures_receiver_similar_images): (futures::channel::mpsc::Sender<similar_images::ProgressData>, futures::channel::mpsc::Receiver<similar_images::ProgressData>) = futures::channel::mpsc::channel(20);
|
||||||
let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::Sender<temporary::ProgressData>, futures::channel::mpsc::Receiver<temporary::ProgressData>) = futures::channel::mpsc::channel(20);
|
let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::Sender<temporary::ProgressData>, futures::channel::mpsc::Receiver<temporary::ProgressData>) = futures::channel::mpsc::channel(20);
|
||||||
let (futures_sender_zeroed, futures_receiver_zeroed): (futures::channel::mpsc::Sender<zeroed::ProgressData>, futures::channel::mpsc::Receiver<zeroed::ProgressData>) = futures::channel::mpsc::channel(20);
|
let (futures_sender_zeroed, futures_receiver_zeroed): (futures::channel::mpsc::Sender<zeroed::ProgressData>, futures::channel::mpsc::Receiver<zeroed::ProgressData>) = futures::channel::mpsc::channel(20);
|
||||||
|
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (futures::channel::mpsc::Sender<invalid_symlinks::ProgressData>, futures::channel::mpsc::Receiver<invalid_symlinks::ProgressData>) = futures::channel::mpsc::channel(20);
|
||||||
|
|
||||||
initialize_gui(&gui_data);
|
initialize_gui(&gui_data);
|
||||||
reset_configuration(&gui_data, false); // Fallback for invalid loading setting project
|
reset_configuration(&gui_data, false); // Fallback for invalid loading setting project
|
||||||
|
@ -94,6 +95,7 @@ fn main() {
|
||||||
futures_sender_similar_images,
|
futures_sender_similar_images,
|
||||||
futures_sender_temporary,
|
futures_sender_temporary,
|
||||||
futures_sender_zeroed,
|
futures_sender_zeroed,
|
||||||
|
futures_sender_invalid_symlinks,
|
||||||
);
|
);
|
||||||
connect_button_select(&gui_data);
|
connect_button_select(&gui_data);
|
||||||
connect_button_stop(&gui_data);
|
connect_button_stop(&gui_data);
|
||||||
|
@ -112,6 +114,7 @@ fn main() {
|
||||||
futures_receiver_similar_images,
|
futures_receiver_similar_images,
|
||||||
futures_receiver_temporary,
|
futures_receiver_temporary,
|
||||||
futures_receiver_zeroed,
|
futures_receiver_zeroed,
|
||||||
|
futures_receiver_invalid_symlinks,
|
||||||
);
|
);
|
||||||
connect_hide_text_view_errors(&gui_data);
|
connect_hide_text_view_errors(&gui_data);
|
||||||
connect_settings(&gui_data);
|
connect_settings(&gui_data);
|
||||||
|
|
|
@ -426,7 +426,7 @@ pub fn reset_configuration(gui_data: &GuiData, manual_clearing: bool) {
|
||||||
{
|
{
|
||||||
let entry_excluded_items = gui_data.entry_excluded_items.clone();
|
let entry_excluded_items = gui_data.entry_excluded_items.clone();
|
||||||
if cfg!(target_family = "unix") {
|
if cfg!(target_family = "unix") {
|
||||||
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*/Trash/*,*/.Trash-*/*");
|
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*/Trash/*,*/.Trash-*/*,*/snap/*");
|
||||||
}
|
}
|
||||||
if cfg!(target_family = "windows") {
|
if cfg!(target_family = "windows") {
|
||||||
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*:/windows/*");
|
entry_excluded_items.set_text("*/.git/*,*/node_modules/*,*/lost+found/*,*:/windows/*");
|
||||||
|
|
Loading…
Reference in a new issue