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