core/timeline: Add plumbing for models
Add a GtkFlattenListModel that flattens out all events from the calendar monitors. Keep a GtkFilterListModel, and a GtkSortListModel, for each subscriber. Manually update the filter when the range of the subscriber changes. Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/742>
This commit is contained in:
committed by
Marge Bot
parent
5f5e438955
commit
71c5d0b70d
+125
-7
@@ -73,6 +73,7 @@ struct _GcalTimeline
|
|||||||
gboolean complete;
|
gboolean complete;
|
||||||
|
|
||||||
GListStore *calendar_monitors;
|
GListStore *calendar_monitors;
|
||||||
|
GListModel *events_model;
|
||||||
|
|
||||||
GHashTable *subscribers; /* GcalTimelineSubscriber* -> SubscriberData* */
|
GHashTable *subscribers; /* GcalTimelineSubscriber* -> SubscriberData* */
|
||||||
GcalRangeTree *subscriber_ranges;
|
GcalRangeTree *subscriber_ranges;
|
||||||
@@ -97,6 +98,73 @@ enum
|
|||||||
static GParamSpec *properties [N_PROPS] = { NULL, };
|
static GParamSpec *properties [N_PROPS] = { NULL, };
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SubscriberData
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GcalRange *range;
|
||||||
|
GtkFilterListModel *events;
|
||||||
|
GtkSortListModel *sorted_events;
|
||||||
|
} SubscriberData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
subscriber_data_free (SubscriberData *data)
|
||||||
|
{
|
||||||
|
gtk_filter_list_model_set_model (data->events, NULL);
|
||||||
|
|
||||||
|
g_clear_pointer (&data->range, gcal_range_unref);
|
||||||
|
g_clear_object (&data->sorted_events);
|
||||||
|
g_clear_object (&data->events);
|
||||||
|
g_clear_pointer (&data, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SubscriberData, subscriber_data_free)
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
event_in_subscriber_range_func (gpointer item,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
SubscriberData *data = user_data;
|
||||||
|
|
||||||
|
g_assert (GCAL_IS_EVENT (item));
|
||||||
|
|
||||||
|
if (!data->range)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return gcal_event_overlaps (item, data->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_events_cb (gconstpointer a,
|
||||||
|
gconstpointer b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GcalEvent *event_a = (GcalEvent *) a;
|
||||||
|
GcalEvent *event_b = (GcalEvent *) b;
|
||||||
|
|
||||||
|
return gcal_range_compare (gcal_event_get_range (event_b), gcal_event_get_range (event_a));
|
||||||
|
}
|
||||||
|
|
||||||
|
static SubscriberData *
|
||||||
|
subscriber_data_new (GcalTimeline *self,
|
||||||
|
GcalTimelineSubscriber *subscriber)
|
||||||
|
{
|
||||||
|
g_autoptr (GtkCustomFilter) filter = NULL;
|
||||||
|
g_autoptr (SubscriberData) data = NULL;
|
||||||
|
|
||||||
|
data = g_new0 (SubscriberData, 1);
|
||||||
|
data->range = gcal_timeline_subscriber_get_range (subscriber);
|
||||||
|
|
||||||
|
filter = gtk_custom_filter_new (event_in_subscriber_range_func, data, NULL);
|
||||||
|
data->events = gtk_filter_list_model_new (g_object_ref (self->events_model), GTK_FILTER (g_steal_pointer (&filter)));
|
||||||
|
data->sorted_events = gtk_sort_list_model_new (G_LIST_MODEL (g_object_ref (data->events)),
|
||||||
|
GTK_SORTER (gtk_custom_sorter_new (compare_events_cb, NULL, NULL)));
|
||||||
|
|
||||||
|
return g_steal_pointer (&data);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Auxiliary methods
|
* Auxiliary methods
|
||||||
*/
|
*/
|
||||||
@@ -266,6 +334,21 @@ remove_event_from_subscriber (GcalTimelineSubscriber *subscriber,
|
|||||||
GCAL_TIMELINE_SUBSCRIBER_GET_IFACE (subscriber)->remove_event (subscriber, event);
|
GCAL_TIMELINE_SUBSCRIBER_GET_IFACE (subscriber)->remove_event (subscriber, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_model_on_subscriber (GcalTimelineSubscriber *subscriber,
|
||||||
|
GListModel *model)
|
||||||
|
{
|
||||||
|
/* Optional while we transition away from add/update/remove_event */
|
||||||
|
if (!GCAL_TIMELINE_SUBSCRIBER_GET_IFACE (subscriber)->set_model)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GCAL_TRACE_MSG ("Setting event model %p on subscriber %s",
|
||||||
|
model,
|
||||||
|
G_OBJECT_TYPE_NAME (subscriber));
|
||||||
|
|
||||||
|
GCAL_TIMELINE_SUBSCRIBER_GET_IFACE (subscriber)->set_model (subscriber, model);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_range (GcalTimeline *self)
|
update_range (GcalTimeline *self)
|
||||||
{
|
{
|
||||||
@@ -485,10 +568,14 @@ update_subscriber_range (GcalTimeline *self,
|
|||||||
{
|
{
|
||||||
g_autoptr (GcalRange) old_range = NULL;
|
g_autoptr (GcalRange) old_range = NULL;
|
||||||
g_autoptr (GcalRange) new_range = NULL;
|
g_autoptr (GcalRange) new_range = NULL;
|
||||||
|
SubscriberData *subscriber_data;
|
||||||
|
GtkFilter *filter;
|
||||||
|
|
||||||
GCAL_ENTRY;
|
GCAL_ENTRY;
|
||||||
|
|
||||||
old_range = g_hash_table_lookup (self->subscribers, subscriber);
|
subscriber_data = g_hash_table_lookup (self->subscribers, subscriber);
|
||||||
|
|
||||||
|
old_range = g_steal_pointer (&subscriber_data->range);
|
||||||
g_assert (old_range != NULL);
|
g_assert (old_range != NULL);
|
||||||
|
|
||||||
new_range = gcal_timeline_subscriber_get_range (subscriber);
|
new_range = gcal_timeline_subscriber_get_range (subscriber);
|
||||||
@@ -500,8 +587,36 @@ update_subscriber_range (GcalTimeline *self,
|
|||||||
gcal_range_tree_remove_data (self->subscriber_ranges, subscriber);
|
gcal_range_tree_remove_data (self->subscriber_ranges, subscriber);
|
||||||
gcal_range_tree_add_range (self->subscriber_ranges, new_range, subscriber);
|
gcal_range_tree_add_range (self->subscriber_ranges, new_range, subscriber);
|
||||||
|
|
||||||
g_hash_table_insert (self->subscribers, g_object_ref (subscriber), g_steal_pointer (&new_range));
|
subscriber_data->range = gcal_range_ref (new_range);
|
||||||
g_steal_pointer (&old_range);
|
|
||||||
|
g_assert (old_range != NULL);
|
||||||
|
g_assert (new_range != NULL);
|
||||||
|
|
||||||
|
filter = gtk_filter_list_model_get_filter (subscriber_data->events);
|
||||||
|
g_assert (GTK_IS_FILTER (filter));
|
||||||
|
|
||||||
|
switch (gcal_range_calculate_overlap (new_range, old_range, NULL))
|
||||||
|
{
|
||||||
|
case GCAL_RANGE_NO_OVERLAP:
|
||||||
|
case GCAL_RANGE_INTERSECTS:
|
||||||
|
gtk_filter_changed (filter, GTK_FILTER_CHANGE_DIFFERENT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCAL_RANGE_SUBSET:
|
||||||
|
gtk_filter_changed (filter, GTK_FILTER_CHANGE_MORE_STRICT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCAL_RANGE_EQUAL:
|
||||||
|
/* No need to refilter */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCAL_RANGE_SUPERSET:
|
||||||
|
gtk_filter_changed (filter, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
GCAL_EXIT;
|
GCAL_EXIT;
|
||||||
}
|
}
|
||||||
@@ -942,12 +1057,13 @@ gcal_timeline_init (GcalTimeline *self)
|
|||||||
self->cancellable = g_cancellable_new ();
|
self->cancellable = g_cancellable_new ();
|
||||||
self->events = gcal_range_tree_new_with_free_func (g_object_unref);
|
self->events = gcal_range_tree_new_with_free_func (g_object_unref);
|
||||||
self->calendars = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
|
self->calendars = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
|
||||||
self->subscribers = g_hash_table_new_full (NULL, NULL, g_object_unref, (GDestroyNotify) gcal_range_unref);
|
self->subscribers = g_hash_table_new_full (NULL, NULL, g_object_unref, (GDestroyNotify) subscriber_data_free);
|
||||||
self->subscriber_ranges = gcal_range_tree_new ();
|
self->subscriber_ranges = gcal_range_tree_new ();
|
||||||
self->event_queue = g_queue_new ();
|
self->event_queue = g_queue_new ();
|
||||||
self->queued_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
self->queued_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
|
|
||||||
self->calendar_monitors = g_list_store_new (GCAL_TYPE_CALENDAR_MONITOR);
|
self->calendar_monitors = g_list_store_new (GCAL_TYPE_CALENDAR_MONITOR);
|
||||||
|
self->events_model = G_LIST_MODEL (gtk_flatten_list_model_new (g_object_ref (G_LIST_MODEL (self->calendar_monitors))));
|
||||||
|
|
||||||
/* Timeline source */
|
/* Timeline source */
|
||||||
timeline_source = (TimelineSource*) g_source_new (&timeline_source_funcs, sizeof (TimelineSource));
|
timeline_source = (TimelineSource*) g_source_new (&timeline_source_funcs, sizeof (TimelineSource));
|
||||||
@@ -1045,7 +1161,7 @@ void
|
|||||||
gcal_timeline_add_subscriber (GcalTimeline *self,
|
gcal_timeline_add_subscriber (GcalTimeline *self,
|
||||||
GcalTimelineSubscriber *subscriber)
|
GcalTimelineSubscriber *subscriber)
|
||||||
{
|
{
|
||||||
g_autoptr (GcalRange) subscriber_range = NULL;
|
g_autoptr (SubscriberData) subscriber_data = NULL;
|
||||||
|
|
||||||
g_return_if_fail (GCAL_IS_TIMELINE (self));
|
g_return_if_fail (GCAL_IS_TIMELINE (self));
|
||||||
g_return_if_fail (GCAL_IS_TIMELINE_SUBSCRIBER (subscriber));
|
g_return_if_fail (GCAL_IS_TIMELINE_SUBSCRIBER (subscriber));
|
||||||
@@ -1057,9 +1173,11 @@ gcal_timeline_add_subscriber (GcalTimeline *self,
|
|||||||
|
|
||||||
g_debug ("Adding subscriber %s to timeline %p", G_OBJECT_TYPE_NAME (subscriber), self);
|
g_debug ("Adding subscriber %s to timeline %p", G_OBJECT_TYPE_NAME (subscriber), self);
|
||||||
|
|
||||||
subscriber_range = gcal_timeline_subscriber_get_range (subscriber);
|
subscriber_data = subscriber_data_new (self, subscriber);
|
||||||
|
|
||||||
g_hash_table_insert (self->subscribers, g_object_ref (subscriber), gcal_range_ref (subscriber_range));
|
set_model_on_subscriber (subscriber, G_LIST_MODEL (subscriber_data->sorted_events));
|
||||||
|
|
||||||
|
g_hash_table_insert (self->subscribers, g_object_ref (subscriber), g_steal_pointer (&subscriber_data));
|
||||||
g_signal_connect_object (subscriber,
|
g_signal_connect_object (subscriber,
|
||||||
"range-changed",
|
"range-changed",
|
||||||
G_CALLBACK (on_subscriber_range_changed_cb),
|
G_CALLBACK (on_subscriber_range_changed_cb),
|
||||||
|
|||||||
Reference in New Issue
Block a user