1 use crate::connect_button_delete::{basic_remove, check_if_can_delete_files, check_if_deleting_all_files_in_group, empty_folder_remover, tree_remove};
2 use crate::create_tree_view::*;
3 use crate::double_click_opening::*;
4 use crate::gui_data::*;
5 use crate::help_functions::*;
6 use czkawka_core::similar_images::SIMILAR_VALUES;
7 use directories_next::ProjectDirs;
8 use gtk::prelude::*;
9 use gtk::{CheckButton, Image, SelectionMode, TextView, TreeView};
10 use image::imageops::FilterType;
11 use image::GenericImageView;
12 use std::cmp::Ordering;
13 use std::fs;
14 use std::path::Path;
15 
initialize_gui(gui_data: &mut GuiData)16 pub fn initialize_gui(gui_data: &mut GuiData) {
17     //// Initialize button
18     {
19         let buttons_search = gui_data.bottom_buttons.buttons_search.clone();
20         let buttons_save = gui_data.bottom_buttons.buttons_save.clone();
21         let buttons_delete = gui_data.bottom_buttons.buttons_delete.clone();
22         let buttons_select = gui_data.bottom_buttons.buttons_select.clone();
23         let buttons_symlink = gui_data.bottom_buttons.buttons_symlink.clone();
24         let buttons_hardlink = gui_data.bottom_buttons.buttons_hardlink.clone();
25         let buttons_move = gui_data.bottom_buttons.buttons_move.clone();
26 
27         // Disable and show buttons - only search button should be visible
28         buttons_search.show();
29         buttons_save.hide();
30         buttons_delete.hide();
31         buttons_select.hide();
32         buttons_symlink.hide();
33         buttons_hardlink.hide();
34         buttons_move.hide();
35     }
36 
37     //// Initialize main scrolled view with notebook
38     {
39         let scrolled_window_duplicate_finder = gui_data.main_notebook.scrolled_window_duplicate_finder.clone();
40         let scrolled_window_empty_folder_finder = gui_data.main_notebook.scrolled_window_empty_folder_finder.clone();
41         let scrolled_window_empty_files_finder = gui_data.main_notebook.scrolled_window_empty_files_finder.clone();
42         let scrolled_window_temporary_files_finder = gui_data.main_notebook.scrolled_window_temporary_files_finder.clone();
43         let scrolled_window_big_files_finder = gui_data.main_notebook.scrolled_window_big_files_finder.clone();
44         let scrolled_window_similar_images_finder = gui_data.main_notebook.scrolled_window_similar_images_finder.clone();
45         let scrolled_window_same_music_finder = gui_data.main_notebook.scrolled_window_same_music_finder.clone();
46         let scrolled_window_invalid_symlinks = gui_data.main_notebook.scrolled_window_invalid_symlinks.clone();
47         let scrolled_window_zeroed_files_finder = gui_data.main_notebook.scrolled_window_zeroed_files_finder.clone();
48         let scrolled_window_broken_files = gui_data.main_notebook.scrolled_window_broken_files.clone();
49 
50         let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone();
51         let image_preview_duplicates = gui_data.main_notebook.image_preview_duplicates.clone();
52         let check_button_settings_show_preview_similar_images = gui_data.settings.check_button_settings_show_preview_similar_images.clone();
53         let check_button_settings_show_preview_duplicates = gui_data.settings.check_button_settings_show_preview_duplicates.clone();
54         let text_view_errors = gui_data.text_view_errors.clone();
55 
56         let scale_similarity = gui_data.main_notebook.scale_similarity.clone();
57 
58         // Set step increment
59         {
60             scale_similarity.set_range(0_f64, SIMILAR_VALUES[1][5] as f64); // This defaults to value of minimal size of hash 8
61             scale_similarity.set_fill_level(SIMILAR_VALUES[1][5] as f64);
62             scale_similarity.adjustment().set_step_increment(1_f64);
63         }
64 
65         // Set Main Scrolled Window Treeviews
66         {
67             // Duplicate Files
68             {
69                 let image_preview_duplicates_cloned = image_preview_duplicates.clone();
70                 image_preview_duplicates.hide();
71                 let text_view_errors_cloned = text_view_errors.clone();
72                 let check_button_settings_show_preview_duplicates_cloned = check_button_settings_show_preview_duplicates.clone();
73 
74                 let col_types: [glib::types::Type; 8] = [
75                     glib::types::Type::BOOL,
76                     glib::types::Type::BOOL,
77                     glib::types::Type::STRING,
78                     glib::types::Type::STRING,
79                     glib::types::Type::STRING,
80                     glib::types::Type::U64,
81                     glib::types::Type::STRING,
82                     glib::types::Type::STRING,
83                 ];
84                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
85 
86                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
87 
88                 tree_view.selection().set_mode(SelectionMode::Multiple);
89                 tree_view.selection().set_select_function(Some(Box::new(select_function_duplicates)));
90 
91                 create_tree_view_duplicates(&mut tree_view);
92 
93                 tree_view.connect_button_press_event(opening_double_click_function_duplicates);
94                 tree_view.connect_key_press_event(opening_enter_function_duplicates);
95                 tree_view.connect_button_release_event(move |tree_view, _event| {
96                     show_preview(
97                         tree_view,
98                         &text_view_errors_cloned,
99                         &check_button_settings_show_preview_duplicates_cloned,
100                         &image_preview_duplicates_cloned,
101                         ColumnsDuplicates::Path as i32,
102                         ColumnsDuplicates::Name as i32,
103                     );
104                     gtk::Inhibit(false)
105                 });
106 
107                 gui_data.main_notebook.tree_view_duplicate_finder = tree_view.clone();
108                 scrolled_window_duplicate_finder.add(&tree_view);
109                 scrolled_window_duplicate_finder.show_all();
110 
111                 let text_view_errors_cloned = text_view_errors.clone();
112 
113                 let gui_data = gui_data.clone();
114                 tree_view.connect_key_release_event(move |tree_view, e| {
115                     if let Some(button_number) = e.keycode() {
116                         // Handle delete button
117                         if button_number == 119 {
118                             if tree_view.selection().selected_rows().0.is_empty() {
119                                 return gtk::Inhibit(false);
120                             }
121                             if !check_if_can_delete_files(&gui_data.settings.check_button_settings_confirm_deletion, &gui_data.window_main) {
122                                 return gtk::Inhibit(false);
123                             }
124                             if gui_data.settings.check_button_settings_confirm_group_deletion.is_active()
125                                 && check_if_deleting_all_files_in_group(
126                                     &tree_view.clone(),
127                                     ColumnsDuplicates::Color as i32,
128                                     ColumnsDuplicates::ActiveSelectButton as i32,
129                                     &gui_data.window_main,
130                                     &gui_data.settings.check_button_settings_confirm_group_deletion,
131                                 )
132                             {
133                                 return gtk::Inhibit(false);
134                             }
135                             tree_remove(
136                                 tree_view,
137                                 ColumnsDuplicates::Name as i32,
138                                 ColumnsDuplicates::Path as i32,
139                                 ColumnsDuplicates::Color as i32,
140                                 ColumnsDuplicates::ActiveSelectButton as i32,
141                                 &gui_data,
142                             );
143                             image_preview_duplicates.hide();
144                         }
145                     }
146                     show_preview(
147                         tree_view,
148                         &text_view_errors_cloned,
149                         &check_button_settings_show_preview_duplicates,
150                         &image_preview_duplicates,
151                         ColumnsDuplicates::Path as i32,
152                         ColumnsDuplicates::Name as i32,
153                     );
154                     gtk::Inhibit(false)
155                 });
156             }
157             // Empty Folders
158             {
159                 let col_types: [glib::types::Type; 4] = [glib::types::Type::BOOL, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING];
160                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
161 
162                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
163 
164                 tree_view.selection().set_mode(SelectionMode::Multiple);
165 
166                 create_tree_view_empty_folders(&mut tree_view);
167 
168                 tree_view.connect_button_press_event(opening_double_click_function_empty_folders);
169                 tree_view.connect_key_press_event(opening_enter_function_empty_folders);
170 
171                 gui_data.main_notebook.tree_view_empty_folder_finder = tree_view.clone();
172                 scrolled_window_empty_folder_finder.add(&tree_view);
173                 scrolled_window_empty_folder_finder.show_all();
174 
175                 let gui_data = gui_data.clone();
176                 tree_view.connect_key_release_event(move |tree_view, e| {
177                     if let Some(button_number) = e.keycode() {
178                         // Handle delete button
179                         if button_number == 119 {
180                             empty_folder_remover(tree_view, ColumnsEmptyFolders::Name as i32, ColumnsEmptyFolders::Path as i32, ColumnsEmptyFolders::ActiveSelectButton as i32, &gui_data);
181                         }
182                     }
183                     gtk::Inhibit(false)
184                 });
185             }
186             // Empty Files
187             {
188                 let col_types: [glib::types::Type; 4] = [glib::types::Type::BOOL, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING];
189                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
190 
191                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
192 
193                 tree_view.selection().set_mode(SelectionMode::Multiple);
194 
195                 create_tree_view_empty_files(&mut tree_view);
196 
197                 tree_view.connect_button_press_event(opening_double_click_function_empty_files);
198                 tree_view.connect_key_press_event(opening_enter_function_empty_files);
199 
200                 gui_data.main_notebook.tree_view_empty_files_finder = tree_view.clone();
201                 scrolled_window_empty_files_finder.add(&tree_view);
202                 scrolled_window_empty_files_finder.show_all();
203 
204                 let gui_data = gui_data.clone();
205                 tree_view.connect_key_release_event(move |tree_view, e| {
206                     if let Some(button_number) = e.keycode() {
207                         // Handle delete button
208                         if button_number == 119 {
209                             basic_remove(tree_view, ColumnsEmptyFiles::Name as i32, ColumnsEmptyFiles::Path as i32, ColumnsEmptyFiles::ActiveSelectButton as i32, &gui_data);
210                         }
211                     }
212                     gtk::Inhibit(false)
213                 });
214             }
215             // Temporary Files
216             {
217                 let col_types: [glib::types::Type; 4] = [glib::types::Type::BOOL, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING];
218                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
219 
220                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
221 
222                 tree_view.selection().set_mode(SelectionMode::Multiple);
223 
224                 create_tree_view_temporary_files(&mut tree_view);
225 
226                 tree_view.connect_button_press_event(opening_double_click_function_temporary_files);
227                 tree_view.connect_key_press_event(opening_enter_function_temporary_files);
228 
229                 gui_data.main_notebook.tree_view_temporary_files_finder = tree_view.clone();
230                 scrolled_window_temporary_files_finder.add(&tree_view);
231                 scrolled_window_temporary_files_finder.show_all();
232 
233                 let gui_data = gui_data.clone();
234                 tree_view.connect_key_release_event(move |tree_view, e| {
235                     if let Some(button_number) = e.keycode() {
236                         // Handle delete button
237                         if button_number == 119 {
238                             basic_remove(tree_view, ColumnsTemporaryFiles::Name as i32, ColumnsTemporaryFiles::Path as i32, ColumnsTemporaryFiles::ActiveSelectButton as i32, &gui_data);
239                         }
240                     }
241                     gtk::Inhibit(false)
242                 });
243             }
244             // Big Files
245             {
246                 let col_types: [glib::types::Type; 5] = [glib::types::Type::BOOL, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING];
247                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
248 
249                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
250 
251                 tree_view.selection().set_mode(SelectionMode::Multiple);
252 
253                 create_tree_view_big_files(&mut tree_view);
254 
255                 tree_view.connect_button_press_event(opening_double_click_function_big_files);
256                 tree_view.connect_key_press_event(opening_enter_function_big_files);
257 
258                 gui_data.main_notebook.tree_view_big_files_finder = tree_view.clone();
259                 scrolled_window_big_files_finder.add(&tree_view);
260                 scrolled_window_big_files_finder.show_all();
261 
262                 let gui_data = gui_data.clone();
263                 tree_view.connect_key_release_event(move |tree_view, e| {
264                     if let Some(button_number) = e.keycode() {
265                         // Handle delete button
266                         if button_number == 119 {
267                             basic_remove(tree_view, ColumnsBigFiles::Name as i32, ColumnsBigFiles::Path as i32, ColumnsBigFiles::ActiveSelectButton as i32, &gui_data);
268                         }
269                     }
270                     gtk::Inhibit(false)
271                 });
272             }
273             // Similar Images
274             {
275                 let image_preview_similar_images_clone = image_preview_similar_images.clone();
276                 image_preview_similar_images.hide();
277 
278                 let col_types: [glib::types::Type; 12] = [
279                     glib::types::Type::BOOL,
280                     glib::types::Type::BOOL,
281                     glib::types::Type::STRING,
282                     glib::types::Type::STRING,
283                     glib::types::Type::U64,
284                     glib::types::Type::STRING,
285                     glib::types::Type::STRING,
286                     glib::types::Type::STRING,
287                     glib::types::Type::STRING,
288                     glib::types::Type::U64,
289                     glib::types::Type::STRING,
290                     glib::types::Type::STRING,
291                 ];
292                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
293 
294                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
295 
296                 tree_view.selection().set_mode(SelectionMode::Multiple);
297                 tree_view.selection().set_select_function(Some(Box::new(select_function_similar_images)));
298 
299                 create_tree_view_similar_images(&mut tree_view);
300 
301                 tree_view.connect_button_press_event(opening_double_click_function_similar_images);
302                 tree_view.connect_key_press_event(opening_enter_function_similar_images);
303                 tree_view.connect_button_release_event(move |tree_view, _event| {
304                     show_preview(
305                         tree_view,
306                         &text_view_errors,
307                         &check_button_settings_show_preview_similar_images,
308                         &image_preview_similar_images,
309                         ColumnsSimilarImages::Path as i32,
310                         ColumnsSimilarImages::Name as i32,
311                     );
312                     gtk::Inhibit(false)
313                 });
314 
315                 gui_data.main_notebook.tree_view_similar_images_finder = tree_view.clone();
316                 scrolled_window_similar_images_finder.add(&tree_view);
317                 scrolled_window_similar_images_finder.show_all();
318 
319                 let image_preview_similar_images = image_preview_similar_images_clone.clone();
320                 let text_view_errors = gui_data.text_view_errors.clone();
321                 let check_button_settings_show_preview_similar_images = gui_data.settings.check_button_settings_show_preview_similar_images.clone();
322                 let gui_data = gui_data.clone();
323                 tree_view.connect_key_release_event(move |tree_view, e| {
324                     if let Some(button_number) = e.keycode() {
325                         // Handle delete button
326                         if button_number == 119 {
327                             if tree_view.selection().selected_rows().0.is_empty() {
328                                 return gtk::Inhibit(false);
329                             }
330                             if !check_if_can_delete_files(&gui_data.settings.check_button_settings_confirm_deletion, &gui_data.window_main) {
331                                 return gtk::Inhibit(false);
332                             }
333                             if gui_data.settings.check_button_settings_confirm_group_deletion.is_active()
334                                 && check_if_deleting_all_files_in_group(
335                                     &tree_view.clone(),
336                                     ColumnsSimilarImages::Color as i32,
337                                     ColumnsSimilarImages::ActiveSelectButton as i32,
338                                     &gui_data.window_main,
339                                     &gui_data.settings.check_button_settings_confirm_group_deletion,
340                                 )
341                             {
342                                 return gtk::Inhibit(false);
343                             }
344                             tree_remove(
345                                 tree_view,
346                                 ColumnsSimilarImages::Name as i32,
347                                 ColumnsSimilarImages::Path as i32,
348                                 ColumnsSimilarImages::Color as i32,
349                                 ColumnsSimilarImages::ActiveSelectButton as i32,
350                                 &gui_data,
351                             );
352                             image_preview_similar_images_clone.hide();
353                         }
354                     }
355                     show_preview(
356                         tree_view,
357                         &text_view_errors,
358                         &check_button_settings_show_preview_similar_images,
359                         &image_preview_similar_images,
360                         ColumnsSimilarImages::Path as i32,
361                         ColumnsSimilarImages::Name as i32,
362                     );
363                     gtk::Inhibit(false)
364                 });
365             }
366             // Zeroed Files
367             {
368                 let col_types: [glib::types::Type; 6] = [
369                     glib::types::Type::BOOL,
370                     glib::types::Type::STRING,
371                     glib::types::Type::U64,
372                     glib::types::Type::STRING,
373                     glib::types::Type::STRING,
374                     glib::types::Type::STRING,
375                 ];
376                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
377 
378                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
379 
380                 tree_view.selection().set_mode(SelectionMode::Multiple);
381 
382                 create_tree_view_zeroed_files(&mut tree_view);
383 
384                 tree_view.connect_button_press_event(opening_double_click_function_zeroed_files);
385                 tree_view.connect_key_press_event(opening_enter_function_zeroed_files);
386 
387                 gui_data.main_notebook.tree_view_zeroed_files_finder = tree_view.clone();
388                 scrolled_window_zeroed_files_finder.add(&tree_view);
389                 scrolled_window_zeroed_files_finder.show_all();
390 
391                 let gui_data = gui_data.clone();
392                 tree_view.connect_key_release_event(move |tree_view, e| {
393                     if let Some(button_number) = e.keycode() {
394                         // Handle delete button
395                         if button_number == 119 {
396                             basic_remove(tree_view, ColumnsZeroedFiles::Name as i32, ColumnsZeroedFiles::Path as i32, ColumnsZeroedFiles::ActiveSelectButton as i32, &gui_data);
397                         }
398                     }
399                     gtk::Inhibit(false)
400                 });
401             }
402             // Same Music
403             {
404                 let col_types: [glib::types::Type; 15] = [
405                     glib::types::Type::BOOL,
406                     glib::types::Type::BOOL,
407                     glib::types::Type::STRING,
408                     glib::types::Type::U64,
409                     glib::types::Type::STRING,
410                     glib::types::Type::STRING,
411                     glib::types::Type::STRING,
412                     glib::types::Type::STRING,
413                     glib::types::Type::STRING,
414                     glib::types::Type::STRING,
415                     glib::types::Type::STRING,
416                     glib::types::Type::STRING,
417                     glib::types::Type::U64,
418                     glib::types::Type::STRING,
419                     glib::types::Type::STRING,
420                 ];
421                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
422 
423                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
424 
425                 tree_view.selection().set_mode(SelectionMode::Multiple);
426 
427                 create_tree_view_same_music(&mut tree_view);
428                 tree_view.selection().set_select_function(Some(Box::new(select_function_same_music)));
429 
430                 tree_view.connect_button_press_event(opening_double_click_function_same_music);
431                 tree_view.connect_key_press_event(opening_enter_function_same_music);
432 
433                 gui_data.main_notebook.tree_view_same_music_finder = tree_view.clone();
434                 scrolled_window_same_music_finder.add(&tree_view);
435                 scrolled_window_same_music_finder.show_all();
436 
437                 let gui_data = gui_data.clone();
438                 tree_view.connect_key_release_event(move |tree_view, e| {
439                     if let Some(button_number) = e.keycode() {
440                         // Handle delete button
441                         if button_number == 119 {
442                             if tree_view.selection().selected_rows().0.is_empty() {
443                                 return gtk::Inhibit(false);
444                             }
445                             if !check_if_can_delete_files(&gui_data.settings.check_button_settings_confirm_deletion, &gui_data.window_main) {
446                                 return gtk::Inhibit(false);
447                             }
448                             if gui_data.settings.check_button_settings_confirm_group_deletion.is_active()
449                                 && check_if_deleting_all_files_in_group(
450                                     &tree_view.clone(),
451                                     ColumnsSameMusic::Color as i32,
452                                     ColumnsSameMusic::ActiveSelectButton as i32,
453                                     &gui_data.window_main,
454                                     &gui_data.settings.check_button_settings_confirm_group_deletion,
455                                 )
456                             {
457                                 return gtk::Inhibit(false);
458                             }
459                             tree_remove(
460                                 tree_view,
461                                 ColumnsSameMusic::Name as i32,
462                                 ColumnsSameMusic::Path as i32,
463                                 ColumnsSameMusic::Color as i32,
464                                 ColumnsSameMusic::ActiveSelectButton as i32,
465                                 &gui_data,
466                             );
467                         }
468                     }
469                     gtk::Inhibit(false)
470                 });
471             }
472             // Invalid Symlinks
473             {
474                 let col_types: [glib::types::Type; 6] = [
475                     glib::types::Type::BOOL,
476                     glib::types::Type::STRING,
477                     glib::types::Type::STRING,
478                     glib::types::Type::STRING,
479                     glib::types::Type::STRING,
480                     glib::types::Type::STRING,
481                 ];
482                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
483 
484                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
485 
486                 tree_view.selection().set_mode(SelectionMode::Multiple);
487 
488                 create_tree_view_invalid_symlinks(&mut tree_view);
489 
490                 tree_view.connect_button_press_event(opening_double_click_function_invalid_symlinks);
491                 tree_view.connect_key_press_event(opening_enter_function_invalid_symlinks);
492 
493                 gui_data.main_notebook.tree_view_invalid_symlinks = tree_view.clone();
494                 scrolled_window_invalid_symlinks.add(&tree_view);
495                 scrolled_window_invalid_symlinks.show_all();
496 
497                 let gui_data = gui_data.clone();
498                 tree_view.connect_key_release_event(move |tree_view, e| {
499                     if let Some(button_number) = e.keycode() {
500                         // Handle delete button
501                         if button_number == 119 {
502                             basic_remove(tree_view, ColumnsInvalidSymlinks::Name as i32, ColumnsInvalidSymlinks::Path as i32, ColumnsInvalidSymlinks::ActiveSelectButton as i32, &gui_data);
503                         }
504                     }
505                     gtk::Inhibit(false)
506                 });
507             }
508             // Broken Files
509             {
510                 let col_types: [glib::types::Type; 5] = [glib::types::Type::BOOL, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING, glib::types::Type::STRING];
511                 let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
512 
513                 let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
514 
515                 tree_view.selection().set_mode(SelectionMode::Multiple);
516 
517                 create_tree_view_broken_files(&mut tree_view);
518 
519                 tree_view.connect_button_press_event(opening_double_click_function_broken_files);
520                 tree_view.connect_key_press_event(opening_enter_function_broken_files);
521 
522                 gui_data.main_notebook.tree_view_broken_files = tree_view.clone();
523                 scrolled_window_broken_files.add(&tree_view);
524                 scrolled_window_broken_files.show_all();
525 
526                 let gui_data = gui_data.clone();
527                 tree_view.connect_key_release_event(move |tree_view, e| {
528                     if let Some(button_number) = e.keycode() {
529                         // Handle delete button
530                         if button_number == 119 {
531                             basic_remove(tree_view, ColumnsBrokenFiles::Name as i32, ColumnsBrokenFiles::Path as i32, ColumnsBrokenFiles::ActiveSelectButton as i32, &gui_data);
532                         }
533                     }
534                     gtk::Inhibit(false)
535                 });
536             }
537         }
538     }
539 
540     //// Initialize upper notebook
541     {
542         let scrolled_window_included_directories = gui_data.upper_notebook.scrolled_window_included_directories.clone();
543         let scrolled_window_excluded_directories = gui_data.upper_notebook.scrolled_window_excluded_directories.clone();
544 
545         // Set Included Directory
546         {
547             let col_types: [glib::types::Type; 1] = [glib::types::Type::STRING];
548             let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
549 
550             let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
551 
552             tree_view.selection().set_mode(SelectionMode::Multiple);
553 
554             create_tree_view_directories(&mut tree_view);
555 
556             gui_data.upper_notebook.tree_view_included_directories = tree_view.clone();
557             scrolled_window_included_directories.add(&tree_view);
558             scrolled_window_included_directories.show_all();
559 
560             tree_view.connect_key_release_event(move |tree_view, e| {
561                 if let Some(button_number) = e.keycode() {
562                     // Handle delete button
563                     if button_number == 119 {
564                         let list_store = get_list_store(tree_view);
565                         let selection = tree_view.selection();
566 
567                         let (vec_tree_path, _tree_model) = selection.selected_rows();
568 
569                         for tree_path in vec_tree_path.iter().rev() {
570                             list_store.remove(&list_store.iter(tree_path).unwrap());
571                         }
572                     }
573                 }
574                 gtk::Inhibit(false)
575             });
576         }
577         // Set Excluded Directory
578         {
579             let col_types: [glib::types::Type; 1] = [glib::types::Type::STRING];
580             let list_store: gtk::ListStore = gtk::ListStore::new(&col_types);
581 
582             let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store);
583 
584             tree_view.selection().set_mode(SelectionMode::Multiple);
585 
586             create_tree_view_directories(&mut tree_view);
587 
588             gui_data.upper_notebook.tree_view_excluded_directories = tree_view.clone();
589             scrolled_window_excluded_directories.add(&tree_view);
590             scrolled_window_excluded_directories.show_all();
591 
592             tree_view.connect_key_release_event(move |tree_view, e| {
593                 if let Some(button_number) = e.keycode() {
594                     // Handle delete button
595                     if button_number == 119 {
596                         let list_store = get_list_store(tree_view);
597                         let selection = tree_view.selection();
598 
599                         let (vec_tree_path, _tree_model) = selection.selected_rows();
600 
601                         for tree_path in vec_tree_path.iter().rev() {
602                             list_store.remove(&list_store.iter(tree_path).unwrap());
603                         }
604                     }
605                 }
606                 gtk::Inhibit(false)
607             });
608         }
609     }
610 
611     //// Window progress
612     {
613         let window_progress = gui_data.progress_window.window_progress.clone();
614         let stop_sender = gui_data.stop_sender.clone();
615 
616         window_progress.hide_on_delete();
617 
618         window_progress.connect_delete_event(move |_e, _y| {
619             stop_sender.send(()).unwrap();
620             gtk::Inhibit(true)
621         });
622     }
623 }
show_preview(tree_view: &TreeView, text_view_errors: &TextView, check_button_settings_show_preview: &CheckButton, image_preview_similar_images: &Image, column_path: i32, column_name: i32)624 fn show_preview(tree_view: &TreeView, text_view_errors: &TextView, check_button_settings_show_preview: &CheckButton, image_preview_similar_images: &Image, column_path: i32, column_name: i32) {
625     let (selected_rows, tree_model) = tree_view.selection().selected_rows();
626 
627     let mut created_image = false;
628 
629     // Only show preview when selected is only one item, because there is no method to recognize current clicked item in multiselection
630     if selected_rows.len() == 1 && check_button_settings_show_preview.is_active() {
631         let tree_path = selected_rows[0].clone();
632         if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") {
633             // TODO labels on {} are in testing stage, so we just ignore for now this warning until found better idea how to fix this
634             #[allow(clippy::never_loop)]
635             'dir: loop {
636                 let cache_dir = proj_dirs.cache_dir();
637                 if cache_dir.exists() {
638                     if !cache_dir.is_dir() {
639                         add_text_to_text_view(text_view_errors, format!("Path {} doesn't point at folder, which is needed by image preview", cache_dir.display()).as_str());
640                         break 'dir;
641                     }
642                 } else if let Err(e) = fs::create_dir_all(cache_dir) {
643                     add_text_to_text_view(text_view_errors, format!("Failed to create dir {} needed by image preview, reason {}", cache_dir.display(), e).as_str());
644                     break 'dir;
645                 }
646                 let path = tree_model.value(&tree_model.iter(&tree_path).unwrap(), column_path).get::<String>().unwrap();
647                 let name = tree_model.value(&tree_model.iter(&tree_path).unwrap(), column_name).get::<String>().unwrap();
648 
649                 let file_name = format!("{}/{}", path, name);
650                 let file_name = file_name.as_str();
651 
652                 if let Some(extension) = Path::new(file_name).extension() {
653                     if !["jpg", "jpeg", "png", "bmp", "tiff", "tif", "tga", "ff", "gif", "jif", "jfi"].contains(&extension.to_string_lossy().to_string().to_lowercase().as_str()) {
654                         break 'dir;
655                     }
656 
657                     let img = match image::open(&file_name) {
658                         Ok(t) => t,
659                         Err(e) => {
660                             add_text_to_text_view(text_view_errors, format!("Failed to open temporary image file {}, reason {}", file_name, e).as_str());
661                             break 'dir;
662                         }
663                     };
664                     if img.width() == 0 || img.height() == 0 {
665                         add_text_to_text_view(text_view_errors, format!("Cannot create preview of image {}, with 0 width or height", file_name).as_str());
666                         break 'dir;
667                     }
668                     let ratio = img.width() / img.height();
669                     let requested_dimensions = (400, 400);
670                     let mut new_size;
671                     match ratio.cmp(&(requested_dimensions.0 / requested_dimensions.1)) {
672                         Ordering::Greater => {
673                             new_size = (requested_dimensions.0, (img.height() * requested_dimensions.0) / img.width());
674                             new_size = (std::cmp::max(new_size.0, 1), std::cmp::max(new_size.1, 1));
675                         }
676                         Ordering::Less => {
677                             new_size = ((img.width() * requested_dimensions.1) / img.height(), requested_dimensions.1);
678                             new_size = (std::cmp::max(new_size.0, 1), std::cmp::max(new_size.1, 1));
679                         }
680                         Ordering::Equal => {
681                             new_size = requested_dimensions;
682                             new_size = (std::cmp::max(new_size.0, 1), std::cmp::max(new_size.1, 1));
683                         }
684                     }
685                     let img = img.resize(new_size.0, new_size.1, FilterType::Triangle);
686                     let file_dir = cache_dir.join(format!("cached_file.{}", extension.to_string_lossy().to_lowercase()));
687                     if let Err(e) = img.save(&file_dir) {
688                         add_text_to_text_view(text_view_errors, format!("Failed to save temporary image file to {}, reason {}", file_dir.display(), e).as_str());
689                         let _ = fs::remove_file(&file_dir);
690                         break 'dir;
691                     }
692                     let string_dir = file_dir.to_string_lossy().to_string();
693                     image_preview_similar_images.set_from_file(string_dir);
694                     if let Err(e) = fs::remove_file(&file_dir) {
695                         add_text_to_text_view(text_view_errors, format!("Failed to delete temporary image file to {}, reason {}", file_dir.display(), e).as_str());
696                         break 'dir;
697                     }
698                     created_image = true;
699                 }
700                 break 'dir;
701             }
702         }
703     }
704     if created_image {
705         image_preview_similar_images.show();
706     } else {
707         image_preview_similar_images.hide();
708     }
709 }
710