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



commit 02aea93c60ad728a7b8b4765df10237d779cb598
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Wed Nov 28 20:32:04 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.c    |  170 +++++++++++++++++++++++++-
 addressbook/libebook/e-book-client.c         |    1 +
 addressbook/libedata-book/e-data-book-view.c |   22 +++-
 3 files changed, 185 insertions(+), 8 deletions(-)
---
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
index 53a18e9..5982295 100644
--- a/addressbook/libebook/e-book-client-view.c
+++ b/addressbook/libebook/e-book-client-view.c
@@ -27,6 +27,7 @@
 #include <glib/gi18n-lib.h>
 
 #include <libedataserver/libedataserver.h>
+#include <libedata-book/libedata-book.h>
 
 #include "e-book-client.h"
 #include "e-book-client-view.h"
@@ -42,7 +43,10 @@ struct _EBookClientViewPrivate {
 	GDBusProxy *dbus_proxy;
 	GDBusConnection *connection;
 	gchar *object_path;
-	gboolean running;
+	guint running : 1;
+	guint complete : 1;
+
+	EDataBook *direct_book;
 
 	gulong objects_added_handler_id;
 	gulong objects_modified_handler_id;
@@ -55,7 +59,8 @@ enum {
 	PROP_0,
 	PROP_CLIENT,
 	PROP_CONNECTION,
-	PROP_OBJECT_PATH
+	PROP_OBJECT_PATH,
+	PROP_DIRECT_BOOK
 };
 
 enum {
@@ -81,6 +86,95 @@ G_DEFINE_TYPE_WITH_CODE (
 		G_TYPE_INITABLE,
 		e_book_client_view_initable_init))
 
+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_free_full (contacts, (GDestroyNotify) g_object_unref);
+	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_free_full (contacts, (GDestroyNotify) g_object_unref);
+		}
+
+	} 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
 book_client_view_objects_added_cb (EGdbusBookView *object,
                                    const gchar * const *vcards,
@@ -92,6 +186,12 @@ book_client_view_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) {
 		EContact *contact;
@@ -120,6 +220,12 @@ book_client_view_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) {
 		EContact *contact;
@@ -181,6 +287,8 @@ book_client_view_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);
@@ -220,6 +328,18 @@ book_client_view_set_object_path (EBookClientView *view,
 }
 
 static void
+book_client_view_set_direct_book (EBookClientView *view,
+				  EDataBook       *book)
+{
+	g_return_if_fail (book == NULL ||
+			  E_IS_DATA_BOOK (book));
+	g_return_if_fail (view->priv->direct_book == NULL);
+
+	if (book)
+		view->priv->direct_book = g_object_ref (book);
+}
+
+static void
 book_client_view_set_property (GObject *object,
                                guint property_id,
                                const GValue *value,
@@ -243,6 +363,12 @@ book_client_view_set_property (GObject *object,
 				E_BOOK_CLIENT_VIEW (object),
 				g_value_get_string (value));
 			return;
+
+		case PROP_DIRECT_BOOK:
+			book_client_view_set_direct_book (
+				E_BOOK_CLIENT_VIEW (object),
+				g_value_get_object (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -297,6 +423,11 @@ book_client_view_dispose (GObject *object)
 		priv->connection = NULL;
 	}
 
+	if (priv->direct_book != NULL) {
+		g_object_unref (priv->direct_book);
+		priv->direct_book = NULL;
+	}
+
 	if (priv->dbus_proxy != NULL) {
 		GError *error = NULL;
 
@@ -396,6 +527,12 @@ book_client_view_initable_init (GInitable *initable,
 		G_CALLBACK (book_client_view_complete_cb), initable);
 	priv->complete_handler_id = handler_id;
 
+	/* When in direct read access mode, we add a special field
+	 * to fields-of-interest indicating we only want uids sent
+	 */
+	if (priv->direct_book)
+		e_book_client_view_set_fields_of_interest (E_BOOK_CLIENT_VIEW (initable), NULL, NULL);
+
 	return TRUE;
 }
 
@@ -450,6 +587,20 @@ e_book_client_view_class_init (EBookClientViewClass *class)
 			G_PARAM_CONSTRUCT_ONLY |
 			G_PARAM_STATIC_STRINGS));
 
+	g_object_class_install_property (
+		object_class,
+		PROP_DIRECT_BOOK,
+		g_param_spec_object (
+			"direct-book",
+			"Direct Book",
+			"The EDataBook to fetch contact "
+			"data from, if direct read access "
+			"is enabled",
+			E_TYPE_DATA_BOOK,
+			G_PARAM_WRITABLE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
+
 	signals[OBJECTS_ADDED] = g_signal_new (
 		"objects-added",
 		G_OBJECT_CLASS_TYPE (object_class),
@@ -671,7 +822,20 @@ e_book_client_view_set_fields_of_interest (EBookClientView *view,
 
 	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
 
-	strv = e_client_util_slist_to_strv (fields_of_interest);
+	/* 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 (
 		view->priv->dbus_proxy,
 		(const gchar * const *) strv,
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index 892a648..3d7a949 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -2768,6 +2768,7 @@ complete_get_view (EBookClient *client,
 			"client", client,
 			"connection", connection,
 			"object-path", view_path,
+			"direct-book", client->priv->direct_book,
 			NULL);
 
 		if (local_error != NULL) {
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 93fed8e..34c0e6e 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;
 };
 
 enum {
@@ -331,12 +332,19 @@ impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
 		view->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 (view->priv->fields_of_interest == NULL)
 			view->priv->fields_of_interest =
 				g_hash_table_new_full (
@@ -824,10 +832,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 (view->priv->changes, utf8_vcard);
+	}
 
-	g_array_append_val (view->priv->changes, utf8_vcard);
+	utf8_id = e_util_utf8_make_valid (id);
 	g_array_append_val (view->priv->changes, utf8_id);
 
 	ensure_pending_flush_timeout (view);
@@ -881,9 +891,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 (view->priv->adds, utf8_vcard);
 		g_array_append_val (view->priv->adds, utf8_id_copy);
 
 		ensure_pending_flush_timeout (view);



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