Sort speedup and manual add window improvements (#782)
* Sort unstable * Multiple entries when using manual add * Do not allow to add multiple same directories to check * Assert
This commit is contained in:
parent
8f0527cd33
commit
2f932e20ff
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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::<Vec<PathBuf>>();
|
||||
actual.sort();
|
||||
actual.sort_unstable();
|
||||
assert_eq!(vec![src, dst], actual);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -549,7 +549,7 @@ impl SameMusic {
|
|||
}
|
||||
let mut hash_map: BTreeMap<String, Vec<MusicEntry>> = 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<String, Vec<MusicEntry>> = 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<String, Vec<MusicEntry>> = 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<String, Vec<MusicEntry>> = 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<String, Vec<MusicEntry>> = 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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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::<Vec<PathBuf>>();
|
||||
|
||||
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)
|
||||
});
|
||||
|
|
|
@ -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<RefCell<(Option<TreePath>, Option<TreePath>)>>,
|
||||
image_cache: Rc<RefCell<Vec<(String, String, Image, Image, TreePath)>>>,
|
||||
) {
|
||||
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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -712,6 +712,7 @@ pub fn set_icon_of_button<P: IsA<Widget>>(button: &P, data: &'static [u8]) {
|
|||
}
|
||||
|
||||
static mut IMAGE_PREVIEW_ARRAY: OnceCell<Vec<u8>> = OnceCell::new();
|
||||
|
||||
pub fn get_pixbuf_from_dynamic_image(dynamic_image: &DynamicImage) -> Result<Pixbuf, Error> {
|
||||
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<Pix
|
|||
Pixbuf::from_read(arra)
|
||||
}
|
||||
|
||||
#[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");
|
||||
pub fn check_if_value_is_in_list_store(list_store: &ListStore, column: i32, value: &str) -> bool {
|
||||
if let Some(iter) = list_store.iter_first() {
|
||||
loop {
|
||||
let list_store_value: String = list_store.get::<String>(&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() {
|
||||
|
|
Loading…
Reference in a new issue