Backport of upstream commits: commit 37768f933d00b64bfc5f902ccc2ecc85fee2b918 Adding new strings to copy/move event/task/memo and handle possible errors on those operations commit 96c6e7bc26132d31c87e05a6ef702b008a47ac85 Add EShellView to E{Calendar,MemoList,TaskList}Selector commit ed2bc85f4fe13a67aec032c8dddef0614df6419f Bug #657808 - Copy/move of a single instance should grab whole serie diff -up evolution-3.8.5/calendar/calendar.error.xml.copy-move-recurrences evolution-3.8.5/calendar/calendar.error.xml --- evolution-3.8.5/calendar/calendar.error.xml.copy-move-recurrences 2013-07-18 14:10:38.000000000 +0200 +++ evolution-3.8.5/calendar/calendar.error.xml 2013-11-04 22:11:17.120317884 +0100 @@ -307,4 +307,16 @@ {0} + + + <_primary>Failed to copy an event into the calendar '{0}' + {1} + + + + + <_primary>Failed to move an event into the calendar '{0}' + {1} + + diff -up evolution-3.8.5/calendar/gui/comp-util.c.copy-move-recurrences evolution-3.8.5/calendar/gui/comp-util.c --- evolution-3.8.5/calendar/gui/comp-util.c.copy-move-recurrences 2013-07-23 14:52:29.000000000 +0200 +++ evolution-3.8.5/calendar/gui/comp-util.c 2013-11-04 22:11:17.120317884 +0100 @@ -813,3 +813,366 @@ icalcomp_suggest_filename (icalcomponent 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 -up evolution-3.8.5/calendar/gui/comp-util.h.copy-move-recurrences evolution-3.8.5/calendar/gui/comp-util.h --- evolution-3.8.5/calendar/gui/comp-util.h.copy-move-recurrences 2013-07-23 14:52:35.000000000 +0200 +++ evolution-3.8.5/calendar/gui/comp-util.h 2013-11-04 22:11:17.121317884 +0100 @@ -75,4 +75,21 @@ void comp_util_sanitize_recurrence_maste 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 -up evolution-3.8.5/calendar/gui/e-calendar-selector.c.copy-move-recurrences evolution-3.8.5/calendar/gui/e-calendar-selector.c --- evolution-3.8.5/calendar/gui/e-calendar-selector.c.copy-move-recurrences 2013-07-23 14:52:35.000000000 +0200 +++ evolution-3.8.5/calendar/gui/e-calendar-selector.c 2013-11-04 22:11:17.122317884 +0100 @@ -20,7 +20,10 @@ #include +#include + #include "e-calendar-selector.h" +#include "comp-util.h" #include @@ -29,7 +32,9 @@ ((obj), E_TYPE_CALENDAR_SELECTOR, ECalendarSelectorPrivate)) struct _ECalendarSelectorPrivate { - gint dummy_value; + EShellView *shell_view; + + gpointer transfer_alert; /* weak pointer to EAlert */ }; G_DEFINE_TYPE ( @@ -37,113 +42,193 @@ G_DEFINE_TYPE ( e_calendar_selector, E_TYPE_CLIENT_SELECTOR) -static gboolean -calendar_selector_update_single_object (ECalClient *client, - icalcomponent *icalcomp) +enum { + PROP_0, + PROP_SHELL_VIEW, +}; + +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; + ECalendarSelectorPrivate *priv; + EShellContent *shell_content; + EAlert *alert; + + g_return_if_fail (calendar_selector != NULL); + g_return_if_fail (calendar_selector->priv != NULL); + + priv = calendar_selector->priv; + + if (priv->transfer_alert) { + e_alert_response ( + priv->transfer_alert, + e_alert_get_default_response (priv->transfer_alert)); + priv->transfer_alert = NULL; + } - uid = (gchar *) icalcomponent_get_uid (icalcomp); + if (!message) + return; - if (e_cal_client_get_object_sync (client, uid, NULL, &tmp_icalcomp, NULL, NULL)) { - icalcomponent_free (tmp_icalcomp); + alert = e_alert_new (domain, calendar, message, NULL); + g_return_if_fail (alert != NULL); - return e_cal_client_modify_object_sync ( - client, icalcomp, CALOBJ_MOD_ALL, NULL, 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 (shell_view); + e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), priv->transfer_alert); + g_object_unref (priv->transfer_alert); +} - uid = NULL; - if (!e_cal_client_create_object_sync (client, icalcomp, &uid, NULL, NULL)) - return FALSE; +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; - if (uid) - icalcomponent_set_uid (icalcomp, uid); - g_free (uid); +static void +transfer_item_to_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + TransferItemToData *titd = user_data; + GError *error = NULL; + GCancellable *cancellable; + gboolean success; - return TRUE; + 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); + } + + 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 gboolean -calendar_selector_update_objects (ECalClient *client, - icalcomponent *icalcomp) +static void +destination_client_connect_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - icalcomponent *subcomp; - icalcomponent_kind kind; + EClient *client; + TransferItemToData *titd = user_data; + GCancellable *cancellable; + GError *error = NULL; - 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; - } + client = e_client_selector_get_client_finish (E_CLIENT_SELECTOR (source_object), result, &error); - subcomp = icalcomponent_get_next_component ( - icalcomp, ICAL_ANY_COMPONENT); + /* 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; } - return TRUE; + 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 -client_connect_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) +source_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); + 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; - icalcomponent_free (icalcomp); +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 @@ -171,40 +256,148 @@ calendar_selector_data_dropped (ESourceS GdkDragAction action, guint info) { - GtkTreePath *path = NULL; - icalcomponent *icalcomp; + icalcomponent *icalcomp = NULL; + EActivity *activity; + EShellBackend *shell_backend; + EShellView *shell_view; + ESource *source = NULL; + 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); + + display_name = e_source_get_display_name (destination); - success = TRUE; + 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; +} + +EShellView * +e_calendar_selector_get_shell_view (ECalendarSelector *calendar_selector) +{ + g_return_val_if_fail (E_IS_CALENDAR_SELECTOR (calendar_selector), NULL); + + return calendar_selector->priv->shell_view; +} + +static void +e_calendar_selector_set_shell_view (ECalendarSelector *calendar_selector, + EShellView *shell_view) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + g_return_if_fail (calendar_selector->priv->shell_view == NULL); + + calendar_selector->priv->shell_view = g_object_ref (shell_view); +} + +static void +calendar_selector_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL_VIEW: + e_calendar_selector_set_shell_view ( + E_CALENDAR_SELECTOR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +calendar_selector_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL_VIEW: + g_value_set_object ( + value, + e_calendar_selector_get_shell_view (E_CALENDAR_SELECTOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +calendar_selector_dispose (GObject *object) +{ + ECalendarSelectorPrivate *priv; + + priv = E_CALENDAR_SELECTOR_GET_PRIVATE (object); + + g_clear_object (&priv->shell_view); + + /* Chain up to the parent' s dispose() method. */ + G_OBJECT_CLASS (e_calendar_selector_parent_class)->dispose (object); } static void @@ -217,9 +410,24 @@ e_calendar_selector_class_init (ECalenda object_class = G_OBJECT_CLASS (class); object_class->constructed = calendar_selector_constructed; + object_class->set_property = calendar_selector_set_property; + object_class->get_property = calendar_selector_get_property; + object_class->dispose = calendar_selector_dispose; source_selector_class = E_SOURCE_SELECTOR_CLASS (class); source_selector_class->data_dropped = calendar_selector_data_dropped; + + g_object_class_install_property ( + object_class, + PROP_SHELL_VIEW, + g_param_spec_object ( + "shell-view", + NULL, + NULL, + E_TYPE_SHELL_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); } static void @@ -235,12 +443,14 @@ e_calendar_selector_init (ECalendarSelec } GtkWidget * -e_calendar_selector_new (EClientCache *client_cache) +e_calendar_selector_new (EClientCache *client_cache, + EShellView *shell_view) { ESourceRegistry *registry; GtkWidget *widget; g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL); + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); registry = e_client_cache_ref_registry (client_cache); @@ -248,7 +458,9 @@ e_calendar_selector_new (EClientCache *c E_TYPE_CALENDAR_SELECTOR, "client-cache", client_cache, "extension-name", E_SOURCE_EXTENSION_CALENDAR, - "registry", registry, NULL); + "registry", registry, + "shell-view", shell_view, + NULL); g_object_unref (registry); diff -up evolution-3.8.5/calendar/gui/e-calendar-selector.h.copy-move-recurrences evolution-3.8.5/calendar/gui/e-calendar-selector.h --- evolution-3.8.5/calendar/gui/e-calendar-selector.h.copy-move-recurrences 2013-07-23 14:52:29.000000000 +0200 +++ evolution-3.8.5/calendar/gui/e-calendar-selector.h 2013-11-04 22:11:17.122317884 +0100 @@ -22,6 +22,7 @@ #define E_CALENDAR_SELECTOR_H #include +#include /* Standard GObject macros */ #define E_TYPE_CALENDAR_SELECTOR \ @@ -58,7 +59,10 @@ struct _ECalendarSelectorClass { }; GType e_calendar_selector_get_type (void); -GtkWidget * e_calendar_selector_new (EClientCache *client_cache); +GtkWidget * e_calendar_selector_new (EClientCache *client_cache, + EShellView *shell_backend); +EShellView * e_calendar_selector_get_shell_view + (ECalendarSelector *calendar_selector); G_END_DECLS diff -up evolution-3.8.5/calendar/gui/e-memo-list-selector.c.copy-move-recurrences evolution-3.8.5/calendar/gui/e-memo-list-selector.c --- evolution-3.8.5/calendar/gui/e-memo-list-selector.c.copy-move-recurrences 2013-07-23 14:52:30.000000000 +0200 +++ evolution-3.8.5/calendar/gui/e-memo-list-selector.c 2013-11-04 22:11:17.122317884 +0100 @@ -32,7 +32,7 @@ ((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorPrivate)) struct _EMemoListSelectorPrivate { - gint dummy_value; + EShellView *shell_view; }; G_DEFINE_TYPE ( @@ -40,6 +40,11 @@ G_DEFINE_TYPE ( e_memo_list_selector, E_TYPE_CLIENT_SELECTOR) +enum { + PROP_0, + PROP_SHELL_VIEW +}; + static gboolean memo_list_selector_update_single_object (ECalClient *client, icalcomponent *icalcomp) @@ -323,6 +328,71 @@ memo_list_selector_data_dropped (ESource return TRUE; } +EShellView * +e_memo_list_selector_get_shell_view (EMemoListSelector *memo_list_selector) +{ + g_return_val_if_fail (E_IS_MEMO_LIST_SELECTOR (memo_list_selector), NULL); + + return memo_list_selector->priv->shell_view; +} + +static void +e_memo_list_selector_set_shell_view (EMemoListSelector *memo_list_selector, + EShellView *shell_view) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + g_return_if_fail (memo_list_selector->priv->shell_view == NULL); + + memo_list_selector->priv->shell_view = g_object_ref (shell_view); +} + +static void +memo_list_selector_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL_VIEW: + e_memo_list_selector_set_shell_view ( + E_MEMO_LIST_SELECTOR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +memo_list_selector_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL_VIEW: + g_value_set_object ( + value, + e_memo_list_selector_get_shell_view (E_MEMO_LIST_SELECTOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +memo_list_selector_dispose (GObject *object) +{ + EMemoListSelectorPrivate *priv; + + priv = E_MEMO_LIST_SELECTOR_GET_PRIVATE (object); + + g_clear_object (&priv->shell_view); + + /* Chain up to the parent' s dispose() method. */ + G_OBJECT_CLASS (e_memo_list_selector_parent_class)->dispose (object); +} + static void e_memo_list_selector_class_init (EMemoListSelectorClass *class) { @@ -333,9 +403,24 @@ e_memo_list_selector_class_init (EMemoLi object_class = G_OBJECT_CLASS (class); object_class->constructed = memo_list_selector_constructed; + object_class->set_property = memo_list_selector_set_property; + object_class->get_property = memo_list_selector_get_property; + object_class->dispose = memo_list_selector_dispose; source_selector_class = E_SOURCE_SELECTOR_CLASS (class); source_selector_class->data_dropped = memo_list_selector_data_dropped; + + g_object_class_install_property ( + object_class, + PROP_SHELL_VIEW, + g_param_spec_object ( + "shell-view", + NULL, + NULL, + E_TYPE_SHELL_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); } static void @@ -351,12 +436,14 @@ e_memo_list_selector_init (EMemoListSele } GtkWidget * -e_memo_list_selector_new (EClientCache *client_cache) +e_memo_list_selector_new (EClientCache *client_cache, + EShellView *shell_view) { ESourceRegistry *registry; GtkWidget *widget; g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL); + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); registry = e_client_cache_ref_registry (client_cache); @@ -364,6 +451,7 @@ e_memo_list_selector_new (EClientCache * E_TYPE_MEMO_LIST_SELECTOR, "client-cache", client_cache, "extension-name", E_SOURCE_EXTENSION_MEMO_LIST, + "shell-view", shell_view, "registry", registry, NULL); g_object_unref (registry); diff -up evolution-3.8.5/calendar/gui/e-memo-list-selector.h.copy-move-recurrences evolution-3.8.5/calendar/gui/e-memo-list-selector.h --- evolution-3.8.5/calendar/gui/e-memo-list-selector.h.copy-move-recurrences 2013-07-23 14:52:30.000000000 +0200 +++ evolution-3.8.5/calendar/gui/e-memo-list-selector.h 2013-11-04 22:11:17.123317884 +0100 @@ -27,6 +27,7 @@ #define E_MEMO_LIST_SELECTOR_H #include +#include /* Standard GObject macros */ #define E_TYPE_MEMO_LIST_SELECTOR \ @@ -63,7 +64,10 @@ struct _EMemoListSelectorClass { }; GType e_memo_list_selector_get_type (void); -GtkWidget * e_memo_list_selector_new (EClientCache *client_cache); +GtkWidget * e_memo_list_selector_new (EClientCache *client_cache, + EShellView *shell_view); +EShellView * e_memo_list_selector_get_shell_view + (EMemoListSelector *memo_list_selector); G_END_DECLS diff -up evolution-3.8.5/calendar/gui/e-task-list-selector.c.copy-move-recurrences evolution-3.8.5/calendar/gui/e-task-list-selector.c --- evolution-3.8.5/calendar/gui/e-task-list-selector.c.copy-move-recurrences 2013-07-23 14:52:36.000000000 +0200 +++ evolution-3.8.5/calendar/gui/e-task-list-selector.c 2013-11-04 22:11:17.123317884 +0100 @@ -32,7 +32,7 @@ ((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorPrivate)) struct _ETaskListSelectorPrivate { - gint dummy_value; + EShellView *shell_view; }; G_DEFINE_TYPE ( @@ -40,6 +40,11 @@ G_DEFINE_TYPE ( e_task_list_selector, E_TYPE_CLIENT_SELECTOR) +enum { + PROP_0, + PROP_SHELL_VIEW +}; + static gboolean task_list_selector_update_single_object (ECalClient *client, icalcomponent *icalcomp) @@ -325,6 +330,71 @@ task_list_selector_data_dropped (ESource return TRUE; } +EShellView * +e_task_list_selector_get_shell_view (ETaskListSelector *task_list_selector) +{ + g_return_val_if_fail (E_IS_TASK_LIST_SELECTOR (task_list_selector), NULL); + + return task_list_selector->priv->shell_view; +} + +static void +e_task_list_selector_set_shell_view (ETaskListSelector *task_list_selector, + EShellView *shell_view) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + g_return_if_fail (task_list_selector->priv->shell_view == NULL); + + task_list_selector->priv->shell_view = g_object_ref (shell_view); +} + +static void +task_list_selector_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL_VIEW: + e_task_list_selector_set_shell_view ( + E_TASK_LIST_SELECTOR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +task_list_selector_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL_VIEW: + g_value_set_object ( + value, + e_task_list_selector_get_shell_view (E_TASK_LIST_SELECTOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +task_list_selector_dispose (GObject *object) +{ + ETaskListSelectorPrivate *priv; + + priv = E_TASK_LIST_SELECTOR_GET_PRIVATE (object); + + g_clear_object (&priv->shell_view); + + /* Chain up to the parent' s dispose() method. */ + G_OBJECT_CLASS (e_task_list_selector_parent_class)->dispose (object); +} + static void e_task_list_selector_class_init (ETaskListSelectorClass *class) { @@ -335,9 +405,24 @@ e_task_list_selector_class_init (ETaskLi object_class = G_OBJECT_CLASS (class); object_class->constructed = task_list_selector_constructed; + object_class->set_property = task_list_selector_set_property; + object_class->get_property = task_list_selector_get_property; + object_class->dispose = task_list_selector_dispose; source_selector_class = E_SOURCE_SELECTOR_CLASS (class); source_selector_class->data_dropped = task_list_selector_data_dropped; + + g_object_class_install_property ( + object_class, + PROP_SHELL_VIEW, + g_param_spec_object ( + "shell-view", + NULL, + NULL, + E_TYPE_SHELL_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); } static void @@ -353,12 +438,14 @@ e_task_list_selector_init (ETaskListSele } GtkWidget * -e_task_list_selector_new (EClientCache *client_cache) +e_task_list_selector_new (EClientCache *client_cache, + EShellView *shell_view) { ESourceRegistry *registry; GtkWidget *widget; g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL); + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); registry = e_client_cache_ref_registry (client_cache); @@ -366,6 +453,7 @@ e_task_list_selector_new (EClientCache * E_TYPE_TASK_LIST_SELECTOR, "client-cache", client_cache, "extension-name", E_SOURCE_EXTENSION_TASK_LIST, + "shell-view", shell_view, "registry", registry, NULL); g_object_unref (registry); diff -up evolution-3.8.5/calendar/gui/e-task-list-selector.h.copy-move-recurrences evolution-3.8.5/calendar/gui/e-task-list-selector.h --- evolution-3.8.5/calendar/gui/e-task-list-selector.h.copy-move-recurrences 2013-07-23 14:52:30.000000000 +0200 +++ evolution-3.8.5/calendar/gui/e-task-list-selector.h 2013-11-04 22:11:17.123317884 +0100 @@ -27,6 +27,7 @@ #define E_TASK_LIST_SELECTOR_H #include +#include /* Standard GObject macros */ #define E_TYPE_TASK_LIST_SELECTOR \ @@ -63,7 +64,10 @@ struct _ETaskListSelectorClass { }; GType e_task_list_selector_get_type (void); -GtkWidget * e_task_list_selector_new (EClientCache *client_cache); +GtkWidget * e_task_list_selector_new (EClientCache *client_cache, + EShellView *shell_view); +EShellView * e_task_list_selector_get_shell_view + (ETaskListSelector *task_list_selector); G_END_DECLS diff -up evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c --- evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c.copy-move-recurrences 2013-07-23 14:51:47.000000000 +0200 +++ evolution-3.8.5/modules/calendar/e-cal-shell-sidebar.c 2013-11-04 22:11:17.124317884 +0100 @@ -576,7 +576,7 @@ cal_shell_sidebar_constructed (GObject * container = widget; client_cache = e_shell_get_client_cache (shell); - widget = e_calendar_selector_new (client_cache); + widget = e_calendar_selector_new (client_cache, shell_view); e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE); gtk_container_add (GTK_CONTAINER (container), widget); a11y = gtk_widget_get_accessible (widget); diff -up evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c --- evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c.copy-move-recurrences 2013-07-23 14:51:48.000000000 +0200 +++ evolution-3.8.5/modules/calendar/e-cal-shell-view-private.c 2013-11-04 22:11:17.125317884 +0100 @@ -914,30 +914,78 @@ e_cal_shell_view_set_status_message (ECa 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; - - g_return_if_fail (ftd != NULL); - g_return_if_fail (ftd->source_client != NULL); - g_return_if_fail (ftd->dest_client != NULL); + TransferItemToData *titd = user_data; + GError *error = NULL; + GCancellable *cancellable; + gboolean success; - tzid = icalparameter_get_tzid (param); - if (!tzid || !*tzid) - return; + success = cal_comp_transfer_item_to_finish (E_CAL_CLIENT (src_object), result, &error); + + cancellable = e_activity_get_cancellable (titd->activity); + e_activity_set_state ( + titd->activity, + g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED); + + 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); + } - if (e_cal_client_get_timezone_sync (ftd->source_client, tzid, &tz, NULL, NULL) && tz) - e_cal_client_add_timezone_sync (ftd->dest_client, tz, NULL, NULL); + g_object_unref (titd->activity); + g_free (titd); } void @@ -946,129 +994,50 @@ e_cal_shell_view_transfer_item_to (ECalS 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); - - /* Put the new object into the destination calendar. */ + source = e_client_get_source (E_CLIENT (destination_client)); + display_name = e_source_get_display_name (source); - success = e_cal_client_get_object_sync ( - destination_client, uid, NULL, &icalcomp, NULL, NULL); - - if (success) { - icalcomponent_free (icalcomp); - success = e_cal_client_modify_object_sync ( - destination_client, icalcomp_event, - CALOBJ_MOD_ALL, NULL, NULL); - - /* 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); - } - - 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; - } - - icalcomponent_free (icalcomp_clone); - g_free (new_uid); - } - - 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); - } + 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); + + shell_backend = e_shell_view_get_shell_backend (E_SHELL_VIEW (cal_shell_view)); + + 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->cal_shell_view = cal_shell_view; + titd->activity = activity; + titd->display_name = display_name; + titd->remove = remove; + + cal_comp_transfer_item_to ( + event->comp_data->client, destination_client, + event->comp_data->icalcomp, !remove, cancellable, transfer_item_to_cb, titd); } void diff -up evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h.copy-move-recurrences evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h --- evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h.copy-move-recurrences 2013-07-23 14:51:48.000000000 +0200 +++ evolution-3.8.5/modules/calendar/e-cal-shell-view-private.h 2013-11-04 22:11:17.125317884 +0100 @@ -115,6 +115,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]; }; diff -up evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c --- evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c.copy-move-recurrences 2013-07-23 14:51:47.000000000 +0200 +++ evolution-3.8.5/modules/calendar/e-memo-shell-sidebar.c 2013-11-04 22:11:17.126317884 +0100 @@ -507,7 +507,7 @@ memo_shell_sidebar_constructed (GObject container = GTK_CONTAINER (widget); client_cache = e_shell_get_client_cache (shell); - widget = e_memo_list_selector_new (client_cache); + widget = e_memo_list_selector_new (client_cache, shell_view); e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE); gtk_container_add (container, widget); a11y = gtk_widget_get_accessible (widget); diff -up evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c.copy-move-recurrences evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c --- evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c.copy-move-recurrences 2013-07-23 14:51:47.000000000 +0200 +++ evolution-3.8.5/modules/calendar/e-task-shell-sidebar.c 2013-11-04 22:11:17.126317884 +0100 @@ -507,7 +507,7 @@ task_shell_sidebar_constructed (GObject container = GTK_CONTAINER (widget); client_cache = e_shell_get_client_cache (shell); - widget = e_task_list_selector_new (client_cache); + widget = e_task_list_selector_new (client_cache, shell_view); e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE); gtk_container_add (container, widget); a11y = gtk_widget_get_accessible (widget);