From f14101139d4764ca2ae6859c0e4bc639299cfa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:38:38 +0100 Subject: [PATCH] More GTK 4 compatibility fixes (#468) Bump minimal version to GTK 3.24 and Ubuntu 18.04 Some performance improvements --- .github/workflows/linux.yml | 6 +- czkawka_gui/Cargo.toml | 2 +- czkawka_gui/src/connect_button_delete.rs | 7 +- czkawka_gui/src/gui_main_notebook.rs | 35 +- czkawka_gui/src/gui_upper_notepad.rs | 10 +- czkawka_gui/src/help_functions.rs | 20 +- czkawka_gui/src/initialize_gui.rs | 441 ++++++++++--------- czkawka_gui/src/opening_selecting_records.rs | 32 +- 8 files changed, 319 insertions(+), 234 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 60805fa..fee119a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -14,7 +14,7 @@ jobs: matrix: toolchain: [ stable ] type: [ release ] - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -132,7 +132,7 @@ jobs: matrix: toolchain: [ stable, 1.53.0 ] type: [ release ] - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -196,7 +196,7 @@ jobs: matrix: toolchain: [ stable ] type: [ release ] - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index 631b3e4..0b19f1f 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -46,5 +46,5 @@ winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_cor [dependencies.gtk] version = "0.14.3" default-features = false # just in case -features = ["v3_22"] +features = ["v3_24_9"] diff --git a/czkawka_gui/src/connect_button_delete.rs b/czkawka_gui/src/connect_button_delete.rs index 8b9d0fc..480b920 100644 --- a/czkawka_gui/src/connect_button_delete.rs +++ b/czkawka_gui/src/connect_button_delete.rs @@ -8,6 +8,7 @@ use gtk::{Align, CheckButton, Dialog, TextView}; use crate::gui_data::GuiData; use crate::help_functions::*; use crate::notebook_enums::*; +use crate::validate_notebook_data; // TODO add support for checking if really symlink doesn't point to correct directory/file @@ -22,6 +23,8 @@ pub fn connect_button_delete(gui_data: &GuiData) { } pub async fn delete_things(gui_data: GuiData) { + validate_notebook_data(&gui_data); // TODO, disable this - only used as test if ever + let notebook_main = gui_data.main_notebook.notebook_main.clone(); let window_main = gui_data.window_main.clone(); let check_button_settings_confirm_deletion = gui_data.settings.check_button_settings_confirm_deletion.clone(); @@ -105,7 +108,7 @@ fn create_dialog_ask_for_deletion(window_main: >k::Window) -> (Dialog, CheckBu check_button.set_active(true); check_button.set_halign(Align::Center); - let button_box = confirmation_dialog_delete.children()[0].clone().downcast::().unwrap().children()[0].clone().downcast::().unwrap().children()[0] + let button_box = get_dialog_box_child(&confirmation_dialog_delete).children()[0].clone().downcast::().unwrap().children()[0] .clone() .downcast::() .unwrap(); @@ -113,7 +116,7 @@ fn create_dialog_ask_for_deletion(window_main: >k::Window) -> (Dialog, CheckBu let button_ok = button_box.children()[0].clone(); button_ok.grab_focus(); - let internal_box = confirmation_dialog_delete.children()[0].clone().downcast::().unwrap(); + let internal_box = get_dialog_box_child(&confirmation_dialog_delete); internal_box.add(&label); internal_box.add(&check_button); diff --git a/czkawka_gui/src/gui_main_notebook.rs b/czkawka_gui/src/gui_main_notebook.rs index cbe553b..809a64d 100644 --- a/czkawka_gui/src/gui_main_notebook.rs +++ b/czkawka_gui/src/gui_main_notebook.rs @@ -1,5 +1,5 @@ use gtk::prelude::*; -use gtk::TreeView; +use gtk::{EventControllerKey, TreeView}; use crate::notebook_enums::NUMBER_OF_NOTEBOOK_MAIN_TABS; @@ -29,6 +29,17 @@ pub struct GuiMainNotebook { pub tree_view_invalid_symlinks: gtk::TreeView, pub tree_view_broken_files: gtk::TreeView, + pub evk_tree_view_duplicate_finder: gtk::EventControllerKey, // TODO, in GTK4 this can be changed to e.g. add_widget - https://discourse.gnome.org/t/how-to-convert-code-to-use-eventcontrollerkey/8198/2 + pub evk_tree_view_empty_folder_finder: gtk::EventControllerKey, + pub evk_tree_view_empty_files_finder: gtk::EventControllerKey, + pub evk_tree_view_temporary_files_finder: gtk::EventControllerKey, + pub evk_tree_view_big_files_finder: gtk::EventControllerKey, + pub evk_tree_view_similar_images_finder: gtk::EventControllerKey, + pub evk_tree_view_similar_videos_finder: gtk::EventControllerKey, + pub evk_tree_view_same_music_finder: gtk::EventControllerKey, + pub evk_tree_view_invalid_symlinks: gtk::EventControllerKey, + pub evk_tree_view_broken_files: gtk::EventControllerKey, + pub entry_similar_images_minimal_size: gtk::Entry, pub entry_similar_images_maximal_size: gtk::Entry, pub entry_similar_videos_minimal_size: gtk::Entry, @@ -97,6 +108,7 @@ impl GuiMainNotebook { let scrolled_window_broken_files: gtk::ScrolledWindow = builder.object("scrolled_window_broken_files").unwrap(); let tree_view_duplicate_finder: gtk::TreeView = TreeView::new(); + tree_view_duplicate_finder.set_widget_name("PIERD"); let tree_view_empty_folder_finder: gtk::TreeView = TreeView::new(); let tree_view_empty_files_finder: gtk::TreeView = TreeView::new(); let tree_view_temporary_files_finder: gtk::TreeView = TreeView::new(); @@ -107,6 +119,17 @@ impl GuiMainNotebook { let tree_view_invalid_symlinks: gtk::TreeView = TreeView::new(); let tree_view_broken_files: gtk::TreeView = TreeView::new(); + let evk_tree_view_duplicate_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_duplicate_finder); + let evk_tree_view_empty_folder_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_empty_folder_finder); + let evk_tree_view_empty_files_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_empty_files_finder); + let evk_tree_view_temporary_files_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_temporary_files_finder); + let evk_tree_view_big_files_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_big_files_finder); + let evk_tree_view_similar_images_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_similar_images_finder); + let evk_tree_view_similar_videos_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_similar_videos_finder); + let evk_tree_view_same_music_finder: gtk::EventControllerKey = EventControllerKey::new(&tree_view_same_music_finder); + let evk_tree_view_invalid_symlinks: gtk::EventControllerKey = EventControllerKey::new(&tree_view_invalid_symlinks); + let evk_tree_view_broken_files: gtk::EventControllerKey = EventControllerKey::new(&tree_view_broken_files); + let entry_similar_images_minimal_size: gtk::Entry = builder.object("entry_similar_images_minimal_size").unwrap(); let entry_similar_images_maximal_size: gtk::Entry = builder.object("entry_similar_images_maximal_size").unwrap(); let entry_similar_videos_minimal_size: gtk::Entry = builder.object("entry_similar_videos_minimal_size").unwrap(); @@ -179,6 +202,16 @@ impl GuiMainNotebook { tree_view_same_music_finder, tree_view_invalid_symlinks, tree_view_broken_files, + evk_tree_view_duplicate_finder, + evk_tree_view_empty_folder_finder, + evk_tree_view_empty_files_finder, + evk_tree_view_temporary_files_finder, + evk_tree_view_big_files_finder, + evk_tree_view_similar_images_finder, + evk_tree_view_similar_videos_finder, + evk_tree_view_same_music_finder, + evk_tree_view_invalid_symlinks, + evk_tree_view_broken_files, entry_similar_images_minimal_size, entry_similar_images_maximal_size, entry_similar_videos_minimal_size, diff --git a/czkawka_gui/src/gui_upper_notepad.rs b/czkawka_gui/src/gui_upper_notepad.rs index a1bab92..815bb01 100644 --- a/czkawka_gui/src/gui_upper_notepad.rs +++ b/czkawka_gui/src/gui_upper_notepad.rs @@ -1,5 +1,5 @@ use gtk::prelude::*; -use gtk::TreeView; +use gtk::{EventControllerKey, TreeView}; #[derive(Clone)] pub struct GuiUpperNotebook { @@ -11,6 +11,9 @@ pub struct GuiUpperNotebook { pub tree_view_included_directories: gtk::TreeView, pub tree_view_excluded_directories: gtk::TreeView, + pub evk_tree_view_included_directories: gtk::EventControllerKey, + pub evk_tree_view_excluded_directories: gtk::EventControllerKey, + pub entry_excluded_items: gtk::Entry, pub entry_allowed_extensions: gtk::Entry, @@ -34,6 +37,9 @@ impl GuiUpperNotebook { let tree_view_included_directories: gtk::TreeView = TreeView::new(); let tree_view_excluded_directories: gtk::TreeView = TreeView::new(); + let evk_tree_view_included_directories: gtk::EventControllerKey = EventControllerKey::new(&tree_view_included_directories); + let evk_tree_view_excluded_directories: gtk::EventControllerKey = EventControllerKey::new(&tree_view_excluded_directories); + let entry_allowed_extensions: gtk::Entry = builder.object("entry_allowed_extensions").unwrap(); let entry_excluded_items: gtk::Entry = builder.object("entry_excluded_items").unwrap(); @@ -52,6 +58,8 @@ impl GuiUpperNotebook { scrolled_window_excluded_directories, tree_view_included_directories, tree_view_excluded_directories, + evk_tree_view_included_directories, + evk_tree_view_excluded_directories, entry_excluded_items, entry_allowed_extensions, check_button_recursive, diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index a8e2f75..7e013e2 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -19,6 +19,17 @@ use czkawka_core::temporary::Temporary; use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS}; +pub const KEY_DELETE: u32 = 119; +pub const KEY_ENTER: u32 = 36; +pub const KEY_SPACE: u32 = 65; + +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; + #[derive(Eq, PartialEq)] pub enum PopoverTypes { All, @@ -416,6 +427,10 @@ pub fn get_dialog_box_child(dialog: >k::Dialog) -> gtk::Box { dialog.child().unwrap().downcast::().unwrap() } +// pub fn get_box_child_from_box(box_main: >k::Box) -> gtk::Box { +// box_main.first_child().unwrap().downcast::().unwrap() // TODO Probably fist_child will be proper replacement for childrens() +// } + pub fn change_dimension_to_krotka(dimensions: String) -> (u64, u64) { #[allow(clippy::single_char_pattern)] let vec = dimensions.split::<&str>("x").collect::>(); @@ -437,7 +452,10 @@ pub fn get_notebook_enum_from_tree_view(tree_view: >k::TreeView) -> NotebookMa "tree_view_same_music_finder" => NotebookMainEnum::SameMusic, "tree_view_invalid_symlinks" => NotebookMainEnum::Symlinks, "tree_view_broken_files" => NotebookMainEnum::BrokenFiles, - _ => panic!(), + e => { + eprintln!("{}", e); + panic!() + } } } diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index 321fc7e..1bded52 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -4,14 +4,13 @@ use std::path::Path; use directories_next::ProjectDirs; use gtk::prelude::*; -use gtk::{CheckButton, Image, SelectionMode, TextView, TreeView}; +use gtk::{CheckButton, EventControllerKey, Image, SelectionMode, TextView, TreeView}; use image::imageops::FilterType; use image::GenericImageView; use czkawka_core::similar_images::SIMILAR_VALUES; use czkawka_core::similar_videos::MAX_TOLERANCE; -use crate::connect_button_delete::{basic_remove, empty_folder_remover}; use crate::create_tree_view::*; use crate::delete_things; use crate::gui_data::*; @@ -19,8 +18,6 @@ use crate::help_functions::*; use crate::notebook_enums::NotebookMainEnum; use crate::opening_selecting_records::*; -const KEY_DELETE: u16 = 119; - pub fn initialize_gui(gui_data: &mut GuiData) { //// Initialize button { @@ -55,10 +52,6 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let scrolled_window_invalid_symlinks = gui_data.main_notebook.scrolled_window_invalid_symlinks.clone(); let scrolled_window_broken_files = gui_data.main_notebook.scrolled_window_broken_files.clone(); - let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone(); - let image_preview_duplicates = gui_data.main_notebook.image_preview_duplicates.clone(); - let check_button_settings_show_preview_similar_images = gui_data.settings.check_button_settings_show_preview_similar_images.clone(); - let check_button_settings_show_preview_duplicates = gui_data.settings.check_button_settings_show_preview_duplicates.clone(); let text_view_errors = gui_data.text_view_errors.clone(); let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); @@ -82,10 +75,8 @@ pub fn initialize_gui(gui_data: &mut GuiData) { { // Duplicate Files { - let image_preview_duplicates_cloned = image_preview_duplicates.clone(); + let image_preview_duplicates = gui_data.main_notebook.image_preview_duplicates.clone(); image_preview_duplicates.hide(); - let text_view_errors_cloned = text_view_errors.clone(); - let check_button_settings_show_preview_duplicates_cloned = check_button_settings_show_preview_duplicates.clone(); let col_types: [glib::types::Type; 8] = [ glib::types::Type::BOOL, @@ -106,39 +97,30 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_duplicates(&mut tree_view); - tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); - tree_view.connect_button_release_event(move |tree_view, _event| { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::Duplicate as usize]; - show_preview( - tree_view, - &text_view_errors_cloned, - &check_button_settings_show_preview_duplicates_cloned, - &image_preview_duplicates_cloned, - nb_object.column_path, - nb_object.column_name, - ); - gtk::Inhibit(false) - }); + { + // EVK + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_duplicate_finder = evk; + } + { + // Other connects + let check_button_settings_show_preview_duplicates = gui_data.settings.check_button_settings_show_preview_duplicates.clone(); + let image_preview_duplicates = gui_data.main_notebook.image_preview_duplicates.clone(); + + tree_view.connect_button_press_event(opening_double_click_function); + tree_view.connect_button_release_event(move |tree_view, _event| { + let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::Duplicate as usize]; + show_preview(tree_view, &text_view_errors, &check_button_settings_show_preview_duplicates, &image_preview_duplicates, nb_object.column_path, nb_object.column_name); + + gtk::Inhibit(false) + }); + } tree_view.set_widget_name("tree_view_duplicate_finder"); gui_data.main_notebook.tree_view_duplicate_finder = tree_view.clone(); scrolled_window_duplicate_finder.add(&tree_view); scrolled_window_duplicate_finder.show_all(); - - let gui_data_clone = gui_data.clone(); - - tree_view.connect_key_release_event(move |tree_view, e| { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::Duplicate as usize]; - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); - } - } - show_preview(tree_view, &text_view_errors, &check_button_settings_show_preview_duplicates, &image_preview_duplicates, nb_object.column_path, nb_object.column_name); - gtk::Inhibit(false) - }); } // Empty Folders { @@ -151,26 +133,17 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_empty_folders(&mut tree_view); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + + gui_data.main_notebook.evk_tree_view_empty_folder_finder = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_empty_folder_finder"); gui_data.main_notebook.tree_view_empty_folder_finder = tree_view.clone(); scrolled_window_empty_folder_finder.add(&tree_view); scrolled_window_empty_folder_finder.show_all(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::EmptyDirectories as usize]; - empty_folder_remover(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } - } - gtk::Inhibit(false) - }); } // Empty Files { @@ -183,26 +156,16 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_empty_files(&mut tree_view); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_empty_files_finder = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_empty_files_finder"); gui_data.main_notebook.tree_view_empty_files_finder = tree_view.clone(); scrolled_window_empty_files_finder.add(&tree_view); scrolled_window_empty_files_finder.show_all(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::EmptyFiles as usize]; - basic_remove(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } - } - gtk::Inhibit(false) - }); } // Temporary Files { @@ -215,26 +178,16 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_temporary_files(&mut tree_view); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_temporary_files_finder = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_temporary_files_finder"); gui_data.main_notebook.tree_view_temporary_files_finder = tree_view.clone(); scrolled_window_temporary_files_finder.add(&tree_view); scrolled_window_temporary_files_finder.show_all(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::Temporary as usize]; - basic_remove(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } - } - gtk::Inhibit(false) - }); } // Big Files { @@ -247,29 +200,20 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_big_files(&mut tree_view); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_big_files_finder = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_big_files_finder"); gui_data.main_notebook.tree_view_big_files_finder = tree_view.clone(); scrolled_window_big_files_finder.add(&tree_view); scrolled_window_big_files_finder.show_all(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::BigFiles as usize]; - basic_remove(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } - } - gtk::Inhibit(false) - }); } // Similar Images { + let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone(); image_preview_similar_images.hide(); let col_types: [glib::types::Type; 12] = [ @@ -295,49 +239,36 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_similar_images(&mut tree_view); - tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_button_release_event(move |tree_view, _event| { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarImages as usize]; - show_preview( - tree_view, - &text_view_errors, - &check_button_settings_show_preview_similar_images, - &image_preview_similar_images, - nb_object.column_path, - nb_object.column_name, - ); - gtk::Inhibit(false) - }); + { + // EVK + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_similar_images_finder = evk; + } + { + // Other connects + let check_button_settings_show_preview_similar_images = gui_data.settings.check_button_settings_show_preview_similar_images.clone(); + + tree_view.connect_button_press_event(opening_double_click_function); + let text_view_errors = gui_data.text_view_errors.clone(); + tree_view.connect_button_release_event(move |tree_view, _event| { + let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarImages as usize]; + show_preview( + tree_view, + &text_view_errors, + &check_button_settings_show_preview_similar_images, + &image_preview_similar_images, + nb_object.column_path, + nb_object.column_name, + ); + gtk::Inhibit(false) + }); + } tree_view.set_widget_name("tree_view_similar_images_finder"); gui_data.main_notebook.tree_view_similar_images_finder = tree_view.clone(); scrolled_window_similar_images_finder.add(&tree_view); scrolled_window_similar_images_finder.show_all(); - - let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone(); - let check_button_settings_show_preview_similar_images = gui_data.settings.check_button_settings_show_preview_similar_images.clone(); - let gui_data_clone = gui_data.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarImages as usize]; - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); - } - } - show_preview( - tree_view, - &text_view_errors, - &check_button_settings_show_preview_similar_images, - &image_preview_similar_images, - nb_object.column_path, - nb_object.column_name, - ); - gtk::Inhibit(false) - }); } // Similar Videos { @@ -362,24 +293,16 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_similar_videos(&mut tree_view); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_similar_videos_finder = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_similar_videos_finder"); gui_data.main_notebook.tree_view_similar_videos_finder = tree_view.clone(); scrolled_window_similar_videos_finder.add(&tree_view); scrolled_window_similar_videos_finder.show_all(); - - let gui_data_clone = gui_data.clone(); - tree_view.connect_key_release_event(move |_tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); - } - } - gtk::Inhibit(false) - }); } // Same Music { @@ -405,28 +328,20 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store); tree_view.selection().set_mode(SelectionMode::Multiple); - - create_tree_view_same_music(&mut tree_view); tree_view.selection().set_select_function(Some(Box::new(select_function_same_music))); + create_tree_view_same_music(&mut tree_view); + + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_same_music_finder = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_same_music_finder"); gui_data.main_notebook.tree_view_same_music_finder = tree_view.clone(); scrolled_window_same_music_finder.add(&tree_view); scrolled_window_same_music_finder.show_all(); - - let gui_data_clone = gui_data.clone(); - tree_view.connect_key_release_event(move |_tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); - } - } - gtk::Inhibit(false) - }); } // Invalid Symlinks { @@ -446,26 +361,16 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_invalid_symlinks(&mut tree_view); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_invalid_symlinks = evk; + tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); tree_view.set_widget_name("tree_view_invalid_symlinks"); gui_data.main_notebook.tree_view_invalid_symlinks = tree_view.clone(); scrolled_window_invalid_symlinks.add(&tree_view); scrolled_window_invalid_symlinks.show_all(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::Symlinks as usize]; - basic_remove(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } - } - gtk::Inhibit(false) - }); } // Broken Files { @@ -478,26 +383,14 @@ pub fn initialize_gui(gui_data: &mut GuiData) { create_tree_view_broken_files(&mut tree_view); - tree_view.connect_button_press_event(opening_double_click_function); - tree_view.connect_key_press_event(opening_enter_function); + let evk = EventControllerKey::new(&tree_view); + evk.connect_key_pressed(opening_enter_function_ported); + gui_data.main_notebook.evk_tree_view_broken_files = evk; tree_view.set_widget_name("tree_view_broken_files"); gui_data.main_notebook.tree_view_broken_files = tree_view.clone(); scrolled_window_broken_files.add(&tree_view); scrolled_window_broken_files.show_all(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.clone(); - let text_view_errors = gui_data.text_view_errors.clone(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::BrokenFiles as usize]; - basic_remove(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } - } - gtk::Inhibit(false) - }); } } } @@ -522,21 +415,19 @@ pub fn initialize_gui(gui_data: &mut GuiData) { scrolled_window_included_directories.add(&tree_view); scrolled_window_included_directories.show_all(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let list_store = get_list_store(tree_view); - let selection = tree_view.selection(); + let evk = EventControllerKey::new(&tree_view); + gui_data.upper_notebook.evk_tree_view_included_directories = evk; + gui_data.upper_notebook.evk_tree_view_included_directories.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + let list_store = get_list_store(&tree_view); + let selection = tree_view.selection(); - let (vec_tree_path, _tree_model) = selection.selected_rows(); + let (vec_tree_path, _tree_model) = selection.selected_rows(); - for tree_path in vec_tree_path.iter().rev() { - list_store.remove(&list_store.iter(tree_path).unwrap()); - } + for tree_path in vec_tree_path.iter().rev() { + list_store.remove(&list_store.iter(tree_path).unwrap()); } } - gtk::Inhibit(false) }); } // Set Excluded Directory @@ -554,21 +445,19 @@ pub fn initialize_gui(gui_data: &mut GuiData) { scrolled_window_excluded_directories.add(&tree_view); scrolled_window_excluded_directories.show_all(); - tree_view.connect_key_release_event(move |tree_view, e| { - if let Some(button_number) = e.keycode() { - // Handle delete button - if button_number == KEY_DELETE { - let list_store = get_list_store(tree_view); - let selection = tree_view.selection(); + let evk = EventControllerKey::new(&tree_view); + gui_data.upper_notebook.evk_tree_view_excluded_directories = evk; + gui_data.upper_notebook.evk_tree_view_excluded_directories.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + let list_store = get_list_store(&tree_view); + let selection = tree_view.selection(); - let (vec_tree_path, _tree_model) = selection.selected_rows(); + let (vec_tree_path, _tree_model) = selection.selected_rows(); - for tree_path in vec_tree_path.iter().rev() { - list_store.remove(&list_store.iter(tree_path).unwrap()); - } + for tree_path in vec_tree_path.iter().rev() { + list_store.remove(&list_store.iter(tree_path).unwrap()); } } - gtk::Inhibit(false) }); } } @@ -583,6 +472,138 @@ pub fn initialize_gui(gui_data: &mut GuiData) { gtk::Inhibit(true) }); } + + // Needs to be called after setting tree_view name, probably in GTK 4 this will be easier + connect_event_buttons(gui_data); +} + +fn connect_event_buttons(gui_data: &GuiData) { + // Duplicate + { + let gui_data_clone = gui_data.clone(); + let text_view_errors = gui_data.text_view_errors.clone(); + let check_button_settings_show_preview_duplicates = gui_data.settings.check_button_settings_show_preview_duplicates.clone(); + let image_preview_duplicates = gui_data.main_notebook.image_preview_duplicates.clone(); + gui_data.main_notebook.evk_tree_view_duplicate_finder.connect_key_released(move |event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + + // Allowed keys for generating preview, + // LEFT, UP, RIGHT, DOWN, Pageup, pagedown, home, end + if [KEY_DOWN, KEY_UP, KEY_PG_DOWN, KEY_PG_UP, KEY_HOME, KEY_END].iter().any(|any_key| *any_key == key_code) { + let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::Duplicate as usize]; + show_preview( + &event_controller_key.widget().unwrap().downcast::().unwrap(), + &text_view_errors, + &check_button_settings_show_preview_duplicates, + &image_preview_duplicates, + nb_object.column_path, + nb_object.column_name, + ); + } + }); + } + // Empty Folder + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_empty_folder_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Empty Files + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_empty_files_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Temporary + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_temporary_files_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Big Files + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_big_files_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Similar Images + { + let check_button_settings_show_preview_similar_images = gui_data.settings.check_button_settings_show_preview_similar_images.clone(); + let text_view_errors = gui_data.text_view_errors.clone(); + let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone(); + let gui_data_clone = gui_data.clone(); + + gui_data.main_notebook.evk_tree_view_similar_images_finder.connect_key_released(move |event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + + // Allowed keys for generating preview, + // LEFT, UP, RIGHT, DOWN, Pageup, pagedown, home, end + if [KEY_DOWN, KEY_UP, KEY_PG_DOWN, KEY_PG_UP, KEY_HOME, KEY_END].iter().any(|any_key| *any_key == key_code) { + let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarImages as usize]; + show_preview( + &event_controller_key.widget().unwrap().downcast::().unwrap(), + &text_view_errors, + &check_button_settings_show_preview_similar_images, + &image_preview_similar_images, + nb_object.column_path, + nb_object.column_name, + ); + } + }); + } + // Empty Folder + { + let gui_data_clone = gui_data.clone(); + + gui_data.main_notebook.evk_tree_view_similar_videos_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Same music + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_same_music_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Invalid Symlinks + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_invalid_symlinks.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } + // Broken Files + { + let gui_data_clone = gui_data.clone(); + gui_data.main_notebook.evk_tree_view_big_files_finder.connect_key_released(move |_event_controller_key, _key_value, key_code, _modifier_type| { + if key_code == KEY_DELETE { + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); + } + }); + } } 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) { diff --git a/czkawka_gui/src/opening_selecting_records.rs b/czkawka_gui/src/opening_selecting_records.rs index 2109ab8..6daa122 100644 --- a/czkawka_gui/src/opening_selecting_records.rs +++ b/czkawka_gui/src/opening_selecting_records.rs @@ -1,12 +1,20 @@ -use gtk::prelude::*; - use crate::help_functions::*; - -const KEY_ENTER: u16 = 36; -const KEY_SPACE: u16 = 65; +use gdk::ModifierType; +use gtk::prelude::*; // TODO add option to open files and folders from context menu activated by pressing ONCE with right mouse button +pub fn opening_enter_function_ported(event_controller: >k::EventControllerKey, _key_value: u32, key_code: u32, _modifier_type: ModifierType) -> bool { + let tree_view = event_controller.widget().unwrap().downcast::().unwrap(); + #[cfg(debug_assertions)] + { + println!("key_code {}", key_code); + } + + let nt_object = get_notebook_object_from_tree_view(&tree_view); + handle_tree_keypress(&tree_view, key_code, nt_object.column_name, nt_object.column_path, nt_object.column_selection); + false // True catches signal, and don't send it to function, e.g. up button is catched and don't move selection +} pub fn opening_double_click_function(tree_view: >k::TreeView, event: &gdk::EventButton) -> gtk::Inhibit { let nt_object = get_notebook_object_from_tree_view(tree_view); if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 1 { @@ -17,11 +25,6 @@ pub fn opening_double_click_function(tree_view: >k::TreeView, event: &gdk::Eve gtk::Inhibit(false) } -pub fn opening_enter_function(tree_view: >k::TreeView, event: &gdk::EventKey) -> gtk::Inhibit { - let nt_object = get_notebook_object_from_tree_view(tree_view); - handle_tree_keypress(tree_view, event, nt_object.column_name, nt_object.column_path, nt_object.column_selection) -} - enum OpenMode { OnlyPath, PathAndName, @@ -65,19 +68,18 @@ fn common_open_function(tree_view: >k::TreeView, column_name: i32, column_path } } -fn handle_tree_keypress(tree_view: >k::TreeView, event: &gdk::EventKey, name_column: i32, path_column: i32, mark_column: i32) -> gtk::Inhibit { - match event.keycode() { - Some(KEY_ENTER) => { +fn handle_tree_keypress(tree_view: >k::TreeView, key_code: u32, name_column: i32, path_column: i32, mark_column: i32) { + match key_code { + KEY_ENTER => { // Enter common_open_function(tree_view, name_column, path_column, OpenMode::PathAndName); } - Some(KEY_SPACE) => { + KEY_SPACE => { // Space common_mark_function(tree_view, mark_column); } _ => {} } - gtk::Inhibit(false) } pub fn select_function_duplicates(_tree_selection: >k::TreeSelection, tree_model: >k::TreeModel, tree_path: >k::TreePath, _is_path_currently_selected: bool) -> bool {