/* * 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; }