[evolution-data-server] EDataBookFactor / EDataBook: Migrated locale handling to EDataBookFactory



commit c8914fc768a69360cef64a65424e05a2f39d25b3
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Sat Nov 30 01:19:04 2013 +0900

    EDataBookFactor / EDataBook: Migrated locale handling to EDataBookFactory
    
    The EDataBookFactory is the server side singleton, this is the right
    place to handle locale changes, now each EDataBook is set into the
    correct locale by the factory, when books are created, and when the
    locale change notification arrives.

 addressbook/libedata-book/e-data-book-cursor.c  |    1 +
 addressbook/libedata-book/e-data-book-factory.c |  250 +++++++++++++++++++++++
 addressbook/libedata-book/e-data-book.c         |  227 ++++-----------------
 addressbook/libedata-book/e-data-book.h         |    5 +
 4 files changed, 294 insertions(+), 189 deletions(-)
---
diff --git a/addressbook/libedata-book/e-data-book-cursor.c b/addressbook/libedata-book/e-data-book-cursor.c
index 6e44c1d..341aa48 100644
--- a/addressbook/libedata-book/e-data-book-cursor.c
+++ b/addressbook/libedata-book/e-data-book-cursor.c
@@ -667,6 +667,7 @@ data_book_cursor_handle_dispose (EDBusAddressBookCursor *dbus_object,
                g_warning ("Error trying to delete cursor: %s", error->message);
                g_clear_error (&error);
        }
+
        e_dbus_address_book_cursor_complete_dispose (dbus_object, invocation);
 
        g_object_unref (cursor);
diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c
index 7017aa1..6e06116 100644
--- a/addressbook/libedata-book/e-data-book-factory.c
+++ b/addressbook/libedata-book/e-data-book-factory.c
@@ -33,6 +33,7 @@
 #include "e-book-backend-factory.h"
 #include "e-data-book.h"
 #include "e-data-book-factory.h"
+#include "e-dbus-localed.h"
 
 #define d(x)
 
@@ -53,6 +54,12 @@ struct _EDataBookFactoryPrivate {
         * The value is the watcher ID for g_bus_unwatch_name(). */
        GHashTable *watched_names;
        GMutex watched_names_lock;
+
+       /* Watching "org.freedesktop.locale1" for locale changes */
+       guint localed_watch_id;
+       EDBusLocale1 *localed_proxy;
+       GCancellable *localed_cancel;
+       gchar *locale;
 };
 
 enum {
@@ -304,6 +311,43 @@ data_book_factory_closed_cb (EBookBackend *backend,
        data_book_factory_connections_remove (factory, sender, backend);
 }
 
+/* This is totally backwards, for some insane reason we holding
+ * references to the EBookBackends and then fetching the EDataBook
+ * via e_book_backend_ref_data_book(), the whole scheme should
+ * be reversed and this function probably removed.
+ */
+static GList *
+data_book_factory_list_books (EDataBookFactory *factory)
+{
+       GList *books = NULL;
+       GHashTable *connections;
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_mutex_lock (&factory->priv->connections_lock);
+
+       connections = factory->priv->connections;
+
+       g_hash_table_iter_init (&iter, connections);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               GPtrArray *array = (GPtrArray *)value;
+               gint i;
+
+               for (i = 0; i < array->len; i++) {
+                       EBookBackend *backend = g_ptr_array_index (array, i);
+                       EDataBook *book = e_book_backend_ref_data_book (backend);
+
+                       if (g_list_find (books, book) == NULL)
+                               books = g_list_prepend (books, book);
+                       else
+                               g_object_unref (book);
+               }
+       }
+       g_mutex_unlock (&factory->priv->connections_lock);
+
+       return books;
+}
+
 static gchar *
 data_book_factory_open (EDataBookFactory *factory,
                         GDBusConnection *connection,
@@ -375,6 +419,13 @@ data_book_factory_open (EDataBookFactory *factory,
                                G_CALLBACK (data_book_factory_closed_cb),
                                factory, 0);
 
+                       /* Don't set the locale on a new book if we have not
+                        * yet received a notification of a locale change
+                        */
+                       if (factory->priv->locale)
+                               e_data_book_set_locale (data_book,
+                                                       factory->priv->locale,
+                                                       NULL, NULL);
                } else {
                        g_free (object_path);
                        object_path = NULL;
@@ -464,6 +515,20 @@ data_book_factory_dispose (GObject *object)
                priv->dbus_factory = NULL;
        }
 
