[evolution-data-server] Rewrite e_load_book_source_async().
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Rewrite e_load_book_source_async().
- Date: Wed, 18 Aug 2010 20:45:52 +0000 (UTC)
commit 7494d975b37e250f78964b11a768dfea06c6f780
Author: Matthew Barnes <mbarnes redhat com>
Date: Wed Aug 18 07:08:06 2010 -0400
Rewrite e_load_book_source_async().
This is a late libedataserverui API break, but so be it.
Rewrite e_load_book_source_async() to use a GIO-style asynchronous
pattern, and add a corresponding e_load_book_source_finish().
The API is fairly obvious:
void e_load_book_source_async (ESource *source,
GtkWindow *parent,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
EBook * e_load_book_source_finish (ESource *source,
GAsyncResult *result,
GError **error);
This also eliminates the thread for loading EBooks from ENameSelector.
configure.ac | 2 +-
.../libedataserverui/libedataserverui-sections.txt | 1 +
.../libedataserverui/tmpl/e-book-auth-util.sgml | 14 +-
libedataserverui/e-book-auth-util.c | 359 ++++++++++++++++++--
libedataserverui/e-book-auth-util.h | 20 +-
libedataserverui/e-name-selector-dialog.c | 84 ++++--
libedataserverui/e-name-selector-entry.c | 47 +++-
libedataserverui/e-name-selector.c | 179 ++++++----
8 files changed, 575 insertions(+), 131 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 180468e..0961866 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,7 +85,7 @@ LIBEDATASERVER_CURRENT=14
LIBEDATASERVER_REVISION=0
LIBEDATASERVER_AGE=0
-LIBEDATASERVERUI_CURRENT=10
+LIBEDATASERVERUI_CURRENT=11
LIBEDATASERVERUI_REVISION=0
LIBEDATASERVERUI_AGE=0
diff --git a/docs/reference/libedataserverui/libedataserverui-sections.txt b/docs/reference/libedataserverui/libedataserverui-sections.txt
index 6e918cf..f089ce3 100644
--- a/docs/reference/libedataserverui/libedataserverui-sections.txt
+++ b/docs/reference/libedataserverui/libedataserverui-sections.txt
@@ -2,6 +2,7 @@
<FILE>e-book-auth-util</FILE>
e_load_book_source
e_load_book_source_async
+e_load_book_source_finish
</SECTION>
<SECTION>
diff --git a/docs/reference/libedataserverui/tmpl/e-book-auth-util.sgml b/docs/reference/libedataserverui/tmpl/e-book-auth-util.sgml
index 5eda8ea..38dce82 100644
--- a/docs/reference/libedataserverui/tmpl/e-book-auth-util.sgml
+++ b/docs/reference/libedataserverui/tmpl/e-book-auth-util.sgml
@@ -37,8 +37,20 @@ e-book-auth-util
</para>
@source:
- open_func:
+ parent:
+ cancellable:
+ callback:
@user_data:
+
+
+<!-- ##### FUNCTION e_load_book_source_finish ##### -->
+<para>
+
+</para>
+
+ source:
+ result:
+ error:
@Returns:
diff --git a/libedataserverui/e-book-auth-util.c b/libedataserverui/e-book-auth-util.c
index db794a4..25b380b 100644
--- a/libedataserverui/e-book-auth-util.c
+++ b/libedataserverui/e-book-auth-util.c
@@ -318,41 +318,358 @@ e_load_book_source (ESource *source, EBookCallback open_func, gpointer user_data
}
#endif
+typedef struct {
+ EBook *book;
+ GtkWindow *parent;
+ GCancellable *cancellable;
+
+ gboolean anonymous_alert;
+
+ /* Authentication Details */
+ gchar *auth_uri;
+ gchar *auth_method;
+ gchar *auth_username;
+ gchar *auth_component;
+ gboolean auth_remember;
+} LoadContext;
+
+static void
+load_book_source_context_free (LoadContext *context)
+{
+ if (context->book != NULL)
+ g_object_unref (context->book);
+
+ if (context->parent != NULL)
+ g_object_unref (context->parent);
+
+ if (context->cancellable != NULL)
+ g_object_unref (context->cancellable);
+
+ g_free (context->auth_uri);
+ g_free (context->auth_method);
+ g_free (context->auth_username);
+ g_free (context->auth_component);
+
+ g_slice_free (LoadContext, context);
+}
+
+static void
+load_book_source_get_auth_details (ESource *source,
+ LoadContext *context)
+{
+ const gchar *property;
+ gchar *uri;
+
+ /* auth_method */
+
+ property = e_source_get_property (source, "auth");
+
+ if (property == NULL || strcmp (property, "none") == 0)
+ return;
+
+ context->auth_method = g_strdup (property);
+
+ /* auth_uri */
+
+ uri = e_source_get_uri (source);
+ context->auth_uri = remove_parameters_from_uri (uri);
+ g_free (uri);
+
+ /* auth_username */
+
+ if (g_strcmp0 (context->auth_method, "ldap/simple-binddn") == 0) {
+ property = e_source_get_property (source, "binddn");
+
+ } else if (g_strcmp0 (context->auth_method, "plain/password") == 0) {
+ property = e_source_get_property (source, "user");
+ if (property == NULL)
+ property = e_source_get_property (source, "username");
+
+ } else
+ property = e_source_get_property (source, "email_addr");
+
+ if (property == NULL)
+ property = "";
+
+ context->auth_username = g_strdup (property);
+
+ /* auth_component */
+
+ property = e_source_get_property (source, "auth-domain");
+
+ if (property == NULL)
+ property = "Addressbook";
+
+ context->auth_component = g_strdup (property);
+
+ /* auth_remember */
+
+ property = e_source_get_property (source, "remember_password");
+
+ context->auth_remember = (g_strcmp0 (property, "true") == 0);
+}
+
+static gchar *
+load_book_source_password_prompt (EBook *book,
+ LoadContext *context,
+ gboolean reprompt)
+{
+ ESource *source;
+ GString *string;
+ const gchar *title;
+ gchar *password;
+ guint32 flags;
+
+ source = e_book_get_source (book);
+ string = g_string_sized_new (256);
+
+ flags = E_PASSWORDS_REMEMBER_FOREVER |
+ E_PASSWORDS_SECRET | E_PASSWORDS_ONLINE;
+
+ if (reprompt) {
+ g_string_assign (string, _("Failed to authenticate.\n"));
+ flags |= E_PASSWORDS_REPROMPT;
+ }
+
+ g_string_append_printf (
+ string, _("Enter password for %s (user %s)"),
+ e_source_peek_name (source), context->auth_username);
+
+ /* XXX Dialog windows should not have titles. */
+ title = "";
+
+ password = e_passwords_ask_password (
+ title, context->auth_component,
+ context->auth_uri, string->str, flags,
+ &context->auth_remember, context->parent);
+
+ g_string_free (string, TRUE);
+
+ return password;
+}
+
+static void
+load_book_source_thread (GSimpleAsyncResult *simple,
+ ESource *source,
+ GCancellable *cancellable)
+{
+ EBook *book;
+ LoadContext *context;
+ gchar *password;
+ gboolean reprompt = FALSE;
+ GError *error = NULL;
+
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ book = e_book_new (source, &error);
+ if (book == NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ return;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_object_unref (book);
+ g_error_free (error);
+ return;
+ }
+
+ if (!e_book_open (book, FALSE, &error)) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_object_unref (book);
+ g_error_free (error);
+ return;
+ }
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_object_unref (book);
+ g_error_free (error);
+ return;
+ }
+
+ /* Do we need to authenticate? */
+ if (context->auth_method == NULL)
+ goto exit;
+
+ password = e_passwords_get_password (
+ context->auth_component, context->auth_uri);
+
+prompt:
+ if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_object_unref (book);
+ g_error_free (error);
+ g_free (password);
+ return;
+ }
+
+ if (password == NULL) {
+ password = load_book_source_password_prompt (
+ book, context, reprompt);
+ reprompt = TRUE;
+ }
+
+ /* If we have a password, attempt to authenticate with it. */
+ if (password != NULL) {
+ e_book_authenticate_user (
+ book, context->auth_username, password,
+ context->auth_method, &error);
+
+ g_free (password);
+ password = NULL;
+
+ /* The user did not wish to provide a password. If the address
+ * book can be accessed anonymously, do that but warn about it. */
+ } else if (e_book_check_static_capability (book, "anon-access")) {
+ context->anonymous_alert = TRUE;
+ goto exit;
+
+ /* Final fallback is to fail. */
+ } else {
+ g_cancellable_cancel (cancellable);
+ goto prompt;
+ }
+
+ /* If authentication failed, forget the password and reprompt. */
+ if (g_error_matches (
+ error, E_BOOK_ERROR, E_BOOK_ERROR_AUTHENTICATION_FAILED)) {
+ e_passwords_forget_password (
+ context->auth_component, context->auth_uri);
+ g_clear_error (&error);
+ goto prompt;
+
+ } else if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
+ g_object_unref (book);
+ g_error_free (error);
+ return;
+ }
+
+exit:
+ context->book = book;
+}
+
/**
* e_load_book_source_async:
* @source: an #ESource
- * @open_func_ex: a function to call when the operation finishes, or %NULL
- * @user_data: data to pass to callback function
+ * @parent: parent window for password dialogs, or %NULL
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: the data to pass to @callback
*
- * Creates a new #EBook specified by @source, and starts a non-blocking
- * open operation on it. If the book requires authorization, presents
- * a window asking the user for such.
+ * Creates a new #EBook specified by @source and opens it, prompting the
+ * user for authentication if necessary.
*
- * When the operation finishes, calls the callback function indicating
- * if it succeeded or not. If you don't care, you can pass %NULL for
- * @open_func_ex, and no action will be taken on completion.
+ * When the operation is finished, @callback will be called. You can
+ * then call e_load_book_source_finish() to obtain the resulting #EBook.
*
- * Returns: A new #EBook that is being opened.
+ * Since: 2.32
+ **/
+void
+e_load_book_source_async (ESource *source,
+ GtkWindow *parent,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ LoadContext *context;
+
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ /* Source must have a group so we can obtain its URI. */
+ g_return_if_fail (e_source_peek_group (source) != NULL);
+
+ if (parent != NULL) {
+ g_return_if_fail (GTK_IS_WINDOW (parent));
+ g_object_ref (parent);
+ }
+
+ if (cancellable != NULL) {
+ g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+ g_object_ref (cancellable);
+ }
+
+ context = g_slice_new0 (LoadContext);
+ context->parent = parent;
+ context->cancellable = cancellable;
+
+ /* Extract authentication details from the ESource before
+ * spawning the thread, since ESource is not thread-safe. */
+ load_book_source_get_auth_details (source, context);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (source), callback,
+ user_data, e_load_book_source_async);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, context, (GDestroyNotify)
+ load_book_source_context_free);
+
+ g_simple_async_result_run_in_thread (
+ simple, (GSimpleAsyncThreadFunc) load_book_source_thread,
+ G_PRIORITY_DEFAULT, context->cancellable);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_load_book_source_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes an asynchronous #EBook open operation started with
+ * e_load_book_source_async(). If an error occurred, or the user
+ * declined to authenticate, the function will return %NULL and
+ * set @error.
+ *
+ * Returns: a ready-to-use #EBook, or %NULL or error
*
* Since: 2.32
**/
EBook *
-e_load_book_source_async (ESource *source, EBookAsyncCallback open_func_ex, gpointer user_data)
+e_load_book_source_finish (ESource *source,
+ GAsyncResult *result,
+ GError **error)
{
- EBook *book;
- LoadSourceData *load_source_data = g_new0 (LoadSourceData, 1);
+ GSimpleAsyncResult *simple;
+ LoadContext *context;
- load_source_data->source = g_object_ref (source);
- load_source_data->open_func_ex = open_func_ex;
- load_source_data->open_func_data = user_data;
+ g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- book = e_book_new (source, NULL);
- if (!book)
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (source),
+ e_load_book_source_async), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
return NULL;
- load_source_data->book = book;
- g_object_ref (book);
- e_book_open_async (book, FALSE, load_source_cb, load_source_data);
+ context = g_simple_async_result_get_op_res_gpointer (simple);
+ g_return_val_if_fail (context != NULL, NULL);
- return book;
+ /* Alert the user that an address book is being accessed anonymously.
+ * FIXME Do not mention "LDAP", as this may apply to other backends. */
+ if (context->anonymous_alert) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (
+ context->parent, 0,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+ _("Accessing LDAP Server anonymously"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+
+ e_source_set_property (
+ source, "remember_password",
+ context->auth_remember ? "true" : "false");
+
+ return g_object_ref (context->book);
}
diff --git a/libedataserverui/e-book-auth-util.h b/libedataserverui/e-book-auth-util.h
index 893991e..b7075b5 100644
--- a/libedataserverui/e-book-auth-util.h
+++ b/libedataserverui/e-book-auth-util.h
@@ -26,12 +26,26 @@
#ifndef E_BOOK_AUTH_UTIL_H
#define E_BOOK_AUTH_UTIL_H
+#include <gtk/gtk.h>
#include <libebook/e-book.h>
+G_BEGIN_DECLS
+
#ifndef E_BOOK_DISABLE_DEPRECATED
-EBook *e_load_book_source (ESource *source, EBookCallback open_func, gpointer user_data);
+EBook * e_load_book_source (ESource *source,
+ EBookCallback open_func,
+ gpointer user_data);
#endif
-EBook *e_load_book_source_async (ESource *source, EBookAsyncCallback open_func, gpointer user_data);
+void e_load_book_source_async (ESource *source,
+ GtkWindow *parent,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+EBook * e_load_book_source_finish (ESource *source,
+ GAsyncResult *result,
+ GError **error);
-#endif
+G_END_DECLS
+
+#endif /* E_BOOK_AUTH_UTIL_H */
diff --git a/libedataserverui/e-name-selector-dialog.c b/libedataserverui/e-name-selector-dialog.c
index 88fe902..c3a58d7 100644
--- a/libedataserverui/e-name-selector-dialog.c
+++ b/libedataserverui/e-name-selector-dialog.c
@@ -58,9 +58,9 @@ typedef struct {
struct _ENameSelectorDialogPrivate {
- EBook *pending_book;
ENameSelectorModel *name_selector_model;
GtkTreeModelSort *contact_sort;
+ GCancellable *cancellable;
GtkBuilder *gui;
GtkTreeView *contact_view;
@@ -460,10 +460,10 @@ remove_books (ENameSelectorDialog *name_selector_dialog)
g_list_free (books);
/* See if we have a book pending; stop loading it if so */
- if (name_selector_dialog->priv->pending_book) {
- e_book_cancel (name_selector_dialog->priv->pending_book, NULL);
- g_object_unref (name_selector_dialog->priv->pending_book);
- name_selector_dialog->priv->pending_book = NULL;
+ if (name_selector_dialog->priv->cancellable != NULL) {
+ g_cancellable_cancel (name_selector_dialog->priv->cancellable);
+ g_object_unref (name_selector_dialog->priv->cancellable);
+ name_selector_dialog->priv->cancellable = NULL;
}
}
@@ -777,51 +777,83 @@ view_complete(EBookView *view, EBookViewStatus status, const gchar *error_msg, E
}
static void
-book_opened (EBook *book, const GError *error, gpointer data)
+book_loaded_cb (ESource *source,
+ GAsyncResult *result,
+ ENameSelectorDialog *name_selector_dialog)
{
- ENameSelectorDialog *name_selector_dialog = E_NAME_SELECTOR_DIALOG (data);
- EContactStore *contact_store;
- EBookView *view;
+ EBook *book;
+ EBookView *view;
+ EContactStore *store;
+ ENameSelectorModel *model;
+ GError *error = NULL;
- if (error) {
- gchar *msg;
+ book = e_load_book_source_finish (source, result, &error);
- msg = g_strdup_printf ("Error loading addressbook, code:%d (%s)", error->code, error->message);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warn_if_fail (book == NULL);
+ g_error_free (error);
+ goto exit;
+ }
- gtk_label_set_text(
- name_selector_dialog->priv->status_label,
- msg);
+ if (error != NULL) {
+ gchar *message;
- g_warning ("ENameSelectorDialog failed to open book! (%d - %s)", error->code, error->message);
+ /* FIXME This shold be translated, no? */
+ message = g_strdup_printf (
+ "Error loading address book: %s", error->message);
+ gtk_label_set_text (
+ name_selector_dialog->priv->status_label, message);
+ g_free (message);
- return;
+ g_warn_if_fail (book == NULL);
+ g_error_free (error);
+ goto exit;
}
- contact_store = e_name_selector_model_peek_contact_store (
- name_selector_dialog->priv->name_selector_model);
- e_contact_store_add_book (contact_store, book);
- view = find_contact_source_by_book_return_view(contact_store, book);
- g_signal_connect(view, "status_message", G_CALLBACK(status_message), name_selector_dialog);
- g_signal_connect(view, "view_complete", G_CALLBACK(view_complete), name_selector_dialog);
+ model = name_selector_dialog->priv->name_selector_model;
+ store = e_name_selector_model_peek_contact_store (model);
+ e_contact_store_add_book (store, book);
+
+ view = find_contact_source_by_book_return_view (store, book);
+
+ g_signal_connect (
+ view, "status-message",
+ G_CALLBACK (status_message), name_selector_dialog);
+
+ g_signal_connect (
+ view, "view-complete",
+ G_CALLBACK (view_complete), name_selector_dialog);
g_object_unref (book);
- name_selector_dialog->priv->pending_book = NULL;
+
+exit:
+ g_object_unref (name_selector_dialog);
}
static void
source_changed (ENameSelectorDialog *name_selector_dialog,
ESourceComboBox *source_combo_box)
{
+ GCancellable *cancellable;
ESource *source;
+ gpointer parent;
source = e_source_combo_box_get_active (source_combo_box);
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (name_selector_dialog));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
/* Remove any previous books being shown or loaded */
remove_books (name_selector_dialog);
+ cancellable = g_cancellable_new ();
+ name_selector_dialog->priv->cancellable = cancellable;
+
/* Start loading selected book */
- name_selector_dialog->priv->pending_book = e_load_book_source_async (
- source, book_opened, name_selector_dialog);
+ e_load_book_source_async (
+ source, parent, cancellable,
+ (GAsyncReadyCallback) book_loaded_cb,
+ g_object_ref (name_selector_dialog));
}
/* --------------- *
diff --git a/libedataserverui/e-name-selector-entry.c b/libedataserverui/e-name-selector-entry.c
index b0422fc..ab44bdc 100644
--- a/libedataserverui/e-name-selector-entry.c
+++ b/libedataserverui/e-name-selector-entry.c
@@ -1948,6 +1948,40 @@ setup_contact_store (ENameSelectorEntry *name_selector_entry)
}
static void
+book_loaded_cb (ESource *source,
+ GAsyncResult *result,
+ ENameSelectorEntry *name_selector_entry)
+{
+ EBook *book;
+ EContactStore *store;
+ GError *error = NULL;
+
+ book = e_load_book_source_finish (source, result, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warn_if_fail (book == NULL);
+ g_error_free (error);
+ goto exit;
+ }
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_warn_if_fail (book == NULL);
+ g_error_free (error);
+ goto exit;
+ }
+
+ g_return_if_fail (E_IS_BOOK (book));
+
+ store = name_selector_entry->priv->contact_store;
+ e_contact_store_add_book (store, book);
+ g_object_unref (book);
+
+exit:
+ g_object_unref (name_selector_entry);
+}
+
+static void
setup_default_contact_store (ENameSelectorEntry *name_selector_entry)
{
GSList *groups;
@@ -1966,8 +2000,7 @@ setup_default_contact_store (ENameSelectorEntry *name_selector_entry)
GSList *m;
for (m = sources; m; m = g_slist_next (m)) {
- ESource *source = m->data;
- EBook *book;
+ ESource *source = m->data;
const gchar *completion;
/* Skip non-completion sources */
@@ -1975,12 +2008,10 @@ setup_default_contact_store (ENameSelectorEntry *name_selector_entry)
if (!completion || g_ascii_strcasecmp (completion, "true"))
continue;
- book = e_load_book_source_async (source, NULL, NULL);
- if (!book)
- continue;
-
- e_contact_store_add_book (name_selector_entry->priv->contact_store, book);
- g_object_unref (book);
+ e_load_book_source_async (
+ source, NULL, NULL,
+ (GAsyncReadyCallback) book_loaded_cb,
+ g_object_ref (name_selector_entry));
}
}
diff --git a/libedataserverui/e-name-selector.c b/libedataserverui/e-name-selector.c
index 96178dd..ec72835 100644
--- a/libedataserverui/e-name-selector.c
+++ b/libedataserverui/e-name-selector.c
@@ -54,84 +54,142 @@ struct _ENameSelectorPrivate {
ENameSelectorDialog *dialog;
GArray *sections;
+ ESourceList *source_list;
- GThread *load_book_thread;
gboolean load_cancelled;
GArray *source_books;
};
G_DEFINE_TYPE (ENameSelector, e_name_selector, G_TYPE_OBJECT)
-static gpointer
-load_books_thread (gpointer user_data)
+static void
+name_selector_book_loaded_cb (ESource *source,
+ GAsyncResult *result,
+ ENameSelector *name_selector)
{
- ENameSelector *name_selector = user_data;
- ENameSelectorPrivate *priv;
- ESourceList *source_list;
- GSList *groups;
- GSList *l;
+ EBook *book;
+ GArray *sections;
+ SourceBook source_book;
+ guint ii;
+ GError *error = NULL;
+
+ book = e_load_book_source_finish (source, result, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "ENameSelector: Could not load \"%s\": %s",
+ e_source_peek_name (source), error->message);
+ g_error_free (error);
+ goto exit;
+ }
- /* XXX This thread is necessary because the e_book_new can block.
- See gnome's bug #540779 for more information. */
+ g_return_if_fail (E_IS_BOOK (book));
- g_return_val_if_fail (name_selector != NULL, NULL);
+ source_book.book = book;
+ source_book.is_completion_book = TRUE;
- priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
+ g_array_append_val (name_selector->priv->source_books, source_book);
+
+ sections = name_selector->priv->sections;
+
+ for (ii = 0; ii < sections->len; ii++) {
+ EContactStore *store;
+ Section *section;
+
+ section = &g_array_index (sections, Section, ii);
+ if (section->entry == NULL)
+ continue;
+
+ store = e_name_selector_entry_peek_contact_store (
+ section->entry);
+ if (store != NULL)
+ e_contact_store_add_book (store, book);
+ }
+
+exit:
+ g_object_unref (name_selector);
+}
+
+static void
+name_selector_load_books (ENameSelector *name_selector)
+{
+ ESourceList *source_list;
+ GSList *groups;
+ GSList *iter1;
if (!e_book_get_addressbooks (&source_list, NULL)) {
g_warning ("ENameSelector can't find any addressbooks!");
- return NULL;
+ return;
}
+ /* This keeps the source groups alive while the async operation
+ * is running, without which e_book_new() can't obtain an absolute
+ * URI for the ESource. We drop the reference in dispose(). */
+ name_selector->priv->source_list = source_list;
+
groups = e_source_list_peek_groups (source_list);
- for (l = groups; l && !priv->load_cancelled; l = g_slist_next (l)) {
- ESourceGroup *group = l->data;
- GSList *sources = e_source_group_peek_sources (group);
- GSList *m;
+ for (iter1 = groups; iter1 != NULL; iter1 = iter1->next) {
+ ESourceGroup *source_group;
+ GSList *sources;
+ GSList *iter2;
+
+ source_group = E_SOURCE_GROUP (iter1->data);
+ sources = e_source_group_peek_sources (source_group);
- for (m = sources; m && !priv->load_cancelled; m = g_slist_next (m)) {
- ESource *source = m->data;
- const gchar *completion;
- SourceBook source_book;
+ for (iter2 = sources; iter2 != NULL; iter2 = iter2->next) {
+ ESource *source;
+ const gchar *property;
- /* We're only loading completion books for now, as we don't want
- * unnecessary auth prompts */
- completion = e_source_get_property (source, "completion");
- if (!completion || g_ascii_strcasecmp (completion, "true"))
+ source = E_SOURCE (iter2->data);
+
+ /* We're only loading completion books for now,
+ * as we don't want unnecessary authentication
+ * prompts. */
+ property = e_source_get_property (source, "completion");
+
+ if (property == NULL)
continue;
- source_book.book = e_load_book_source_async (source, NULL, NULL);
- if (!source_book.book)
+ if (g_ascii_strcasecmp (property, "true") != 0)
continue;
- source_book.is_completion_book = TRUE;
+ /* XXX Should we allow for cancellation? */
+ e_load_book_source_async (
+ source, NULL, NULL,
+ (GAsyncReadyCallback)
+ name_selector_book_loaded_cb,
+ g_object_ref (name_selector));
+ }
+ }
+}
- g_array_append_val (priv->source_books, source_book);
+static void
+name_selector_dispose (GObject *object)
+{
+ ENameSelectorPrivate *priv;
+ guint ii;
- if (!priv->load_cancelled) {
- EContactStore *store;
+ priv = E_NAME_SELECTOR_GET_PRIVATE (object);
- if (name_selector->priv->sections) {
- gint j;
+ if (priv->source_list != NULL) {
+ g_object_unref (priv->source_list);
+ priv->source_list = NULL;
+ }
- for (j = 0; j < name_selector->priv->sections->len && !priv->load_cancelled; j++) {
- Section *section = &g_array_index (name_selector->priv->sections, Section, j);
+ for (ii = 0; ii < priv->source_books->len; ii++) {
+ SourceBook *source_book;
- if (section->entry) {
- store = e_name_selector_entry_peek_contact_store (section->entry);
- if (store)
- e_contact_store_add_book (store, source_book.book);
- }
- }
- }
- }
- }
+ source_book = &g_array_index (
+ priv->source_books, SourceBook, ii);
+ if (source_book->book != NULL)
+ g_object_unref (source_book->book);
}
- g_object_unref (source_list);
+ g_array_set_size (priv->source_books, 0);
- return NULL;
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_name_selector_parent_class)->dispose (object);
}
static void
@@ -141,27 +199,9 @@ name_selector_finalize (GObject *object)
priv = E_NAME_SELECTOR_GET_PRIVATE (object);
- if (priv->load_book_thread) {
- priv->load_cancelled = TRUE;
- g_thread_join (priv->load_book_thread);
- priv->load_book_thread = NULL;
- }
-
- if (priv->source_books) {
- gint i;
-
- for (i = 0; i < priv->source_books->len; i++) {
- SourceBook *source_book = &g_array_index (priv->source_books, SourceBook, i);
+ g_array_free (priv->source_books, TRUE);
- if (source_book->book)
- g_object_unref (source_book->book);
- }
-
- g_array_free (priv->source_books, TRUE);
- priv->source_books = NULL;
- }
-
- /* Chain up to parent's finalize() methods. */
+ /* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_name_selector_parent_class)->finalize (object);
}
@@ -173,6 +213,7 @@ e_name_selector_class_init (ENameSelectorClass *class)
g_type_class_add_private (class, sizeof (ENameSelectorPrivate));
object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = name_selector_dispose;
object_class->finalize = name_selector_finalize;
}
@@ -181,7 +222,6 @@ e_name_selector_init (ENameSelector *name_selector)
{
GArray *sections;
GArray *source_books;
- GThread *load_book_thread;
sections = g_array_new (FALSE, FALSE, sizeof (Section));
source_books = g_array_new (FALSE, FALSE, sizeof (SourceBook));
@@ -190,11 +230,8 @@ e_name_selector_init (ENameSelector *name_selector)
name_selector->priv->sections = sections;
name_selector->priv->model = e_name_selector_model_new ();
name_selector->priv->source_books = source_books;
- name_selector->priv->load_book_thread = load_book_thread;
-
- load_book_thread = g_thread_create (
- load_books_thread, name_selector, TRUE, NULL);
+ name_selector_load_books (name_selector);
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]