[evolution-data-server/treitter-factory-refactor] Factor out common EDataView code from EDataCalView and EDataBookView



commit 3671f9599bdf63d46bcba4fc405e772338f4a171
Author: Travis Reitter <treitter gmail com>
Date:   Tue Jan 26 09:35:03 2010 -0800

    Factor out common EDataView code from EDataCalView and EDataBookView

 addressbook/libedata-book/e-data-book-view.c |  195 +++++------------
 calendar/libedata-cal/e-data-cal-view.c      |  299 ++++++-------------------
 libebackend/e-data-view.c                    |  288 ++++++++++++++++++++++++-
 libebackend/e-data-view.h                    |   48 ++++-
 4 files changed, 458 insertions(+), 372 deletions(-)
---
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 5b715a7..46aaf0e 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -35,13 +35,9 @@ static gboolean impl_BookView_dispose (EDataBookView *view, GError **eror);
 
 #include "e-data-book-view-glue.h"
 
-static void reset_array (GArray *array);
-
 G_DEFINE_TYPE (EDataBookView, e_data_book_view, E_TYPE_DATA_VIEW);
 #define E_DATA_BOOK_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_BOOK_VIEW, EDataBookViewPrivate))
 
-#define THRESHOLD 32
-
 struct _EDataBookViewPrivate {
 	gchar* query;
 	gint max_results;
@@ -50,11 +46,6 @@ struct _EDataBookViewPrivate {
 
 	GMutex *pending_mutex;
 
-	GArray *adds;
-	GArray *changes;
-	GArray *removes;
-
-	GHashTable *ids;
 	guint idle_id;
 };
 
@@ -70,6 +61,7 @@ enum {
 	CONTACTS_REMOVED,
 	STATUS_MESSAGE,
 	COMPLETE,
+	DONE,
 	LAST_SIGNAL
 };
 
@@ -91,104 +83,24 @@ e_data_book_view_stop_if_running (EDataBookView *view)
 }
 
 static void
-send_pending_adds (EDataBookView *view)
-{
-	EDataBookViewPrivate *priv = view->priv;
-
-	if (priv->adds->len == 0)
-		return;
-
-	g_signal_emit (view, signals[CONTACTS_ADDED], 0, priv->adds->data);
-	reset_array (priv->adds);
-}
-
-static void
-send_pending_changes (EDataBookView *view)
-{
-	EDataBookViewPrivate *priv = view->priv;
-
-	if (priv->changes->len == 0)
-		return;
-
-	g_signal_emit (view, signals[CONTACTS_CHANGED], 0, priv->changes->data);
-	reset_array (priv->changes);
-}
-
-static void
-send_pending_removes (EDataBookView *view)
-{
-	EDataBookViewPrivate *priv = view->priv;
-
-	if (priv->removes->len == 0)
-		return;
-
-	g_signal_emit (view, signals[CONTACTS_REMOVED], 0, priv->removes->data);
-	reset_array (priv->removes);
-}
-
-/*
- * Queue @vcard to be sent as a change notification. This takes ownership of
- * @vcard.
- */
-static void
-notify_change (EDataBookView *view, gchar *vcard)
-{
-	EDataBookViewPrivate *priv = view->priv;
-	send_pending_adds (view);
-	send_pending_removes (view);
-
-	g_array_append_val (priv->changes, vcard);
-}
-
-/*
- * Queue @id to be sent as a change notification. This takes ownership of @id.
- */
-static void
-notify_remove (EDataBookView *view, gchar *id)
+contacts_added (EDataView    *view,
+		const gchar **objects)
 {
-	EDataBookViewPrivate *priv = view->priv;
-
-	send_pending_adds (view);
-	send_pending_changes (view);
-
-	g_array_append_val (priv->removes, id);
-	g_hash_table_remove (priv->ids, id);
+	g_signal_emit (view, signals[CONTACTS_ADDED], 0, objects);
 }
 
-/*
- * Queue @id and @vcard to be sent as a change notification. This takes ownership of
- * @vcard but not @id.
- */
 static void
-notify_add (EDataBookView *view, const gchar *id, gchar *vcard)
+contacts_changed (EDataView    *view,
+		  const gchar **objects)
 {
-	EDataBookViewPrivate *priv = view->priv;
-	send_pending_changes (view);
-	send_pending_removes (view);
-
-	if (priv->adds->len == THRESHOLD) {
-		send_pending_adds (view);
-	}
-	g_array_append_val (priv->adds, vcard);
-	g_hash_table_insert (priv->ids, g_strdup (id),
-			     GUINT_TO_POINTER (1));
+	g_signal_emit (view, signals[CONTACTS_CHANGED], 0, objects);
 }
 
 static void
