diff --git a/po/POTFILES.in b/po/POTFILES.in index 3a9d9fc5..b4279a49 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -21,6 +21,8 @@ src/gui/event-editor/gcal-attendee-row.blp src/gui/event-editor/gcal-attendee-row.c src/gui/event-editor/gcal-attendee-details-page.blp src/gui/event-editor/gcal-attendee-details-page.c +src/gui/event-editor/gcal-attendee-summary-row.blp +src/gui/event-editor/gcal-attendee-summary-row.c src/gui/event-editor/gcal-attendees-section.blp src/gui/event-editor/gcal-attendees-section.c src/gui/event-editor/gcal-date-chooser-row.blp diff --git a/src/gui/event-editor/event-editor.gresource.xml b/src/gui/event-editor/event-editor.gresource.xml index 92ed8298..c933afd3 100644 --- a/src/gui/event-editor/event-editor.gresource.xml +++ b/src/gui/event-editor/event-editor.gresource.xml @@ -16,5 +16,6 @@ gcal-attendees-section.ui gcal-attendee-row.ui gcal-attendee-details-page.ui + gcal-attendee-summary-row.ui diff --git a/src/gui/event-editor/gcal-attendee-details-page.c b/src/gui/event-editor/gcal-attendee-details-page.c index 82efcbee..b55cad06 100644 --- a/src/gui/event-editor/gcal-attendee-details-page.c +++ b/src/gui/event-editor/gcal-attendee-details-page.c @@ -415,6 +415,15 @@ gcal_attendee_details_page_set_attendees (GcalAttendeeDetailsPage *self, } } +/** + * gcal_attendee_details_page_set_type_filter: + * @self: a #GcalAttendeeDetailsPage instance. + * @flags: flags of type #GcalEventAttendeeTypeFilterFlags. + * + * Sets the type of attendees to use as the base filter on the + * list of attendees. E.g. only people or only resources, or both + * are filtered before grouping by response is performed. + */ void gcal_attendee_details_page_set_type_filter (GcalAttendeeDetailsPage *self, GcalEventAttendeeTypeFilterFlags flags) diff --git a/src/gui/event-editor/gcal-attendee-summary-row.blp b/src/gui/event-editor/gcal-attendee-summary-row.blp new file mode 100644 index 00000000..6cf83504 --- /dev/null +++ b/src/gui/event-editor/gcal-attendee-summary-row.blp @@ -0,0 +1,26 @@ +using Gtk 4.0; +using Adw 1; + +template $GcalAttendeeSummaryRow: Adw.ActionRow { + visible: bind template.filtered-list as .n-items; + activatable-widget: open_details; + + styles [ + "property", + ] + + [suffix] + Label { + valign: center; + label: bind template.filtered-list as .n-items; + + styles [ + "participants-count-label", + ] + } + + [suffix] + Image open_details { + icon-name: "go-next-symbolic"; + } +} diff --git a/src/gui/event-editor/gcal-attendee-summary-row.c b/src/gui/event-editor/gcal-attendee-summary-row.c new file mode 100644 index 00000000..a4554c27 --- /dev/null +++ b/src/gui/event-editor/gcal-attendee-summary-row.c @@ -0,0 +1,359 @@ +/* gcal-attendee-summary-row.c + * + * Copyright (C) 2025 Alen Galinec + * + * 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 . + */ + +#include "gcal-attendee-summary-row.h" +#include "gcal-enum-types.h" +#include "gcal-enums.h" +#include "gcal-event-attendee.h" +#include "gio/gio.h" +#include "glib.h" + +#include +#include +#include +#include + +struct _GcalAttendeeSummaryRow +{ + AdwActionRow parent_instance; + + GListStore *attendees; + GtkFilterListModel *filtered_attendees; + GtkCustomFilter *attendee_filter; + + /* participation summary */ + guint num_accepted; + guint num_declined; + guint num_tentative; + guint num_not_responded; + guint num_delegated; + + GcalEventAttendeeTypeFilterFlags filter_flags; +}; + +G_DEFINE_FINAL_TYPE (GcalAttendeeSummaryRow, gcal_attendee_summary_row, ADW_TYPE_ACTION_ROW) + +enum +{ + PROP_ATTENDEES = 1, + PROP_FILTER_FLAGS, + PROP_FILTERED_LIST, + PROP_NUM_ACCEPTED, + PROP_NUM_DECLINED, + PROP_NUM_TENTATIVE, + PROP_NUM_DELEGATED, + PROP_NUM_UNKNOWN, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +/* Auxiliary methods */ + +static void +notify_summary_changed (GcalAttendeeSummaryRow *self) +{ + for (guint i = 1; i < N_PROPS; ++i) + g_object_notify_by_pspec (G_OBJECT (self), properties[i]); +} + +static gboolean +custom_filter_func (GcalEventAttendee *attendee, + GcalAttendeeSummaryRow *self) +{ + GcalEventAttendeeType attendee_type = gcal_event_attendee_get_attendee_type (attendee); + + switch (self->filter_flags) + { + case GCAL_EVENT_ATTENDEE_TYPE_FILTER_PERSON: + return attendee_type == GCAL_EVENT_ATTENDEE_TYPE_INDIVIDUAL || attendee_type == GCAL_EVENT_ATTENDEE_TYPE_GROUP; + + case GCAL_EVENT_ATTENDEE_TYPE_FILTER_RESOURCE: + return attendee_type == GCAL_EVENT_ATTENDEE_TYPE_ROOM || attendee_type == GCAL_EVENT_ATTENDEE_TYPE_RESOURCE; + + default: + return TRUE; + } +} + +static inline void +concat_subtitle_part (GStrvBuilder *builder, + guint value, + const gchar *text) +{ + if (value <= 0) + return; + + g_strv_builder_take (builder, g_strdup_printf ("%d %s", value, text)); +} + +static const gchar* +build_summary_subtitle (GcalAttendeeSummaryRow *self) +{ + g_autoptr (GStrvBuilder) builder = g_strv_builder_new (); + g_auto (GStrv) parts = NULL; + + concat_subtitle_part (builder, self->num_accepted, ngettext ("accepted", "accepted", self->num_accepted)); + concat_subtitle_part (builder, self->num_tentative, ngettext ("maybe", "maybe", self->num_tentative)); + concat_subtitle_part (builder, self->num_declined, ngettext ("declined", "declined", self->num_declined)); + concat_subtitle_part (builder, self->num_delegated, ngettext ("delegated", "delegated", self->num_delegated)); + concat_subtitle_part (builder, self->num_not_responded, ngettext ("not responded", "not responded", self->num_not_responded)); + + parts = g_strv_builder_end (builder); + + return g_strjoinv (", ", parts); +} + +static void +setup_filtered_attendees (GcalAttendeeSummaryRow *self, + GListModel *attendees) +{ + g_return_if_fail (GCAL_IS_ATTENDEE_SUMMARY_ROW (self)); + + g_list_store_remove_all (self->attendees); + self->num_accepted = 0; + self->num_declined = 0; + self->num_delegated = 0; + self->num_tentative = 0; + self->num_not_responded = 0; + + if (attendees == NULL) + return; + + guint n = g_list_model_get_n_items (attendees); + for (uint i = 0; i < n; ++i) + { + GcalEventAttendee *attendee = g_list_model_get_item (attendees, i); + g_list_store_append (self->attendees, attendee); + + /* this should be faster than going through self->filtered_attendees afterwards */ + if (!custom_filter_func (attendee, self)) + continue; + + switch (gcal_event_attendee_get_part_status (attendee)) + { + case GCAL_EVENT_ATTENDEE_PART_ACCEPTED: + self->num_accepted++; + break; + case GCAL_EVENT_ATTENDEE_PART_DECLINED: + self->num_declined++; + break; + case GCAL_EVENT_ATTENDEE_PART_DELEGATED: + self->num_delegated++; + break; + case GCAL_EVENT_ATTENDEE_PART_TENTATIVE: + self->num_tentative++; + break; + default: + self->num_not_responded++; + } + } + + g_autofree const gchar *subtitle = build_summary_subtitle (self); + adw_action_row_set_subtitle (ADW_ACTION_ROW (self), subtitle); + + notify_summary_changed (self); +} + +static void +change_attendee_filter_type (GcalAttendeeSummaryRow *self, + GcalEventAttendeeTypeFilterFlags value) +{ + self->filter_flags = value; + gtk_filter_changed (GTK_FILTER (self->attendee_filter), GTK_FILTER_CHANGE_DIFFERENT); + gtk_actionable_set_action_target (GTK_ACTIONABLE (self), "u", self->filter_flags); +} + +static void +gcal_attendee_summary_row_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GcalAttendeeSummaryRow *self = GCAL_ATTENDEE_SUMMARY_ROW (object); + + switch (property_id) + { + case PROP_ATTENDEES: + setup_filtered_attendees (self, g_value_get_object (value)); + break; + case PROP_FILTER_FLAGS: + change_attendee_filter_type (self, g_value_get_flags (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gcal_attendee_summary_row_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GcalAttendeeSummaryRow *self = GCAL_ATTENDEE_SUMMARY_ROW (object); + + switch (property_id) + { + case PROP_FILTER_FLAGS: + g_value_set_flags (value, self->filter_flags); + break; + case PROP_FILTERED_LIST: + g_value_set_object (value, self->filtered_attendees); + break; + case PROP_NUM_ACCEPTED: + g_value_set_uint (value, self->num_accepted); + break; + case PROP_NUM_DECLINED: + g_value_set_uint (value, self->num_declined); + break; + case PROP_NUM_DELEGATED: + g_value_set_uint (value, self->num_delegated); + break; + case PROP_NUM_TENTATIVE: + g_value_set_uint (value, self->num_tentative); + break; + case PROP_NUM_UNKNOWN: + g_value_set_uint (value, self->num_not_responded); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gcal_attendee_summary_row_finalize (GObject *object) +{ + GcalAttendeeSummaryRow *self = (GcalAttendeeSummaryRow *) object; + + g_clear_pointer (&self->attendees, g_list_store_remove_all); + g_clear_object (&self->attendee_filter); + + self->filtered_attendees = NULL; + + G_OBJECT_CLASS (gcal_attendee_summary_row_parent_class)->finalize (object); +} + +static void +gcal_attendee_summary_row_class_init (GcalAttendeeSummaryRowClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gcal_attendee_summary_row_finalize; + object_class->set_property = gcal_attendee_summary_row_set_property; + object_class->get_property = gcal_attendee_summary_row_get_property; + + /** + * GcalAttendeeSummaryRow:attendees: + * + * The unfiltered list of attendees. + */ + properties[PROP_ATTENDEES] = + g_param_spec_object ("attendees", NULL, NULL, + G_TYPE_LIST_MODEL, + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:filter-flags: + * + * The GCAL_TYPE_EVENT_ATTENDEE_TYPE_FILTER_FLAGS used to filter the attendees. + */ + properties[PROP_FILTER_FLAGS] = + g_param_spec_flags ("filter-flags", NULL, NULL, + GCAL_TYPE_EVENT_ATTENDEE_TYPE_FILTER_FLAGS, GCAL_EVENT_ATTENDEE_TYPE_FILTER_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:filtered-list: + * + * The filtered list of attendees. + * Filtered by #GcalAttendeeSummaryRow:filter-type + */ + properties[PROP_FILTERED_LIST] = + g_param_spec_object ("filtered-list", NULL, NULL, + GTK_TYPE_FILTER_LIST_MODEL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:num-accepted: + * + * Gets the number of attendees who accepted. + */ + properties[PROP_NUM_ACCEPTED] = + g_param_spec_uint ("num-accepted", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:num-declined: + * + * Gets the number of attendees who declined. + */ + properties[PROP_NUM_DECLINED] = + g_param_spec_uint ("num-declined", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:num-tentative: + * + * Gets the number of attendees who "maybe" will attend. + */ + properties[PROP_NUM_TENTATIVE] = + g_param_spec_uint ("num-tentative", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:num-unknown: + * + * Gets the number of attendees with an unknown response. + */ + properties[PROP_NUM_UNKNOWN] = + g_param_spec_uint ("num-unknown", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GcalAttendeeSummaryRow:num-delegated: + * + * Gets the number of attendees who delegated their attendance to someone else. + */ + properties[PROP_NUM_DELEGATED] = + g_param_spec_uint ("num-delegated", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/event-editor/gcal-attendee-summary-row.ui"); +} + +static void +gcal_attendee_summary_row_init (GcalAttendeeSummaryRow *instance) +{ + instance->attendees = g_list_store_new (GCAL_TYPE_EVENT_ATTENDEE); + instance->attendee_filter = gtk_custom_filter_new ((GtkCustomFilterFunc) custom_filter_func, instance, NULL); + instance->filtered_attendees = gtk_filter_list_model_new (G_LIST_MODEL (instance->attendees), GTK_FILTER (instance->attendee_filter)); + + gtk_widget_init_template(GTK_WIDGET(instance)); + + gtk_actionable_set_action_name (GTK_ACTIONABLE (instance), "event-editor.show-attendees-detail-page"); +} + diff --git a/src/gui/event-editor/gcal-attendee-summary-row.h b/src/gui/event-editor/gcal-attendee-summary-row.h new file mode 100644 index 00000000..4dee576c --- /dev/null +++ b/src/gui/event-editor/gcal-attendee-summary-row.h @@ -0,0 +1,32 @@ +/* gcal-attendee-summary-row.c + * + * Copyright (C) 2025 Alen Galinec + * + * 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 . + */ + +#ifndef GCAL_ATTENDEE_SUMMARY_ROW_H +#define GCAL_ATTENDEE_SUMMARY_ROW_H + +#include +#include + +G_BEGIN_DECLS + +#define GCAL_TYPE_ATTENDEE_SUMMARY_ROW (gcal_attendee_summary_row_get_type ()) +G_DECLARE_FINAL_TYPE (GcalAttendeeSummaryRow, gcal_attendee_summary_row, GCAL, ATTENDEE_SUMMARY_ROW, AdwActionRow) + +G_END_DECLS + +#endif diff --git a/src/gui/event-editor/gcal-attendees-section.blp b/src/gui/event-editor/gcal-attendees-section.blp index e4bfdf22..e6b980bf 100644 --- a/src/gui/event-editor/gcal-attendees-section.blp +++ b/src/gui/event-editor/gcal-attendees-section.blp @@ -23,30 +23,16 @@ template $GcalAttendeesSection: Gtk.Box { ] } - Adw.ActionRow summary_row { + $GcalAttendeeSummaryRow summary_row { title: _("Participants"); - activatable-widget: open_details; - activated => $on_participant_summary_row_activated_cb(template) not-swapped; + attendees: bind template.attendees; + filter-flags: GCAL_EVENT_ATTENDEE_TYPE_FILTER_PERSON; + } - styles [ - "property", - ] - - [suffix] - Label { - valign: center; - label: bind template.num-participants as ; - tooltip-text: _("Number of participants"); - - styles [ - "participants-count-label", - ] - } - - [suffix] - Image open_details { - icon-name: "go-next-symbolic"; - } + $GcalAttendeeSummaryRow { + title: _("Resources"); + attendees: bind template.attendees; + filter-flags: GCAL_EVENT_ATTENDEE_TYPE_FILTER_RESOURCE; } } } diff --git a/src/gui/event-editor/gcal-attendees-section.c b/src/gui/event-editor/gcal-attendees-section.c index a1e02e31..58df2efe 100644 --- a/src/gui/event-editor/gcal-attendees-section.c +++ b/src/gui/event-editor/gcal-attendees-section.c @@ -22,13 +22,14 @@ #include #include +#include "gcal-attendee-summary-row.h" #include "gcal-context.h" -#include "gcal-enums.h" #include "gcal-event-attendee.h" #include "gcal-event-editor-section.h" #include "gcal-event-organizer.h" #include "gcal-event.h" #include "gcal-utils.h" +#include "glib-object.h" struct _GcalAttendeesSection { @@ -40,12 +41,7 @@ struct _GcalAttendeesSection AdwActionRow *organizer_row; AdwActionRow *summary_row; - /* participation summary */ - guint num_accepted; - guint num_declined; - guint num_tentative; - guint num_not_responded; - guint num_delegated; + GListStore *attendees; }; static void gcal_event_editor_section_init_iface (GcalEventEditorSectionInterface *iface); @@ -57,22 +53,10 @@ enum { PROP_0, PROP_CONTEXT, - PROP_NUM_ACCEPTED, - PROP_NUM_DECLINED, - PROP_NUM_TENTATIVE, - PROP_NUM_DELEGATED, - PROP_NUM_UNKNOWN, - PROP_NUM_TOTAL, + PROP_ATTENDEES, N_PROPS }; -enum -{ - SUMMARY_ROW_ACTIVATED, - N_SIGNALS, -}; - -static guint signals[N_SIGNALS] = { 0, }; static GParamSpec *properties[N_PROPS] = { NULL, }; static void @@ -84,50 +68,8 @@ reset_section (GcalAttendeesSection *self, g_set_object (&self->event, event); + g_list_store_remove_all (self->attendees); adw_action_row_set_subtitle (self->organizer_row, NULL); - adw_action_row_set_subtitle (self->summary_row, NULL); - - self->num_accepted = 0; - self->num_declined = 0; - self->num_tentative = 0; - self->num_not_responded = 0; - self->num_delegated = 0; -} - -static inline void -concat_subtitle_part (GStrvBuilder *builder, - guint value, - const gchar *text) -{ - if (value <= 0) - return; - - g_strv_builder_take (builder, g_strdup_printf ("%d %s", value, text)); -} - -static gchar* -build_summary_subtitle (GcalAttendeesSection *self) -{ - g_autoptr (GStrvBuilder) builder = g_strv_builder_new (); - - concat_subtitle_part (builder, self->num_accepted, ngettext ("accepted", "accepted", self->num_accepted)); - concat_subtitle_part (builder, self->num_tentative, ngettext ("maybe", "maybe", self->num_tentative)); - concat_subtitle_part (builder, self->num_declined, ngettext ("declined", "declined", self->num_declined)); - concat_subtitle_part (builder, self->num_delegated, ngettext ("delegated", "delegated", self->num_delegated)); - concat_subtitle_part (builder, self->num_not_responded, ngettext ("not responded", "not responded", self->num_not_responded)); - - g_auto (GStrv) parts = g_strv_builder_end (builder); - - gchar *result = g_strjoinv (", ", parts); - - return result; -} - -static void -gcal_attendees_section_notify (GcalAttendeesSection *self) -{ - for (guint i = 1; i < N_PROPS; ++i) - g_object_notify_by_pspec (G_OBJECT (self), properties[i]); } static void @@ -157,37 +99,9 @@ gcal_attendees_section_set_event (GcalEventEditorSection *section, /* set attendees and summarize attendance status */ attendees = gcal_event_get_attendees (self->event); for (GSList *l = attendees; l != NULL; l = l->next) - { - g_autoptr (GcalEventAttendee) attendee = GCAL_EVENT_ATTENDEE (l->data); + g_list_store_append (self->attendees, GCAL_EVENT_ATTENDEE (l->data)); - switch (gcal_event_attendee_get_part_status (attendee)) - { - case GCAL_EVENT_ATTENDEE_PART_ACCEPTED: - self->num_accepted++; - break; - - case GCAL_EVENT_ATTENDEE_PART_DECLINED: - self->num_declined++; - break; - - case GCAL_EVENT_ATTENDEE_PART_TENTATIVE: - self->num_tentative++; - break; - - case GCAL_EVENT_ATTENDEE_PART_DELEGATED: - self->num_delegated++; - break; - - default: - self->num_not_responded++; - break; - } - } - - adw_action_row_set_subtitle (self->summary_row, build_summary_subtitle (self)); - - /* notify properties changed */ - gcal_attendees_section_notify (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ATTENDEES]); } static void @@ -211,21 +125,6 @@ gcal_event_editor_section_init_iface (GcalEventEditorSectionInterface *iface) iface->changed = gcal_attendees_section_changed; } -static guint -gcal_attendees_section_get_num_participants (GcalAttendeesSection *self) -{ - g_assert (GCAL_IS_ATTENDEES_SECTION (self)); - - return self->num_accepted + self->num_declined + self->num_tentative + self->num_delegated + self->num_not_responded; -} - -static void -on_participant_summary_row_activated_cb (AdwActionRow *summary_row, - GcalAttendeesSection *self) -{ - g_signal_emit (self, signals[SUMMARY_ROW_ACTIVATED], 0); -} - static void gcal_attendees_section_get_property (GObject *object, guint property_id, @@ -240,28 +139,8 @@ gcal_attendees_section_get_property (GObject *object, g_value_set_object (value, self->context); break; - case PROP_NUM_ACCEPTED: - g_value_set_uint (value, self->num_accepted); - break; - - case PROP_NUM_DECLINED: - g_value_set_uint (value, self->num_declined); - break; - - case PROP_NUM_TENTATIVE: - g_value_set_uint (value, self->num_tentative); - break; - - case PROP_NUM_DELEGATED: - g_value_set_uint (value, self->num_delegated); - break; - - case PROP_NUM_UNKNOWN: - g_value_set_uint (value, self->num_not_responded); - break; - - case PROP_NUM_TOTAL: - g_value_set_uint (value, gcal_attendees_section_get_num_participants (self)); + case PROP_ATTENDEES: + g_value_set_object (value, self->attendees); break; default: @@ -296,6 +175,7 @@ gcal_attendees_section_finalize (GObject *object) g_clear_object (&self->context); g_clear_object (&self->event); + g_clear_pointer (&self->attendees, g_list_store_remove_all); G_OBJECT_CLASS (gcal_attendees_section_parent_class)->finalize (object); } @@ -303,6 +183,7 @@ gcal_attendees_section_finalize (GObject *object) static void gcal_attendees_section_init (GcalAttendeesSection *instance) { + instance->attendees = g_list_store_new (GCAL_TYPE_EVENT_ATTENDEE); gtk_widget_init_template (GTK_WIDGET (instance)); } @@ -312,6 +193,8 @@ gcal_attendees_section_class_init (GcalAttendeesSectionClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + g_type_ensure (GCAL_TYPE_ATTENDEE_SUMMARY_ROW); + object_class->finalize = gcal_attendees_section_finalize; object_class->get_property = gcal_attendees_section_get_property; object_class->set_property = gcal_attendees_section_set_property; @@ -326,87 +209,15 @@ gcal_attendees_section_class_init (GcalAttendeesSectionClass *klass) GCAL_TYPE_CONTEXT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - /** - * GcalAttendeesSection:num-accepted: - * - * Gets the number of attendees who accepted. - */ - properties[PROP_NUM_ACCEPTED] = - g_param_spec_uint ("num-accepted", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - - /** - * GcalAttendeesSection:num-declined: - * - * Gets the number of attendees who declined. - */ - properties[PROP_NUM_DECLINED] = - g_param_spec_uint ("num-declined", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - - /** - * GcalAttendeesSection:num-tentative: - * - * Gets the number of attendees who "maybe" will attend. - */ - properties[PROP_NUM_TENTATIVE] = - g_param_spec_uint ("num-tentative", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - - /** - * GcalAttendeesSection:num-unknown: - * - * Gets the number of attendees with an unknown response. - */ - properties[PROP_NUM_UNKNOWN] = - g_param_spec_uint ("num-unknown", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - - /** - * GcalAttendeesSection: num-delegated: - * - * Gets the number of attendees who delegated their attendance to someone else. - */ - properties[PROP_NUM_DELEGATED] = - g_param_spec_uint ("num-delegated", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - - /** - * GcalAttendeesSection:num-participants: - * - * Gets the total number of attendees/participants. - */ - properties[PROP_NUM_TOTAL] = - g_param_spec_uint ("num-participants", NULL, NULL, - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + properties[PROP_ATTENDEES] = + g_param_spec_object ("attendees", NULL, NULL, + G_TYPE_LIST_STORE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); - /** - * GcalAttendeesSection::summary-row-activated: - * - * This signal is emitted when the summary row is activated. - */ - signals[SUMMARY_ROW_ACTIVATED] = - g_signal_new ("summary-row-activated", - GCAL_TYPE_ATTENDEES_SECTION, - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, - 0); - gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/event-editor/gcal-attendees-section.ui"); gtk_widget_class_bind_template_child (widget_class, GcalAttendeesSection, organizer_row); gtk_widget_class_bind_template_child (widget_class, GcalAttendeesSection, summary_row); - - gtk_widget_class_bind_template_callback (widget_class, on_participant_summary_row_activated_cb); } diff --git a/src/gui/event-editor/gcal-event-editor-dialog.blp b/src/gui/event-editor/gcal-event-editor-dialog.blp index aa7f8572..18a204e6 100644 --- a/src/gui/event-editor/gcal-event-editor-dialog.blp +++ b/src/gui/event-editor/gcal-event-editor-dialog.blp @@ -63,7 +63,6 @@ template $GcalEventEditorDialog: Adw.Dialog { Adw.PreferencesGroup participants_group { $GcalAttendeesSection attendees_section { sensitive: bind template.writable; - summary-row-activated => $on_attendees_summary_activated_cb(template) not-swapped; } } diff --git a/src/gui/event-editor/gcal-event-editor-dialog.c b/src/gui/event-editor/gcal-event-editor-dialog.c index 0b643795..d7b5ad7c 100644 --- a/src/gui/event-editor/gcal-event-editor-dialog.c +++ b/src/gui/event-editor/gcal-event-editor-dialog.c @@ -309,23 +309,6 @@ out: * Callbacks */ -static void -on_attendees_summary_activated_cb (GcalAttendeesSection *section, - GcalEventEditorDialog *self) -{ - g_autoptr (GSList) attendees = NULL; - - g_assert (GCAL_IS_EVENT_EDITOR_DIALOG (self)); - - attendees = gcal_event_get_attendees (self->event); - - gcal_attendee_details_page_set_attendees (GCAL_ATTENDEE_DETAILS_PAGE (self->attendee_details_page), - attendees); - - adw_navigation_view_push (ADW_NAVIGATION_VIEW (self->nav_view), - ADW_NAVIGATION_PAGE (self->attendee_details_page)); -} - static void on_event_editor_save_action_activated_cb (GSimpleAction *action, GVariant *param, @@ -635,7 +618,6 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass) /* callbacks */ gtk_widget_class_bind_template_callback (widget_class, on_cancel_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, on_delete_row_activated_cb); - gtk_widget_class_bind_template_callback (widget_class, on_attendees_summary_activated_cb); } static void @@ -643,7 +625,7 @@ gcal_event_editor_dialog_init (GcalEventEditorDialog *self) { static const GActionEntry actions[] = { {"save", on_event_editor_save_action_activated_cb }, - {"show-attendees-detail-page", on_show_attendees_detail_page_action_activated_cb }, + {"show-attendees-detail-page", on_show_attendees_detail_page_action_activated_cb, "u" }, }; gint i = 0; diff --git a/src/gui/event-editor/meson.build b/src/gui/event-editor/meson.build index 7032c132..eadba486 100644 --- a/src/gui/event-editor/meson.build +++ b/src/gui/event-editor/meson.build @@ -19,6 +19,7 @@ blueprints = custom_target( 'gcal-attendees-section.blp', 'gcal-attendee-row.blp', 'gcal-attendee-details-page.blp', + 'gcal-attendee-summary-row.blp', ), output: '.', command: [ @@ -55,4 +56,5 @@ sources += files( 'gcal-attendees-section.c', 'gcal-attendee-row.c', 'gcal-attendee-details-page.c', + 'gcal-attendee-summary-row.c', )