Re: [evolution-patches] patch for #59904 (calendar)



On Thu, 2004-08-26 at 00:48 +0200, Rodrigo Moya wrote:
> On Wed, 2004-08-25 at 13:17 -0400, JP Rosevear wrote:
> > On Fri, 2004-08-13 at 14:06 +0200, Rodrigo Moya wrote:
> > > On Tue, 2004-08-03 at 14:36 +0200, Rodrigo Moya wrote:
> > > > This makes ECal use a cache of queries, so that we don't have to run
> > > > them over and over again. I've seen a lot of speed improvements in the
> > > > local calendars, not that much in the DVD movies file (mentioned in the
> > > > bug), so I'm still looking at fixing that, but this should make things
> > > > much quicker for most users
> > > >
> > > here is a much better patch, with the cache in the backends, so that
> > > they are really shared between calendar clients.
> > 
> > The patch is malformed.
> > 
> ugh, not sure what's happening lately with my patches :) Here's a new
> one
>
updated patch attached, which includes the use of the query cache in the
get_object_list method also.
-- 
Rodrigo Moya <rodrigo novell com>
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/ChangeLog,v
retrieving revision 1.324.2.1
diff -u -p -r1.324.2.1 ChangeLog
--- ChangeLog	16 Sep 2004 14:44:03 -0000	1.324.2.1
+++ ChangeLog	17 Sep 2004 09:55:36 -0000
@@ -1,3 +1,39 @@
+2004-09-17  Rodrigo Moya <rodrigo novell com>
+
+	Fixes #59904
+
+	* libecal/e-cal-component.[ch] (e_cal_component_new_from_string): new
+	function to avoid repeating the same code over and over.
+
+	* libedata-cal/e-data-cal-view.c: changed to keep a list of listeners,
+	not only one.
+	(listener_died_cb): remove the listener from the list of listeners.
+	(impl_EDataCalView_start): see if the query has already been started,
+	and if so, just notify correctly the listeners we need to notify.
+	(e_data_cal_view_init): create hash table for storing the objects we
+	have matching the live query.
+	(e_data_cal_view_set_property): add correctly the listeners to the list.
+	(e_data_cal_view_get_property): return always the first listener.
+	(e_data_cal_view_finalize): free all listeners and cached objects.
+	(add_object_to_cache, remove_object_from_cache):
+	new functions to manage the matched objects cache.
+	(e_data_cal_view_notify_objects_added,
+	e_data_cal_view_notify_objects_modified): add objects to our private
+	cache, and notify all listeners, now that we might have more than one.
+	(e_data_cal_view_notify_objects_removed,
+	e_data_cal_view_notify_progress, e_data_cal_view_notify_done): notify
+	all listeners.
+	(e_data_cal_view_add_listener, e_data_cal_view_get_matched_objects,
+	e_data_cal_view_is_started, e_data_cal_view_is_done,
+	e_data_cal_view_get_done_status): new functions.
+
+	* libedata-cal/e-data-cal.c: keep a cache of all queries.
+	(impl_Cal_getQuery): first look in the cache of queries. And when
+	creating a new query, add it to the cache.
+	(impl_Cal_getObjectList): use the query cache also.
+	(e_data_cal_finalize): destroy the live queries hash table.
+	(e_data_cal_init): create live queries hash table.
+
 2004-09-08  Chenthill Palanisamy <pchenthill novell com>
 
 	* backends/groupwise/e-cal-backend-groupwise-utils.c