+       if (priv->localed_cancel) {
+               g_cancellable_cancel (priv->localed_cancel);
+               g_object_unref (priv->localed_cancel);
+               priv->localed_cancel = NULL;
+       }
+
+       if (priv->localed_proxy) {
+               g_object_unref (priv->localed_proxy);
+               priv->localed_proxy = NULL;
+       }
+
+       if (priv->localed_watch_id > 0)
+               g_bus_unwatch_name (priv->localed_watch_id);
+
        g_hash_table_remove_all (priv->connections);
        g_hash_table_remove_all (priv->watched_names);
 
@@ -484,6 +549,8 @@ data_book_factory_finalize (GObject *object)
        g_hash_table_destroy (priv->watched_names);
        g_mutex_clear (&priv->watched_names_lock);
 
+       g_free (priv->locale);
+
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_data_book_factory_parent_class)->finalize (object);
 }
@@ -546,17 +613,200 @@ data_book_factory_quit_server (EDBusServer *server,
                quit_server (server, exit_code);
 }
 
+static gchar *
+data_book_factory_interpret_locale_value (const gchar *value)
+{
+       gchar *interpreted_value = NULL;
+       gchar **split;
+
+       split = g_strsplit (value, "=", 2);
+
+       if (split && split[0] && split[1])
+               interpreted_value = g_strdup (split[1]);
+
+       g_strfreev (split);
+
+       if (!interpreted_value)
+               g_warning ("Failed to interpret locale value: %s", value);
+
+       return interpreted_value;
+}
+
+static gchar *
+data_book_factory_interpret_locale (const gchar * const * locale)
+{
+       gint i;
+       gchar *interpreted_locale = NULL;
+
+       /* Prioritize LC_COLLATE and then LANG values
+        * in the 'locale' specified by localed.
+        *
+        * If localed explicitly specifies no locale, then
+        * default to checking system locale.
+        */
+       if (locale) {
+               for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
+                       if (strncmp (locale[i], "LC_COLLATE", 10) == 0)
+                               interpreted_locale = 
+                                       data_book_factory_interpret_locale_value (locale[i]);
+               }
+
+               for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
+                       if (strncmp (locale[i], "LANG", 4) == 0)
+                               interpreted_locale = 
+                                       data_book_factory_interpret_locale_value (locale[i]);
+               }
+       }
+
+       if (!interpreted_locale) {
+               const gchar *system_locale = setlocale (LC_COLLATE, NULL);
+
+               interpreted_locale = g_strdup (system_locale);
+       }
+
+       return interpreted_locale;
+}
+
+static void
+data_book_factory_set_locale (EDataBookFactory *factory,
+                             const gchar *locale)
+{
+       EDataBookFactoryPrivate *priv = factory->priv;
+       GError *error = NULL;
+       GList *books, *l;
+
+       if (g_strcmp0 (priv->locale, locale) != 0) {
+
+               g_free (priv->locale);
+               priv->locale = g_strdup (locale);
+
+               books = data_book_factory_list_books (factory);
+               for (l = books; l; l = l->next) {
+                       EDataBook *book = l->data;
+
+                       if (!e_data_book_set_locale (book, locale, NULL, &error)) {
+                               g_warning ("Failed to set locale on addressbook: %s",
+                                          error->message);
+                               g_clear_error (&error);
+                       }
+               }
+               g_list_free_full (books, g_object_unref);
+       }
+}
+
+static void
+data_book_factory_locale_changed (GObject *object,
+                                 GParamSpec *pspec,
+                                 gpointer user_data)
+{
+       EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object);
+       EDataBookFactory *factory = (EDataBookFactory *)user_data;
+       const gchar * const *locale;
+       gchar *interpreted_locale;
+
+       locale = e_dbus_locale1_get_locale (locale_proxy);
+       interpreted_locale = data_book_factory_interpret_locale (locale);
+
+       data_book_factory_set_locale (factory, interpreted_locale);
+
+       g_free (interpreted_locale);
+}
+
+static void
+data_book_factory_localed_ready (GObject *source_object,
+                                GAsyncResult *res,
+                                gpointer user_data)
+{
+       EDataBookFactory *factory = (EDataBookFactory *)user_data;
+       GError *error = NULL;
+
+       factory->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error);
+
+       if (factory->priv->localed_proxy == NULL) {
+               g_warning ("Error fetching localed proxy: %s", error->message);
+               g_error_free (error);
+       }
+
+       if (factory->priv->localed_cancel) {
+               g_object_unref (factory->priv->localed_cancel);
+               factory->priv->localed_cancel = NULL;
+       }
+
+       if (factory->priv->localed_proxy) {
+               g_signal_connect (factory->priv->localed_proxy, "notify::locale",
+                                 G_CALLBACK (data_book_factory_locale_changed), factory);
+
+               /* Initial refresh of the locale */
+               data_book_factory_locale_changed (G_OBJECT (factory->priv->localed_proxy), NULL, factory);
+       }
+}
+
+static void
+data_book_factory_localed_appeared (GDBusConnection *connection,
+                                   const gchar *name,
+                                   const gchar *name_owner,
+                                   gpointer user_data)
+{
+       EDataBookFactory *factory = (EDataBookFactory *)user_data;
+
+       factory->priv->localed_cancel = g_cancellable_new ();
+
+       e_dbus_locale1_proxy_new (connection,
+                                 G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
+                                 "org.freedesktop.locale1",
+                                 "/org/freedesktop/locale1",
+                                 factory->priv->localed_cancel,
+                                 data_book_factory_localed_ready,
+                                 factory);
+}
+
+static void
+data_book_factory_localed_vanished (GDBusConnection *connection,
+                                   const gchar *name,
+                                   gpointer user_data)
+{
+       EDataBookFactory *factory = (EDataBookFactory *)user_data;
+
+       if (factory->priv->localed_cancel) {
+               g_cancellable_cancel (factory->priv->localed_cancel);
+               g_object_unref (factory->priv->localed_cancel);
+               factory->priv->localed_cancel = NULL;
+       }
+
+       if (factory->priv->localed_proxy) {
+               g_object_unref (factory->priv->localed_proxy);
+               factory->priv->localed_proxy = NULL;
+       }
+}
+
 static gboolean
 data_book_factory_initable_init (GInitable *initable,
                                  GCancellable *cancellable,
                                  GError **error)
 {
        EDataBookFactoryPrivate *priv;
+       GBusType bus_type = G_BUS_TYPE_SYSTEM;
 
        priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (initable);
 
        priv->registry = e_source_registry_new_sync (cancellable, error);
 
+       /* When running tests, we pretend to be the "org.freedesktop.locale1" service
+        * on the session bus instead of the real location on the system bus.
+        */
+       if (g_getenv ("EDS_TESTING") != NULL)
+               bus_type = G_BUS_TYPE_SESSION;
+
+       /* Watch system bus for locale change notifications */
+       priv->localed_watch_id =
+               g_bus_watch_name (bus_type,
+                                 "org.freedesktop.locale1",
+                                 G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                 data_book_factory_localed_appeared,
+                                 data_book_factory_localed_vanished,
+                                 initable,
+                                 NULL);
+
        return (priv->registry != NULL);
 }
 
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 935b1f5..97b04b2 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -37,7 +37,6 @@
 #include "e-book-backend.h"
 #include "e-book-backend-sexp.h"
 #include "e-book-backend-factory.h"
