[gnome-calendar/gnome-3-36] Move Shell search to GcalShellSearchProvider



commit 227586a1d156c6a1d824e911d2c7488999d55caa
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Mar 27 12:39:08 2020 -0300

    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 | 194 +++++++++++++++-------
 src/core/gcal-timeline.c              |  69 ++++++++
 src/core/gcal-timeline.h              |   2 +
 6 files changed, 249 insertions(+), 388 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;
-  g_autofree gchar *search_query = NULL;
-  GcalManager *manager;
-  time_t range_start, range_end;
-  guint i;
+  gboolean range_changed = FALSE;
 
   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);
+  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;
+  guint i;
+
+  GCAL_ENTRY;
+
+  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;
+
+        g_assert (self->context == NULL);
+        self->context = g_value_get_object (value);
+
+        self->timeline = gcal_timeline_new (self->context);
+        g_signal_connect (self->timeline, "notify::complete", G_CALLBACK (on_timeline_completed_cb), self);
 
-          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);
+        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]);
-        }
+        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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]