[evolution] Bug #657808 - Copy/move of a single instance should grab whole serie
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Bug #657808 - Copy/move of a single instance should grab whole serie
- Date: Mon, 4 Nov 2013 20:04:35 +0000 (UTC)
commit ed2bc85f4fe13a67aec032c8dddef0614df6419f
Author: Milan Crha <mcrha redhat com>
Date: Mon Nov 4 21:04:07 2013 +0100
Bug #657808 - Copy/move of a single instance should grab whole serie
calendar/gui/comp-util.c | 363 +++++++++++++++++++++++++++
calendar/gui/comp-util.h | 17 ++
calendar/gui/e-calendar-selector.c | 320 ++++++++++++++++--------
modules/calendar/e-cal-shell-view-private.c | 222 +++++++----------
modules/calendar/e-cal-shell-view-private.h | 3 +
5 files changed, 696 insertions(+), 229 deletions(-)
---
diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c
index be67211..a5c231e 100644
--- a/calendar/gui/comp-util.c
+++ b/calendar/gui/comp-util.c
@@ -822,3 +822,366 @@ icalcomp_suggest_filename (icalcomponent *icalcomp,
return g_strconcat (summary, ".ics", NULL);
}
+
+typedef struct _AsyncContext {
+ ECalClient *src_client;
+ icalcomponent *icalcomp_clone;
+ gboolean do_copy;
+} AsyncContext;
+
+struct ForeachTzidData
+{
+ ECalClient *source_client;
+ ECalClient *destination_client;
+ GCancellable *cancellable;
+ GError **error;
+ gboolean success;
+};
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ if (async_context->src_client)
+ g_object_unref (async_context->src_client);
+
+ if (async_context->icalcomp_clone)
+ icalcomponent_free (async_context->icalcomp_clone);
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static void
+add_timezone_to_cal_cb (icalparameter *param,
+ gpointer data)
+{
+ struct ForeachTzidData *ftd = data;
+ icaltimezone *tz = NULL;
+ const gchar *tzid;
+
+ g_return_if_fail (ftd != NULL);
+ g_return_if_fail (ftd->source_client != NULL);
+ g_return_if_fail (ftd->destination_client != NULL);
+
+ if (!ftd->success)
+ return;
+
+ if (ftd->cancellable && g_cancellable_is_cancelled (ftd->cancellable)) {
+ ftd->success = FALSE;
+ return;
+ }
+
+ tzid = icalparameter_get_tzid (param);
+ if (!tzid || !*tzid)
+ return;
+
+ if (e_cal_client_get_timezone_sync (ftd->source_client, tzid, &tz, ftd->cancellable, NULL) && tz)
+ ftd->success = e_cal_client_add_timezone_sync (
+ ftd->destination_client, tz, ftd->cancellable, ftd->error);
+}
+
+/* Helper for cal_comp_transfer_item_to() */
+static void
+cal_comp_transfer_item_to_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ AsyncContext *async_context;
+ GError *local_error = NULL;
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ cal_comp_transfer_item_to_sync (
+ async_context->src_client,
+ E_CAL_CLIENT (source_object),
+ async_context->icalcomp_clone,
+ async_context->do_copy,
+ cancellable, &local_error);
+
+ if (local_error != NULL)
+ g_simple_async_result_take_error (simple, local_error);
+}
+
+void
+cal_comp_transfer_item_to (ECalClient *src_client,
+ ECalClient *dest_client,
+ icalcomponent *icalcomp_vcal,
+ gboolean do_copy,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (E_IS_CAL_CLIENT (src_client), FALSE);
+ g_return_val_if_fail (E_IS_CAL_CLIENT (dest_client), FALSE);
+ g_return_val_if_fail (icalcomp_vcal != NULL, FALSE);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->src_client = g_object_ref (src_client);
+ async_context->icalcomp_clone = icalcomponent_new_clone (icalcomp_vcal);
+ async_context->do_copy = do_copy;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (dest_client), callback, user_data,
+ cal_comp_transfer_item_to);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ g_simple_async_result_run_in_thread (
+ simple, cal_comp_transfer_item_to_thread,
+ G_PRIORITY_DEFAULT, cancellable);
+
+ g_object_unref (simple);
+}
+
+gboolean
+cal_comp_transfer_item_to_finish (ECalClient *client,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (result, G_OBJECT (client), cal_comp_transfer_item_to),
+ FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+cal_comp_transfer_item_to_sync (ECalClient *src_client,
+ ECalClient *dest_client,
+ icalcomponent *icalcomp_vcal,
+ gboolean do_copy,
+ GCancellable *cancellable,
+ GError **error)
+{
+ icalcomponent *icalcomp;
+ icalcomponent *icalcomp_event, *subcomp;
+ icalcomponent_kind icalcomp_kind;
+ const gchar *uid;
+ gchar *new_uid = NULL;
+ struct ForeachTzidData ftd;
+ ECalClientSourceType source_type;
+ GHashTable *processed_uids;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CAL_CLIENT (src_client), FALSE);
+ g_return_val_if_fail (E_IS_CAL_CLIENT (dest_client), FALSE);
+ g_return_val_if_fail (icalcomp_vcal != NULL, FALSE);
+
+ icalcomp_event = icalcomponent_get_inner (icalcomp_vcal);
+ g_return_val_if_fail (icalcomp_event != NULL, FALSE);
+
+ source_type = e_cal_client_get_source_type (src_client);
+ switch (source_type) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ icalcomp_kind = ICAL_VEVENT_COMPONENT;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ icalcomp_kind = ICAL_VTODO_COMPONENT;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+ icalcomp_kind = ICAL_VJOURNAL_COMPONENT;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ processed_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ icalcomp_event = icalcomponent_get_first_component (icalcomp_vcal, icalcomp_kind);
+ /*
+ * This check should be removed in the near future.
+ * We should be able to work properly with multiselection, which means that we always
+ * will receive a component with subcomponents.
+ */
+ if (icalcomp_event == NULL)
+ icalcomp_event = icalcomp_vcal;
+ for (;
+ icalcomp_event;
+ icalcomp_event = icalcomponent_get_next_component (icalcomp_vcal, icalcomp_kind)) {
+ GError *local_error = NULL;
+
+ uid = icalcomponent_get_uid (icalcomp_event);
+
+ if (g_hash_table_lookup (processed_uids, uid))
+ continue;
+
+ success = e_cal_client_get_object_sync (dest_client, uid, NULL, &icalcomp, cancellable,
&local_error);
+ if (success) {
+ success = e_cal_client_modify_object_sync (
+ dest_client, icalcomp_event, CALOBJ_MOD_ALL, cancellable, error);
+
+ icalcomponent_free (icalcomp);
+ if (!success)
+ goto exit;
+
+ if (!do_copy) {
+ ECalObjModType mod_type = CALOBJ_MOD_THIS;
+
+ /* Remove the item from the source calendar. */
+ if (e_cal_util_component_is_instance (icalcomp_event) ||
+ e_cal_util_component_has_recurrences (icalcomp_event))
+ mod_type = CALOBJ_MOD_ALL;
+
+ success = e_cal_client_remove_object_sync (
+ src_client, uid, NULL, mod_type, cancellable, error);
+ if (!success)
+ goto exit;
+ }
+
+ continue;
+ } else if (local_error != NULL && !g_error_matches (
+ local_error, E_CAL_CLIENT_ERROR,
E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
+ g_propagate_error (error, local_error);
+ goto exit;
+ } else {
+ g_clear_error (&local_error);
+ }
+
+ if (e_cal_util_component_is_instance (icalcomp_event)) {
+ GSList *ecalcomps = NULL, *eiter;
+ ECalComponent *comp ;
+
+ success = e_cal_client_get_objects_for_uid_sync (src_client, uid, &ecalcomps,
cancellable, error);
+ if (!success)
+ goto exit;
+
+ if (ecalcomps && !ecalcomps->next) {
+ /* only one component, no need for a vCalendar list */
+ comp = ecalcomps->data;
+ icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+ } else {
+ icalcomp = icalcomponent_new (ICAL_VCALENDAR_COMPONENT);
+ for (eiter = ecalcomps; eiter; eiter = g_slist_next (eiter)) {
+ comp = eiter->data;
+
+ icalcomponent_add_component (icalcomp,
+ icalcomponent_new_clone (e_cal_component_get_icalcomponent
(comp)));
+ }
+ }
+
+ e_cal_client_free_ecalcomp_slist (ecalcomps);
+ } else {
+ icalcomp = icalcomponent_new_clone (icalcomp_event);
+ }
+
+ if (do_copy) {
+ /* Change the UID to avoid problems with duplicated UID */
+ new_uid = e_cal_component_gen_uid ();
+ if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+ /* in case of a vCalendar, the component might have detached instances,
+ thus change the UID on all of the subcomponents of it */
+ for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+ subcomp;
+ subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+ icalcomponent_set_uid (subcomp, new_uid);
+ }
+ } else {
+ icalcomponent_set_uid (icalcomp, new_uid);
+ }
+ g_free (new_uid);
+ new_uid = NULL;
+ }
+
+ ftd.source_client = src_client;
+ ftd.destination_client = dest_client;
+ ftd.cancellable = cancellable;
+ ftd.error = error;
+ ftd.success = TRUE;
+
+ if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+ /* in case of a vCalendar, the component might have detached instances,
+ thus check timezones on all of the subcomponents of it */
+ for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+ subcomp && ftd.success;
+ subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+ icalcomponent_foreach_tzid (subcomp, add_timezone_to_cal_cb, &ftd);
+ }
+ } else {
+ icalcomponent_foreach_tzid (icalcomp, add_timezone_to_cal_cb, &ftd);
+ }
+
+ if (!ftd.success) {
+ success = FALSE;
+ goto exit;
+ }
+
+ if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+ gboolean did_add = FALSE;
+
+ /* in case of a vCalendar, the component might have detached instances,
+ thus add the master object first, and then all of the subcomponents of it */
+ for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+ subcomp && !did_add;
+ subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+ if (icaltime_is_null_time (icalcomponent_get_recurrenceid (subcomp))) {
+ did_add = TRUE;
+ success = e_cal_client_create_object_sync (dest_client, subcomp,
+ &new_uid, cancellable, error);
+ g_free (new_uid);
+ }
+ }
+
+ if (!success) {
+ icalcomponent_free (icalcomp);
+ goto exit;
+ }
+
+ /* deal with detached instances */
+ for (subcomp = icalcomponent_get_first_component (icalcomp, icalcomp_kind);
+ subcomp && success;
+ subcomp = icalcomponent_get_next_component (icalcomp, icalcomp_kind)) {
+ if (!icaltime_is_null_time (icalcomponent_get_recurrenceid (subcomp))) {
+ if (did_add) {
+ success = e_cal_client_modify_object_sync (dest_client,
subcomp,
+ CALOBJ_MOD_THIS, cancellable, error);
+ } else {
+ /* just in case there are only detached instances and no
master object */
+ did_add = TRUE;
+ success = e_cal_client_create_object_sync (dest_client,
subcomp,
+ &new_uid, cancellable, error);
+ g_free (new_uid);
+ }
+ }
+ }
+ } else {
+ success = e_cal_client_create_object_sync (dest_client, icalcomp, &new_uid,
cancellable, error);
+ g_free (new_uid);
+ }
+
+ icalcomponent_free (icalcomp);
+ if (!success)
+ goto exit;
+
+ if (!do_copy) {
+ ECalObjModType mod_type = CALOBJ_MOD_THIS;
+
+ /* Remove the item from the source calendar. */
+ if (e_cal_util_component_is_instance (icalcomp_event) ||
+ e_cal_util_component_has_recurrences (icalcomp_event))
+ mod_type = CALOBJ_MOD_ALL;
+
+ success = e_cal_client_remove_object_sync (src_client, uid, NULL, mod_type,
cancellable, error);
+ if (!success)
+ goto exit;
+ }
+
+ g_hash_table_insert (processed_uids, g_strdup (uid), GINT_TO_POINTER (1));
+ }
+
+ exit:
+ g_hash_table_destroy (processed_uids);
+
+ return success;
+}
diff --git a/calendar/gui/comp-util.h b/calendar/gui/comp-util.h
index dcf5844..56ddd54 100644
--- a/calendar/gui/comp-util.h
+++ b/calendar/gui/comp-util.h
@@ -75,4 +75,21 @@ void comp_util_sanitize_recurrence_master (ECalComponent *comp, ECalClient *clie
gchar *icalcomp_suggest_filename (icalcomponent *icalcomp, const gchar *default_name);
+void cal_comp_transfer_item_to (ECalClient *src_client,
+ ECalClient *dest_client,
+ icalcomponent *icalcomp_vcal,
+ gboolean do_copy,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean cal_comp_transfer_item_to_finish (ECalClient *client,
+ GAsyncResult *result,
+ GError **error);
+gboolean cal_comp_transfer_item_to_sync (ECalClient *src_client,
+ ECalClient *dest_client,
+ icalcomponent *icalcomp_event,
+ gboolean do_copy,
+ GCancellable *cancellable,
+ GError **error);
+
#endif
diff --git a/calendar/gui/e-calendar-selector.c b/calendar/gui/e-calendar-selector.c
index 9557c44..b588c6a 100644
--- a/calendar/gui/e-calendar-selector.c
+++ b/calendar/gui/e-calendar-selector.c
@@ -20,7 +20,10 @@
#include <config.h>
+#include <glib/gi18n.h>
+
#include "e-calendar-selector.h"
+#include "comp-util.h"
#include <libecal/libecal.h>
@@ -30,6 +33,8 @@
struct _ECalendarSelectorPrivate {
EShellView *shell_view;
+
+ gpointer transfer_alert; /* weak pointer to EAlert */
};
G_DEFINE_TYPE (
@@ -42,118 +47,188 @@ enum {
PROP_SHELL_VIEW,
};
-static gboolean
-calendar_selector_update_single_object (ECalClient *client,
- icalcomponent *icalcomp)
+static void
+cal_transferring_update_alert (ECalendarSelector *calendar_selector,
+ EShellView *shell_view,
+ const gchar *domain,
+ const gchar *calendar,
+ const gchar *message)
{
- gchar *uid;
- icalcomponent *tmp_icalcomp = NULL;
- gboolean success;
-
- uid = (gchar *) icalcomponent_get_uid (icalcomp);
+ ECalendarSelectorPrivate *priv;
+ EShellContent *shell_content;
+ EAlert *alert;
- e_cal_client_get_object_sync (
- client, uid, NULL, &tmp_icalcomp, NULL, NULL);
+ g_return_if_fail (calendar_selector != NULL);
+ g_return_if_fail (calendar_selector->priv != NULL);
- if (tmp_icalcomp != NULL) {
- icalcomponent_free (tmp_icalcomp);
+ priv = calendar_selector->priv;
- return e_cal_client_modify_object_sync (
- client, icalcomp, CALOBJ_MOD_ALL, NULL, NULL);
+ if (priv->transfer_alert) {
+ e_alert_response (
+ priv->transfer_alert,
+ e_alert_get_default_response (priv->transfer_alert));
+ priv->transfer_alert = NULL;
}
- uid = NULL;
- success = e_cal_client_create_object_sync (
- client, icalcomp, &uid, NULL, NULL);
+ if (!message)
+ return;
- if (uid != NULL) {
- icalcomponent_set_uid (icalcomp, uid);
- g_free (uid);
- }
+ alert = e_alert_new (domain, calendar, message, NULL);
+ g_return_if_fail (alert != NULL);
- return success;
+ priv->transfer_alert = alert;
+ g_object_add_weak_pointer (G_OBJECT (alert), &priv->transfer_alert);
+ e_alert_start_timer (priv->transfer_alert, 300);
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), priv->transfer_alert);
+ g_object_unref (priv->transfer_alert);
}
-static gboolean
-calendar_selector_update_objects (ECalClient *client,
- icalcomponent *icalcomp)
+typedef struct _TransferItemToData {
+ ESource *destination;
+ ESourceSelector *selector;
+ EClient *src_client;
+ EShellView *shell_view;
+ EActivity *activity;
+ icalcomponent *icalcomp;
+ const gchar *display_name;
+ gboolean do_copy;
+} TransferItemToData;
+
+static void
+transfer_item_to_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- icalcomponent *subcomp;
- icalcomponent_kind kind;
-
- kind = icalcomponent_isa (icalcomp);
- if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT)
- return calendar_selector_update_single_object (
- client, icalcomp);
- else if (kind != ICAL_VCALENDAR_COMPONENT)
- return FALSE;
-
- subcomp = icalcomponent_get_first_component (
- icalcomp, ICAL_ANY_COMPONENT);
- while (subcomp != NULL) {
- gboolean success;
-
- kind = icalcomponent_isa (subcomp);
- if (kind == ICAL_VTIMEZONE_COMPONENT) {
- icaltimezone *zone;
- GError *error = NULL;
-
- zone = icaltimezone_new ();
- icaltimezone_set_component (zone, subcomp);
-
- e_cal_client_add_timezone_sync (client, zone, NULL, &error);
- icaltimezone_free (zone, 1);
-
- if (error != NULL) {
- g_warning (
- "%s: Failed to add timezone: %s",
- G_STRFUNC, error->message);
- g_error_free (error);
- return FALSE;
- }
- } else if (kind == ICAL_VTODO_COMPONENT ||
- kind == ICAL_VEVENT_COMPONENT) {
- success = calendar_selector_update_single_object (
- client, subcomp);
- if (!success)
- return FALSE;
- }
-
- subcomp = icalcomponent_get_next_component (
- icalcomp, ICAL_ANY_COMPONENT);
+ TransferItemToData *titd = user_data;
+ GError *error = NULL;
+ GCancellable *cancellable;
+ gboolean success;
+
+ success = cal_comp_transfer_item_to_finish (E_CAL_CLIENT (source_object), result, &error);
+
+ if (!success) {
+ cal_transferring_update_alert (
+ E_CALENDAR_SELECTOR (titd->selector),
+ titd->shell_view,
+ titd->do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event",
+ titd->display_name,
+ error->message);
+ g_clear_error (&error);
}
- return TRUE;
+ cancellable = e_activity_get_cancellable (titd->activity);
+ e_activity_set_state (
+ titd->activity,
+ g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
+ g_object_unref (titd->activity);
+ icalcomponent_free (titd->icalcomp);
+ g_free (titd);
}
static void
-client_connect_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+destination_client_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
EClient *client;
- icalcomponent *icalcomp = user_data;
+ TransferItemToData *titd = user_data;
+ GCancellable *cancellable;
GError *error = NULL;
- g_return_if_fail (icalcomp != NULL);
+ client = e_client_selector_get_client_finish (E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ cancellable = e_activity_get_cancellable (titd->activity);
+
+ if (error != NULL) {
+ cal_transferring_update_alert (
+ E_CALENDAR_SELECTOR (titd->selector),
+ titd->shell_view,
+ titd->do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event",
+ titd->display_name,
+ error->message);
+ g_clear_error (&error);
+
+ goto exit;
+ }
+
+ if (g_cancellable_is_cancelled (cancellable))
+ goto exit;
+
+ cal_comp_transfer_item_to (
+ E_CAL_CLIENT (titd->src_client), E_CAL_CLIENT (client),
+ titd->icalcomp, titd->do_copy, cancellable, transfer_item_to_cb, titd);
+
+ return;
+
+exit:
+ e_activity_set_state (
+ titd->activity,
+ g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
+ g_object_unref (titd->activity);
+ icalcomponent_free (titd->icalcomp);
+ g_free (titd);
+
+}
+
+static void
+source_client_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ TransferItemToData *titd = user_data;
+ GCancellable *cancellable;
+ GError *error = NULL;
- client = e_client_selector_get_client_finish (
- E_CLIENT_SELECTOR (source_object), result, &error);
+ client = e_client_selector_get_client_finish (E_CLIENT_SELECTOR (source_object), result, &error);
/* Sanity check. */
g_return_if_fail (
((client != NULL) && (error == NULL)) ||
((client == NULL) && (error != NULL)));
+ cancellable = e_activity_get_cancellable (titd->activity);
+
if (error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_error_free (error);
+ cal_transferring_update_alert (
+ E_CALENDAR_SELECTOR (titd->selector),
+ titd->shell_view,
+ titd->do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event",
+ titd->display_name,
+ error->message);
+ g_clear_error (&error);
+
+ goto exit;
}
- calendar_selector_update_objects (E_CAL_CLIENT (client), icalcomp);
- g_object_unref (client);
+ if (g_cancellable_is_cancelled (cancellable))
+ goto exit;
+
+ titd->src_client = client;
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (titd->selector), titd->destination, cancellable,
+ destination_client_connect_cb, titd);
+
+ return;
+
+exit:
+ e_activity_set_state (
+ titd->activity,
+ g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
- icalcomponent_free (icalcomp);
+ g_object_unref (titd->activity);
+ icalcomponent_free (titd->icalcomp);
+ g_free (titd);
}
static void
@@ -239,40 +314,83 @@ calendar_selector_data_dropped (ESourceSelector *selector,
GdkDragAction action,
guint info)
{
- GtkTreePath *path = NULL;
icalcomponent *icalcomp;
+ EActivity *activity;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ ESource *source;
+ ESourceRegistry *registry;
+ GCancellable *cancellable;
+ gchar **segments;
+ gchar *source_uid = NULL;
+ gchar *message;
+ const gchar *display_name;
const guchar *data;
- gboolean success = FALSE;
- gpointer object = NULL;
+ gboolean do_copy;
+ TransferItemToData *titd;
data = gtk_selection_data_get_data (selection_data);
- icalcomp = icalparser_parse_string ((const gchar *) data);
+ g_return_val_if_fail (data != NULL, FALSE);
- if (icalcomp == NULL)
+ segments = g_strsplit ((const gchar *) data, "\n", 2);
+ if (g_strv_length (segments) != 2)
goto exit;
- /* FIXME Deal with GDK_ACTION_ASK. */
- if (action == GDK_ACTION_COPY) {
- gchar *uid;
+ source_uid = g_strdup (segments[0]);
+ icalcomp = icalparser_parse_string (segments[1]);
- uid = e_cal_component_gen_uid ();
- icalcomponent_set_uid (icalcomp, uid);
- }
+ if (!icalcomp)
+ goto exit;
- e_client_selector_get_client (
- E_CLIENT_SELECTOR (selector), destination, NULL,
- client_connect_cb, icalcomp);
+ registry = e_source_selector_get_registry (selector);
+ source = e_source_registry_ref_source (registry, source_uid);
+ if (!source)
+ goto exit;
+
+ shell_view = e_calendar_selector_get_shell_view (E_CALENDAR_SELECTOR (selector));
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
- success = TRUE;
+ display_name = e_source_get_display_name (destination);
+
+ do_copy = action == GDK_ACTION_COPY ? TRUE : FALSE;
+
+ message = do_copy ?
+ g_strdup_printf (_("Copying an event into the calendar %s"), display_name) :
+ g_strdup_printf (_("Moving an event into the calendar %s"), display_name);
+
+ cancellable = g_cancellable_new ();
+ activity = e_activity_new ();
+ e_activity_set_cancellable (activity, cancellable);
+ e_activity_set_state (activity, E_ACTIVITY_RUNNING);
+ e_activity_set_text (activity, message);
+ g_free (message);
+
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ titd = g_new0 (TransferItemToData, 1);
+
+ titd->destination = destination;
+ titd->icalcomp = icalcomponent_new_clone (icalcomp);
+ titd->selector = selector;
+ titd->shell_view = shell_view;
+ titd->activity = activity;
+ titd->display_name = display_name;
+ titd->do_copy = do_copy;
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source, cancellable,
+ source_client_connect_cb, titd);
exit:
- if (path != NULL)
- gtk_tree_path_free (path);
+ if (source)
+ g_object_unref (source);
- if (object != NULL)
- g_object_unref (object);
+ if (icalcomp)
+ icalcomponent_free (icalcomp);
- return success;
+ g_free (source_uid);
+ g_strfreev (segments);
+ return TRUE;
}
static void
diff --git a/modules/calendar/e-cal-shell-view-private.c b/modules/calendar/e-cal-shell-view-private.c
index 46f89e8..98c6da4 100644
--- a/modules/calendar/e-cal-shell-view-private.c
+++ b/modules/calendar/e-cal-shell-view-private.c
@@ -993,33 +993,78 @@ e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
cal_shell_view->priv->calendar_activity = activity;
}
-struct ForeachTzidData
+static void
+cal_transferring_update_alert (ECalShellView *cal_shell_view,
+ const gchar *domain,
+ const gchar *calendar,
+ const gchar *message)
{
- ECalClient *source_client;
- ECalClient *dest_client;
-};
+ ECalShellViewPrivate *priv;
+ EShellContent *shell_content;
+ EAlert *alert;
+
+ g_return_if_fail (cal_shell_view != NULL);
+ g_return_if_fail (cal_shell_view->priv != NULL);
+
+ priv = cal_shell_view->priv;
+
+ if (priv->transfer_alert) {
+ e_alert_response (
+ priv->transfer_alert,
+ e_alert_get_default_response (priv->transfer_alert));
+ priv->transfer_alert = NULL;
+ }
+
+ if (!message)
+ return;
+
+ alert = e_alert_new (domain, calendar, message, NULL);
+ g_return_if_fail (alert != NULL);
+
+ priv->transfer_alert = alert;
+ g_object_add_weak_pointer (G_OBJECT (alert), &priv->transfer_alert);
+ e_alert_start_timer (priv->transfer_alert, 300);
+
+ shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (cal_shell_view));
+ e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), priv->transfer_alert);
+ g_object_unref (priv->transfer_alert);
+}
+
+typedef struct _TransferItemToData {
+ ECalShellView *cal_shell_view;
+ EActivity *activity;
+ const gchar *display_name;
+ gboolean remove;
+} TransferItemToData;
static void
-add_timezone_to_cal_cb (icalparameter *param,
- gpointer data)
+transfer_item_to_cb (GObject *src_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- struct ForeachTzidData *ftd = data;
- icaltimezone *tz = NULL;
- const gchar *tzid;
+ TransferItemToData *titd = user_data;
+ GError *error = NULL;
+ GCancellable *cancellable;
+ gboolean success;
- g_return_if_fail (ftd != NULL);
- g_return_if_fail (ftd->source_client != NULL);
- g_return_if_fail (ftd->dest_client != NULL);
+ success = cal_comp_transfer_item_to_finish (E_CAL_CLIENT (src_object), result, &error);
- tzid = icalparameter_get_tzid (param);
- if (!tzid || !*tzid)
- return;
+ cancellable = e_activity_get_cancellable (titd->activity);
+ e_activity_set_state (
+ titd->activity,
+ g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
- e_cal_client_get_timezone_sync (
- ftd->source_client, tzid, &tz, NULL, NULL);
- if (tz != NULL)
- e_cal_client_add_timezone_sync (
- ftd->dest_client, tz, NULL, NULL);
+ if (!success) {
+ cal_transferring_update_alert (
+ titd->cal_shell_view,
+ titd->remove ? "calendar:failed-move-event" : "calendar:failed-copy-event",
+ titd->display_name,
+ error->message);
+ g_clear_error (&error);
+ }
+
+ g_object_unref (titd->activity);
+ g_free (titd);
}
void
@@ -1028,129 +1073,50 @@ e_cal_shell_view_transfer_item_to (ECalShellView *cal_shell_view,
ECalClient *destination_client,
gboolean remove)
{
- icalcomponent *icalcomp;
- icalcomponent *icalcomp_clone;
- icalcomponent *icalcomp_event;
- gboolean success;
- const gchar *uid;
-
- /* XXX This function should be split up into
- * smaller, more understandable pieces. */
+ EActivity *activity;
+ EShellBackend *shell_backend;
+ ESource *source;
+ GCancellable *cancellable = NULL;
+ gchar *message;
+ const gchar *display_name;
+ TransferItemToData *titd;
g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
g_return_if_fail (event != NULL);
+ g_return_if_fail (is_comp_data_valid (event) != FALSE);
g_return_if_fail (E_IS_CAL_CLIENT (destination_client));
if (!is_comp_data_valid (event))
return;
- icalcomp_event = event->comp_data->icalcomp;
- uid = icalcomponent_get_uid (icalcomp_event);
+ source = e_client_get_source (E_CLIENT (destination_client));
+ display_name = e_source_get_display_name (source);
- /* Put the new object into the destination calendar. */
+ message = remove ?
+ g_strdup_printf (_("Moving an event into the calendar %s"), display_name) :
+ g_strdup_printf (_("Copying an event into the calendar %s"), display_name);
- success = e_cal_client_get_object_sync (
- destination_client, uid, NULL, &icalcomp, NULL, NULL);
+ shell_backend = e_shell_view_get_shell_backend (E_SHELL_VIEW (cal_shell_view));
- if (success) {
- icalcomponent_free (icalcomp);
- success = e_cal_client_modify_object_sync (
- destination_client, icalcomp_event,
- CALOBJ_MOD_ALL, NULL, NULL);
+ cancellable = g_cancellable_new ();
+ activity = e_activity_new ();
+ e_activity_set_cancellable (activity, cancellable);
+ e_activity_set_state (activity, E_ACTIVITY_RUNNING);
+ e_activity_set_text (activity, message);
+ g_free (message);
- /* do not delete the event when it was found in the calendar */
- return;
- } else {
- icalproperty *icalprop;
- gchar *new_uid;
- GError *error = NULL;
- struct ForeachTzidData ftd;
-
- ftd.source_client = event->comp_data->client;
- ftd.dest_client = destination_client;
-
- if (e_cal_util_component_is_instance (icalcomp_event)) {
- success = e_cal_client_get_object_sync (
- event->comp_data->client,
- uid, NULL, &icalcomp, NULL, NULL);
- if (success) {
- /* Use master object when working
- * with a recurring event ... */
- icalcomp_clone = icalcomponent_new_clone (icalcomp);
- icalcomponent_free (icalcomp);
- } else {
- /* ... or remove the recurrence ID ... */
- icalcomp_clone =
- icalcomponent_new_clone (icalcomp_event);
- if (e_cal_util_component_has_recurrences (icalcomp_clone)) {
- /* ... for non-detached instances,
- * to make it a master object. */
- icalprop = icalcomponent_get_first_property (
- icalcomp_clone, ICAL_RECURRENCEID_PROPERTY);
- if (icalprop != NULL)
- icalcomponent_remove_property (
- icalcomp_clone, icalprop);
- }
- }
- } else
- icalcomp_clone =
- icalcomponent_new_clone (icalcomp_event);
-
- icalprop = icalproperty_new_x ("1");
- icalproperty_set_x_name (icalprop, "X-EVOLUTION-MOVE-CALENDAR");
- icalcomponent_add_property (icalcomp_clone, icalprop);
-
- if (!remove) {
- /* Change the UID to avoid problems with
- * duplicated UIDs. */
- new_uid = e_cal_component_gen_uid ();
- icalcomponent_set_uid (icalcomp_clone, new_uid);
- g_free (new_uid);
- }
+ e_shell_backend_add_activity (shell_backend, activity);
- new_uid = NULL;
- icalcomponent_foreach_tzid (
- icalcomp_clone, add_timezone_to_cal_cb, &ftd);
- success = e_cal_client_create_object_sync (
- destination_client, icalcomp_clone,
- &new_uid, NULL, &error);
- if (!success) {
- icalcomponent_free (icalcomp_clone);
- g_warning (
- "%s: Failed to create object: %s",
- G_STRFUNC, error->message);
- g_error_free (error);
- return;
- }
+ titd = g_new0 (TransferItemToData, 1);
- icalcomponent_free (icalcomp_clone);
- g_free (new_uid);
- }
+ titd->cal_shell_view = cal_shell_view;
+ titd->activity = activity;
+ titd->display_name = display_name;
+ titd->remove = remove;
- if (remove) {
- ECalClient *source_client = event->comp_data->client;
-
- /* Remove the item from the source calendar. */
- if (e_cal_util_component_is_instance (icalcomp_event) ||
- e_cal_util_component_has_recurrences (icalcomp_event)) {
- icaltimetype icaltime;
- gchar *rid;
-
- icaltime =
- icalcomponent_get_recurrenceid (icalcomp_event);
- if (!icaltime_is_null_time (icaltime))
- rid = icaltime_as_ical_string_r (icaltime);
- else
- rid = NULL;
- e_cal_client_remove_object_sync (
- source_client, uid, rid,
- CALOBJ_MOD_ALL, NULL, NULL);
- g_free (rid);
- } else
- e_cal_client_remove_object_sync (
- source_client, uid, NULL,
- CALOBJ_MOD_THIS, NULL, NULL);
- }
+ cal_comp_transfer_item_to (
+ event->comp_data->client, destination_client,
+ event->comp_data->icalcomp, !remove, cancellable, transfer_item_to_cb, titd);
}
void
diff --git a/modules/calendar/e-cal-shell-view-private.h b/modules/calendar/e-cal-shell-view-private.h
index 000602b..40b2ec6 100644
--- a/modules/calendar/e-cal-shell-view-private.h
+++ b/modules/calendar/e-cal-shell-view-private.h
@@ -150,6 +150,9 @@ struct _ECalShellViewPrivate {
gint search_direction; /* negative value is backward, positive is forward, zero is error; in days */
GSList *search_hit_cache; /* pointers on time_t for matched events */
+ /* Event/Task/Memo transferring */
+ gpointer transfer_alert; /* weak pointer to EAlert * */
+
GFileMonitor *monitors[CHECK_NB];
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]