1 use czkawka_core::big_file::BigFile;
2 use czkawka_core::broken_files::BrokenFiles;
3 use czkawka_core::common_messages::Messages;
4 use czkawka_core::duplicate::DuplicateFinder;
5 use czkawka_core::empty_files::EmptyFiles;
6 use czkawka_core::empty_folder::EmptyFolder;
7 use czkawka_core::invalid_symlinks;
8 use czkawka_core::invalid_symlinks::InvalidSymlinks;
9 use czkawka_core::same_music::SameMusic;
10 use czkawka_core::similar_images::SimilarImages;
11 use czkawka_core::temporary::Temporary;
12 use czkawka_core::zeroed::ZeroedFiles;
13 use gtk::prelude::*;
14 use gtk::{ListStore, TextView};
15 use std::collections::HashMap;
16 use std::path::{Path, PathBuf};
17 
18 pub enum Message {
19     Duplicates(DuplicateFinder),
20     EmptyFolders(EmptyFolder),
21     EmptyFiles(EmptyFiles),
22     BigFiles(BigFile),
23     Temporary(Temporary),
24     SimilarImages(SimilarImages),
25     ZeroedFiles(ZeroedFiles),
26     SameMusic(SameMusic),
27     InvalidSymlinks(InvalidSymlinks),
28     BrokenFiles(BrokenFiles),
29 }
30 
31 #[derive(Debug)]
32 pub enum ColumnsDuplicates {
33     // Columns for duplicate treeview
34     ActivatableSelectButton = 0,
35     ActiveSelectButton,
36     Name,
37     Path,
38     Modification,
39     ModificationAsSecs,
40     Color,
41     TextColor,
42 }
43 
44 pub enum ColumnsEmptyFolders {
45     // Columns for empty folder treeview
46     ActiveSelectButton = 0,
47     Name,
48     Path,
49     Modification,
50 }
51 pub enum ColumnsDirectory {
52     // Columns for Included and Excluded Directories in upper Notebook
53     Path = 0,
54 }
55 pub enum ColumnsBigFiles {
56     ActiveSelectButton = 0,
57     Size,
58     Name,
59     Path,
60     Modification,
61 }
62 pub enum ColumnsEmptyFiles {
63     ActiveSelectButton = 0,
64     Name,
65     Path,
66     Modification,
67 }
68 pub enum ColumnsTemporaryFiles {
69     ActiveSelectButton = 0,
70     Name,
71     Path,
72     Modification,
73 }
74 pub enum ColumnsSimilarImages {
75     ActivatableSelectButton = 0,
76     ActiveSelectButton,
77     Similarity,
78     Size,
79     SizeAsBytes,
80     Dimensions,
81     Name,
82     Path,
83     Modification,
84     ModificationAsSecs,
85     Color,
86     TextColor,
87 }
88 pub enum ColumnsZeroedFiles {
89     ActiveSelectButton = 0,
90     Size,
91     SizeAsBytes,
92     Name,
93     Path,
94     Modification,
95 }
96 pub enum ColumnsSameMusic {
97     ActivatableSelectButton = 0,
98     ActiveSelectButton,
99     Size,
100     SizeAsBytes,
101     Name,
102     Path,
103     Title,
104     Artist,
105     AlbumTitle,
106     AlbumArtist,
107     Year,
108     Modification,
109     ModificationAsSecs,
110     Color,
111     TextColor,
112 }
113 pub enum ColumnsInvalidSymlinks {
114     ActiveSelectButton = 0,
115     Name,
116     Path,
117     DestinationPath,
118     TypeOfError,
119     Modification,
120 }
121 
122 pub enum ColumnsBrokenFiles {
123     ActiveSelectButton = 0,
124     Name,
125     Path,
126     ErrorType,
127     Modification,
128 }
129 
130 pub const TEXT_COLOR: &str = "#ffffff";
131 pub const MAIN_ROW_COLOR: &str = "#343434";
132 pub const HEADER_ROW_COLOR: &str = "#272727";
133 //pub const MAIN_ROW_COLOR: &str = "#f4f434"; // TEST
134 //pub const HEADER_ROW_COLOR: &str = "#010101"; // TEST
135 
get_string_from_list_store(tree_view: &gtk::TreeView) -> Vec<String>136 pub fn get_string_from_list_store(tree_view: &gtk::TreeView) -> Vec<String> {
137     let list_store: gtk::ListStore = get_list_store(tree_view);
138 
139     let mut string_vector: Vec<String> = Vec::new();
140 
141     let tree_iter = match list_store.iter_first() {
142         Some(t) => t,
143         None => {
144             return string_vector;
145         }
146     };
147     loop {
148         string_vector.push(list_store.value(&tree_iter, 0).get::<String>().unwrap());
149         if !list_store.iter_next(&tree_iter) {
150             return string_vector;
151         }
152     }
153 }
get_path_buf_from_vector_of_strings(vec_string: Vec<String>) -> Vec<PathBuf>154 pub fn get_path_buf_from_vector_of_strings(vec_string: Vec<String>) -> Vec<PathBuf> {
155     vec_string.iter().map(PathBuf::from).collect()
156 }
157 
split_path(path: &Path) -> (String, String)158 pub fn split_path(path: &Path) -> (String, String) {
159     match (path.parent(), path.file_name()) {
160         (Some(dir), Some(file)) => (dir.display().to_string(), file.to_string_lossy().into_owned()),
161         (Some(dir), None) => (dir.display().to_string(), String::new()),
162         (None, _) => (String::new(), String::new()),
163     }
164 }
165 
print_text_messages_to_text_view(text_messages: &Messages, text_view: &gtk::TextView)166 pub fn print_text_messages_to_text_view(text_messages: &Messages, text_view: &gtk::TextView) {
167     let mut messages: String = String::from("");
168     if !text_messages.messages.is_empty() {
169         messages += "############### MESSAGES ###############\n";
170     }
171     for text in &text_messages.messages {
172         messages += text.as_str();
173         messages += "\n";
174     }
175     if !text_messages.messages.is_empty() {
176         messages += "\n";
177     }
178     if !text_messages.warnings.is_empty() {
179         messages += "############### WARNINGS ###############\n";
180     }
181     for text in &text_messages.warnings {
182         messages += text.as_str();
183         messages += "\n";
184     }
185     if !text_messages.warnings.is_empty() {
186         messages += "\n";
187     }
188     if !text_messages.errors.is_empty() {
189         messages += "############### ERRORS ###############\n";
190     }
191     for text in &text_messages.errors {
192         messages += text.as_str();
193         messages += "\n";
194     }
195     if !text_messages.errors.is_empty() {
196         messages += "\n";
197     }
198 
199     text_view.buffer().unwrap().set_text(messages.as_str());
200 }
201 
reset_text_view(text_view: &TextView)202 pub fn reset_text_view(text_view: &TextView) {
203     text_view.buffer().unwrap().set_text("");
204 }
205 
add_text_to_text_view(text_view: &TextView, string_to_append: &str)206 pub fn add_text_to_text_view(text_view: &TextView, string_to_append: &str) {
207     let buffer = text_view.buffer().unwrap();
208     let current_text = match buffer.text(&buffer.start_iter(), &buffer.end_iter(), true) {
209         Some(t) => t.to_string(),
210         None => "".to_string(),
211     };
212     buffer.set_text(format!("{}\n{}", current_text, string_to_append).as_str());
213 }
214 
select_function_duplicates(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::TreePath, _is_path_currently_selected: bool) -> bool215 pub fn select_function_duplicates(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::TreePath, _is_path_currently_selected: bool) -> bool {
216     // let name = tree_model.value(&tree_model.iter(tree_path).unwrap(),ColumnsDuplicates::Name as i32).get::<String>().unwrap();
217     // let path = tree_model.value(&tree_model.iter(tree_path).unwrap(), ColumnsDuplicates::Path as i32).get::<String>().unwrap();
218     // let modification = tree_model.value(&tree_model.iter(tree_path).unwrap(),ColumnsDuplicates::Modification as i32).get::<String>().unwrap();
219     let color = tree_model.value(&tree_model.iter(tree_path).unwrap(), ColumnsDuplicates::Color as i32).get::<String>().unwrap();
220 
221     if color == HEADER_ROW_COLOR {
222         return false;
223     }
224 
225     true
226 }
select_function_same_music(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::TreePath, _is_path_currently_selected: bool) -> bool227 pub fn select_function_same_music(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::TreePath, _is_path_currently_selected: bool) -> bool {
228     let color = tree_model.value(&tree_model.iter(tree_path).unwrap(), ColumnsSameMusic::Color as i32).get::<String>().unwrap();
229 
230     if color == HEADER_ROW_COLOR {
231         return false;
232     }
233 
234     true
235 }
select_function_similar_images(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::TreePath, _is_path_currently_selected: bool) -> bool236 pub fn select_function_similar_images(_tree_selection: &gtk::TreeSelection, tree_model: &gtk::TreeModel, tree_path: &gtk::TreePath, _is_path_currently_selected: bool) -> bool {
237     let color = tree_model.value(&tree_model.iter(tree_path).unwrap(), ColumnsSimilarImages::Color as i32).get::<String>().unwrap();
238 
239     if color == HEADER_ROW_COLOR {
240         return false;
241     }
242 
243     true
244 }
245 
set_buttons(hashmap: &mut HashMap<String, bool>, buttons_array: &[gtk::Button], button_names: &[String])246 pub fn set_buttons(hashmap: &mut HashMap<String, bool>, buttons_array: &[gtk::Button], button_names: &[String]) {
247     for (index, button) in buttons_array.iter().enumerate() {
248         if *hashmap.get_mut(button_names[index].as_str()).unwrap() {
249             button.show();
250         } else {
251             button.hide();
252         }
253     }
254 }
hide_all_buttons(buttons_array: &[gtk::Button])255 pub fn hide_all_buttons(buttons_array: &[gtk::Button]) {
256     for button in buttons_array {
257         button.hide();
258     }
259 }
260 
get_text_from_invalid_symlink_cause(error: &invalid_symlinks::ErrorType) -> &str261 pub fn get_text_from_invalid_symlink_cause(error: &invalid_symlinks::ErrorType) -> &str {
262     match error {
263         invalid_symlinks::ErrorType::InfiniteRecursion => "Infinite recursion",
264         invalid_symlinks::ErrorType::NonExistentFile => "Non existent destination file",
265     }
266 }
267 
get_list_store(tree_view: &gtk::TreeView) -> ListStore268 pub fn get_list_store(tree_view: &gtk::TreeView) -> ListStore {
269     tree_view.model().unwrap().downcast::<gtk::ListStore>().unwrap()
270 }
get_dialog_box_child(dialog: &gtk::Dialog) -> gtk::Box271 pub fn get_dialog_box_child(dialog: &gtk::Dialog) -> gtk::Box {
272     dialog.children()[0].clone().downcast::<gtk::Box>().unwrap()
273 }
274 
change_dimension_to_krotka(dimensions: String) -> (u64, u64)275 pub fn change_dimension_to_krotka(dimensions: String) -> (u64, u64) {
276     #[allow(clippy::single_char_pattern)]
277     let vec = dimensions.split::<&str>("x").collect::<Vec<_>>();
278     assert_eq!(vec.len(), 2); // 400x400 - should only have two elements, if have more, then something is not good
279     let number1 = vec[0].parse::<u64>().expect("Invalid data in image dimension in position 0");
280     let number2 = vec[1].parse::<u64>().expect("Invalid data in image dimension in position 1");
281     (number1, number2)
282 }
283