From 79a37917c730ee672dc3ad6baa6f3807167df753 Mon Sep 17 00:00:00 2001 From: mindonwarp Date: Sun, 11 Jan 2026 18:07:26 +0100 Subject: [PATCH] event-editor: Reuse attendees list model in subviews Store a list model of attendees inside the event editor dialog and use this model when displaying the details page. The attendees section (like other sections) gets injected with the event and gets another copy of the attendees from the event. Both the section and the details page can now avoid resetting themselves when the underlying data (event) doesn't change. Note: the details page uses a ListBox for the sake of the UI style, which can underperform with a lot of attendees (building the visual tree can be laggy). Part-of: --- .../event-editor/gcal-attendee-details-page.c | 43 +++++++------------ .../event-editor/gcal-attendee-details-page.h | 3 +- src/gui/event-editor/gcal-attendees-section.c | 6 +-- .../event-editor/gcal-event-editor-dialog.c | 19 +++++--- 4 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/gui/event-editor/gcal-attendee-details-page.c b/src/gui/event-editor/gcal-attendee-details-page.c index b55cad06..eb152026 100644 --- a/src/gui/event-editor/gcal-attendee-details-page.c +++ b/src/gui/event-editor/gcal-attendee-details-page.c @@ -31,7 +31,7 @@ struct _GcalAttendeeDetailsPage { AdwNavigationPage parent_instance; - GListStore *attendees; + GListModel *attendees; GtkFilterListModel *base_filtered_list; GtkFilterListModel *filter_list_accepted; @@ -79,14 +79,6 @@ set_type_filter_flags (GcalAttendeeDetailsPage *self, gtk_filter_changed (GTK_FILTER (self->base_filter), GTK_FILTER_CHANGE_DIFFERENT); } -static void -gcal_attendee_details_page_clear_list (GcalAttendeeDetailsPage *self) -{ - g_assert (GCAL_IS_ATTENDEE_DETAILS_PAGE (self)); - - g_list_store_remove_all (self->attendees); -} - static GtkWidget * create_attendee_row_widget (void *attendee, void *user_data) @@ -99,8 +91,6 @@ gcal_attendee_details_page_finalize (GObject *object) { GcalAttendeeDetailsPage *page = (GcalAttendeeDetailsPage *) object; - g_clear_pointer (&page->attendees, g_list_store_remove_all); - g_clear_object (&page->base_filter); g_clear_object (&page->accepted_filter); g_clear_object (&page->tentative_filter); @@ -125,7 +115,7 @@ base_filter_cb (GcalEventAttendee *attendee, GcalEventAttendeeType type = gcal_event_attendee_get_attendee_type (attendee); switch (self->attendee_type_filter_flags) - { + { case GCAL_EVENT_ATTENDEE_TYPE_FILTER_PERSON: return type == GCAL_EVENT_ATTENDEE_TYPE_INDIVIDUAL || type == GCAL_EVENT_ATTENDEE_TYPE_GROUP; case GCAL_EVENT_ATTENDEE_TYPE_FILTER_RESOURCE: @@ -133,7 +123,7 @@ base_filter_cb (GcalEventAttendee *attendee, case GCAL_EVENT_ATTENDEE_TYPE_FILTER_NONE: default: return TRUE; - } + } } static gboolean @@ -193,7 +183,7 @@ static void gcal_attendee_details_page_init_filter_models (GcalAttendeeDetailsPage *self) { self->base_filtered_list = - gtk_filter_list_model_new (G_LIST_MODEL (self->attendees), + gtk_filter_list_model_new (self->attendees, GTK_FILTER (self->base_filter)); self->filter_list_accepted = @@ -275,7 +265,6 @@ gcal_attendee_details_page_init (GcalAttendeeDetailsPage *instance) instance->attendee_type_filter_flags = GCAL_EVENT_ATTENDEE_TYPE_FILTER_NONE; - instance->attendees = g_list_store_new (GCAL_TYPE_EVENT_ATTENDEE); gcal_attendee_details_page_init_filters (instance); gcal_attendee_details_page_init_filter_models (instance); @@ -375,9 +364,9 @@ gcal_attendee_details_page_class_init (GcalAttendeeDetailsPageClass *klass) */ properties[PROP_ATTENDEE_TYPE] = g_param_spec_flags ("attendee-type-filter-flags", NULL, NULL, - GCAL_TYPE_EVENT_ATTENDEE_TYPE_FILTER_FLAGS, - GCAL_EVENT_ATTENDEE_TYPE_FILTER_NONE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + GCAL_TYPE_EVENT_ATTENDEE_TYPE_FILTER_FLAGS, + GCAL_EVENT_ATTENDEE_TYPE_FILTER_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); @@ -395,24 +384,22 @@ gcal_attendee_details_page_class_init (GcalAttendeeDetailsPageClass *klass) /** * gcal_attendee_details_page_set_attendees: * @self: a #GcalAttendeeDetailsPage instance. - * @attendees: a list of #GcalEventAttendee to display. + * @attendees: a borrowed list of #GcalEventAttendee to display. * - * Sets the attendees for display. + * Sets the attendees for display. This list is owned by the + * event editor dialog. Do not free here. */ void gcal_attendee_details_page_set_attendees (GcalAttendeeDetailsPage *self, - GSList *attendees) + GListModel *attendees) { g_assert (GCAL_IS_ATTENDEE_DETAILS_PAGE (self)); - gcal_attendee_details_page_clear_list (self); + if (self->attendees == attendees) + return; - g_autoptr (GSList) iter = NULL; - - for (iter = attendees; iter != NULL; iter = iter->next) - { - g_list_store_append (self->attendees, iter->data); - } + self->attendees = attendees; + gtk_filter_list_model_set_model (self->base_filtered_list, self->attendees); } /** diff --git a/src/gui/event-editor/gcal-attendee-details-page.h b/src/gui/event-editor/gcal-attendee-details-page.h index 57cc8ffb..958ed798 100644 --- a/src/gui/event-editor/gcal-attendee-details-page.h +++ b/src/gui/event-editor/gcal-attendee-details-page.h @@ -21,6 +21,7 @@ #include "gcal-enums.h" #include +#include G_BEGIN_DECLS @@ -28,7 +29,7 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (GcalAttendeeDetailsPage, gcal_attendee_details_page, GCAL, ATTENDEE_DETAILS_PAGE, AdwNavigationPage) void gcal_attendee_details_page_set_attendees (GcalAttendeeDetailsPage *self, - GSList *attendees); + GListModel *attendees); void gcal_attendee_details_page_set_type_filter (GcalAttendeeDetailsPage *self, GcalEventAttendeeTypeFilterFlags flags); diff --git a/src/gui/event-editor/gcal-attendees-section.c b/src/gui/event-editor/gcal-attendees-section.c index 58df2efe..929d37c6 100644 --- a/src/gui/event-editor/gcal-attendees-section.c +++ b/src/gui/event-editor/gcal-attendees-section.c @@ -63,9 +63,6 @@ static void reset_section (GcalAttendeesSection *self, GcalEvent *event) { - if (event == self->event) - return; - g_set_object (&self->event, event); g_list_store_remove_all (self->attendees); @@ -81,6 +78,9 @@ gcal_attendees_section_set_event (GcalEventEditorSection *section, GcalEventOrganizer *organizer; g_autoptr (GSList) attendees = NULL; + if (event == self->event) + return; + reset_section (self, event); if (self->event == NULL) diff --git a/src/gui/event-editor/gcal-event-editor-dialog.c b/src/gui/event-editor/gcal-event-editor-dialog.c index d7b5ad7c..feb35cd8 100644 --- a/src/gui/event-editor/gcal-event-editor-dialog.c +++ b/src/gui/event-editor/gcal-event-editor-dialog.c @@ -24,6 +24,7 @@ #include "gcal-calendar-combo-row.h" #include "gcal-context.h" #include "gcal-debug.h" +#include "gcal-event-attendee.h" #include "gcal-event-editor-dialog.h" #include "gcal-event-editor-section.h" #include "gcal-event.h" @@ -80,6 +81,7 @@ struct _GcalEventEditorDialog GBinding *event_title_binding; GListStore *read_only_calendar_model; + GListStore *attendees_model; GSimpleActionGroup *action_group; /* flags */ @@ -203,6 +205,7 @@ setup_context (GcalEventEditorDialog *self) writable_calendars = gcal_create_writable_calendars_model (manager); self->read_only_calendar_model = g_list_store_new (GCAL_TYPE_CALENDAR); + self->attendees_model = g_list_store_new (GCAL_TYPE_EVENT_ATTENDEE); all_calendars = g_list_store_new (G_TYPE_LIST_MODEL); g_list_store_append (all_calendars, self->read_only_calendar_model); @@ -326,10 +329,8 @@ on_show_attendees_detail_page_action_activated_cb (GSimpleAction *action, { GcalEventEditorDialog *self = GCAL_EVENT_EDITOR_DIALOG (user_data); - g_autoptr (GSList) attendees = gcal_event_get_attendees (self->event); - gcal_attendee_details_page_set_attendees (GCAL_ATTENDEE_DETAILS_PAGE (self->attendee_details_page), - attendees); + G_LIST_MODEL (self->attendees_model)); gcal_attendee_details_page_set_type_filter (GCAL_ATTENDEE_DETAILS_PAGE (self->attendee_details_page), g_variant_get_uint32 (param)); @@ -478,6 +479,7 @@ gcal_event_editor_dialog_finalize (GObject *object) g_clear_object (&self->action_group); g_clear_object (&self->context); g_clear_object (&self->event); + g_clear_pointer (&self->attendees_model, g_list_store_remove_all); G_OBJECT_CLASS (gcal_event_editor_dialog_parent_class)->finalize (object); @@ -624,8 +626,8 @@ static void 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, "u" }, + { "save", on_event_editor_save_action_activated_cb }, + { "show-attendees-detail-page", on_show_attendees_detail_page_action_activated_cb, "u" }, }; gint i = 0; @@ -675,6 +677,7 @@ gcal_event_editor_dialog_set_event (GcalEventEditorDialog *self, { g_autoptr (GdkPaintable) paintable = NULL; g_autoptr (GcalEvent) cloned_event = NULL; + g_autoptr (GSList) attendees = NULL; GcalEventEditorFlags flags; GcalCalendar *calendar; gint i; @@ -684,6 +687,7 @@ gcal_event_editor_dialog_set_event (GcalEventEditorDialog *self, g_return_if_fail (GCAL_IS_EVENT_EDITOR_DIALOG (self)); g_clear_object (&self->event); + g_list_store_remove_all (self->attendees_model); /* If we just set the event to NULL, simply send a property notify */ if (!event) @@ -727,6 +731,11 @@ gcal_event_editor_dialog_set_event (GcalEventEditorDialog *self, if (!self->writable) gtk_widget_grab_focus (self->done_button); + /* fill attendees list */ + attendees = gcal_event_get_attendees (self->event); + for (GSList *it = attendees; it != NULL; it = it->next) + g_list_store_append (self->attendees_model, GCAL_EVENT_ATTENDEE (it->data)); + out: flags = GCAL_EVENT_EDITOR_FLAG_NONE;