-#include "e-dbus-localed.h"
 
 #define E_DATA_BOOK_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -56,10 +55,6 @@ struct _EDataBookPrivate {
 
        GMutex sender_lock;
        GHashTable *sender_table;
-
-       guint localed_watch_id;
-       EDBusLocale1 *localed_proxy;
-       GCancellable *localed_cancel;
 };
 
 struct _AsyncContext {
@@ -1644,159 +1639,6 @@ e_data_book_report_backend_property_changed (EDataBook *book,
        /* Disregard anything else. */
 }
 
-static gchar *
-data_book_interpret_locale_value (const gchar *value)
-{
-       gchar *interpreted_value = NULL;
-       gchar **split;
-
-       split = g_strsplit (value, "=", 2);
-
-       if (split && split[0] && split[1])
-               interpreted_value = g_strdup (split[1]);
-
-       g_strfreev (split);
-
-       if (!interpreted_value)
-               g_warning ("Failed to interpret locale value: %s", value);
-
-       return interpreted_value;
-}
-
-static gchar *
-data_book_interpret_locale (const gchar * const * locale)
-{
-       gint i;
-       gchar *interpreted_locale = NULL;
-
-       /* Prioritize LC_COLLATE and then LANG values
-        * in the 'locale' specified by localed.
-        *
-        * If localed explicitly specifies no locale, then
-        * default to checking system locale.
-        */
-       if (locale) {
-
-               for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
-
-                       if (strncmp (locale[i], "LC_COLLATE", 10) == 0)
-                               interpreted_locale = data_book_interpret_locale_value (locale[i]);
-               }
-
-               for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
-
-                       if (strncmp (locale[i], "LANG", 4) == 0)
-                               interpreted_locale = data_book_interpret_locale_value (locale[i]);
-               }
-       }
-
-       if (!interpreted_locale) {
-               const gchar *system_locale = setlocale (LC_COLLATE, NULL);
-
-               interpreted_locale = g_strdup (system_locale);
-       }
-
-       return interpreted_locale;
-}
-
-static void
-data_book_locale_changed (GObject *object,
-                         GParamSpec *pspec,
-                         gpointer user_data)
-{
-       EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object);
-       EDataBook *book = (EDataBook *)user_data;
-       EBookBackend *backend;
-
-       backend = e_data_book_ref_backend (book);
-
-       if (backend) {
-               const gchar * const *locale;
-               gchar *interpreted_locale;
-
-               locale = e_dbus_locale1_get_locale (locale_proxy);
-               interpreted_locale = data_book_interpret_locale (locale);
-
-               /* XXX This needs work, the whole handling should be done
-                * by the singleton EDataBookFactory, and handle errors well
-                */
-               e_book_backend_set_locale (backend, interpreted_locale, NULL, NULL);
-
-               e_dbus_address_book_set_locale (book->priv->dbus_interface, interpreted_locale);
-
-               g_free (interpreted_locale);
-       }
-
-       g_object_unref (backend);
-}
-
-static void
-data_book_localed_ready (GObject *source_object,
-                        GAsyncResult *res,
-                        gpointer user_data)
-{
-       EDataBook *book = (EDataBook *)user_data;
-       GError *error = NULL;
-
-       book->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error);
-
-       if (book->priv->localed_proxy == NULL) {
-               g_warning ("Error fetching localed proxy: %s", error->message);
-               g_error_free (error);
-       }
-
-       if (book->priv->localed_cancel) {
-               g_object_unref (book->priv->localed_cancel);
-               book->priv->localed_cancel = NULL;
-       }
-
-       if (book->priv->localed_proxy) {
-               g_signal_connect (book->priv->localed_proxy, "notify::locale",
-                                 G_CALLBACK (data_book_locale_changed), book);
-
-               /* Initial refresh of the locale */
-               data_book_locale_changed (G_OBJECT (book->priv->localed_proxy), NULL, book);
-       }
-}
-
-static void
-data_book_localed_appeared (GDBusConnection *connection,
-                           const gchar *name,
-                           const gchar *name_owner,
-                           gpointer user_data)
-{
-       EDataBook *book = (EDataBook *)user_data;
-
-       book->priv->localed_cancel = g_cancellable_new ();
-
-       e_dbus_locale1_proxy_new (connection,
-                                 G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
-                                 "org.freedesktop.locale1",
-                                 "/org/freedesktop/locale1",
-                                 book->priv->localed_cancel,
-                                 data_book_localed_ready,
-                                 book);
-}
-
-static void
-data_book_localed_vanished (GDBusConnection *connection,
-                           const gchar *name,
-                           gpointer user_data)
-{
-       EDataBook *book = (EDataBook *)user_data;
-
-       if (book->priv->localed_cancel) {
-               g_cancellable_cancel (book->priv->localed_cancel);
-               g_object_unref (book->priv->localed_cancel);
-               book->priv->localed_cancel = NULL;
-       }
-
-       if (book->priv->localed_proxy) {
-               g_object_unref (book->priv->localed_proxy);
-               book->priv->localed_proxy = NULL;
-       }
-}
-
 static void
 data_book_set_backend (EDataBook *book,
                        EBookBackend *backend)
