From 84eeb58804eb7c98dc5aa77c6ae460eea7475b2f Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Fri, 27 Mar 2020 12:39:08 -0300 Subject: [PATCH] Move Shell search to GcalShellSearchProvider Add a custom timeline to GcalShellSearchProvier and use it to gather events. Do a massive cleanup of unused APIs as well. --- src/core/gcal-calendar-monitor.c | 44 ++++ src/core/gcal-manager.c | 304 -------------------------- src/core/gcal-manager.h | 24 -- src/core/gcal-shell-search-provider.c | 198 +++++++++++------ src/core/gcal-timeline.c | 69 ++++++ src/core/gcal-timeline.h | 2 + 6 files changed, 251 insertions(+), 390 deletions(-) diff --git a/src/core/gcal-calendar-monitor.c b/src/core/gcal-calendar-monitor.c index e61da075..a84ceaac 100644 --- a/src/core/gcal-calendar-monitor.c +++ b/src/core/gcal-calendar-monitor.c @@ -84,6 +84,7 @@ struct _GcalCalendarMonitor static gboolean add_event_to_timeline_in_idle_cb (gpointer user_data); static gboolean update_event_in_idle_cb (gpointer user_data); static gboolean remove_event_from_timeline_in_idle_cb (gpointer user_data); +static gboolean complete_in_idle_cb (gpointer user_data); G_DEFINE_TYPE (GcalCalendarMonitor, gcal_calendar_monitor, G_TYPE_OBJECT) @@ -92,6 +93,7 @@ enum EVENT_ADDED, EVENT_UPDATED, EVENT_REMOVED, + COMPLETED, N_SIGNALS, }; @@ -241,6 +243,21 @@ remove_event_in_idle (GcalCalendarMonitor *self, (GDestroyNotify) idle_data_free); } +static void +complete_in_idle (GcalCalendarMonitor *self) +{ + IdleData *idle_data; + + idle_data = g_new0 (IdleData, 1); + idle_data->monitor = g_object_ref (self); + + g_main_context_invoke_full (self->main_context, + G_PRIORITY_DEFAULT_IDLE, + complete_in_idle_cb, + idle_data, + (GDestroyNotify) idle_data_free); +} + typedef struct { GcalCalendarMonitor *monitor; @@ -568,6 +585,8 @@ on_client_view_complete_cb (ECalClientView *view, self->monitor_thread.populated = TRUE; + complete_in_idle (self); + g_debug ("Finished initial loading of calendar '%s'", gcal_calendar_get_name (self->calendar)); GCAL_EXIT; @@ -939,6 +958,24 @@ on_calendar_visible_changed_cb (GcalCalendar *calendar, } } +static gboolean +complete_in_idle_cb (gpointer user_data) +{ + g_autoptr (GcalEvent) event = NULL; + GcalCalendarMonitor *self; + IdleData *idle_data; + + GCAL_ENTRY; + + idle_data = user_data; + self = idle_data->monitor; + g_assert (idle_data->event == NULL); + g_assert (idle_data->event_id == NULL); + + g_signal_emit (self, signals[COMPLETED], 0, event); + GCAL_RETURN (G_SOURCE_REMOVE); +} + /* * GObject overrides @@ -1044,6 +1081,13 @@ gcal_calendar_monitor_class_init (GcalCalendarMonitorClass *klass) 1, GCAL_TYPE_EVENT); + signals[COMPLETED] = g_signal_new ("completed", + GCAL_TYPE_CALENDAR_MONITOR, + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 0); + properties[PROP_CALENDAR] = g_param_spec_object ("calendar", "Calendar", "Calendar to be monitores", diff --git a/src/core/gcal-manager.c b/src/core/gcal-manager.c index 317765a5..e9729c81 100644 --- a/src/core/gcal-manager.c +++ b/src/core/gcal-manager.c @@ -45,16 +45,6 @@ typedef struct GcalManager *manager; } AsyncOpsData; -typedef struct -{ - ECalDataModelSubscriber *subscriber; - gchar *query; - - guint sources_left; - gboolean passed_start; - gboolean search_done; -} ViewStateData; - typedef struct { gchar *event_uid; @@ -64,12 +54,6 @@ typedef struct GcalManager *manager; } MoveEventData; -typedef struct -{ - GcalManager *manager; - GList *events; -} GatherEventData; - struct _GcalManager { GObject parent; @@ -84,9 +68,6 @@ struct _GcalManager ESourceRegistry *source_registry; ECredentialsPrompter *credentials_prompter; - ECalDataModel *shell_search_data_model; - ViewStateData *search_view_data; - GCancellable *async_ops; gint clients_synchronizing; @@ -126,36 +107,6 @@ free_async_ops_data (AsyncOpsData *data) g_free (data); } -static gboolean -gather_events (ECalDataModel *data_model, - ECalClient *client, - const ECalComponentId *id, - ECalComponent *comp, - time_t instance_start, - time_t instance_end, - gpointer user_data) -{ - GatherEventData *data = user_data; - GcalCalendar *calendar; - GcalEvent *event; - GError *error; - - error = NULL; - calendar = g_hash_table_lookup (data->manager->clients, e_client_get_source (E_CLIENT (client))); - event = gcal_event_new (calendar, comp, &error); - - if (error) - { - g_warning ("Error: %s", error->message); - g_clear_error (&error); - return TRUE; - } - - data->events = g_list_append (data->events, event);/* FIXME: add me sorted */ - - return TRUE; -} - static void remove_source (GcalManager *self, ESource *source) @@ -198,21 +149,6 @@ source_changed (GcalManager *self, if (!calendar) GCAL_RETURN (); - if (gcal_calendar_get_visible (calendar)) - { - ECalClient *client = gcal_calendar_get_client (calendar); - - if (self->shell_search_data_model) - e_cal_data_model_add_client (self->shell_search_data_model, client); - } - else - { - const gchar *id = gcal_calendar_get_id (calendar); - - if (self->shell_search_data_model) - e_cal_data_model_remove_client (self->shell_search_data_model, id); - } - g_signal_emit (self, signals[CALENDAR_CHANGED], 0, calendar); GCAL_EXIT; @@ -286,12 +222,6 @@ on_calendar_created_cb (GObject *source_object, gcal_timeline_add_calendar (self->timeline, calendar); - if (visible) - { - if (self->shell_search_data_model != NULL) - e_cal_data_model_add_client (self->shell_search_data_model, client); - } - /* refresh client when it's added */ if (visible && e_client_check_refresh_supported (E_CLIENT (client))) { @@ -464,45 +394,6 @@ on_event_removed (GObject *source_object, GCAL_EXIT; } -static void -model_state_changed (GcalManager *self, - ECalClientView *view, - ECalDataModelViewState state, - guint percent, - const gchar *message, - const GError *error, - ECalDataModel *data_model) -{ - gchar *filter; - - GCAL_ENTRY; - - filter = e_cal_data_model_dup_filter (data_model); - - if (state == E_CAL_DATA_MODEL_VIEW_STATE_START && - g_strcmp0 (self->search_view_data->query, filter) == 0) - { - self->search_view_data->passed_start = TRUE; - GCAL_GOTO (out); - } - - if (self->search_view_data->passed_start && - state == E_CAL_DATA_MODEL_VIEW_STATE_COMPLETE && - g_strcmp0 (self->search_view_data->query, filter) == 0) - { - self->search_view_data->sources_left--; - self->search_view_data->search_done = (self->search_view_data->sources_left == 0); - - if (self->search_view_data->search_done) - g_signal_emit (self, signals[QUERY_COMPLETED], 0); - } - -out: - g_free (filter); - - GCAL_EXIT; -} - static void show_source_error (const gchar *where, const gchar *what, @@ -653,7 +544,6 @@ gcal_manager_finalize (GObject *object) GCAL_ENTRY; g_clear_object (&self->timeline); - g_clear_object (&self->shell_search_data_model); if (self->context) { @@ -661,12 +551,6 @@ gcal_manager_finalize (GObject *object) self->context = NULL; } - if (self->search_view_data) - { - g_clear_pointer (&self->search_view_data->query, g_free); - g_clear_pointer (&self->search_view_data, g_free); - } - g_clear_pointer (&self->clients, g_hash_table_destroy); G_OBJECT_CLASS (gcal_manager_parent_class)->finalize (object); @@ -903,137 +787,6 @@ gcal_manager_set_default_calendar (GcalManager *self, gcal_calendar_get_source (calendar)); } -/** - * gcal_manager_setup_shell_search: - * @self: a #GcalManager - * @subscriber: an #ECalDataModelSubscriber - * - * Sets up the GNOME Shell search subscriber. - */ -void -gcal_manager_setup_shell_search (GcalManager *self, - ECalDataModelSubscriber *subscriber) -{ - GTimeZone *zone; - - g_return_if_fail (GCAL_IS_MANAGER (self)); - - if (self->shell_search_data_model) - return; - - self->shell_search_data_model = e_cal_data_model_new (gcal_thread_submit_job); - g_signal_connect_object (self->shell_search_data_model, - "view-state-changed", - G_CALLBACK (model_state_changed), - self, - G_CONNECT_SWAPPED); - - e_cal_data_model_set_expand_recurrences (self->shell_search_data_model, TRUE); - - zone = gcal_context_get_timezone (self->context); - e_cal_data_model_set_timezone (self->shell_search_data_model, gcal_timezone_to_icaltimezone (zone)); - - self->search_view_data = g_new0 (ViewStateData, 1); - self->search_view_data->subscriber = subscriber; -} - -/** - * gcal_manager_set_shell_search_query: - * @self: A #GcalManager instance - * @query: query string (an s-exp) - * - * Set the query terms of the #ECalDataModel used in the shell search - */ -void -gcal_manager_set_shell_search_query (GcalManager *self, - const gchar *query) -{ - GCAL_ENTRY; - - g_return_if_fail (GCAL_IS_MANAGER (self)); - - self->search_view_data->passed_start = FALSE; - self->search_view_data->search_done = FALSE; - self->search_view_data->sources_left = g_hash_table_size (self->clients); - - if (self->search_view_data->query != NULL) - g_free (self->search_view_data->query); - self->search_view_data->query = g_strdup (query); - - e_cal_data_model_set_filter (self->shell_search_data_model, query); -} - -/** - * gcal_manager_set_shell_search_subscriber: - * @self: a #GcalManager - * @subscriber: the #ECalDataModelSubscriber to subscribe - * @range_start: the start of the range - * @range_end: the end of the range - * - * Subscribe @subscriber to the shell data modal at the given range. - */ -void -gcal_manager_set_shell_search_subscriber (GcalManager *self, - ECalDataModelSubscriber *subscriber, - time_t range_start, - time_t range_end) -{ - GCAL_ENTRY; - - e_cal_data_model_subscribe (self->shell_search_data_model, subscriber, range_start, range_end); - - GCAL_EXIT; -} - -/** - * gcal_manager_shell_search_done: - * @self: a #GcalManager - * - * Retrieves whether the search at @self is done or not. - * - * Returns: %TRUE if the search is finished. - */ -gboolean -gcal_manager_shell_search_done (GcalManager *self) -{ - g_return_val_if_fail (GCAL_IS_MANAGER (self), FALSE); - - return self->search_view_data->search_done; -} - -/** - * gcal_manager_get_shell_search_events: - * @self: a #GcalManager - * - * Retrieves all the events available for GNOME Shell search. - * - * Returns: (nullable)(transfer full)(content-type GcalEvent): a #GList - */ -GList* -gcal_manager_get_shell_search_events (GcalManager *self) -{ - time_t range_start, range_end; - GatherEventData data = { - .manager = self, - .events = NULL, - }; - - GCAL_ENTRY; - - e_cal_data_model_get_subscriber_range (self->shell_search_data_model, - self->search_view_data->subscriber, - &range_start, - &range_end); - - e_cal_data_model_foreach_component (self->shell_search_data_model, - range_start, - range_end, - gather_events, - &data); - - GCAL_RETURN (data.events); -} - /** * gcal_manager_set_subscriber: * @self: a #GcalManager @@ -1469,63 +1222,6 @@ gcal_manager_get_events (GcalManager *self, GCAL_RETURN (g_steal_pointer (&events_at_range)); } -/** - * gcal_manager_get_event_from_shell_search: - * @self: a #GcalManager - * @uuid: the unique identier of the event - * - * Retrieves the #GcalEvent with @uuid. - * - * Returns: (nullable)(transfer full): a #GcalEvent - */ -GcalEvent* -gcal_manager_get_event_from_shell_search (GcalManager *self, - const gchar *uuid) -{ - GcalEvent *new_event; - GList *l; - time_t range_start, range_end; - GatherEventData data = { - .manager = self, - .events = NULL, - }; - - - GCAL_ENTRY; - - g_return_val_if_fail (GCAL_IS_MANAGER (self), NULL); - - new_event = NULL; - - e_cal_data_model_get_subscriber_range (self->shell_search_data_model, - self->search_view_data->subscriber, - &range_start, - &range_end); - - e_cal_data_model_foreach_component (self->shell_search_data_model, - range_start, - range_end, - gather_events, - &data); - - for (l = data.events; l != NULL; l = g_list_next (l)) - { - GcalEvent *event; - - event = l->data; - - /* Found the event */ - if (g_strcmp0 (gcal_event_get_uid (event), uuid) == 0) - new_event = event; - else - g_object_unref (event); - } - - g_list_free (data.events); - - GCAL_RETURN (new_event); -} - /** * gcal_manager_get_synchronizing: * @self: a #GcalManager diff --git a/src/core/gcal-manager.h b/src/core/gcal-manager.h index e4f91392..f59add2d 100644 --- a/src/core/gcal-manager.h +++ b/src/core/gcal-manager.h @@ -48,11 +48,6 @@ void gcal_manager_set_subscriber (GcalManager time_t range_start, time_t range_end); -void gcal_manager_set_search_subscriber (GcalManager *self, - ECalDataModelSubscriber *subscriber, - time_t range_start, - time_t range_end); - void gcal_manager_set_query (GcalManager *self, const gchar *query); @@ -89,25 +84,6 @@ GPtrArray* gcal_manager_get_events (GcalManager GDateTime *range_start, GDateTime *range_end); -/* GNOME Shell-related functions */ -GcalEvent* gcal_manager_get_event_from_shell_search (GcalManager *self, - const gchar *uuid); - -void gcal_manager_setup_shell_search (GcalManager *self, - ECalDataModelSubscriber *subscriber); - -void gcal_manager_set_shell_search_query (GcalManager *self, - const gchar *query); - -void gcal_manager_set_shell_search_subscriber (GcalManager *self, - ECalDataModelSubscriber *subscriber, - time_t range_start, - time_t range_end); - -gboolean gcal_manager_shell_search_done (GcalManager *self); - -GList* gcal_manager_get_shell_search_events (GcalManager *self); - gboolean gcal_manager_get_synchronizing (GcalManager *self); void gcal_manager_startup (GcalManager *self); diff --git a/src/core/gcal-shell-search-provider.c b/src/core/gcal-shell-search-provider.c index 1ab0390a..a9391f00 100644 --- a/src/core/gcal-shell-search-provider.c +++ b/src/core/gcal-shell-search-provider.c @@ -24,6 +24,8 @@ #include "gcal-application.h" #include "gcal-debug.h" #include "gcal-event.h" +#include "gcal-timeline.h" +#include "gcal-timeline-subscriber.h" #include "gcal-window.h" #include "gcal-utils.h" @@ -42,12 +44,17 @@ struct _GcalShellSearchProvider PendingSearch *pending_search; GHashTable *events; + + GDateTime *range_start; + GDateTime *range_end; + GcalTimeline *timeline; }; -static void gcal_subscriber_interface_init (ECalDataModelSubscriberInterface *iface); +static void gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface); G_DEFINE_TYPE_WITH_CODE (GcalShellSearchProvider, gcal_shell_search_provider, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, gcal_subscriber_interface_init)); + G_IMPLEMENT_INTERFACE (GCAL_TYPE_TIMELINE_SUBSCRIBER, + gcal_timeline_subscriber_interface_init)); enum { @@ -71,48 +78,65 @@ sort_event_data (GcalEvent *a, return gcal_event_compare_with_current (a, b, GPOINTER_TO_INT (user_data)); } -static gboolean -execute_search (GcalShellSearchProvider *self) +static void +maybe_update_range (GcalShellSearchProvider *self) { g_autoptr (GDateTime) start = NULL; g_autoptr (GDateTime) end = NULL; g_autoptr (GDateTime) now = NULL; + gboolean range_changed = FALSE; + + GCAL_ENTRY; + + now = g_date_time_new_now (gcal_context_get_timezone (self->context)); + start = g_date_time_add_weeks (now, -1); + end = g_date_time_add_weeks (now, 3); + + if (self->range_start && gcal_date_time_compare_date (self->range_start, start) != 0) + { + gcal_set_date_time (&self->range_start, start); + range_changed = TRUE; + } + + if (self->range_end && gcal_date_time_compare_date (self->range_end, end) != 0) + { + gcal_set_date_time (&self->range_end, end); + range_changed = TRUE; + } + + if (range_changed) + gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (self)); +} + +static gboolean +execute_search (GcalShellSearchProvider *self) +{ g_autofree gchar *search_query = NULL; - GcalManager *manager; - time_t range_start, range_end; guint i; GCAL_ENTRY; - manager = gcal_context_get_manager (self->context); - - now = g_date_time_new_now (gcal_context_get_timezone (self->context)); - start = g_date_time_add_weeks (now, -1); - range_start = g_date_time_to_unix (start); - - end = g_date_time_add_weeks (now, 3); - range_end = g_date_time_to_unix (end); - - gcal_manager_set_shell_search_subscriber (manager, - E_CAL_DATA_MODEL_SUBSCRIBER (self), - range_start, range_end); + maybe_update_range (self); search_query = g_strdup_printf ("(or (contains? \"summary\" \"%s\") (contains? \"description\" \"%s\"))", - self->pending_search->terms[0], self->pending_search->terms[0]); + self->pending_search->terms[0], + self->pending_search->terms[0]); + for (i = 1; i < g_strv_length (self->pending_search->terms); i++) { g_autofree gchar *complete_query = NULL; g_autofree gchar *second_query = NULL; second_query = g_strdup_printf ("(or (contains? \"summary\" \"%s\") (contains? \"description\" \"%s\"))", - self->pending_search->terms[0], self->pending_search->terms[0]); + self->pending_search->terms[0], + self->pending_search->terms[0]); complete_query = g_strdup_printf ("(and %s %s)", search_query, second_query); g_clear_pointer (&search_query, g_free); search_query = g_steal_pointer (&complete_query); } - gcal_manager_set_shell_search_query (manager, search_query); + gcal_timeline_set_filter (self->timeline, search_query); g_application_hold (g_application_get_default ()); GCAL_RETURN (FALSE); @@ -240,15 +264,13 @@ activate_result_cb (GcalShellSearchProvider *self, { g_autoptr (GcalEvent) event = NULL; GApplication *application; - GcalManager *manager; GDateTime *dtstart; GCAL_ENTRY; application = g_application_get_default (); - manager = gcal_context_get_manager (self->context); - event = gcal_manager_get_event_from_shell_search (manager, result); + event = g_hash_table_lookup (self->events, result); dtstart = gcal_event_get_date_start (event); gcal_application_set_uuid (GCAL_APPLICATION (application), result); @@ -283,20 +305,23 @@ launch_search_cb (GcalShellSearchProvider *self, GCAL_RETURN (TRUE); } -static gboolean -query_completed_cb (GcalShellSearchProvider *self, - GcalManager *manager) +static void +on_timeline_completed_cb (GcalTimeline *timeline, + GParamSpec *pspec, + GcalShellSearchProvider *self) { GVariantBuilder builder; - GList *events, *l; + g_autoptr (GList) events = NULL; + GList *l; time_t current_time_t; GCAL_ENTRY; - g_hash_table_remove_all (self->events); + if (!gcal_timeline_is_complete (timeline)) + GCAL_RETURN (); - events = gcal_manager_get_shell_search_events (manager); - if (events == NULL) + events = g_hash_table_get_values (self->events); + if (!events) { g_dbus_method_invocation_return_value (self->pending_search->invocation, g_variant_new ("(as)", NULL)); GCAL_GOTO (out); @@ -319,7 +344,6 @@ query_completed_cb (GcalShellSearchProvider *self, g_hash_table_insert (self->events, g_strdup (uid), l->data); } - g_list_free (events); g_dbus_method_invocation_return_value (self->pending_search->invocation, g_variant_new ("(as)", &builder)); @@ -329,51 +353,95 @@ out: g_clear_pointer (&self->pending_search, g_free); g_application_release (g_application_get_default ()); - GCAL_RETURN (FALSE); + GCAL_EXIT; } +static void +on_manager_calendar_added_cb (GcalManager *manager, + GcalCalendar *calendar, + GcalShellSearchProvider *self) +{ + GCAL_ENTRY; + + gcal_timeline_add_calendar (self->timeline, calendar); + + GCAL_EXIT; +} + +static void +on_manager_calendar_removed_cb (GcalManager *manager, + GcalCalendar *calendar, + GcalShellSearchProvider *self) +{ + GCAL_ENTRY; + + gcal_timeline_remove_calendar (self->timeline, calendar); + + GCAL_EXIT; +} /* - * ECalDataModelSubscriber iface + * GcalTimelineSubscriber iface */ -static void -gcal_shell_search_provider_component_changed (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp) +static GDateTime* +gcal_shell_search_provider_get_range_start (GcalTimelineSubscriber *subscriber) { - ; + GcalShellSearchProvider *self = GCAL_SHELL_SEARCH_PROVIDER (subscriber); + + return g_date_time_ref (self->range_start); +} + +static GDateTime* +gcal_shell_search_provider_get_range_end (GcalTimelineSubscriber *subscriber) +{ + GcalShellSearchProvider *self = GCAL_SHELL_SEARCH_PROVIDER (subscriber); + + return g_date_time_ref (self->range_end); } static void -gcal_shell_search_provider_component_removed (ECalDataModelSubscriber *subscriber, - ECalClient *client, - const gchar *uid, - const gchar *rid) +gcal_shell_search_provider_add_event (GcalTimelineSubscriber *subscriber, + GcalEvent *event) { - ; + GcalShellSearchProvider *self = GCAL_SHELL_SEARCH_PROVIDER (subscriber); + + GCAL_ENTRY; + + g_hash_table_insert (self->events, + g_strdup (gcal_event_get_uid (event)), + g_object_ref (event)); + + GCAL_EXIT; } static void -gcal_shell_search_provider_freeze (ECalDataModelSubscriber *subscriber) +gcal_shell_search_provider_update_event (GcalTimelineSubscriber *subscriber, + GcalEvent *event) { - ; } static void -gcal_shell_search_provider_thaw (ECalDataModelSubscriber *subscriber) +gcal_shell_search_provider_remove_event (GcalTimelineSubscriber *subscriber, + GcalEvent *event) { - ; + GcalShellSearchProvider *self = GCAL_SHELL_SEARCH_PROVIDER (subscriber); + + GCAL_ENTRY; + + g_hash_table_remove (self->events, gcal_event_get_uid (event)); + + GCAL_EXIT; } static void -gcal_subscriber_interface_init (ECalDataModelSubscriberInterface *iface) +gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface) { - iface->component_added = gcal_shell_search_provider_component_changed; - iface->component_modified = gcal_shell_search_provider_component_changed; - iface->component_removed = gcal_shell_search_provider_component_removed; - iface->freeze = gcal_shell_search_provider_freeze; - iface->thaw = gcal_shell_search_provider_thaw; + iface->get_range_start = gcal_shell_search_provider_get_range_start; + iface->get_range_end = gcal_shell_search_provider_get_range_end; + iface->add_event = gcal_shell_search_provider_add_event; + iface->update_event = gcal_shell_search_provider_update_event; + iface->remove_event = gcal_shell_search_provider_remove_event; } @@ -423,15 +491,21 @@ gcal_shell_search_provider_set_property (GObject *object, switch (property_id) { case PROP_CONTEXT: - if (g_set_object (&self->context, g_value_get_object (value))) - { - GcalManager *manager = gcal_context_get_manager (self->context); + { + GcalManager *manager; - gcal_manager_setup_shell_search (manager, E_CAL_DATA_MODEL_SUBSCRIBER (self)); - g_signal_connect_object (manager, "query-completed", G_CALLBACK (query_completed_cb), self, G_CONNECT_SWAPPED); + g_assert (self->context == NULL); + self->context = g_value_get_object (value); - g_object_notify_by_pspec (object, properties[PROP_CONTEXT]); - } + self->timeline = gcal_timeline_new (self->context); + g_signal_connect (self->timeline, "notify::complete", G_CALLBACK (on_timeline_completed_cb), self); + + manager = gcal_context_get_manager (self->context); + g_signal_connect (manager, "calendar-added", G_CALLBACK (on_manager_calendar_added_cb), self); + g_signal_connect (manager, "calendar-removed", G_CALLBACK (on_manager_calendar_removed_cb), self); + + g_object_notify_by_pspec (object, properties[PROP_CONTEXT]); + } break; default: @@ -452,7 +526,7 @@ gcal_shell_search_provider_class_init (GcalShellSearchProviderClass *klass) "The context object", "The context object", GCAL_TYPE_CONTEXT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); } diff --git a/src/core/gcal-timeline.c b/src/core/gcal-timeline.c index 6cace9e4..8914d503 100644 --- a/src/core/gcal-timeline.c +++ b/src/core/gcal-timeline.c @@ -50,6 +50,8 @@ struct _GcalTimeline gchar *filter; GHashTable *calendars; /* GcalCalendar* -> GcalCalendarMonitor* */ + gint completed_calendars; + GHashTable *subscribers; /* GcalTimelineSubscriber* -> SubscriberData* */ GcalRangeTree *subscriber_ranges; @@ -63,6 +65,7 @@ G_DEFINE_TYPE (GcalTimeline, gcal_timeline, G_TYPE_OBJECT) enum { PROP_0, + PROP_COMPLETE, PROP_CONTEXT, PROP_FILTER, N_PROPS @@ -75,6 +78,33 @@ static GParamSpec *properties [N_PROPS] = { NULL, }; * Auxiliary methods */ +static inline gboolean +is_timeline_complete (GcalTimeline *self) +{ + return self->completed_calendars == g_hash_table_size (self->calendars); +} + +static void +reset_completed_calendars (GcalTimeline *self) +{ + gboolean was_complete = is_timeline_complete (self); + + self->completed_calendars = 0; + if (is_timeline_complete (self) != was_complete) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMPLETE]); +} + +static void +increase_completed_calendars (GcalTimeline *self) +{ + self->completed_calendars++; + + g_assert (self->completed_calendars <= g_hash_table_size (self->calendars)); + + if (is_timeline_complete (self)) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMPLETE]); +} + static SubscriberData* subscriber_data_new (GcalTimelineSubscriber *subscriber) { @@ -226,6 +256,8 @@ update_range (GcalTimeline *self) { GcalCalendarMonitor *monitor; + reset_completed_calendars (self); + g_hash_table_iter_init (&iter, self->calendars); while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &monitor)) gcal_calendar_monitor_set_range (monitor, self->range_start, self->range_end); @@ -357,6 +389,8 @@ update_calendar_monitor_filters (GcalTimeline *self) GcalCalendarMonitor *monitor; GHashTableIter iter; + reset_completed_calendars (self); + g_hash_table_iter_init (&iter, self->calendars); while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &monitor)) gcal_calendar_monitor_set_filter (monitor, self->filter); @@ -473,6 +507,17 @@ on_calendar_monitor_event_removed_cb (GcalCalendarMonitor *monitor, GCAL_EXIT; } +static void +on_calendar_monitor_completed_cb (GcalCalendarMonitor *monitor, + GcalTimeline *self) +{ + GCAL_ENTRY; + + increase_completed_calendars (self); + + GCAL_EXIT; +} + static gboolean update_timeline_range_in_idle_cb (gpointer user_data) { @@ -538,6 +583,10 @@ gcal_timeline_get_property (GObject *object, switch (prop_id) { + case PROP_COMPLETE: + g_value_set_boolean (value, is_timeline_complete (self)); + break; + case PROP_CONTEXT: g_value_set_object (value, self->context); break; @@ -584,6 +633,17 @@ gcal_timeline_class_init (GcalTimelineClass *klass) object_class->get_property = gcal_timeline_get_property; object_class->set_property = gcal_timeline_set_property; + /** + * GcalTimeline::complete: + * + * Whether all calendars in this timeline are completed. + */ + properties[PROP_COMPLETE] = g_param_spec_boolean ("complete", + "Complete", + "Complete", + FALSE, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** * GcalSearchEngine::context: * @@ -664,6 +724,7 @@ gcal_timeline_add_calendar (GcalTimeline *self, g_signal_connect (monitor, "event-added", G_CALLBACK (on_calendar_monitor_event_added_cb), self); g_signal_connect (monitor, "event-updated", G_CALLBACK (on_calendar_monitor_event_updated_cb), self); g_signal_connect (monitor, "event-removed", G_CALLBACK (on_calendar_monitor_event_removed_cb), self); + g_signal_connect (monitor, "completed", G_CALLBACK (on_calendar_monitor_completed_cb), self); g_hash_table_insert (self->calendars, calendar, g_object_ref (monitor)); if (self->range_start && self->range_end) @@ -789,3 +850,11 @@ gcal_timeline_set_filter (GcalTimeline *self, GCAL_EXIT; } + +gboolean +gcal_timeline_is_complete (GcalTimeline *self) +{ + g_return_val_if_fail (GCAL_IS_TIMELINE (self), FALSE); + + return is_timeline_complete (self); +} diff --git a/src/core/gcal-timeline.h b/src/core/gcal-timeline.h index 03d037d8..6d088330 100644 --- a/src/core/gcal-timeline.h +++ b/src/core/gcal-timeline.h @@ -52,4 +52,6 @@ const gchar* gcal_timeline_get_filter (GcalTimeline void gcal_timeline_set_filter (GcalTimeline *self, const gchar *filter); +gboolean gcal_timeline_is_complete (GcalTimeline *self); + G_END_DECLS