Index: libecal/e-cal-component.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libecal/e-cal-component.c,v
retrieving revision 1.9
diff -u -p -r1.9 e-cal-component.c
--- libecal/e-cal-component.c	16 Jul 2004 14:29:20 -0000	1.9
+++ libecal/e-cal-component.c	17 Sep 2004 09:55:38 -0000
@@ -437,6 +437,38 @@ e_cal_component_new (void)
 }
 
 /**
+ * e_cal_component_new_from_string:
+ * @calobj: A string representation of an iCalendar component.
+ *
+ * Creates a new calendar component object from the given string.
+ *
+ * Return value: A calendar component representing the given iCalendar string on
+ * success, NULL if there was an error.
+ **/
+ECalComponent *
+e_cal_component_new_from_string (const char *calobj)
+{
+	ECalComponent *comp;
+	icalcomponent *icalcomp;
+
+	g_return_val_if_fail (calobj != NULL, NULL);
+
+	icalcomp = icalparser_parse_string (calobj);
+	if (!icalcomp)
+		return NULL;
+
+	comp = e_cal_component_new ();
+	if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+		icalcomponent_free (icalcomp);
+		g_object_unref (comp);
+
+		return NULL;
+	}
+
+	return comp;
+}
+
+/**
  * e_cal_component_clone:
  * @comp: A calendar component object.
  *
Index: libecal/e-cal-component.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libecal/e-cal-component.h,v
retrieving revision 1.4
diff -u -p -r1.4 e-cal-component.h
--- libecal/e-cal-component.h	13 Jan 2004 13:14:58 -0000	1.4
+++ libecal/e-cal-component.h	17 Sep 2004 09:55:39 -0000
@@ -200,6 +200,8 @@ char *e_cal_component_gen_uid (void);
 
 ECalComponent *e_cal_component_new (void);
 
+ECalComponent *e_cal_component_new_from_string (const char *calobj);
+
 ECalComponent *e_cal_component_clone (ECalComponent *comp);
 
 void e_cal_component_set_new_vtype (ECalComponent *comp, ECalComponentVType type);
Index: libedata-cal/e-data-cal-view.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libedata-cal/e-data-cal-view.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 e-data-cal-view.c
--- libedata-cal/e-data-cal-view.c	3 Nov 2003 18:24:02 -0000	1.1.1.1
+++ libedata-cal/e-data-cal-view.c	17 Sep 2004 09:55:39 -0000
@@ -22,6 +22,7 @@
 #include <config.h>
 #endif
 
+#include <string.h>
 #include <glib.h>
 #include <bonobo/bonobo-exception.h>
 #include <libedataserver/e-component-listener.h>
@@ -30,14 +31,27 @@
 
 
 
+typedef struct {
+	GNOME_Evolution_Calendar_CalViewListener listener;
+	EComponentListener *component_listener;
+
+	gboolean notified_start;
+	gboolean notified_done;
+} ListenerData;
+
 /* Private part of the Query structure */
 struct _EDataCalViewPrivate {
 	/* The backend we are monitoring */
 	ECalBackend *backend;
 
+	gboolean started;
+	gboolean done;
+	GNOME_Evolution_Calendar_CallStatus done_status;
+
+	GHashTable *matched_objects;
+
 	/* The listener we report to */
-	GNOME_Evolution_Calendar_CalViewListener listener;
-	EComponentListener *component_listener;
+	GList *listeners;
 
 	/* Sexp that defines the query */
 	ECalBackendSExp *sexp;
@@ -69,18 +83,132 @@ enum props {
 
 
 static void
+add_object_to_cache (EDataCalView *query, const char *calobj)
+{
+	ECalComponent *comp;
+	char *real_uid;
+	const char *uid;
+	EDataCalViewPrivate *priv;
+
+	priv = query->priv;
+
+	comp = e_cal_component_new_from_string (calobj);
+	if (!comp)
+		return;
+
+	e_cal_component_get_uid (comp, &uid);
+	if (!uid || !*uid) {
+		g_object_unref (comp);
+		return;
+	}
+
+	if (e_cal_component_is_instance (comp))
+		real_uid = g_strdup_printf ("%s %s", uid, e_cal_component_get_recurid_as_string (comp));
+	else
+		real_uid = g_strdup (uid);
+
+	if (g_hash_table_lookup (priv->matched_objects, real_uid))
+		g_hash_table_replace (priv->matched_objects, real_uid, g_strdup (calobj));
+	else
+		g_hash_table_insert (priv->matched_objects, real_uid, g_strdup (calobj));
+
+	/* free memory */
+	g_object_unref (comp);
+}
+
+static gboolean
+uncache_with_uid_cb (gpointer key, gpointer value, gpointer user_data)
+{
+	ECalComponent *comp;
+	const char *this_uid;
+	char *uid, *object;
+
+	uid = user_data;
+	object = value;
+
+	comp = e_cal_component_new_from_string (object);
+	if (comp) {
+		e_cal_component_get_uid (comp, &this_uid);
+		if (this_uid && *this_uid && !strcmp (uid, this_uid)) {
+			g_object_unref (comp);
+			return TRUE;
+		}
+
+		g_object_unref (comp);
+	}
+
+	return FALSE;
+}
+
+static void
+remove_object_from_cache (EDataCalView *query, const char *uid)
+{
+	EDataCalViewPrivate *priv;
+
+	priv = query->priv;
+
+	g_hash_table_foreach_remove (priv->matched_objects, (GHRFunc) uncache_with_uid_cb, (gpointer) uid);
+}
+
+static void
 listener_died_cb (EComponentListener *cl, gpointer data)
 {
 	EDataCalView *query = QUERY (data);
 	EDataCalViewPrivate *priv;
+	GList *l;
 
 	priv = query->priv;
 
-	g_object_unref (priv->component_listener);
-	priv->component_listener = NULL;
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
+
+		if (ld->component_listener == cl) {
+			g_object_unref (ld->component_listener);
+			ld->component_listener = NULL;
 	
-	bonobo_object_release_unref (priv->listener, NULL);
-	priv->listener = NULL;
+			bonobo_object_release_unref (ld->listener, NULL);
+			ld->listener = NULL;
+
+			priv->listeners = g_list_remove_link (priv->listeners, l);
+			g_list_free (l);
+			g_free (ld);
+			break;
+		}
+	}
+}
+
+static void
+notify_matched_object_cb (gpointer key, gpointer value, gpointer user_data)
+{
+	char *uid, *object;
+	EDataCalView *query;
+	EDataCalViewPrivate *priv;
+	GList *l;
+
+	uid = key;
+	object = value;
+	query = user_data;
+	priv = query->priv;
+
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
+
+		if (!ld->notified_start) {
+			GNOME_Evolution_Calendar_stringlist obj_list;
+			CORBA_Environment ev;
+
+			obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (1);
+			obj_list._maximum = 1;
+			obj_list._length = 1;
+			obj_list._buffer[0] = CORBA_string_dup (object);
+
+			CORBA_exception_init (&ev);
+			GNOME_Evolution_Calendar_CalViewListener_notifyObjectsAdded (ld->listener, &obj_list, &ev);
+			CORBA_exception_free (&ev);
+
+			CORBA_free (obj_list._buffer);
+		}
+	}
 }
 
 static void
