From 27659cf4fb11b1570c41cf39ee462bbcc51858fc Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Tue, 11 Jan 2022 17:30:44 -0300 Subject: [PATCH] calendar-management/new-calendar-page: Port to GTK4 --- .../gcal-file-chooser-button.c | 268 +++++++++++++ .../gcal-file-chooser-button.h | 44 ++ .../gcal-new-calendar-page.c | 60 ++- .../gcal-new-calendar-page.ui | 377 ++++++++---------- src/gui/calendar-management/meson.build | 1 + 5 files changed, 511 insertions(+), 239 deletions(-) create mode 100644 src/gui/calendar-management/gcal-file-chooser-button.c create mode 100644 src/gui/calendar-management/gcal-file-chooser-button.h diff --git a/src/gui/calendar-management/gcal-file-chooser-button.c b/src/gui/calendar-management/gcal-file-chooser-button.c new file mode 100644 index 00000000..bad14f57 --- /dev/null +++ b/src/gui/calendar-management/gcal-file-chooser-button.c @@ -0,0 +1,268 @@ +/* gcal-file-chooser-button.c + * + * Copyright 2021 Georges Basile Stavracas Neto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "gcal-file-chooser-button.h" + +#include + +struct _GcalFileChooserButton +{ + GtkButton parent_instance; + + GtkFileChooser *filechooser; + GFile *file; + gchar *title; +}; + +G_DEFINE_FINAL_TYPE (GcalFileChooserButton, gcal_file_chooser_button, GTK_TYPE_BUTTON) + +enum +{ + PROP_0, + PROP_FILE, + PROP_TITLE, + N_PROPS +}; + +static GParamSpec *properties [N_PROPS] = { NULL, }; + +static const gchar * +get_title (GcalFileChooserButton *self) +{ + return self->title ? self->title : _("Select a file"); +} + +static void +update_label (GcalFileChooserButton *self) +{ + g_autofree gchar *label = NULL; + + if (self->file) + label = g_file_get_basename (self->file); + else + label = g_strdup (get_title (self)); + + gtk_button_set_label (GTK_BUTTON (self), label); +} + +static void +on_filechooser_dialog_response_cb (GtkFileChooser *filechooser, + gint response, + GcalFileChooserButton *self) +{ + if (response == GTK_RESPONSE_ACCEPT) + { + g_autoptr(GFile) file = NULL; + + file = gtk_file_chooser_get_file (filechooser); + gcal_file_chooser_button_set_file (self, file); + } + + gtk_widget_hide (GTK_WIDGET (filechooser)); +} +static void +ensure_filechooser (GcalFileChooserButton *self) +{ + GtkNative *native; + GtkWidget *dialog; + + if (self->filechooser) + return; + + native = gtk_widget_get_native (GTK_WIDGET (self)); + + dialog = gtk_file_chooser_dialog_new (get_title (self), + GTK_WINDOW (native), + GTK_FILE_CHOOSER_ACTION_OPEN, + _("Cancel"), + GTK_RESPONSE_CANCEL, + _("Open"), + GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + gtk_window_set_hide_on_close (GTK_WINDOW (dialog), TRUE); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + if (self->file) + gtk_file_chooser_set_file (GTK_FILE_CHOOSER (dialog), self->file, NULL); + + g_signal_connect (dialog, "response", G_CALLBACK (on_filechooser_dialog_response_cb), self); + + self->filechooser = GTK_FILE_CHOOSER (dialog); +} + + +static void +gcal_file_chooser_button_clicked (GtkButton *button) +{ + GcalFileChooserButton *self = GCAL_FILE_CHOOSER_BUTTON (button); + GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self)); + + ensure_filechooser (self); + + gtk_window_set_transient_for (GTK_WINDOW (self->filechooser), GTK_WINDOW (native)); + gtk_window_present (GTK_WINDOW (self->filechooser)); +} + +static void +gcal_file_chooser_button_finalize (GObject *object) +{ + GcalFileChooserButton *self = (GcalFileChooserButton *)object; + + g_clear_pointer (&self->title, g_free); + g_clear_object (&self->file); + + G_OBJECT_CLASS (gcal_file_chooser_button_parent_class)->finalize (object); +} + +static void +gcal_file_chooser_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GcalFileChooserButton *self = GCAL_FILE_CHOOSER_BUTTON (object); + + switch (prop_id) + { + case PROP_FILE: + g_value_set_object (value, self->file); + break; + + case PROP_TITLE: + g_value_set_string (value, self->title); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_file_chooser_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GcalFileChooserButton *self = GCAL_FILE_CHOOSER_BUTTON (object); + + switch (prop_id) + { + case PROP_FILE: + gcal_file_chooser_button_set_file (self, g_value_get_object (value)); + break; + + case PROP_TITLE: + gcal_file_chooser_button_set_title (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_file_chooser_button_class_init (GcalFileChooserButtonClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass); + + button_class->clicked = gcal_file_chooser_button_clicked; + + object_class->finalize = gcal_file_chooser_button_finalize; + object_class->get_property = gcal_file_chooser_button_get_property; + object_class->set_property = gcal_file_chooser_button_set_property; + + properties[PROP_FILE] = g_param_spec_object ("file", "", "", + G_TYPE_FILE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + properties[PROP_TITLE] = g_param_spec_string ("title", "", "", NULL, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +gcal_file_chooser_button_init (GcalFileChooserButton *self) +{ + update_label (self); +} + +GtkWidget* +gcal_file_chooser_button_new (void) +{ + return g_object_new (GCAL_TYPE_FILE_CHOOSER_BUTTON, NULL); +} + +void +gcal_file_chooser_button_set_file (GcalFileChooserButton *self, + GFile *file) +{ + g_return_if_fail (GCAL_IS_FILE_CHOOSER_BUTTON (self)); + + if (g_set_object (&self->file, file)) + { + gtk_file_chooser_set_file (self->filechooser, file, NULL); + update_label (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]); + } +} + +GFile * +gcal_file_chooser_button_get_file (GcalFileChooserButton *self) +{ + g_return_val_if_fail (GCAL_IS_FILE_CHOOSER_BUTTON (self), NULL); + + return self->file ? g_object_ref (self->file) : NULL; +} + +void +gcal_file_chooser_button_set_title (GcalFileChooserButton *self, + const gchar *title) +{ + g_autofree gchar *old_title = NULL; + + g_return_if_fail (GCAL_IS_FILE_CHOOSER_BUTTON (self)); + + old_title = g_steal_pointer (&self->title); + self->title = g_strdup (title); + + update_label (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]); +} + +const gchar* +gcal_file_chooser_button_get_title (GcalFileChooserButton *self) +{ + g_return_val_if_fail (GCAL_IS_FILE_CHOOSER_BUTTON (self), NULL); + + return self->title; +} + +GtkFileChooser* +gcal_file_chooser_button_get_filechooser (GcalFileChooserButton *self) +{ + g_return_val_if_fail (GCAL_IS_FILE_CHOOSER_BUTTON (self), NULL); + + ensure_filechooser (self); + + return self->filechooser; +} diff --git a/src/gui/calendar-management/gcal-file-chooser-button.h b/src/gui/calendar-management/gcal-file-chooser-button.h new file mode 100644 index 00000000..bc1faa5a --- /dev/null +++ b/src/gui/calendar-management/gcal-file-chooser-button.h @@ -0,0 +1,44 @@ +/* gcal-file-chooser-button.h + * + * Copyright 2021 Georges Basile Stavracas Neto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define GCAL_TYPE_FILE_CHOOSER_BUTTON (gcal_file_chooser_button_get_type()) +G_DECLARE_FINAL_TYPE (GcalFileChooserButton, gcal_file_chooser_button, GCAL, FILE_CHOOSER_BUTTON, GtkButton) + +GtkWidget* gcal_file_chooser_button_new (void); + +void gcal_file_chooser_button_set_file (GcalFileChooserButton *self, + GFile *file); + +GFile* gcal_file_chooser_button_get_file (GcalFileChooserButton *self); + +void gcal_file_chooser_button_set_title (GcalFileChooserButton *self, + const char *title); + +const gchar* gcal_file_chooser_button_get_title (GcalFileChooserButton *self); + +GtkFileChooser* gcal_file_chooser_button_get_filechooser (GcalFileChooserButton *self); + +G_END_DECLS diff --git a/src/gui/calendar-management/gcal-new-calendar-page.c b/src/gui/calendar-management/gcal-new-calendar-page.c index e8fa9895..e701df82 100644 --- a/src/gui/calendar-management/gcal-new-calendar-page.c +++ b/src/gui/calendar-management/gcal-new-calendar-page.c @@ -25,6 +25,7 @@ #include "gcal-context.h" #include "gcal-calendar-management-page.h" #include "gcal-debug.h" +#include "gcal-file-chooser-button.h" #include "gcal-new-calendar-page.h" #include "gcal-source-discoverer.h" #include "gcal-utils.h" @@ -46,13 +47,13 @@ struct _GcalNewCalendarPage GtkWidget *add_button; GtkEntry *calendar_address_entry; EntryState calendar_address_entry_state; - GtkFileChooser *calendar_file_chooser_button; + GcalFileChooserButton *calendar_file_chooser_button; GtkFileFilter *calendar_file_filter; GtkWidget *cancel_button; GtkWidget *credentials_cancel_button; GtkWidget *credentials_connect_button; GtkEntry *credentials_password_entry; - GtkPopover *credentials_popover; + GtkWidget *credentials_popover; GtkEntry *credentials_user_entry; GtkColorChooser *local_calendar_color_button; GtkEntry *local_calendar_name_entry; @@ -153,7 +154,7 @@ update_local_source (GcalNewCalendarPage *self) g_clear_object (&self->local_source); - calendar_name = g_strdup (gtk_entry_get_text (self->local_calendar_name_entry)); + calendar_name = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->local_calendar_name_entry))); calendar_name = g_strstrip (calendar_name); if (calendar_name && g_utf8_strlen (calendar_name, -1) > 0) @@ -224,9 +225,9 @@ discover_sources (GcalNewCalendarPage *self) self->validate_url_resource_id = 0; - url = gtk_entry_get_text (self->calendar_address_entry); - username = gtk_entry_get_text (self->credentials_user_entry); - password = gtk_entry_get_text (self->credentials_password_entry); + url = gtk_editable_get_text (GTK_EDITABLE (self->calendar_address_entry)); + username = gtk_editable_get_text (GTK_EDITABLE (self->credentials_user_entry)); + password = gtk_editable_get_text (GTK_EDITABLE (self->credentials_password_entry)); gcal_discover_sources_from_uri (url, username, @@ -242,10 +243,10 @@ discover_sources (GcalNewCalendarPage *self) static void popdown_credentials_popover (GcalNewCalendarPage *self) { - gtk_entry_set_text (self->credentials_user_entry, ""); - gtk_entry_set_text (self->credentials_password_entry, ""); + gtk_editable_set_text (GTK_EDITABLE (self->credentials_user_entry), ""); + gtk_editable_set_text (GTK_EDITABLE (self->credentials_password_entry), ""); - gtk_popover_popdown (self->credentials_popover); + gtk_popover_popdown (GTK_POPOVER (self->credentials_popover)); } /* @@ -253,8 +254,9 @@ popdown_credentials_popover (GcalNewCalendarPage *self) */ static void -on_file_chooser_button_file_set_cb (GtkFileChooser *chooser, - GcalNewCalendarPage *self) +on_file_chooser_button_file_changed_cb (GcalFileChooserButton *chooser, + GParamSpec *pspec, + GcalNewCalendarPage *self) { g_autofree gchar *display_name = NULL; g_autoptr (ESource) source = NULL; @@ -263,7 +265,7 @@ on_file_chooser_button_file_set_cb (GtkFileChooser *chooser, GCAL_ENTRY; - file = gtk_file_chooser_get_file (chooser); + file = gcal_file_chooser_button_get_file (chooser); if (!file) GCAL_RETURN (); @@ -289,7 +291,7 @@ on_file_chooser_button_file_set_cb (GtkFileChooser *chooser, "calendars", NULL); - gtk_file_chooser_unselect_all (self->calendar_file_chooser_button); + gcal_file_chooser_button_set_file (self->calendar_file_chooser_button, NULL); GCAL_EXIT; } @@ -324,7 +326,7 @@ sources_discovered_cb (GObject *source_object, GCAL_SOURCE_DISCOVERER_ERROR_UNAUTHORIZED)) { g_debug ("Unauthorized, asking for credentials..."); - gtk_popover_popup (self->credentials_popover); + gtk_popover_popup (GTK_POPOVER (self->credentials_popover)); } else { @@ -352,7 +354,7 @@ validate_url_cb (gpointer data) self->validate_url_resource_id = 0; - uri = soup_uri_new (gtk_entry_get_text (self->calendar_address_entry)); + uri = soup_uri_new (gtk_editable_get_text (GTK_EDITABLE (self->calendar_address_entry))); if (uri != NULL && SOUP_URI_IS_VALID (uri)) { @@ -431,7 +433,7 @@ on_url_entry_text_changed_cb (GtkEntry *entry, GCAL_ENTRY; - text = gtk_entry_get_text (entry); + text = gtk_editable_get_text (GTK_EDITABLE (entry)); if (self->calendar_address_id != 0) { @@ -550,8 +552,8 @@ gcal_new_calendar_page_deactivate (GcalCalendarManagementPage *page) g_clear_pointer (&self->remote_sources, g_ptr_array_unref); update_add_button (self); - gtk_entry_set_text (self->local_calendar_name_entry, ""); - gtk_entry_set_text (self->calendar_address_entry, ""); + gtk_editable_set_text (GTK_EDITABLE (self->local_calendar_name_entry), ""); + gtk_editable_set_text (GTK_EDITABLE (self->calendar_address_entry), ""); toggle_url_entry_pulsing (self, FALSE); @@ -571,6 +573,16 @@ gcal_calendar_management_page_iface_init (GcalCalendarManagementPageInterface *i * GObject overrides */ +static void +gcal_new_calendar_page_dispose (GObject *object) +{ + GcalNewCalendarPage *self = (GcalNewCalendarPage *)object; + + g_clear_pointer (&self->credentials_popover, gtk_widget_unparent); + + G_OBJECT_CLASS (gcal_new_calendar_page_parent_class)->dispose (object); +} + static void gcal_new_calendar_page_finalize (GObject *object) { @@ -631,12 +643,15 @@ gcal_new_calendar_page_class_init (GcalNewCalendarPageClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + object_class->dispose = gcal_new_calendar_page_dispose; object_class->finalize = gcal_new_calendar_page_finalize; object_class->get_property = gcal_new_calendar_page_get_property; object_class->set_property = gcal_new_calendar_page_set_property; g_object_class_override_property (object_class, PROP_CONTEXT, "context"); + g_type_ensure (GCAL_TYPE_FILE_CHOOSER_BUTTON); + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/calendar-management/gcal-new-calendar-page.ui"); gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, add_button); @@ -659,7 +674,7 @@ gcal_new_calendar_page_class_init (GcalNewCalendarPageClass *klass) gtk_widget_class_bind_template_callback (widget_class, on_cancel_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, on_credential_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, on_credential_entry_activate_cb); - gtk_widget_class_bind_template_callback (widget_class, on_file_chooser_button_file_set_cb); + gtk_widget_class_bind_template_callback (widget_class, on_file_chooser_button_file_changed_cb); gtk_widget_class_bind_template_callback (widget_class, on_local_calendar_name_entry_text_changed_cb); gtk_widget_class_bind_template_callback (widget_class, on_local_calendar_color_button_color_changed_cb); gtk_widget_class_bind_template_callback (widget_class, on_url_entry_text_changed_cb); @@ -669,9 +684,16 @@ gcal_new_calendar_page_class_init (GcalNewCalendarPageClass *klass) static void gcal_new_calendar_page_init (GcalNewCalendarPage *self) { + GtkFileChooser *chooser; + self->cancellable = g_cancellable_new (); gtk_widget_init_template (GTK_WIDGET (self)); gtk_file_filter_set_name (self->calendar_file_filter, _("Calendar files")); + + chooser = gcal_file_chooser_button_get_filechooser (self->calendar_file_chooser_button); + gtk_file_chooser_add_filter (chooser, self->calendar_file_filter); + + gtk_widget_set_parent (self->credentials_popover, GTK_WIDGET (self->calendar_address_entry)); } diff --git a/src/gui/calendar-management/gcal-new-calendar-page.ui b/src/gui/calendar-management/gcal-new-calendar-page.ui index 955fe825..6f97c33d 100644 --- a/src/gui/calendar-management/gcal-new-calendar-page.ui +++ b/src/gui/calendar-management/gcal-new-calendar-page.ui @@ -1,182 +1,135 @@