@@ -1912,17 +1754,6 @@ data_book_dispose (GObject *object)
                priv->direct_module = NULL;
        }
 
-       if (priv->localed_cancel) {
-               g_cancellable_cancel (priv->localed_cancel);
-               g_object_unref (priv->localed_cancel);
-               priv->localed_cancel = NULL;
-       }
-
-       if (priv->localed_proxy) {
-               g_object_unref (priv->localed_proxy);
-               priv->localed_proxy = NULL;
-       }
-
        g_hash_table_remove_all (priv->sender_table);
 
        /* Chain up to parent's dispose() metnod. */
@@ -1946,9 +1777,6 @@ data_book_finalize (GObject *object)
                priv->dbus_interface = NULL;
        }
 
-       if (priv->localed_watch_id > 0)
-               g_bus_unwatch_name (priv->localed_watch_id);
-
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_data_book_parent_class)->finalize (object);
 }
@@ -2028,7 +1856,6 @@ data_book_initable_init (GInitable *initable,
        EBookBackend *backend;
        EDataBook *book;
        gchar *locale;
-       GBusType bus_type = G_BUS_TYPE_SYSTEM;
 
        book = E_DATA_BOOK (initable);
 
@@ -2065,22 +1892,6 @@ data_book_initable_init (GInitable *initable,
        e_dbus_address_book_set_locale (book->priv->dbus_interface, locale);
        g_free (locale);
 
-       /* When running tests, we pretend to be the "org.freedesktop.locale1" service
-        * on the session bus instead of the real location on the system bus.
-        */
-       if (g_getenv ("EDS_TESTING") != NULL)
-               bus_type = G_BUS_TYPE_SESSION;
-
-       /* Watch system bus for locale change notifications */
-       book->priv->localed_watch_id =
-               g_bus_watch_name (bus_type,
-                                 "org.freedesktop.locale1",
-                                 G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                 data_book_localed_appeared,
-                                 data_book_localed_vanished,
-                                 book,
-                                 NULL);
-
        return g_dbus_interface_skeleton_export (
                G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface),
                book->priv->connection,
@@ -2303,3 +2114,41 @@ e_data_book_get_object_path (EDataBook *book)
        return book->priv->object_path;
 }
 
+/**
+ * e_data_book_set_locale:
+ * @book: an #EDataBook 
+ * @locale: the new locale to set for this book
+ * @cancellable: (allow-none): a #GCancellable
+ * @error: (allow-none): a location to store any error which might occur
+ *
+ * Set's the locale for this addressbook, this can result in renormalization of
+ * locale sensitive data.
+ *
+ * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
+ *
+ * Since: 3.12
+ */
+gboolean
+e_data_book_set_locale (EDataBook *book,
+                       const gchar *locale,
+                       GCancellable *cancellable,
+                       GError **error)
+{
+       EBookBackend *backend;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+
+       backend = e_data_book_ref_backend (book);
+       success = e_book_backend_set_locale (backend,
+                                            locale,
+                                            cancellable,
+                                            error);
+
+       if (success)
+               e_dbus_address_book_set_locale (book->priv->dbus_interface, locale);
+
+       g_object_unref (backend);
+
+       return success;
+}
diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h
index d3bc9a2..e7d0949 100644
--- a/addressbook/libedata-book/e-data-book.h
+++ b/addressbook/libedata-book/e-data-book.h
@@ -106,6 +106,10 @@ GDBusConnection *
                e_data_book_get_connection      (EDataBook *book);
 const gchar *  e_data_book_get_object_path     (EDataBook *book);
 
+gboolean        e_data_book_set_locale          (EDataBook *book,
+                                                const gchar *locale,
+                                                GCancellable *cancellable,
+                                                GError **error);
 void           e_data_book_respond_open        (EDataBook *book,
                                                 guint32 opid,
                                                 GError *error);
@@ -152,6 +156,7 @@ void                e_data_book_report_backend_property_changed
 gchar *                e_data_book_string_slist_to_comma_string
                                                (const GSList *strings);
 
+
 G_END_DECLS
 
 #endif /* E_DATA_BOOK_H */


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