-reset_array (GArray *array)
+contacts_removed (EDataView    *view,
+		  const gchar **ids)
 {
-	gint i = 0;
-	gchar *tmp = NULL;
-
-	/* Free stored strings */
-	for (i = 0; i < array->len; i++)
-		{
-			tmp = g_array_index (array, gchar *, i);
-			g_free (tmp);
-		}
-
-	/* Force the array size to 0 */
-	g_array_set_size (array, 0);
+	g_signal_emit (view, signals[CONTACTS_REMOVED], 0, ids);
 }
 
 /**
@@ -219,8 +131,7 @@ e_data_book_view_notify_update (EDataBookView *book_view,
 
 	id = e_contact_get_const (contact, E_CONTACT_UID);
 
-	currently_in_view =
-		g_hash_table_lookup (priv->ids, id) != NULL;
+	currently_in_view = e_data_view_contains_object (E_DATA_VIEW (book_view), (gpointer) id);
 
 	sexp = E_BOOK_BACKEND_SEXP (e_data_view_get_sexp (E_DATA_VIEW (book_view)));
 	want_in_view =
@@ -230,13 +141,15 @@ e_data_book_view_notify_update (EDataBookView *book_view,
 		vcard = e_vcard_to_string (E_VCARD (contact),
 					   EVC_FORMAT_VCARD_30);
 
-		if (currently_in_view)
-			notify_change (book_view, vcard);
-		else
-			notify_add (book_view, id, vcard);
+		if (currently_in_view) {
+			e_data_view_notify_object_modification (E_DATA_VIEW (book_view), vcard);
+		} else {
+			e_data_view_notify_object_add (E_DATA_VIEW (book_view), (gpointer) g_strdup (id), vcard);
+		}
 	} else {
-		if (currently_in_view)
-			notify_remove (book_view, g_strdup (id));
+		if (currently_in_view) {
+			e_data_view_notify_object_remove (E_DATA_VIEW (book_view), (gpointer) id);
+		}
 		/* else nothing; we're removing a card that wasn't there */
 	}
 
@@ -272,24 +185,27 @@ e_data_book_view_notify_update_vcard (EDataBookView *book_view, gchar *vcard)
 
 	contact = e_contact_new_from_vcard (vcard);
 	id = e_contact_get_const (contact, E_CONTACT_UID);
-	currently_in_view =
-		g_hash_table_lookup (priv->ids, id) != NULL;
+	currently_in_view = e_data_view_contains_object (E_DATA_VIEW (book_view), (gpointer) id);
 
 	sexp = E_BOOK_BACKEND_SEXP (e_data_view_get_sexp (E_DATA_VIEW (book_view)));
 	want_in_view =
 		e_book_backend_sexp_match_contact (sexp, contact);
 
 	if (want_in_view) {
-		if (currently_in_view)
-			notify_change (book_view, vcard);
-		else
-			notify_add (book_view, id, vcard);
+		if (currently_in_view) {
+			e_data_view_notify_object_modification (E_DATA_VIEW (book_view), vcard);
+		} else {
+			e_data_view_notify_object_add (E_DATA_VIEW (book_view), (gpointer) g_strdup (id), vcard);
+		}
 	} else {
-		if (currently_in_view)
-			notify_remove (book_view, g_strdup (id));
-		else
+		if (currently_in_view) {
+			e_data_view_notify_object_remove (E_DATA_VIEW (book_view), (gpointer) id);
+		} else {
 			/* else nothing; we're removing a card that wasn't there */
+			/* FIXME: this seems to not have been intended to be
+			 * included in this else block, but it was */
 			g_free (vcard);
+		}
 	}
 	/* Do this last so that id is still valid when notify_ is called */
 	g_object_unref (contact);
@@ -328,13 +244,13 @@ e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view, cons
 
 	g_mutex_lock (priv->pending_mutex);
 
-	currently_in_view =
-		g_hash_table_lookup (priv->ids, id) != NULL;
+	currently_in_view = e_data_view_contains_object (E_DATA_VIEW (book_view), (gpointer) id);
 
-	if (currently_in_view)
-		notify_change (book_view, vcard);
-	else
-		notify_add (book_view, id, vcard);
+	if (currently_in_view) {
+		e_data_view_notify_object_modification (E_DATA_VIEW (book_view), vcard);
+	} else {
+		e_data_view_notify_object_add (E_DATA_VIEW (book_view), (gpointer) g_strdup (id), vcard);
+	}
 
 	g_mutex_unlock (priv->pending_mutex);
 }
@@ -357,8 +273,9 @@ e_data_book_view_notify_remove (EDataBookView *book_view, const gchar *id)
 
 	g_mutex_lock (priv->pending_mutex);
 
