diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-11-07 02:33:55 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-11-08 03:01:46 +0800 |
commit | aa66a17e401d73cbe394ed7f99bf73350e9b938b (patch) | |
tree | 305c80be39d688cf8386b5e123f3df631f2cfc84 | |
parent | b2dd9c153519d315f96bfd760e91a6f6b32affd6 (diff) | |
download | gsoc2013-evolution-aa66a17e401d73cbe394ed7f99bf73350e9b938b.tar.gz gsoc2013-evolution-aa66a17e401d73cbe394ed7f99bf73350e9b938b.tar.zst gsoc2013-evolution-aa66a17e401d73cbe394ed7f99bf73350e9b938b.zip |
Test drive EIOActivity with a simple asynchronous function.
Rename e-fsutils to e-file-utils. This is where we'll add asynchronous
functions for common file I/O operations with EActivity integration.
Start with e_file_replace_contents_async() (and corresponding finish()
function). This is a simple wrapper for g_file_replace_contents_async()
which also returns an EActivity. It replaces e_write_file_uri().
Also redesign EIOActivity to -contain- a GAsyncResult rather than
implement the interface for itself. This is easier for now but I may
change my mind again when I figure out how to tie centralized error
reporting into the EActivity framework.
-rw-r--r-- | e-util/Makefile.am | 4 | ||||
-rw-r--r-- | e-util/e-file-utils.c (renamed from e-util/e-fsutils.c) | 125 | ||||
-rw-r--r-- | e-util/e-file-utils.h (renamed from e-util/e-fsutils.h) | 26 | ||||
-rw-r--r-- | e-util/e-io-activity.c | 206 | ||||
-rw-r--r-- | e-util/e-io-activity.h | 12 | ||||
-rw-r--r-- | shell/e-shell-migrate.c | 2 |
6 files changed, 284 insertions, 91 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index bc5e7cd4fc..ecc3220f29 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -24,8 +24,8 @@ eutilinclude_HEADERS = \ e-dialog-widgets.h \ e-error.h \ e-event.h \ + e-file-utils.h \ e-folder-map.h \ - e-fsutils.h \ e-html-utils.h \ e-icon-factory.h \ e-import.h \ @@ -98,8 +98,8 @@ libeutil_la_SOURCES = \ e-dialog-widgets.c \ e-error.c \ e-event.c \ + e-file-utils.c \ e-folder-map.c \ - e-fsutils.c \ e-html-utils.c \ e-icon-factory.c \ e-import.c \ diff --git a/e-util/e-fsutils.c b/e-util/e-file-utils.c index c5426f8c81..f8adcc7a60 100644 --- a/e-util/e-fsutils.c +++ b/e-util/e-file-utils.c @@ -48,8 +48,131 @@ #include <glib.h> #include <glib/gstdio.h> +#include <glib/gi18n-lib.h> -#include "e-fsutils.h" +#include "e-file-utils.h" +#include "e-io-activity.h" + +static void +file_replace_contents_cb (GFile *file, + GAsyncResult *result, + EActivity *activity) +{ + gchar *new_etag; + gboolean success; + GError *error = NULL; + + success = g_file_replace_contents_finish ( + file, result, &new_etag, &error); + + result = e_io_activity_get_async_result (E_IO_ACTIVITY (activity)); + + g_object_set_data_full ( + G_OBJECT (result), + "__new_etag__", new_etag, + (GDestroyNotify) g_free); + + g_simple_async_result_set_op_res_gboolean ( + G_SIMPLE_ASYNC_RESULT (result), success); + + if (error != NULL) { + g_simple_async_result_set_from_error ( + G_SIMPLE_ASYNC_RESULT (result), error); + g_error_free (error); + } + + e_activity_complete (activity); + + g_object_unref (activity); +} + +EActivity * +e_file_replace_contents_async (GFile *file, + const gchar *contents, + gsize length, + const gchar *etag, + gboolean make_backup, + GFileCreateFlags flags, + GAsyncReadyCallback callback, + gpointer user_data) +{ + EActivity *activity; + GSimpleAsyncResult *simple; + GCancellable *cancellable; + const gchar *format; + gchar *description; + gchar *basename; + gchar *filename; + gchar *hostname; + gchar *uri; + + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (contents != NULL, NULL); + + uri = g_file_get_uri (file); + filename = g_filename_from_uri (uri, &hostname, NULL); + basename = g_filename_display_basename (filename); + + if (hostname != NULL) { + /* Translators: The string value is the basename of a file. */ + format = _("Writing \"%s\""); + description = g_strdup_printf (format, basename); + } else { + /* Translators: The first string value is the basename of a + * remote file, the second string value is the hostname. */ + format = _("Writing \"%s\" to %s"); + description = g_strdup_printf (format, basename, hostname); + } + + cancellable = g_cancellable_new (); + + simple = g_simple_async_result_new ( + G_OBJECT (file), callback, user_data, + e_file_replace_contents_async); + + activity = e_io_activity_new ( + description, G_ASYNC_RESULT (simple), cancellable); + + g_file_replace_contents_async ( + file, contents, length, etag, + make_backup, flags, cancellable, + (GAsyncReadyCallback) file_replace_contents_cb, + activity); + + g_object_unref (cancellable); + g_object_unref (simple); + + g_free (description); + g_free (basename); + g_free (filename); + g_free (hostname); + g_free (uri); + + return activity; +} + +gboolean +e_file_replace_contents_finish (GFile *file, + GAsyncResult *result, + gchar **new_etag, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + if (new_etag != NULL) + *new_etag = g_object_steal_data ( + G_OBJECT (result), "__new_etag__"); + + return TRUE; +} /** * e_fsutils_usage: diff --git a/e-util/e-fsutils.h b/e-util/e-file-utils.h index 6143e487ab..147b9b5b79 100644 --- a/e-util/e-fsutils.h +++ b/e-util/e-file-utils.h @@ -20,16 +20,30 @@ * */ -#ifndef E_FSUTILS_H -#define E_FSUTILS_H +#ifndef E_FILE_UTILS_H +#define E_FILE_UTILS_H -#include <glib.h> +#include <gio/gio.h> +#include <e-util/e-activity.h> G_BEGIN_DECLS -glong e_fsutils_usage(const gchar *path); -glong e_fsutils_avail(const gchar *path); +EActivity * e_file_replace_contents_async (GFile *file, + const gchar *contents, + gsize length, + const gchar *etag, + gboolean make_backup, + GFileCreateFlags flags, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_file_replace_contents_finish (GFile *file, + GAsyncResult *result, + gchar **new_etag, + GError **error); + +glong e_fsutils_usage (const gchar *path); +glong e_fsutils_avail (const gchar *path); G_END_DECLS -#endif /* !E_FOLDER_MAP_H */ +#endif /* E_FILE_UTILS_H */ diff --git a/e-util/e-io-activity.c b/e-util/e-io-activity.c index 086ee10529..9569e42914 100644 --- a/e-util/e-io-activity.c +++ b/e-util/e-io-activity.c @@ -26,26 +26,54 @@ ((obj), E_TYPE_IO_ACTIVITY, EIOActivityPrivate)) struct _EIOActivityPrivate { - GObject *source_object; + GAsyncResult *async_result; GCancellable *cancellable; - GAsyncReadyCallback callback; - gpointer user_data; }; enum { PROP_0, + PROP_ASYNC_RESULT, PROP_CANCELLABLE }; static gpointer parent_class; static void +io_activity_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ASYNC_RESULT: + e_io_activity_set_async_result ( + E_IO_ACTIVITY (object), + g_value_get_object (value)); + return; + + case PROP_CANCELLABLE: + e_io_activity_set_cancellable ( + E_IO_ACTIVITY (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void io_activity_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { + case PROP_ASYNC_RESULT: + g_value_set_object ( + value, e_io_activity_get_async_result ( + E_IO_ACTIVITY (object))); + return; + case PROP_CANCELLABLE: g_value_set_object ( value, e_io_activity_get_cancellable ( @@ -63,9 +91,9 @@ io_activity_dispose (GObject *object) priv = E_IO_ACTIVITY_GET_PRIVATE (object); - if (priv->source_object != NULL) { - g_object_unref (priv->source_object); - priv->source_object = NULL; + if (priv->async_result != NULL) { + g_object_unref (priv->async_result); + priv->async_result = NULL; } if (priv->cancellable != NULL) { @@ -80,55 +108,37 @@ io_activity_dispose (GObject *object) static void io_activity_cancelled (EActivity *activity) { - EIOActivityPrivate *priv; - - priv = E_IO_ACTIVITY_GET_PRIVATE (activity); + EIOActivity *io_activity; + GCancellable *cancellable; /* Chain up to parent's cancelled() method. */ E_ACTIVITY_CLASS (parent_class)->cancelled (activity); - g_cancellable_cancel (priv->cancellable); + io_activity = E_IO_ACTIVITY (activity); + cancellable = e_io_activity_get_cancellable (io_activity); + + if (cancellable != NULL) + g_cancellable_cancel (cancellable); } static void io_activity_completed (EActivity *activity) { - EIOActivityPrivate *priv; - - priv = E_IO_ACTIVITY_GET_PRIVATE (activity); + EIOActivity *io_activity; + GAsyncResult *async_result; /* Chain up to parent's completed() method. */ E_ACTIVITY_CLASS (parent_class)->completed (activity); - /* Clear the function pointer after invoking it - * to guarantee it will not be invoked again. */ - if (priv->callback != NULL) { - priv->callback ( - priv->source_object, - G_ASYNC_RESULT (activity), - priv->user_data); - priv->callback = NULL; - } -} - -static gpointer -io_activity_get_user_data (GAsyncResult *async_result) -{ - EIOActivityPrivate *priv; + io_activity = E_IO_ACTIVITY (activity); + async_result = e_io_activity_get_async_result (io_activity); - priv = E_IO_ACTIVITY_GET_PRIVATE (async_result); - - return priv->user_data; -} - -static GObject * -io_activity_get_source_object (GAsyncResult *async_result) -{ - EIOActivityPrivate *priv; - - priv = E_IO_ACTIVITY_GET_PRIVATE (async_result); - - return priv->source_object; + /* We know how to invoke a GSimpleAsyncResult. For any other + * type of GAsyncResult the caller will have to take measures + * to invoke it himself. */ + if (G_IS_SIMPLE_ASYNC_RESULT (async_result)) + g_simple_async_result_complete ( + G_SIMPLE_ASYNC_RESULT (async_result)); } static void @@ -141,6 +151,7 @@ io_activity_class_init (EIOActivityClass *class) g_type_class_add_private (class, sizeof (EIOActivityPrivate)); object_class = G_OBJECT_CLASS (class); + object_class->set_property = io_activity_set_property; object_class->get_property = io_activity_get_property; object_class->dispose = io_activity_dispose; @@ -150,28 +161,31 @@ io_activity_class_init (EIOActivityClass *class) g_object_class_install_property ( object_class, + PROP_ASYNC_RESULT, + g_param_spec_object ( + "async-result", + "Asynchronous Result", + NULL, + G_TYPE_ASYNC_RESULT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, PROP_CANCELLABLE, g_param_spec_object ( "cancellable", "Cancellable", NULL, G_TYPE_CANCELLABLE, - G_PARAM_READABLE)); -} - -static void -io_activity_iface_init (GAsyncResultIface *iface) -{ - iface->get_user_data = io_activity_get_user_data; - iface->get_source_object = io_activity_get_source_object; + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); } static void io_activity_init (EIOActivity *io_activity) { io_activity->priv = E_IO_ACTIVITY_GET_PRIVATE (io_activity); - - io_activity->priv->cancellable = g_cancellable_new (); } GType @@ -193,45 +207,57 @@ e_io_activity_get_type (void) NULL /* value_table */ }; - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) io_activity_iface_init, - (GInterfaceFinalizeFunc) NULL, - NULL /* interface_data */ - }; - type = g_type_register_static ( E_TYPE_ACTIVITY, "EIOActivity", &type_info, 0); - - g_type_add_interface_static ( - type, G_TYPE_ASYNC_RESULT, &iface_info); } return type; } EActivity * -e_io_activity_new (GObject *source_object, - const gchar *primary_text, - GAsyncReadyCallback callback, - gpointer user_data) +e_io_activity_new (const gchar *primary_text, + GAsyncResult *async_result, + GCancellable *cancellable) { - EActivity *activity; - EIOActivityPrivate *priv; - - g_return_val_if_fail (G_IS_OBJECT (source_object), NULL); g_return_val_if_fail (primary_text != NULL, NULL); - g_return_val_if_fail (callback != NULL, NULL); - activity = g_object_new ( - E_TYPE_IO_ACTIVITY, "primary-text", primary_text, NULL); + if (async_result != NULL) + g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL); - /* XXX Should these be construct properties? */ - priv = E_IO_ACTIVITY_GET_PRIVATE (activity); - priv->source_object = g_object_ref (source_object); - priv->callback = callback; - priv->user_data = user_data; + if (cancellable != NULL) + g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), NULL); - return activity; + return g_object_new ( + E_TYPE_IO_ACTIVITY, + "async-result", async_result, "cancellable", + cancellable, "primary-text", primary_text, NULL); +} + +GAsyncResult * +e_io_activity_get_async_result (EIOActivity *io_activity) +{ + g_return_val_if_fail (E_IS_IO_ACTIVITY (io_activity), NULL); + + return io_activity->priv->async_result; +} + +void +e_io_activity_set_async_result (EIOActivity *io_activity, + GAsyncResult *async_result) +{ + g_return_if_fail (E_IS_IO_ACTIVITY (io_activity)); + + if (async_result != NULL) { + g_return_if_fail (G_IS_ASYNC_RESULT (async_result)); + g_object_ref (async_result); + } + + if (io_activity->priv->async_result != NULL) + g_object_unref (io_activity->priv->async_result); + + io_activity->priv->async_result = async_result; + + g_object_notify (G_OBJECT (io_activity), "async-result"); } GCancellable * @@ -241,3 +267,29 @@ e_io_activity_get_cancellable (EIOActivity *io_activity) return io_activity->priv->cancellable; } + +void +e_io_activity_set_cancellable (EIOActivity *io_activity, + GCancellable *cancellable) +{ + g_return_if_fail (E_IS_IO_ACTIVITY (io_activity)); + + if (cancellable != NULL) { + g_return_if_fail (G_IS_CANCELLABLE (cancellable)); + g_object_ref (cancellable); + } + + if (io_activity->priv->cancellable != NULL) + g_object_unref (io_activity->priv->cancellable); + + io_activity->priv->cancellable = cancellable; + + g_object_freeze_notify (G_OBJECT (io_activity)); + + e_activity_set_allow_cancel ( + E_ACTIVITY (io_activity), (cancellable != NULL)); + + g_object_notify (G_OBJECT (io_activity), "cancellable"); + + g_object_thaw_notify (G_OBJECT (io_activity)); +} diff --git a/e-util/e-io-activity.h b/e-util/e-io-activity.h index c94953af3e..773417472d 100644 --- a/e-util/e-io-activity.h +++ b/e-util/e-io-activity.h @@ -60,11 +60,15 @@ struct _EIOActivityClass { }; GType e_io_activity_get_type (void); -EActivity * e_io_activity_new (GObject *source_object, - const gchar *primary_text, - GAsyncReadyCallback callback, - gpointer user_data); +EActivity * e_io_activity_new (const gchar *primary_text, + GAsyncResult *async_result, + GCancellable *cancellable); +GAsyncResult * e_io_activity_get_async_result (EIOActivity *io_activity); +void e_io_activity_set_async_result (EIOActivity *io_activity, + GAsyncResult *async_result); GCancellable * e_io_activity_get_cancellable (EIOActivity *io_activity); +void e_io_activity_set_cancellable (EIOActivity *io_activity, + GCancellable *cancellable); G_END_DECLS diff --git a/shell/e-shell-migrate.c b/shell/e-shell-migrate.c index a330d9d1a5..d7c8312a86 100644 --- a/shell/e-shell-migrate.c +++ b/shell/e-shell-migrate.c @@ -29,7 +29,7 @@ #include "e-util/e-bconf-map.h" #include "e-util/e-error.h" -#include "e-util/e-fsutils.h" +#include "e-util/e-file-utils.h" #include "e-util/e-util.h" #include "es-event.h" |