From 997f6bb671d08d7a1df08f4a02fae0239eb4d10d Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 30 Oct 2020 22:05:23 -0300 Subject: [PATCH] event-editor-dialog: Move reminders to GcalRemindersSection Move all widgetry, logic, and setup to GcalReminderSection. --- .../event-editor/event-editor.gresource.xml | 1 + .../event-editor/gcal-event-editor-dialog.c | 303 +----------- .../event-editor/gcal-event-editor-dialog.ui | 122 +---- .../event-editor/gcal-event-editor-section.h | 2 +- src/gui/event-editor/gcal-reminders-section.c | 460 ++++++++++++++++++ src/gui/event-editor/gcal-reminders-section.h | 30 ++ .../event-editor/gcal-reminders-section.ui | 124 +++++ src/gui/event-editor/meson.build | 1 + 8 files changed, 635 insertions(+), 408 deletions(-) create mode 100644 src/gui/event-editor/gcal-reminders-section.c create mode 100644 src/gui/event-editor/gcal-reminders-section.h create mode 100644 src/gui/event-editor/gcal-reminders-section.ui diff --git a/src/gui/event-editor/event-editor.gresource.xml b/src/gui/event-editor/event-editor.gresource.xml index 9edfba49..e75b38f7 100644 --- a/src/gui/event-editor/event-editor.gresource.xml +++ b/src/gui/event-editor/event-editor.gresource.xml @@ -6,6 +6,7 @@ gcal-date-selector.ui gcal-event-editor-dialog.ui gcal-multi-choice.ui + gcal-reminders-section.ui gcal-time-selector.ui diff --git a/src/gui/event-editor/gcal-event-editor-dialog.c b/src/gui/event-editor/gcal-event-editor-dialog.c index 072bd474..76cdea89 100644 --- a/src/gui/event-editor/gcal-event-editor-dialog.c +++ b/src/gui/event-editor/gcal-event-editor-dialog.c @@ -24,10 +24,12 @@ #include "gcal-date-selector.h" #include "gcal-debug.h" #include "gcal-event-editor-dialog.h" +#include "gcal-event-editor-section.h" #include "gcal-time-selector.h" #include "gcal-utils.h" #include "gcal-event.h" #include "gcal-recurrence.h" +#include "gcal-reminders-section.h" #include #include @@ -60,6 +62,8 @@ struct _GcalEventEditorDialog GtkWidget *scrolled_window; + GcalEventEditorSection *reminders_section; + GtkWidget *lock; GtkWidget *source_image; GtkWidget *source_label; @@ -82,10 +86,6 @@ struct _GcalEventEditorDialog GtkWidget *location_entry; GtkWidget *notes_text; - GtkWidget *alarms_listbox; - GtkPopover *alarms_popover; - GtkListBoxRow *new_alarm_row; - GtkWidget *repeat_combo; GtkWidget *repeat_duration_combo; @@ -93,16 +93,6 @@ struct _GcalEventEditorDialog GtkWidget *number_of_occurrences_spin; GtkWidget *until_date_selector; - /* Add Alarms popover buttons */ - GtkWidget *five_minutes_button; - GtkWidget *ten_minutes_button; - GtkWidget *thirty_minutes_button; - GtkWidget *one_hour_button; - GtkWidget *one_day_button; - GtkWidget *two_days_button; - GtkWidget *three_days_button; - GtkWidget *one_week_button; - /* actions */ GMenu *sources_menu; GSimpleActionGroup *action_group; @@ -110,7 +100,6 @@ struct _GcalEventEditorDialog /* new data holders */ GcalEvent *event; GcalCalendar *selected_calendar; - GPtrArray *alarms; /* flags */ gboolean event_is_new; @@ -130,9 +119,6 @@ static void on_location_entry_changed_cb (GtkEntry GParamSpec *pspec, GcalEventEditorDialog *self); -static void on_add_alarm_button_clicked_cb (GtkWidget *button, - GcalEventEditorDialog *self); - G_DEFINE_TYPE (GcalEventEditorDialog, gcal_event_editor_dialog, GTK_TYPE_DIALOG) enum @@ -583,78 +569,6 @@ gcal_event_editor_dialog_clear_data (GcalEventEditorDialog *self) gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->notes_text)), "", -1); } -#define OFFSET(x) (G_STRUCT_OFFSET (GcalEventEditorDialog, x)) -#define WIDGET_FROM_OFFSET(x) (G_STRUCT_MEMBER (GtkWidget*, self, x)) - -struct -{ - gint minutes; - gint button_offset; -} minutes_button[] = { - { 5, OFFSET (five_minutes_button) }, - { 10, OFFSET (ten_minutes_button) }, - { 30, OFFSET (thirty_minutes_button) }, - { 60, OFFSET (one_hour_button) }, - { 1440, OFFSET (one_day_button) }, - { 2880, OFFSET (two_days_button) }, - { 4320, OFFSET (three_days_button) }, - { 10080, OFFSET (one_week_button) } -}; - -static GtkWidget* -get_row_for_alarm_trigger_minutes (GcalEventEditorDialog *self, - gint minutes) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (minutes_button); i++) - { - if (minutes_button[i].minutes == minutes) - return WIDGET_FROM_OFFSET (minutes_button[i].button_offset); - } - - return NULL; -} - -static ECalComponentAlarm* -create_alarm (guint minutes) -{ - - ECalComponentAlarmTrigger *trigger; - ECalComponentAlarm *alarm; - ICalDuration *duration; - - duration = i_cal_duration_new_null_duration (); - i_cal_duration_set_is_neg (duration, TRUE); - i_cal_duration_set_minutes (duration, minutes); - - trigger = e_cal_component_alarm_trigger_new_relative (E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START, duration); - - g_clear_object (&duration); - - alarm = e_cal_component_alarm_new (); - e_cal_component_alarm_take_trigger (alarm, trigger); - e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_DISPLAY); - - return alarm; -} - -static void -clear_alarms (GcalEventEditorDialog *self) -{ - g_autoptr (GList) children = NULL; - GList *l; - - g_ptr_array_set_size (self->alarms, 0); - - children = gtk_container_get_children (GTK_CONTAINER (self->alarms_listbox)); - for (l = children; l != NULL; l = l->next) - { - if (l->data != self->new_alarm_row) - gtk_widget_destroy (l->data); - } -} - static void apply_changes_to_event (GcalEventEditorDialog *self) { @@ -664,7 +578,6 @@ apply_changes_to_event (GcalEventEditorDialog *self) gboolean was_all_day; gboolean all_day; gchar *note_text; - gsize i; /* Update summary */ gcal_event_set_summary (self->event, gtk_entry_get_text (GTK_ENTRY (self->summary_entry))); @@ -739,12 +652,7 @@ apply_changes_to_event (GcalEventEditorDialog *self) g_clear_pointer (&end_date, g_date_time_unref); /* Update alarms */ - gcal_event_remove_all_alarms (self->event); - - for (i = 0; i < self->alarms->len; i++) - gcal_event_add_alarm (self->event, g_ptr_array_index (self->alarms, i)); - - clear_alarms (self); + gcal_event_editor_section_apply (self->reminders_section); /* Check Repeat popover and set recurrence-rules accordingly */ old_recur = gcal_event_get_recurrence (self->event); @@ -871,33 +779,6 @@ on_summary_entry_changed_cb (GtkEntry *entry, gtk_widget_set_sensitive (self->done_button, gtk_entry_get_text_length (entry) > 0); } -static gint -sort_alarms_func (GtkListBoxRow *a, - GtkListBoxRow *b, - gpointer user_data) -{ - ECalComponentAlarm *alarm_a; - ECalComponentAlarm *alarm_b; - GcalEventEditorDialog *self; - gint minutes_a; - gint minutes_b; - - self = GCAL_EVENT_EDITOR_DIALOG (user_data); - - if (a == self->new_alarm_row) - return 1; - else if (b == self->new_alarm_row) - return -1; - - alarm_a = gcal_alarm_row_get_alarm (GCAL_ALARM_ROW (a)); - minutes_a = get_alarm_trigger_minutes (self->event, alarm_a); - - alarm_b = gcal_alarm_row_get_alarm (GCAL_ALARM_ROW (b)); - minutes_b = get_alarm_trigger_minutes (self->event, alarm_b); - - return minutes_a - minutes_b; -} - static void fix_reminders_label_height_cb (GtkWidget *summary_label, GdkRectangle *allocation, @@ -995,45 +876,6 @@ on_all_day_switch_active_changed_cb (GtkSwitch *all_day_switch, update_date_labels (self); } -static void -on_remove_alarm_cb (GcalAlarmRow *alarm_row, - GcalEventEditorDialog *self) -{ - ECalComponentAlarm *alarm; - GtkWidget *alarm_button; - gint trigger_minutes; - gsize i; - - GCAL_ENTRY; - - alarm = gcal_alarm_row_get_alarm (alarm_row); - trigger_minutes = get_alarm_trigger_minutes (self->event, alarm); - - /* Make the button sensitive again */ - alarm_button = get_row_for_alarm_trigger_minutes (self, trigger_minutes); - - if (alarm_button) - gtk_widget_set_sensitive (alarm_button, TRUE); - - /* Remove from the array */ - for (i = 0; i < self->alarms->len; i++) - { - ECalComponentAlarm *a = g_ptr_array_index (self->alarms, i); - - if (trigger_minutes == get_alarm_trigger_minutes (self->event, a)) - { - GCAL_TRACE_MSG ("Removed alarm for %d minutes", trigger_minutes); - - g_ptr_array_remove_index (self->alarms, i); - break; - } - } - - gtk_container_remove (GTK_CONTAINER (self->alarms_listbox), GTK_WIDGET (alarm_row)); - - GCAL_EXIT; -} - static void on_time_format_changed_cb (GcalEventEditorDialog *self) { @@ -1045,107 +887,6 @@ on_time_format_changed_cb (GcalEventEditorDialog *self) gcal_time_selector_set_time_format (GCAL_TIME_SELECTOR (self->end_time_selector), time_format); } -static GtkWidget * -create_alarm_row (GcalEventEditorDialog *self, - ECalComponentAlarm *alarm) -{ - GtkWidget *row; - - row = gcal_alarm_row_new (alarm); - g_signal_connect_object (row, "remove-alarm", G_CALLBACK (on_remove_alarm_cb), self, 0); - - return row; -} - -static void -setup_alarms (GcalEventEditorDialog *self) -{ - g_autoptr (GList) alarms = NULL; - GList *l; - gsize i; - - GCAL_ENTRY; - - clear_alarms (self); - - /* We start by making all alarm buttons sensitive, and only make them insensitive when needed */ - for (i = 0; i < G_N_ELEMENTS (minutes_button); i++) - gtk_widget_set_sensitive (WIDGET_FROM_OFFSET (minutes_button[i].button_offset), TRUE); - - alarms = gcal_event_get_alarms (self->event); - for (l = alarms; l != NULL; l = l->next) - g_ptr_array_add (self->alarms, l->data); - - for (i = 0; i < self->alarms->len; i++) - { - ECalComponentAlarm *alarm; - GtkWidget *row; - gint minutes; - guint j; - - alarm = g_ptr_array_index (self->alarms, i); - - /* Make already-added alarm buttons insensitive */ - minutes = get_alarm_trigger_minutes (self->event, alarm); - - for (j = 0; j < G_N_ELEMENTS (minutes_button); j++) - { - if (minutes_button[i].minutes == minutes) - gtk_widget_set_sensitive (WIDGET_FROM_OFFSET (minutes_button[j].button_offset), FALSE); - } - - GCAL_TRACE_MSG ("Adding alarm for %u minutes", minutes); - - /* Add the row */ - row = create_alarm_row (self, alarm); - gtk_container_add (GTK_CONTAINER (self->alarms_listbox), row); - } - - GCAL_EXIT; -} - -static void -on_add_alarm_button_clicked_cb (GtkWidget *button, - GcalEventEditorDialog *self) -{ - ECalComponentAlarm *alarm; - GtkWidget *row; - guint i, minutes; - - /* Search for the button minute */ - minutes = 0; - - for (i = 0; i < G_N_ELEMENTS (minutes_button); i++) - { - if (WIDGET_FROM_OFFSET (minutes_button[i].button_offset) == button) - { - minutes = minutes_button[i].minutes; - break; - } - } - - if (minutes == 0) - return; - - alarm = create_alarm (minutes); - - row = create_alarm_row (self, alarm); - gtk_container_add (GTK_CONTAINER (self->alarms_listbox), row); - - g_ptr_array_add (self->alarms, alarm); - - gtk_widget_set_sensitive (button, FALSE); -} - -static void -on_alarms_listbox_row_activated_cb (GtkListBox *alarms_listbox, - GtkListBoxRow *row, - GcalEventEditorDialog *self) -{ - if (row == self->new_alarm_row) - gtk_popover_popup (self->alarms_popover); -} - /* * Gobject overrides @@ -1160,7 +901,6 @@ gcal_event_editor_dialog_finalize (GObject *object) self = GCAL_EVENT_EDITOR_DIALOG (object); - g_clear_pointer (&self->alarms, g_ptr_array_unref); g_clear_object (&self->action_group); g_clear_object (&self->context); g_clear_object (&self->event); @@ -1273,6 +1013,7 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); g_type_ensure (GCAL_TYPE_DATE_SELECTOR); + g_type_ensure (GCAL_TYPE_REMINDERS_SECTION); g_type_ensure (GCAL_TYPE_TIME_SELECTOR); object_class->finalize = gcal_event_editor_dialog_finalize; @@ -1317,17 +1058,6 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/event-editor/gcal-event-editor-dialog.ui"); - /* Alarms */ - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, five_minutes_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, ten_minutes_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, thirty_minutes_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, one_hour_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, one_day_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, two_days_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, three_days_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, one_week_button); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, alarms_popover); - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, new_alarm_row); /* Buttons */ gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, done_button); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, cancel_button); @@ -1343,7 +1073,6 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass) gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, event_start_label); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, event_end_label); /* Other */ - gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, alarms_listbox); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, notes_text); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, all_day_switch); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, titlebar); @@ -1357,14 +1086,13 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass) gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, source_image); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, sources_popover); gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, until_date_selector); + gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, reminders_section); /* callbacks */ gtk_widget_class_bind_template_callback (widget_class, fix_reminders_label_height_cb); gtk_widget_class_bind_template_callback (widget_class, sync_datetimes); gtk_widget_class_bind_template_callback (widget_class, on_action_button_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, on_add_alarm_button_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, on_alarms_listbox_row_activated_cb); gtk_widget_class_bind_template_callback (widget_class, on_all_day_switch_active_changed_cb); gtk_widget_class_bind_template_callback (widget_class, on_repeat_duration_changed_cb); gtk_widget_class_bind_template_callback (widget_class, on_repeat_type_changed_cb); @@ -1375,15 +1103,11 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass) static void gcal_event_editor_dialog_init (GcalEventEditorDialog *self) { - self->alarms = g_ptr_array_new_with_free_func (e_cal_component_alarm_free); self->writable = TRUE; gtk_widget_init_template (GTK_WIDGET (self)); - gtk_list_box_set_sort_func (GTK_LIST_BOX (self->alarms_listbox), - sort_alarms_func, - self, - NULL); + g_object_bind_property (self, "context", self->reminders_section, "context", G_BINDING_DEFAULT); } /** @@ -1445,6 +1169,7 @@ gcal_event_editor_dialog_set_event (GcalEventEditorDialog *self, GcalEvent *event) { g_autoptr (GcalEvent) cloned_event = NULL; + GcalEventEditorFlags flags; GcalRecurrenceLimitType limit_type; GcalRecurrenceFrequency frequency; GcalRecurrence *recur; @@ -1591,10 +1316,14 @@ gcal_event_editor_dialog_set_event (GcalEventEditorDialog *self, g_clear_pointer (&date_start, g_date_time_unref); g_clear_pointer (&date_end, g_date_time_unref); - /* Setup the alarms */ - setup_alarms (self); - out: + flags = GCAL_EVENT_EDITOR_FLAG_NONE; + + if (self->event_is_new) + flags |= GCAL_EVENT_EDITOR_FLAG_NEW_EVENT; + + gcal_event_editor_section_set_event (self->reminders_section, cloned_event, flags); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EVENT]); self->setting_event = FALSE; diff --git a/src/gui/event-editor/gcal-event-editor-dialog.ui b/src/gui/event-editor/gcal-event-editor-dialog.ui index f0680985..ecea5fbd 100644 --- a/src/gui/event-editor/gcal-event-editor-dialog.ui +++ b/src/gui/event-editor/gcal-event-editor-dialog.ui @@ -444,43 +444,9 @@ - + True - vertical - - - - - - True - False - none - - - - - - True - - - - - True - True - True - 12 - Add a Reminder… - - - - - - - - - + @@ -555,90 +521,6 @@ - - False - 175 - new_alarm_row - - - True - False - 12 - vertical - - - True - True - True - 5 minutes - - - - - - True - True - True - 10 minutes - - - - - - True - True - True - 30 minutes - - - - - - True - True - True - 1 hour - - - - - - True - True - 1 day - - - - - - True - True - True - 2 days - - - - - - True - True - True - 3 days - - - - - - True - True - True - 1 week - - - - - - vertical diff --git a/src/gui/event-editor/gcal-event-editor-section.h b/src/gui/event-editor/gcal-event-editor-section.h index fc2b5ed3..bf34aafa 100644 --- a/src/gui/event-editor/gcal-event-editor-section.h +++ b/src/gui/event-editor/gcal-event-editor-section.h @@ -28,7 +28,7 @@ G_BEGIN_DECLS #define GCAL_TYPE_EVENT_EDITOR_SECTION (gcal_event_editor_section_get_type ()) -G_DECLARE_INTERFACE (GcalEventEditorSection, gcal_event_editor_section, GCAL, EVENT_EDITOR_SECTION, GtkWidget) +G_DECLARE_INTERFACE (GcalEventEditorSection, gcal_event_editor_section, GCAL, EVENT_EDITOR_SECTION, GtkBox) typedef enum { diff --git a/src/gui/event-editor/gcal-reminders-section.c b/src/gui/event-editor/gcal-reminders-section.c new file mode 100644 index 00000000..a40b9327 --- /dev/null +++ b/src/gui/event-editor/gcal-reminders-section.c @@ -0,0 +1,460 @@ +/* gcal-reminders-section.c + * + * Copyright 2020 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 + */ + +#define G_LOG_DOMAIN "GcalRemindersSection" + +#include "gcal-alarm-row.h" +#include "gcal-debug.h" +#include "gcal-event-editor-section.h" +#include "gcal-reminders-section.h" +#include "gcal-utils.h" + +#include + +struct _GcalRemindersSection +{ + GtkBox parent; + + GtkListBox *alarms_listbox; + GtkPopover *alarms_popover; + GtkListBoxRow *new_alarm_row; + + GtkWidget *five_minutes_button; + GtkWidget *ten_minutes_button; + GtkWidget *thirty_minutes_button; + GtkWidget *one_hour_button; + GtkWidget *one_day_button; + GtkWidget *two_days_button; + GtkWidget *three_days_button; + GtkWidget *one_week_button; + + GcalContext *context; + GcalEvent *event; + GPtrArray *alarms; +}; + + +static void gcal_event_editor_section_iface_init (GcalEventEditorSectionInterface *iface); + +static void on_remove_alarm_cb (GcalAlarmRow *alarm_row, + GcalRemindersSection *self); + + +G_DEFINE_TYPE_WITH_CODE (GcalRemindersSection, gcal_reminders_section, GTK_TYPE_BOX, + G_IMPLEMENT_INTERFACE (GCAL_TYPE_EVENT_EDITOR_SECTION, gcal_event_editor_section_iface_init)) + +enum +{ + PROP_0, + PROP_CONTEXT, + N_PROPS +}; + +/* + * Auxiliary methods + */ + +#define OFFSET(x) (G_STRUCT_OFFSET (GcalRemindersSection, x)) +#define WIDGET_FROM_OFFSET(x) (G_STRUCT_MEMBER (GtkWidget*, self, x)) + +struct +{ + gint minutes; + gint button_offset; +} minutes_button[] = { + { 5, OFFSET (five_minutes_button) }, + { 10, OFFSET (ten_minutes_button) }, + { 30, OFFSET (thirty_minutes_button) }, + { 60, OFFSET (one_hour_button) }, + { 1440, OFFSET (one_day_button) }, + { 2880, OFFSET (two_days_button) }, + { 4320, OFFSET (three_days_button) }, + { 10080, OFFSET (one_week_button) } +}; + +static GtkWidget* +get_row_for_alarm_trigger_minutes (GcalRemindersSection *self, + gint minutes) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (minutes_button); i++) + { + if (minutes_button[i].minutes == minutes) + return WIDGET_FROM_OFFSET (minutes_button[i].button_offset); + } + + return NULL; +} + +static ECalComponentAlarm* +create_alarm (guint minutes) +{ + + ECalComponentAlarmTrigger *trigger; + ECalComponentAlarm *alarm; + ICalDuration *duration; + + duration = i_cal_duration_new_null_duration (); + i_cal_duration_set_is_neg (duration, TRUE); + i_cal_duration_set_minutes (duration, minutes); + + trigger = e_cal_component_alarm_trigger_new_relative (E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START, duration); + + g_clear_object (&duration); + + alarm = e_cal_component_alarm_new (); + e_cal_component_alarm_take_trigger (alarm, trigger); + e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_DISPLAY); + + return alarm; +} + +static void +clear_alarms (GcalRemindersSection *self) +{ + g_autoptr (GList) children = NULL; + GList *l; + + g_ptr_array_set_size (self->alarms, 0); + + children = gtk_container_get_children (GTK_CONTAINER (self->alarms_listbox)); + for (l = children; l != NULL; l = l->next) + { + if (l->data != self->new_alarm_row) + gtk_widget_destroy (l->data); + } +} + +static GtkWidget * +create_alarm_row (GcalRemindersSection *self, + ECalComponentAlarm *alarm) +{ + GtkWidget *row; + + row = gcal_alarm_row_new (alarm); + g_signal_connect_object (row, "remove-alarm", G_CALLBACK (on_remove_alarm_cb), self, 0); + + return row; +} + +static void +setup_alarms (GcalRemindersSection *self) +{ + g_autoptr (GList) alarms = NULL; + GList *l; + gsize i; + + GCAL_ENTRY; + + clear_alarms (self); + + if (!self->event) + GCAL_RETURN (); + + /* We start by making all alarm buttons sensitive, and only make them insensitive when needed */ + for (i = 0; i < G_N_ELEMENTS (minutes_button); i++) + gtk_widget_set_sensitive (WIDGET_FROM_OFFSET (minutes_button[i].button_offset), TRUE); + + alarms = gcal_event_get_alarms (self->event); + for (l = alarms; l != NULL; l = l->next) + g_ptr_array_add (self->alarms, l->data); + + for (i = 0; i < self->alarms->len; i++) + { + ECalComponentAlarm *alarm; + GtkWidget *row; + gint minutes; + guint j; + + alarm = g_ptr_array_index (self->alarms, i); + + /* Make already-added alarm buttons insensitive */ + minutes = get_alarm_trigger_minutes (self->event, alarm); + + for (j = 0; j < G_N_ELEMENTS (minutes_button); j++) + { + if (minutes_button[i].minutes == minutes) + gtk_widget_set_sensitive (WIDGET_FROM_OFFSET (minutes_button[j].button_offset), FALSE); + } + + GCAL_TRACE_MSG ("Adding alarm for %u minutes", minutes); + + /* Add the row */ + row = create_alarm_row (self, alarm); + gtk_container_add (GTK_CONTAINER (self->alarms_listbox), row); + } + + GCAL_EXIT; +} + + +/* + * Callbacks + */ + +static gint +sort_alarms_func (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer user_data) +{ + ECalComponentAlarm *alarm_a; + ECalComponentAlarm *alarm_b; + GcalRemindersSection *self; + gint minutes_a; + gint minutes_b; + + self = GCAL_REMINDERS_SECTION (user_data); + + if (a == self->new_alarm_row) + return 1; + else if (b == self->new_alarm_row) + return -1; + + alarm_a = gcal_alarm_row_get_alarm (GCAL_ALARM_ROW (a)); + minutes_a = get_alarm_trigger_minutes (self->event, alarm_a); + + alarm_b = gcal_alarm_row_get_alarm (GCAL_ALARM_ROW (b)); + minutes_b = get_alarm_trigger_minutes (self->event, alarm_b); + + return minutes_a - minutes_b; +} + +static void +on_remove_alarm_cb (GcalAlarmRow *alarm_row, + GcalRemindersSection *self) +{ + ECalComponentAlarm *alarm; + GtkWidget *alarm_button; + gint trigger_minutes; + gsize i; + + GCAL_ENTRY; + + alarm = gcal_alarm_row_get_alarm (alarm_row); + trigger_minutes = get_alarm_trigger_minutes (self->event, alarm); + + /* Make the button sensitive again */ + alarm_button = get_row_for_alarm_trigger_minutes (self, trigger_minutes); + + if (alarm_button) + gtk_widget_set_sensitive (alarm_button, TRUE); + + /* Remove from the array */ + for (i = 0; i < self->alarms->len; i++) + { + ECalComponentAlarm *a = g_ptr_array_index (self->alarms, i); + + if (trigger_minutes == get_alarm_trigger_minutes (self->event, a)) + { + GCAL_TRACE_MSG ("Removed alarm for %d minutes", trigger_minutes); + + g_ptr_array_remove_index (self->alarms, i); + break; + } + } + + gtk_container_remove (GTK_CONTAINER (self->alarms_listbox), GTK_WIDGET (alarm_row)); + + GCAL_EXIT; +} + +static void +on_add_alarm_button_clicked_cb (GtkWidget *button, + GcalRemindersSection *self) +{ + ECalComponentAlarm *alarm; + GtkWidget *row; + guint i, minutes; + + /* Search for the button minute */ + minutes = 0; + + for (i = 0; i < G_N_ELEMENTS (minutes_button); i++) + { + if (WIDGET_FROM_OFFSET (minutes_button[i].button_offset) == button) + { + minutes = minutes_button[i].minutes; + break; + } + } + + if (minutes == 0) + return; + + alarm = create_alarm (minutes); + + row = create_alarm_row (self, alarm); + gtk_container_add (GTK_CONTAINER (self->alarms_listbox), row); + + g_ptr_array_add (self->alarms, alarm); + + gtk_widget_set_sensitive (button, FALSE); +} + +static void +on_alarms_listbox_row_activated_cb (GtkListBox *alarms_listbox, + GtkListBoxRow *row, + GcalRemindersSection *self) +{ + if (row == self->new_alarm_row) + gtk_popover_popup (self->alarms_popover); +} + + +/* + * GcalEventEditorSection interface + */ + +static void +gcal_reminders_section_set_event (GcalEventEditorSection *section, + GcalEvent *event, + GcalEventEditorFlags flags) +{ + GcalRemindersSection *self = GCAL_REMINDERS_SECTION (section); + + GCAL_ENTRY; + + g_set_object (&self->event, event); + setup_alarms (self); + + GCAL_EXIT; +} + +static void +gcal_reminders_section_apply (GcalEventEditorSection *section) +{ + GcalRemindersSection *self = GCAL_REMINDERS_SECTION (section); + gint i; + + GCAL_ENTRY; + + gcal_event_remove_all_alarms (self->event); + + for (i = 0; i < self->alarms->len; i++) + gcal_event_add_alarm (self->event, g_ptr_array_index (self->alarms, i)); + + clear_alarms (self); + + GCAL_EXIT; +} + +static void +gcal_event_editor_section_iface_init (GcalEventEditorSectionInterface *iface) +{ + iface->set_event = gcal_reminders_section_set_event; + iface->apply = gcal_reminders_section_apply; +} + + +/* + * GObject overrides + */ + +static void +gcal_reminders_section_finalize (GObject *object) +{ + GcalRemindersSection *self = (GcalRemindersSection *)object; + + g_clear_pointer (&self->alarms, g_ptr_array_unref); + g_clear_object (&self->context); + g_clear_object (&self->event); + + G_OBJECT_CLASS (gcal_reminders_section_parent_class)->finalize (object); +} + +static void +gcal_reminders_section_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GcalRemindersSection *self = GCAL_REMINDERS_SECTION (object); + + switch (prop_id) + { + case PROP_CONTEXT: + g_value_set_object (value, self->context); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_reminders_section_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GcalRemindersSection *self = GCAL_REMINDERS_SECTION (object); + + switch (prop_id) + { + case PROP_CONTEXT: + g_assert (self->context == NULL); + self->context = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_reminders_section_class_init (GcalRemindersSectionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = gcal_reminders_section_finalize; + object_class->get_property = gcal_reminders_section_get_property; + object_class->set_property = gcal_reminders_section_set_property; + + g_object_class_override_property (object_class, PROP_CONTEXT, "context"); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/event-editor/gcal-reminders-section.ui"); + + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, alarms_listbox); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, alarms_popover); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, five_minutes_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, new_alarm_row); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, one_day_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, one_hour_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, one_week_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, ten_minutes_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, thirty_minutes_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, three_days_button); + gtk_widget_class_bind_template_child (widget_class, GcalRemindersSection, two_days_button); + + gtk_widget_class_bind_template_callback (widget_class, on_add_alarm_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, on_alarms_listbox_row_activated_cb); +} + +static void +gcal_reminders_section_init (GcalRemindersSection *self) +{ + self->alarms = g_ptr_array_new_with_free_func (e_cal_component_alarm_free); + + gtk_widget_init_template (GTK_WIDGET (self)); + + gtk_list_box_set_sort_func (self->alarms_listbox, sort_alarms_func, self, NULL); +} diff --git a/src/gui/event-editor/gcal-reminders-section.h b/src/gui/event-editor/gcal-reminders-section.h new file mode 100644 index 00000000..202a8c08 --- /dev/null +++ b/src/gui/event-editor/gcal-reminders-section.h @@ -0,0 +1,30 @@ +/* gcal-reminders-section.h + * + * Copyright 2020 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_REMINDERS_SECTION (gcal_reminders_section_get_type()) +G_DECLARE_FINAL_TYPE (GcalRemindersSection, gcal_reminders_section, GCAL, REMINDERS_SECTION, GtkBox) + +G_END_DECLS diff --git a/src/gui/event-editor/gcal-reminders-section.ui b/src/gui/event-editor/gcal-reminders-section.ui new file mode 100644 index 00000000..3de43583 --- /dev/null +++ b/src/gui/event-editor/gcal-reminders-section.ui @@ -0,0 +1,124 @@ + + + + + + False + 175 + new_alarm_row + + + True + False + 12 + vertical + + + True + True + True + 5 minutes + + + + + + True + True + True + 10 minutes + + + + + + True + True + True + 30 minutes + + + + + + True + True + True + 1 hour + + + + + + True + True + 1 day + + + + + + True + True + True + 2 days + + + + + + True + True + True + 3 days + + + + + + True + True + True + 1 week + + + + + + + diff --git a/src/gui/event-editor/meson.build b/src/gui/event-editor/meson.build index 2c9f717e..698a136e 100644 --- a/src/gui/event-editor/meson.build +++ b/src/gui/event-editor/meson.build @@ -14,5 +14,6 @@ sources += files( 'gcal-event-editor-dialog.c', 'gcal-event-editor-section.c', 'gcal-multi-choice.c', + 'gcal-reminders-section.c', 'gcal-time-selector.c', )