@@ -88,11 +216,46 @@ impl_EDataCalView_start (PortableServer_
 {
 	EDataCalView *query;
 	EDataCalViewPrivate *priv;
+	GList *l;
 
 	query = QUERY (bonobo_object_from_servant (servant));
 	priv = query->priv;
 
-	e_cal_backend_start_query (priv->backend, query);
+	if (priv->started) {
+		g_warning (G_STRLOC ": Query already started, notifying matched objects");
+		g_hash_table_foreach (priv->matched_objects, (GHFunc) notify_matched_object_cb, query);
+
+		/* notify all listeners correctly if the query is already done */
+		for (l = priv->listeners; l != NULL; l = l->next) {
+			ListenerData *ld = l->data;
+
+			if (!ld->notified_start) {
+				ld->notified_start = TRUE;
+
+				if (priv->done && !ld->notified_done) {
+					CORBA_Environment ev;
+
+					ld->notified_done = TRUE;
+
+					g_warning (G_STRLOC ": Query already done before, notifying new listener");
+					CORBA_exception_init (&ev);
+					GNOME_Evolution_Calendar_CalViewListener_notifyQueryDone (
+						ld->listener, priv->done_status, &ev);
+					CORBA_exception_free (&ev);
+				}
+			}
+		}
+	} else {
+		g_warning (G_STRLOC ": Starting new query");
+		priv->started = TRUE;
+		e_cal_backend_start_query (priv->backend, query);
+
+		for (l = priv->listeners; l != NULL; l = l->next) {
+			ListenerData *ld = l->data;
+
+			ld->notified_start = TRUE;
+		}
+	}
 }
 
 static void
@@ -100,7 +263,6 @@ e_data_cal_view_set_property (GObject *o
 {
 	EDataCalView *query;
 	EDataCalViewPrivate *priv;
-	CORBA_Environment ev;
 
 	query = QUERY (object);
 	priv = query->priv;
@@ -110,13 +272,7 @@ e_data_cal_view_set_property (GObject *o
 		priv->backend = E_CAL_BACKEND (g_value_dup_object (value));
 		break;
 	case PROP_LISTENER:
-		CORBA_exception_init (&ev);
-		priv->listener = CORBA_Object_duplicate (g_value_get_pointer (value), &ev);
-		CORBA_exception_free (&ev);
-
-		priv->component_listener = e_component_listener_new (priv->listener);
-		g_signal_connect (G_OBJECT (priv->component_listener), "component_died",
-				  G_CALLBACK (listener_died_cb), query);
+		e_data_cal_view_add_listener (query, g_value_get_pointer (value));
 		break;
 	case PROP_SEXP:
 		priv->sexp = E_CAL_BACKEND_SEXP (g_value_dup_object (value));
@@ -140,7 +296,13 @@ e_data_cal_view_get_property (GObject *o
 	case PROP_BACKEND:
 		g_value_set_object (value, priv->backend);
 	case PROP_LISTENER:
-		g_value_set_pointer (value, priv->listener);
+
+		if (priv->listeners) {
+			ListenerData *ld;
+
+			ld = priv->listeners->data;
+			g_value_set_pointer (value, ld->listener);
+		}
 		break;
 	case PROP_SEXP:
 		g_value_set_object (value, priv->sexp);
@@ -190,8 +352,11 @@ e_data_cal_view_init (EDataCalView *quer
 	query->priv = priv;
 
 	priv->backend = NULL;
-	priv->listener = NULL;
-	priv->component_listener = NULL;
+	priv->started = FALSE;
+	priv->done = FALSE;
+	priv->done_status = GNOME_Evolution_Calendar_Success;
+	priv->matched_objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	priv->listeners = NULL;
 	priv->sexp = NULL;
 }
 
@@ -211,11 +376,19 @@ e_data_cal_view_finalize (GObject *objec
 	if (priv->backend)
 		g_object_unref (priv->backend);
 
-	if (priv->listener != NULL)
-		bonobo_object_release_unref (priv->listener, NULL);
+	while (priv->listeners) {
+		ListenerData *ld = priv->listeners->data;
+
+		if (ld->listener)
+			bonobo_object_release_unref (ld->listener, NULL);
+		if (ld->component_listener)
+			g_object_unref (ld->component_listener);
+		priv->listeners = g_list_remove (priv->listeners, ld);
+		g_free (ld);
+	}
 
-	if (priv->component_listener != NULL)
-		g_object_unref (priv->component_listener);
+	if (priv->matched_objects)
+		g_hash_table_destroy (priv->matched_objects);
 
 	if (priv->sexp)
 		g_object_unref (priv->sexp);
@@ -238,8 +411,8 @@ e_data_cal_view_finalize (GObject *objec
  **/
 EDataCalView *
 e_data_cal_view_new (ECalBackend *backend,
-	   GNOME_Evolution_Calendar_CalViewListener ql,
-	   ECalBackendSExp *sexp)
+		     GNOME_Evolution_Calendar_CalViewListener ql,
+		     ECalBackendSExp *sexp)
 {
 	EDataCalView *query;
 
@@ -250,6 +423,40 @@ e_data_cal_view_new (ECalBackend *backen
 }
 
 /**
+ * e_data_cal_view_add_listener:
+ * @query: A #EDataCalView object.
+ * @ql: A CORBA query listener to add to the list of listeners.
+ *
+ * Adds the given CORBA listener to a #EDataCalView object. This makes the view
+ * object notify that listener when notifying the other listeners already attached
+ * to the view.
+ */
+void
+e_data_cal_view_add_listener (EDataCalView *query, GNOME_Evolution_Calendar_CalViewListener ql)
+{
+	ListenerData *ld;
+	EDataCalViewPrivate *priv;
+	CORBA_Environment ev;
+
+	g_return_if_fail (IS_QUERY (query));
+	g_return_if_fail (ql != CORBA_OBJECT_NIL);
+
+	priv = query->priv;
+
+	ld = g_new0 (ListenerData, 1);
+
+	CORBA_exception_init (&ev);
+	ld->listener = CORBA_Object_duplicate (ql, &ev);
+	CORBA_exception_free (&ev);
+
+	ld->component_listener = e_component_listener_new (ld->listener);
+	g_signal_connect (G_OBJECT (ld->component_listener), "component_died",
+			  G_CALLBACK (listener_died_cb), query);
+
+	priv->listeners = g_list_prepend (priv->listeners, ld);
+}
+
+/**
  * e_data_cal_view_get_sexp
  * @query: A #EDataCalView object.
  *
@@ -287,6 +494,68 @@ e_data_cal_view_object_matches (EDataCal
 	return e_cal_backend_sexp_match_object (priv->sexp, object, priv->backend);
 }
 
+static void
+add_object_to_list (gpointer key, gpointer value, gpointer user_data)
+{
+	GList **list = user_data;
+
+	*list = g_list_append (*list, value);
+}
+
+GList *
+e_data_cal_view_get_matched_objects (EDataCalView *query)
+{
+	EDataCalViewPrivate *priv;
+	GList *list = NULL;
+
+	g_return_val_if_fail (IS_QUERY (query), NULL);
+
+	priv = query->priv;
+
+	g_hash_table_foreach (priv->matched_objects, (GHFunc) add_object_to_list, &list);
+
+	return list;
+}
+
+gboolean
+e_data_cal_view_is_started (EDataCalView *query)
+{
+	EDataCalViewPrivate *priv;
+
+	g_return_val_if_fail (IS_QUERY (query), FALSE);
+
+	priv = query->priv;
+
+	return priv->started;
+}
+
+gboolean
+e_data_cal_view_is_done (EDataCalView *query)
+{
+	EDataCalViewPrivate *priv;
+
+	g_return_val_if_fail (IS_QUERY (query), FALSE);
+
+	priv = query->priv;
+
+	return priv->done;
+}
+
+GNOME_Evolution_Calendar_CallStatus
+e_data_cal_view_get_done_status (EDataCalView *query)
+{
+	EDataCalViewPrivate *priv;
+
+	g_return_val_if_fail (IS_QUERY (query), FALSE);
+
+	priv = query->priv;
+
+	if (priv->done)
+		return priv->done_status;
+
+	return GNOME_Evolution_Calendar_Success;
+}
+
 void
 e_data_cal_view_notify_objects_added (EDataCalView *query, const GList *objects)
 {
@@ -300,26 +569,36 @@ e_data_cal_view_notify_objects_added (ED
 	g_return_if_fail (IS_QUERY (query));
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
-	
-	CORBA_exception_init (&ev);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	num_objs = g_list_length ((GList*)objects);
+	if (num_objs <= 0)
+		return;
+
 	obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (num_objs);
 	obj_list._maximum = num_objs;
 	obj_list._length = num_objs;
 
-	for (l = objects, i = 0; l; l = l->next, i++)
+	for (l = objects, i = 0; l; l = l->next, i++) {
 		obj_list._buffer[i] = CORBA_string_dup (l->data);
 
-	GNOME_Evolution_Calendar_CalViewListener_notifyObjectsAdded (priv->listener, &obj_list, &ev);
+		/* update our cache */
+		add_object_to_cache (query, l->data);
+	}
 
-	CORBA_free (obj_list._buffer);
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
 
-	if (BONOBO_EX (&ev))
-		g_warning (G_STRLOC ": could not notify the listener of object addition");
+		CORBA_exception_init (&ev);
 
-	CORBA_exception_free (&ev);
+		GNOME_Evolution_Calendar_CalViewListener_notifyObjectsAdded (ld->listener, &obj_list, &ev);
+		if (BONOBO_EX (&ev))
+			g_warning (G_STRLOC ": could not notify the listener of object addition");
+
+		CORBA_exception_free (&ev);
+	}
+
+	CORBA_free (obj_list._buffer);
 }
 
 void
@@ -330,9 +609,10 @@ e_data_cal_view_notify_objects_added_1 (
 	
 	g_return_if_fail (query != NULL);
 	g_return_if_fail (IS_QUERY (query));
+	g_return_if_fail (object != NULL);
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	objects.next = objects.prev = NULL;
 	objects.data = (gpointer)object;
@@ -353,26 +633,36 @@ e_data_cal_view_notify_objects_modified 
 	g_return_if_fail (IS_QUERY (query));
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
-	
-	CORBA_exception_init (&ev);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	num_objs = g_list_length ((GList*)objects);
+	if (num_objs <= 0)
+		return;
+
 	obj_list._buffer = GNOME_Evolution_Calendar_stringlist_allocbuf (num_objs);
 	obj_list._maximum = num_objs;
 	obj_list._length = num_objs;
 
-	for (l = objects, i = 0; l; l = l->next, i++)
+	for (l = objects, i = 0; l; l = l->next, i++) {
 		obj_list._buffer[i] = CORBA_string_dup (l->data);
 
-	GNOME_Evolution_Calendar_CalViewListener_notifyObjectsModified (priv->listener, &obj_list, &ev);
+		/* update our cache */
+		add_object_to_cache (query, l->data);
+	}
 
-	CORBA_free (obj_list._buffer);
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
 
-	if (BONOBO_EX (&ev))
-		g_warning (G_STRLOC ": could not notify the listener of object modification");
+		CORBA_exception_init (&ev);
 
-	CORBA_exception_free (&ev);
+		GNOME_Evolution_Calendar_CalViewListener_notifyObjectsModified (ld->listener, &obj_list, &ev);
+		if (BONOBO_EX (&ev))
+			g_warning (G_STRLOC ": could not notify the listener of object modification");
+
+		CORBA_exception_free (&ev);
+	}
+
+	CORBA_free (obj_list._buffer);
 }
 
 void
@@ -383,9 +673,10 @@ e_data_cal_view_notify_objects_modified_
 	
 	g_return_if_fail (query != NULL);
 	g_return_if_fail (IS_QUERY (query));
+	g_return_if_fail (object != NULL);
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	objects.next = objects.prev = NULL;
 	objects.data = (gpointer)object;
@@ -406,27 +697,36 @@ e_data_cal_view_notify_objects_removed (
 	g_return_if_fail (IS_QUERY (query));
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
-	
-	CORBA_exception_init (&ev);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	num_uids = g_list_length ((GList*)uids);
+	if (num_uids <= 0)
+		return;
+
 	uid_list._buffer = GNOME_Evolution_Calendar_CalObjUIDSeq_allocbuf (num_uids);
 	uid_list._maximum = num_uids;
 	uid_list._length = num_uids;
 
-	for (l = uids, i = 0; l; l = l->next, i ++)
+	for (l = uids, i = 0; l; l = l->next, i ++) {
 		uid_list._buffer[i] = CORBA_string_dup (l->data);
 
-	GNOME_Evolution_Calendar_CalViewListener_notifyObjectsRemoved (priv->listener, &uid_list, &ev);
+		/* update our cache */
+		remove_object_from_cache (query, l->data);
+	}
 
-	CORBA_free (uid_list._buffer);
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
 
-	if (BONOBO_EX (&ev))
-		g_warning (G_STRLOC ": could not notify the listener of object removal");
+		CORBA_exception_init (&ev);
 
+		GNOME_Evolution_Calendar_CalViewListener_notifyObjectsRemoved (ld->listener, &uid_list, &ev);
+		if (BONOBO_EX (&ev))
+			g_warning (G_STRLOC ": could not notify the listener of object removal");
 
-	CORBA_exception_free (&ev);
+		CORBA_exception_free (&ev);
+	}
+
+	CORBA_free (uid_list._buffer);
 }
 
 void
@@ -437,9 +737,10 @@ e_data_cal_view_notify_objects_removed_1
 	
 	g_return_if_fail (query != NULL);
 	g_return_if_fail (IS_QUERY (query));
+	g_return_if_fail (uid != NULL);
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	uids.next = uids.prev = NULL;
 	uids.data = (gpointer)uid;
@@ -452,21 +753,25 @@ e_data_cal_view_notify_progress (EDataCa
 {
 	EDataCalViewPrivate *priv;	
 	CORBA_Environment ev;
+	GList *l;
 
 	g_return_if_fail (query != NULL);
 	g_return_if_fail (IS_QUERY (query));
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
-	
-	CORBA_exception_init (&ev);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
-	GNOME_Evolution_Calendar_CalViewListener_notifyQueryProgress (priv->listener, message, percent, &ev);
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
 
-	if (BONOBO_EX (&ev))
-		g_warning (G_STRLOC ": could not notify the listener of query progress");
+		CORBA_exception_init (&ev);
 
-	CORBA_exception_free (&ev);
+		GNOME_Evolution_Calendar_CalViewListener_notifyQueryProgress (ld->listener, message, percent, &ev);
+		if (BONOBO_EX (&ev))
+			g_warning (G_STRLOC ": could not notify the listener of query progress");
+
+		CORBA_exception_free (&ev);
+	}
 }
 
 void
@@ -474,19 +779,26 @@ e_data_cal_view_notify_done (EDataCalVie
 {
 	EDataCalViewPrivate *priv;	
 	CORBA_Environment ev;
+	GList *l;
 
 	g_return_if_fail (query != NULL);
 	g_return_if_fail (IS_QUERY (query));
 
 	priv = query->priv;
-	g_return_if_fail (priv->listener != CORBA_OBJECT_NIL);
-	
-	CORBA_exception_init (&ev);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
-	GNOME_Evolution_Calendar_CalViewListener_notifyQueryDone (priv->listener, status, &ev);
+	priv->done = TRUE;
+	priv->done_status = status;
 
-	if (BONOBO_EX (&ev))
-		g_warning (G_STRLOC ": could not notify the listener of query completion");
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
 
-	CORBA_exception_free (&ev);
+		CORBA_exception_init (&ev);
+
+		GNOME_Evolution_Calendar_CalViewListener_notifyQueryDone (ld->listener, status, &ev);
+		if (BONOBO_EX (&ev))
+			g_warning (G_STRLOC ": could not notify the listener of query completion");
+
+		CORBA_exception_free (&ev);
+	}
 }
Index: libedata-cal/e-data-cal-view.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libedata-cal/e-data-cal-view.h,v
retrieving revision 1.3
diff -u -p -r1.3 e-data-cal-view.h
--- libedata-cal/e-data-cal-view.h	6 Nov 2003 00:33:17 -0000	1.3
+++ libedata-cal/e-data-cal-view.h	17 Sep 2004 09:55:39 -0000
@@ -52,29 +52,36 @@ struct _EDataCalViewClass {
 };
 
 GType                 e_data_cal_view_get_type (void);
-EDataCalView                *e_data_cal_view_new (ECalBackend                             *backend,
-				 GNOME_Evolution_Calendar_CalViewListener  ql,
-				 ECalBackendSExp                   *sexp);
+EDataCalView         *e_data_cal_view_new (ECalBackend                             *backend,
+					   GNOME_Evolution_Calendar_CalViewListener  ql,
+					   ECalBackendSExp                   *sexp);
+void                  e_data_cal_view_add_listener (EDataCalView *query, GNOME_Evolution_Calendar_CalViewListener ql);
 const char           *e_data_cal_view_get_text (EDataCalView *query);
-ECalBackendSExp *e_data_cal_view_get_object_sexp (EDataCalView *query);
-gboolean e_data_cal_view_object_matches (EDataCalView *query, const char *object);
+ECalBackendSExp      *e_data_cal_view_get_object_sexp (EDataCalView *query);
+gboolean              e_data_cal_view_object_matches (EDataCalView *query, const char *object);
+
+GList                *e_data_cal_view_get_matched_objects (EDataCalView *query);
+gboolean              e_data_cal_view_is_started (EDataCalView *query);
+gboolean              e_data_cal_view_is_done (EDataCalView *query);
+GNOME_Evolution_Calendar_CallStatus e_data_cal_view_get_done_status (EDataCalView *query);
+
 void                  e_data_cal_view_notify_objects_added (EDataCalView       *query,
-						  const GList *objects);
+							    const GList *objects);
 void                  e_data_cal_view_notify_objects_added_1 (EDataCalView       *query,
-						    const char *object);
+							      const char *object);
 void                  e_data_cal_view_notify_objects_modified (EDataCalView       *query,
-						     const GList *objects);
+							       const GList *objects);
 void                  e_data_cal_view_notify_objects_modified_1 (EDataCalView       *query,
-						     const char *object);
+								 const char *object);
 void                  e_data_cal_view_notify_objects_removed (EDataCalView       *query,
-						    const GList *uids);
+							      const GList *uids);
 void                  e_data_cal_view_notify_objects_removed_1 (EDataCalView       *query,
-						    const char *uid);
+								const char *uid);
 void                  e_data_cal_view_notify_progress (EDataCalView      *query,
-						   const char *message,
-						   int         percent);
+						       const char *message,
+						       int         percent);
 void                  e_data_cal_view_notify_done (EDataCalView                               *query,
-					       GNOME_Evolution_Calendar_CallStatus status);
+						   GNOME_Evolution_Calendar_CallStatus status);
 
 G_END_DECLS
 
