2022-01-11 00:19:28 +13:00
|
|
|
use std::cmp::Ordering;
|
2021-11-28 08:49:20 +13:00
|
|
|
use std::collections::HashMap;
|
2023-05-03 08:37:12 +12:00
|
|
|
use std::io::BufReader;
|
2024-01-16 07:47:07 +13:00
|
|
|
use std::path::{PathBuf, MAIN_SEPARATOR};
|
2021-11-28 08:49:20 +13:00
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
use gdk4::gdk_pixbuf::{InterpType, Pixbuf};
|
2022-06-09 07:42:51 +12:00
|
|
|
use glib::Error;
|
2022-05-22 20:59:09 +12:00
|
|
|
use gtk4::prelude::*;
|
2023-05-08 06:54:05 +12:00
|
|
|
use gtk4::{ListStore, Scale, ScrollType, TextView, TreeView, Widget};
|
2022-06-09 07:42:51 +12:00
|
|
|
use image::codecs::jpeg::JpegEncoder;
|
|
|
|
use image::{DynamicImage, EncodableLayout};
|
|
|
|
use once_cell::sync::OnceCell;
|
2021-11-28 08:49:20 +13:00
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
use czkawka_core::bad_extensions::BadExtensions;
|
2020-11-01 02:23:31 +13:00
|
|
|
use czkawka_core::big_file::BigFile;
|
2021-01-13 08:06:12 +13:00
|
|
|
use czkawka_core::broken_files::BrokenFiles;
|
2022-01-20 10:35:07 +13:00
|
|
|
use czkawka_core::common_dir_traversal;
|
2020-09-30 05:44:20 +13:00
|
|
|
use czkawka_core::common_messages::Messages;
|
2020-11-01 02:23:31 +13:00
|
|
|
use czkawka_core::duplicate::DuplicateFinder;
|
|
|
|
use czkawka_core::empty_files::EmptyFiles;
|
|
|
|
use czkawka_core::empty_folder::EmptyFolder;
|
2020-12-22 04:09:39 +13:00
|
|
|
use czkawka_core::invalid_symlinks::InvalidSymlinks;
|
2020-11-03 09:56:07 +13:00
|
|
|
use czkawka_core::same_music::SameMusic;
|
2021-07-25 08:00:39 +12:00
|
|
|
use czkawka_core::similar_images::SimilarImages;
|
2021-11-23 23:10:24 +13:00
|
|
|
use czkawka_core::similar_videos::SimilarVideos;
|
2020-11-01 02:23:31 +13:00
|
|
|
use czkawka_core::temporary::Temporary;
|
2021-11-28 08:49:20 +13:00
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
use crate::flg;
|
2022-06-22 03:24:08 +12:00
|
|
|
use crate::notebook_enums::{NotebookMainEnum, NotebookUpperEnum};
|
|
|
|
use crate::notebook_info::{NotebookObject, NOTEBOOKS_INFO};
|
2020-11-01 02:23:31 +13:00
|
|
|
|
2021-11-29 23:38:38 +13:00
|
|
|
pub const KEY_DELETE: u32 = 119;
|
|
|
|
pub const KEY_ENTER: u32 = 36;
|
|
|
|
pub const KEY_SPACE: u32 = 65;
|
|
|
|
|
2021-12-04 03:17:59 +13:00
|
|
|
// pub const KEY_DOWN: u32 = 116;
|
|
|
|
// pub const KEY_UP: u32 = 111;
|
|
|
|
// pub const KEY_PG_DOWN: u32 = 117;
|
|
|
|
// pub const KEY_PG_UP: u32 = 112;
|
|
|
|
// pub const KEY_HOME: u32 = 115;
|
|
|
|
// pub const KEY_END: u32 = 110;
|
2021-11-29 23:38:38 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
2021-11-25 20:36:49 +13:00
|
|
|
pub enum PopoverTypes {
|
|
|
|
All,
|
2021-12-02 08:09:04 +13:00
|
|
|
Size,
|
2021-11-25 20:36:49 +13:00
|
|
|
Reverse,
|
|
|
|
Custom,
|
|
|
|
Date,
|
|
|
|
}
|
|
|
|
|
2023-07-10 18:36:03 +12:00
|
|
|
#[derive(Eq, PartialEq, Copy, Clone, Hash, Debug)]
|
2022-01-14 18:34:43 +13:00
|
|
|
pub enum BottomButtonsEnum {
|
|
|
|
Search,
|
|
|
|
Select,
|
|
|
|
Delete,
|
|
|
|
Save,
|
|
|
|
Symlink,
|
|
|
|
Hardlink,
|
|
|
|
Move,
|
|
|
|
Compare,
|
2023-02-19 22:21:14 +13:00
|
|
|
Sort,
|
2022-01-14 18:34:43 +13:00
|
|
|
}
|
|
|
|
|
2020-11-01 02:23:31 +13:00
|
|
|
pub enum Message {
|
|
|
|
Duplicates(DuplicateFinder),
|
|
|
|
EmptyFolders(EmptyFolder),
|
|
|
|
EmptyFiles(EmptyFiles),
|
|
|
|
BigFiles(BigFile),
|
|
|
|
Temporary(Temporary),
|
|
|
|
SimilarImages(SimilarImages),
|
2021-11-23 23:10:24 +13:00
|
|
|
SimilarVideos(SimilarVideos),
|
2020-11-03 09:56:07 +13:00
|
|
|
SameMusic(SameMusic),
|
2020-12-22 04:09:39 +13:00
|
|
|
InvalidSymlinks(InvalidSymlinks),
|
2021-01-13 08:06:12 +13:00
|
|
|
BrokenFiles(BrokenFiles),
|
2022-04-23 07:46:33 +12:00
|
|
|
BadExtensions(BadExtensions),
|
2020-11-01 02:23:31 +13:00
|
|
|
}
|
2020-09-30 05:44:20 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-10-01 19:53:17 +13:00
|
|
|
pub enum ColumnsDuplicates {
|
2020-10-02 02:55:45 +13:00
|
|
|
// Columns for duplicate treeview
|
2021-11-20 21:43:24 +13:00
|
|
|
ActivatableSelectButton = 0,
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton,
|
2021-12-24 21:18:55 +13:00
|
|
|
Size,
|
2023-02-19 22:21:14 +13:00
|
|
|
SizeAsBytes,
|
2021-07-16 16:51:54 +12:00
|
|
|
Name,
|
2020-10-01 19:53:17 +13:00
|
|
|
Path,
|
|
|
|
Modification,
|
|
|
|
ModificationAsSecs,
|
|
|
|
Color,
|
2022-05-22 20:59:09 +12:00
|
|
|
IsHeader,
|
2020-10-02 02:25:58 +13:00
|
|
|
TextColor,
|
2020-10-01 19:53:17 +13:00
|
|
|
}
|
2020-10-02 02:25:58 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-10-02 06:26:25 +13:00
|
|
|
pub enum ColumnsEmptyFolders {
|
2020-10-02 02:55:45 +13:00
|
|
|
// Columns for empty folder treeview
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton = 0,
|
2021-07-16 16:51:54 +12:00
|
|
|
Name,
|
2020-09-30 05:44:20 +13:00
|
|
|
Path,
|
|
|
|
Modification,
|
2021-12-05 08:41:02 +13:00
|
|
|
ModificationAsSecs,
|
2020-09-30 05:44:20 +13:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2021-12-24 21:18:55 +13:00
|
|
|
pub enum ColumnsIncludedDirectory {
|
|
|
|
// Columns for Included Directories in upper Notebook
|
|
|
|
Path = 0,
|
|
|
|
ReferenceButton,
|
|
|
|
}
|
2022-06-01 03:52:55 +12:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2021-12-24 21:18:55 +13:00
|
|
|
pub enum ColumnsExcludedDirectory {
|
|
|
|
// Columns for Excluded Directories in upper Notebook
|
2020-09-30 05:44:20 +13:00
|
|
|
Path = 0,
|
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-10-02 06:26:25 +13:00
|
|
|
pub enum ColumnsBigFiles {
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton = 0,
|
2021-07-16 16:51:54 +12:00
|
|
|
Size,
|
2020-10-02 06:26:25 +13:00
|
|
|
Name,
|
|
|
|
Path,
|
|
|
|
Modification,
|
2021-12-05 08:41:02 +13:00
|
|
|
SizeAsBytes,
|
|
|
|
ModificationAsSecs,
|
2020-10-02 06:26:25 +13:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-10-02 06:26:25 +13:00
|
|
|
pub enum ColumnsEmptyFiles {
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton = 0,
|
2021-07-16 16:51:54 +12:00
|
|
|
Name,
|
2020-10-02 06:26:25 +13:00
|
|
|
Path,
|
|
|
|
Modification,
|
2021-12-05 08:41:02 +13:00
|
|
|
ModificationAsSecs,
|
2020-10-02 06:26:25 +13:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-10-02 06:26:25 +13:00
|
|
|
pub enum ColumnsTemporaryFiles {
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton = 0,
|
2021-07-16 16:51:54 +12:00
|
|
|
Name,
|
2020-10-02 06:26:25 +13:00
|
|
|
Path,
|
|
|
|
Modification,
|
2021-12-05 08:41:02 +13:00
|
|
|
ModificationAsSecs,
|
2020-10-02 06:26:25 +13:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-10-15 20:04:02 +13:00
|
|
|
pub enum ColumnsSimilarImages {
|
2021-11-20 21:43:24 +13:00
|
|
|
ActivatableSelectButton = 0,
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton,
|
2021-07-16 16:51:54 +12:00
|
|
|
Similarity,
|
2020-10-16 04:51:47 +13:00
|
|
|
Size,
|
2020-12-26 22:35:43 +13:00
|
|
|
SizeAsBytes,
|
2020-10-16 04:51:47 +13:00
|
|
|
Dimensions,
|
2020-10-15 20:04:02 +13:00
|
|
|
Name,
|
|
|
|
Path,
|
|
|
|
Modification,
|
2020-11-09 22:09:22 +13:00
|
|
|
ModificationAsSecs,
|
2020-10-16 04:51:47 +13:00
|
|
|
Color,
|
2022-05-22 20:59:09 +12:00
|
|
|
IsHeader,
|
2020-10-16 04:51:47 +13:00
|
|
|
TextColor,
|
2020-10-15 20:04:02 +13:00
|
|
|
}
|
2021-11-23 23:10:24 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2021-11-23 23:10:24 +13:00
|
|
|
pub enum ColumnsSimilarVideos {
|
|
|
|
ActivatableSelectButton = 0,
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton,
|
2021-11-23 23:10:24 +13:00
|
|
|
Size,
|
|
|
|
SizeAsBytes,
|
|
|
|
Name,
|
|
|
|
Path,
|
|
|
|
Modification,
|
|
|
|
ModificationAsSecs,
|
|
|
|
Color,
|
2022-05-22 20:59:09 +12:00
|
|
|
IsHeader,
|
2021-11-23 23:10:24 +13:00
|
|
|
TextColor,
|
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-11-03 09:56:07 +13:00
|
|
|
pub enum ColumnsSameMusic {
|
2021-11-20 21:43:24 +13:00
|
|
|
ActivatableSelectButton = 0,
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton,
|
2021-07-16 16:51:54 +12:00
|
|
|
Size,
|
2020-12-26 22:35:43 +13:00
|
|
|
SizeAsBytes,
|
2020-11-03 09:56:07 +13:00
|
|
|
Name,
|
|
|
|
Path,
|
|
|
|
Title,
|
|
|
|
Artist,
|
|
|
|
Year,
|
2022-02-26 06:47:25 +13:00
|
|
|
Bitrate,
|
|
|
|
BitrateAsNumber,
|
|
|
|
Length,
|
|
|
|
Genre,
|
2020-11-03 09:56:07 +13:00
|
|
|
Modification,
|
2020-11-09 22:09:22 +13:00
|
|
|
ModificationAsSecs,
|
2020-11-03 09:56:07 +13:00
|
|
|
Color,
|
2022-05-22 20:59:09 +12:00
|
|
|
IsHeader,
|
2020-11-03 09:56:07 +13:00
|
|
|
TextColor,
|
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2020-12-22 04:09:39 +13:00
|
|
|
pub enum ColumnsInvalidSymlinks {
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton = 0,
|
2021-07-16 16:51:54 +12:00
|
|
|
Name,
|
2020-12-22 09:19:59 +13:00
|
|
|
Path,
|
2020-12-22 04:09:39 +13:00
|
|
|
DestinationPath,
|
|
|
|
TypeOfError,
|
|
|
|
Modification,
|
2021-12-05 08:41:02 +13:00
|
|
|
ModificationAsSecs,
|
2020-12-22 04:09:39 +13:00
|
|
|
}
|
2020-09-30 05:44:20 +13:00
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2021-01-13 08:06:12 +13:00
|
|
|
pub enum ColumnsBrokenFiles {
|
2021-11-25 20:36:49 +13:00
|
|
|
SelectionButton = 0,
|
2021-07-16 16:51:54 +12:00
|
|
|
Name,
|
2021-01-13 08:06:12 +13:00
|
|
|
Path,
|
|
|
|
ErrorType,
|
|
|
|
Modification,
|
2021-12-05 08:41:02 +13:00
|
|
|
ModificationAsSecs,
|
2021-01-13 08:06:12 +13:00
|
|
|
}
|
|
|
|
|
2023-02-19 22:21:14 +13:00
|
|
|
#[derive(Clone, Copy)]
|
2022-04-23 07:46:33 +12:00
|
|
|
pub enum ColumnsBadExtensions {
|
|
|
|
SelectionButton = 0,
|
|
|
|
Name,
|
|
|
|
Path,
|
|
|
|
CurrentExtension,
|
|
|
|
ValidExtensions,
|
|
|
|
Modification,
|
|
|
|
ModificationAsSecs,
|
|
|
|
}
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
pub const MAIN_ROW_COLOR: &str = "#222222";
|
|
|
|
pub const HEADER_ROW_COLOR: &str = "#111111";
|
2020-10-02 02:25:58 +13:00
|
|
|
pub const TEXT_COLOR: &str = "#ffffff";
|
2020-09-30 05:44:20 +13:00
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn get_string_from_list_store(tree_view: &TreeView, column_full_path: i32, column_selection: Option<i32>) -> Vec<String> {
|
|
|
|
let list_store: ListStore = get_list_store(tree_view);
|
2020-09-30 05:44:20 +13:00
|
|
|
|
2021-01-11 08:44:10 +13:00
|
|
|
let mut string_vector: Vec<String> = Vec::new();
|
|
|
|
|
2023-04-05 18:08:43 +12:00
|
|
|
let Some(tree_iter) = list_store.iter_first() else {
|
|
|
|
return string_vector;
|
2020-09-30 05:44:20 +13:00
|
|
|
};
|
2021-12-24 21:18:55 +13:00
|
|
|
match column_selection {
|
|
|
|
Some(column_selection) => loop {
|
2022-05-22 20:59:09 +12:00
|
|
|
if list_store.get::<bool>(&tree_iter, column_selection) {
|
|
|
|
string_vector.push(list_store.get::<String>(&tree_iter, column_full_path));
|
2021-12-24 21:18:55 +13:00
|
|
|
}
|
|
|
|
if !list_store.iter_next(&tree_iter) {
|
|
|
|
return string_vector;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => loop {
|
2022-05-22 20:59:09 +12:00
|
|
|
string_vector.push(list_store.get::<String>(&tree_iter, column_full_path));
|
2021-12-24 21:18:55 +13:00
|
|
|
if !list_store.iter_next(&tree_iter) {
|
|
|
|
return string_vector;
|
|
|
|
}
|
|
|
|
},
|
2020-09-30 07:19:36 +13:00
|
|
|
}
|
2020-09-30 05:44:20 +13:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2023-01-29 06:54:02 +13:00
|
|
|
pub fn get_path_buf_from_vector_of_strings(vec_string: &[String]) -> Vec<PathBuf> {
|
2021-01-11 08:44:10 +13:00
|
|
|
vec_string.iter().map(PathBuf::from).collect()
|
|
|
|
}
|
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn print_text_messages_to_text_view(text_messages: &Messages, text_view: &TextView) {
|
2023-01-29 06:54:02 +13:00
|
|
|
let mut messages: String = String::new();
|
2020-09-30 05:44:20 +13:00
|
|
|
if !text_messages.messages.is_empty() {
|
2022-01-20 10:35:07 +13:00
|
|
|
messages += format!("############### {}({}) ###############\n", flg!("text_view_messages"), text_messages.messages.len()).as_str();
|
2020-09-30 05:44:20 +13:00
|
|
|
}
|
|
|
|
for text in &text_messages.messages {
|
|
|
|
messages += text.as_str();
|
|
|
|
messages += "\n";
|
|
|
|
}
|
2021-12-06 09:01:16 +13:00
|
|
|
// if !text_messages.messages.is_empty() {
|
|
|
|
// messages += "\n";
|
|
|
|
// }
|
2020-09-30 05:44:20 +13:00
|
|
|
if !text_messages.warnings.is_empty() {
|
2022-01-20 10:35:07 +13:00
|
|
|
messages += format!("############### {}({}) ###############\n", flg!("text_view_warnings"), text_messages.warnings.len()).as_str();
|
2020-09-30 05:44:20 +13:00
|
|
|
}
|
|
|
|
for text in &text_messages.warnings {
|
|
|
|
messages += text.as_str();
|
|
|
|
messages += "\n";
|
|
|
|
}
|
2021-12-06 09:01:16 +13:00
|
|
|
// if !text_messages.warnings.is_empty() {
|
|
|
|
// messages += "\n";
|
|
|
|
// }
|
2020-09-30 05:44:20 +13:00
|
|
|
if !text_messages.errors.is_empty() {
|
2022-01-20 10:35:07 +13:00
|
|
|
messages += format!("############### {}({}) ###############\n", flg!("text_view_errors"), text_messages.errors.len()).as_str();
|
2020-09-30 05:44:20 +13:00
|
|
|
}
|
|
|
|
for text in &text_messages.errors {
|
|
|
|
messages += text.as_str();
|
|
|
|
messages += "\n";
|
|
|
|
}
|
2021-12-06 09:01:16 +13:00
|
|
|
// if !text_messages.errors.is_empty() {
|
|
|
|
// messages += "\n";
|
|
|
|
// }
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
text_view.buffer().set_text(messages.as_str());
|
2020-09-30 05:44:20 +13:00
|
|
|
}
|
|
|
|
|
2020-12-19 22:03:04 +13:00
|
|
|
pub fn reset_text_view(text_view: &TextView) {
|
2022-05-22 20:59:09 +12:00
|
|
|
text_view.buffer().set_text("");
|
2020-12-19 22:03:04 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_text_to_text_view(text_view: &TextView, string_to_append: &str) {
|
2022-05-22 20:59:09 +12:00
|
|
|
let buffer = text_view.buffer();
|
|
|
|
let current_text = buffer.text(&buffer.start_iter(), &buffer.end_iter(), true).to_string();
|
2021-12-27 00:08:37 +13:00
|
|
|
if current_text.is_empty() {
|
|
|
|
buffer.set_text(string_to_append);
|
|
|
|
} else {
|
2022-12-21 20:44:26 +13:00
|
|
|
buffer.set_text(format!("{current_text}\n{string_to_append}").as_str());
|
2021-12-27 00:08:37 +13:00
|
|
|
}
|
2020-12-19 22:03:04 +13:00
|
|
|
}
|
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn set_buttons(hashmap: &mut HashMap<BottomButtonsEnum, bool>, buttons_array: &[Widget], button_names: &[BottomButtonsEnum]) {
|
2020-10-08 09:22:39 +13:00
|
|
|
for (index, button) in buttons_array.iter().enumerate() {
|
2022-01-14 18:34:43 +13:00
|
|
|
if *hashmap.get_mut(&button_names[index]).unwrap() {
|
2021-01-11 00:06:25 +13:00
|
|
|
button.show();
|
2020-10-08 09:22:39 +13:00
|
|
|
} else {
|
|
|
|
button.hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2021-12-01 23:09:47 +13:00
|
|
|
pub fn hide_all_buttons(buttons_array: &[Widget]) {
|
2020-12-02 22:58:31 +13:00
|
|
|
for button in buttons_array {
|
|
|
|
button.hide();
|
2020-10-08 09:22:39 +13:00
|
|
|
}
|
|
|
|
}
|
2020-10-15 20:04:02 +13:00
|
|
|
|
2022-01-02 09:07:20 +13:00
|
|
|
pub fn get_text_from_invalid_symlink_cause(error: &common_dir_traversal::ErrorType) -> String {
|
2020-12-22 04:09:39 +13:00
|
|
|
match error {
|
2022-01-20 10:35:07 +13:00
|
|
|
common_dir_traversal::ErrorType::InfiniteRecursion => flg!("invalid_symlink_infinite_recursion"),
|
|
|
|
common_dir_traversal::ErrorType::NonExistentFile => flg!("invalid_symlink_non_existent_destination"),
|
2020-12-22 04:09:39 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn get_list_store(tree_view: &TreeView) -> ListStore {
|
|
|
|
tree_view.model().unwrap().downcast::<ListStore>().unwrap()
|
2020-11-08 04:26:40 +13:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
pub fn get_dialog_box_child(dialog: >k4::Dialog) -> gtk4::Box {
|
|
|
|
dialog.child().unwrap().downcast::<gtk4::Box>().unwrap()
|
2021-01-08 10:10:11 +13:00
|
|
|
}
|
2020-12-27 00:53:40 +13:00
|
|
|
|
2023-01-29 06:54:02 +13:00
|
|
|
pub fn change_dimension_to_krotka(dimensions: &str) -> (u64, u64) {
|
2020-12-27 00:53:40 +13:00
|
|
|
#[allow(clippy::single_char_pattern)]
|
|
|
|
let vec = dimensions.split::<&str>("x").collect::<Vec<_>>();
|
2021-01-11 00:06:25 +13:00
|
|
|
assert_eq!(vec.len(), 2); // 400x400 - should only have two elements, if have more, then something is not good
|
2020-12-27 00:53:40 +13:00
|
|
|
let number1 = vec[0].parse::<u64>().expect("Invalid data in image dimension in position 0");
|
|
|
|
let number2 = vec[1].parse::<u64>().expect("Invalid data in image dimension in position 1");
|
|
|
|
(number1, number2)
|
|
|
|
}
|
2021-11-25 20:36:49 +13:00
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn get_notebook_enum_from_tree_view(tree_view: &TreeView) -> NotebookMainEnum {
|
2021-11-25 20:36:49 +13:00
|
|
|
match (*tree_view).widget_name().to_string().as_str() {
|
|
|
|
"tree_view_duplicate_finder" => NotebookMainEnum::Duplicate,
|
|
|
|
"tree_view_empty_folder_finder" => NotebookMainEnum::EmptyDirectories,
|
|
|
|
"tree_view_empty_files_finder" => NotebookMainEnum::EmptyFiles,
|
|
|
|
"tree_view_temporary_files_finder" => NotebookMainEnum::Temporary,
|
|
|
|
"tree_view_big_files_finder" => NotebookMainEnum::BigFiles,
|
|
|
|
"tree_view_similar_images_finder" => NotebookMainEnum::SimilarImages,
|
|
|
|
"tree_view_similar_videos_finder" => NotebookMainEnum::SimilarVideos,
|
|
|
|
"tree_view_same_music_finder" => NotebookMainEnum::SameMusic,
|
|
|
|
"tree_view_invalid_symlinks" => NotebookMainEnum::Symlinks,
|
|
|
|
"tree_view_broken_files" => NotebookMainEnum::BrokenFiles,
|
2022-04-23 07:46:33 +12:00
|
|
|
"tree_view_bad_extensions" => NotebookMainEnum::BadExtensions,
|
2021-11-29 23:38:38 +13:00
|
|
|
e => {
|
2021-12-01 23:09:47 +13:00
|
|
|
panic!("{}", e)
|
2021-11-29 23:38:38 +13:00
|
|
|
}
|
2021-11-25 20:36:49 +13:00
|
|
|
}
|
|
|
|
}
|
2023-10-05 19:06:47 +13:00
|
|
|
|
2023-05-11 07:27:41 +12:00
|
|
|
pub fn get_tree_view_name_from_notebook_enum(notebook_enum: NotebookMainEnum) -> &'static str {
|
|
|
|
match notebook_enum {
|
|
|
|
NotebookMainEnum::Duplicate => "tree_view_duplicate_finder",
|
|
|
|
NotebookMainEnum::EmptyDirectories => "tree_view_empty_folder_finder",
|
|
|
|
NotebookMainEnum::EmptyFiles => "tree_view_empty_files_finder",
|
|
|
|
NotebookMainEnum::Temporary => "tree_view_temporary_files_finder",
|
|
|
|
NotebookMainEnum::BigFiles => "tree_view_big_files_finder",
|
|
|
|
NotebookMainEnum::SimilarImages => "tree_view_similar_images_finder",
|
|
|
|
NotebookMainEnum::SimilarVideos => "tree_view_similar_videos_finder",
|
|
|
|
NotebookMainEnum::SameMusic => "tree_view_same_music_finder",
|
|
|
|
NotebookMainEnum::Symlinks => "tree_view_invalid_symlinks",
|
|
|
|
NotebookMainEnum::BrokenFiles => "tree_view_broken_files",
|
|
|
|
NotebookMainEnum::BadExtensions => "tree_view_bad_extensions",
|
|
|
|
}
|
|
|
|
}
|
2021-11-25 20:36:49 +13:00
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn get_notebook_upper_enum_from_tree_view(tree_view: &TreeView) -> NotebookUpperEnum {
|
2021-12-24 21:18:55 +13:00
|
|
|
match (*tree_view).widget_name().to_string().as_str() {
|
|
|
|
"tree_view_upper_included_directories" => NotebookUpperEnum::IncludedDirectories,
|
|
|
|
"tree_view_upper_excluded_directories" => NotebookUpperEnum::ExcludedDirectories,
|
2023-05-11 07:27:41 +12:00
|
|
|
e => panic!("{}", e),
|
|
|
|
}
|
|
|
|
}
|
2023-10-05 19:06:47 +13:00
|
|
|
|
2023-05-11 07:27:41 +12:00
|
|
|
pub fn get_tree_view_name_from_notebook_upper_enum(notebook_upper_enum: NotebookUpperEnum) -> &'static str {
|
|
|
|
match notebook_upper_enum {
|
|
|
|
NotebookUpperEnum::IncludedDirectories => "tree_view_upper_included_directories",
|
|
|
|
NotebookUpperEnum::ExcludedDirectories => "tree_view_upper_excluded_directories",
|
|
|
|
_ => panic!(),
|
2021-12-24 21:18:55 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn get_notebook_object_from_tree_view(tree_view: &TreeView) -> &NotebookObject {
|
2021-11-25 20:36:49 +13:00
|
|
|
let nb_enum = get_notebook_enum_from_tree_view(tree_view);
|
2022-06-22 03:24:08 +12:00
|
|
|
&NOTEBOOKS_INFO[nb_enum as usize]
|
2021-11-25 20:36:49 +13:00
|
|
|
}
|
|
|
|
|
2021-12-22 06:23:17 +13:00
|
|
|
pub fn get_full_name_from_path_name(path: &str, name: &str) -> String {
|
|
|
|
let mut string = String::with_capacity(path.len() + name.len() + 1);
|
|
|
|
string.push_str(path);
|
2024-01-16 07:47:07 +13:00
|
|
|
string.push(MAIN_SEPARATOR);
|
2021-12-22 06:23:17 +13:00
|
|
|
string.push_str(name);
|
|
|
|
string
|
|
|
|
}
|
|
|
|
|
2021-11-25 20:36:49 +13:00
|
|
|
// After e.g. deleting files, header may become orphan or have one child, so should be deleted in this case
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn clean_invalid_headers(model: &ListStore, column_header: i32, column_path: i32) {
|
2021-11-25 20:36:49 +13:00
|
|
|
// Remove only child from header
|
|
|
|
if let Some(first_iter) = model.iter_first() {
|
2022-05-22 20:59:09 +12:00
|
|
|
let mut vec_tree_path_to_delete: Vec<gtk4::TreePath> = Vec::new();
|
2021-11-25 20:36:49 +13:00
|
|
|
let mut current_iter = first_iter;
|
2023-01-29 06:54:02 +13:00
|
|
|
// First element should be header
|
|
|
|
assert!(model.get::<bool>(¤t_iter, column_header), "First deleted element, should be a header");
|
2021-11-25 20:36:49 +13:00
|
|
|
|
|
|
|
let mut next_iter;
|
|
|
|
let mut next_next_iter;
|
|
|
|
|
2021-12-24 21:18:55 +13:00
|
|
|
// Empty means default check type
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<String>(¤t_iter, column_path).is_empty() {
|
2021-12-24 21:18:55 +13:00
|
|
|
'main: loop {
|
2023-01-29 06:54:02 +13:00
|
|
|
// First element should be header
|
|
|
|
assert!(model.get::<bool>(¤t_iter, column_header), "First deleted element, should be a header");
|
2021-12-24 21:18:55 +13:00
|
|
|
|
2022-02-02 05:08:41 +13:00
|
|
|
next_iter = current_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
if !model.iter_next(&next_iter) {
|
|
|
|
// There is only single header left (H1 -> END) -> (NOTHING)
|
2022-05-22 20:59:09 +12:00
|
|
|
vec_tree_path_to_delete.push(model.path(¤t_iter));
|
2021-12-24 21:18:55 +13:00
|
|
|
break 'main;
|
|
|
|
}
|
2021-11-25 20:36:49 +13:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&next_iter, column_header) {
|
2021-12-24 21:18:55 +13:00
|
|
|
// There are two headers each others(we remove just first) -> (H1 -> H2) -> (H2)
|
2022-05-22 20:59:09 +12:00
|
|
|
vec_tree_path_to_delete.push(model.path(¤t_iter));
|
2022-02-02 05:08:41 +13:00
|
|
|
current_iter = next_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
continue 'main;
|
|
|
|
}
|
2021-11-25 20:36:49 +13:00
|
|
|
|
2022-02-02 05:08:41 +13:00
|
|
|
next_next_iter = next_iter;
|
2021-11-25 20:36:49 +13:00
|
|
|
if !model.iter_next(&next_next_iter) {
|
2021-12-24 21:18:55 +13:00
|
|
|
// There is only one child of header left, so we remove it with header (H1 -> C1 -> END) -> (NOTHING)
|
2022-05-22 20:59:09 +12:00
|
|
|
vec_tree_path_to_delete.push(model.path(¤t_iter));
|
|
|
|
vec_tree_path_to_delete.push(model.path(&next_iter));
|
2021-11-25 20:36:49 +13:00
|
|
|
break 'main;
|
|
|
|
}
|
2021-12-24 21:18:55 +13:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&next_next_iter, column_header) {
|
2021-12-24 21:18:55 +13:00
|
|
|
// One child between two headers, we can remove them (H1 -> C1 -> H2) -> (H2)
|
2022-05-22 20:59:09 +12:00
|
|
|
vec_tree_path_to_delete.push(model.path(¤t_iter));
|
|
|
|
vec_tree_path_to_delete.push(model.path(&next_iter));
|
2022-02-02 05:08:41 +13:00
|
|
|
current_iter = next_next_iter;
|
2021-11-25 20:36:49 +13:00
|
|
|
continue 'main;
|
|
|
|
}
|
2021-12-24 21:18:55 +13:00
|
|
|
|
|
|
|
loop {
|
|
|
|
// (H1 -> C1 -> C2 -> Cn -> END) -> (NO CHANGE, BECAUSE IS GOOD)
|
|
|
|
if !model.iter_next(&next_next_iter) {
|
|
|
|
break 'main;
|
|
|
|
}
|
|
|
|
// Move to next header
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&next_next_iter, column_header) {
|
2022-02-02 05:08:41 +13:00
|
|
|
current_iter = next_next_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
continue 'main;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for tree_path in vec_tree_path_to_delete.iter().rev() {
|
|
|
|
model.remove(&model.iter(tree_path).unwrap());
|
2021-11-25 20:36:49 +13:00
|
|
|
}
|
|
|
|
}
|
2021-12-24 21:18:55 +13:00
|
|
|
// Non empty means that header points at reference folder
|
|
|
|
else {
|
|
|
|
'reference: loop {
|
2023-01-29 06:54:02 +13:00
|
|
|
// First element should be header
|
|
|
|
assert!(model.get::<bool>(¤t_iter, column_header), "First deleted element, should be a header");
|
2021-12-24 21:18:55 +13:00
|
|
|
|
2022-02-02 05:08:41 +13:00
|
|
|
next_iter = current_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
if !model.iter_next(&next_iter) {
|
|
|
|
// There is only single header left (H1 -> END) -> (NOTHING)
|
2022-05-22 20:59:09 +12:00
|
|
|
vec_tree_path_to_delete.push(model.path(¤t_iter));
|
2021-12-24 21:18:55 +13:00
|
|
|
break 'reference;
|
|
|
|
}
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&next_iter, column_header) {
|
2021-12-24 21:18:55 +13:00
|
|
|
// There are two headers each others(we remove just first) -> (H1 -> H2) -> (H2)
|
2022-05-22 20:59:09 +12:00
|
|
|
vec_tree_path_to_delete.push(model.path(¤t_iter));
|
2022-02-02 05:08:41 +13:00
|
|
|
current_iter = next_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
continue 'reference;
|
|
|
|
}
|
|
|
|
|
2022-02-02 05:08:41 +13:00
|
|
|
next_next_iter = next_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&next_next_iter, column_header) {
|
2021-12-24 21:18:55 +13:00
|
|
|
// One child between two headers, we can remove them (H1 -> C1 -> H2) -> (H2)
|
2022-02-02 05:08:41 +13:00
|
|
|
current_iter = next_next_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
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
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&next_next_iter, column_header) {
|
2022-02-02 05:08:41 +13:00
|
|
|
current_iter = next_next_iter;
|
2021-12-24 21:18:55 +13:00
|
|
|
continue 'reference;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for tree_path in vec_tree_path_to_delete.iter().rev() {
|
|
|
|
model.remove(&model.iter(tree_path).unwrap());
|
|
|
|
}
|
2021-11-25 20:36:49 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Last step, remove orphan header if exists
|
|
|
|
if let Some(iter) = model.iter_first() {
|
|
|
|
if !model.iter_next(&iter) {
|
|
|
|
model.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-01 03:52:55 +12:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
pub fn check_how_much_elements_is_selected(tree_view: &TreeView, column_header: Option<i32>, column_selection: i32) -> (u64, u64) {
|
2021-12-22 06:23:17 +13:00
|
|
|
let mut number_of_selected_items: u64 = 0;
|
|
|
|
let mut number_of_selected_groups: u64 = 0;
|
|
|
|
|
|
|
|
let model = get_list_store(tree_view);
|
|
|
|
|
|
|
|
let mut is_item_currently_selected_in_group: bool = false;
|
|
|
|
|
|
|
|
// First iter
|
|
|
|
if let Some(iter) = model.iter_first() {
|
2022-05-22 20:59:09 +12:00
|
|
|
if let Some(column_header) = column_header {
|
|
|
|
assert!(model.get::<bool>(&iter, column_header)); // First element should be header
|
2021-12-22 06:23:17 +13:00
|
|
|
|
|
|
|
loop {
|
|
|
|
if !model.iter_next(&iter) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&iter, column_header) {
|
2021-12-22 06:23:17 +13:00
|
|
|
is_item_currently_selected_in_group = false;
|
|
|
|
} else {
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&iter, column_selection) {
|
2021-12-22 06:23:17 +13:00
|
|
|
number_of_selected_items += 1;
|
|
|
|
|
|
|
|
if !is_item_currently_selected_in_group {
|
|
|
|
number_of_selected_groups += 1;
|
|
|
|
}
|
|
|
|
is_item_currently_selected_in_group = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&iter, column_selection) {
|
|
|
|
number_of_selected_items += 1;
|
|
|
|
}
|
2021-12-22 06:23:17 +13:00
|
|
|
loop {
|
|
|
|
if !model.iter_next(&iter) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&iter, column_selection) {
|
2021-12-22 06:23:17 +13:00
|
|
|
number_of_selected_items += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(number_of_selected_items, number_of_selected_groups)
|
|
|
|
}
|
2021-12-12 04:16:14 +13:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
pub fn count_number_of_groups(tree_view: &TreeView, column_header: i32) -> u32 {
|
2022-01-11 00:19:28 +13:00
|
|
|
let mut number_of_selected_groups = 0;
|
|
|
|
|
|
|
|
let model = get_list_store(tree_view);
|
|
|
|
|
|
|
|
if let Some(iter) = model.iter_first() {
|
2022-05-22 20:59:09 +12:00
|
|
|
assert!(model.get::<bool>(&iter, column_header)); // First element should be header
|
2022-01-11 00:19:28 +13:00
|
|
|
number_of_selected_groups += 1;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if !model.iter_next(&iter) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
if model.get::<bool>(&iter, column_header) {
|
2022-01-11 00:19:28 +13:00
|
|
|
number_of_selected_groups += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
number_of_selected_groups
|
|
|
|
}
|
|
|
|
|
2023-01-29 06:54:02 +13:00
|
|
|
pub fn resize_pixbuf_dimension(pixbuf: &Pixbuf, requested_size: (i32, i32), interp_type: InterpType) -> Option<Pixbuf> {
|
2022-04-06 02:40:41 +12:00
|
|
|
let current_ratio = pixbuf.width() as f32 / pixbuf.height() as f32;
|
2022-01-11 00:19:28 +13:00
|
|
|
let mut new_size;
|
|
|
|
match current_ratio.partial_cmp(&(requested_size.0 as f32 / requested_size.1 as f32)).unwrap() {
|
|
|
|
Ordering::Greater => {
|
2022-04-06 02:40:41 +12:00
|
|
|
new_size = (requested_size.0, (pixbuf.height() * requested_size.0) / pixbuf.width());
|
2022-01-11 00:19:28 +13:00
|
|
|
new_size = (std::cmp::max(new_size.0, 1), std::cmp::max(new_size.1, 1));
|
|
|
|
}
|
|
|
|
Ordering::Less => {
|
2022-04-06 02:40:41 +12:00
|
|
|
new_size = ((pixbuf.width() * requested_size.1) / pixbuf.height(), requested_size.1);
|
2022-01-11 00:19:28 +13:00
|
|
|
new_size = (std::cmp::max(new_size.0, 1), std::cmp::max(new_size.1, 1));
|
|
|
|
}
|
|
|
|
Ordering::Equal => {
|
|
|
|
new_size = (requested_size.0, requested_size.1);
|
|
|
|
new_size = (std::cmp::max(new_size.0, 1), std::cmp::max(new_size.1, 1));
|
|
|
|
}
|
|
|
|
}
|
2022-04-06 02:40:41 +12:00
|
|
|
pixbuf.scale_simple(new_size.0, new_size.1, interp_type)
|
2022-01-11 00:19:28 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_max_file_name(file_name: &str, max_length: usize) -> String {
|
|
|
|
assert!(max_length > 10); // Maybe in future will be supported lower values
|
2022-07-20 05:09:52 +12:00
|
|
|
let characters_in_filename = file_name.chars().count();
|
|
|
|
if characters_in_filename > max_length {
|
|
|
|
let start_characters = 10;
|
|
|
|
let difference = characters_in_filename - max_length;
|
|
|
|
let second_part_start = start_characters + difference;
|
2023-01-29 06:54:02 +13:00
|
|
|
let mut string_pre = String::new();
|
|
|
|
let mut string_after = String::new();
|
2022-07-20 05:09:52 +12:00
|
|
|
|
|
|
|
for (index, character) in file_name.chars().enumerate() {
|
|
|
|
if index < start_characters {
|
|
|
|
string_pre.push(character);
|
|
|
|
} else if index >= second_part_start {
|
|
|
|
string_after.push(character);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
format!("{string_pre} ... {string_after}")
|
2022-01-11 00:19:28 +13:00
|
|
|
} else {
|
|
|
|
file_name.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn get_custom_label_from_widget<P: IsA<Widget>>(item: &P) -> gtk4::Label {
|
|
|
|
let mut widgets_to_check = vec![item.clone().upcast::<Widget>()];
|
2022-05-22 20:59:09 +12:00
|
|
|
|
|
|
|
while let Some(widget) = widgets_to_check.pop() {
|
|
|
|
if let Ok(label) = widget.clone().downcast::<gtk4::Label>() {
|
|
|
|
return label;
|
2021-12-12 04:16:14 +13:00
|
|
|
}
|
2023-01-29 06:54:02 +13:00
|
|
|
widgets_to_check.extend(get_all_direct_children(&widget));
|
2021-12-12 04:16:14 +13:00
|
|
|
}
|
|
|
|
panic!("Button doesn't have proper custom label child");
|
|
|
|
}
|
2022-06-01 03:52:55 +12:00
|
|
|
|
|
|
|
pub fn get_custom_image_from_widget<P: IsA<Widget>>(item: &P) -> gtk4::Image {
|
|
|
|
let mut widgets_to_check = vec![item.clone().upcast::<Widget>()];
|
2022-05-22 20:59:09 +12:00
|
|
|
|
|
|
|
while let Some(widget) = widgets_to_check.pop() {
|
|
|
|
if let Ok(image) = widget.clone().downcast::<gtk4::Image>() {
|
|
|
|
return image;
|
2022-04-04 02:03:01 +12:00
|
|
|
}
|
2023-01-29 06:54:02 +13:00
|
|
|
widgets_to_check.extend(get_all_direct_children(&widget));
|
2022-04-04 02:03:01 +12:00
|
|
|
}
|
|
|
|
panic!("Button doesn't have proper custom label child");
|
|
|
|
}
|
2021-12-19 04:48:30 +13:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
#[allow(dead_code)]
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn debug_print_widget<P: IsA<Widget>>(item: &P) {
|
|
|
|
let mut widgets_to_check = vec![(0, 0, item.clone().upcast::<Widget>())];
|
2022-05-22 20:59:09 +12:00
|
|
|
|
|
|
|
let mut next_free_number = 1;
|
|
|
|
println!("{}, {}, {:?} ", widgets_to_check[0].0, widgets_to_check[0].1, widgets_to_check[0].2);
|
|
|
|
|
|
|
|
while let Some((current_number, parent_number, widget)) = widgets_to_check.pop() {
|
2022-07-20 05:09:52 +12:00
|
|
|
for widget in get_all_direct_children(&widget) {
|
2022-05-22 20:59:09 +12:00
|
|
|
widgets_to_check.push((next_free_number, current_number, widget));
|
|
|
|
next_free_number += 1;
|
|
|
|
}
|
2022-12-21 20:44:26 +13:00
|
|
|
println!("{current_number}, {parent_number}, {widget:?} ");
|
2022-04-24 07:16:57 +12:00
|
|
|
}
|
|
|
|
}
|
2022-06-01 03:52:55 +12:00
|
|
|
|
|
|
|
pub fn get_all_boxes_from_widget<P: IsA<Widget>>(item: &P) -> Vec<gtk4::Box> {
|
|
|
|
let mut widgets_to_check = vec![item.clone().upcast::<Widget>()];
|
2022-05-22 20:59:09 +12:00
|
|
|
let mut boxes = Vec::new();
|
2022-04-24 07:16:57 +12:00
|
|
|
|
2022-05-22 20:59:09 +12:00
|
|
|
while let Some(widget) = widgets_to_check.pop() {
|
2022-07-20 05:09:52 +12:00
|
|
|
widgets_to_check.extend(get_all_direct_children(&widget));
|
2022-05-22 20:59:09 +12:00
|
|
|
if let Ok(bbox) = widget.clone().downcast::<gtk4::Box>() {
|
|
|
|
boxes.push(bbox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boxes
|
|
|
|
}
|
|
|
|
|
2022-07-20 05:09:52 +12:00
|
|
|
pub fn get_all_direct_children<P: IsA<Widget>>(wid: &P) -> Vec<Widget> {
|
2022-05-22 20:59:09 +12:00
|
|
|
let mut vector = vec![];
|
|
|
|
if let Some(mut child) = wid.first_child() {
|
|
|
|
vector.push(child.clone());
|
|
|
|
loop {
|
|
|
|
child = match child.next_sibling() {
|
|
|
|
Some(t) => t,
|
|
|
|
None => break,
|
|
|
|
};
|
|
|
|
vector.push(child.clone());
|
|
|
|
}
|
2022-04-24 07:16:57 +12:00
|
|
|
}
|
2022-05-22 20:59:09 +12:00
|
|
|
|
|
|
|
vector
|
|
|
|
}
|
2022-04-04 02:03:01 +12:00
|
|
|
|
|
|
|
const SIZE_OF_ICON: i32 = 18;
|
|
|
|
const TYPE_OF_INTERPOLATION: InterpType = InterpType::Tiles;
|
|
|
|
|
2022-06-01 03:52:55 +12:00
|
|
|
pub fn set_icon_of_button<P: IsA<Widget>>(button: &P, data: &'static [u8]) {
|
2022-05-22 20:59:09 +12:00
|
|
|
let image = get_custom_image_from_widget(&button.clone());
|
2023-05-03 08:37:12 +12:00
|
|
|
let pixbuf = Pixbuf::from_read(BufReader::new(data)).unwrap();
|
2022-04-04 02:03:01 +12:00
|
|
|
let pixbuf = pixbuf.scale_simple(SIZE_OF_ICON, SIZE_OF_ICON, TYPE_OF_INTERPOLATION).unwrap();
|
2022-05-22 20:59:09 +12:00
|
|
|
image.set_from_pixbuf(Some(&pixbuf));
|
2022-04-04 02:03:01 +12:00
|
|
|
}
|
2022-06-09 07:42:51 +12:00
|
|
|
|
|
|
|
static mut IMAGE_PREVIEW_ARRAY: OnceCell<Vec<u8>> = OnceCell::new();
|
2022-07-25 06:48:02 +12:00
|
|
|
|
2022-06-09 07:42:51 +12:00
|
|
|
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();
|
|
|
|
let arra;
|
|
|
|
unsafe {
|
|
|
|
IMAGE_PREVIEW_ARRAY.take();
|
|
|
|
IMAGE_PREVIEW_ARRAY.set(output).unwrap();
|
|
|
|
arra = IMAGE_PREVIEW_ARRAY.get().unwrap().as_bytes();
|
|
|
|
}
|
|
|
|
Pixbuf::from_read(arra)
|
|
|
|
}
|
2022-07-20 05:09:52 +12:00
|
|
|
|
2022-07-25 06:48:02 +12:00
|
|
|
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 {
|
2022-11-24 08:23:17 +13:00
|
|
|
let list_store_value: String = list_store.get::<String>(&iter, column);
|
2022-07-25 06:48:02 +12:00
|
|
|
|
|
|
|
if value == list_store_value {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !list_store.iter_next(&iter) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
2022-07-20 05:09:52 +12:00
|
|
|
}
|
|
|
|
|
2022-07-31 18:45:19 +12:00
|
|
|
pub fn check_if_list_store_column_have_all_same_values(list_store: &ListStore, column: i32, value: bool) -> bool {
|
|
|
|
if let Some(iter) = list_store.iter_first() {
|
|
|
|
loop {
|
2022-11-24 08:23:17 +13:00
|
|
|
let list_store_value: bool = list_store.get::<bool>(&iter, column);
|
2022-07-31 18:45:19 +12:00
|
|
|
|
|
|
|
if value != list_store_value {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !list_store.iter_next(&iter) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:54:05 +12:00
|
|
|
pub fn scale_set_min_max_values(scale: &Scale, minimum: f64, maximum: f64, current_value: f64, step: Option<f64>) {
|
|
|
|
scale.set_range(minimum, maximum);
|
|
|
|
scale.set_fill_level(maximum);
|
|
|
|
scale.set_value(current_value);
|
|
|
|
if let Some(step) = step {
|
|
|
|
scale.adjustment().set_step_increment(step);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 19:06:47 +13:00
|
|
|
pub fn scale_step_function(scale: &Scale, _scroll_type: ScrollType, value: f64) -> glib::Propagation {
|
2022-11-26 08:38:27 +13:00
|
|
|
scale.set_increments(1_f64, 1_f64);
|
|
|
|
scale.set_round_digits(0);
|
|
|
|
scale.set_fill_level(value.round());
|
2023-10-05 19:06:47 +13:00
|
|
|
glib::Propagation::Proceed
|
2022-11-26 08:38:27 +13:00
|
|
|
}
|
|
|
|
|
2022-07-20 05:09:52 +12:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2023-05-03 08:37:12 +12:00
|
|
|
use glib::types::Type;
|
2023-05-11 07:27:41 +12:00
|
|
|
use glib::Value;
|
2022-07-20 05:09:52 +12:00
|
|
|
use gtk4::prelude::*;
|
2023-05-11 07:27:41 +12:00
|
|
|
use gtk4::{Orientation, TreeView};
|
2022-07-20 05:09:52 +12:00
|
|
|
use image::DynamicImage;
|
|
|
|
|
2022-07-25 06:48:02 +12:00
|
|
|
use crate::help_functions::{
|
2022-07-31 18:45:19 +12:00
|
|
|
change_dimension_to_krotka, check_if_list_store_column_have_all_same_values, check_if_value_is_in_list_store, get_all_boxes_from_widget, get_all_direct_children,
|
2023-05-11 07:27:41 +12:00
|
|
|
get_max_file_name, get_pixbuf_from_dynamic_image, get_string_from_list_store,
|
2022-07-25 06:48:02 +12:00
|
|
|
};
|
|
|
|
|
2023-05-11 07:27:41 +12:00
|
|
|
#[gtk4::test]
|
|
|
|
fn test_get_string_from_list_store() {
|
|
|
|
let columns_types: &[Type] = &[Type::STRING];
|
|
|
|
let list_store = gtk4::ListStore::new(columns_types);
|
|
|
|
let tree_view = TreeView::with_model(&list_store);
|
|
|
|
|
|
|
|
let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &"test"), (0, &"test2"), (0, &"test3")];
|
|
|
|
for i in values_to_add {
|
|
|
|
list_store.set(&list_store.append(), &[*i]);
|
|
|
|
}
|
|
|
|
assert_eq!(
|
|
|
|
get_string_from_list_store(&tree_view, 0, None),
|
|
|
|
vec!["test".to_string(), "test2".to_string(), "test3".to_string()]
|
|
|
|
);
|
|
|
|
|
|
|
|
let columns_types: &[Type] = &[Type::BOOL, Type::STRING];
|
|
|
|
let list_store = gtk4::ListStore::new(columns_types);
|
|
|
|
let tree_view = TreeView::with_model(&list_store);
|
|
|
|
|
|
|
|
let values_to_add: &[&[(u32, &dyn ToValue)]] = &[
|
|
|
|
&[(0, &Into::<Value>::into(true)), (1, &Into::<Value>::into("test"))],
|
|
|
|
&[(0, &Into::<Value>::into(true)), (1, &Into::<Value>::into("test2"))],
|
|
|
|
&[(0, &Into::<Value>::into(false)), (1, &Into::<Value>::into("test3"))],
|
|
|
|
];
|
|
|
|
for i in values_to_add {
|
|
|
|
list_store.set(&list_store.append(), i);
|
|
|
|
}
|
|
|
|
assert_eq!(get_string_from_list_store(&tree_view, 1, Some(0)), vec!["test".to_string(), "test2".to_string()]);
|
|
|
|
}
|
|
|
|
|
2022-07-31 18:45:19 +12:00
|
|
|
#[gtk4::test]
|
|
|
|
fn test_check_if_list_store_column_have_all_same_values() {
|
2023-05-03 08:37:12 +12:00
|
|
|
let columns_types: &[Type] = &[Type::BOOL];
|
2022-07-31 18:45:19 +12:00
|
|
|
let list_store = gtk4::ListStore::new(columns_types);
|
|
|
|
|
|
|
|
list_store.clear();
|
|
|
|
let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &true), (0, &true), (0, &false)];
|
|
|
|
for i in values_to_add {
|
|
|
|
list_store.set(&list_store.append(), &[*i]);
|
|
|
|
}
|
|
|
|
assert!(!check_if_list_store_column_have_all_same_values(&list_store, 0, true));
|
|
|
|
assert!(!check_if_list_store_column_have_all_same_values(&list_store, 0, false));
|
|
|
|
|
|
|
|
list_store.clear();
|
|
|
|
let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &true), (0, &true), (0, &true)];
|
|
|
|
for i in values_to_add {
|
|
|
|
list_store.set(&list_store.append(), &[*i]);
|
|
|
|
}
|
|
|
|
assert!(check_if_list_store_column_have_all_same_values(&list_store, 0, true));
|
|
|
|
assert!(!check_if_list_store_column_have_all_same_values(&list_store, 0, false));
|
|
|
|
|
|
|
|
list_store.clear();
|
|
|
|
let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &false)];
|
|
|
|
for i in values_to_add {
|
|
|
|
list_store.set(&list_store.append(), &[*i]);
|
|
|
|
}
|
|
|
|
assert!(!check_if_list_store_column_have_all_same_values(&list_store, 0, true));
|
|
|
|
assert!(check_if_list_store_column_have_all_same_values(&list_store, 0, false));
|
|
|
|
|
|
|
|
list_store.clear();
|
|
|
|
assert!(!check_if_list_store_column_have_all_same_values(&list_store, 0, true));
|
|
|
|
assert!(!check_if_list_store_column_have_all_same_values(&list_store, 0, false));
|
|
|
|
}
|
|
|
|
|
2022-07-25 06:48:02 +12:00
|
|
|
#[gtk4::test]
|
|
|
|
fn test_check_if_value_is_in_list_store() {
|
2023-05-03 08:37:12 +12:00
|
|
|
let columns_types: &[Type] = &[Type::STRING];
|
2022-07-25 06:48:02 +12:00
|
|
|
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"));
|
|
|
|
|
2023-05-03 08:37:12 +12:00
|
|
|
let columns_types: &[Type] = &[Type::STRING, Type::STRING];
|
2022-07-25 06:48:02 +12:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2022-07-20 05:09:52 +12:00
|
|
|
#[test]
|
|
|
|
fn test_pixbuf_from_dynamic_image() {
|
|
|
|
let dynamic_image = DynamicImage::new_rgb8(1, 1);
|
|
|
|
get_pixbuf_from_dynamic_image(&dynamic_image).unwrap();
|
|
|
|
get_pixbuf_from_dynamic_image(&dynamic_image).unwrap();
|
|
|
|
get_pixbuf_from_dynamic_image(&dynamic_image).unwrap();
|
|
|
|
get_pixbuf_from_dynamic_image(&dynamic_image).unwrap();
|
|
|
|
}
|
2022-07-31 18:45:19 +12:00
|
|
|
|
2022-07-25 06:48:02 +12:00
|
|
|
#[test]
|
|
|
|
fn test_change_dimension_to_krotka() {
|
2023-01-29 06:54:02 +13:00
|
|
|
assert_eq!(change_dimension_to_krotka("50x50"), (50, 50));
|
|
|
|
assert_eq!(change_dimension_to_krotka("6000x6000"), (6000, 6000));
|
2022-07-25 06:48:02 +12:00
|
|
|
}
|
2022-07-20 05:09:52 +12:00
|
|
|
|
|
|
|
#[gtk4::test]
|
|
|
|
fn test_get_all_direct_children() {
|
|
|
|
let obj = gtk4::Box::new(Orientation::Horizontal, 0);
|
|
|
|
let obj2 = gtk4::Box::new(Orientation::Horizontal, 0);
|
|
|
|
let obj3 = gtk4::Image::new();
|
|
|
|
let obj4 = gtk4::Image::new();
|
|
|
|
let obj5 = gtk4::Image::new();
|
|
|
|
obj.append(&obj2);
|
|
|
|
obj.append(&obj3);
|
|
|
|
obj2.append(&obj4);
|
|
|
|
obj2.append(&obj5);
|
|
|
|
assert_eq!(get_all_direct_children(&obj).len(), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[gtk4::test]
|
|
|
|
fn test_get_all_boxes_from_widget() {
|
|
|
|
let obj = gtk4::Box::new(Orientation::Horizontal, 0);
|
|
|
|
let obj2 = gtk4::Box::new(Orientation::Horizontal, 0);
|
|
|
|
let obj3 = gtk4::Image::new();
|
|
|
|
let obj4 = gtk4::Image::new();
|
|
|
|
let obj5 = gtk4::Image::new();
|
|
|
|
obj.append(&obj2);
|
|
|
|
obj.append(&obj3);
|
|
|
|
obj2.append(&obj4);
|
|
|
|
obj2.append(&obj5);
|
|
|
|
assert_eq!(get_all_boxes_from_widget(&obj).len(), 2);
|
|
|
|
}
|
|
|
|
}
|