From 5836e3e5b30faec8fd96b1c1ad9310260abfbacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Sat, 27 Nov 2021 16:44:30 +0100 Subject: [PATCH] GTK 4 compatibility fixes (#467) App still require GTK 3.22(3.24 in near future), but converting to GTK 4 should be easier and faster --- czkawka_gui/src/connect_button_delete.rs | 199 +++++++++--------- czkawka_gui/src/connect_button_move.rs | 31 +-- czkawka_gui/src/connect_button_search.rs | 1 + czkawka_gui/src/connect_header_buttons.rs | 12 +- czkawka_gui/src/connect_popovers.rs | 144 +++++++------ .../src/connect_selection_of_directories.rs | 49 +++-- czkawka_gui/src/connect_settings.rs | 4 +- czkawka_gui/src/create_tree_view.rs | 20 +- czkawka_gui/src/gui_data.rs | 7 +- czkawka_gui/src/gui_progress_dialog.rs | 6 +- czkawka_gui/src/gui_settings.rs | 7 +- czkawka_gui/src/help_functions.rs | 2 +- czkawka_gui/src/initialize_gui.rs | 133 ++---------- czkawka_gui/src/main.rs | 163 ++++++-------- czkawka_gui/src/saving_loading.rs | 8 +- 15 files changed, 344 insertions(+), 442 deletions(-) diff --git a/czkawka_gui/src/connect_button_delete.rs b/czkawka_gui/src/connect_button_delete.rs index 2c12091..35cfa73 100644 --- a/czkawka_gui/src/connect_button_delete.rs +++ b/czkawka_gui/src/connect_button_delete.rs @@ -2,7 +2,7 @@ use crate::gui_data::GuiData; use crate::help_functions::*; use crate::notebook_enums::*; use gtk::prelude::*; -use gtk::{Align, CheckButton, TextView}; +use gtk::{Align, CheckButton, Dialog, TextView}; use std::collections::BTreeMap; use std::fs; use std::fs::Metadata; @@ -11,7 +11,15 @@ use std::fs::Metadata; pub fn connect_button_delete(gui_data: &GuiData) { let buttons_delete = gui_data.bottom_buttons.buttons_delete.clone(); - let tree_view_duplicate_finder = gui_data.main_notebook.tree_view_duplicate_finder.clone(); + + let gui_data = gui_data.clone(); // TODO this maybe can be replaced, not sure if worth to do it + + buttons_delete.connect_clicked(move |_| { + glib::MainContext::default().spawn_local(delete_things(gui_data.clone())); + }); +} + +pub async fn delete_things(gui_data: GuiData) { 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(); @@ -24,77 +32,50 @@ pub fn connect_button_delete(gui_data: &GuiData) { 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(); + if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main).await { + return; + } - buttons_delete.connect_clicked(move |_| { - // TODO maybe add to this dialog info how much things will be deleted - if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main) { - return; + let nb_number = notebook_main.current_page().unwrap(); + let tree_view = &main_tree_views[nb_number as usize]; + let nb_object = &NOTEBOOKS_INFOS[nb_number as usize]; + + if let Some(column_color) = nb_object.column_color { + if !check_button_settings_confirm_group_deletion.is_active() || !check_if_deleting_all_files_in_group(tree_view, column_color, nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion).await { + tree_remove( + &tree_view.clone(), + nb_object.column_name, + nb_object.column_path, + column_color, + nb_object.column_selection, + &check_button_settings_use_trash, + &text_view_errors, + ); } - - let nb_number = notebook_main.current_page().unwrap(); - let tree_view = &main_tree_views[nb_number as usize]; - let nb_object = &NOTEBOOKS_INFOS[nb_number as usize]; - - if let Some(column_color) = nb_object.column_color { - if !check_button_settings_confirm_group_deletion.is_active() || !check_if_deleting_all_files_in_group(tree_view, column_color, nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion) { - tree_remove( - &tree_view_duplicate_finder.clone(), - nb_object.column_name, - nb_object.column_path, - column_color, - nb_object.column_selection, - &check_button_settings_use_trash, - &text_view_errors, - ); - } + } else { + if nb_number == NotebookMainEnum::EmptyDirectories as u32 { + empty_folder_remover(&tree_view.clone(), nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); } else { - if nb_number == NotebookMainEnum::EmptyDirectories as u32 { - empty_folder_remover(&tree_view.clone(), nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } else { - basic_remove(&tree_view.clone(), nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); - } + basic_remove(&tree_view.clone(), nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors); } + } - match &nb_object.notebook_type { - NotebookMainEnum::SimilarImages => { - image_preview_similar_images.hide(); - } - NotebookMainEnum::Duplicate => { - image_preview_duplicates.hide(); - } - _ => {} + match &nb_object.notebook_type { + NotebookMainEnum::SimilarImages => { + image_preview_similar_images.hide(); } - }); + NotebookMainEnum::Duplicate => { + image_preview_duplicates.hide(); + } + _ => {} + } } -pub fn check_if_can_delete_files(check_button_settings_confirm_deletion: >k::CheckButton, window_main: >k::Window) -> bool { +pub async fn check_if_can_delete_files(check_button_settings_confirm_deletion: >k::CheckButton, window_main: >k::Window) -> bool { if check_button_settings_confirm_deletion.is_active() { - let confirmation_dialog_delete = gtk::Dialog::with_buttons( - Some("Delete confirmation"), - Some(window_main), - gtk::DialogFlags::DESTROY_WITH_PARENT, - &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)], - ); - let label: gtk::Label = gtk::Label::new(Some("Are you sure that you want to delete files?")); - let check_button: gtk::CheckButton = gtk::CheckButton::with_label("Ask next time"); - check_button.set_active(true); - check_button.set_halign(Align::Center); + let (confirmation_dialog_delete, check_button) = create_dialog_ask_for_deletion(window_main); - let button_box = confirmation_dialog_delete.children()[0].clone().downcast::().unwrap().children()[0].clone().downcast::().unwrap().children()[0] - .clone() - .downcast::() - .unwrap(); - - let button_ok = button_box.children()[0].clone(); - button_ok.grab_focus(); - - let internal_box = confirmation_dialog_delete.children()[0].clone().downcast::().unwrap(); - internal_box.add(&label); - internal_box.add(&check_button); - - confirmation_dialog_delete.show_all(); - - let response_type = confirmation_dialog_delete.run(); + let response_type = confirmation_dialog_delete.run_future().await; if response_type == gtk::ResponseType::Ok { if !check_button.is_active() { check_button_settings_confirm_deletion.set_active(false); @@ -109,8 +90,65 @@ pub fn check_if_can_delete_files(check_button_settings_confirm_deletion: >k::C } true } +fn create_dialog_ask_for_deletion(window_main: >k::Window) -> (Dialog, CheckButton) { + let confirmation_dialog_delete = gtk::Dialog::with_buttons( + Some("Delete confirmation"), + Some(window_main), + gtk::DialogFlags::DESTROY_WITH_PARENT, + &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)], + ); + let label: gtk::Label = gtk::Label::new(Some("Are you sure that you want to delete files?")); + let check_button: gtk::CheckButton = gtk::CheckButton::with_label("Ask next time"); + check_button.set_active(true); + check_button.set_halign(Align::Center); -pub fn check_if_deleting_all_files_in_group(tree_view: >k::TreeView, column_color: i32, column_selection: i32, window_main: >k::Window, check_button_settings_confirm_group_deletion: >k::CheckButton) -> bool { + let button_box = confirmation_dialog_delete.children()[0].clone().downcast::().unwrap().children()[0].clone().downcast::().unwrap().children()[0] + .clone() + .downcast::() + .unwrap(); + + let button_ok = button_box.children()[0].clone(); + button_ok.grab_focus(); + + let internal_box = confirmation_dialog_delete.children()[0].clone().downcast::().unwrap(); + internal_box.add(&label); + internal_box.add(&check_button); + + confirmation_dialog_delete.show_all(); + (confirmation_dialog_delete, check_button) +} + +fn create_dialog_group_deletion(window_main: >k::Window) -> (Dialog, CheckButton) { + let confirmation_dialog_group_delete = gtk::Dialog::with_buttons( + Some("Confirmation of deleting all files in group"), + Some(window_main), + gtk::DialogFlags::MODAL, + &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)], + ); + let label: gtk::Label = gtk::Label::new(Some("In some groups there are selected all records.")); + let label2: gtk::Label = gtk::Label::new(Some("Are you sure that you want to delete them?")); + let check_button: gtk::CheckButton = gtk::CheckButton::with_label("Ask next time"); + check_button.set_active(true); + check_button.set_halign(Align::Center); + + let button_box = get_dialog_box_child(&confirmation_dialog_group_delete).children()[0].clone().downcast::().unwrap().children()[0] + .clone() + .downcast::() + .unwrap(); + + let button_ok = button_box.children()[0].clone(); + button_ok.grab_focus(); + + let internal_box = get_dialog_box_child(&confirmation_dialog_group_delete); + internal_box.add(&label); + internal_box.add(&label2); + internal_box.add(&check_button); + + confirmation_dialog_group_delete.show_all(); + (confirmation_dialog_group_delete, check_button) +} + +pub async fn check_if_deleting_all_files_in_group(tree_view: >k::TreeView, column_color: i32, column_selection: i32, window_main: >k::Window, check_button_settings_confirm_group_deletion: >k::CheckButton) -> bool { let model = get_list_store(tree_view); let mut selected_all_records: bool = true; @@ -141,38 +179,9 @@ pub fn check_if_deleting_all_files_in_group(tree_view: >k::TreeView, column_co if !selected_all_records { return false; } else { - let confirmation_dialog_group_delete = gtk::Dialog::with_buttons( - Some("Confirmation of deleting all files in group"), - Some(window_main), - gtk::DialogFlags::MODAL, - &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)], - ); - let label: gtk::Label = gtk::Label::new(Some("In some groups there are selected all records.")); - let label2: gtk::Label = gtk::Label::new(Some("Are you sure that you want to delete them?")); - let check_button: gtk::CheckButton = gtk::CheckButton::with_label("Ask next time"); - check_button.set_active(true); - check_button.set_halign(Align::Center); + let (confirmation_dialog_group_delete, check_button) = create_dialog_group_deletion(window_main); - let button_box = confirmation_dialog_group_delete.children()[0].clone().downcast::().unwrap().children()[0] - .clone() - .downcast::() - .unwrap() - .children()[0] - .clone() - .downcast::() - .unwrap(); - - let button_ok = button_box.children()[0].clone(); - button_ok.grab_focus(); - - let internal_box = confirmation_dialog_group_delete.children()[0].clone().downcast::().unwrap(); - internal_box.add(&label); - internal_box.add(&label2); - internal_box.add(&check_button); - - confirmation_dialog_group_delete.show_all(); - - let response_type = confirmation_dialog_group_delete.run(); + let response_type = confirmation_dialog_group_delete.run_future().await; if response_type == gtk::ResponseType::Ok { if !check_button.is_active() { check_button_settings_confirm_group_deletion.set_active(false); diff --git a/czkawka_gui/src/connect_button_move.rs b/czkawka_gui/src/connect_button_move.rs index 2efbbcf..746e787 100644 --- a/czkawka_gui/src/connect_button_move.rs +++ b/czkawka_gui/src/connect_button_move.rs @@ -57,23 +57,28 @@ fn move_things(tree_view: >k::TreeView, column_file_name: i32, column_path: i3 gtk::FileChooserAction::SelectFolder, &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)], ); - chooser.set_select_multiple(true); + chooser.set_select_multiple(false); chooser.show_all(); - let response_type = chooser.run(); - if response_type == gtk::ResponseType::Ok { - let folders = chooser.filenames(); - if folders.len() != 1 { - add_text_to_text_view(text_view_errors, format!("Only 1 path must be selected to be able to copy there duplicated files, found {:?}", folders).as_str()); - } else { - let folder = folders[0].clone(); - if let Some(column_color) = column_color { - move_with_tree(tree_view, column_file_name, column_path, column_color, column_selection, folder, entry_info, text_view_errors); + + let entry_info = entry_info.clone(); + let text_view_errors = text_view_errors.clone(); + let tree_view = tree_view.clone(); + chooser.connect_response(move |file_chooser, response_type| { + if response_type == gtk::ResponseType::Ok { + let folders = file_chooser.filenames(); + if folders.len() != 1 { + add_text_to_text_view(&text_view_errors, format!("Only 1 path must be selected to be able to copy there duplicated files, found {:?}", folders).as_str()); } else { - move_with_list(tree_view, column_file_name, column_path, column_selection, folder, entry_info, text_view_errors); + let folder = folders[0].clone(); + if let Some(column_color) = column_color { + move_with_tree(&tree_view, column_file_name, column_path, column_color, column_selection, folder, &entry_info, &text_view_errors); + } else { + move_with_list(&tree_view, column_file_name, column_path, column_selection, folder, &entry_info, &text_view_errors); + } } } - } - chooser.close(); + file_chooser.close(); + }); } fn move_with_tree(tree_view: >k::TreeView, column_file_name: i32, column_path: i32, column_color: i32, column_selection: i32, destination_folder: PathBuf, entry_info: >k::Entry, text_view_errors: >k::TextView) { let model = get_list_store(tree_view); diff --git a/czkawka_gui/src/connect_button_search.rs b/czkawka_gui/src/connect_button_search.rs index c6d5aab..74eb2e6 100644 --- a/czkawka_gui/src/connect_button_search.rs +++ b/czkawka_gui/src/connect_button_search.rs @@ -15,6 +15,7 @@ use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; use glib::Sender; use gtk::prelude::*; + use gtk::WindowPosition; use img_hash::{FilterType, HashAlg}; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/czkawka_gui/src/connect_header_buttons.rs b/czkawka_gui/src/connect_header_buttons.rs index 6468663..04a481e 100644 --- a/czkawka_gui/src/connect_header_buttons.rs +++ b/czkawka_gui/src/connect_header_buttons.rs @@ -1,6 +1,6 @@ use crate::gui_data::GuiData; use gtk::prelude::*; -use gtk::{ResponseType, WindowPosition}; +use gtk::WindowPosition; pub fn connect_button_about(gui_data: &GuiData) { let about_dialog = gui_data.about.about_dialog.clone(); @@ -8,9 +8,11 @@ pub fn connect_button_about(gui_data: &GuiData) { button_app_info.connect_clicked(move |_| { about_dialog.set_position(WindowPosition::Center); about_dialog.show(); - let response = about_dialog.run(); - if response != ResponseType::None { - about_dialog.hide(); - } + + // Prevent from deleting dialog after close + about_dialog.connect_delete_event(|e, _f| { + e.hide(); + Inhibit(true) + }); }); } diff --git a/czkawka_gui/src/connect_popovers.rs b/czkawka_gui/src/connect_popovers.rs index a955e60..106dffd 100644 --- a/czkawka_gui/src/connect_popovers.rs +++ b/czkawka_gui/src/connect_popovers.rs @@ -213,13 +213,11 @@ fn popover_one_oldest_newest(popover: >k::Popover, tree_view: >k::TreeView, fn popover_custom_select_unselect(popover: >k::Popover, window_main: &Window, tree_view: >k::TreeView, column_color: Option, column_file_name: i32, column_path: i32, column_button_selection: u32, select_things: bool) { popover.popdown(); - let wildcard: String; enum WildcardType { Path, Name, PathName, } - let wildcard_type: WildcardType; let window_title = match select_things { false => "Unselect Custom", @@ -231,9 +229,11 @@ fn popover_custom_select_unselect(popover: >k::Popover, window_main: &Window, let confirmation_dialog_delete = gtk::Dialog::with_buttons(Some(window_title), Some(window_main), gtk::DialogFlags::MODAL, &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)]); let label: gtk::Label = gtk::Label::new(Some("Usage: */folder-nr*/* or name-version-*.txt")); - let radio_path = gtk::RadioButton::with_label("Path"); - let radio_name = gtk::RadioButton::with_label_from_widget(&radio_path, "Name"); - let radio_name_path = gtk::RadioButton::with_label_from_widget(&radio_path, "Path + Name"); + let radio_path = gtk::RadioButton::builder().label("Path").build(); + let radio_name_path = gtk::RadioButton::builder().label("Path + Name").build(); + radio_name_path.join_group(Some(&radio_path)); + let radio_name = gtk::RadioButton::builder().label("Name").build(); + radio_name.join_group(Some(&radio_path)); // TODO, not sure why this not exists for builder, but should let entry_path = gtk::Entry::new(); let entry_name = gtk::Entry::new(); @@ -263,73 +263,79 @@ fn popover_custom_select_unselect(popover: >k::Popover, window_main: &Window, confirmation_dialog_delete.show_all(); - let response_type = confirmation_dialog_delete.run(); - if response_type == gtk::ResponseType::Ok { - if radio_path.is_active() { - wildcard_type = WildcardType::Path; - wildcard = entry_path.text().to_string(); - } else if radio_name.is_active() { - wildcard_type = WildcardType::Name; - wildcard = entry_name.text().to_string(); - } else if radio_name_path.is_active() { - wildcard_type = WildcardType::PathName; - wildcard = entry_name_path.text().to_string(); + let tree_view = tree_view.clone(); + confirmation_dialog_delete.connect_response(move |confirmation_dialog_delete, response_type| { + let wildcard_type: WildcardType; + let wildcard: String; + + if response_type == gtk::ResponseType::Ok { + if radio_path.is_active() { + wildcard_type = WildcardType::Path; + wildcard = entry_path.text().to_string(); + } else if radio_name.is_active() { + wildcard_type = WildcardType::Name; + wildcard = entry_name.text().to_string(); + } else if radio_name_path.is_active() { + wildcard_type = WildcardType::PathName; + wildcard = entry_name_path.text().to_string(); + } else { + panic!("Non handled option in wildcard"); + } + + if !wildcard.is_empty() { + let wildcard = wildcard.trim(); + + #[cfg(target_family = "windows")] + let wildcard = wildcard.replace("/", "\\"); + #[cfg(target_family = "windows")] + let wildcard = wildcard.as_str(); + + let model = get_list_store(&tree_view); + + let iter = model.iter_first().unwrap(); // Never should be available button where there is no available records + + loop { + if let Some(column_color) = column_color { + let color = model.value(&iter, column_color).get::().unwrap(); + if color == HEADER_ROW_COLOR { + if !model.iter_next(&iter) { + break; + } + continue; + } + } + + let path = model.value(&iter, column_path).get::().unwrap(); + let name = model.value(&iter, column_file_name).get::().unwrap(); + match wildcard_type { + WildcardType::Path => { + if Common::regex_check(wildcard, path) { + model.set_value(&iter, column_button_selection, &select_things.to_value()); + } + } + WildcardType::Name => { + if Common::regex_check(wildcard, name) { + model.set_value(&iter, column_button_selection, &select_things.to_value()); + } + } + WildcardType::PathName => { + if Common::regex_check(wildcard, format!("{}/{}", path, name)) { + model.set_value(&iter, column_button_selection, &select_things.to_value()); + } + } + } + + if !model.iter_next(&iter) { + break; + } + } + } } else { - panic!("Non handled option in wildcard"); + confirmation_dialog_delete.close(); + return; } - } else { confirmation_dialog_delete.close(); - return; - } - confirmation_dialog_delete.close(); - } - if !wildcard.is_empty() { - let wildcard = wildcard.trim(); - - #[cfg(target_family = "windows")] - let wildcard = wildcard.replace("/", "\\"); - #[cfg(target_family = "windows")] - let wildcard = wildcard.as_str(); - - let model = get_list_store(tree_view); - - let iter = model.iter_first().unwrap(); // Never should be available button where there is no available records - - loop { - if let Some(column_color) = column_color { - let color = model.value(&iter, column_color).get::().unwrap(); - if color == HEADER_ROW_COLOR { - if !model.iter_next(&iter) { - break; - } - continue; - } - } - - let path = model.value(&iter, column_path).get::().unwrap(); - let name = model.value(&iter, column_file_name).get::().unwrap(); - match wildcard_type { - WildcardType::Path => { - if Common::regex_check(wildcard, path) { - model.set_value(&iter, column_button_selection, &select_things.to_value()); - } - } - WildcardType::Name => { - if Common::regex_check(wildcard, name) { - model.set_value(&iter, column_button_selection, &select_things.to_value()); - } - } - WildcardType::PathName => { - if Common::regex_check(wildcard, format!("{}/{}", path, name)) { - model.set_value(&iter, column_button_selection, &select_things.to_value()); - } - } - } - - if !model.iter_next(&iter) { - break; - } - } + }); } } diff --git a/czkawka_gui/src/connect_selection_of_directories.rs b/czkawka_gui/src/connect_selection_of_directories.rs index 1df4492..2c97233 100644 --- a/czkawka_gui/src/connect_selection_of_directories.rs +++ b/czkawka_gui/src/connect_selection_of_directories.rs @@ -80,18 +80,21 @@ fn add_chosen_directories(window_main: &Window, tree_view: &TreeView, excluded_i let chooser = gtk::FileChooserDialog::with_buttons(Some(folders_to), Some(window_main), gtk::FileChooserAction::SelectFolder, &[("Ok", gtk::ResponseType::Ok), ("Close", gtk::ResponseType::Cancel)]); chooser.set_select_multiple(true); chooser.show_all(); - let response_type = chooser.run(); - if response_type == gtk::ResponseType::Ok { - let folder = chooser.filenames(); - let list_store = get_list_store(tree_view); + let tree_view = tree_view.clone(); + chooser.connect_response(move |chooser, response_type| { + if response_type == gtk::ResponseType::Ok { + let folder = chooser.filenames(); - for file_entry in &folder { - let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &file_entry.to_string_lossy().to_string())]; - list_store.set(&list_store.append(), &values); + let list_store = get_list_store(&tree_view); + + for file_entry in &folder { + let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &file_entry.to_string_lossy().to_string())]; + list_store.set(&list_store.append(), &values); + } } - } - chooser.close(); + chooser.close(); + }); } fn add_manually_directories(window_main: &Window, tree_view: &TreeView) { @@ -105,22 +108,24 @@ fn add_manually_directories(window_main: &Window, tree_view: &TreeView) { dialog_manual_add_directory.show_all(); - let response_type = dialog_manual_add_directory.run(); - if response_type == gtk::ResponseType::Ok { - let text = entry.text().to_string().trim().to_string(); + let tree_view = tree_view.clone(); + dialog_manual_add_directory.connect_response(move |dialog_manual_add_directory, response_type| { + if response_type == gtk::ResponseType::Ok { + let text = entry.text().to_string().trim().to_string(); - #[cfg(target_family = "windows")] - let text = Common::normalize_windows_path(text).to_string_lossy().to_string(); + #[cfg(target_family = "windows")] + let text = Common::normalize_windows_path(text).to_string_lossy().to_string(); - if !text.is_empty() { - let list_store = get_list_store(tree_view); + if !text.is_empty() { + let list_store = get_list_store(&tree_view); - let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &text)]; - list_store.set(&list_store.append(), &values); + let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &text)]; + list_store.set(&list_store.append(), &values); + } + } else { + dialog_manual_add_directory.close(); + return; } - } else { dialog_manual_add_directory.close(); - return; - } - dialog_manual_add_directory.close(); + }); } diff --git a/czkawka_gui/src/connect_settings.rs b/czkawka_gui/src/connect_settings.rs index 984e828..5bff065 100644 --- a/czkawka_gui/src/connect_settings.rs +++ b/czkawka_gui/src/connect_settings.rs @@ -10,16 +10,14 @@ pub fn connect_settings(gui_data: &GuiData) { let window_main = gui_data.window_main.clone(); let window_settings = gui_data.settings.window_settings.clone(); button_settings.connect_clicked(move |_| { + window_main.set_position(WindowPosition::Center); window_main.set_sensitive(false); window_settings.show(); - window_settings.set_position(WindowPosition::Center); }); let window_main = gui_data.window_main.clone(); let window_settings = gui_data.settings.window_settings.clone(); - window_settings.hide_on_delete(); - window_settings.connect_delete_event(move |window, _y| { window.hide(); window_main.set_sensitive(true); diff --git a/czkawka_gui/src/create_tree_view.rs b/czkawka_gui/src/create_tree_view.rs index 40cb5a5..9a34a1a 100644 --- a/czkawka_gui/src/create_tree_view.rs +++ b/czkawka_gui/src/create_tree_view.rs @@ -11,7 +11,7 @@ pub fn create_tree_view_duplicates(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsDuplicates::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsDuplicates::SelectionButton as u32, &fixed.to_value()); }); @@ -69,7 +69,7 @@ pub fn create_tree_view_empty_folders(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsEmptyFolders::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsEmptyFolders::SelectionButton as u32, &fixed.to_value()); }); @@ -119,7 +119,7 @@ pub fn create_tree_view_big_files(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsBigFiles::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsBigFiles::SelectionButton as u32, &fixed.to_value()); }); @@ -178,7 +178,7 @@ pub fn create_tree_view_temporary_files(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsTemporaryFiles::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsTemporaryFiles::SelectionButton as u32, &fixed.to_value()); }); @@ -228,7 +228,7 @@ pub fn create_tree_view_empty_files(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsEmptyFiles::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsEmptyFiles::SelectionButton as u32, &fixed.to_value()); }); @@ -278,7 +278,7 @@ pub fn create_tree_view_similar_images(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsSimilarImages::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsSimilarImages::SelectionButton as u32, &fixed.to_value()); }); @@ -369,7 +369,7 @@ pub fn create_tree_view_similar_videos(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsSimilarVideos::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsSimilarVideos::SelectionButton as u32, &fixed.to_value()); }); @@ -448,7 +448,7 @@ pub fn create_tree_view_same_music(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsSameMusic::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsSameMusic::SelectionButton as u32, &fixed.to_value()); }); @@ -572,7 +572,7 @@ pub fn create_tree_view_invalid_symlinks(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsInvalidSymlinks::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsInvalidSymlinks::SelectionButton as u32, &fixed.to_value()); }); @@ -640,7 +640,7 @@ pub fn create_tree_view_broken_files(tree_view: &mut gtk::TreeView) { let mut fixed = model .value(&iter, ColumnsBrokenFiles::SelectionButton as i32) .get::() - .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + .unwrap_or_else(|err| panic!("ListStore value missing at path {:?}: {}", path, err)); fixed = !fixed; model.set_value(&iter, ColumnsBrokenFiles::SelectionButton as u32, &fixed.to_value()); }); diff --git a/czkawka_gui/src/gui_data.rs b/czkawka_gui/src/gui_data.rs index 9b94fb1..910185c 100644 --- a/czkawka_gui/src/gui_data.rs +++ b/czkawka_gui/src/gui_data.rs @@ -77,7 +77,7 @@ pub struct GuiData { } impl GuiData { - pub fn new() -> Self { + pub fn new_with_application(application: >k::Application) -> Self { //// Loading glade file content and build with it help UI let glade_src = include_str!("../ui/main_window.glade").to_string(); let builder = Builder::from_string(glade_src.as_str()); @@ -87,15 +87,16 @@ impl GuiData { window_main.show_all(); window_main.set_title("Czkawka"); window_main.set_position(WindowPosition::Center); + window_main.set_application(Some(application)); let main_notebook = GuiMainNotebook::create_from_builder(&builder); let upper_notebook = GuiUpperNotebook::create_from_builder(&builder); let popovers = GuiPopovers::create_from_builder(); let bottom_buttons = GuiBottomButtons::create_from_builder(&builder); - let progress_window = GuiProgressDialog::create_from_builder(); + let progress_window = GuiProgressDialog::create_from_builder(&window_main); let about = GuiAbout::create_from_builder(); let header = GuiHeader::create_from_builder(&builder); - let settings = GuiSettings::create_from_builder(); + let settings = GuiSettings::create_from_builder(&window_main); //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/czkawka_gui/src/gui_progress_dialog.rs b/czkawka_gui/src/gui_progress_dialog.rs index 2261291..92940fb 100644 --- a/czkawka_gui/src/gui_progress_dialog.rs +++ b/czkawka_gui/src/gui_progress_dialog.rs @@ -1,5 +1,5 @@ use gtk::prelude::*; -use gtk::Builder; +use gtk::{Builder, Window}; #[derive(Clone)] pub struct GuiProgressDialog { @@ -16,11 +16,13 @@ pub struct GuiProgressDialog { } impl GuiProgressDialog { - pub fn create_from_builder() -> Self { + pub fn create_from_builder(window_main: &Window) -> Self { let glade_src = include_str!("../ui/progress.glade").to_string(); let builder = Builder::from_string(glade_src.as_str()); let window_progress: gtk::Window = builder.object("window_progress").unwrap(); + window_progress.set_transient_for(Some(window_main)); + window_progress.set_modal(true); let progress_bar_current_stage: gtk::ProgressBar = builder.object("progress_bar_current_stage").unwrap(); let progress_bar_all_stages: gtk::ProgressBar = builder.object("progress_bar_all_stages").unwrap(); diff --git a/czkawka_gui/src/gui_settings.rs b/czkawka_gui/src/gui_settings.rs index 10128df..699afe6 100644 --- a/czkawka_gui/src/gui_settings.rs +++ b/czkawka_gui/src/gui_settings.rs @@ -1,5 +1,5 @@ use gtk::prelude::*; -use gtk::{Builder, WindowPosition}; +use gtk::{Builder, Window}; #[derive(Clone)] pub struct GuiSettings { @@ -29,12 +29,13 @@ pub struct GuiSettings { } impl GuiSettings { - pub fn create_from_builder() -> Self { + pub fn create_from_builder(window_main: &Window) -> Self { let glade_src = include_str!("../ui/settings.glade").to_string(); let builder = Builder::from_string(glade_src.as_str()); let window_settings: gtk::Window = builder.object("window_settings").unwrap(); - window_settings.set_position(WindowPosition::Center); + window_settings.set_modal(true); + window_settings.set_transient_for(Some(window_main)); // General let check_button_settings_save_at_exit: gtk::CheckButton = builder.object("check_button_settings_save_at_exit").unwrap(); diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index a0181c3..8233510 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -400,7 +400,7 @@ pub fn get_list_store(tree_view: >k::TreeView) -> ListStore { tree_view.model().unwrap().downcast::().unwrap() } pub fn get_dialog_box_child(dialog: >k::Dialog) -> gtk::Box { - dialog.children()[0].clone().downcast::().unwrap() + dialog.child().unwrap().downcast::().unwrap() } pub fn change_dimension_to_krotka(dimensions: String) -> (u64, u64) { diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index 9c85192..c507ee5 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -1,5 +1,6 @@ -use crate::connect_button_delete::{basic_remove, check_if_can_delete_files, check_if_deleting_all_files_in_group, empty_folder_remover, tree_remove}; +use crate::connect_button_delete::{basic_remove, empty_folder_remover}; use crate::create_tree_view::*; +use crate::delete_things; use crate::gui_data::*; use crate::help_functions::*; use crate::notebook_enums::NotebookMainEnum; @@ -122,49 +123,17 @@ pub fn initialize_gui(gui_data: &mut GuiData) { scrolled_window_duplicate_finder.add(&tree_view); scrolled_window_duplicate_finder.show_all(); - let text_view_errors_cloned = text_view_errors.clone(); + let gui_data_clone = gui_data.clone(); - let check_button_settings_confirm_group_deletion = gui_data.settings.check_button_settings_confirm_group_deletion.clone(); - let check_button_settings_confirm_deletion = gui_data.settings.check_button_settings_confirm_deletion.clone(); - let window_main = gui_data.window_main.clone(); - - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.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 { - if tree_view.selection().selected_rows().0.is_empty() { - return gtk::Inhibit(false); - } - if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main) { - return gtk::Inhibit(false); - } - if check_button_settings_confirm_group_deletion.is_active() - && check_if_deleting_all_files_in_group(&tree_view.clone(), nb_object.column_color.unwrap(), nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion) - { - return gtk::Inhibit(false); - } - tree_remove( - tree_view, - nb_object.column_name, - nb_object.column_path, - nb_object.column_color.unwrap(), - nb_object.column_selection, - &check_button_settings_use_trash, - &text_view_errors, - ); - image_preview_duplicates.hide(); + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); } } - show_preview( - tree_view, - &text_view_errors_cloned, - &check_button_settings_show_preview_duplicates, - &image_preview_duplicates, - nb_object.column_path, - nb_object.column_name, - ); + 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) }); } @@ -298,7 +267,6 @@ pub fn initialize_gui(gui_data: &mut GuiData) { } // Similar Images { - let image_preview_similar_images_clone = image_preview_similar_images.clone(); image_preview_similar_images.hide(); let col_types: [glib::types::Type; 12] = [ @@ -345,39 +313,16 @@ pub fn initialize_gui(gui_data: &mut GuiData) { scrolled_window_similar_images_finder.add(&tree_view); scrolled_window_similar_images_finder.show_all(); - let image_preview_similar_images = image_preview_similar_images_clone.clone(); + 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 check_button_settings_confirm_group_deletion = gui_data.settings.check_button_settings_confirm_group_deletion.clone(); - let check_button_settings_confirm_deletion = gui_data.settings.check_button_settings_confirm_deletion.clone(); - let window_main = gui_data.window_main.clone(); - let check_button_settings_use_trash = gui_data.settings.check_button_settings_use_trash.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 { - if tree_view.selection().selected_rows().0.is_empty() { - return gtk::Inhibit(false); - } - if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main) { - return gtk::Inhibit(false); - } - if check_button_settings_confirm_group_deletion.is_active() - && check_if_deleting_all_files_in_group(&tree_view.clone(), nb_object.column_color.unwrap(), nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion) - { - return gtk::Inhibit(false); - } - tree_remove( - tree_view, - nb_object.column_name, - nb_object.column_path, - nb_object.column_color.unwrap(), - nb_object.column_selection, - &check_button_settings_use_trash, - &text_view_errors, - ); - image_preview_similar_images_clone.hide(); + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); } } show_preview( @@ -422,36 +367,12 @@ pub fn initialize_gui(gui_data: &mut GuiData) { scrolled_window_similar_videos_finder.add(&tree_view); scrolled_window_similar_videos_finder.show_all(); - let check_button_settings_confirm_deletion = gui_data.settings.check_button_settings_confirm_deletion.clone(); - let check_button_settings_confirm_group_deletion = gui_data.settings.check_button_settings_confirm_group_deletion.clone(); - let window_main = gui_data.window_main.clone(); - 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| { + 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 { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SimilarVideos as usize]; - if tree_view.selection().selected_rows().0.is_empty() { - return gtk::Inhibit(false); - } - if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main) { - return gtk::Inhibit(false); - } - if check_button_settings_confirm_group_deletion.is_active() - && check_if_deleting_all_files_in_group(&tree_view.clone(), nb_object.column_color.unwrap(), nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion) - { - return gtk::Inhibit(false); - } - tree_remove( - tree_view, - nb_object.column_name, - nb_object.column_path, - nb_object.column_color.unwrap(), - nb_object.column_selection, - &check_button_settings_use_trash, - &text_view_errors, - ); + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); } } gtk::Inhibit(false) @@ -493,36 +414,12 @@ pub fn initialize_gui(gui_data: &mut GuiData) { scrolled_window_same_music_finder.add(&tree_view); scrolled_window_same_music_finder.show_all(); - let check_button_settings_confirm_group_deletion = gui_data.settings.check_button_settings_confirm_group_deletion.clone(); - let window_main = gui_data.window_main.clone(); - 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| { + 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 { - let nb_object = &NOTEBOOKS_INFOS[NotebookMainEnum::SameMusic as usize]; - - if tree_view.selection().selected_rows().0.is_empty() { - return gtk::Inhibit(false); - } - if !check_if_can_delete_files(&check_button_settings_confirm_group_deletion, &window_main) { - return gtk::Inhibit(false); - } - if check_button_settings_confirm_group_deletion.is_active() - && check_if_deleting_all_files_in_group(&tree_view.clone(), nb_object.column_color.unwrap(), nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion) - { - return gtk::Inhibit(false); - } - tree_remove( - tree_view, - nb_object.column_name, - nb_object.column_path, - nb_object.column_color.unwrap(), - nb_object.column_selection, - &check_button_settings_use_trash, - &text_view_errors, - ); + glib::MainContext::default().spawn_local(delete_things(gui_data_clone.clone())); } } gtk::Inhibit(false) @@ -678,8 +575,6 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let window_progress = gui_data.progress_window.window_progress.clone(); let stop_sender = gui_data.stop_sender.clone(); - window_progress.hide_on_delete(); - window_progress.connect_delete_event(move |_e, _y| { stop_sender.send(()).unwrap(); gtk::Inhibit(true) diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index 2b613d4..bdf0753 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -66,112 +66,89 @@ use crate::initialize_gui::*; use crate::saving_loading::*; use crate::tests::validate_notebook_data; use gtk::prelude::*; -use std::{env, process}; fn main() { - let mut exit_program_after_initialization: bool = false; - // Printing version - { - let all_arguments: Vec = env::args().skip(1).collect(); // Not need to check program name + let application = gtk::Application::builder().application_id("com.github.qarmin").build(); + application.connect_activate(|application| { + let mut gui_data: GuiData = GuiData::new_with_application(application); - for i in all_arguments { - if i == "-v" || i == "--version" { - println!("Czkawka GUI {}", CZKAWKA_VERSION); - process::exit(0); - } - if i == "-q" || i == "--quit" { - exit_program_after_initialization = true; - } - } - } + // Used for getting data from thread + let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); - gtk::init().expect("Failed to initialize GTK."); + // Futures progress report + let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); + let (futures_sender_empty_files, futures_receiver_empty_files): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); + let (futures_sender_empty_folder, futures_receiver_empty_folder): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); + let (futures_sender_big_file, futures_receiver_big_file): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); + let (futures_sender_same_music, futures_receiver_same_music): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); + let (futures_sender_similar_images, futures_receiver_similar_images): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); + let (futures_sender_similar_videos, futures_receiver_similar_videos): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); + let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); + let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); + let (futures_sender_broken_files, futures_receiver_broken_files): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); - let mut gui_data: GuiData = GuiData::new(); + initialize_gui(&mut gui_data); + validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup + reset_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors); // Fallback for invalid loading setting project + load_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors, &gui_data.scrolled_window_errors); - // Used for getting data from thread - let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + connect_button_delete(&gui_data); + connect_button_save(&gui_data); + connect_button_search( + &gui_data, + glib_stop_sender, + futures_sender_duplicate_files, + futures_sender_empty_files, + futures_sender_empty_folder, + futures_sender_big_file, + futures_sender_same_music, + futures_sender_similar_images, + futures_sender_similar_videos, + futures_sender_temporary, + futures_sender_invalid_symlinks, + futures_sender_broken_files, + ); + connect_button_select(&gui_data); + connect_button_stop(&gui_data); + connect_button_hardlink_symlink(&gui_data); + connect_button_move(&gui_data); + connect_notebook_tabs(&gui_data); + connect_selection_of_directories(&gui_data); + connect_popovers(&gui_data); + connect_compute_results(&gui_data, glib_stop_receiver); + connect_progress_window( + &gui_data, + futures_receiver_duplicate_files, + futures_receiver_empty_files, + futures_receiver_empty_folder, + futures_receiver_big_file, + futures_receiver_same_music, + futures_receiver_similar_images, + futures_receiver_similar_videos, + futures_receiver_temporary, + futures_receiver_invalid_symlinks, + futures_receiver_broken_files, + ); + connect_hide_text_view_errors(&gui_data); + connect_settings(&gui_data); + connect_button_about(&gui_data); + connect_about_buttons(&gui_data); + connect_similar_image_size_change(&gui_data); - // Futures progress report - let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - let (futures_sender_empty_files, futures_receiver_empty_files): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - let (futures_sender_empty_folder, futures_receiver_empty_folder): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - let (futures_sender_big_file, futures_receiver_big_file): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - let (futures_sender_same_music, futures_receiver_same_music): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - let (futures_sender_similar_images, futures_receiver_similar_images): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = - futures::channel::mpsc::unbounded(); - let (futures_sender_similar_videos, futures_receiver_similar_videos): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = - futures::channel::mpsc::unbounded(); - let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = - futures::channel::mpsc::unbounded(); - let (futures_sender_broken_files, futures_receiver_broken_files): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); - - initialize_gui(&mut gui_data); - validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup - reset_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors); // Fallback for invalid loading setting project - load_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors, &gui_data.scrolled_window_errors); - - connect_button_delete(&gui_data); - connect_button_save(&gui_data); - connect_button_search( - &gui_data, - glib_stop_sender, - futures_sender_duplicate_files, - futures_sender_empty_files, - futures_sender_empty_folder, - futures_sender_big_file, - futures_sender_same_music, - futures_sender_similar_images, - futures_sender_similar_videos, - futures_sender_temporary, - futures_sender_invalid_symlinks, - futures_sender_broken_files, - ); - connect_button_select(&gui_data); - connect_button_stop(&gui_data); - connect_button_hardlink_symlink(&gui_data); - connect_button_move(&gui_data); - connect_notebook_tabs(&gui_data); - connect_selection_of_directories(&gui_data); - connect_popovers(&gui_data); - connect_compute_results(&gui_data, glib_stop_receiver); - connect_progress_window( - &gui_data, - futures_receiver_duplicate_files, - futures_receiver_empty_files, - futures_receiver_empty_folder, - futures_receiver_big_file, - futures_receiver_same_music, - futures_receiver_similar_images, - futures_receiver_similar_videos, - futures_receiver_temporary, - futures_receiver_invalid_symlinks, - futures_receiver_broken_files, - ); - connect_hide_text_view_errors(&gui_data); - connect_settings(&gui_data); - connect_button_about(&gui_data); - connect_about_buttons(&gui_data); - connect_similar_image_size_change(&gui_data); - - // Quit the program when X in main window was clicked - { let window_main = gui_data.window_main.clone(); let taskbar_state = gui_data.taskbar_state.clone(); window_main.connect_delete_event(move |_, _| { save_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors); // Save configuration at exit - gtk::main_quit(); taskbar_state.borrow_mut().release(); Inhibit(false) }); - } + }); - // We start the gtk main loop. - gtk::main(); - - // Quiting if quit flag was provided - if exit_program_after_initialization { - gtk::main_quit(); - } + application.run(); } diff --git a/czkawka_gui/src/saving_loading.rs b/czkawka_gui/src/saving_loading.rs index 74efeeb..fd10a62 100644 --- a/czkawka_gui/src/saving_loading.rs +++ b/czkawka_gui/src/saving_loading.rs @@ -456,7 +456,7 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb list_store.clear(); for directory in included_directories { - let values: [(u32, &dyn ToValue); 1] = [(0, &directory)]; + let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &directory)]; list_store.set(&list_store.append(), &values); } @@ -466,7 +466,7 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb list_store.clear(); for directory in excluded_directories { - let values: [(u32, &dyn ToValue); 1] = [(0, &directory)]; + let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &directory)]; list_store.set(&list_store.append(), &values); } @@ -535,7 +535,7 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb } }; - let values: [(u32, &dyn ToValue); 1] = [(0, ¤t_dir)]; + let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, ¤t_dir)]; list_store.set(&list_store.append(), &values); } // Resetting excluded directories @@ -545,7 +545,7 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb list_store.clear(); if cfg!(target_family = "unix") { for i in ["/proc", "/dev", "/sys", "/run", "/snap"].iter() { - let values: [(u32, &dyn ToValue); 1] = [(0, &i)]; + let values: [(u32, &dyn ToValue); 1] = [(ColumnsDirectory::Path as u32, &i)]; list_store.set(&list_store.append(), &values); } }