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



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 DVD calendar makes things still a bit slow, but that seems to be
entirely on the GUI part.

I guess this patch should go in, if accepted, after the release, so that
we can really test it enough. It is working well for me when using other
calendars than the DVD one.
-- 
Rodrigo Moya <rodrigo novell com>
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/calendar/ChangeLog,v
retrieving revision 1.308
diff -u -p -r1.308 ChangeLog
--- ChangeLog	10 Aug 2004 15:19:44 -0000	1.308
+++ ChangeLog	13 Aug 2004 12:01:24 -0000
@@ -1,3 +1,54 @@
+2004-08-13  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): new function.
+
+	* 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.
+	(e_data_cal_finalize): destroy the live queries hash table.
+	(e_data_cal_init): create live queries hash table.
+
 2004-08-09  Jeffrey Stedfast  <fejj novell com>
 
 	Fixes bug #58150
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	13 Aug 2004 12:01:26 -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	13 Aug 2004 12:01:26 -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	13 Aug 2004 12:01:27 -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.
  *
@@ -300,26 +507,33 @@ 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);
 	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
@@ -332,7 +546,7 @@ e_data_cal_view_notify_objects_added_1 (
 	g_return_if_fail (IS_QUERY (query));
 
 	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 +567,33 @@ 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);
 	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
@@ -385,7 +606,7 @@ 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);
+	g_return_if_fail (priv->listeners != CORBA_OBJECT_NIL);
 
 	objects.next = objects.prev = NULL;
 	objects.data = (gpointer)object;
@@ -406,9 +627,7 @@ 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);
 	uid_list._buffer = GNOME_Evolution_Calendar_CalObjUIDSeq_allocbuf (num_uids);
@@ -418,15 +637,19 @@ e_data_cal_view_notify_objects_removed (
 	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);
+	for (l = priv->listeners; l != NULL; l = l->next) {
+		ListenerData *ld = l->data;
 
-	CORBA_free (uid_list._buffer);
+		CORBA_exception_init (&ev);
 
-	if (BONOBO_EX (&ev))
-		g_warning (G_STRLOC ": could not notify the listener of object removal");
+		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
@@ -439,7 +662,7 @@ e_data_cal_view_notify_objects_removed_1
 	g_return_if_fail (IS_QUERY (query));
 
 	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 +675,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 +701,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	13 Aug 2004 12:01:27 -0000
@@ -52,29 +52,30 @@ 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);
 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	13 Aug 2004 12:01:27 -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 */
@@ -368,8 +371,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 +398,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 +548,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 +570,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 +591,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 +631,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]