From 977be20ced747224c0e08d565f961f0fa8d0baf8 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 1 Mar 2013 12:19:40 -0500 Subject: Add EClientComboBox. --- e-util/Makefile.am | 2 + e-util/e-client-combo-box.c | 461 ++++++++++++++++++++++++++++++++++++++++++++ e-util/e-client-combo-box.h | 92 +++++++++ e-util/e-util.h | 1 + 4 files changed, 556 insertions(+) create mode 100644 e-util/e-client-combo-box.c create mode 100644 e-util/e-client-combo-box.h (limited to 'e-util') diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 3eca4435d7..9fa1877396 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -159,6 +159,7 @@ eutilinclude_HEADERS = \ e-charset-combo-box.h \ e-charset.h \ e-client-cache.h \ + e-client-combo-box.h \ e-client-selector.h \ e-config.h \ e-contact-store.h \ @@ -406,6 +407,7 @@ libeutil_la_SOURCES = \ e-charset-combo-box.c \ e-charset.c \ e-client-cache.c \ + e-client-combo-box.c \ e-client-selector.c \ e-config.c \ e-contact-store.c \ diff --git a/e-util/e-client-combo-box.c b/e-util/e-client-combo-box.c new file mode 100644 index 0000000000..657b5b6ac6 --- /dev/null +++ b/e-util/e-client-combo-box.c @@ -0,0 +1,461 @@ +/* + * e-client-combo-box.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +/** + * SECTION: e-client-combo-box + * @include: e-util/e-util.h + * @short_description: Combo box of #EClient instances + * + * #EClientComboBox extends the functionality of #ESourceComboBox by + * providing convenient access to #EClient instances with #EClientCache. + * + * As a future enhancement, this widget may also display status information + * about the backends associated with the displayed data sources, similar to + * #EClientSelector. + **/ + +#include "e-client-combo-box.h" + +#define E_CLIENT_COMBO_BOX_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_CLIENT_COMBO_BOX, EClientComboBoxPrivate)) + +struct _EClientComboBoxPrivate { + EClientCache *client_cache; +}; + +enum { + PROP_0, + PROP_CLIENT_CACHE +}; + +G_DEFINE_TYPE ( + EClientComboBox, + e_client_combo_box, + E_TYPE_SOURCE_COMBO_BOX) + +static void +client_combo_box_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CLIENT_CACHE: + e_client_combo_box_set_client_cache ( + E_CLIENT_COMBO_BOX (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +client_combo_box_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CLIENT_CACHE: + g_value_take_object ( + value, + e_client_combo_box_ref_client_cache ( + E_CLIENT_COMBO_BOX (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +client_combo_box_dispose (GObject *object) +{ + EClientComboBoxPrivate *priv; + + priv = E_CLIENT_COMBO_BOX_GET_PRIVATE (object); + + g_clear_object (&priv->client_cache); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_client_combo_box_parent_class)->dispose (object); +} + +static void +e_client_combo_box_class_init (EClientComboBoxClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EClientComboBoxPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = client_combo_box_set_property; + object_class->get_property = client_combo_box_get_property; + object_class->dispose = client_combo_box_dispose; + + /** + * EClientComboBox:client-cache: + * + * Cache of shared #EClient instances. + **/ + /* XXX Don't use G_PARAM_CONSTRUCT_ONLY here. We need to allow + * for this class to be instantiated by a GtkBuilder with no + * special construct parameters, and then subsequently give + * it an EClientCache. */ + g_object_class_install_property ( + object_class, + PROP_CLIENT_CACHE, + g_param_spec_object ( + "client-cache", + "Client Cache", + "Cache of shared EClient instances", + E_TYPE_CLIENT_CACHE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +e_client_combo_box_init (EClientComboBox *combo_box) +{ + combo_box->priv = E_CLIENT_COMBO_BOX_GET_PRIVATE (combo_box); +} + +/** + * e_client_combo_box_new: + * @client_cache: an #EClientCache + * @extension_name: the name of an #ESource extension + * + * Creates a new #EClientComboBox widget that lets the user pick an #ESource + * from the provided @client_cache. The displayed sources are restricted to + * those which have an @extension_name extension. + * + * Returns: a new #EClientComboBox + **/ +GtkWidget * +e_client_combo_box_new (EClientCache *client_cache, + const gchar *extension_name) +{ + ESourceRegistry *registry; + GtkWidget *widget; + + g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL); + g_return_val_if_fail (extension_name != NULL, NULL); + + registry = e_client_cache_ref_registry (client_cache); + + widget = g_object_new ( + E_TYPE_CLIENT_COMBO_BOX, + "client-cache", client_cache, + "extension-name", extension_name, + "registry", registry, NULL); + + g_object_unref (registry); + + return widget; +} + +/** + * e_client_combo_box_ref_client_cache: + * @combo_box: an #EClientComboBox + * + * Returns the #EClientCache passed to e_client_combo_box_new(). + * + * The returned #EClientCache is referenced for thread-safety and must be + * unreferenced with g_object_unref() when finished with it. + * + * Returns: an #EClientCache + **/ +EClientCache * +e_client_combo_box_ref_client_cache (EClientComboBox *combo_box) +{ + g_return_val_if_fail (E_IS_CLIENT_COMBO_BOX (combo_box), NULL); + + return g_object_ref (combo_box->priv->client_cache); +} + +/** + * e_client_combo_box_set_client_cache: + * @combo_box: an #EClientComboBox + * + * Simultaneously sets the #EClientComboBox:client-cache and + * #ESourceComboBox:registry properties. + * + * This function is intended for cases where @combo_box is instantiated + * by a #GtkBuilder and has to be given an #EClientCache after it is fully + * constructed. + **/ +void +e_client_combo_box_set_client_cache (EClientComboBox *combo_box, + EClientCache *client_cache) +{ + ESourceRegistry *registry = NULL; + + g_return_if_fail (E_IS_CLIENT_COMBO_BOX (combo_box)); + + if (combo_box->priv->client_cache == client_cache) + return; + + if (client_cache != NULL) { + g_return_if_fail (E_IS_CLIENT_CACHE (client_cache)); + g_object_ref (client_cache); + } + + if (combo_box->priv->client_cache != NULL) + g_object_unref (combo_box->priv->client_cache); + + combo_box->priv->client_cache = client_cache; + + if (client_cache != NULL) + registry = e_client_cache_ref_registry (client_cache); + + e_source_combo_box_set_registry ( + E_SOURCE_COMBO_BOX (combo_box), registry); + + g_clear_object (®istry); + + g_object_notify (G_OBJECT (combo_box), "client-cache"); +} + +/** + * e_client_combo_box_get_client_sync: + * @combo_box: an #EClientComboBox + * @source: an #ESource + * @cancellable: optional #GCancellable object, or %NULL + * @error: return location for a #GError, or %NULL + * + * Obtains a shared #EClient instance for @source, or else creates a new + * #EClient instance to be shared. + * + * The #ESourceComboBox:extension-name property determines the type of + * #EClient to obtain. See e_client_cache_get_client_sync() for a list + * of valid extension names. + * + * If a request for the same @source and #ESourceComboBox:extension-name + * is already in progress when this function is called, this request will + * "piggyback" on the in-progress request such that they will both succeed + * or fail simultaneously. + * + * Unreference the returned #EClient with g_object_unref() when finished + * with it. If an error occurs, the function will set @error and return + * %NULL. + * + * Returns: an #EClient, or %NULL + **/ +EClient * +e_client_combo_box_get_client_sync (EClientComboBox *combo_box, + ESource *source, + GCancellable *cancellable, + GError **error) +{ + EAsyncClosure *closure; + GAsyncResult *result; + EClient *client; + + g_return_val_if_fail (E_IS_CLIENT_COMBO_BOX (combo_box), NULL); + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + closure = e_async_closure_new (); + + e_client_combo_box_get_client ( + combo_box, source, cancellable, + e_async_closure_callback, closure); + + result = e_async_closure_wait (closure); + + client = e_client_combo_box_get_client_finish ( + combo_box, result, error); + + e_async_closure_free (closure); + + return client; +} + +/* Helper for e_client_combo_box_get_client() */ +static void +client_combo_box_get_client_done_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + EClient *client; + GSimpleAsyncResult *simple; + GError *error = NULL; + + simple = G_SIMPLE_ASYNC_RESULT (user_data); + + client = e_client_cache_get_client_finish ( + E_CLIENT_CACHE (source_object), result, &error); + + /* Sanity check. */ + g_return_if_fail ( + ((client != NULL) && (error == NULL)) || + ((client == NULL) && (error != NULL))); + + if (client != NULL) { + g_simple_async_result_set_op_res_gpointer ( + simple, g_object_ref (client), + (GDestroyNotify) g_object_unref); + g_object_unref (client); + } + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + + g_simple_async_result_complete (simple); + + g_object_unref (simple); +} + +/** + * e_client_combo_box_get_client: + * @combo_box: an #EClientComboBox + * @source: an #ESource + * @cancellable: optional #GCancellable object, or %NULL + * @callback: a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: data to pass to the callback function + * + * Asynchronously obtains a shared #EClient instance for @source, or else + * creates a new #EClient instance to be shared. + * + * The #ESourceComboBox:extension-name property determines the type of + * #EClient to obtain. See e_client_cache_get_client_sync() for a list + * of valid extension names. + * + * If a request for the same @source and #ESourceComboBox:extension-name + * is already in progress when this function is called, this request will + * "piggyback" on the in-progress request such that they will both succeed + * or fail simultaneously. + * + * When the operation is finished, @callback will be called. You can + * then call e_client_combo_box_get_client_finish() to get the result of + * the operation. + **/ +void +e_client_combo_box_get_client (EClientComboBox *combo_box, + ESource *source, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + EClientCache *client_cache; + GSimpleAsyncResult *simple; + const gchar *extension_name; + + g_return_if_fail (E_IS_CLIENT_COMBO_BOX (combo_box)); + g_return_if_fail (E_IS_SOURCE (source)); + + simple = g_simple_async_result_new ( + G_OBJECT (combo_box), callback, + user_data, e_client_combo_box_get_client); + + g_simple_async_result_set_check_cancellable (simple, cancellable); + + extension_name = e_source_combo_box_get_extension_name ( + E_SOURCE_COMBO_BOX (combo_box)); + + client_cache = e_client_combo_box_ref_client_cache (combo_box); + + e_client_cache_get_client ( + client_cache, source, + extension_name, cancellable, + client_combo_box_get_client_done_cb, + g_object_ref (simple)); + + g_object_unref (client_cache); + + g_object_unref (simple); +} + +/** + * e_client_combo_box_get_client_finish: + * @combo_box: an #EClientComboBox + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes the operation started with e_client_combo_box_get_client(). + * + * Unreference the returned #EClient with g_object_unref() when finished + * with it. If an error occurred, the function will set @error and return + * %NULL. + * + * Returns: an #EClient, or %NULL + **/ +EClient * +e_client_combo_box_get_client_finish (EClientComboBox *combo_box, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + EClient *client; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (combo_box), + e_client_combo_box_get_client), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + client = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + g_return_val_if_fail (client != NULL, NULL); + + return g_object_ref (client); +} + +/** + * e_client_combo_box_ref_cached_client: + * @combo_box: an #EClientComboBox + * @source: an #ESource + * + * Returns a shared #EClient instance for @source and the value of + * #ESourceComboBox:extension-name if such an instance is already cached, + * or else %NULL. This function does not create a new #EClient instance, + * and therefore does not block. + * + * The returned #EClient is referenced for thread-safety and must be + * unreferenced with g_object_unref() when finished with it. + * + * Returns: an #EClient, or %NULL + **/ +EClient * +e_client_combo_box_ref_cached_client (EClientComboBox *combo_box, + ESource *source) +{ + EClient *client; + EClientCache *client_cache; + const gchar *extension_name; + + g_return_val_if_fail (E_IS_CLIENT_COMBO_BOX (combo_box), NULL); + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + + extension_name = e_source_combo_box_get_extension_name ( + E_SOURCE_COMBO_BOX (combo_box)); + + client_cache = e_client_combo_box_ref_client_cache (combo_box); + + client = e_client_cache_ref_cached_client ( + client_cache, source, extension_name); + + g_object_unref (client_cache); + + return client; +} + diff --git a/e-util/e-client-combo-box.h b/e-util/e-client-combo-box.h new file mode 100644 index 0000000000..e48c9df31d --- /dev/null +++ b/e-util/e-client-combo-box.h @@ -0,0 +1,92 @@ +/* + * e-client-combo-box.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_CLIENT_COMBO_BOX_H +#define E_CLIENT_COMBO_BOX_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_CLIENT_COMBO_BOX \ + (e_client_combo_box_get_type ()) +#define E_CLIENT_COMBO_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CLIENT_COMBO_BOX, EClientComboBox)) +#define E_CLIENT_COMBO_BOX_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_CLIENT_COMBO_BOX, EClientComboBoxClass)) +#define E_IS_CLIENT_COMBO_BOX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CLIENT_COMBO_BOX)) +#define E_IS_CLIENT_COMBO_BOX_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_CLIENT_COMBO_BOX)) +#define E_CLIENT_COMBO_BOX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_CLIENT_COMBO_BOX, EClientComboBoxClass)) + +G_BEGIN_DECLS + +typedef struct _EClientComboBox EClientComboBox; +typedef struct _EClientComboBoxClass EClientComboBoxClass; +typedef struct _EClientComboBoxPrivate EClientComboBoxPrivate; + +struct _EClientComboBox { + ESourceComboBox parent; + EClientComboBoxPrivate *priv; +}; + +struct _EClientComboBoxClass { + ESourceComboBoxClass parent_class; +}; + +GType e_client_combo_box_get_type (void) G_GNUC_CONST; +GtkWidget * e_client_combo_box_new (EClientCache *client_cache, + const gchar *extension_name); +EClientCache * e_client_combo_box_ref_client_cache + (EClientComboBox *combo_box); +void e_client_combo_box_set_client_cache + (EClientComboBox *combo_box, + EClientCache *client_cache); +EClient * e_client_combo_box_get_client_sync + (EClientComboBox *combo_box, + ESource *source, + GCancellable *cancellable, + GError **error); +void e_client_combo_box_get_client (EClientComboBox *combo_box, + ESource *source, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +EClient * e_client_combo_box_get_client_finish + (EClientComboBox *combo_box, + GAsyncResult *result, + GError **error); +EClient * e_client_combo_box_ref_cached_client + (EClientComboBox *combo_box, + ESource *source); + +G_END_DECLS + +#endif /* E_CLIENT_COMBO_BOX_H */ + diff --git a/e-util/e-util.h b/e-util/e-util.h index cbdc77c3b2..8c897f6952 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3