[evolution-data-server/openismus-work] Add support for direct access queries in book views



commit cf8eb3a12e9c7d36c3d6bff8a289f74721d93322
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Wed Nov 28 22:21:07 2012 +0900

    Add support for direct access queries in book views
    
    By using a special field name 'x-evolution-uids-only', an EBookClientView
    tells the backend that it doesnt want contact data sent over the bus,
    instead direct calls are used to fetch the contact data when notifications
    are delivered to the EBookClientView.

 addressbook/libebook/e-book-client-view-private.h |    5 +-
 addressbook/libebook/e-book-client-view.c         |  142 ++++++++++++++++++++-
 addressbook/libebook/e-book-client.c              |    3 +-
 addressbook/libedata-book/e-data-book-view.c      |   22 +++-
 4 files changed, 161 insertions(+), 11 deletions(-)
---
diff --git a/addressbook/libebook/e-book-client-view-private.h b/addressbook/libebook/e-book-client-view-private.h
index 668da47..086ceb3 100644
--- a/addressbook/libebook/e-book-client-view-private.h
+++ b/addressbook/libebook/e-book-client-view-private.h
@@ -23,10 +23,13 @@
 #define E_BOOK_CLIENT_VIEW_PRIVATE_H
 
 #include <libebook/libebook.h>
+#include <libedata-book/libedata-book.h>
 
 struct _EGdbusBookView;
 