-	if (g_hash_table_lookup (priv->ids, id))
-		notify_remove (book_view, g_strdup (id));
+	if (e_data_view_contains_object (E_DATA_VIEW (book_view), (gpointer) id)) {
+		e_data_view_notify_object_remove (E_DATA_VIEW (book_view), (gpointer) id);
+	}
 
 	g_mutex_unlock (priv->pending_mutex);
 }
@@ -382,15 +299,17 @@ e_data_book_view_notify_complete (EDataBookView *book_view, EDataBookStatus stat
 
 	g_mutex_lock (priv->pending_mutex);
 
-	send_pending_adds (book_view);
-	send_pending_changes (book_view);
-	send_pending_removes (book_view);
+	e_data_view_send_pending_adds (E_DATA_VIEW (book_view));
+	e_data_view_send_pending_modifications (E_DATA_VIEW (book_view));
+	e_data_view_send_pending_removes (E_DATA_VIEW (book_view));
 
 	g_mutex_unlock (priv->pending_mutex);
 
 	/* We're done now, so tell the backend to stop?  TODO: this is a bit different to
 	   how the CORBA backend works... */
 
+	e_data_view_notify_done (E_DATA_VIEW (book_view), status);
+	/* retained for backwards compatibility */
 	g_signal_emit (book_view, signals[COMPLETE], 0, status);
 }
 
@@ -457,19 +376,9 @@ e_data_book_view_finalize (GObject *object)
 	EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
 	EDataBookViewPrivate *priv = book_view->priv;
 
-	reset_array (priv->adds);
-	reset_array (priv->changes);
-	reset_array (priv->removes);
-	g_array_free (priv->adds, TRUE);
-	g_array_free (priv->changes, TRUE);
-	g_array_free (priv->removes, TRUE);
-
 	g_free (priv->query);
-
 	g_mutex_free (priv->pending_mutex);
 
-	g_hash_table_destroy (priv->ids);
-
 	G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
 }
 
@@ -531,6 +440,9 @@ e_data_book_view_class_init (EDataBookViewClass *klass)
 	object_class->set_property = e_data_book_view_set_property;
 
 	parent_class->stop_if_running = (void (*)(EDataView*)) e_data_book_view_stop_if_running;
+	parent_class->objects_added = contacts_added;
+	parent_class->objects_modified = contacts_changed;
+	parent_class->objects_removed = contacts_removed;
 
 	signals[CONTACTS_ADDED] =
 		g_signal_new ("contacts-added",
@@ -564,6 +476,8 @@ e_data_book_view_class_init (EDataBookViewClass *klass)
 			      g_cclosure_marshal_VOID__STRING,
 			      G_TYPE_NONE, 1, G_TYPE_STRING);
 
+	/* this is meant to do the same thing as "done", but existed before it,
+	 * so it's retained for compatibility */
 	signals[COMPLETE] =
 		g_signal_new ("complete",
 			      G_OBJECT_CLASS_TYPE (klass),
@@ -572,6 +486,8 @@ e_data_book_view_class_init (EDataBookViewClass *klass)
 			      g_cclosure_marshal_VOID__UINT,
 			      G_TYPE_NONE, 1, G_TYPE_UINT);
 
+	signals[DONE] = g_signal_lookup ("done", E_TYPE_DATA_VIEW);
+
         g_object_class_install_property
                 (object_class,
                  PROP_MAX_RESULTS,
@@ -607,13 +523,6 @@ e_data_book_view_init (EDataBookView *book_view)
 
 	priv->running = FALSE;
 	priv->pending_mutex = g_mutex_new ();
-
-	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-	priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-
-	priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal,
-					   g_free, NULL);
 }
 
 static gboolean
diff --git a/calendar/libedata-cal/e-data-cal-view.c b/calendar/libedata-cal/e-data-cal-view.c
index 0120fc8..1f8cd96 100644
--- a/calendar/libedata-cal/e-data-cal-view.c
+++ b/calendar/libedata-cal/e-data-cal-view.c
@@ -46,29 +46,19 @@ static gboolean impl_EDataCalView_start (EDataCalView *query, GError **error);
 
 struct _EDataCalViewPrivate {
 	gboolean started;
-	gboolean done;
-	EDataCalCallStatus done_status;
-
-	GArray *adds;
-	GArray *changes;
-	GArray *removes;
-
-	GHashTable *ids;
 };
 
 G_DEFINE_TYPE (EDataCalView, e_data_cal_view, E_TYPE_DATA_VIEW);
 #define E_DATA_CAL_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_DATA_CAL_VIEW_TYPE, EDataCalViewPrivate))
 