Index: libedata-cal/e-data-cal.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/libedata-cal/e-data-cal.c,v
retrieving revision 1.8
diff -u -p -r1.8 e-data-cal.c
--- libedata-cal/e-data-cal.c	23 Apr 2004 20:24:19 -0000	1.8
+++ libedata-cal/e-data-cal.c	17 Sep 2004 09:55:39 -0000
@@ -41,6 +41,9 @@ struct _EDataCalPrivate {
 
 	/* Listener on the client we notify */
 	GNOME_Evolution_Calendar_CalListener listener;
+
+	/* Cache of live queries */
+	GHashTable *live_queries;
 };
 
 /* Cal::get_uri method */
@@ -205,19 +208,32 @@ impl_Cal_getObject (PortableServer_Serva
 	e_cal_backend_get_object (priv->backend, cal, uid, rid);
 }
 
-/* Cal::getObjectsInRange method */
+/* Cal::getObjectList method */
 static void
 impl_Cal_getObjectList (PortableServer_Servant servant,
-			const CORBA_char *query,
+			const CORBA_char *sexp,
 			CORBA_Environment *ev)
 {
 	EDataCal *cal;
 	EDataCalPrivate *priv;
+	EDataCalView *query;
 	
 	cal = E_DATA_CAL (bonobo_object_from_servant (servant));
 	priv = cal->priv;
 
-	e_cal_backend_get_object_list (priv->backend, cal, query);
+	query = g_hash_table_lookup (priv->live_queries, sexp);
+	if (query) {
+		GList *matched_objects;
+
+		matched_objects = e_data_cal_view_get_matched_objects (query);
+		e_data_cal_notify_object_list (
+			cal,
+			e_data_cal_view_is_done (query) ? e_data_cal_view_get_done_status (query) : GNOME_Evolution_Calendar_Success,
+			matched_objects);
+
+		g_list_free (matched_objects);
+	} else
+		e_cal_backend_get_object_list (priv->backend, cal, sexp);
 }
 
 /* Cal::getChanges method */
