diff --git a/Cargo.lock b/Cargo.lock index 24b3210..3663f16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,9 +341,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.12" +version = "3.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8b79fe3946ceb4a0b1c080b4018992b8d27e9ff363644c1c9b6387c854614d" +checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b" dependencies = [ "atty", "bitflags", @@ -410,9 +410,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -420,9 +420,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -431,9 +431,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", "cfg-if", @@ -445,9 +445,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "once_cell", @@ -669,9 +669,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -785,9 +785,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.13" +version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceeb589a3157cac0ab8cc585feb749bd2cea5cb55a6ee802ad72d9fd38303da" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", @@ -1569,9 +1569,9 @@ dependencies = [ [[package]] name = "lofty" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d1ba3c036ad548be962a93536441b393429b24da8492b1b5288012164b8a8f" +checksum = "b3b64d3508069f7addfe636551140ddf45afb2b5317b2a2b8c12a99f08f2dba3" dependencies = [ "base64 0.13.0", "byteorder", @@ -2187,9 +2187,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" dependencies = [ "bitflags", ] @@ -2393,18 +2393,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", diff --git a/czkawka_cli/Cargo.toml b/czkawka_cli/Cargo.toml index f741d8b..81779a8 100644 --- a/czkawka_cli/Cargo.toml +++ b/czkawka_cli/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://github.com/qarmin/czkawka" repository = "https://github.com/qarmin/czkawka" [dependencies] -clap = { version = "3.2.12", features = ["derive"] } +clap = { version = "3.2.14", features = ["derive"] } # For enum types image_hasher = "1.0.0" diff --git a/czkawka_cli/src/main.rs b/czkawka_cli/src/main.rs index 3565657..08c3f09 100644 --- a/czkawka_cli/src/main.rs +++ b/czkawka_cli/src/main.rs @@ -1,6 +1,9 @@ #![allow(clippy::needless_late_init)] +use std::process; + use clap::Parser; + use commands::Commands; #[allow(unused_imports)] // It is used in release for print_results(). use czkawka_core::common_traits::*; @@ -18,7 +21,6 @@ use czkawka_core::{ similar_videos::SimilarVideos, temporary::{self, Temporary}, }; -use std::process; mod commands; diff --git a/czkawka_core/Cargo.toml b/czkawka_core/Cargo.toml index 35aedf0..92e30dc 100644 --- a/czkawka_core/Cargo.toml +++ b/czkawka_core/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/qarmin/czkawka" [dependencies] humansize = "1.1.1" rayon = "1.5.3" -crossbeam-channel = "0.5.5" +crossbeam-channel = "0.5.6" # For saving/loading config files to specific directories directories-next = "2.0.0" @@ -26,7 +26,7 @@ hamming = "0.1.3" # Needed by same music bitflags = "1.3.2" -lofty= "0.7.2" +lofty = "0.7.3" # Futures - needed by async progress sender futures = "0.3.21" @@ -48,7 +48,7 @@ vid_dup_finder_lib = "0.1.0" ffmpeg_cmdline_utils = "0.1.1" # Saving/Loading Cache -serde = "1.0.139" +serde = "1.0.140" bincode = "1.3.3" serde_json = "1.0.82" @@ -68,6 +68,7 @@ infer = "0.9.0" num_cpus = "1.13.1" +# Heif/Heic libheif-rs = { version = "0.15.0", optional = true } anyhow = { version = "1.0.58", optional = true } diff --git a/czkawka_core/src/big_file.rs b/czkawka_core/src/big_file.rs index f454b3c..45de73c 100644 --- a/czkawka_core/src/big_file.rs +++ b/czkawka_core/src/big_file.rs @@ -336,7 +336,7 @@ impl BigFile { for (size, mut vector) in iter { if self.information.number_of_real_files < self.number_of_files_to_check { if vector.len() > 1 { - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index 2abd765..8b22103 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -794,6 +794,7 @@ fn check_extension_availability(file_name_lowercase: &str) -> TypeOfFile { TypeOfFile::Unknown } } + fn check_extension_allowed(type_of_file: &TypeOfFile, checked_types: &CheckedTypes) -> bool { ((*type_of_file == TypeOfFile::Image) && ((*checked_types & CheckedTypes::IMAGE) == CheckedTypes::IMAGE)) || ((*type_of_file == TypeOfFile::PDF) && ((*checked_types & CheckedTypes::PDF) == CheckedTypes::PDF)) diff --git a/czkawka_core/src/common.rs b/czkawka_core/src/common.rs index 9ec88d1..3ff4ddc 100644 --- a/czkawka_core/src/common.rs +++ b/czkawka_core/src/common.rs @@ -5,12 +5,11 @@ use std::io::BufReader; use std::path::{Path, PathBuf}; use std::time::SystemTime; +#[cfg(feature = "heif")] +use anyhow::Result; use directories_next::ProjectDirs; use image::{DynamicImage, ImageBuffer, Rgb}; use imagepipe::{ImageSource, Pipeline}; - -#[cfg(feature = "heif")] -use anyhow::Result; #[cfg(feature = "heif")] use libheif_rs::{Channel, ColorSpace, HeifContext, RgbChroma}; diff --git a/czkawka_core/src/common_dir_traversal.rs b/czkawka_core/src/common_dir_traversal.rs index 3b0ab33..9093880 100644 --- a/czkawka_core/src/common_dir_traversal.rs +++ b/czkawka_core/src/common_dir_traversal.rs @@ -34,7 +34,7 @@ pub enum CheckingMethod { Hash, } -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct FileEntry { pub path: PathBuf, pub size: u64, @@ -47,13 +47,13 @@ pub struct FileEntry { const MAX_NUMBER_OF_SYMLINK_JUMPS: i32 = 20; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct SymlinkInfo { pub destination_path: PathBuf, pub type_of_error: ErrorType, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ErrorType { InfiniteRecursion, NonExistentFile, diff --git a/czkawka_core/src/common_directory.rs b/czkawka_core/src/common_directory.rs index 0a94e0c..ac496f4 100644 --- a/czkawka_core/src/common_directory.rs +++ b/czkawka_core/src/common_directory.rs @@ -171,9 +171,9 @@ impl Directories { // Remove duplicated entries like: "/", "/" - self.excluded_directories.sort(); - self.included_directories.sort(); - self.reference_directories.sort(); + self.excluded_directories.sort_unstable(); + self.included_directories.sort_unstable(); + self.reference_directories.sort_unstable(); self.excluded_directories.dedup(); self.included_directories.dedup(); @@ -292,8 +292,8 @@ impl Directories { } // Not needed, but better is to have sorted everything - self.excluded_directories.sort(); - self.included_directories.sort(); + self.excluded_directories.sort_unstable(); + self.included_directories.sort_unstable(); Common::print_time(start_time, SystemTime::now(), "optimize_directories".to_string()); // Get device IDs for included directories diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index 1870e2d..269f18b 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -1476,7 +1476,7 @@ mod tests { assert_eq!(metadata.modified()?, fs::metadata(&src)?.modified()?); let mut actual = read_dir(&dir)?.map(|e| e.unwrap().path()).collect::>(); - actual.sort(); + actual.sort_unstable(); assert_eq!(vec![src, dst], actual); Ok(()) } diff --git a/czkawka_core/src/same_music.rs b/czkawka_core/src/same_music.rs index ff50e51..7a024c6 100644 --- a/czkawka_core/src/same_music.rs +++ b/czkawka_core/src/same_music.rs @@ -549,7 +549,7 @@ impl SameMusic { } let mut hash_map: BTreeMap> = Default::default(); for file_entry in vec_file_entry { - let mut thing = file_entry.track_title.to_lowercase().trim().to_string(); + let mut thing = file_entry.track_title.trim().to_lowercase(); if self.approximate_comparison { get_approximate_conversion(&mut thing); } @@ -577,7 +577,7 @@ impl SameMusic { } let mut hash_map: BTreeMap> = Default::default(); for file_entry in vec_file_entry { - let mut thing = file_entry.track_artist.to_lowercase().trim().to_string(); + let mut thing = file_entry.track_artist.trim().to_lowercase(); if self.approximate_comparison { get_approximate_conversion(&mut thing); } @@ -605,7 +605,7 @@ impl SameMusic { } let mut hash_map: BTreeMap> = Default::default(); for file_entry in vec_file_entry { - let thing = file_entry.year.to_lowercase().trim().to_string(); + let thing = file_entry.year.trim().to_lowercase(); if !thing.is_empty() { hash_map.entry(thing.clone()).or_insert_with(Vec::new).push(file_entry); } @@ -630,7 +630,7 @@ impl SameMusic { } let mut hash_map: BTreeMap> = Default::default(); for file_entry in vec_file_entry { - let thing = file_entry.length.to_lowercase().trim().to_string(); + let thing = file_entry.length.trim().to_lowercase(); if !thing.is_empty() { hash_map.entry(thing.clone()).or_insert_with(Vec::new).push(file_entry); } @@ -655,7 +655,7 @@ impl SameMusic { } let mut hash_map: BTreeMap> = Default::default(); for file_entry in vec_file_entry { - let thing = file_entry.genre.to_lowercase().trim().to_string(); + let thing = file_entry.genre.trim().to_lowercase(); if !thing.is_empty() { hash_map.entry(thing.clone()).or_insert_with(Vec::new).push(file_entry); } diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index 8ef9a92..89d4fd9 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -21,7 +21,6 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "heif")] use crate::common::get_dynamic_image_from_heic; use crate::common::{get_dynamic_image_from_raw_image, open_cache_folder, Common, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, LOOP_DURATION, RAW_IMAGE_EXTENSIONS}; - use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -570,7 +569,7 @@ impl SimilarImages { break 'krztyna; } - # [cfg(feature = "heif")] + #[cfg(feature = "heif")] if HEIC_EXTENSIONS.iter().any(|e| file_name_lowercase.ends_with(e)) { image = match get_dynamic_image_from_heic(&file_entry.path.to_string_lossy().to_string()) { Ok(t) => t, diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index 81a49a6..8ea70bc 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -17,7 +17,7 @@ humansize = "1.1.1" chrono = "0.4.19" # Used for sending stop signal across threads -crossbeam-channel = "0.5.5" +crossbeam-channel = "0.5.6" # To get informations about progress futures = "0.3.21" diff --git a/czkawka_gui/i18n/en/czkawka_gui.ftl b/czkawka_gui/i18n/en/czkawka_gui.ftl index 11bce18..ba0b50c 100644 --- a/czkawka_gui/i18n/en/czkawka_gui.ftl +++ b/czkawka_gui/i18n/en/czkawka_gui.ftl @@ -132,10 +132,20 @@ upper_manual_add_excluded_button = Manual Add upper_add_excluded_button = Add upper_remove_excluded_button = Remove -upper_manual_add_included_button_tooltip = Add directory name to search by hand. +upper_manual_add_included_button_tooltip = + Add directory name to search by hand. + + To add multiple paths at once, separate them by ; + + /home/roman;/home/rozkaz will add two directories /home/roman and /home/rozkaz upper_add_included_button_tooltip = Add new directory to search. upper_remove_included_button_tooltip = Delete directory from search. -upper_manual_add_excluded_button_tooltip = Add excluded directory name by hand. +upper_manual_add_excluded_button_tooltip = + Add excluded directory name by hand. + + To add multiple paths at once, separate them by ; + + /home/roman;/home/krokiet will add two directories /home/roman and /home/keokiet upper_add_excluded_button_tooltip = Add directory to be excluded in search. upper_remove_excluded_button_tooltip = Delete directory from excluded. diff --git a/czkawka_gui/src/compute_results.rs b/czkawka_gui/src/compute_results.rs index 0274d5b..11c0e7a 100644 --- a/czkawka_gui/src/compute_results.rs +++ b/czkawka_gui/src/compute_results.rs @@ -157,7 +157,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let vector = if vector.len() >= 2 { let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -216,7 +216,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let vector = if vector.len() >= 2 { let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -276,7 +276,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let vector = if vector.len() >= 2 { let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -339,7 +339,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let vector = if vector.len() >= 2 { let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -395,7 +395,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let vector = if vector.len() >= 2 { let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -449,7 +449,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let vector = if vector.len() >= 2 { let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -550,7 +550,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< let hashmap = ef.get_empty_folder_list(); let mut vector = hashmap.keys().cloned().collect::>(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.as_path()); (t.0, t.1) }); @@ -616,7 +616,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -742,7 +742,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -999,7 +999,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // 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| { + vec_file_entry.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -1057,7 +1057,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // 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| { + vec_file_entry.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -1181,7 +1181,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // 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| { + vec_file_entry.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -1252,7 +1252,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // 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| { + vec_file_entry.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -1402,7 +1402,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -1474,7 +1474,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); @@ -1540,7 +1540,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< // Sort let mut vector = vector.clone(); - vector.sort_by_key(|e| { + vector.sort_unstable_by_key(|e| { let t = split_path(e.path.as_path()); (t.0, t.1) }); diff --git a/czkawka_gui/src/connect_things/connect_button_compare.rs b/czkawka_gui/src/connect_things/connect_button_compare.rs index 054499a..dc323b5 100644 --- a/czkawka_gui/src/connect_things/connect_button_compare.rs +++ b/czkawka_gui/src/connect_things/connect_button_compare.rs @@ -1,14 +1,15 @@ use std::cell::RefCell; use std::rc::Rc; -#[cfg(feature = "heif")] -use czkawka_core::common::get_dynamic_image_from_heic; -use czkawka_core::common::HEIC_EXTENSIONS; use gdk4::gdk_pixbuf::{InterpType, Pixbuf}; use gtk4::prelude::*; use gtk4::{Align, CheckButton, Image, ListStore, Orientation, ScrolledWindow, TreeIter, TreeModel, TreePath, TreeSelection, Widget}; use image::DynamicImage; +#[cfg(feature = "heif")] +use czkawka_core::common::get_dynamic_image_from_heic; +use czkawka_core::common::HEIC_EXTENSIONS; + use crate::flg; use crate::gui_structs::gui_data::GuiData; use crate::help_functions::{ @@ -617,8 +618,8 @@ fn update_bottom_buttons( shared_using_for_preview: Rc, Option)>>, image_cache: Rc>>, ) { - let left_tree_view = (*shared_using_for_preview.borrow()).0.clone().unwrap(); - let right_tree_view = (*shared_using_for_preview.borrow()).1.clone().unwrap(); + let left_tree_view = (shared_using_for_preview.borrow()).0.clone().unwrap(); + let right_tree_view = (shared_using_for_preview.borrow()).1.clone().unwrap(); for (number, i) in get_all_direct_children(all_gtk_box).into_iter().enumerate() { let cache_tree_path = (*image_cache.borrow())[number].4.clone(); diff --git a/czkawka_gui/src/connect_things/connect_button_delete.rs b/czkawka_gui/src/connect_things/connect_button_delete.rs index 7e951c2..732ea6d 100644 --- a/czkawka_gui/src/connect_things/connect_button_delete.rs +++ b/czkawka_gui/src/connect_things/connect_button_delete.rs @@ -509,7 +509,7 @@ pub fn tree_remove( // Delete duplicated entries, and remove real files for (path, mut vec_file_name) in map_with_path_to_delete { - vec_file_name.sort(); + vec_file_name.sort_unstable(); vec_file_name.dedup(); for file_name in vec_file_name { if !use_trash { diff --git a/czkawka_gui/src/connect_things/connect_selection_of_directories.rs b/czkawka_gui/src/connect_things/connect_selection_of_directories.rs index 2dff914..0deb3b4 100644 --- a/czkawka_gui/src/connect_things/connect_selection_of_directories.rs +++ b/czkawka_gui/src/connect_things/connect_selection_of_directories.rs @@ -8,7 +8,7 @@ use czkawka_core::common::Common; use crate::flg; use crate::gui_structs::gui_data::GuiData; -use crate::help_functions::{get_list_store, ColumnsExcludedDirectory, ColumnsIncludedDirectory}; +use crate::help_functions::{check_if_value_is_in_list_store, get_list_store, ColumnsExcludedDirectory, ColumnsIncludedDirectory}; pub fn connect_selection_of_directories(gui_data: &GuiData) { // Add manually directory @@ -157,20 +157,29 @@ fn add_manually_directories(window_main: &Window, tree_view: &TreeView, excluded let tree_view = tree_view.clone(); dialog.connect_response(move |dialog, response_type| { if response_type == gtk4::ResponseType::Ok { - let text = entry.text().to_string().trim().to_string(); + for text in entry.text().split(';') { + let mut text = text.trim().to_string(); + #[cfg(target_family = "windows")] + let mut text = Common::normalize_windows_path(text).to_string_lossy().to_string(); - #[cfg(target_family = "windows")] - let text = Common::normalize_windows_path(text).to_string_lossy().to_string(); + while text != "/" && (text.ends_with('/') || text.ends_with('\\')) { + text.pop(); + } - if !text.is_empty() { - let list_store = get_list_store(&tree_view); + if !text.is_empty() { + let list_store = get_list_store(&tree_view); - if excluded_items { - let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &text)]; - list_store.set(&list_store.append(), &values); - } else { - let values: [(u32, &dyn ToValue); 2] = [(ColumnsIncludedDirectory::Path as u32, &text), (ColumnsIncludedDirectory::ReferenceButton as u32, &false)]; - list_store.set(&list_store.append(), &values); + if excluded_items { + if !(check_if_value_is_in_list_store(&list_store, ColumnsExcludedDirectory::Path as i32, &text)) { + let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &text)]; + list_store.set(&list_store.append(), &values); + } + } else { + if !check_if_value_is_in_list_store(&list_store, ColumnsIncludedDirectory::Path as i32, &text) { + let values: [(u32, &dyn ToValue); 2] = [(ColumnsIncludedDirectory::Path as u32, &text), (ColumnsIncludedDirectory::ReferenceButton as u32, &false)]; + list_store.set(&list_store.append(), &values); + } + } } } } diff --git a/czkawka_gui/src/gui_structs/gui_main_notebook.rs b/czkawka_gui/src/gui_structs/gui_main_notebook.rs index 5284c88..7da8581 100644 --- a/czkawka_gui/src/gui_structs/gui_main_notebook.rs +++ b/czkawka_gui/src/gui_structs/gui_main_notebook.rs @@ -1,7 +1,7 @@ -use czkawka_core::big_file::SearchMode; use gtk4::prelude::*; use gtk4::{Builder, CheckButton, ComboBoxText, Entry, EventControllerKey, GestureClick, Image, Label, Notebook, Scale, ScrolledWindow, TreeView, Widget}; +use czkawka_core::big_file::SearchMode; use czkawka_core::common_dir_traversal::CheckingMethod; use czkawka_core::localizer_core::{fnc_get_similarity_minimal, fnc_get_similarity_very_high}; use czkawka_core::similar_images::{get_string_from_similarity, SIMILAR_VALUES}; diff --git a/czkawka_gui/src/help_combo_box.rs b/czkawka_gui/src/help_combo_box.rs index b8adbe6..525e997 100644 --- a/czkawka_gui/src/help_combo_box.rs +++ b/czkawka_gui/src/help_combo_box.rs @@ -1,6 +1,6 @@ -use czkawka_core::big_file::SearchMode; use image_hasher::{FilterType, HashAlg}; +use czkawka_core::big_file::SearchMode; use czkawka_core::common_dir_traversal::CheckingMethod; use czkawka_core::duplicate::HashType; diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index b56430e..ccfb2b1 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -712,6 +712,7 @@ pub fn set_icon_of_button>(button: &P, data: &'static [u8]) { } static mut IMAGE_PREVIEW_ARRAY: OnceCell> = OnceCell::new(); + pub fn get_pixbuf_from_dynamic_image(dynamic_image: &DynamicImage) -> Result { let mut output = Vec::new(); JpegEncoder::new(&mut output).encode_image(dynamic_image).unwrap(); @@ -724,31 +725,81 @@ pub fn get_pixbuf_from_dynamic_image(dynamic_image: &DynamicImage) -> Result bool { + if let Some(iter) = list_store.iter_first() { + loop { + let list_store_value: String = list_store.get::(&iter, column as i32); + + if value == list_store_value { + return true; + } + + if !list_store.iter_next(&iter) { + break; + } + } + } + + false } #[cfg(test)] mod test { - use crate::help_functions::{get_all_boxes_from_widget, get_all_direct_children, get_pixbuf_from_dynamic_image}; use gtk4::prelude::*; use gtk4::Orientation; use image::DynamicImage; + use crate::help_functions::{ + change_dimension_to_krotka, check_if_value_is_in_list_store, get_all_boxes_from_widget, get_all_direct_children, get_max_file_name, get_pixbuf_from_dynamic_image, + }; + + #[gtk4::test] + fn test_check_if_value_is_in_list_store() { + let columns_types: &[glib::types::Type] = &[glib::types::Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &"Koczkodan"), (0, &"Kachir")]; + for i in values_to_add { + list_store.set(&list_store.append(), &[*i]); + } + assert!(check_if_value_is_in_list_store(&list_store, 0, "Koczkodan")); + assert!(check_if_value_is_in_list_store(&list_store, 0, "Kachir")); + assert!(!check_if_value_is_in_list_store(&list_store, 0, "Koczkodan2")); + + let columns_types: &[glib::types::Type] = &[glib::types::Type::STRING, glib::types::Type::STRING]; + let list_store = gtk4::ListStore::new(columns_types); + let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &"Koczkodan"), (1, &"Krakus")], &[(0, &"Kachir"), (1, &"Wodnica")]]; + for i in values_to_add { + list_store.set(&list_store.append(), i); + } + assert!(check_if_value_is_in_list_store(&list_store, 0, "Koczkodan")); + assert!(check_if_value_is_in_list_store(&list_store, 1, "Krakus")); + assert!(check_if_value_is_in_list_store(&list_store, 0, "Kachir")); + assert!(check_if_value_is_in_list_store(&list_store, 1, "Wodnica")); + assert!(!check_if_value_is_in_list_store(&list_store, 0, "Krakus")); + assert!(!check_if_value_is_in_list_store(&list_store, 1, "Kachir")); + } + + #[test] + fn test_file_name_shortener() { + let name_to_check = "/home/rafal/czkawek/romek/atomek.txt"; + assert_eq!(get_max_file_name(name_to_check, 20), "/home/rafa ... atomek.txt"); + assert_eq!(get_max_file_name(name_to_check, 21), "/home/rafa ... /atomek.txt"); + let name_to_check = "/home/rafal/czkawek/romek/czekistan/atomek.txt"; + assert_eq!(get_max_file_name(name_to_check, 21), "/home/rafa ... /atomek.txt"); + assert_eq!(get_max_file_name(name_to_check, 80), name_to_check); + let name_to_check = "/home/rafal/‍🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈.txt"; + assert_eq!(get_max_file_name(name_to_check, 21), "/home/rafa ... 🌈🌈🌈🌈🌈🌈🌈.txt"); + assert_eq!(get_max_file_name(name_to_check, 20), "/home/rafa ... 🌈🌈🌈🌈🌈🌈.txt"); + assert_eq!(get_max_file_name(name_to_check, 19), "/home/rafa ... 🌈🌈🌈🌈🌈.txt"); + let name_to_check = "/home/rafal/‍🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️🏳️‍🌈️.txt"; + assert_eq!(get_max_file_name(name_to_check, 21), "/home/rafa ... 🌈\u{fe0f}🏳\u{fe0f}\u{200d}🌈\u{fe0f}.txt"); + assert_eq!(get_max_file_name(name_to_check, 20), "/home/rafa ... \u{fe0f}🏳\u{fe0f}\u{200d}🌈\u{fe0f}.txt"); + assert_eq!(get_max_file_name(name_to_check, 19), "/home/rafa ... 🏳\u{fe0f}\u{200d}🌈\u{fe0f}.txt"); + assert_eq!(get_max_file_name(name_to_check, 18), "/home/rafa ... \u{fe0f}\u{200d}🌈\u{fe0f}.txt"); + assert_eq!(get_max_file_name(name_to_check, 17), "/home/rafa ... \u{200d}🌈\u{fe0f}.txt"); + assert_eq!(get_max_file_name(name_to_check, 16), "/home/rafa ... 🌈\u{fe0f}.txt"); + } + #[test] fn test_pixbuf_from_dynamic_image() { let dynamic_image = DynamicImage::new_rgb8(1, 1); @@ -757,6 +808,11 @@ mod test { get_pixbuf_from_dynamic_image(&dynamic_image).unwrap(); get_pixbuf_from_dynamic_image(&dynamic_image).unwrap(); } + #[test] + fn test_change_dimension_to_krotka() { + assert_eq!(change_dimension_to_krotka("50x50".to_string()), (50, 50)); + assert_eq!(change_dimension_to_krotka("6000x6000".to_string()), (6000, 6000)); + } #[gtk4::test] fn test_get_all_direct_children() {