-static void e_data_cal_view_finalize (GObject *object);
-
 /* Signals */
 enum {
-  OBJECTS_ADDED,
-  OBJECTS_MODIFIED,
-  OBJECTS_REMOVED,
-  PROGRESS,
-  DONE,
-  LAST_SIGNAL
+	OBJECTS_ADDED,
+	OBJECTS_MODIFIED,
+	OBJECTS_REMOVED,
+	PROGRESS,
+	DONE,
+	LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -79,6 +69,43 @@ e_data_cal_view_stop_if_running (EDataCalView *query)
 	/* Nothing for us to do here */
 }
 
+static void
+e_data_cal_view_finalize (GObject *object)
+{
+	EDataCalView *query;
+	EDataCalViewPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (IS_QUERY (object));
+
+	query = QUERY (object);
+	priv = query->priv;
+
+	(* G_OBJECT_CLASS (e_data_cal_view_parent_class)->finalize) (object);
+}
+
+static guint
+id_hash (gconstpointer key)
+{
+	const ECalComponentId *id = key;
+	return g_str_hash (id->uid) ^ (id->rid ? g_str_hash (id->rid) : 0);
+}
+
+static gboolean
+id_equal (gconstpointer a, gconstpointer b)
+{
+	const ECalComponentId *id_a = a, *id_b = b;
+
+	return (g_strcmp0 (id_a->uid, id_b->uid) == 0) &&
+	       (g_strcmp0 (id_a->rid, id_b->rid) == 0);
+}
+
+static const gchar*
+id_get_str_id (ECalComponentId *id)
+{
+	return id->uid;
+}
+
 /* Class init */
 static void
 e_data_cal_view_class_init (EDataCalViewClass *klass)
@@ -91,30 +118,15 @@ e_data_cal_view_class_init (EDataCalViewClass *klass)
 	object_class->finalize = e_data_cal_view_finalize;
 
 	parent_class->stop_if_running = (void (*)(EDataView*)) e_data_cal_view_stop_if_running;
+	parent_class->id_hash = (GHashFunc) id_hash;
+	parent_class->id_equal = (GEqualFunc) id_equal;
+	parent_class->id_destroy = (GDestroyNotify) e_cal_component_free_id;
+	parent_class->id_get_str_id = (const gchar* (*)(gconstpointer)) id_get_str_id;
 
-        signals[OBJECTS_ADDED] =
-          g_signal_new ("objects-added",
-                        G_OBJECT_CLASS_TYPE (klass),
-                        G_SIGNAL_RUN_LAST,
-                        0, NULL, NULL,
-                        g_cclosure_marshal_VOID__BOXED,
-                        G_TYPE_NONE, 1, G_TYPE_STRV);
-
-        signals[OBJECTS_MODIFIED] =
-          g_signal_new ("objects-modified",
-                        G_OBJECT_CLASS_TYPE (klass),
-                        G_SIGNAL_RUN_LAST,
-                        0, NULL, NULL,
-                        g_cclosure_marshal_VOID__BOXED,
-                        G_TYPE_NONE, 1, G_TYPE_STRV);
-
-        signals[OBJECTS_REMOVED] =
-          g_signal_new ("objects-removed",
-                        G_OBJECT_CLASS_TYPE (klass),
-                        G_SIGNAL_RUN_LAST,
-                        0, NULL, NULL,
-                        g_cclosure_marshal_VOID__BOXED,
-                        G_TYPE_NONE, 1, G_TYPE_STRV);
+        signals[OBJECTS_ADDED] = g_signal_lookup ("objects-added", E_TYPE_DATA_VIEW);
+        signals[OBJECTS_MODIFIED] = g_signal_lookup ("objects-modified", E_TYPE_DATA_VIEW);
+        signals[OBJECTS_REMOVED] = g_signal_lookup ("objects-removed", E_TYPE_DATA_VIEW);
+        signals[DONE] = g_signal_lookup ("done", E_TYPE_DATA_VIEW);
 
         signals[PROGRESS] =
           g_signal_new ("progress",
@@ -124,31 +136,9 @@ e_data_cal_view_class_init (EDataCalViewClass *klass)
                         e_data_cal_marshal_VOID__STRING_UINT,
                         G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
 
-        signals[DONE] =
-          g_signal_new ("done",
-                        G_OBJECT_CLASS_TYPE (klass),
-                        G_SIGNAL_RUN_LAST,
-                        0, NULL, NULL,
-                        g_cclosure_marshal_VOID__UINT,
-                        G_TYPE_NONE, 1, G_TYPE_UINT);
-
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_e_data_cal_view_object_info);
 }
 
-static guint
-id_hash (gconstpointer key)
-{
-	const ECalComponentId *id = key;
-	return g_str_hash (id->uid) ^ (id->rid ? g_str_hash (id->rid) : 0);
-}
-
-static gboolean
-id_equal (gconstpointer a, gconstpointer b)
-{
-	const ECalComponentId *id_a = a, *id_b = b;
-	return g_strcmp0 (id_a->uid, id_b->uid) == 0 && g_strcmp0 (id_a->rid, id_b->rid) == 0;
-}
-
 /* Instance init */
 static void
 e_data_cal_view_init (EDataCalView *view)