@@ -368,8 +384,16 @@ impl_Cal_getQuery (PortableServer_Servan
 	cal = E_DATA_CAL (bonobo_object_from_servant (servant));
 	priv = cal->priv;
 
+	/* first see if we already have the query in the cache */
+	query = g_hash_table_lookup (priv->live_queries, sexp);
+	if (query) {
+		e_data_cal_view_add_listener (query, ql);
+		e_data_cal_notify_query (cal, GNOME_Evolution_Calendar_Success, query);
+		return;
+	}
+
 	/* we handle this entirely here, since it doesn't require any
-	   backend involvement now that we have pas_book_view_start to
+	   backend involvement now that we have e_cal_view_start to
 	   actually kick off the search. */
 
 	obj_sexp = e_cal_backend_sexp_new (sexp);
@@ -387,11 +411,10 @@ impl_Cal_getQuery (PortableServer_Servan
 		return;
 	}
 
+	g_hash_table_insert (priv->live_queries, g_strdup (sexp), query);
 	e_cal_backend_add_query (priv->backend, query);
 
 	e_data_cal_notify_query (cal, GNOME_Evolution_Calendar_Success, query);
-
-	g_object_unref (query);
 }
 
 
@@ -538,7 +561,7 @@ e_data_cal_get_listener (EDataCal *cal)
 
 /* Destroy handler for the calendar */
 static void