-EBookClientView *_e_book_client_view_new (EBookClient *book_client, struct _EGdbusBookView *gdbus_bookview);
+EBookClientView *_e_book_client_view_new (EBookClient *book_client,
+					  struct _EGdbusBookView *gdbus_bookview,
+					  EDataBook *direct_book);
 
 G_END_DECLS
 
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
index eb5dea9..c8066b4 100644
--- a/addressbook/libebook/e-book-client-view.c
+++ b/addressbook/libebook/e-book-client-view.c
@@ -43,7 +43,10 @@ G_DEFINE_TYPE (EBookClientView, e_book_client_view, G_TYPE_OBJECT);
 struct _EBookClientViewPrivate {
 	GDBusProxy *gdbus_bookview;
 	EBookClient *client;
-	gboolean running;
+	EDataBook *direct_book;
+	guint running : 1;
+	guint complete : 1;
+
 };
 
 enum {
@@ -57,6 +60,97 @@ enum {
 
 static guint signals[LAST_SIGNAL];
 
+typedef struct {
+	EBookClientView *view;
+	guint signum;
+} NotificationData;
+
+static gchar *
+direct_contacts_query (const gchar * const *uids)
+{
+	EBookQuery *query, **qs;
+	gchar *sexp;
+	gint i, len;
+
+	len = g_strv_length ((gchar **)uids);
+	qs = g_new0 (EBookQuery *, len);
+
+	for (i = 0; uids[i] != NULL; i++) {
+		const gchar *uid = uids[i];
+
+		qs[i] = e_book_query_field_test (E_CONTACT_UID, E_BOOK_QUERY_IS, uid);
+	}
+
+	query = e_book_query_or (len, qs, TRUE);
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+
+	return sexp;
+}
+
+static void
+direct_contacts_ready (GObject *source_object,
+		       GAsyncResult *res,
+		       gpointer user_data)
+{
+	NotificationData *data = (NotificationData *)user_data;
+	GSList *contacts = NULL;
+	GError *error = NULL;
+
+	if (!e_data_book_get_contacts_finish (E_DATA_BOOK (source_object),
+					      res, &contacts, &error)) {
+		g_warning ("Error fetching contacts directly: %s\n", error->message);
+		g_error_free (error);
+	} else {
+		g_signal_emit (data->view, data->signum, 0, contacts);
+	}
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+	g_object_unref (data->view);
+	g_slice_free (NotificationData, data);
+}
+
+static void
+direct_contacts_fetch (EBookClientView *view,
+		       const gchar * const *uids,
+		       guint signum)
+{
+	NotificationData *data;
+	gchar *sexp = direct_contacts_query (uids);
+
+	/* Until the view has completely loaded, we need to make
+	 * sync calls to the backend
+	 */
+	if (!view->priv->complete) {
+		GSList *contacts = NULL;
+		GError *error = NULL;
+
+		if (!e_data_book_get_contacts_sync (view->priv->direct_book,
+						    sexp, &contacts, NULL, &error)) {
+			g_warning ("Error fetching contacts directly: %s\n", error->message);
+			g_error_free (error);
+		} else {
+			g_signal_emit (view, signum, 0, contacts);
+			g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+			g_slist_free (contacts);
+		}
+
+	} else {
+		/* Make async calls, avoid blocking the thread owning the view
+		 * as much as possible
+		 */
+		data = g_slice_new (NotificationData);
+		data->view = g_object_ref (view);
+		data->signum = signum;
+
+		e_data_book_get_contacts (view->priv->direct_book,
+					  sexp, NULL, direct_contacts_ready, data);
+	}
+
+	g_free (sexp);
+}
+
 static void
 objects_added_cb (EGdbusBookView *object,
                   const gchar * const *vcards,
@@ -68,6 +162,12 @@ objects_added_cb (EGdbusBookView *object,
 	if (!view->priv->running)
 		return;
 
+	/* array contains UIDs only */
+	if (view->priv->direct_book) {
+		direct_contacts_fetch (view, vcards, signals[OBJECTS_ADDED]);
+		return;
+	}
+
 	/* array contains both UID and vcard */
 	for (p = vcards; p[0] && p[1]; p += 2) {
 		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
@@ -91,6 +191,12 @@ objects_modified_cb (EGdbusBookView *object,
 	if (!view->priv->running)
 		return;
 
+	/* array contains UIDs only */
+	if (view->priv->direct_book) {
+		direct_contacts_fetch (view, vcards, signals[OBJECTS_MODIFIED]);
+		return;
+	}
+
 	/* array contains both UID and vcard */
 	for (p = vcards; p[0] && p[1]; p += 2) {
 		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
@@ -146,6 +252,8 @@ complete_cb (EGdbusBookView *object,
 	if (!view->priv->running)
 		return;
 
+	view->priv->complete = TRUE;
+
 	g_return_if_fail (e_gdbus_templates_decode_error (in_error_strv, &error));
 
 	g_signal_emit (view, signals[COMPLETE], 0, error);
@@ -167,7 +275,8 @@ complete_cb (EGdbusBookView *object,
  **/
 EBookClientView *
 _e_book_client_view_new (EBookClient *book_client,
-                         EGdbusBookView *gdbus_bookview)
+                         EGdbusBookView *gdbus_bookview,
+			 EDataBook *direct_book)
 {
 	EBookClientView *view;
 	EBookClientViewPrivate *priv;
@@ -187,6 +296,11 @@ _e_book_client_view_new (EBookClient *book_client,
 	g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
 	g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
 
+	if (direct_book) {
+		view->priv->direct_book = g_object_ref (direct_book);
+		e_book_client_view_set_fields_of_interest (view, NULL, NULL);
+	}
+
 	return view;
 }
 
@@ -333,8 +447,22 @@ e_book_client_view_set_fields_of_interest (EBookClientView *view,
 		GError *local_error = NULL;
 		gchar **strv;
 
-		strv = e_client_util_slist_to_strv (fields_of_interest);
-		e_gdbus_book_view_call_set_fields_of_interest_sync (priv->gdbus_bookview, (const gchar * const *) strv, NULL, &local_error);
+		/* When in direct read access mode, ensure that the
+		 * backend is configured to only send us UIDs for everything,
+		 *
+		 * Just ignore the fields_of_interest and use them locally
+		 * when filtering cards to be returned in direct reads.
+		 */
+		if (view->priv->direct_book) {
+			GSList uid_field = { 0, };
+
+			uid_field.data = (gpointer)"x-evolution-uids-only";
+			strv = e_client_util_slist_to_strv (&uid_field);
+		} else
+			strv = e_client_util_slist_to_strv (fields_of_interest);
+
+		e_gdbus_book_view_call_set_fields_of_interest_sync (priv->gdbus_bookview,
+								    (const gchar * const *) strv, NULL, &local_error);
 		g_strfreev (strv);
 
 		e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
@@ -352,6 +480,7 @@ e_book_client_view_init (EBookClientView *view)
 
 	view->priv->client = NULL;
 	view->priv->running = FALSE;
+	view->priv->complete = FALSE;
 }
 
 static void
@@ -378,6 +507,11 @@ book_client_view_dispose (GObject *object)
 		view->priv->client = NULL;
 	}
 
+	if (view->priv->direct_book != NULL) {
+		g_object_unref (view->priv->direct_book);
+		view->priv->direct_book = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_book_client_view_parent_class)->dispose (object);
 }
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index a7c5008..f821378 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -2492,7 +2492,8 @@ complete_get_view (EBookClient *client,
 			&local_error);
 
 		if (gdbus_bookview) {
-			*view = _e_book_client_view_new (client, gdbus_bookview);
+			*view = _e_book_client_view_new (client, gdbus_bookview,
+							 client->priv->direct_book);
 			g_object_unref (gdbus_bookview);
 		} else {
 			*view = NULL;
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index ce78805..1da382d 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -68,6 +68,7 @@ struct _EDataBookViewPrivate {
 
 	/* which fields is listener interested in */
 	GHashTable *fields_of_interest;
+	gboolean send_uids_only;
 };
 
 static void e_data_book_view_dispose (GObject *object);
@@ -244,10 +245,12 @@ notify_change (EDataBookView *view,
 		send_pending_changes (view);
 	}
 
-	utf8_vcard = e_util_utf8_make_valid (vcard);
-	utf8_id = e_util_utf8_make_valid (id);
+	if (view->priv->send_uids_only == FALSE) {
+		utf8_vcard = e_util_utf8_make_valid (vcard);
+		g_array_append_val (priv->changes, utf8_vcard);
+	}
 
-	g_array_append_val (priv->changes, utf8_vcard);
+	utf8_id = e_util_utf8_make_valid (id);
 	g_array_append_val (priv->changes, utf8_id);
 
 	ensure_pending_flush_timeout (view);
@@ -303,9 +306,11 @@ notify_add (EDataBookView *view,
 			send_pending_adds (view);
 		}
 
-		utf8_vcard = e_util_utf8_make_valid (vcard);
+		if (view->priv->send_uids_only == FALSE) {
+			utf8_vcard = e_util_utf8_make_valid (vcard);
+			g_array_append_val (view->priv->adds, utf8_vcard);
+		}
 
-		g_array_append_val (priv->adds, utf8_vcard);
 		g_array_append_val (priv->adds, utf8_id_copy);
 
 		ensure_pending_flush_timeout (view);
@@ -333,12 +338,19 @@ impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
 		g_hash_table_destroy (priv->fields_of_interest);
 	priv->fields_of_interest = NULL;
 
+	view->priv->send_uids_only = FALSE;
+
 	for (ii = 0; in_fields_of_interest[ii]; ii++) {
 		const gchar *field = in_fields_of_interest[ii];
 
 		if (!*field)
 			continue;
 
+		if (strcmp (field, "x-evolution-uids-only") == 0) {
+			view->priv->send_uids_only = TRUE;
+			continue;
+		}
+
 		if (!priv->fields_of_interest)
 			priv->fields_of_interest = g_hash_table_new_full (str_ic_hash, str_ic_equal, g_free, NULL);
 



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