@@ -158,15 +148,6 @@ e_data_cal_view_init (EDataCalView *view)
 	view->priv = priv;
 
 	priv->started = FALSE;
-	priv->done = FALSE;
-	priv->done_status = Success;
-	priv->started = FALSE;
-
-	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-	priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-
-	priv->ids = g_hash_table_new_full (id_hash, id_equal, (GDestroyNotify)e_cal_component_free_id, NULL);
 }
 
 EDataCalView *
@@ -198,119 +179,6 @@ e_data_cal_view_get_dbus_path (EDataCalView *view)
 	return e_data_view_get_dbus_path (E_DATA_VIEW (view));
 }
 
-static void
-reset_array (GArray *array)
-{
-	gint i = 0;
-	gchar *tmp = NULL;
-
-	/* Free stored strings */
-	for (i = 0; i < array->len; i++) {
-		tmp = g_array_index (array, gchar *, i);
-		g_free (tmp);
-	}
-
-	/* Force the array size to 0 */
-	g_array_set_size (array, 0);
-}
-
-static void
-send_pending_adds (EDataCalView *view)
-{
-	EDataCalViewPrivate *priv = view->priv;
-
-	if (priv->adds->len == 0)
-		return;
-
-	g_signal_emit (view, signals[OBJECTS_ADDED], 0, priv->adds->data);
-	reset_array (priv->adds);
-}
-
-static void
-send_pending_changes (EDataCalView *view)
-{
-	EDataCalViewPrivate *priv = view->priv;
-
-	if (priv->changes->len == 0)
-		return;
-
-	g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, priv->changes->data);
-	reset_array (priv->changes);
-}
-
-static void
-send_pending_removes (EDataCalView *view)
-{
-	EDataCalViewPrivate *priv = view->priv;
-
-	if (priv->removes->len == 0)
-		return;
-
-	/* TODO: send ECalComponentIds as a list of pairs */
-	g_signal_emit (view, signals[OBJECTS_REMOVED], 0, priv->removes->data);
-	reset_array (priv->removes);
-}
-
-static void
-notify_add (EDataCalView *view, gchar *obj)
-{
-	EDataCalViewPrivate *priv = view->priv;
-	ECalComponent *comp;
-
-	send_pending_changes (view);
-	send_pending_removes (view);
-
-	if (priv->adds->len == THRESHOLD) {
-		send_pending_adds (view);
-	}
-	g_array_append_val (priv->adds, obj);
-
-	comp = e_cal_component_new_from_string (obj);
-	g_hash_table_insert (priv->ids,
-			     e_cal_component_get_id (comp),
-			     GUINT_TO_POINTER (1));
-	g_object_unref (comp);
-}
-
-static void
-notify_change (EDataCalView *view, gchar *obj)
-{
-	EDataCalViewPrivate *priv = view->priv;
-
-	send_pending_adds (view);
-	send_pending_removes (view);
-
-	g_array_append_val (priv->changes, obj);
-}
-
-static void
-notify_remove (EDataCalView *view, ECalComponentId *id)
-{
-	EDataCalViewPrivate *priv = view->priv;
-	gchar *uid;
-
-	send_pending_adds (view);
-	send_pending_changes (view);
-
-	/* TODO: store ECalComponentId instead of just uid*/
-	uid = g_strdup (id->uid);
-	g_array_append_val (priv->removes, uid);
-
-	g_hash_table_remove (priv->ids, id);
-}
-
-static void
-notify_done (EDataCalView *view)
-{
-	EDataCalViewPrivate *priv = view->priv;
-
-	send_pending_adds (view);
-	send_pending_changes (view);
-	send_pending_removes (view);
-
-	g_signal_emit (view, signals[DONE], 0, priv->done_status);
-}
-
 static gboolean
 impl_EDataCalView_start (EDataCalView *query, GError **error)
 {
@@ -326,23 +194,6 @@ impl_EDataCalView_start (EDataCalView *query, GError **error)
 	return TRUE;
 }
 
