/* * Copyright (C) 2007 OpenedHand Ltd * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "koto-task.h" #include "koto-actions.h" /* Closures */ typedef struct { ECal *cal; char *uid; /* The UID to remove */ icalcomponent *comp; /* The task to add */ } AddRemoveData; typedef struct { ECal *cal; icalcomponent *before, *after; } ModifyData; /* Workers */ static void add_remove_task_undo (gpointer closure) { GError *error = NULL; AddRemoveData *data = closure; if (!data->cal) { g_warning ("ECal has been destroyed"); return; } /* TODO Set ->comp now? */ if (!e_cal_remove_object (data->cal, data->uid, &error)) { g_warning (G_STRLOC ": cannot remove task: %s", error->message); g_error_free (error); } g_free (data->uid); data->uid = NULL; } static void add_remove_task_redo (gpointer closure) { GError *error = NULL; AddRemoveData *data = closure; if (!data->cal) { g_warning ("ECal has been destroyed"); return; } g_free (data->uid); data->uid = NULL; if (!e_cal_create_object (data->cal, data->comp, &data->uid, &error)) { g_warning (G_STRLOC ": cannot create task: %s", error->message); g_error_free (error); } } static void add_remove_task_destroy (gpointer closure) { AddRemoveData *data = closure; g_object_unref (data->cal); g_free (data->uid); icalcomponent_free (data->comp); g_slice_free (AddRemoveData, data); } static void modify_task_undo (gpointer closure) { GError *error = NULL; ModifyData *data = closure; if (!data->cal) { g_warning ("ECal has been destroyed"); return; } if (!e_cal_modify_object (data->cal, data->before, CALOBJ_MOD_THIS, &error)) { g_warning (G_STRLOC ": cannot modify task: %s", error->message); g_error_free (error); } } static void modify_task_redo (gpointer closure) { GError *error = NULL; ModifyData *data = closure; if (!data->cal) { g_warning ("ECal has been destroyed"); return; } if (!e_cal_modify_object (data->cal, data->after, CALOBJ_MOD_THIS, &error)) { g_warning (G_STRLOC ": cannot modify task: %s", error->message); g_error_free (error); } } static void modify_task_destroy (gpointer closure) { ModifyData *data = closure; g_object_unref (data->cal); icalcomponent_free (data->before); icalcomponent_free (data->after); g_slice_free (ModifyData, data); } /* Public API */ gboolean koto_action_delete_task (ECal *cal, KotoTask *task, KotoUndoContext *undo) { GError *error = NULL; g_return_val_if_fail (E_IS_CAL (cal), FALSE); g_return_val_if_fail (task, FALSE); if (!e_cal_remove_object (cal, icalcomponent_get_uid (task->comp), &error)) { g_warning ("Cannot remove object: %s", error->message); g_error_free (error); return FALSE; } if (undo) { KotoUndoable *u; AddRemoveData *c; c = g_slice_new0 (AddRemoveData); c->cal = cal; g_object_add_weak_pointer (G_OBJECT (cal), (gpointer)&c->cal); c->uid = NULL; c->comp = icalcomponent_new_clone (task->comp); u = koto_undoable_new (add_remove_task_redo, add_remove_task_undo, add_remove_task_destroy, c); koto_undo_context_add (undo, u); } return TRUE; } gboolean koto_action_create_task (ECal *cal, icalcomponent *comp, char **uid, KotoUndoContext *undo) { GError *error = NULL; char *real_uid = NULL; g_return_val_if_fail (E_IS_CAL (cal), FALSE); g_return_val_if_fail (comp, FALSE); if (!e_cal_create_object (cal, comp, &real_uid, &error)) { g_warning (G_STRLOC ": cannot create task: %s", error->message); g_error_free (error); return FALSE; } if (uid) *uid = real_uid; if (undo) { AddRemoveData *c; KotoUndoable *u; c = g_slice_new0 (AddRemoveData); c->cal = cal; g_object_add_weak_pointer (G_OBJECT (cal), (gpointer)&c->cal); c->uid = g_strdup (real_uid); c->comp = icalcomponent_new_clone (comp); u = koto_undoable_new (add_remove_task_undo, add_remove_task_redo, add_remove_task_destroy, c); koto_undo_context_add (undo, u); } return TRUE; } /* Note that this function takes ownership of old */ gboolean koto_action_modify_task (ECal *cal, KotoTask *task, icalcomponent *old, KotoUndoContext *undo) { GError *error = NULL; gboolean ret; g_return_val_if_fail (E_IS_CAL (cal), FALSE); g_return_val_if_fail (task, FALSE); /* If we have an undo context, we need an old task */ g_return_val_if_fail (undo ? old != NULL : TRUE, FALSE); if (!e_cal_modify_object (cal, task->comp, CALOBJ_MOD_THIS, &error)) { g_warning (G_STRLOC ": cannot modify task: %s", error->message); g_error_free (error); ret = FALSE; goto done; } if (undo) { ModifyData *c; KotoUndoable *u; c = g_slice_new0 (ModifyData); c->cal = cal; g_object_add_weak_pointer (G_OBJECT (cal), (gpointer)&c->cal); c->before = old; old = NULL; /* Set old to NULL so that it isn't freed later */ c->after = icalcomponent_new_clone (task->comp); u = koto_undoable_new (modify_task_undo, modify_task_redo, modify_task_destroy, c); koto_undo_context_add (undo, u); } done: if (old) { icalcomponent_free (old); } return TRUE; }