-cal_finalize (GObject *object)
+e_data_cal_finalize (GObject *object)
 {
 	EDataCal *cal;
 	EDataCalPrivate *priv;
@@ -560,6 +583,9 @@ cal_finalize (GObject *object)
 	priv->listener = NULL;
 	CORBA_exception_free (&ev);
 
+	g_hash_table_destroy (priv->live_queries);
+	priv->live_queries = NULL;
+
 	g_free (priv);
 
 	if (G_OBJECT_CLASS (parent_class)->finalize)
@@ -578,7 +604,7 @@ e_data_cal_class_init (EDataCalClass *kl
 	parent_class = g_type_class_peek_parent (klass);
 
 	/* Class method overrides */
-	object_class->finalize = cal_finalize;
+	object_class->finalize = e_data_cal_finalize;
 
 	/* Epv methods */
 	epv->_get_uri = impl_Cal_get_uri;
@@ -618,6 +644,9 @@ e_data_cal_init (EDataCal *cal, EDataCal
 	cal->priv = priv;
 
 	priv->listener = CORBA_OBJECT_NIL;
+	priv->live_queries = g_hash_table_new_full (g_str_hash, g_str_equal,
+						    (GDestroyNotify) g_free,
+						    (GDestroyNotify) g_object_unref);
 }
 
 BONOBO_TYPE_FUNC_FULL (EDataCal, GNOME_Evolution_Calendar_Cal, PARENT_TYPE, e_data_cal);


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