462 lines
13 KiB
C
462 lines
13 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|