-static void
-e_data_cal_view_finalize (GObject *object)
-{
-	EDataCalView *query;
-	EDataCalViewPrivate *priv;
-
-	g_return_if_fail (object != NULL);
-	g_return_if_fail (IS_QUERY (object));
-
-	query = QUERY (object);
-	priv = query->priv;
-
-	g_hash_table_destroy (priv->ids);
-
-	(* G_OBJECT_CLASS (e_data_cal_view_parent_class)->finalize) (object);
-}
-
 /**
  * e_data_cal_view_get_backend:
  * @query: A query object.
@@ -467,13 +318,7 @@ e_data_cal_view_is_started (EDataCalView *view)
 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;
+	return e_data_view_is_done (E_DATA_VIEW (query));
 }
 
 /**
@@ -488,14 +333,8 @@ e_data_cal_view_is_done (EDataCalView *query)
 EDataCalCallStatus
 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;
+	if (e_data_view_is_done (E_DATA_VIEW (query)))
+		return e_data_view_get_done_status (E_DATA_VIEW (query));
 
 	return Success;
 }
@@ -520,10 +359,18 @@ e_data_cal_view_notify_objects_added (EDataCalView *view, const GList *objects)
 		return;
 
 	for (l = objects; l; l = l->next) {
-		notify_add (view, g_strdup (l->data));
+		gchar *object;
+		ECalComponent *comp;
+
+		object = g_strdup (l->data);
+		comp = e_cal_component_new_from_string (object);
+
+		e_data_view_notify_object_add (E_DATA_VIEW (view), e_cal_component_get_id (comp), object);
+
+		g_object_unref (comp);
 	}
 
-	send_pending_adds (view);
+	e_data_view_send_pending_adds (E_DATA_VIEW (view));
 }
 
 /**
@@ -565,11 +412,10 @@ e_data_cal_view_notify_objects_modified (EDataCalView *view, const GList *object
 		return;
 
 	for (l = objects; l; l = l->next) {
-		/* TODO: send add/remove/change as relevant, based on ->ids */
-		notify_change (view, g_strdup (l->data));
+		e_data_view_notify_object_modification (E_DATA_VIEW (view), g_strdup (l->data));
 	}
 
