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: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/671>
This commit is contained in:
mindonwarp
2026-01-21 19:37:55 +00:00
committed by Marge Bot
parent e7d10964e8
commit 79a37917c7
4 changed files with 34 additions and 37 deletions
@@ -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);
}
/**
@@ -21,6 +21,7 @@
#include "gcal-enums.h"
#include <adwaita.h>
#include <gio/gio.h>
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);
@@ -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)
@@ -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;