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',
)