-	send_pending_changes (view);
+	e_data_view_send_pending_modifications (E_DATA_VIEW (view));
 }
 
 /**
@@ -612,11 +458,13 @@ e_data_cal_view_notify_objects_removed (EDataCalView *view, const GList *ids)
 
 	for (l = ids; l; l = l->next) {
 		ECalComponentId *id = l->data;
-		if (g_hash_table_lookup (priv->ids, id))
-		    notify_remove (view, id);
+
+		if (e_data_view_contains_object (E_DATA_VIEW (view), id)) {
+			e_data_view_notify_object_remove (E_DATA_VIEW (view), id);
+		}
 	}
 
-	send_pending_removes (view);
+	e_data_view_send_pending_removes (E_DATA_VIEW (view));
 }
 
 /**
@@ -679,8 +527,5 @@ e_data_cal_view_notify_done (EDataCalView *view, GNOME_Evolution_Calendar_CallSt
 	if (!priv->started)
 		return;
 
-	priv->done = TRUE;
-	priv->done_status = status;
-
-	notify_done (view);
+	e_data_view_notify_done (E_DATA_VIEW (view), status);
 }
diff --git a/libebackend/e-data-view.c b/libebackend/e-data-view.c
index 6aa47c6..8085ef6 100644
--- a/libebackend/e-data-view.c
+++ b/libebackend/e-data-view.c
@@ -45,6 +45,15 @@ struct _EDataViewPrivate {
 	EBackendSExp *sexp;
 
 	gchar *dbus_path;
+
+	GArray *adds;
+	GArray *modifications;
+	GArray *removes;
+
+	GHashTable *ids;
+
+	gboolean done;
+	guint done_status;
 };
 
 enum {
@@ -55,6 +64,16 @@ enum {
 	PROP_SEXP,
 };
 
+enum {
+	OBJECTS_ADDED,
+	OBJECTS_MODIFIED,
+	OBJECTS_REMOVED,
+	DONE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 static void
 data_destroyed_cb (gpointer data, GObject *dead)
 {
@@ -187,6 +206,21 @@ e_data_view_dispose (GObject *object)
 		priv->sexp = NULL;
 	}
 
+	if (priv->adds) {
+		g_array_unref (priv->adds);
+		priv->adds = NULL;
+	}
+
+	if (priv->modifications) {
+		g_array_unref (priv->modifications);
+		priv->modifications = NULL;
+	}
+
+	if (priv->removes) {
+		g_array_unref (priv->removes);
+		priv->removes = NULL;
+	}
+
 	G_OBJECT_CLASS (e_data_view_parent_class)->dispose (object);
 }
 
@@ -198,6 +232,8 @@ e_data_view_finalize (GObject *object)
 
 	g_free (priv->dbus_path);
 
+	g_hash_table_destroy (priv->ids);
+
 	G_OBJECT_CLASS (e_data_view_parent_class)->finalize (object);
 }
 
@@ -205,6 +241,18 @@ static void
 e_data_view_constructed (GObject *object)
 {
 	EDataView *view = E_DATA_VIEW (object);
+        EDataViewClass *klass;
+	GHashFunc id_hash;
+	GEqualFunc id_equal;
+	GDestroyNotify id_destroy;
+
+        klass = E_DATA_VIEW_GET_CLASS (view);
+
+	id_hash = klass->id_hash ? klass->id_hash : g_str_hash;
+	id_equal = klass->id_equal ? klass->id_equal : g_str_equal;
+	id_destroy = klass->id_destroy ? klass->id_destroy : g_free;
+
+        view->priv->ids = g_hash_table_new_full (id_hash, id_equal, id_destroy, NULL);
 
 	dbus_g_connection_register_g_object (connection, view->priv->dbus_path, G_OBJECT (view));
 }
@@ -264,13 +312,58 @@ e_data_view_class_init (EDataViewClass *klass)
                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
 
+        signals[OBJECTS_ADDED] =
+		g_signal_new ("objects-added",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EDataViewClass, objects_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_STRV);
+
+        signals[OBJECTS_MODIFIED] =
+		g_signal_new ("objects-modified",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EDataViewClass, objects_modified),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_STRV);
+
+        signals[OBJECTS_REMOVED] =
+		g_signal_new ("objects-removed",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EDataViewClass, objects_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_STRV);
+
+        signals[DONE] =
+		g_signal_new ("done",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+
+
 	g_type_class_add_private (klass, sizeof (EDataViewPrivate));
 }
 
 static void
 e_data_view_init (EDataView *view)
 {
-	view->priv = E_DATA_VIEW_GET_PRIVATE (view);
+	EDataViewPrivate *priv = E_DATA_VIEW_GET_PRIVATE (view);
+
+	view->priv = priv;
+
+        priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
+        priv->modifications = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
+        priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
+
+	priv->done = FALSE;
+	priv->done_status = 0;
 }
 
 /**
@@ -321,3 +414,196 @@ e_data_view_get_dbus_path (EDataView *view)
 
 	return view->priv->dbus_path;
 }
+
+static void
+reset_array (GArray *array)
+{
+        gint i = 0;
+        gchar *tmp = NULL;
+
+        /* Free stored strings */
+        for (i = 0; i < array->len; i++) {
+                tmp = g_array_index (array, gchar *, i);
+                g_free (tmp);
+        }
+
+        /* Force the array size to 0 */
+        g_array_set_size (array, 0);
+}
+
+void
+e_data_view_send_pending_adds (EDataView *view)
+{
+        EDataViewPrivate *priv = view->priv;
+
+        if (priv->adds->len == 0)
+                return;
+
+        g_signal_emit (view, signals[OBJECTS_ADDED], 0, priv->adds->data);
+        reset_array (priv->adds);
+}
+
+void
+e_data_view_send_pending_modifications (EDataView *view)
+{
+        EDataViewPrivate *priv = view->priv;
+
+        if (priv->modifications->len == 0)
+                return;
+
+        g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, priv->modifications->data);
+        reset_array (priv->modifications);
+}
+
+void
+e_data_view_send_pending_removes (EDataView *view)
+{
+        EDataViewPrivate *priv = view->priv;
+
+        if (priv->removes->len == 0)
+                return;
+
+        /* TODO: send ECalComponentIds as a list of pairs */
+        g_signal_emit (view, signals[OBJECTS_REMOVED], 0, priv->removes->data);
+        reset_array (priv->removes);
+}
+
+gboolean
+e_data_view_contains_object (EDataView *view,
+			     gpointer   id)
+{
+	g_return_val_if_fail (E_IS_DATA_VIEW (view), FALSE);
+
+	return g_hash_table_lookup (view->priv->ids, id) != NULL;
+}
+
+void
+e_data_view_notify_object_add (EDataView   *view,
+			       gpointer     id,
+			       const gchar *obj)
+{
+        EDataViewPrivate *priv;
+        EDataViewClass *klass;
+
+	g_return_if_fail (E_IS_DATA_VIEW (view));
+
+        priv = view->priv;
+        klass = E_DATA_VIEW_GET_CLASS (view);
+
+        e_data_view_send_pending_modifications (view);
+        e_data_view_send_pending_removes (view);
+
+        if (priv->adds->len == THRESHOLD) {
+                e_data_view_send_pending_adds (view);
+        }
+
+	if (e_data_view_contains_object (view, id)) {
+		if (klass->id_destroy) {
+			klass->id_destroy (id);
+		} else {
+			g_free (id);
+		}
+
+		return;
+	}
+
+        g_array_append_val (priv->adds, obj);
+
+        g_hash_table_insert (priv->ids, id, GUINT_TO_POINTER (1));
+}
+
+void
+e_data_view_notify_object_modification (EDataView *view,
+					gchar     *obj)
+{
+        EDataViewPrivate *priv;
+
+	g_return_if_fail (E_IS_DATA_VIEW (view));
+
+        priv = view->priv;
+
+        e_data_view_send_pending_adds (view);
+        e_data_view_send_pending_removes (view);
+
+        g_array_append_val (priv->modifications, obj);
+}
+
+void
+e_data_view_notify_object_remove (EDataView *view,
+				  gpointer   id)
+{
+        EDataViewPrivate *priv;
+        gchar *uid;
+        EDataViewClass *klass;
+
+	g_return_if_fail (E_IS_DATA_VIEW (view));
+
+        priv = view->priv;
+        klass = E_DATA_VIEW_GET_CLASS (view);
+
+	if (!e_data_view_contains_object (view, id)) {
+		g_warning (G_STRLOC ": view does not contain id %p", id);
+		return;
+	}
+
+        e_data_view_send_pending_adds (view);
+        e_data_view_send_pending_modifications (view);
+
+	if (klass->id_get_str_id) {
+		uid = g_strdup (klass->id_get_str_id (id));
+	} else {
+		uid = g_strdup ((const gchar*) id);
+	}
+
+        g_array_append_val (priv->removes, uid);
+
+        g_hash_table_remove (priv->ids, id);
+}
+
+void
+e_data_view_notify_done (EDataView *view,
+			 guint      status)
+{
+        e_data_view_send_pending_adds (view);
+        e_data_view_send_pending_modifications (view);
+        e_data_view_send_pending_removes (view);
+
+        g_signal_emit (view, signals[DONE], 0, status);
+}
+
+/**
+ * e_data_view_is_done:
+ * @view: An #EDataView
+ *
+ * Checks whether the given view is already done. Being done means the initial
+ * matching of objects have been finished, not that no more notifications about
+ * changes will be sent. In fact, even after done, notifications will still be
+ * sent if there are changes in the objects matching the query search
+ * expression.
+ *
+ * Return value: TRUE if the view is done, FALSE if still in progress.
+ */
+gboolean
+e_data_view_is_done (EDataView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_VIEW (view), FALSE);
+
+	return view->priv->done;
+}
+
+/**
+ * e_data_view_get_done_status:
+ * @view: An #EDataView
+ *
+ * Gets the status code obtained when the initial matching of objects was done
+ * for the given view.
+ *
+ * Return value: The view status.
+ */
+guint
+e_data_view_get_done_status (EDataView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_VIEW (view), FALSE);
+
+	return view->priv->done_status;
+}
diff --git a/libebackend/e-data-view.h b/libebackend/e-data-view.h
index f83c54b..8f5ba4c 100644
--- a/libebackend/e-data-view.h
+++ b/libebackend/e-data-view.h
@@ -50,7 +50,29 @@ struct _EDataView {
 struct _EDataViewClass {
 	GObjectClass parent;
 
-        void	(*stop_if_running)	(EDataView *view);
+        void		(*stop_if_running)	(EDataView *view);
+
+	GHashFunc	id_hash;
+
+	GEqualFunc	id_equal;
+
+	GDestroyNotify	id_destroy;
+
+        const gchar*	(*id_get_str_id)	(gconstpointer id);
+
+	/* Notification signals */
+	void		(*objects_added)	(EDataView    *view,
+						 const gchar **objects);
+
+	void		(*objects_modified)	(EDataView    *view,
+						 const gchar **objects);
+
+	void		(*objects_removed)	(EDataView    *view,
+						 const gchar **ids);
+/* FIXME: cut this
+	void		(*done)			(EDataView    *view,
+						 guint         status);
+*/
 };
 
 GType		e_data_view_get_type		(void);
@@ -59,6 +81,30 @@ EBackendSExp*	e_data_view_get_sexp		(EDataView *view);
 EBackend*	e_data_view_get_backend		(EDataView *view);
 const gchar*	e_data_view_get_dbus_path	(EDataView *view);
 
+void		e_data_view_send_pending_adds		(EDataView *view);
+void		e_data_view_send_pending_modifications	(EDataView *view);
+void		e_data_view_send_pending_removes	(EDataView *view);
+
+gboolean	e_data_view_contains_object		(EDataView   *view,
+							 gpointer     id);
+
+void		e_data_view_notify_object_add		(EDataView   *view,
+							 gpointer     id,
+							 const gchar *obj);
+
+void		e_data_view_notify_object_modification	(EDataView *view,
+							 gchar     *obj);
+
+void		e_data_view_notify_object_remove	(EDataView *view,
+							 gpointer   id);
+
+void		e_data_view_notify_done			(EDataView *view,
+							 guint      status);
+
+gboolean	e_data_view_is_done			(EDataView *view);
+
+guint		e_data_view_get_done_status		(EDataView *view);
+
 
 G_END_DECLS
 



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