Add reference folders (#516)
* Add reference folder * Basic tree view cleaning * Computations * Similar Images * Muzyka i Wideo * Podwójne dwa razy, cztery razy! * Rozmiar i Nazwa * Spanko i działanko(przynajmniej zdaje mi się że działa) * Translatanko
This commit is contained in:
parent
5db5d17afb
commit
c4f26883b1
|
@ -11,7 +11,7 @@
|
||||||
- Option to not remove cache from non existent files(e.g. from unplugged pendrive) - [#472](https://github.com/qarmin/czkawka/pull/472)
|
- Option to not remove cache from non existent files(e.g. from unplugged pendrive) - [#472](https://github.com/qarmin/czkawka/pull/472)
|
||||||
- Add multiple tooltips with helpful messages - [#472](https://github.com/qarmin/czkawka/pull/472)
|
- Add multiple tooltips with helpful messages - [#472](https://github.com/qarmin/czkawka/pull/472)
|
||||||
- Allow to cache prehash - [#477](https://github.com/qarmin/czkawka/pull/477)
|
- Allow to cache prehash - [#477](https://github.com/qarmin/czkawka/pull/477)
|
||||||
- Improve custom selecting of records(allows to use Rust red regex) - [#489](https://github.com/qarmin/czkawka/pull/478)
|
- Improve custom selecting of records(allows to use Rust regex) - [#489](https://github.com/qarmin/czkawka/pull/478)
|
||||||
- Remove support for finding zeroed files - [#461](https://github.com/qarmin/czkawka/pull/461)
|
- Remove support for finding zeroed files - [#461](https://github.com/qarmin/czkawka/pull/461)
|
||||||
- Remove HashMB mode - [#476](https://github.com/qarmin/czkawka/pull/476)
|
- Remove HashMB mode - [#476](https://github.com/qarmin/czkawka/pull/476)
|
||||||
- Approximate comparison of music - [#483](https://github.com/qarmin/czkawka/pull/483)
|
- Approximate comparison of music - [#483](https://github.com/qarmin/czkawka/pull/483)
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
- CLI frontend - for easy automation
|
- CLI frontend - for easy automation
|
||||||
- GUI frontend - uses modern GTK 3 and looks similar to FSlint
|
- GUI frontend - uses modern GTK 3 and looks similar to FSlint
|
||||||
- No spying - Czkawka does not have access to the Internet, nor does it collect any user information or statistics
|
- No spying - Czkawka does not have access to the Internet, nor does it collect any user information or statistics
|
||||||
- Multilingual - app support multiple languages
|
- Multilingual - support multiple languages like Polish, English or Italian
|
||||||
- Multiple tools to use:
|
- Multiple tools to use:
|
||||||
- Duplicates - Finds duplicates based on file name, size or hash
|
- Duplicates - Finds duplicates based on file name, size or hash
|
||||||
- Empty Folders - Finds empty folders with the help of an advanced algorithm
|
- Empty Folders - Finds empty folders with the help of an advanced algorithm
|
||||||
|
@ -113,7 +113,7 @@ Bleachbit is a master at finding and removing temporary files, while Czkawka onl
|
||||||
| Non stripped binaries | | • | | |
|
| Non stripped binaries | | • | | |
|
||||||
| Redundant whitespace | | • | | |
|
| Redundant whitespace | | • | | |
|
||||||
| Overwriting files | | • | | • |
|
| Overwriting files | | • | | • |
|
||||||
| Multiple languages(po) | • | • | • | • |
|
| Multiple languages | • | • | • | • |
|
||||||
| Cache support | • | | • | |
|
| Cache support | • | | • | |
|
||||||
| In active development | Yes | No | Yes | Yes |
|
| In active development | Yes | No | Yes | Yes |
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ pub enum DeleteMethod {
|
||||||
/// Info struck with helpful information's about results
|
/// Info struck with helpful information's about results
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub taken_space: u64,
|
|
||||||
pub number_of_real_files: usize,
|
pub number_of_real_files: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +301,6 @@ impl BigFile {
|
||||||
if self.information.number_of_real_files < self.number_of_files_to_check {
|
if self.information.number_of_real_files < self.number_of_files_to_check {
|
||||||
new_map.entry(*size).or_insert_with(Vec::new);
|
new_map.entry(*size).or_insert_with(Vec::new);
|
||||||
new_map.get_mut(size).unwrap().push(file.clone());
|
new_map.get_mut(size).unwrap().push(file.clone());
|
||||||
self.information.taken_space += size;
|
|
||||||
self.information.number_of_real_files += 1;
|
self.information.number_of_real_files += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -445,11 +443,6 @@ impl SaveResults for BigFile {
|
||||||
impl PrintResults for BigFile {
|
impl PrintResults for BigFile {
|
||||||
fn print_results(&self) {
|
fn print_results(&self) {
|
||||||
let start_time: SystemTime = SystemTime::now();
|
let start_time: SystemTime = SystemTime::now();
|
||||||
println!(
|
|
||||||
"Found {} files which take {}:",
|
|
||||||
self.information.number_of_real_files,
|
|
||||||
self.information.taken_space.file_size(options::BINARY).unwrap()
|
|
||||||
);
|
|
||||||
for (size, vector) in self.big_files.iter().rev() {
|
for (size, vector) in self.big_files.iter().rev() {
|
||||||
// TODO Align all to same width
|
// TODO Align all to same width
|
||||||
for entry in vector {
|
for entry in vector {
|
||||||
|
|
|
@ -60,8 +60,6 @@ pub enum TypeOfFile {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_broken_files: usize,
|
pub number_of_broken_files: usize,
|
||||||
pub number_of_removed_files: usize,
|
|
||||||
pub number_of_failed_to_remove_files: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -550,8 +548,6 @@ impl DebugPrint for BrokenFiles {
|
||||||
println!("Errors size - {}", self.text_messages.errors.len());
|
println!("Errors size - {}", self.text_messages.errors.len());
|
||||||
println!("Warnings size - {}", self.text_messages.warnings.len());
|
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||||
println!("Messages size - {}", self.text_messages.messages.len());
|
println!("Messages size - {}", self.text_messages.messages.len());
|
||||||
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!("### Other");
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::common_messages::Messages;
|
||||||
pub struct Directories {
|
pub struct Directories {
|
||||||
pub excluded_directories: Vec<PathBuf>,
|
pub excluded_directories: Vec<PathBuf>,
|
||||||
pub included_directories: Vec<PathBuf>,
|
pub included_directories: Vec<PathBuf>,
|
||||||
|
pub reference_directories: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Directories {
|
impl Directories {
|
||||||
|
@ -15,6 +16,10 @@ impl Directories {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_reference_directory(&mut self, reference_directory: Vec<PathBuf>) {
|
||||||
|
self.reference_directories = reference_directory
|
||||||
|
}
|
||||||
|
|
||||||
/// Setting included directories, at least one must be provided
|
/// Setting included directories, at least one must be provided
|
||||||
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>, text_messages: &mut Messages) -> bool {
|
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>, text_messages: &mut Messages) -> bool {
|
||||||
let start_time: SystemTime = SystemTime::now();
|
let start_time: SystemTime = SystemTime::now();
|
||||||
|
@ -146,15 +151,18 @@ impl Directories {
|
||||||
if cfg!(target_family = "windows") {
|
if cfg!(target_family = "windows") {
|
||||||
self.included_directories = self.included_directories.iter().map(Common::normalize_windows_path).collect();
|
self.included_directories = self.included_directories.iter().map(Common::normalize_windows_path).collect();
|
||||||
self.excluded_directories = self.excluded_directories.iter().map(Common::normalize_windows_path).collect();
|
self.excluded_directories = self.excluded_directories.iter().map(Common::normalize_windows_path).collect();
|
||||||
|
self.reference_directories = self.reference_directories.iter().map(Common::normalize_windows_path).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicated entries like: "/", "/"
|
// Remove duplicated entries like: "/", "/"
|
||||||
|
|
||||||
self.excluded_directories.sort();
|
self.excluded_directories.sort();
|
||||||
self.included_directories.sort();
|
self.included_directories.sort();
|
||||||
|
self.reference_directories.sort();
|
||||||
|
|
||||||
self.excluded_directories.dedup();
|
self.excluded_directories.dedup();
|
||||||
self.included_directories.dedup();
|
self.included_directories.dedup();
|
||||||
|
self.reference_directories.dedup();
|
||||||
|
|
||||||
// Optimize for duplicated included directories - "/", "/home". "/home/Pulpit" to "/"
|
// Optimize for duplicated included directories - "/", "/home". "/home/Pulpit" to "/"
|
||||||
if recursive_search {
|
if recursive_search {
|
||||||
|
@ -251,6 +259,20 @@ impl Directories {
|
||||||
|
|
||||||
self.excluded_directories = optimized_excluded;
|
self.excluded_directories = optimized_excluded;
|
||||||
|
|
||||||
|
// Selecting Reference folders
|
||||||
|
{
|
||||||
|
let mut ref_folders = Vec::new();
|
||||||
|
for folder in &self.reference_directories {
|
||||||
|
if self.included_directories.iter().any(|e| folder.starts_with(&e)) {
|
||||||
|
ref_folders.push(folder.clone());
|
||||||
|
// println!("REF: VALID reference folder {:?}", folder);
|
||||||
|
} else {
|
||||||
|
// println!("REF: Invalid reference folder {:?}", folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.reference_directories = ref_folders;
|
||||||
|
}
|
||||||
|
|
||||||
if self.included_directories.is_empty() {
|
if self.included_directories.is_empty() {
|
||||||
text_messages
|
text_messages
|
||||||
.errors
|
.errors
|
||||||
|
|
|
@ -18,7 +18,8 @@ impl Messages {
|
||||||
if !self.messages.is_empty() {
|
if !self.messages.is_empty() {
|
||||||
text_to_return += "-------------------------------MESSAGES--------------------------------\n";
|
text_to_return += "-------------------------------MESSAGES--------------------------------\n";
|
||||||
for i in &self.messages {
|
for i in &self.messages {
|
||||||
text_to_return += format!("{}\n", i).as_str();
|
text_to_return += i;
|
||||||
|
text_to_return += "\n";
|
||||||
}
|
}
|
||||||
text_to_return += "---------------------------END OF MESSAGES-----------------------------\n";
|
text_to_return += "---------------------------END OF MESSAGES-----------------------------\n";
|
||||||
}
|
}
|
||||||
|
@ -27,7 +28,8 @@ impl Messages {
|
||||||
text_to_return += "-------------------------------WARNINGS--------------------------------\n";
|
text_to_return += "-------------------------------WARNINGS--------------------------------\n";
|
||||||
|
|
||||||
for i in &self.warnings {
|
for i in &self.warnings {
|
||||||
text_to_return += format!("{}\n", i).as_str();
|
text_to_return += i;
|
||||||
|
text_to_return += "\n";
|
||||||
}
|
}
|
||||||
text_to_return += "---------------------------END OF WARNINGS-----------------------------\n";
|
text_to_return += "---------------------------END OF WARNINGS-----------------------------\n";
|
||||||
}
|
}
|
||||||
|
@ -36,7 +38,8 @@ impl Messages {
|
||||||
text_to_return += "--------------------------------ERRORS---------------------------------\n";
|
text_to_return += "--------------------------------ERRORS---------------------------------\n";
|
||||||
|
|
||||||
for i in &self.errors {
|
for i in &self.errors {
|
||||||
text_to_return += format!("{}\n", i).as_str();
|
text_to_return += i;
|
||||||
|
text_to_return += "\n";
|
||||||
}
|
}
|
||||||
text_to_return += "----------------------------END OF ERRORS------------------------------\n";
|
text_to_return += "----------------------------END OF ERRORS------------------------------\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,6 @@ pub struct Info {
|
||||||
pub number_of_duplicated_files_by_name: usize,
|
pub number_of_duplicated_files_by_name: usize,
|
||||||
pub lost_space_by_size: u64,
|
pub lost_space_by_size: u64,
|
||||||
pub lost_space_by_hash: u64,
|
pub lost_space_by_hash: u64,
|
||||||
pub gained_space: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -107,7 +106,10 @@ pub struct DuplicateFinder {
|
||||||
information: Info,
|
information: Info,
|
||||||
files_with_identical_names: BTreeMap<String, Vec<FileEntry>>, // File Size, File Entry
|
files_with_identical_names: BTreeMap<String, Vec<FileEntry>>, // File Size, File Entry
|
||||||
files_with_identical_size: BTreeMap<u64, Vec<FileEntry>>, // File Size, File Entry
|
files_with_identical_size: BTreeMap<u64, Vec<FileEntry>>, // File Size, File Entry
|
||||||
files_with_identical_hashes: BTreeMap<u64, Vec<Vec<FileEntry>>>, // File Size, File Entry
|
files_with_identical_hashes: BTreeMap<u64, Vec<Vec<FileEntry>>>, // File Size, next grouped by file size, next grouped by hash
|
||||||
|
files_with_identical_names_referenced: BTreeMap<String, (FileEntry, Vec<FileEntry>)>, // File Size, File Entry
|
||||||
|
files_with_identical_size_referenced: BTreeMap<u64, (FileEntry, Vec<FileEntry>)>, // File Size, File Entry
|
||||||
|
files_with_identical_hashes_referenced: BTreeMap<u64, Vec<(FileEntry, Vec<FileEntry>)>>, // File Size, next grouped by file size, next grouped by hash
|
||||||
directories: Directories,
|
directories: Directories,
|
||||||
allowed_extensions: Extensions,
|
allowed_extensions: Extensions,
|
||||||
excluded_items: ExcludedItems,
|
excluded_items: ExcludedItems,
|
||||||
|
@ -125,6 +127,7 @@ pub struct DuplicateFinder {
|
||||||
minimal_cache_file_size: u64,
|
minimal_cache_file_size: u64,
|
||||||
minimal_prehash_cache_file_size: u64,
|
minimal_prehash_cache_file_size: u64,
|
||||||
delete_outdated_cache: bool,
|
delete_outdated_cache: bool,
|
||||||
|
use_reference_folders: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DuplicateFinder {
|
impl DuplicateFinder {
|
||||||
|
@ -135,6 +138,9 @@ impl DuplicateFinder {
|
||||||
files_with_identical_names: Default::default(),
|
files_with_identical_names: Default::default(),
|
||||||
files_with_identical_size: Default::default(),
|
files_with_identical_size: Default::default(),
|
||||||
files_with_identical_hashes: Default::default(),
|
files_with_identical_hashes: Default::default(),
|
||||||
|
files_with_identical_names_referenced: Default::default(),
|
||||||
|
files_with_identical_size_referenced: Default::default(),
|
||||||
|
files_with_identical_hashes_referenced: Default::default(),
|
||||||
recursive_search: true,
|
recursive_search: true,
|
||||||
allowed_extensions: Extensions::new(),
|
allowed_extensions: Extensions::new(),
|
||||||
check_method: CheckingMethod::None,
|
check_method: CheckingMethod::None,
|
||||||
|
@ -152,11 +158,13 @@ impl DuplicateFinder {
|
||||||
minimal_cache_file_size: 1024 * 1024 / 4, // By default cache only >= 256 KB files
|
minimal_cache_file_size: 1024 * 1024 / 4, // By default cache only >= 256 KB files
|
||||||
minimal_prehash_cache_file_size: 0,
|
minimal_prehash_cache_file_size: 0,
|
||||||
delete_outdated_cache: true,
|
delete_outdated_cache: true,
|
||||||
|
use_reference_folders: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_duplicates(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
pub fn find_duplicates(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
||||||
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
|
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
|
||||||
|
self.use_reference_folders = !self.directories.reference_directories.is_empty();
|
||||||
|
|
||||||
match self.check_method {
|
match self.check_method {
|
||||||
CheckingMethod::Name => {
|
CheckingMethod::Name => {
|
||||||
|
@ -270,23 +278,43 @@ impl DuplicateFinder {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_use_reference(&self) -> bool {
|
||||||
|
self.use_reference_folders
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_recursive_search(&mut self, recursive_search: bool) {
|
pub fn set_recursive_search(&mut self, recursive_search: bool) {
|
||||||
self.recursive_search = recursive_search;
|
self.recursive_search = recursive_search;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>) -> bool {
|
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>) {
|
||||||
self.directories.set_included_directory(included_directory, &mut self.text_messages)
|
self.directories.set_included_directory(included_directory, &mut self.text_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_reference_directory(&mut self, reference_directory: Vec<PathBuf>) {
|
||||||
|
self.directories.set_reference_directory(reference_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
||||||
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_excluded_items(&mut self, excluded_items: Vec<String>) {
|
||||||
|
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
|
||||||
|
}
|
||||||
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) {
|
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) {
|
||||||
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
|
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_excluded_items(&mut self, excluded_items: Vec<String>) {
|
pub fn get_files_with_identical_hashes_referenced(&self) -> &BTreeMap<u64, Vec<(FileEntry, Vec<FileEntry>)>> {
|
||||||
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
|
&self.files_with_identical_hashes_referenced
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_files_with_identical_name_referenced(&self) -> &BTreeMap<String, (FileEntry, Vec<FileEntry>)> {
|
||||||
|
&self.files_with_identical_names_referenced
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_files_with_identical_size_referenced(&self) -> &BTreeMap<u64, (FileEntry, Vec<FileEntry>)> {
|
||||||
|
&self.files_with_identical_size_referenced
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_files_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
|
fn check_files_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
|
||||||
|
@ -473,13 +501,53 @@ impl DuplicateFinder {
|
||||||
|
|
||||||
for (name, vector) in &self.files_with_identical_names {
|
for (name, vector) in &self.files_with_identical_names {
|
||||||
if vector.len() > 1 {
|
if vector.len() > 1 {
|
||||||
self.information.number_of_duplicated_files_by_name += vector.len() - 1;
|
|
||||||
self.information.number_of_groups_by_name += 1;
|
|
||||||
new_map.insert(name.clone(), vector.clone());
|
new_map.insert(name.clone(), vector.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.files_with_identical_names = new_map;
|
self.files_with_identical_names = new_map;
|
||||||
|
|
||||||
|
// Reference - only use in size, because later hash will be counted differently
|
||||||
|
if self.use_reference_folders {
|
||||||
|
let mut btree_map = Default::default();
|
||||||
|
mem::swap(&mut self.files_with_identical_names, &mut btree_map);
|
||||||
|
let reference_directories = self.directories.reference_directories.clone();
|
||||||
|
let vec = btree_map
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(_size, vec_file_entry)| {
|
||||||
|
let mut files_from_referenced_folders = Vec::new();
|
||||||
|
let mut normal_files = Vec::new();
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
if reference_directories.iter().any(|e| file_entry.path.starts_with(&e)) {
|
||||||
|
files_from_referenced_folders.push(file_entry);
|
||||||
|
} else {
|
||||||
|
normal_files.push(file_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if files_from_referenced_folders.is_empty() || normal_files.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((files_from_referenced_folders.pop().unwrap(), normal_files))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<(FileEntry, Vec<FileEntry>)>>();
|
||||||
|
for (fe, vec_fe) in vec {
|
||||||
|
self.files_with_identical_names_referenced.insert(fe.path.to_string_lossy().to_string(), (fe, vec_fe));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
for (_fe, vector) in self.files_with_identical_names_referenced.values() {
|
||||||
|
self.information.number_of_duplicated_files_by_name += vector.len();
|
||||||
|
self.information.number_of_groups_by_name += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for vector in self.files_with_identical_names.values() {
|
||||||
|
self.information.number_of_duplicated_files_by_name += vector.len() - 1;
|
||||||
|
self.information.number_of_groups_by_name += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Common::print_time(start_time, SystemTime::now(), "check_files_name".to_string());
|
Common::print_time(start_time, SystemTime::now(), "check_files_name".to_string());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -684,10 +752,51 @@ impl DuplicateFinder {
|
||||||
let vector = if self.ignore_hard_links { filter_hard_links(&vec) } else { vec };
|
let vector = if self.ignore_hard_links { filter_hard_links(&vec) } else { vec };
|
||||||
|
|
||||||
if vector.len() > 1 {
|
if vector.len() > 1 {
|
||||||
|
self.files_with_identical_size.insert(size, vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference - only use in size, because later hash will be counted differently
|
||||||
|
if self.use_reference_folders && self.check_method == CheckingMethod::Size {
|
||||||
|
let mut btree_map = Default::default();
|
||||||
|
mem::swap(&mut self.files_with_identical_size, &mut btree_map);
|
||||||
|
let reference_directories = self.directories.reference_directories.clone();
|
||||||
|
let vec = btree_map
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(_size, vec_file_entry)| {
|
||||||
|
let mut files_from_referenced_folders = Vec::new();
|
||||||
|
let mut normal_files = Vec::new();
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
if reference_directories.iter().any(|e| file_entry.path.starts_with(&e)) {
|
||||||
|
files_from_referenced_folders.push(file_entry);
|
||||||
|
} else {
|
||||||
|
normal_files.push(file_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if files_from_referenced_folders.is_empty() || normal_files.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((files_from_referenced_folders.pop().unwrap(), normal_files))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<(FileEntry, Vec<FileEntry>)>>();
|
||||||
|
for (fe, vec_fe) in vec {
|
||||||
|
self.files_with_identical_size_referenced.insert(fe.size, (fe, vec_fe));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
for (size, (_fe, vector)) in &self.files_with_identical_size_referenced {
|
||||||
|
self.information.number_of_duplicated_files_by_size += vector.len();
|
||||||
|
self.information.number_of_groups_by_size += 1;
|
||||||
|
self.information.lost_space_by_size += (vector.len() as u64) * size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size, vector) in &self.files_with_identical_size {
|
||||||
self.information.number_of_duplicated_files_by_size += vector.len() - 1;
|
self.information.number_of_duplicated_files_by_size += vector.len() - 1;
|
||||||
self.information.number_of_groups_by_size += 1;
|
self.information.number_of_groups_by_size += 1;
|
||||||
self.information.lost_space_by_size += (vector.len() as u64 - 1) * size;
|
self.information.lost_space_by_size += (vector.len() as u64 - 1) * size;
|
||||||
self.files_with_identical_size.insert(size, vector);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1036,9 +1145,57 @@ impl DuplicateFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////
|
///////////////////////////////////////////////////////////////////////////// HASHING END
|
||||||
|
|
||||||
|
// Reference - only use in size, because later hash will be counted differently
|
||||||
|
if self.use_reference_folders {
|
||||||
|
let mut btree_map = Default::default();
|
||||||
|
mem::swap(&mut self.files_with_identical_hashes, &mut btree_map);
|
||||||
|
let reference_directories = self.directories.reference_directories.clone();
|
||||||
|
let vec = btree_map
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(_size, vec_vec_file_entry)| {
|
||||||
|
let mut all_results_with_same_size = Vec::new();
|
||||||
|
for vec_file_entry in vec_vec_file_entry {
|
||||||
|
let mut files_from_referenced_folders = Vec::new();
|
||||||
|
let mut normal_files = Vec::new();
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
if reference_directories.iter().any(|e| file_entry.path.starts_with(&e)) {
|
||||||
|
files_from_referenced_folders.push(file_entry);
|
||||||
|
} else {
|
||||||
|
normal_files.push(file_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if files_from_referenced_folders.is_empty() || normal_files.is_empty() {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
all_results_with_same_size.push((files_from_referenced_folders.pop().unwrap(), normal_files))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if all_results_with_same_size.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(all_results_with_same_size)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<Vec<(FileEntry, Vec<FileEntry>)>>>();
|
||||||
|
for vec_of_vec in vec {
|
||||||
|
self.files_with_identical_hashes_referenced.insert(vec_of_vec[0].0.size, vec_of_vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
for (size, vector_vectors) in &self.files_with_identical_hashes_referenced {
|
||||||
|
for (_fe, vector) in vector_vectors {
|
||||||
|
self.information.number_of_duplicated_files_by_hash += vector.len();
|
||||||
|
self.information.number_of_groups_by_hash += 1;
|
||||||
|
self.information.lost_space_by_hash += (vector.len() as u64) * size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (size, vector_vectors) in &self.files_with_identical_hashes {
|
for (size, vector_vectors) in &self.files_with_identical_hashes {
|
||||||
for vector in vector_vectors {
|
for vector in vector_vectors {
|
||||||
self.information.number_of_duplicated_files_by_hash += vector.len() - 1;
|
self.information.number_of_duplicated_files_by_hash += vector.len() - 1;
|
||||||
|
@ -1048,8 +1205,6 @@ impl DuplicateFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////// HASHING END
|
|
||||||
|
|
||||||
Common::print_time(start_time, SystemTime::now(), "check_files_hash - full hash".to_string());
|
Common::print_time(start_time, SystemTime::now(), "check_files_hash - full hash".to_string());
|
||||||
|
|
||||||
// Clean unused data
|
// Clean unused data
|
||||||
|
@ -1069,22 +1224,19 @@ impl DuplicateFinder {
|
||||||
match self.check_method {
|
match self.check_method {
|
||||||
CheckingMethod::Name => {
|
CheckingMethod::Name => {
|
||||||
for vector in self.files_with_identical_names.values() {
|
for vector in self.files_with_identical_names.values() {
|
||||||
let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
|
let _tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
|
||||||
self.information.gained_space += tuple.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckingMethod::Hash => {
|
CheckingMethod::Hash => {
|
||||||
for vector_vectors in self.files_with_identical_hashes.values() {
|
for vector_vectors in self.files_with_identical_hashes.values() {
|
||||||
for vector in vector_vectors.iter() {
|
for vector in vector_vectors.iter() {
|
||||||
let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
|
let _tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
|
||||||
self.information.gained_space += tuple.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckingMethod::Size => {
|
CheckingMethod::Size => {
|
||||||
for vector in self.files_with_identical_size.values() {
|
for vector in self.files_with_identical_size.values() {
|
||||||
let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
|
let _tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
|
||||||
self.information.gained_space += tuple.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckingMethod::None => {
|
CheckingMethod::None => {
|
||||||
|
@ -1140,11 +1292,6 @@ impl DebugPrint for DuplicateFinder {
|
||||||
self.information.lost_space_by_hash.file_size(options::BINARY).unwrap(),
|
self.information.lost_space_by_hash.file_size(options::BINARY).unwrap(),
|
||||||
self.information.lost_space_by_hash
|
self.information.lost_space_by_hash
|
||||||
);
|
);
|
||||||
println!(
|
|
||||||
"Gained space by removing duplicated entries - {} ({} bytes)",
|
|
||||||
self.information.gained_space.file_size(options::BINARY).unwrap(),
|
|
||||||
self.information.gained_space
|
|
||||||
);
|
|
||||||
|
|
||||||
println!("### Other");
|
println!("### Other");
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,6 @@ pub struct FileEntry {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_empty_files: usize,
|
pub number_of_empty_files: usize,
|
||||||
pub number_of_removed_files: usize,
|
|
||||||
pub number_of_failed_to_remove_files: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -350,8 +348,6 @@ impl DebugPrint for EmptyFiles {
|
||||||
println!("Errors size - {}", self.text_messages.errors.len());
|
println!("Errors size - {}", self.text_messages.errors.len());
|
||||||
println!("Warnings size - {}", self.text_messages.warnings.len());
|
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||||
println!("Messages size - {}", self.text_messages.messages.len());
|
println!("Messages size - {}", self.text_messages.messages.len());
|
||||||
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!("### Other");
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,6 @@ pub struct FileEntry {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_invalid_symlinks: usize,
|
pub number_of_invalid_symlinks: usize,
|
||||||
pub number_of_removed_files: usize,
|
|
||||||
pub number_of_failed_to_remove_files: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -400,8 +398,6 @@ impl DebugPrint for InvalidSymlinks {
|
||||||
println!("Errors size - {}", self.text_messages.errors.len());
|
println!("Errors size - {}", self.text_messages.errors.len());
|
||||||
println!("Warnings size - {}", self.text_messages.warnings.len());
|
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||||
println!("Messages size - {}", self.text_messages.messages.len());
|
println!("Messages size - {}", self.text_messages.messages.len());
|
||||||
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!("### Other");
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
use std::{fs, thread};
|
use std::{fs, mem, thread};
|
||||||
|
|
||||||
use audiotags::Tag;
|
use audiotags::Tag;
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
|
@ -71,10 +71,8 @@ pub struct FileEntry {
|
||||||
/// Info struck with helpful information's about results
|
/// Info struck with helpful information's about results
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_music_entries: usize,
|
pub number_of_duplicates: usize,
|
||||||
pub number_of_removed_files: usize,
|
pub number_of_groups: u64,
|
||||||
pub number_of_failed_to_remove_files: usize,
|
|
||||||
pub number_of_duplicates_music_files: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -90,6 +88,7 @@ pub struct SameMusic {
|
||||||
music_to_check: Vec<FileEntry>,
|
music_to_check: Vec<FileEntry>,
|
||||||
music_entries: Vec<FileEntry>,
|
music_entries: Vec<FileEntry>,
|
||||||
duplicated_music_entries: Vec<Vec<FileEntry>>,
|
duplicated_music_entries: Vec<Vec<FileEntry>>,
|
||||||
|
duplicated_music_entries_referenced: Vec<(FileEntry, Vec<FileEntry>)>,
|
||||||
directories: Directories,
|
directories: Directories,
|
||||||
allowed_extensions: Extensions,
|
allowed_extensions: Extensions,
|
||||||
excluded_items: ExcludedItems,
|
excluded_items: ExcludedItems,
|
||||||
|
@ -100,6 +99,7 @@ pub struct SameMusic {
|
||||||
music_similarity: MusicSimilarity,
|
music_similarity: MusicSimilarity,
|
||||||
stopped_search: bool,
|
stopped_search: bool,
|
||||||
approximate_comparison: bool,
|
approximate_comparison: bool,
|
||||||
|
use_reference_folders: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SameMusic {
|
impl SameMusic {
|
||||||
|
@ -120,11 +120,14 @@ impl SameMusic {
|
||||||
duplicated_music_entries: vec![],
|
duplicated_music_entries: vec![],
|
||||||
music_to_check: Vec::with_capacity(2048),
|
music_to_check: Vec::with_capacity(2048),
|
||||||
approximate_comparison: true,
|
approximate_comparison: true,
|
||||||
|
use_reference_folders: false,
|
||||||
|
duplicated_music_entries_referenced: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_same_music(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
pub fn find_same_music(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
||||||
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
|
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
|
||||||
|
self.use_reference_folders = !self.directories.reference_directories.is_empty();
|
||||||
if !self.check_files(stop_receiver, progress_sender) {
|
if !self.check_files(stop_receiver, progress_sender) {
|
||||||
self.stopped_search = true;
|
self.stopped_search = true;
|
||||||
return;
|
return;
|
||||||
|
@ -172,8 +175,13 @@ impl SameMusic {
|
||||||
self.recursive_search = recursive_search;
|
self.recursive_search = recursive_search;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>) -> bool {
|
/// Set included dir which needs to be relative, exists etc.
|
||||||
self.directories.set_included_directory(included_directory, &mut self.text_messages)
|
pub fn set_included_directory(&mut self, included_directory: Vec<PathBuf>) {
|
||||||
|
self.directories.set_included_directory(included_directory, &mut self.text_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_reference_directory(&mut self, reference_directory: Vec<PathBuf>) {
|
||||||
|
self.directories.set_reference_directory(reference_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
||||||
|
@ -183,6 +191,7 @@ impl SameMusic {
|
||||||
pub fn set_excluded_items(&mut self, excluded_items: Vec<String>) {
|
pub fn set_excluded_items(&mut self, excluded_items: Vec<String>) {
|
||||||
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
|
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) {
|
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) {
|
||||||
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
|
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
@ -198,6 +207,22 @@ impl SameMusic {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_similar_music_referenced(&self) -> &Vec<(FileEntry, Vec<FileEntry>)> {
|
||||||
|
&self.duplicated_music_entries_referenced
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_number_of_base_duplicated_files(&self) -> usize {
|
||||||
|
if self.use_reference_folders {
|
||||||
|
self.duplicated_music_entries_referenced.len()
|
||||||
|
} else {
|
||||||
|
self.duplicated_music_entries.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_use_reference(&self) -> bool {
|
||||||
|
self.use_reference_folders
|
||||||
|
}
|
||||||
|
|
||||||
/// Check files for any with size == 0
|
/// Check files for any with size == 0
|
||||||
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
|
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
|
||||||
let start_time: SystemTime = SystemTime::now();
|
let start_time: SystemTime = SystemTime::now();
|
||||||
|
@ -382,7 +407,6 @@ impl SameMusic {
|
||||||
// End thread which send info to gui
|
// End thread which send info to gui
|
||||||
progress_thread_run.store(false, Ordering::Relaxed);
|
progress_thread_run.store(false, Ordering::Relaxed);
|
||||||
progress_thread_handle.join().unwrap();
|
progress_thread_handle.join().unwrap();
|
||||||
self.information.number_of_music_entries = self.music_entries.len();
|
|
||||||
|
|
||||||
Common::print_time(start_time, SystemTime::now(), "check_files".to_string());
|
Common::print_time(start_time, SystemTime::now(), "check_files".to_string());
|
||||||
true
|
true
|
||||||
|
@ -669,15 +693,50 @@ impl SameMusic {
|
||||||
// new_duplicates = Vec::new();
|
// new_duplicates = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.duplicated_music_entries = old_duplicates;
|
|
||||||
|
|
||||||
for vec in &self.duplicated_music_entries {
|
|
||||||
self.information.number_of_duplicates_music_files += vec.len() - 1;
|
|
||||||
}
|
|
||||||
// End thread which send info to gui
|
// End thread which send info to gui
|
||||||
progress_thread_run.store(false, Ordering::Relaxed);
|
progress_thread_run.store(false, Ordering::Relaxed);
|
||||||
progress_thread_handle.join().unwrap();
|
progress_thread_handle.join().unwrap();
|
||||||
|
|
||||||
|
self.duplicated_music_entries = old_duplicates;
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
let mut similars_vector = Default::default();
|
||||||
|
mem::swap(&mut self.duplicated_music_entries, &mut similars_vector);
|
||||||
|
let reference_directories = self.directories.reference_directories.clone();
|
||||||
|
self.duplicated_music_entries_referenced = similars_vector
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|vec_file_entry| {
|
||||||
|
let mut files_from_referenced_folders = Vec::new();
|
||||||
|
let mut normal_files = Vec::new();
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
if reference_directories.iter().any(|e| file_entry.path.starts_with(&e)) {
|
||||||
|
files_from_referenced_folders.push(file_entry);
|
||||||
|
} else {
|
||||||
|
normal_files.push(file_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if files_from_referenced_folders.is_empty() || normal_files.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((files_from_referenced_folders.pop().unwrap(), normal_files))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<(FileEntry, Vec<FileEntry>)>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
for (_fe, vector) in &self.duplicated_music_entries_referenced {
|
||||||
|
self.information.number_of_duplicates += vector.len();
|
||||||
|
self.information.number_of_groups += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for vector in &self.duplicated_music_entries {
|
||||||
|
self.information.number_of_duplicates += vector.len() - 1;
|
||||||
|
self.information.number_of_groups += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Common::print_time(start_time, SystemTime::now(), "check_for_duplicates".to_string());
|
Common::print_time(start_time, SystemTime::now(), "check_for_duplicates".to_string());
|
||||||
|
|
||||||
// Clear unused data
|
// Clear unused data
|
||||||
|
@ -735,9 +794,6 @@ impl DebugPrint for SameMusic {
|
||||||
println!("Errors size - {}", self.text_messages.errors.len());
|
println!("Errors size - {}", self.text_messages.errors.len());
|
||||||
println!("Warnings size - {}", self.text_messages.warnings.len());
|
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||||
println!("Messages size - {}", self.text_messages.messages.len());
|
println!("Messages size - {}", self.text_messages.messages.len());
|
||||||
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!("Number of duplicated music files - {}", self.information.number_of_duplicates_music_files);
|
|
||||||
|
|
||||||
println!("### Other");
|
println!("### Other");
|
||||||
|
|
||||||
|
@ -780,7 +836,7 @@ impl SaveResults for SameMusic {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.music_entries.is_empty() {
|
if !self.music_entries.is_empty() {
|
||||||
writeln!(writer, "Found {} same music files.", self.information.number_of_music_entries).unwrap();
|
writeln!(writer, "Found {} same music files.", self.information.number_of_duplicates).unwrap();
|
||||||
for file_entry in self.music_entries.iter() {
|
for file_entry in self.music_entries.iter() {
|
||||||
writeln!(writer, "{}", file_entry.path.display()).unwrap();
|
writeln!(writer, "{}", file_entry.path.display()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ pub struct SimilarImages {
|
||||||
excluded_items: ExcludedItems,
|
excluded_items: ExcludedItems,
|
||||||
bktree: BKTree<Vec<u8>, Hamming>,
|
bktree: BKTree<Vec<u8>, Hamming>,
|
||||||
similar_vectors: Vec<Vec<FileEntry>>,
|
similar_vectors: Vec<Vec<FileEntry>>,
|
||||||
|
similar_referenced_vectors: Vec<(FileEntry, Vec<FileEntry>)>,
|
||||||
recursive_search: bool,
|
recursive_search: bool,
|
||||||
minimal_file_size: u64,
|
minimal_file_size: u64,
|
||||||
maximal_file_size: u64,
|
maximal_file_size: u64,
|
||||||
|
@ -106,14 +107,14 @@ pub struct SimilarImages {
|
||||||
use_cache: bool,
|
use_cache: bool,
|
||||||
delete_outdated_cache: bool,
|
delete_outdated_cache: bool,
|
||||||
exclude_images_with_same_size: bool,
|
exclude_images_with_same_size: bool,
|
||||||
|
use_reference_folders: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Info struck with helpful information's about results
|
/// Info struck with helpful information's about results
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_removed_files: usize,
|
pub number_of_duplicates: usize,
|
||||||
pub number_of_failed_to_remove_files: usize,
|
pub number_of_groups: u64,
|
||||||
pub gained_space: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -134,6 +135,7 @@ impl SimilarImages {
|
||||||
allowed_extensions: Extensions::new(),
|
allowed_extensions: Extensions::new(),
|
||||||
bktree: BKTree::new(Hamming),
|
bktree: BKTree::new(Hamming),
|
||||||
similar_vectors: vec![],
|
similar_vectors: vec![],
|
||||||
|
similar_referenced_vectors: Default::default(),
|
||||||
recursive_search: true,
|
recursive_search: true,
|
||||||
minimal_file_size: 1024 * 16, // 16 KB should be enough to exclude too small images from search
|
minimal_file_size: 1024 * 16, // 16 KB should be enough to exclude too small images from search
|
||||||
maximal_file_size: u64::MAX,
|
maximal_file_size: u64::MAX,
|
||||||
|
@ -147,6 +149,7 @@ impl SimilarImages {
|
||||||
use_cache: true,
|
use_cache: true,
|
||||||
delete_outdated_cache: true,
|
delete_outdated_cache: true,
|
||||||
exclude_images_with_same_size: false,
|
exclude_images_with_same_size: false,
|
||||||
|
use_reference_folders: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +190,14 @@ impl SimilarImages {
|
||||||
&self.similar_vectors
|
&self.similar_vectors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_similar_images_referenced(&self) -> &Vec<(FileEntry, Vec<FileEntry>)> {
|
||||||
|
&self.similar_referenced_vectors
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_use_reference(&self) -> bool {
|
||||||
|
self.use_reference_folders
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn get_information(&self) -> &Info {
|
pub const fn get_information(&self) -> &Info {
|
||||||
&self.information
|
&self.information
|
||||||
}
|
}
|
||||||
|
@ -221,6 +232,7 @@ impl SimilarImages {
|
||||||
/// Public function used by CLI to search for empty folders
|
/// Public function used by CLI to search for empty folders
|
||||||
pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
||||||
self.directories.optimize_directories(true, &mut self.text_messages);
|
self.directories.optimize_directories(true, &mut self.text_messages);
|
||||||
|
self.use_reference_folders = !self.directories.reference_directories.is_empty();
|
||||||
if !self.check_for_similar_images(stop_receiver, progress_sender) {
|
if !self.check_for_similar_images(stop_receiver, progress_sender) {
|
||||||
self.stopped_search = true;
|
self.stopped_search = true;
|
||||||
return;
|
return;
|
||||||
|
@ -695,8 +707,46 @@ impl SimilarImages {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
let mut similars_vector = Default::default();
|
||||||
|
mem::swap(&mut self.similar_vectors, &mut similars_vector);
|
||||||
|
let reference_directories = self.directories.reference_directories.clone();
|
||||||
|
self.similar_referenced_vectors = similars_vector
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|vec_file_entry| {
|
||||||
|
let mut files_from_referenced_folders = Vec::new();
|
||||||
|
let mut normal_files = Vec::new();
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
if reference_directories.iter().any(|e| file_entry.path.starts_with(&e)) {
|
||||||
|
files_from_referenced_folders.push(file_entry);
|
||||||
|
} else {
|
||||||
|
normal_files.push(file_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if files_from_referenced_folders.is_empty() || normal_files.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((files_from_referenced_folders.pop().unwrap(), normal_files))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<(FileEntry, Vec<FileEntry>)>>();
|
||||||
|
}
|
||||||
|
|
||||||
Common::print_time(hash_map_modification, SystemTime::now(), "sort_images - selecting data from BtreeMap".to_string());
|
Common::print_time(hash_map_modification, SystemTime::now(), "sort_images - selecting data from BtreeMap".to_string());
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
for (_fe, vector) in &self.similar_referenced_vectors {
|
||||||
|
self.information.number_of_duplicates += vector.len();
|
||||||
|
self.information.number_of_groups += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for vector in &self.similar_vectors {
|
||||||
|
self.information.number_of_duplicates += vector.len() - 1;
|
||||||
|
self.information.number_of_groups += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean unused data
|
// Clean unused data
|
||||||
self.image_hashes = Default::default();
|
self.image_hashes = Default::default();
|
||||||
self.images_to_check = Default::default();
|
self.images_to_check = Default::default();
|
||||||
|
@ -710,6 +760,10 @@ impl SimilarImages {
|
||||||
self.directories.set_included_directory(included_directory, &mut self.text_messages);
|
self.directories.set_included_directory(included_directory, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_reference_directory(&mut self, reference_directory: Vec<PathBuf>) {
|
||||||
|
self.directories.set_reference_directory(reference_directory);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
||||||
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub struct SimilarVideos {
|
||||||
excluded_items: ExcludedItems,
|
excluded_items: ExcludedItems,
|
||||||
allowed_extensions: Extensions,
|
allowed_extensions: Extensions,
|
||||||
similar_vectors: Vec<Vec<FileEntry>>,
|
similar_vectors: Vec<Vec<FileEntry>>,
|
||||||
|
similar_referenced_vectors: Vec<(FileEntry, Vec<FileEntry>)>,
|
||||||
recursive_search: bool,
|
recursive_search: bool,
|
||||||
minimal_file_size: u64,
|
minimal_file_size: u64,
|
||||||
maximal_file_size: u64,
|
maximal_file_size: u64,
|
||||||
|
@ -78,14 +79,14 @@ pub struct SimilarVideos {
|
||||||
tolerance: i32,
|
tolerance: i32,
|
||||||
delete_outdated_cache: bool,
|
delete_outdated_cache: bool,
|
||||||
exclude_videos_with_same_size: bool,
|
exclude_videos_with_same_size: bool,
|
||||||
|
use_reference_folders: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Info struck with helpful information's about results
|
/// Info struck with helpful information's about results
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_removed_files: usize,
|
pub number_of_duplicates: usize,
|
||||||
pub number_of_failed_to_remove_files: usize,
|
pub number_of_groups: u64,
|
||||||
pub gained_space: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -115,6 +116,8 @@ impl SimilarVideos {
|
||||||
tolerance: 10,
|
tolerance: 10,
|
||||||
delete_outdated_cache: false,
|
delete_outdated_cache: false,
|
||||||
exclude_videos_with_same_size: false,
|
exclude_videos_with_same_size: false,
|
||||||
|
use_reference_folders: false,
|
||||||
|
similar_referenced_vectors: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +174,21 @@ impl SimilarVideos {
|
||||||
t => t,
|
t => t,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn get_similar_videos_referenced(&self) -> &Vec<(FileEntry, Vec<FileEntry>)> {
|
||||||
|
&self.similar_referenced_vectors
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_number_of_base_duplicated_files(&self) -> usize {
|
||||||
|
if self.use_reference_folders {
|
||||||
|
self.similar_referenced_vectors.len()
|
||||||
|
} else {
|
||||||
|
self.similar_vectors.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_use_reference(&self) -> bool {
|
||||||
|
self.use_reference_folders
|
||||||
|
}
|
||||||
|
|
||||||
/// Public function used by CLI to search for empty folders
|
/// Public function used by CLI to search for empty folders
|
||||||
pub fn find_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
pub fn find_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
|
||||||
|
@ -178,6 +196,7 @@ impl SimilarVideos {
|
||||||
self.text_messages.errors.push("Cannot find proper installation of FFmpeg.".to_string());
|
self.text_messages.errors.push("Cannot find proper installation of FFmpeg.".to_string());
|
||||||
} else {
|
} else {
|
||||||
self.directories.optimize_directories(true, &mut self.text_messages);
|
self.directories.optimize_directories(true, &mut self.text_messages);
|
||||||
|
self.use_reference_folders = !self.directories.reference_directories.is_empty();
|
||||||
if !self.check_for_similar_videos(stop_receiver, progress_sender) {
|
if !self.check_for_similar_videos(stop_receiver, progress_sender) {
|
||||||
self.stopped_search = true;
|
self.stopped_search = true;
|
||||||
return;
|
return;
|
||||||
|
@ -539,6 +558,44 @@ impl SimilarVideos {
|
||||||
|
|
||||||
self.similar_vectors = collected_similar_videos;
|
self.similar_vectors = collected_similar_videos;
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
let mut similars_vector = Default::default();
|
||||||
|
mem::swap(&mut self.similar_vectors, &mut similars_vector);
|
||||||
|
let reference_directories = self.directories.reference_directories.clone();
|
||||||
|
self.similar_referenced_vectors = similars_vector
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|vec_file_entry| {
|
||||||
|
let mut files_from_referenced_folders = Vec::new();
|
||||||
|
let mut normal_files = Vec::new();
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
if reference_directories.iter().any(|e| file_entry.path.starts_with(&e)) {
|
||||||
|
files_from_referenced_folders.push(file_entry);
|
||||||
|
} else {
|
||||||
|
normal_files.push(file_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if files_from_referenced_folders.is_empty() || normal_files.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((files_from_referenced_folders.pop().unwrap(), normal_files))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<(FileEntry, Vec<FileEntry>)>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.use_reference_folders {
|
||||||
|
for (_fe, vector) in &self.similar_referenced_vectors {
|
||||||
|
self.information.number_of_duplicates += vector.len();
|
||||||
|
self.information.number_of_groups += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for vector in &self.similar_vectors {
|
||||||
|
self.information.number_of_duplicates += vector.len() - 1;
|
||||||
|
self.information.number_of_groups += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Common::print_time(hash_map_modification, SystemTime::now(), "sort_videos - selecting data from BtreeMap".to_string());
|
Common::print_time(hash_map_modification, SystemTime::now(), "sort_videos - selecting data from BtreeMap".to_string());
|
||||||
|
|
||||||
// Clean unused data
|
// Clean unused data
|
||||||
|
@ -553,6 +610,10 @@ impl SimilarVideos {
|
||||||
self.directories.set_included_directory(included_directory, &mut self.text_messages);
|
self.directories.set_included_directory(included_directory, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_reference_directory(&mut self, reference_directory: Vec<PathBuf>) {
|
||||||
|
self.directories.set_reference_directory(reference_directory);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
pub fn set_excluded_directory(&mut self, excluded_directory: Vec<PathBuf>) {
|
||||||
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,6 @@ pub struct FileEntry {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub number_of_temporary_files: usize,
|
pub number_of_temporary_files: usize,
|
||||||
pub number_of_removed_files: usize,
|
|
||||||
pub number_of_failed_to_remove_files: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Info {
|
impl Info {
|
||||||
|
@ -357,8 +355,6 @@ impl DebugPrint for Temporary {
|
||||||
println!("Errors size - {}", self.text_messages.errors.len());
|
println!("Errors size - {}", self.text_messages.errors.len());
|
||||||
println!("Warnings size - {}", self.text_messages.warnings.len());
|
println!("Warnings size - {}", self.text_messages.warnings.len());
|
||||||
println!("Messages size - {}", self.text_messages.messages.len());
|
println!("Messages size - {}", self.text_messages.messages.len());
|
||||||
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!("### Other");
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ use crate::gui_data::GuiData;
|
||||||
use crate::help_combo_box::IMAGES_HASH_SIZE_COMBO_BOX;
|
use crate::help_combo_box::IMAGES_HASH_SIZE_COMBO_BOX;
|
||||||
use crate::help_functions::*;
|
use crate::help_functions::*;
|
||||||
use crate::notebook_enums::*;
|
use crate::notebook_enums::*;
|
||||||
|
use crate::opening_selecting_records::*;
|
||||||
|
use czkawka_core::localizer::generate_translation_hashmap;
|
||||||
|
|
||||||
pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<Message>) {
|
pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<Message>) {
|
||||||
let combo_box_image_hash_size = gui_data.main_notebook.combo_box_image_hash_size.clone();
|
let combo_box_image_hash_size = gui_data.main_notebook.combo_box_image_hash_size.clone();
|
||||||
|
@ -76,6 +78,12 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
if df.get_stopped_search() {
|
if df.get_stopped_search() {
|
||||||
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
||||||
} else {
|
} else {
|
||||||
|
if df.get_use_reference() {
|
||||||
|
tree_view_duplicate_finder.selection().set_select_function(Some(Box::new(select_function_always_true)));
|
||||||
|
} else {
|
||||||
|
tree_view_duplicate_finder.selection().set_select_function(Some(Box::new(select_function_duplicates)));
|
||||||
|
}
|
||||||
|
|
||||||
let information = df.get_information();
|
let information = df.get_information();
|
||||||
let text_messages = df.get_text_messages();
|
let text_messages = df.get_text_messages();
|
||||||
|
|
||||||
|
@ -83,31 +91,31 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
let duplicates_size: u64;
|
let duplicates_size: u64;
|
||||||
let duplicates_group: usize;
|
let duplicates_group: usize;
|
||||||
|
|
||||||
let fl_found = fl!("compute_found");
|
|
||||||
let fl_groups = fl!("compute_groups");
|
|
||||||
let fl_groups_which_took = fl!("compute_groups_which_took");
|
|
||||||
let fl_duplicated_files_in = fl!("compute_duplicated_files_in");
|
|
||||||
|
|
||||||
match df.get_check_method() {
|
match df.get_check_method() {
|
||||||
CheckingMethod::Name => {
|
CheckingMethod::Name => {
|
||||||
duplicates_number = information.number_of_duplicated_files_by_name;
|
duplicates_number = information.number_of_duplicated_files_by_name;
|
||||||
// duplicates_size = 0;
|
// duplicates_size = 0;
|
||||||
duplicates_group = information.number_of_groups_by_name;
|
duplicates_group = information.number_of_groups_by_name;
|
||||||
entry_info.set_text(format!("{} {} {} {} {}", fl_found, duplicates_number, fl_duplicated_files_in, duplicates_group, fl_groups).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_duplicates_name",
|
||||||
|
generate_translation_hashmap(vec![("number_files", duplicates_number.to_string()), ("number_groups", duplicates_group.to_string())])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
CheckingMethod::Hash => {
|
CheckingMethod::Hash => {
|
||||||
duplicates_number = information.number_of_duplicated_files_by_hash;
|
duplicates_number = information.number_of_duplicated_files_by_hash;
|
||||||
duplicates_size = information.lost_space_by_hash;
|
duplicates_size = information.lost_space_by_hash;
|
||||||
duplicates_group = information.number_of_groups_by_hash;
|
duplicates_group = information.number_of_groups_by_hash;
|
||||||
entry_info.set_text(
|
entry_info.set_text(
|
||||||
format!(
|
fl!(
|
||||||
"{} {} {} {} {} {}.",
|
"compute_found_duplicates_hash_size",
|
||||||
fl_found,
|
generate_translation_hashmap(vec![
|
||||||
duplicates_number,
|
("number_files", duplicates_number.to_string()),
|
||||||
fl_duplicated_files_in,
|
("number_groups", duplicates_group.to_string()),
|
||||||
duplicates_group,
|
("size", duplicates_size.file_size(options::BINARY).unwrap())
|
||||||
fl_groups_which_took,
|
])
|
||||||
duplicates_size.file_size(options::BINARY).unwrap()
|
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
@ -117,14 +125,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
duplicates_size = information.lost_space_by_size;
|
duplicates_size = information.lost_space_by_size;
|
||||||
duplicates_group = information.number_of_groups_by_size;
|
duplicates_group = information.number_of_groups_by_size;
|
||||||
entry_info.set_text(
|
entry_info.set_text(
|
||||||
format!(
|
fl!(
|
||||||
"{} {} {} {} {} {}.",
|
"compute_found_duplicates_hash_size",
|
||||||
fl_found,
|
generate_translation_hashmap(vec![
|
||||||
duplicates_number,
|
("number_files", duplicates_number.to_string()),
|
||||||
fl_duplicated_files_in,
|
("number_groups", duplicates_group.to_string()),
|
||||||
duplicates_group,
|
("size", duplicates_size.file_size(options::BINARY).unwrap())
|
||||||
fl_groups_which_took,
|
])
|
||||||
duplicates_size.file_size(options::BINARY).unwrap()
|
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
@ -138,11 +145,12 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
{
|
{
|
||||||
let list_store = get_list_store(&tree_view_duplicate_finder);
|
let list_store = get_list_store(&tree_view_duplicate_finder);
|
||||||
|
|
||||||
|
if df.get_use_reference() {
|
||||||
match df.get_check_method() {
|
match df.get_check_method() {
|
||||||
CheckingMethod::Name => {
|
CheckingMethod::Name => {
|
||||||
let btreemap = df.get_files_sorted_by_names();
|
let btreemap = df.get_files_with_identical_name_referenced();
|
||||||
|
|
||||||
for (name, vector) in btreemap.iter().rev() {
|
for (_name, (base_file_entry, vector)) in btreemap.iter().rev() {
|
||||||
// Sort
|
// Sort
|
||||||
let vector = if vector.len() >= 2 {
|
let vector = if vector.len() >= 2 {
|
||||||
let mut vector = vector.clone();
|
let mut vector = vector.clone();
|
||||||
|
@ -155,10 +163,195 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
vector.clone()
|
vector.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let values: [(u32, &dyn ToValue); 8] = [
|
// HEADER
|
||||||
|
let (directory, file) = split_path(&base_file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
||||||
(ColumnsDuplicates::SelectionButton as u32, &false),
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
(ColumnsDuplicates::Name as u32, &name),
|
(ColumnsDuplicates::Size as u32, (&base_file_entry.size.file_size(options::BINARY).unwrap())),
|
||||||
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsDuplicates::Modification as u32,
|
||||||
|
&(format!(
|
||||||
|
"{} - ({})",
|
||||||
|
NaiveDateTime::from_timestamp(base_file_entry.modified_date as i64, 0),
|
||||||
|
base_file_entry.size.file_size(options::BINARY).unwrap()
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(base_file_entry.modified_date)),
|
||||||
|
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsDuplicates::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
|
||||||
|
// MEAT
|
||||||
|
for entry in vector {
|
||||||
|
let (directory, file) = split_path(&entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
||||||
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&entry.size.file_size(options::BINARY).unwrap())),
|
||||||
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsDuplicates::Modification as u32,
|
||||||
|
&(format!(
|
||||||
|
"{} - ({})",
|
||||||
|
NaiveDateTime::from_timestamp(entry.modified_date as i64, 0),
|
||||||
|
entry.size.file_size(options::BINARY).unwrap()
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(entry.modified_date)),
|
||||||
|
(ColumnsDuplicates::Color as u32, &(MAIN_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsDuplicates::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CheckingMethod::Hash => {
|
||||||
|
let btreemap = df.get_files_with_identical_hashes_referenced();
|
||||||
|
|
||||||
|
for (_size, vectors_vector) in btreemap.iter().rev() {
|
||||||
|
for (base_file_entry, vector) in vectors_vector {
|
||||||
|
// Sort
|
||||||
|
let vector = if vector.len() >= 2 {
|
||||||
|
let mut vector = vector.clone();
|
||||||
|
vector.sort_by_key(|e| {
|
||||||
|
let t = split_path(e.path.as_path());
|
||||||
|
(t.0, t.1)
|
||||||
|
});
|
||||||
|
vector
|
||||||
|
} else {
|
||||||
|
vector.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// HEADER
|
||||||
|
let (directory, file) = split_path(&base_file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&base_file_entry.size.file_size(options::BINARY).unwrap())),
|
||||||
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsDuplicates::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(base_file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(base_file_entry.modified_date)),
|
||||||
|
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsDuplicates::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
|
||||||
|
// MEAT
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
for entry in vector {
|
||||||
|
let (directory, file) = split_path(&entry.path);
|
||||||
|
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
||||||
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&entry.size.file_size(options::BINARY).unwrap())),
|
||||||
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsDuplicates::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(entry.modified_date)),
|
||||||
|
(ColumnsDuplicates::Color as u32, &(MAIN_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsDuplicates::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CheckingMethod::Size => {
|
||||||
|
let btreemap = df.get_files_with_identical_size_referenced();
|
||||||
|
|
||||||
|
for (_size, (base_file_entry, vector)) in btreemap.iter().rev() {
|
||||||
|
// Sort
|
||||||
|
let vector = if vector.len() >= 2 {
|
||||||
|
let mut vector = vector.clone();
|
||||||
|
vector.sort_by_key(|e| {
|
||||||
|
let t = split_path(e.path.as_path());
|
||||||
|
(t.0, t.1)
|
||||||
|
});
|
||||||
|
vector
|
||||||
|
} else {
|
||||||
|
vector.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// HEADER
|
||||||
|
let (directory, file) = split_path(&base_file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&base_file_entry.size.file_size(options::BINARY).unwrap())),
|
||||||
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsDuplicates::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(base_file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(base_file_entry.modified_date)),
|
||||||
|
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsDuplicates::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
|
||||||
|
// MEAT
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
for entry in vector {
|
||||||
|
let (directory, file) = split_path(&entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
||||||
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&entry.size.file_size(options::BINARY).unwrap())),
|
||||||
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsDuplicates::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(entry.modified_date)),
|
||||||
|
(ColumnsDuplicates::Color as u32, &(MAIN_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsDuplicates::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CheckingMethod::None => {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match df.get_check_method() {
|
||||||
|
CheckingMethod::Name => {
|
||||||
|
let btreemap = df.get_files_sorted_by_names();
|
||||||
|
|
||||||
|
for (_name, vector) in btreemap.iter().rev() {
|
||||||
|
// Sort
|
||||||
|
let vector = if vector.len() >= 2 {
|
||||||
|
let mut vector = vector.clone();
|
||||||
|
vector.sort_by_key(|e| {
|
||||||
|
let t = split_path(e.path.as_path());
|
||||||
|
(t.0, t.1)
|
||||||
|
});
|
||||||
|
vector
|
||||||
|
} else {
|
||||||
|
vector.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&"".to_string())),
|
||||||
|
(ColumnsDuplicates::Name as u32, (&"".to_string())),
|
||||||
(ColumnsDuplicates::Path as u32, (&(format!("{} results", vector.len())))),
|
(ColumnsDuplicates::Path as u32, (&(format!("{} results", vector.len())))),
|
||||||
(ColumnsDuplicates::Modification as u32, (&"".to_string())), // No text in 3 column
|
(ColumnsDuplicates::Modification as u32, (&"".to_string())), // No text in 3 column
|
||||||
(ColumnsDuplicates::ModificationAsSecs as u32, (&(0))), // Not used here
|
(ColumnsDuplicates::ModificationAsSecs as u32, (&(0))), // Not used here
|
||||||
|
@ -169,9 +362,10 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
for entry in vector {
|
for entry in vector {
|
||||||
let (directory, file) = split_path(&entry.path);
|
let (directory, file) = split_path(&entry.path);
|
||||||
let values: [(u32, &dyn ToValue); 8] = [
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
||||||
(ColumnsDuplicates::SelectionButton as u32, &false),
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&entry.size.file_size(options::BINARY).unwrap())),
|
||||||
(ColumnsDuplicates::Name as u32, &file),
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
(ColumnsDuplicates::Path as u32, &directory),
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
(
|
(
|
||||||
|
@ -193,7 +387,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
CheckingMethod::Hash => {
|
CheckingMethod::Hash => {
|
||||||
let btreemap = df.get_files_sorted_by_hash();
|
let btreemap = df.get_files_sorted_by_hash();
|
||||||
|
|
||||||
for (size, vectors_vector) in btreemap.iter().rev() {
|
for (_size, vectors_vector) in btreemap.iter().rev() {
|
||||||
for vector in vectors_vector {
|
for vector in vectors_vector {
|
||||||
// Sort
|
// Sort
|
||||||
let vector = if vector.len() >= 2 {
|
let vector = if vector.len() >= 2 {
|
||||||
|
@ -207,23 +401,12 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
vector.clone()
|
vector.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let values: [(u32, &dyn ToValue); 8] = [
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
||||||
(ColumnsDuplicates::SelectionButton as u32, &false),
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
(
|
(ColumnsDuplicates::Size as u32, (&"".to_string())),
|
||||||
ColumnsDuplicates::Name as u32,
|
(ColumnsDuplicates::Name as u32, (&"".to_string())),
|
||||||
&(format!("{} x {} ({} {})", vector.len(), size.file_size(options::BINARY).unwrap(), size, fl!("general_bytes"))),
|
(ColumnsDuplicates::Path as u32, (&"".to_string())),
|
||||||
),
|
|
||||||
(
|
|
||||||
ColumnsDuplicates::Path as u32,
|
|
||||||
&(format!(
|
|
||||||
"{} ({} {}) {}",
|
|
||||||
((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(),
|
|
||||||
(vector.len() - 1) as u64 * *size as u64,
|
|
||||||
fl!("general_bytes"),
|
|
||||||
fl!("general_lost")
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
(ColumnsDuplicates::Modification as u32, &"".to_string()), // No text in 3 column
|
(ColumnsDuplicates::Modification as u32, &"".to_string()), // No text in 3 column
|
||||||
(ColumnsDuplicates::ModificationAsSecs as u32, &(0)),
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(0)),
|
||||||
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
@ -234,9 +417,10 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
for entry in vector {
|
for entry in vector {
|
||||||
let (directory, file) = split_path(&entry.path);
|
let (directory, file) = split_path(&entry.path);
|
||||||
|
|
||||||
let values: [(u32, &dyn ToValue); 8] = [
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
||||||
(ColumnsDuplicates::SelectionButton as u32, &false),
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&entry.size.file_size(options::BINARY).unwrap())),
|
||||||
(ColumnsDuplicates::Name as u32, &file),
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
(ColumnsDuplicates::Path as u32, &directory),
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
(
|
(
|
||||||
|
@ -256,7 +440,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
CheckingMethod::Size => {
|
CheckingMethod::Size => {
|
||||||
let btreemap = df.get_files_sorted_by_size();
|
let btreemap = df.get_files_sorted_by_size();
|
||||||
|
|
||||||
for (size, vector) in btreemap.iter().rev() {
|
for (_size, vector) in btreemap.iter().rev() {
|
||||||
// Sort
|
// Sort
|
||||||
let vector = if vector.len() >= 2 {
|
let vector = if vector.len() >= 2 {
|
||||||
let mut vector = vector.clone();
|
let mut vector = vector.clone();
|
||||||
|
@ -268,23 +452,12 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
} else {
|
} else {
|
||||||
vector.clone()
|
vector.clone()
|
||||||
};
|
};
|
||||||
let values: [(u32, &dyn ToValue); 8] = [
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
|
||||||
(ColumnsDuplicates::SelectionButton as u32, &false),
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
(
|
(ColumnsDuplicates::Size as u32, (&"".to_string())),
|
||||||
ColumnsDuplicates::Name as u32,
|
(ColumnsDuplicates::Name as u32, (&"".to_string())),
|
||||||
&(format!("{} x {} ({} {})", vector.len(), size.file_size(options::BINARY).unwrap(), size, fl!("general_bytes"))),
|
(ColumnsDuplicates::Path as u32, (&"".to_string())),
|
||||||
),
|
|
||||||
(
|
|
||||||
ColumnsDuplicates::Path as u32,
|
|
||||||
&(format!(
|
|
||||||
"{} ({} {}) {}",
|
|
||||||
((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(),
|
|
||||||
(vector.len() - 1) as u64 * *size as u64,
|
|
||||||
fl!("general_bytes"),
|
|
||||||
fl!("general_lost")
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
(ColumnsDuplicates::Modification as u32, &"".to_string()), // No text in 3 column
|
(ColumnsDuplicates::Modification as u32, &"".to_string()), // No text in 3 column
|
||||||
(ColumnsDuplicates::ModificationAsSecs as u32, &(0)), // Not used here
|
(ColumnsDuplicates::ModificationAsSecs as u32, &(0)), // Not used here
|
||||||
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
(ColumnsDuplicates::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
@ -294,9 +467,10 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
for entry in vector {
|
for entry in vector {
|
||||||
let (directory, file) = split_path(&entry.path);
|
let (directory, file) = split_path(&entry.path);
|
||||||
let values: [(u32, &dyn ToValue); 8] = [
|
let values: [(u32, &dyn ToValue); 9] = [
|
||||||
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
(ColumnsDuplicates::ActivatableSelectButton as u32, &true),
|
||||||
(ColumnsDuplicates::SelectionButton as u32, &false),
|
(ColumnsDuplicates::SelectionButton as u32, &false),
|
||||||
|
(ColumnsDuplicates::Size as u32, (&entry.size.file_size(options::BINARY).unwrap())),
|
||||||
(ColumnsDuplicates::Name as u32, &file),
|
(ColumnsDuplicates::Name as u32, &file),
|
||||||
(ColumnsDuplicates::Path as u32, &directory),
|
(ColumnsDuplicates::Path as u32, &directory),
|
||||||
(
|
(
|
||||||
|
@ -315,7 +489,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +521,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
|
|
||||||
let empty_folder_number: usize = information.number_of_empty_folders;
|
let empty_folder_number: usize = information.number_of_empty_folders;
|
||||||
|
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), empty_folder_number, fl!("compute_empty_folders")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_empty_folders",
|
||||||
|
generate_translation_hashmap(vec![("number_files", empty_folder_number.to_string()),])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
|
@ -406,7 +586,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
|
|
||||||
let empty_files_number: usize = information.number_of_empty_files;
|
let empty_files_number: usize = information.number_of_empty_files;
|
||||||
|
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), empty_files_number, fl!("compute_empty_files")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_empty_files",
|
||||||
|
generate_translation_hashmap(vec![("number_files", empty_files_number.to_string()),])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
|
@ -466,7 +652,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
|
|
||||||
let biggest_files_number: usize = information.number_of_real_files;
|
let biggest_files_number: usize = information.number_of_real_files;
|
||||||
|
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), biggest_files_number, fl!("compute_biggest_files")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_big_files",
|
||||||
|
generate_translation_hashmap(vec![("number_files", biggest_files_number.to_string()),])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
|
@ -530,7 +722,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
let text_messages = tf.get_text_messages();
|
let text_messages = tf.get_text_messages();
|
||||||
|
|
||||||
let temporary_files_number: usize = information.number_of_temporary_files;
|
let temporary_files_number: usize = information.number_of_temporary_files;
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), temporary_files_number, fl!("compute_temporary_files")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_temporary_files",
|
||||||
|
generate_translation_hashmap(vec![("number_files", temporary_files_number.to_string()),])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
|
@ -585,18 +783,25 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
if sf.get_stopped_search() {
|
if sf.get_stopped_search() {
|
||||||
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
||||||
} else {
|
} else {
|
||||||
//let information = sf.get_information();
|
if sf.get_use_reference() {
|
||||||
|
tree_view_similar_images_finder.selection().set_select_function(Some(Box::new(select_function_always_true)));
|
||||||
|
} else {
|
||||||
|
tree_view_similar_images_finder
|
||||||
|
.selection()
|
||||||
|
.set_select_function(Some(Box::new(select_function_similar_images)));
|
||||||
|
}
|
||||||
|
let information = sf.get_information();
|
||||||
let text_messages = sf.get_text_messages();
|
let text_messages = sf.get_text_messages();
|
||||||
|
|
||||||
let base_images_size = sf.get_similar_images().len();
|
let found_any_duplicates = information.number_of_duplicates > 0;
|
||||||
|
|
||||||
entry_info.set_text(
|
entry_info.set_text(
|
||||||
format!(
|
fl!(
|
||||||
"{} {} {} {}.",
|
"compute_found_images",
|
||||||
fl!("compute_found"),
|
generate_translation_hashmap(vec![
|
||||||
fl!("compute_duplicates_for"),
|
("number_files", information.number_of_duplicates.to_string()),
|
||||||
base_images_size,
|
("number_groups", information.number_of_groups.to_string()),
|
||||||
fl!("compute_similar_image")
|
])
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
@ -605,8 +810,71 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
{
|
{
|
||||||
let list_store = get_list_store(&tree_view_similar_images_finder);
|
let list_store = get_list_store(&tree_view_similar_images_finder);
|
||||||
|
|
||||||
let vec_struct_similar = sf.get_similar_images();
|
if sf.get_use_reference() {
|
||||||
|
let vec_struct_similar: &Vec<(czkawka_core::similar_images::FileEntry, Vec<czkawka_core::similar_images::FileEntry>)> =
|
||||||
|
sf.get_similar_images_referenced();
|
||||||
|
for (base_file_entry, vec_file_entry) in vec_struct_similar.iter() {
|
||||||
|
// Sort
|
||||||
|
let vec_file_entry = if vec_file_entry.len() >= 2 {
|
||||||
|
let mut vec_file_entry = vec_file_entry.clone();
|
||||||
|
vec_file_entry.sort_by_key(|e| {
|
||||||
|
let t = split_path(e.path.as_path());
|
||||||
|
(t.0, t.1)
|
||||||
|
});
|
||||||
|
vec_file_entry
|
||||||
|
} else {
|
||||||
|
vec_file_entry.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Header
|
||||||
|
let (directory, file) = split_path(&base_file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 12] = [
|
||||||
|
(ColumnsSimilarImages::ActivatableSelectButton as u32, &false),
|
||||||
|
(ColumnsSimilarImages::SelectionButton as u32, &false),
|
||||||
|
(ColumnsSimilarImages::Similarity as u32, &"".to_string()),
|
||||||
|
(ColumnsSimilarImages::Size as u32, &base_file_entry.size.file_size(options::BINARY).unwrap()),
|
||||||
|
(ColumnsSimilarImages::SizeAsBytes as u32, &base_file_entry.size),
|
||||||
|
(ColumnsSimilarImages::Dimensions as u32, &base_file_entry.dimensions),
|
||||||
|
(ColumnsSimilarImages::Name as u32, &file),
|
||||||
|
(ColumnsSimilarImages::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsSimilarImages::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(base_file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSimilarImages::ModificationAsSecs as u32, &(base_file_entry.modified_date)),
|
||||||
|
(ColumnsSimilarImages::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsSimilarImages::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
|
||||||
|
// Meat
|
||||||
|
for file_entry in vec_file_entry.iter() {
|
||||||
|
let (directory, file) = split_path(&file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 12] = [
|
||||||
|
(ColumnsSimilarImages::ActivatableSelectButton as u32, &true),
|
||||||
|
(ColumnsSimilarImages::SelectionButton as u32, &false),
|
||||||
|
(
|
||||||
|
ColumnsSimilarImages::Similarity as u32,
|
||||||
|
&(similar_images::get_string_from_similarity(&file_entry.similarity, hash_size).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSimilarImages::Size as u32, &file_entry.size.file_size(options::BINARY).unwrap()),
|
||||||
|
(ColumnsSimilarImages::SizeAsBytes as u32, &file_entry.size),
|
||||||
|
(ColumnsSimilarImages::Dimensions as u32, &file_entry.dimensions),
|
||||||
|
(ColumnsSimilarImages::Name as u32, &file),
|
||||||
|
(ColumnsSimilarImages::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsSimilarImages::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSimilarImages::ModificationAsSecs as u32, &(file_entry.modified_date)),
|
||||||
|
(ColumnsSimilarImages::Color as u32, &(MAIN_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsSimilarImages::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let vec_struct_similar = sf.get_similar_images();
|
||||||
for vec_file_entry in vec_struct_similar.iter() {
|
for vec_file_entry in vec_struct_similar.iter() {
|
||||||
// Sort
|
// Sort
|
||||||
let vec_file_entry = if vec_file_entry.len() >= 2 {
|
let vec_file_entry = if vec_file_entry.len() >= 2 {
|
||||||
|
@ -663,6 +931,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||||
}
|
}
|
||||||
|
@ -675,7 +944,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
&shared_buttons,
|
&shared_buttons,
|
||||||
&NotebookMainEnum::SimilarImages,
|
&NotebookMainEnum::SimilarImages,
|
||||||
&["save", "delete", "select", "symlink", "hardlink", "move"],
|
&["save", "delete", "select", "symlink", "hardlink", "move"],
|
||||||
base_images_size > 0,
|
found_any_duplicates,
|
||||||
);
|
);
|
||||||
|
|
||||||
set_buttons(
|
set_buttons(
|
||||||
|
@ -690,18 +959,24 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
if ff.get_stopped_search() {
|
if ff.get_stopped_search() {
|
||||||
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
||||||
} else {
|
} else {
|
||||||
//let information = ff.get_information();
|
if ff.get_use_reference() {
|
||||||
|
tree_view_similar_videos_finder.selection().set_select_function(Some(Box::new(select_function_always_true)));
|
||||||
|
} else {
|
||||||
|
tree_view_similar_videos_finder
|
||||||
|
.selection()
|
||||||
|
.set_select_function(Some(Box::new(select_function_similar_videos)));
|
||||||
|
}
|
||||||
|
let information = ff.get_information();
|
||||||
let text_messages = ff.get_text_messages();
|
let text_messages = ff.get_text_messages();
|
||||||
|
let found_any_duplicates = information.number_of_duplicates > 0;
|
||||||
let base_videos_size = ff.get_similar_videos().len();
|
|
||||||
|
|
||||||
entry_info.set_text(
|
entry_info.set_text(
|
||||||
format!(
|
fl!(
|
||||||
"{} {} {} {}.",
|
"compute_found_videos",
|
||||||
fl!("compute_found"),
|
generate_translation_hashmap(vec![
|
||||||
fl!("compute_duplicates_for"),
|
("number_files", information.number_of_duplicates.to_string()),
|
||||||
base_videos_size,
|
("number_groups", information.number_of_groups.to_string()),
|
||||||
fl!("compute_similar_videos")
|
])
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
@ -710,6 +985,63 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
{
|
{
|
||||||
let list_store = get_list_store(&tree_view_similar_videos_finder);
|
let list_store = get_list_store(&tree_view_similar_videos_finder);
|
||||||
|
|
||||||
|
if ff.get_use_reference() {
|
||||||
|
let vec_struct_similar = ff.get_similar_videos_referenced();
|
||||||
|
|
||||||
|
for (base_file_entry, vec_file_entry) in vec_struct_similar.iter() {
|
||||||
|
// Sort
|
||||||
|
let vec_file_entry = if vec_file_entry.len() >= 2 {
|
||||||
|
let mut vec_file_entry = vec_file_entry.clone();
|
||||||
|
vec_file_entry.sort_by_key(|e| {
|
||||||
|
let t = split_path(e.path.as_path());
|
||||||
|
(t.0, t.1)
|
||||||
|
});
|
||||||
|
vec_file_entry
|
||||||
|
} else {
|
||||||
|
vec_file_entry.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Header
|
||||||
|
let (directory, file) = split_path(&base_file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 10] = [
|
||||||
|
(ColumnsSimilarVideos::ActivatableSelectButton as u32, &false),
|
||||||
|
(ColumnsSimilarVideos::SelectionButton as u32, &false),
|
||||||
|
(ColumnsSimilarVideos::Size as u32, &base_file_entry.size.file_size(options::BINARY).unwrap()),
|
||||||
|
(ColumnsSimilarVideos::SizeAsBytes as u32, &base_file_entry.size),
|
||||||
|
(ColumnsSimilarVideos::Name as u32, &file),
|
||||||
|
(ColumnsSimilarVideos::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsSimilarVideos::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(base_file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSimilarVideos::ModificationAsSecs as u32, &(base_file_entry.modified_date)),
|
||||||
|
(ColumnsSimilarVideos::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsSimilarVideos::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
|
||||||
|
// Meat
|
||||||
|
for file_entry in vec_file_entry.iter() {
|
||||||
|
let (directory, file) = split_path(&file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 10] = [
|
||||||
|
(ColumnsSimilarVideos::ActivatableSelectButton as u32, &true),
|
||||||
|
(ColumnsSimilarVideos::SelectionButton as u32, &false),
|
||||||
|
(ColumnsSimilarVideos::Size as u32, &file_entry.size.file_size(options::BINARY).unwrap()),
|
||||||
|
(ColumnsSimilarVideos::SizeAsBytes as u32, &file_entry.size),
|
||||||
|
(ColumnsSimilarVideos::Name as u32, &file),
|
||||||
|
(ColumnsSimilarVideos::Path as u32, &directory),
|
||||||
|
(
|
||||||
|
ColumnsSimilarVideos::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSimilarVideos::ModificationAsSecs as u32, &(file_entry.modified_date)),
|
||||||
|
(ColumnsSimilarVideos::Color as u32, &(MAIN_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsSimilarVideos::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let vec_struct_similar = ff.get_similar_videos();
|
let vec_struct_similar = ff.get_similar_videos();
|
||||||
|
|
||||||
for vec_file_entry in vec_struct_similar.iter() {
|
for vec_file_entry in vec_struct_similar.iter() {
|
||||||
|
@ -761,6 +1093,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||||
}
|
}
|
||||||
|
@ -773,7 +1106,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
&shared_buttons,
|
&shared_buttons,
|
||||||
&NotebookMainEnum::SimilarVideos,
|
&NotebookMainEnum::SimilarVideos,
|
||||||
&["save", "delete", "select", "symlink", "hardlink", "move"],
|
&["save", "delete", "select", "symlink", "hardlink", "move"],
|
||||||
base_videos_size > 0,
|
found_any_duplicates,
|
||||||
);
|
);
|
||||||
|
|
||||||
set_buttons(
|
set_buttons(
|
||||||
|
@ -788,19 +1121,32 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
if mf.get_stopped_search() {
|
if mf.get_stopped_search() {
|
||||||
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
entry_info.set_text(&fl!("compute_stopped_by_user"));
|
||||||
} else {
|
} else {
|
||||||
|
if mf.get_use_reference() {
|
||||||
|
tree_view_same_music_finder.selection().set_select_function(Some(Box::new(select_function_always_true)));
|
||||||
|
} else {
|
||||||
|
tree_view_same_music_finder.selection().set_select_function(Some(Box::new(select_function_same_music)));
|
||||||
|
}
|
||||||
|
|
||||||
let information = mf.get_information();
|
let information = mf.get_information();
|
||||||
let text_messages = mf.get_text_messages();
|
let text_messages = mf.get_text_messages();
|
||||||
|
|
||||||
let same_music_number: usize = information.number_of_duplicates_music_files;
|
let same_music_number: usize = information.number_of_duplicates;
|
||||||
|
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), same_music_number, fl!("compute_music_files")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_music",
|
||||||
|
generate_translation_hashmap(vec![
|
||||||
|
("number_files", information.number_of_duplicates.to_string()),
|
||||||
|
("number_groups", information.number_of_groups.to_string()),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
let list_store = get_list_store(&tree_view_same_music_finder);
|
let list_store = get_list_store(&tree_view_same_music_finder);
|
||||||
|
|
||||||
let vector = mf.get_duplicated_music_entries();
|
|
||||||
|
|
||||||
let music_similarity = *mf.get_music_similarity();
|
let music_similarity = *mf.get_music_similarity();
|
||||||
|
|
||||||
let is_title = (MusicSimilarity::TITLE & music_similarity) != MusicSimilarity::NONE;
|
let is_title = (MusicSimilarity::TITLE & music_similarity) != MusicSimilarity::NONE;
|
||||||
|
@ -809,6 +1155,72 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
let is_album_artist = (MusicSimilarity::ALBUM_ARTIST & music_similarity) != MusicSimilarity::NONE;
|
let is_album_artist = (MusicSimilarity::ALBUM_ARTIST & music_similarity) != MusicSimilarity::NONE;
|
||||||
let is_year = (MusicSimilarity::YEAR & music_similarity) != MusicSimilarity::NONE;
|
let is_year = (MusicSimilarity::YEAR & music_similarity) != MusicSimilarity::NONE;
|
||||||
|
|
||||||
|
if mf.get_use_reference() {
|
||||||
|
let vector = mf.get_similar_music_referenced();
|
||||||
|
|
||||||
|
for (base_file_entry, vec_file_entry) in vector {
|
||||||
|
// Sort
|
||||||
|
let vec_file_entry = if vec_file_entry.len() >= 2 {
|
||||||
|
let mut vec_file_entry = vec_file_entry.clone();
|
||||||
|
vec_file_entry.sort_by_key(|e| {
|
||||||
|
let t = split_path(e.path.as_path());
|
||||||
|
(t.0, t.1)
|
||||||
|
});
|
||||||
|
vec_file_entry
|
||||||
|
} else {
|
||||||
|
vec_file_entry.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (directory, file) = split_path(&base_file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 15] = [
|
||||||
|
(ColumnsSameMusic::ActivatableSelectButton as u32, &false),
|
||||||
|
(ColumnsSameMusic::SelectionButton as u32, &false),
|
||||||
|
(ColumnsSameMusic::Size as u32, &base_file_entry.size.file_size(options::BINARY).unwrap()),
|
||||||
|
(ColumnsSameMusic::SizeAsBytes as u32, &base_file_entry.size),
|
||||||
|
(ColumnsSameMusic::Name as u32, &file),
|
||||||
|
(ColumnsSameMusic::Path as u32, &directory),
|
||||||
|
(ColumnsSameMusic::Title as u32, &base_file_entry.title),
|
||||||
|
(ColumnsSameMusic::Artist as u32, &base_file_entry.artist),
|
||||||
|
(ColumnsSameMusic::AlbumTitle as u32, &base_file_entry.album_title),
|
||||||
|
(ColumnsSameMusic::AlbumArtist as u32, &base_file_entry.album_artist),
|
||||||
|
(ColumnsSameMusic::Year as u32, &base_file_entry.year.to_string()),
|
||||||
|
(
|
||||||
|
ColumnsSameMusic::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(base_file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSameMusic::ModificationAsSecs as u32, &(base_file_entry.modified_date)),
|
||||||
|
(ColumnsSameMusic::Color as u32, &(HEADER_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsSameMusic::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
for file_entry in vec_file_entry {
|
||||||
|
let (directory, file) = split_path(&file_entry.path);
|
||||||
|
let values: [(u32, &dyn ToValue); 15] = [
|
||||||
|
(ColumnsSameMusic::ActivatableSelectButton as u32, &true),
|
||||||
|
(ColumnsSameMusic::SelectionButton as u32, &false),
|
||||||
|
(ColumnsSameMusic::Size as u32, &file_entry.size.file_size(options::BINARY).unwrap()),
|
||||||
|
(ColumnsSameMusic::SizeAsBytes as u32, &file_entry.size),
|
||||||
|
(ColumnsSameMusic::Name as u32, &file),
|
||||||
|
(ColumnsSameMusic::Path as u32, &directory),
|
||||||
|
(ColumnsSameMusic::Title as u32, &file_entry.title),
|
||||||
|
(ColumnsSameMusic::Artist as u32, &file_entry.artist),
|
||||||
|
(ColumnsSameMusic::AlbumTitle as u32, &file_entry.album_title),
|
||||||
|
(ColumnsSameMusic::AlbumArtist as u32, &file_entry.album_artist),
|
||||||
|
(ColumnsSameMusic::Year as u32, &file_entry.year.to_string()),
|
||||||
|
(
|
||||||
|
ColumnsSameMusic::Modification as u32,
|
||||||
|
&(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string()),
|
||||||
|
),
|
||||||
|
(ColumnsSameMusic::ModificationAsSecs as u32, &(file_entry.modified_date)),
|
||||||
|
(ColumnsSameMusic::Color as u32, &(MAIN_ROW_COLOR.to_string())),
|
||||||
|
(ColumnsSameMusic::TextColor as u32, &(TEXT_COLOR.to_string())),
|
||||||
|
];
|
||||||
|
list_store.set(&list_store.append(), &values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let vector = mf.get_duplicated_music_entries();
|
||||||
|
|
||||||
let text: String = "-----".to_string();
|
let text: String = "-----".to_string();
|
||||||
|
|
||||||
for vec_file_entry in vector {
|
for vec_file_entry in vector {
|
||||||
|
@ -897,6 +1309,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
print_text_messages_to_text_view(text_messages, &text_view_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,7 +1341,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
|
|
||||||
let invalid_symlinks: usize = information.number_of_invalid_symlinks;
|
let invalid_symlinks: usize = information.number_of_invalid_symlinks;
|
||||||
|
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), invalid_symlinks, fl!("compute_symlinks")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_invalid_symlinks",
|
||||||
|
generate_translation_hashmap(vec![("number_files", invalid_symlinks.to_string()),])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
|
@ -986,7 +1405,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
|
||||||
|
|
||||||
let broken_files_number: usize = information.number_of_broken_files;
|
let broken_files_number: usize = information.number_of_broken_files;
|
||||||
|
|
||||||
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), broken_files_number, fl!("compute_broken_files")).as_str());
|
entry_info.set_text(
|
||||||
|
fl!(
|
||||||
|
"compute_found_broken_files",
|
||||||
|
generate_translation_hashmap(vec![("number_files", broken_files_number.to_string()),])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create GUI
|
// Create GUI
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub async fn delete_things(gui_data: GuiData) {
|
||||||
tree_view,
|
tree_view,
|
||||||
column_color,
|
column_color,
|
||||||
nb_object.column_selection,
|
nb_object.column_selection,
|
||||||
|
nb_object.column_path,
|
||||||
&window_main,
|
&window_main,
|
||||||
&check_button_settings_confirm_group_deletion,
|
&check_button_settings_confirm_group_deletion,
|
||||||
)
|
)
|
||||||
|
@ -201,6 +202,7 @@ pub async fn check_if_deleting_all_files_in_group(
|
||||||
tree_view: >k::TreeView,
|
tree_view: >k::TreeView,
|
||||||
column_color: i32,
|
column_color: i32,
|
||||||
column_selection: i32,
|
column_selection: i32,
|
||||||
|
column_path: i32,
|
||||||
window_main: >k::Window,
|
window_main: >k::Window,
|
||||||
check_button_settings_confirm_group_deletion: >k::CheckButton,
|
check_button_settings_confirm_group_deletion: >k::CheckButton,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -211,6 +213,11 @@ pub async fn check_if_deleting_all_files_in_group(
|
||||||
if let Some(iter) = model.iter_first() {
|
if let Some(iter) = model.iter_first() {
|
||||||
assert_eq!(model.value(&iter, column_color).get::<String>().unwrap(), HEADER_ROW_COLOR); // First element should be header
|
assert_eq!(model.value(&iter, column_color).get::<String>().unwrap(), HEADER_ROW_COLOR); // First element should be header
|
||||||
|
|
||||||
|
// It is safe to remove any number of files in reference mode
|
||||||
|
if !model.value(&iter, column_path).get::<String>().unwrap().is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if !model.iter_next(&iter) {
|
if !model.iter_next(&iter) {
|
||||||
break;
|
break;
|
||||||
|
@ -523,7 +530,7 @@ pub fn tree_remove(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_invalid_headers(&model, column_color);
|
clean_invalid_headers(&model, column_color, column_path);
|
||||||
|
|
||||||
text_view_errors.buffer().unwrap().set_text(messages.as_str());
|
text_view_errors.buffer().unwrap().set_text(messages.as_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,7 +253,7 @@ pub fn hardlink_symlink(
|
||||||
model.remove(&model.iter(tree_path).unwrap());
|
model.remove(&model.iter(tree_path).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_invalid_headers(&model, column_color);
|
clean_invalid_headers(&model, column_color, column_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dialog_non_group(window_main: >k::Window) -> Dialog {
|
fn create_dialog_non_group(window_main: >k::Window) -> Dialog {
|
||||||
|
|
|
@ -175,7 +175,7 @@ fn move_with_tree(
|
||||||
|
|
||||||
move_files_common(&selected_rows, &model, column_file_name, column_path, &destination_folder, entry_info, text_view_errors);
|
move_files_common(&selected_rows, &model, column_file_name, column_path, &destination_folder, entry_info, text_view_errors);
|
||||||
|
|
||||||
clean_invalid_headers(&model, column_color);
|
clean_invalid_headers(&model, column_color, column_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_with_list(
|
fn move_with_list(
|
||||||
|
|
|
@ -72,6 +72,7 @@ pub fn connect_button_search(
|
||||||
let entry_settings_prehash_cache_file_minimal_size = gui_data.settings.entry_settings_prehash_cache_file_minimal_size.clone();
|
let entry_settings_prehash_cache_file_minimal_size = gui_data.settings.entry_settings_prehash_cache_file_minimal_size.clone();
|
||||||
let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone();
|
let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone();
|
||||||
let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone();
|
let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone();
|
||||||
|
let image_preview_duplicates = gui_data.main_notebook.image_preview_duplicates.clone();
|
||||||
let label_stage = gui_data.progress_window.label_stage.clone();
|
let label_stage = gui_data.progress_window.label_stage.clone();
|
||||||
let notebook_main = gui_data.main_notebook.notebook_main.clone();
|
let notebook_main = gui_data.main_notebook.notebook_main.clone();
|
||||||
let notebook_upper = gui_data.upper_notebook.notebook_upper.clone();
|
let notebook_upper = gui_data.upper_notebook.notebook_upper.clone();
|
||||||
|
@ -102,8 +103,13 @@ pub fn connect_button_search(
|
||||||
let check_button_music_approximate_comparison = gui_data.main_notebook.check_button_music_approximate_comparison.clone();
|
let check_button_music_approximate_comparison = gui_data.main_notebook.check_button_music_approximate_comparison.clone();
|
||||||
|
|
||||||
buttons_search_clone.connect_clicked(move |_| {
|
buttons_search_clone.connect_clicked(move |_| {
|
||||||
let included_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(&tree_view_included_directories));
|
let included_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(&tree_view_included_directories, ColumnsIncludedDirectory::Path as i32, None));
|
||||||
let excluded_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(&tree_view_excluded_directories));
|
let excluded_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(&tree_view_excluded_directories, ColumnsExcludedDirectory::Path as i32, None));
|
||||||
|
let reference_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(
|
||||||
|
&tree_view_included_directories,
|
||||||
|
ColumnsIncludedDirectory::Path as i32,
|
||||||
|
Some(ColumnsIncludedDirectory::ReferenceButton as i32),
|
||||||
|
));
|
||||||
let recursive_search = check_button_recursive.is_active();
|
let recursive_search = check_button_recursive.is_active();
|
||||||
let excluded_items = entry_excluded_items.text().as_str().to_string().split(',').map(|e| e.to_string()).collect::<Vec<String>>();
|
let excluded_items = entry_excluded_items.text().as_str().to_string().split(',').map(|e| e.to_string()).collect::<Vec<String>>();
|
||||||
let allowed_extensions = entry_allowed_extensions.text().as_str().to_string();
|
let allowed_extensions = entry_allowed_extensions.text().as_str().to_string();
|
||||||
|
@ -111,6 +117,9 @@ pub fn connect_button_search(
|
||||||
let use_cache = check_button_settings_use_cache.is_active();
|
let use_cache = check_button_settings_use_cache.is_active();
|
||||||
let minimal_cache_file_size = entry_settings_cache_file_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 / 4);
|
let minimal_cache_file_size = entry_settings_cache_file_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 / 4);
|
||||||
|
|
||||||
|
let minimal_file_size = entry_general_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 8);
|
||||||
|
let maximal_file_size = entry_general_maximal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 * 1024 * 1024);
|
||||||
|
|
||||||
let show_dialog = Arc::new(AtomicBool::new(true));
|
let show_dialog = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
hide_all_buttons(&buttons_array);
|
hide_all_buttons(&buttons_array);
|
||||||
|
@ -133,6 +142,8 @@ pub fn connect_button_search(
|
||||||
|
|
||||||
match to_notebook_main_enum(notebook_main.current_page().unwrap()) {
|
match to_notebook_main_enum(notebook_main.current_page().unwrap()) {
|
||||||
NotebookMainEnum::Duplicate => {
|
NotebookMainEnum::Duplicate => {
|
||||||
|
image_preview_duplicates.hide();
|
||||||
|
|
||||||
label_stage.show();
|
label_stage.show();
|
||||||
grid_progress_stages.show_all();
|
grid_progress_stages.show_all();
|
||||||
window_progress.resize(1, 1);
|
window_progress.resize(1, 1);
|
||||||
|
@ -145,9 +156,6 @@ pub fn connect_button_search(
|
||||||
let hash_type_index = combo_box_duplicate_hash_type.active().unwrap() as usize;
|
let hash_type_index = combo_box_duplicate_hash_type.active().unwrap() as usize;
|
||||||
let hash_type = DUPLICATES_HASH_TYPE_COMBO_BOX[hash_type_index].hash_type;
|
let hash_type = DUPLICATES_HASH_TYPE_COMBO_BOX[hash_type_index].hash_type;
|
||||||
|
|
||||||
let minimal_file_size = entry_general_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 8);
|
|
||||||
let maximal_file_size = entry_general_maximal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 * 1024 * 1024);
|
|
||||||
|
|
||||||
let use_prehash_cache = check_button_duplicates_use_prehash_cache.is_active();
|
let use_prehash_cache = check_button_duplicates_use_prehash_cache.is_active();
|
||||||
let minimal_prehash_cache_file_size = entry_settings_prehash_cache_file_minimal_size.text().as_str().parse::<u64>().unwrap_or(0);
|
let minimal_prehash_cache_file_size = entry_settings_prehash_cache_file_minimal_size.text().as_str().parse::<u64>().unwrap_or(0);
|
||||||
|
|
||||||
|
@ -159,6 +167,7 @@ pub fn connect_button_search(
|
||||||
let mut df = DuplicateFinder::new();
|
let mut df = DuplicateFinder::new();
|
||||||
df.set_included_directory(included_directories);
|
df.set_included_directory(included_directories);
|
||||||
df.set_excluded_directory(excluded_directories);
|
df.set_excluded_directory(excluded_directories);
|
||||||
|
df.set_reference_directory(reference_directories);
|
||||||
df.set_recursive_search(recursive_search);
|
df.set_recursive_search(recursive_search);
|
||||||
df.set_excluded_items(excluded_items);
|
df.set_excluded_items(excluded_items);
|
||||||
df.set_allowed_extensions(allowed_extensions);
|
df.set_allowed_extensions(allowed_extensions);
|
||||||
|
@ -277,9 +286,6 @@ pub fn connect_button_search(
|
||||||
let hash_alg_index = combo_box_image_hash_algorithm.active().unwrap() as usize;
|
let hash_alg_index = combo_box_image_hash_algorithm.active().unwrap() as usize;
|
||||||
let hash_alg = IMAGES_HASH_TYPE_COMBO_BOX[hash_alg_index].hash_alg;
|
let hash_alg = IMAGES_HASH_TYPE_COMBO_BOX[hash_alg_index].hash_alg;
|
||||||
|
|
||||||
let minimal_file_size = entry_general_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 16);
|
|
||||||
let maximal_file_size = entry_general_maximal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 * 1024 * 1024);
|
|
||||||
|
|
||||||
let ignore_same_size = check_button_image_ignore_same_size.is_active();
|
let ignore_same_size = check_button_image_ignore_same_size.is_active();
|
||||||
|
|
||||||
let similarity = similar_images::Similarity::Similar(scale_similarity_similar_images.value() as u32);
|
let similarity = similar_images::Similarity::Similar(scale_similarity_similar_images.value() as u32);
|
||||||
|
@ -293,6 +299,7 @@ pub fn connect_button_search(
|
||||||
|
|
||||||
sf.set_included_directory(included_directories);
|
sf.set_included_directory(included_directories);
|
||||||
sf.set_excluded_directory(excluded_directories);
|
sf.set_excluded_directory(excluded_directories);
|
||||||
|
sf.set_reference_directory(reference_directories);
|
||||||
sf.set_recursive_search(recursive_search);
|
sf.set_recursive_search(recursive_search);
|
||||||
sf.set_excluded_items(excluded_items);
|
sf.set_excluded_items(excluded_items);
|
||||||
sf.set_minimal_file_size(minimal_file_size);
|
sf.set_minimal_file_size(minimal_file_size);
|
||||||
|
@ -316,9 +323,6 @@ pub fn connect_button_search(
|
||||||
|
|
||||||
get_list_store(&tree_view_similar_videos_finder).clear();
|
get_list_store(&tree_view_similar_videos_finder).clear();
|
||||||
|
|
||||||
let minimal_file_size = entry_general_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 16);
|
|
||||||
let maximal_file_size = entry_general_maximal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 * 1024 * 1024);
|
|
||||||
|
|
||||||
let tolerance = scale_similarity_similar_videos.value() as i32;
|
let tolerance = scale_similarity_similar_videos.value() as i32;
|
||||||
|
|
||||||
let delete_outdated_cache = check_button_settings_similar_videos_delete_outdated_cache.is_active();
|
let delete_outdated_cache = check_button_settings_similar_videos_delete_outdated_cache.is_active();
|
||||||
|
@ -332,6 +336,7 @@ pub fn connect_button_search(
|
||||||
|
|
||||||
sf.set_included_directory(included_directories);
|
sf.set_included_directory(included_directories);
|
||||||
sf.set_excluded_directory(excluded_directories);
|
sf.set_excluded_directory(excluded_directories);
|
||||||
|
sf.set_reference_directory(reference_directories);
|
||||||
sf.set_recursive_search(recursive_search);
|
sf.set_recursive_search(recursive_search);
|
||||||
sf.set_excluded_items(excluded_items);
|
sf.set_excluded_items(excluded_items);
|
||||||
sf.set_minimal_file_size(minimal_file_size);
|
sf.set_minimal_file_size(minimal_file_size);
|
||||||
|
@ -352,8 +357,6 @@ pub fn connect_button_search(
|
||||||
|
|
||||||
get_list_store(&tree_view_same_music_finder).clear();
|
get_list_store(&tree_view_same_music_finder).clear();
|
||||||
|
|
||||||
let minimal_file_size = entry_general_minimal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 8);
|
|
||||||
let maximal_file_size = entry_general_maximal_size.text().as_str().parse::<u64>().unwrap_or(1024 * 1024 * 1024 * 1024);
|
|
||||||
let approximate_comparison = check_button_music_approximate_comparison.is_active();
|
let approximate_comparison = check_button_music_approximate_comparison.is_active();
|
||||||
|
|
||||||
let mut music_similarity: MusicSimilarity = MusicSimilarity::NONE;
|
let mut music_similarity: MusicSimilarity = MusicSimilarity::NONE;
|
||||||
|
@ -382,6 +385,7 @@ pub fn connect_button_search(
|
||||||
|
|
||||||
mf.set_included_directory(included_directories);
|
mf.set_included_directory(included_directories);
|
||||||
mf.set_excluded_directory(excluded_directories);
|
mf.set_excluded_directory(excluded_directories);
|
||||||
|
mf.set_reference_directory(reference_directories);
|
||||||
mf.set_excluded_items(excluded_items);
|
mf.set_excluded_items(excluded_items);
|
||||||
mf.set_minimal_file_size(minimal_file_size);
|
mf.set_minimal_file_size(minimal_file_size);
|
||||||
mf.set_maximal_file_size(maximal_file_size);
|
mf.set_maximal_file_size(maximal_file_size);
|
||||||
|
|
|
@ -45,18 +45,18 @@ pub fn load_system_language(gui_data: &GuiData) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut found: bool = false;
|
// let mut found: bool = false;
|
||||||
for (index, lang) in LANGUAGES_ALL.iter().enumerate() {
|
for (index, lang) in LANGUAGES_ALL.iter().enumerate() {
|
||||||
if lang.short_text == short_lang {
|
if lang.short_text == short_lang {
|
||||||
found = true;
|
// found = true;
|
||||||
gui_data.settings.combo_box_settings_language.set_active(Some(index as u32));
|
gui_data.settings.combo_box_settings_language.set_active(Some(index as u32));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found {
|
// if found {
|
||||||
println!("INFO: Default system language {} is available, so choosing them", short_lang);
|
// println!("INFO: Default system language {} is available, so choosing them", short_lang);
|
||||||
} else {
|
// } else {
|
||||||
println!("INFO: Default system language {} is not available, using English(en) instead", short_lang);
|
// println!("INFO: Default system language {} is not available, using English(en) instead", short_lang);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,13 @@ pub fn connect_duplicate_combo_box(gui_data: &GuiData) {
|
||||||
let combo_box_duplicate_check_method = gui_data.main_notebook.combo_box_duplicate_check_method.clone();
|
let combo_box_duplicate_check_method = gui_data.main_notebook.combo_box_duplicate_check_method.clone();
|
||||||
let combo_box_duplicate_hash_type = gui_data.main_notebook.combo_box_duplicate_hash_type.clone();
|
let combo_box_duplicate_hash_type = gui_data.main_notebook.combo_box_duplicate_hash_type.clone();
|
||||||
combo_box_duplicate_check_method.connect_changed(move |combo_box_duplicate_check_method| {
|
combo_box_duplicate_check_method.connect_changed(move |combo_box_duplicate_check_method| {
|
||||||
let chosen_index = combo_box_duplicate_check_method.active().unwrap() as usize;
|
// None active can be if when adding elements(this signal is activated when e.g. adding new fields or removing them)
|
||||||
if DUPLICATES_CHECK_METHOD_COMBO_BOX[chosen_index].check_method == CheckingMethod::Hash {
|
if let Some(chosen_index) = combo_box_duplicate_check_method.active() {
|
||||||
|
if DUPLICATES_CHECK_METHOD_COMBO_BOX[chosen_index as usize].check_method == CheckingMethod::Hash {
|
||||||
combo_box_duplicate_hash_type.set_sensitive(true);
|
combo_box_duplicate_hash_type.set_sensitive(true);
|
||||||
} else {
|
} else {
|
||||||
combo_box_duplicate_hash_type.set_sensitive(false);
|
combo_box_duplicate_hash_type.set_sensitive(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use czkawka_core::common::Common;
|
||||||
use czkawka_core::fl;
|
use czkawka_core::fl;
|
||||||
|
|
||||||
use crate::gui_data::GuiData;
|
use crate::gui_data::GuiData;
|
||||||
use crate::help_functions::{get_dialog_box_child, get_list_store, ColumnsDirectory};
|
use crate::help_functions::{get_dialog_box_child, get_list_store, ColumnsIncludedDirectory};
|
||||||
|
|
||||||
pub fn connect_selection_of_directories(gui_data: &GuiData) {
|
pub fn connect_selection_of_directories(gui_data: &GuiData) {
|
||||||
// Add manually directory
|
// Add manually directory
|
||||||
|
@ -120,7 +120,10 @@ fn add_chosen_directories(window_main: &Window, tree_view: &TreeView, excluded_i
|
||||||
let list_store = get_list_store(&tree_view);
|
let list_store = get_list_store(&tree_view);
|
||||||
|
|
||||||
for file_entry in &folders {
|
for file_entry in &folders {
|
||||||
let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &file_entry.to_string_lossy().to_string())];
|
let values: [(u32, &dyn ToValue); 2] = [
|
||||||
|
(ColumnsIncludedDirectory::Path as u32, &file_entry.to_string_lossy().to_string()),
|
||||||
|
(ColumnsIncludedDirectory::ReferenceButton as u32, &false),
|
||||||
|
];
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +157,7 @@ fn add_manually_directories(window_main: &Window, tree_view: &TreeView) {
|
||||||
if !text.is_empty() {
|
if !text.is_empty() {
|
||||||
let list_store = get_list_store(&tree_view);
|
let list_store = get_list_store(&tree_view);
|
||||||
|
|
||||||
let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &text)];
|
let values: [(u32, &dyn ToValue); 2] = [(ColumnsIncludedDirectory::Path as u32, &text), (ColumnsIncludedDirectory::ReferenceButton as u32, &false)];
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,46 @@ use gtk::TreeViewColumn;
|
||||||
|
|
||||||
use crate::help_functions::*;
|
use crate::help_functions::*;
|
||||||
|
|
||||||
|
// When adding new column do not forget to update translations
|
||||||
|
|
||||||
|
pub fn create_tree_view_included_directories(tree_view: >k::TreeView) {
|
||||||
|
let model = get_list_store(tree_view);
|
||||||
|
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::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 = gtk::CellRendererToggle::new();
|
||||||
|
renderer.connect_toggled(move |_r, path| {
|
||||||
|
let iter = model.iter(&path).unwrap();
|
||||||
|
let mut fixed = model
|
||||||
|
.value(&iter, ColumnsIncludedDirectory::ReferenceButton as i32)
|
||||||
|
.get::<bool>()
|
||||||
|
.unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err));
|
||||||
|
fixed = !fixed;
|
||||||
|
model.set_value(&iter, ColumnsIncludedDirectory::ReferenceButton as u32, &fixed.to_value());
|
||||||
|
});
|
||||||
|
renderer.set_activatable(true);
|
||||||
|
let column = gtk::TreeViewColumn::new();
|
||||||
|
column.set_title("Reference folder");
|
||||||
|
column.pack_start(&renderer, true);
|
||||||
|
column.add_attribute(&renderer, "active", ColumnsIncludedDirectory::ReferenceButton as i32);
|
||||||
|
tree_view.append_column(&column);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_tree_view_excluded_directories(tree_view: >k::TreeView) {
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::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);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_tree_view_duplicates(tree_view: >k::TreeView) {
|
pub fn create_tree_view_duplicates(tree_view: >k::TreeView) {
|
||||||
let model = get_list_store(tree_view);
|
let model = get_list_store(tree_view);
|
||||||
|
|
||||||
|
@ -25,6 +65,17 @@ pub fn create_tree_view_duplicates(tree_view: >k::TreeView) {
|
||||||
column.add_attribute(&renderer, "cell-background", ColumnsDuplicates::Color as i32);
|
column.add_attribute(&renderer, "cell-background", ColumnsDuplicates::Color as i32);
|
||||||
tree_view.append_column(&column);
|
tree_view.append_column(&column);
|
||||||
|
|
||||||
|
let renderer = gtk::CellRendererText::new();
|
||||||
|
let column: gtk::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 = gtk::CellRendererText::new();
|
let renderer = gtk::CellRendererText::new();
|
||||||
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
||||||
column.pack_start(&renderer, true);
|
column.pack_start(&renderer, true);
|
||||||
|
@ -443,16 +494,6 @@ pub fn create_tree_view_similar_videos(tree_view: >k::TreeView) {
|
||||||
tree_view.set_vexpand(true);
|
tree_view.set_vexpand(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_tree_view_directories(tree_view: >k::TreeView) {
|
|
||||||
let renderer = gtk::CellRendererText::new();
|
|
||||||
let column: gtk::TreeViewColumn = TreeViewColumn::new();
|
|
||||||
column.pack_start(&renderer, true);
|
|
||||||
column.add_attribute(&renderer, "text", ColumnsDirectory::Path as i32);
|
|
||||||
tree_view.append_column(&column);
|
|
||||||
|
|
||||||
tree_view.set_headers_visible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_tree_view_same_music(tree_view: >k::TreeView) {
|
pub fn create_tree_view_same_music(tree_view: >k::TreeView) {
|
||||||
let model = get_list_store(tree_view);
|
let model = get_list_store(tree_view);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
use czkawka_core::duplicate::CheckingMethod;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{EventControllerKey, TreeView};
|
use gtk::{EventControllerKey, TreeView};
|
||||||
|
|
||||||
use czkawka_core::similar_images::{get_string_from_similarity, Similarity, SIMILAR_VALUES};
|
use czkawka_core::similar_images::{get_string_from_similarity, Similarity, SIMILAR_VALUES};
|
||||||
|
|
||||||
use crate::fl;
|
use crate::fl;
|
||||||
use crate::help_combo_box::IMAGES_HASH_SIZE_COMBO_BOX;
|
use crate::help_combo_box::{DUPLICATES_CHECK_METHOD_COMBO_BOX, IMAGES_HASH_SIZE_COMBO_BOX};
|
||||||
use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
|
use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -406,6 +407,7 @@ impl GuiMainNotebook {
|
||||||
// Change names of columns
|
// Change names of columns
|
||||||
let names_of_columns = [
|
let names_of_columns = [
|
||||||
vec![
|
vec![
|
||||||
|
fl!("main_tree_view_column_size"),
|
||||||
fl!("main_tree_view_column_file_name"),
|
fl!("main_tree_view_column_file_name"),
|
||||||
fl!("main_tree_view_column_path"),
|
fl!("main_tree_view_column_path"),
|
||||||
fl!("main_tree_view_column_modification"),
|
fl!("main_tree_view_column_modification"),
|
||||||
|
@ -479,5 +481,22 @@ impl GuiMainNotebook {
|
||||||
column.set_title(&names_of_columns[notebook_index][column_index - 1]);
|
column.set_title(&names_of_columns[notebook_index][column_index - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let active = self.combo_box_duplicate_check_method.active().unwrap_or(0);
|
||||||
|
self.combo_box_duplicate_check_method.remove_all();
|
||||||
|
for i in &DUPLICATES_CHECK_METHOD_COMBO_BOX {
|
||||||
|
let text = match i.check_method {
|
||||||
|
CheckingMethod::Hash => fl!("duplicate_mode_hash_combo_box"),
|
||||||
|
CheckingMethod::Size => fl!("duplicate_mode_size_combo_box"),
|
||||||
|
CheckingMethod::Name => fl!("duplicate_mode_name_combo_box"),
|
||||||
|
_ => {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.combo_box_duplicate_check_method.append_text(&text);
|
||||||
|
}
|
||||||
|
self.combo_box_duplicate_check_method.set_active(Some(active));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,5 +164,15 @@ impl GuiUpperNotebook {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_text(&fl_thing);
|
.set_text(&fl_thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let names_of_columns = [
|
||||||
|
vec![fl!("upper_tree_view_included_folder_column_title"), fl!("upper_tree_view_included_reference_column_title")], // Included folders
|
||||||
|
];
|
||||||
|
|
||||||
|
for (notebook_index, tree_view) in [self.tree_view_included_directories.clone()].iter().enumerate() {
|
||||||
|
for (column_index, column) in tree_view.columns().iter().enumerate() {
|
||||||
|
column.set_title(&names_of_columns[notebook_index][column_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use czkawka_core::similar_videos::SimilarVideos;
|
||||||
use czkawka_core::temporary::Temporary;
|
use czkawka_core::temporary::Temporary;
|
||||||
use czkawka_core::{fl, invalid_symlinks};
|
use czkawka_core::{fl, invalid_symlinks};
|
||||||
|
|
||||||
use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
|
use crate::notebook_enums::{NotebookMainEnum, NotebookUpperEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
|
||||||
|
|
||||||
#[cfg(not(target_family = "windows"))]
|
#[cfg(not(target_family = "windows"))]
|
||||||
pub const CHARACTER: char = '/';
|
pub const CHARACTER: char = '/';
|
||||||
|
@ -69,8 +69,8 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
|
||||||
column_selection: ColumnsDuplicates::SelectionButton as i32,
|
column_selection: ColumnsDuplicates::SelectionButton as i32,
|
||||||
column_color: Some(ColumnsDuplicates::Color as i32),
|
column_color: Some(ColumnsDuplicates::Color as i32),
|
||||||
column_dimensions: None,
|
column_dimensions: None,
|
||||||
column_size: None,
|
column_size: None, // Do not add, useless in hash and size mode
|
||||||
column_size_as_bytes: None,
|
column_size_as_bytes: None, // Do not add, useless in hash and size mode
|
||||||
column_modification_as_secs: Some(ColumnsDuplicates::ModificationAsSecs as i32),
|
column_modification_as_secs: Some(ColumnsDuplicates::ModificationAsSecs as i32),
|
||||||
},
|
},
|
||||||
NotebookObject {
|
NotebookObject {
|
||||||
|
@ -209,6 +209,7 @@ pub enum ColumnsDuplicates {
|
||||||
// Columns for duplicate treeview
|
// Columns for duplicate treeview
|
||||||
ActivatableSelectButton = 0,
|
ActivatableSelectButton = 0,
|
||||||
SelectionButton,
|
SelectionButton,
|
||||||
|
Size,
|
||||||
Name,
|
Name,
|
||||||
Path,
|
Path,
|
||||||
Modification,
|
Modification,
|
||||||
|
@ -226,8 +227,13 @@ pub enum ColumnsEmptyFolders {
|
||||||
ModificationAsSecs,
|
ModificationAsSecs,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ColumnsDirectory {
|
pub enum ColumnsIncludedDirectory {
|
||||||
// Columns for Included and Excluded Directories in upper Notebook
|
// Columns for Included Directories in upper Notebook
|
||||||
|
Path = 0,
|
||||||
|
ReferenceButton,
|
||||||
|
}
|
||||||
|
pub enum ColumnsExcludedDirectory {
|
||||||
|
// Columns for Excluded Directories in upper Notebook
|
||||||
Path = 0,
|
Path = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +334,7 @@ pub const HEADER_ROW_COLOR: &str = "#272727";
|
||||||
//pub const MAIN_ROW_COLOR: &str = "#f4f434"; // TEST
|
//pub const MAIN_ROW_COLOR: &str = "#f4f434"; // TEST
|
||||||
//pub const HEADER_ROW_COLOR: &str = "#010101"; // TEST
|
//pub const HEADER_ROW_COLOR: &str = "#010101"; // TEST
|
||||||
|
|
||||||
pub fn get_string_from_list_store(tree_view: >k::TreeView) -> Vec<String> {
|
pub fn get_string_from_list_store(tree_view: >k::TreeView, column_full_path: i32, column_selection: Option<i32>) -> Vec<String> {
|
||||||
let list_store: gtk::ListStore = get_list_store(tree_view);
|
let list_store: gtk::ListStore = get_list_store(tree_view);
|
||||||
|
|
||||||
let mut string_vector: Vec<String> = Vec::new();
|
let mut string_vector: Vec<String> = Vec::new();
|
||||||
|
@ -339,11 +345,21 @@ pub fn get_string_from_list_store(tree_view: >k::TreeView) -> Vec<String> {
|
||||||
return string_vector;
|
return string_vector;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
loop {
|
match column_selection {
|
||||||
string_vector.push(list_store.value(&tree_iter, 0).get::<String>().unwrap());
|
Some(column_selection) => loop {
|
||||||
|
if list_store.value(&tree_iter, column_selection).get::<bool>().unwrap() {
|
||||||
|
string_vector.push(list_store.value(&tree_iter, column_full_path).get::<String>().unwrap());
|
||||||
|
}
|
||||||
if !list_store.iter_next(&tree_iter) {
|
if !list_store.iter_next(&tree_iter) {
|
||||||
return string_vector;
|
return string_vector;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
None => loop {
|
||||||
|
string_vector.push(list_store.value(&tree_iter, column_full_path).get::<String>().unwrap());
|
||||||
|
if !list_store.iter_next(&tree_iter) {
|
||||||
|
return string_vector;
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +486,16 @@ pub fn get_notebook_enum_from_tree_view(tree_view: >k::TreeView) -> NotebookMa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_notebook_upper_enum_from_tree_view(tree_view: >k::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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_notebook_object_from_tree_view(tree_view: >k::TreeView) -> &NotebookObject {
|
pub fn get_notebook_object_from_tree_view(tree_view: >k::TreeView) -> &NotebookObject {
|
||||||
let nb_enum = get_notebook_enum_from_tree_view(tree_view);
|
let nb_enum = get_notebook_enum_from_tree_view(tree_view);
|
||||||
&NOTEBOOKS_INFOS[nb_enum as usize]
|
&NOTEBOOKS_INFOS[nb_enum as usize]
|
||||||
|
@ -484,7 +510,7 @@ pub fn get_full_name_from_path_name(path: &str, name: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
// After e.g. deleting files, header may become orphan or have one child, so should be deleted in this case
|
// After e.g. deleting files, header may become orphan or have one child, so should be deleted in this case
|
||||||
pub fn clean_invalid_headers(model: >k::ListStore, column_color: i32) {
|
pub fn clean_invalid_headers(model: >k::ListStore, column_color: i32, column_path: i32) {
|
||||||
// Remove only child from header
|
// Remove only child from header
|
||||||
if let Some(first_iter) = model.iter_first() {
|
if let Some(first_iter) = model.iter_first() {
|
||||||
let mut vec_tree_path_to_delete: Vec<gtk::TreePath> = Vec::new();
|
let mut vec_tree_path_to_delete: Vec<gtk::TreePath> = Vec::new();
|
||||||
|
@ -495,6 +521,9 @@ pub fn clean_invalid_headers(model: >k::ListStore, column_color: i32) {
|
||||||
|
|
||||||
let mut next_iter;
|
let mut next_iter;
|
||||||
let mut next_next_iter;
|
let mut next_next_iter;
|
||||||
|
|
||||||
|
// Empty means default check type
|
||||||
|
if model.value(¤t_iter, column_path).get::<String>().unwrap().is_empty() {
|
||||||
'main: loop {
|
'main: loop {
|
||||||
if model.value(¤t_iter, column_color).get::<String>().unwrap() != HEADER_ROW_COLOR {
|
if model.value(¤t_iter, column_color).get::<String>().unwrap() != HEADER_ROW_COLOR {
|
||||||
panic!("First deleted element, should be a header"); // First element should be header
|
panic!("First deleted element, should be a header"); // First element should be header
|
||||||
|
@ -546,6 +575,57 @@ pub fn clean_invalid_headers(model: >k::ListStore, column_color: i32) {
|
||||||
model.remove(&model.iter(tree_path).unwrap());
|
model.remove(&model.iter(tree_path).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Non empty means that header points at reference folder
|
||||||
|
else {
|
||||||
|
// TODO verify how it works
|
||||||
|
'reference: loop {
|
||||||
|
if model.value(¤t_iter, column_color).get::<String>().unwrap() != HEADER_ROW_COLOR {
|
||||||
|
panic!("First deleted element, should be a header"); // First element should be header
|
||||||
|
};
|
||||||
|
|
||||||
|
next_iter = current_iter.clone();
|
||||||
|
if !model.iter_next(&next_iter) {
|
||||||
|
// There is only single header left (H1 -> END) -> (NOTHING)
|
||||||
|
vec_tree_path_to_delete.push(model.path(¤t_iter).unwrap());
|
||||||
|
break 'reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
if model.value(&next_iter, column_color).get::<String>().unwrap() == HEADER_ROW_COLOR {
|
||||||
|
// There are two headers each others(we remove just first) -> (H1 -> H2) -> (H2)
|
||||||
|
vec_tree_path_to_delete.push(model.path(¤t_iter).unwrap());
|
||||||
|
current_iter = next_iter.clone();
|
||||||
|
continue 'reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_next_iter = next_iter.clone();
|
||||||
|
if !model.iter_next(&next_next_iter) {
|
||||||
|
// There is only one child of header left, so we remove it with header (H1 -> C1 -> END) -> (NOTHING)
|
||||||
|
break 'reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
if model.value(&next_next_iter, column_color).get::<String>().unwrap() == HEADER_ROW_COLOR {
|
||||||
|
// One child between two headers, we can remove them (H1 -> C1 -> H2) -> (H2)
|
||||||
|
current_iter = next_next_iter.clone();
|
||||||
|
continue 'reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// (H1 -> C1 -> C2 -> Cn -> END) -> (NO CHANGE, BECAUSE IS GOOD)
|
||||||
|
if !model.iter_next(&next_next_iter) {
|
||||||
|
break 'reference;
|
||||||
|
}
|
||||||
|
// Move to next header
|
||||||
|
if model.value(&next_next_iter, column_color).get::<String>().unwrap() == HEADER_ROW_COLOR {
|
||||||
|
current_iter = next_next_iter.clone();
|
||||||
|
continue 'reference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for tree_path in vec_tree_path_to_delete.iter().rev() {
|
||||||
|
model.remove(&model.iter(tree_path).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Last step, remove orphan header if exists
|
// Last step, remove orphan header if exists
|
||||||
if let Some(iter) = model.iter_first() {
|
if let Some(iter) = model.iter_first() {
|
||||||
|
|
|
@ -101,8 +101,8 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
|
||||||
// Set step increment
|
// Set step increment
|
||||||
{
|
{
|
||||||
let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone();
|
let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone();
|
||||||
scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[1][5] as f64); // This defaults to value of minimal size of hash 8
|
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[1][5] as f64);
|
scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[0][5] as f64);
|
||||||
scale_similarity_similar_images.adjustment().set_step_increment(1_f64);
|
scale_similarity_similar_images.adjustment().set_step_increment(1_f64);
|
||||||
}
|
}
|
||||||
// Set step increment
|
// Set step increment
|
||||||
|
@ -124,9 +124,10 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
|
||||||
let image_preview = gui_data.main_notebook.image_preview_duplicates.clone();
|
let image_preview = gui_data.main_notebook.image_preview_duplicates.clone();
|
||||||
image_preview.hide();
|
image_preview.hide();
|
||||||
|
|
||||||
let col_types: [glib::types::Type; 8] = [
|
let col_types: [glib::types::Type; 9] = [
|
||||||
glib::types::Type::BOOL, // ActivatableSelectButton
|
glib::types::Type::BOOL, // ActivatableSelectButton
|
||||||
glib::types::Type::BOOL, // SelectionButton
|
glib::types::Type::BOOL, // SelectionButton
|
||||||
|
glib::types::Type::STRING, // Size
|
||||||
glib::types::Type::STRING, // Name
|
glib::types::Type::STRING, // Name
|
||||||
glib::types::Type::STRING, // Path
|
glib::types::Type::STRING, // Path
|
||||||
glib::types::Type::STRING, // Modification
|
glib::types::Type::STRING, // Modification
|
||||||
|
@ -397,17 +398,23 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
|
||||||
let tree_view = gui_data.upper_notebook.tree_view_included_directories.clone();
|
let tree_view = gui_data.upper_notebook.tree_view_included_directories.clone();
|
||||||
let evk = gui_data.upper_notebook.evk_tree_view_included_directories.clone();
|
let evk = gui_data.upper_notebook.evk_tree_view_included_directories.clone();
|
||||||
|
|
||||||
let col_types: [glib::types::Type; 1] = [glib::types::Type::STRING];
|
let col_types: [glib::types::Type; 2] = [
|
||||||
|
glib::types::Type::STRING, // Path
|
||||||
|
glib::types::Type::BOOL, // ReferenceButton
|
||||||
|
];
|
||||||
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
|
||||||
|
|
||||||
tree_view.set_model(Some(&list_store));
|
tree_view.set_model(Some(&list_store));
|
||||||
tree_view.selection().set_mode(SelectionMode::Multiple);
|
tree_view.selection().set_mode(SelectionMode::Multiple);
|
||||||
|
|
||||||
create_tree_view_directories(&tree_view);
|
create_tree_view_included_directories(&tree_view);
|
||||||
|
|
||||||
|
tree_view.set_widget_name("tree_view_upper_included_directories");
|
||||||
scrolled_window.add(&tree_view);
|
scrolled_window.add(&tree_view);
|
||||||
scrolled_window.show_all();
|
scrolled_window.show_all();
|
||||||
|
|
||||||
|
tree_view.connect_button_press_event(opening_double_click_function_directories);
|
||||||
|
evk.connect_key_pressed(opening_enter_function_ported_upper_directories);
|
||||||
evk.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| {
|
evk.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| {
|
||||||
if key_code == KEY_DELETE {
|
if key_code == KEY_DELETE {
|
||||||
let list_store = get_list_store(&tree_view);
|
let list_store = get_list_store(&tree_view);
|
||||||
|
@ -433,11 +440,14 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
|
||||||
tree_view.set_model(Some(&list_store));
|
tree_view.set_model(Some(&list_store));
|
||||||
tree_view.selection().set_mode(SelectionMode::Multiple);
|
tree_view.selection().set_mode(SelectionMode::Multiple);
|
||||||
|
|
||||||
create_tree_view_directories(&tree_view);
|
create_tree_view_excluded_directories(&tree_view);
|
||||||
|
|
||||||
|
tree_view.set_widget_name("tree_view_upper_excluded_directories");
|
||||||
scrolled_window.add(&tree_view);
|
scrolled_window.add(&tree_view);
|
||||||
scrolled_window.show_all();
|
scrolled_window.show_all();
|
||||||
|
|
||||||
|
tree_view.connect_button_press_event(opening_double_click_function_directories);
|
||||||
|
evk.connect_key_pressed(opening_enter_function_ported_upper_directories);
|
||||||
evk.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| {
|
evk.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| {
|
||||||
if key_code == KEY_DELETE {
|
if key_code == KEY_DELETE {
|
||||||
let list_store = get_list_store(&tree_view);
|
let list_store = get_list_store(&tree_view);
|
||||||
|
@ -516,7 +526,6 @@ fn connect_event_mouse(gui_data: &GuiData) {
|
||||||
let preview_path = gui_data.preview_path.clone();
|
let preview_path = gui_data.preview_path.clone();
|
||||||
let image_preview = gui_data.main_notebook.image_preview_similar_images.clone();
|
let image_preview = gui_data.main_notebook.image_preview_similar_images.clone();
|
||||||
|
|
||||||
tree_view.connect_button_press_event(opening_double_click_function);
|
|
||||||
tree_view.connect_button_release_event(move |tree_view, _event| {
|
tree_view.connect_button_release_event(move |tree_view, _event| {
|
||||||
let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarImages as usize];
|
let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarImages as usize];
|
||||||
let preview_path = preview_path.clone();
|
let preview_path = preview_path.clone();
|
||||||
|
|
|
@ -2,6 +2,7 @@ use gdk::ModifierType;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
use crate::help_functions::*;
|
use crate::help_functions::*;
|
||||||
|
use crate::notebook_enums::NotebookUpperEnum;
|
||||||
|
|
||||||
// TODO add option to open files and folders from context menu activated by pressing ONCE with right mouse button
|
// TODO add option to open files and folders from context menu activated by pressing ONCE with right mouse button
|
||||||
|
|
||||||
|
@ -13,7 +14,40 @@ pub fn opening_enter_function_ported(event_controller: >k::EventControllerKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
let nt_object = get_notebook_object_from_tree_view(&tree_view);
|
let nt_object = get_notebook_object_from_tree_view(&tree_view);
|
||||||
handle_tree_keypress(&tree_view, key_code, nt_object.column_name, nt_object.column_path, nt_object.column_selection);
|
handle_tree_keypress(
|
||||||
|
&tree_view,
|
||||||
|
key_code,
|
||||||
|
nt_object.column_name,
|
||||||
|
nt_object.column_path,
|
||||||
|
nt_object.column_selection,
|
||||||
|
nt_object.column_color,
|
||||||
|
);
|
||||||
|
false // True catches signal, and don't send it to function, e.g. up button is catched and don't move selection
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opening_enter_function_ported_upper_directories(event_controller: >k::EventControllerKey, _key_value: u32, key_code: u32, _modifier_type: ModifierType) -> bool {
|
||||||
|
let tree_view = event_controller.widget().unwrap().downcast::<gtk::TreeView>().unwrap();
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
println!("key_code {}", key_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
match get_notebook_upper_enum_from_tree_view(&tree_view) {
|
||||||
|
NotebookUpperEnum::IncludedDirectories => {
|
||||||
|
handle_tree_keypress_upper_directories(
|
||||||
|
&tree_view,
|
||||||
|
key_code,
|
||||||
|
ColumnsIncludedDirectory::Path as i32,
|
||||||
|
Some(ColumnsIncludedDirectory::ReferenceButton as i32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
NotebookUpperEnum::ExcludedDirectories => {
|
||||||
|
handle_tree_keypress_upper_directories(&tree_view, key_code, ColumnsExcludedDirectory::Path as i32, None);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
false // True catches signal, and don't send it to function, e.g. up button is catched and don't move selection
|
false // True catches signal, and don't send it to function, e.g. up button is catched and don't move selection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +61,23 @@ pub fn opening_double_click_function(tree_view: >k::TreeView, event: &gdk::Eve
|
||||||
gtk::Inhibit(false)
|
gtk::Inhibit(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn opening_double_click_function_directories(tree_view: >k::TreeView, event: &gdk::EventButton) -> gtk::Inhibit {
|
||||||
|
if event.event_type() == gdk::EventType::DoubleButtonPress && (event.button() == 1 || event.button() == 3) {
|
||||||
|
match get_notebook_upper_enum_from_tree_view(tree_view) {
|
||||||
|
NotebookUpperEnum::IncludedDirectories => {
|
||||||
|
common_open_function_upper_directories(tree_view, ColumnsIncludedDirectory::Path as i32);
|
||||||
|
}
|
||||||
|
NotebookUpperEnum::ExcludedDirectories => {
|
||||||
|
common_open_function_upper_directories(tree_view, ColumnsExcludedDirectory::Path as i32);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gtk::Inhibit(false)
|
||||||
|
}
|
||||||
|
|
||||||
// // GTK 4
|
// // GTK 4
|
||||||
// pub fn opening_enter_function_ported(event_controller: >k4::EventControllerKey, _key: gdk4::keys::Key, key_code: u32, _modifier_type: ModifierType) -> gtk4::Inhibit {
|
// pub fn opening_enter_function_ported(event_controller: >k4::EventControllerKey, _key: gdk4::keys::Key, key_code: u32, _modifier_type: ModifierType) -> gtk4::Inhibit {
|
||||||
// let tree_view = event_controller.widget().unwrap().downcast::<gtk4::TreeView>().unwrap();
|
// let tree_view = event_controller.widget().unwrap().downcast::<gtk4::TreeView>().unwrap();
|
||||||
|
@ -58,15 +109,20 @@ enum OpenMode {
|
||||||
PathAndName,
|
PathAndName,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common_mark_function(tree_view: >k::TreeView, column_name: i32) {
|
fn common_mark_function(tree_view: >k::TreeView, column_selection: i32, column_color: Option<i32>) {
|
||||||
let selection = tree_view.selection();
|
let selection = tree_view.selection();
|
||||||
let (selected_rows, tree_model) = selection.selected_rows();
|
let (selected_rows, tree_model) = selection.selected_rows();
|
||||||
|
|
||||||
let model = get_list_store(tree_view);
|
let model = get_list_store(tree_view);
|
||||||
|
|
||||||
for tree_path in selected_rows.iter().rev() {
|
for tree_path in selected_rows.iter().rev() {
|
||||||
let value = !tree_model.value(&tree_model.iter(tree_path).unwrap(), column_name).get::<bool>().unwrap();
|
if let Some(column_color) = column_color {
|
||||||
model.set_value(&tree_model.iter(tree_path).unwrap(), column_name as u32, &value.to_value());
|
if model.value(&model.iter(tree_path).unwrap(), column_color).get::<String>().unwrap() == HEADER_ROW_COLOR {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let value = !tree_model.value(&tree_model.iter(tree_path).unwrap(), column_selection).get::<bool>().unwrap();
|
||||||
|
model.set_value(&tree_model.iter(tree_path).unwrap(), column_selection as u32, &value.to_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,13 +147,38 @@ fn common_open_function(tree_view: >k::TreeView, column_name: i32, column_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tree_keypress(tree_view: >k::TreeView, key_code: u32, name_column: i32, path_column: i32, mark_column: i32) {
|
fn common_open_function_upper_directories(tree_view: >k::TreeView, column_full_path: i32) {
|
||||||
|
let selection = tree_view.selection();
|
||||||
|
let (selected_rows, tree_model) = selection.selected_rows();
|
||||||
|
|
||||||
|
for tree_path in selected_rows.iter().rev() {
|
||||||
|
let full_path = tree_model.value(&tree_model.iter(tree_path).unwrap(), column_full_path).get::<String>().unwrap();
|
||||||
|
|
||||||
|
open::that_in_background(&full_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_tree_keypress_upper_directories(tree_view: >k::TreeView, key_code: u32, full_path_column: i32, mark_column: Option<i32>) {
|
||||||
|
match key_code {
|
||||||
|
KEY_ENTER => {
|
||||||
|
common_open_function_upper_directories(tree_view, full_path_column);
|
||||||
|
}
|
||||||
|
KEY_SPACE => {
|
||||||
|
if let Some(mark_column) = mark_column {
|
||||||
|
common_mark_function(tree_view, mark_column, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_tree_keypress(tree_view: >k::TreeView, key_code: u32, name_column: i32, path_column: i32, mark_column: i32, column_color: Option<i32>) {
|
||||||
match key_code {
|
match key_code {
|
||||||
KEY_ENTER => {
|
KEY_ENTER => {
|
||||||
common_open_function(tree_view, name_column, path_column, OpenMode::PathAndName);
|
common_open_function(tree_view, name_column, path_column, OpenMode::PathAndName);
|
||||||
}
|
}
|
||||||
KEY_SPACE => {
|
KEY_SPACE => {
|
||||||
common_mark_function(tree_view, mark_column);
|
common_mark_function(tree_view, mark_column, column_color);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -154,3 +235,6 @@ pub fn select_function_similar_videos(_tree_selection: >k::TreeSelection, tree
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
pub fn select_function_always_true(_tree_selection: >k::TreeSelection, _tree_model: >k::TreeModel, _tree_path: >k::TreePath, _is_path_currently_selected: bool) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
|
@ -57,7 +57,8 @@ pub fn save_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
|
||||||
let list_store = get_list_store(&tree_view_included_directories);
|
let list_store = get_list_store(&tree_view_included_directories);
|
||||||
if let Some(iter) = list_store.iter_first() {
|
if let Some(iter) = list_store.iter_first() {
|
||||||
loop {
|
loop {
|
||||||
data_to_save.push(list_store.value(&iter, ColumnsDirectory::Path as i32).get::<String>().unwrap());
|
// TODO maybe save also here reference directories?
|
||||||
|
data_to_save.push(list_store.value(&iter, ColumnsIncludedDirectory::Path as i32).get::<String>().unwrap());
|
||||||
if !list_store.iter_next(&iter) {
|
if !list_store.iter_next(&iter) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ pub fn save_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
|
||||||
let list_store = get_list_store(&tree_view_excluded_directories);
|
let list_store = get_list_store(&tree_view_excluded_directories);
|
||||||
if let Some(iter) = list_store.iter_first() {
|
if let Some(iter) = list_store.iter_first() {
|
||||||
loop {
|
loop {
|
||||||
data_to_save.push(list_store.value(&iter, ColumnsDirectory::Path as i32).get::<String>().unwrap());
|
data_to_save.push(list_store.value(&iter, ColumnsExcludedDirectory::Path as i32).get::<String>().unwrap());
|
||||||
if !list_store.iter_next(&iter) {
|
if !list_store.iter_next(&iter) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -213,12 +214,26 @@ pub fn save_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if data_saved {
|
if data_saved {
|
||||||
add_text_to_text_view(&text_view_errors, format!("{} {}", fl!("saving_loading_saving_success"), config_file.display()).as_str());
|
add_text_to_text_view(
|
||||||
|
&text_view_errors,
|
||||||
|
fl!(
|
||||||
|
"saving_loading_saving_success",
|
||||||
|
generate_translation_hashmap(vec![("name", config_file.display().to_string())])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
add_text_to_text_view(&text_view_errors, format!("Failed to save configuration data to file {}", config_file.display()).as_str());
|
add_text_to_text_view(
|
||||||
|
&text_view_errors,
|
||||||
|
fl!(
|
||||||
|
"saving_loading_saving_failure",
|
||||||
|
generate_translation_hashmap(vec![("name", config_file.display().to_string())])
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
add_text_to_text_view(&text_view_errors, "Failed to get home directory, so can't save file.");
|
add_text_to_text_view(&text_view_errors, fl!("saving_loading_failed_to_get_home_directory").as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +697,10 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
|
||||||
list_store.clear();
|
list_store.clear();
|
||||||
|
|
||||||
for directory in included_directories {
|
for directory in included_directories {
|
||||||
let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &directory)];
|
let values: [(u32, &dyn ToValue); 2] = [
|
||||||
|
(ColumnsIncludedDirectory::Path as u32, &directory),
|
||||||
|
(ColumnsIncludedDirectory::ReferenceButton as u32, &false),
|
||||||
|
];
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,7 +710,7 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
|
||||||
list_store.clear();
|
list_store.clear();
|
||||||
|
|
||||||
for directory in excluded_directories {
|
for directory in excluded_directories {
|
||||||
let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &directory)];
|
let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &directory)];
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,7 +800,10 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, ¤t_dir)];
|
let values: [(u32, &dyn ToValue); 2] = [
|
||||||
|
(ColumnsIncludedDirectory::Path as u32, ¤t_dir),
|
||||||
|
(ColumnsIncludedDirectory::ReferenceButton as u32, &false),
|
||||||
|
];
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
// Resetting excluded directories
|
// Resetting excluded directories
|
||||||
|
@ -792,7 +813,7 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb
|
||||||
list_store.clear();
|
list_store.clear();
|
||||||
if cfg!(target_family = "unix") {
|
if cfg!(target_family = "unix") {
|
||||||
for i in ["/proc", "/dev", "/sys", "/run", "/snap"].iter() {
|
for i in ["/proc", "/dev", "/sys", "/run", "/snap"].iter() {
|
||||||
let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &i)];
|
let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &i)];
|
||||||
list_store.set(&list_store.append(), &values);
|
list_store.set(&list_store.append(), &values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,8 +117,11 @@ check_button_general_same_size_tooltip = Ignore from results, files which have i
|
||||||
main_label_size_bytes_tooltip = Size of files which will be used in scan
|
main_label_size_bytes_tooltip = Size of files which will be used in scan
|
||||||
|
|
||||||
# Upper window
|
# Upper window
|
||||||
|
upper_tree_view_included_folder_column_title = Folders to Search
|
||||||
|
upper_tree_view_included_reference_column_title = Reference Folders
|
||||||
|
|
||||||
upper_recursive_button = Recursive
|
upper_recursive_button = Recursive
|
||||||
upper_recursive_button_tooltip = If selected, search also for files which are not placed directly under chosen folders
|
upper_recursive_button_tooltip = If selected, search also for files which are not placed directly under chosen folders.
|
||||||
|
|
||||||
upper_manual_add_included_button = Manual Add
|
upper_manual_add_included_button = Manual Add
|
||||||
upper_add_included_button = Add
|
upper_add_included_button = Add
|
||||||
|
@ -127,19 +130,19 @@ upper_manual_add_excluded_button = Manual Add
|
||||||
upper_add_excluded_button = Add
|
upper_add_excluded_button = Add
|
||||||
upper_remove_excluded_button = Remove
|
upper_remove_excluded_button = Remove
|
||||||
|
|
||||||
upper_manual_add_included_button_tooltip = Allows to add directory name to search by hand
|
upper_manual_add_included_button_tooltip = Allows to add directory name to search by hand.
|
||||||
upper_add_included_button_tooltip = Add new directory to search
|
upper_add_included_button_tooltip = Add new directory to search.
|
||||||
upper_remove_included_button_tooltip = Delete directory from search
|
upper_remove_included_button_tooltip = Delete directory from search.
|
||||||
upper_manual_add_excluded_button_tooltip = Allows to add excluded directory name by hand
|
upper_manual_add_excluded_button_tooltip = Allows to add excluded directory name by hand.
|
||||||
upper_add_excluded_button_tooltip = Add directory to be excluded in search
|
upper_add_excluded_button_tooltip = Add directory to be excluded in search.
|
||||||
upper_remove_excluded_button_tooltip = Delete directory from excluded
|
upper_remove_excluded_button_tooltip = Delete directory from excluded.
|
||||||
|
|
||||||
upper_notebook_items_configuration = Items Configuration
|
upper_notebook_items_configuration = Items Configuration
|
||||||
upper_notebook_excluded_directories = Excluded Directories
|
upper_notebook_excluded_directories = Excluded Directories
|
||||||
upper_notebook_included_directories = Included Directories
|
upper_notebook_included_directories = Included Directories
|
||||||
|
|
||||||
upper_allowed_extensions_tooltip =
|
upper_allowed_extensions_tooltip =
|
||||||
Allowed extensions must be separated by commas(by default all are available)
|
Allowed extensions must be separated by commas(by default all are available).
|
||||||
|
|
||||||
Macros IMAGE, VIDEO, MUSIC, TEXT which adds multiple extensions at once are also available.
|
Macros IMAGE, VIDEO, MUSIC, TEXT which adds multiple extensions at once are also available.
|
||||||
|
|
||||||
|
@ -181,7 +184,7 @@ popover_custom_name_check_button_entry_tooltip =
|
||||||
popover_custom_regex_check_button_entry_tooltip =
|
popover_custom_regex_check_button_entry_tooltip =
|
||||||
Allows to select records by specified Regex.
|
Allows to select records by specified Regex.
|
||||||
|
|
||||||
With this mode, searched text is Path with Name
|
With this mode, searched text is Path with Name.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
/usr/bin/ziemniak.txt can be found with /ziem[a-z]+
|
/usr/bin/ziemniak.txt can be found with /ziem[a-z]+
|
||||||
|
@ -216,9 +219,9 @@ bottom_symlink_button = Symlink
|
||||||
bottom_hardlink_button = Hardlink
|
bottom_hardlink_button = Hardlink
|
||||||
bottom_move_button = Move
|
bottom_move_button = Move
|
||||||
|
|
||||||
bottom_search_button_tooltip = Start to search for files/folders
|
bottom_search_button_tooltip = Start to search for files/folders.
|
||||||
bottom_select_button_tooltip = Selects records. Only selected files/folders can be later processed.
|
bottom_select_button_tooltip = Selects records. Only selected files/folders can be later processed.
|
||||||
bottom_delete_button_tooltip = Delete selected files/folders
|
bottom_delete_button_tooltip = Delete selected files/folders.
|
||||||
bottom_save_button_tooltip = Save data about search to file
|
bottom_save_button_tooltip = Save data about search to file
|
||||||
bottom_symlink_button_tooltip =
|
bottom_symlink_button_tooltip =
|
||||||
Creates symbolic links.
|
Creates symbolic links.
|
||||||
|
@ -362,21 +365,17 @@ settings_folder_settings_open = Open settings folder
|
||||||
# Compute results
|
# Compute results
|
||||||
compute_stopped_by_user = Searching was stopped by user
|
compute_stopped_by_user = Searching was stopped by user
|
||||||
|
|
||||||
compute_found = Found
|
compute_found_duplicates_hash_size = Found { $number_files } duplicates in { $number_groups } groups which took { $size }
|
||||||
compute_duplicated_files_in = duplicated files in
|
compute_found_duplicates_name = Found { $number_files } duplicates in { $number_groups } groups
|
||||||
compute_groups_which_took = groups which took
|
compute_found_empty_folders = Found { $number_files } empty folders
|
||||||
compute_groups = groups
|
compute_found_empty_files = Found { $number_files } empty files
|
||||||
compute_duplicates_for = duplicates for
|
compute_found_big_files = Found { $number_files } big files
|
||||||
|
compute_found_temporary_files = Found { $number_files } temporary files
|
||||||
compute_empty_folders = empty folders
|
compute_found_images = Found { $number_files } similar images in { $number_groups } groups
|
||||||
compute_empty_files = empty files
|
compute_found_videos = Found { $number_files } similar videos in { $number_groups } groups
|
||||||
compute_biggest_files = biggest files
|
compute_found_music = Found { $number_files } similar music files in { $number_groups } groups
|
||||||
compute_temporary_files = temporary files
|
compute_found_invalid_symlinks = Found { $number_files } invalid symlinks
|
||||||
compute_similar_image = images
|
compute_found_broken_files = Found { $number_files } broken files
|
||||||
compute_similar_videos = videos
|
|
||||||
compute_music_files = music files
|
|
||||||
compute_symlinks = invalid symlinks
|
|
||||||
compute_broken_files = broken files
|
|
||||||
|
|
||||||
# Progress window
|
# Progress window
|
||||||
progress_scanning_general_file = Scanning {$file_number} file
|
progress_scanning_general_file = Scanning {$file_number} file
|
||||||
|
@ -396,9 +395,12 @@ progress_current_stage = Current Stage:{" "}
|
||||||
progress_all_stages = All Stages:{" "}
|
progress_all_stages = All Stages:{" "}
|
||||||
|
|
||||||
# Saving loading
|
# Saving loading
|
||||||
saving_loading_saving_success = Saved configuration to file
|
saving_loading_saving_success = Saved configuration to file { $name }.
|
||||||
|
saving_loading_saving_failure = Failed to save configuration data to file { $name }.
|
||||||
saving_loading_reset_configuration = Current configuration was cleared.
|
saving_loading_reset_configuration = Current configuration was cleared.
|
||||||
saving_loading_loading_success = Properly loaded configuration from file
|
saving_loading_loading_success = Properly loaded configuration from file.
|
||||||
|
|
||||||
|
saving_loading_failed_to_get_home_directory = Failed to get home directory to open/save config file.
|
||||||
|
|
||||||
# Invalid symlinks
|
# Invalid symlinks
|
||||||
invalid_symlink_infinite_recursion = Infinite recursion
|
invalid_symlink_infinite_recursion = Infinite recursion
|
||||||
|
@ -438,7 +440,7 @@ hard_sym_link_label = Are you sure that you want to link this files?
|
||||||
move_folder_failed = Failed to move folder {$name}, reason {$reason}
|
move_folder_failed = Failed to move folder {$name}, reason {$reason}
|
||||||
move_file_failed = Failed to move file {$name}, reason {$reason}
|
move_file_failed = Failed to move file {$name}, reason {$reason}
|
||||||
move_files_title_dialog = Choose folder to which you want to move duplicated files
|
move_files_title_dialog = Choose folder to which you want to move duplicated files
|
||||||
move_files_choose_more_than_1_path = Only 1 path must be selected to be able to copy there duplicated files, selected {$path_number}
|
move_files_choose_more_than_1_path = Only 1 path must be selected to be able to copy there duplicated files, selected {$path_number}.
|
||||||
move_stats = Properly moved {$num_files}/{$all_files} items
|
move_stats = Properly moved {$num_files}/{$all_files} items
|
||||||
|
|
||||||
save_results_to_file = Saved results to file {$name}
|
save_results_to_file = Saved results to file {$name}
|
||||||
|
@ -460,8 +462,8 @@ cache_clear_message_label_3 = This may speedup a little loading/saving to cache.
|
||||||
cache_clear_message_label_4 = WARNING: Operation will remove all cached data from unplugged external drives, so hash will need to be generated again.
|
cache_clear_message_label_4 = WARNING: Operation will remove all cached data from unplugged external drives, so hash will need to be generated again.
|
||||||
|
|
||||||
# Show preview
|
# Show preview
|
||||||
preview_temporary_file = Failed to open temporary image file {$name}, reason {$reason}
|
preview_temporary_file = Failed to open temporary image file {$name}, reason {$reason}.
|
||||||
preview_0_size = Cannot create preview of image {$name}, with 0 width or height
|
preview_0_size = Cannot create preview of image {$name}, with 0 width or height.
|
||||||
preview_temporary_image_save = Failed to save temporary image file to {$name}, reason {$reason}
|
preview_temporary_image_save = Failed to save temporary image file to {$name}, reason {$reason}.
|
||||||
preview_temporary_image_remove = Failed to delete temporary image file {$name}, reason {$reason}
|
preview_temporary_image_remove = Failed to delete temporary image file {$name}, reason {$reason}.
|
||||||
preview_failed_to_create_cache_dir = Failed to create dir {$name} needed by image preview, reason {$reason}
|
preview_failed_to_create_cache_dir = Failed to create dir {$name} needed by image preview, reason {$reason}.
|
||||||
|
|
|
@ -97,6 +97,8 @@ check_button_general_same_size = Ignoruj identyczny rozmiar
|
||||||
check_button_general_same_size_tooltip = Wyrzuca z wyników skanowania pliki, które posiadają identyczny rozmiar, po to by w wynikach zostały tylko niemal identyczne rekordy.
|
check_button_general_same_size_tooltip = Wyrzuca z wyników skanowania pliki, które posiadają identyczny rozmiar, po to by w wynikach zostały tylko niemal identyczne rekordy.
|
||||||
main_label_size_bytes_tooltip = Rozmiar plików które będą zawarte przy przeszukiwaniu
|
main_label_size_bytes_tooltip = Rozmiar plików które będą zawarte przy przeszukiwaniu
|
||||||
# Upper window
|
# Upper window
|
||||||
|
upper_tree_view_included_folder_column_title = Foldery do Przeszukania
|
||||||
|
upper_tree_view_included_reference_column_title = Źródłowy Folder
|
||||||
upper_recursive_button = Rekursywnie
|
upper_recursive_button = Rekursywnie
|
||||||
upper_recursive_button_tooltip = Jeśli zaznaczony, szuka plików i folderów również w katalogach wewnątrz, nawet jeśli nie znajdują się one bezpośrednio w tym folderze.
|
upper_recursive_button_tooltip = Jeśli zaznaczony, szuka plików i folderów również w katalogach wewnątrz, nawet jeśli nie znajdują się one bezpośrednio w tym folderze.
|
||||||
upper_manual_add_included_button = Ręcznie Dodaj
|
upper_manual_add_included_button = Ręcznie Dodaj
|
||||||
|
|
Loading…
Reference in a new issue