diff options
author | Amos Brocco <amos.brocco@gmail.com> | 2012-01-16 22:20:36 -0500 |
---|---|---|
committer | Cosimo Cecchi <cosimoc@gnome.org> | 2012-01-20 22:14:01 -0500 |
commit | dcf5d6796b5adc13a4b03d36f30d9f15025e9df9 (patch) | |
tree | 99c74ec8093435c5eb31b920df6abf9044f50f74 /libnautilus-private/nautilus-file-undo-operations.c | |
parent | 88f18618ba15b952a739e410b910508f244b1fc3 (diff) | |
download | nautilus-dcf5d6796b5adc13a4b03d36f30d9f15025e9df9.tar.gz |
undo: introduce undo support
Diffstat (limited to 'libnautilus-private/nautilus-file-undo-operations.c')
-rw-r--r-- | libnautilus-private/nautilus-file-undo-operations.c | 1297 |
1 files changed, 1297 insertions, 0 deletions
diff --git a/libnautilus-private/nautilus-file-undo-operations.c b/libnautilus-private/nautilus-file-undo-operations.c new file mode 100644 index 000000000..f2d61c900 --- /dev/null +++ b/libnautilus-private/nautilus-file-undo-operations.c @@ -0,0 +1,1297 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-file-undo-operations.c - Manages undo/redo of file operations + * + * Copyright (C) 2007-2011 Amos Brocco + * Copyright (C) 2010 Red Hat, Inc. + * + * This library 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 library 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 library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Amos Brocco <amos.brocco@gmail.com> + * Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include <config.h> + +#include "nautilus-file-undo-operations.h" + +#include <glib/gi18n.h> + +#include "nautilus-file-operations.h" +#include "nautilus-file.h" +#include "nautilus-file-undo-manager.h" +#include "nautilus-file-undo-types.h" + +void +nautilus_file_undo_data_free (NautilusFileUndoData *action) +{ + g_return_if_fail (action != NULL); + + g_free (action->undo_label); + g_free (action->undo_description); + g_free (action->redo_label); + g_free (action->redo_description); + + action->finalize_func (action); +} + +static char * +get_first_target_short_name (NautilusFileUndoDataExt *eaction) +{ + GList *targets_first; + char *file_name = NULL; + + targets_first = g_list_first (eaction->destinations); + + if (targets_first != NULL && + targets_first->data != NULL) { + file_name = g_file_get_basename (targets_first->data); + } + + return file_name; +} + +static GList * +uri_list_to_gfile_list (GList * urilist) +{ + const GList *l; + GList *file_list = NULL; + GFile *file; + + for (l = urilist; l != NULL; l = l->next) { + file = g_file_new_for_uri (l->data); + file_list = g_list_append (file_list, file); + } + + return file_list; +} + +/* TODO: Synch-I/O, error handling */ +static GHashTable * +retrieve_files_to_restore (GHashTable * trashed) +{ + GFileEnumerator *enumerator; + GHashTable *to_restore; + GFile *trash; + + to_restore = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, g_free); + + trash = g_file_new_for_uri ("trash:///"); + + enumerator = g_file_enumerate_children (trash, + G_FILE_ATTRIBUTE_STANDARD_NAME"," + G_FILE_ATTRIBUTE_TIME_MODIFIED"," + G_FILE_ATTRIBUTE_TRASH_ORIG_PATH, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, NULL); + + if (enumerator) { + GFileInfo *info; + guint64 *mtime; + gpointer lookupvalue; + GFile *item; + guint64 mtime_item; + char *origpath; + GFile *origfile; + char *origuri; + + mtime = 0; + while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) { + /* Retrieve the original file uri */ + origpath = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH); + origfile = g_file_new_for_path (origpath); + origuri = g_file_get_uri (origfile); + g_object_unref (origfile); + g_free (origpath); + + lookupvalue = g_hash_table_lookup (trashed, origuri); + + if (lookupvalue) { + mtime = (guint64 *)lookupvalue; + mtime_item = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); + if (*mtime == mtime_item) { + /* File in the trash */ + item = g_file_get_child (trash, g_file_info_get_name (info)); + g_hash_table_insert (to_restore, item, origuri); + } + } else { + g_free (origuri); + } + + } + g_file_enumerator_close (enumerator, FALSE, NULL); + g_object_unref (enumerator); + } + g_object_unref (trash); + + return to_restore; +} + +static void +undo_redo_done_transfer_callback (GHashTable * debuting_uris, + gpointer data) +{ + NautilusFileUndoData *action = data; + NautilusFileUndoManager *manager = action->manager; + + /* If the action needed to be freed but was locked, free now */ + if (action->freed) { + nautilus_file_undo_data_free (action); + } else { + action->locked = FALSE; + } + + /* Update menus */ + g_signal_emit_by_name (manager, "undo-changed", 0); +} + +static void +undo_redo_done_rename_callback (NautilusFile * file, + GFile * result_location, + GError * error, + gpointer callback_data) +{ + undo_redo_done_transfer_callback (NULL, callback_data); +} + +static void +undo_redo_done_create_callback (GFile * new_file, + gpointer callback_data) +{ + undo_redo_done_transfer_callback (NULL, callback_data); +} + +static void +undo_redo_done_delete_callback (GHashTable *debuting_uris, + gboolean user_cancel, + gpointer callback_data) +{ + undo_redo_done_transfer_callback (debuting_uris, callback_data); +} + +static void +undo_redo_op_callback (gpointer callback_data) +{ + undo_redo_done_transfer_callback (NULL, callback_data); +} + +/* undo helpers */ + +static void +delete_files (NautilusFileUndoManager *self, + GList *files, + NautilusFileUndoData *action) +{ + nautilus_file_operations_delete (files, NULL, + undo_redo_done_delete_callback, action); +} + +static void +create_undo_func (NautilusFileUndoData *action) +{ + GList *files = NULL; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + files = g_list_append (files, g_object_ref (eaction->target_file)); + delete_files (action->manager, files, action); + + g_list_free_full (files, g_object_unref); +} + +static void +copy_or_link_undo_func (NautilusFileUndoData *action) +{ + GList *files; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + files = g_list_copy (eaction->destinations); + files = g_list_reverse (files); /* Deleting must be done in reverse */ + + delete_files (action->manager, files, action); + + g_list_free (files); +} + +static void +restore_undo_func (NautilusFileUndoData *action) +{ + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + nautilus_file_operations_trash_or_delete (eaction->destinations, NULL, + undo_redo_done_delete_callback, action); +} + +static void +trash_undo_func (NautilusFileUndoData *action) +{ + NautilusFileUndoManagerPrivate *priv = action->manager->priv; + GHashTable *files_to_restore; + NautilusFileUndoDataTrash* eaction = (NautilusFileUndoDataTrash*) action; + + /* Internally managed op, clear the undo_redo_flag. + * Same as calling nautilus_file_undo_manager_is_undo_redo() + * minus the function call and unused return val. + */ + + priv->undo_redo_flag = FALSE; + files_to_restore = retrieve_files_to_restore (eaction->trashed); + + if (g_hash_table_size (files_to_restore) > 0) { + GList *gfiles_in_trash, *l; + GFile *item; + GFile *dest; + char *value; + + gfiles_in_trash = g_hash_table_get_keys (files_to_restore); + + for (l = gfiles_in_trash; l != NULL; l = l->next) { + item = l->data; + value = g_hash_table_lookup (files_to_restore, item); + dest = g_file_new_for_uri (value); + g_file_move (item, dest, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, NULL, NULL, NULL); + g_object_unref (dest); + } + + g_list_free (gfiles_in_trash); + } + + g_hash_table_destroy (files_to_restore); + + /* Here we must do what's necessary for the callback */ + undo_redo_done_transfer_callback (NULL, action); +} + +static void +move_undo_func (NautilusFileUndoData *action) +{ + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + nautilus_file_operations_move (eaction->destinations, NULL, + eaction->src_dir, NULL, + undo_redo_done_transfer_callback, action); +} + +static void +rename_undo_func (NautilusFileUndoData *action) +{ + gchar *new_name; + NautilusFile *file; + NautilusFileUndoDataRename* eaction = (NautilusFileUndoDataRename*) action; + + new_name = g_file_get_basename (eaction->old_file); + file = nautilus_file_get (eaction->new_file); + + nautilus_file_rename (file, new_name, + undo_redo_done_rename_callback, action); + + nautilus_file_unref (file); + g_free (new_name); +} + +static void +set_permissions_undo_func (NautilusFileUndoData *action) +{ + NautilusFile *file; + NautilusFileUndoDataPermissions* eaction = (NautilusFileUndoDataPermissions*) action; + + file = nautilus_file_get (eaction->target_file); + + nautilus_file_set_permissions (file, + eaction->current_permissions, + undo_redo_done_rename_callback, action); + + nautilus_file_unref (file); +} + +static void +recursive_permissions_undo_func (NautilusFileUndoData *action) +{ + NautilusFileUndoManagerPrivate *priv = action->manager->priv; + NautilusFileUndoDataRecursivePermissions* eaction = (NautilusFileUndoDataRecursivePermissions*) action; + + /* Internally managed op, clear the undo_redo_flag. */ + priv->undo_redo_flag = FALSE; + + if (g_hash_table_size (eaction->original_permissions) > 0) { + GList *gfiles_list; + guint32 *perm; + GList *l; + GFile *dest; + char *item; + + gfiles_list = g_hash_table_get_keys (eaction->original_permissions); + for (l = gfiles_list; l != NULL; l = l->next) { + item = l->data; + perm = g_hash_table_lookup (eaction->original_permissions, item); + dest = g_file_new_for_uri (item); + g_file_set_attribute_uint32 (dest, + G_FILE_ATTRIBUTE_UNIX_MODE, + *perm, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); + g_object_unref (dest); + } + + g_list_free (gfiles_list); + /* Here we must do what's necessary for the callback */ + undo_redo_done_transfer_callback (NULL, action); + } +} + +static void +change_group_undo_func (NautilusFileUndoData *action) +{ + NautilusFile *file; + NautilusFileUndoDataOwnership* eaction = (NautilusFileUndoDataOwnership*) action; + + file = nautilus_file_get (eaction->target_file); + + nautilus_file_set_group (file, + eaction->original_ownership, + undo_redo_done_rename_callback, action); + + nautilus_file_unref (file); +} + +static void +change_owner_undo_func (NautilusFileUndoData *action) +{ + NautilusFile *file; + NautilusFileUndoDataOwnership* eaction = (NautilusFileUndoDataOwnership*) action; + + file = nautilus_file_get (eaction->target_file); + + nautilus_file_set_owner (file, + eaction->original_ownership, + undo_redo_done_rename_callback, action); + + nautilus_file_unref (file); +} + +/* redo helpers */ + +static void +copy_redo_func (NautilusFileUndoData *action) +{ + GList *locations; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + locations = eaction->sources; + nautilus_file_operations_copy (locations, NULL, + eaction->dest_dir, NULL, + undo_redo_done_transfer_callback, action); +} + +static void +create_from_template_redo_func (NautilusFileUndoData *action) +{ + GFile *parent; + gchar *parent_uri, *new_name; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + parent = g_file_get_parent (eaction->target_file); + parent_uri = g_file_get_uri (parent); + new_name = g_file_get_parse_name (eaction->target_file); + nautilus_file_operations_new_file_from_template (NULL, NULL, + parent_uri, new_name, + eaction->template, + undo_redo_done_create_callback, action); + + g_free (parent_uri); + g_free (new_name); + g_object_unref (parent); +} + +static void +duplicate_redo_func (NautilusFileUndoData *action) +{ + GList *locations; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + locations = eaction->sources; + nautilus_file_operations_duplicate (locations, NULL, NULL, + undo_redo_done_transfer_callback, action); +} + +static void +move_restore_redo_func (NautilusFileUndoData *action) +{ + GList *locations; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + locations = eaction->sources; + nautilus_file_operations_move (locations, NULL, + eaction->dest_dir, NULL, + undo_redo_done_transfer_callback, action); +} + +static void +rename_redo_func (NautilusFileUndoData *action) +{ + gchar *new_name; + NautilusFile *file; + NautilusFileUndoDataRename* eaction = (NautilusFileUndoDataRename*) action; + + new_name = g_file_get_basename (eaction->new_file); + file = nautilus_file_get (eaction->old_file); + nautilus_file_rename (file, new_name, + undo_redo_done_rename_callback, action); + + nautilus_file_unref (file); + g_free (new_name); +} + +static void +create_empty_redo_func (NautilusFileUndoData *action) +{ + GFile *parent; + gchar *parent_uri; + gchar *new_name; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + parent = g_file_get_parent (eaction->target_file); + parent_uri = g_file_get_uri (parent); + new_name = g_file_get_parse_name (eaction->target_file); + nautilus_file_operations_new_file (NULL, NULL, parent_uri, + new_name, + eaction->template, + action->count, undo_redo_done_create_callback, action); + + g_free (parent_uri); + g_free (new_name); + g_object_unref (parent); +} + +static void +create_folder_redo_func (NautilusFileUndoData *action) +{ + GFile *parent; + gchar *parent_uri; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + parent = g_file_get_parent (eaction->target_file); + parent_uri = g_file_get_uri (parent); + nautilus_file_operations_new_folder (NULL, NULL, parent_uri, + undo_redo_done_create_callback, action); + + g_free (parent_uri); + g_object_unref (parent); +} + +static void +trash_redo_func (NautilusFileUndoData *action) +{ + NautilusFileUndoDataTrash* eaction = (NautilusFileUndoDataTrash*) action; + + if (g_hash_table_size (eaction->trashed) > 0) { + GList *uri_to_trash, *locations; + + uri_to_trash = g_hash_table_get_keys (eaction->trashed); + locations = uri_list_to_gfile_list (uri_to_trash); + nautilus_file_operations_trash_or_delete (locations, NULL, + undo_redo_done_delete_callback, action); + g_list_free (uri_to_trash); + g_list_free_full (locations, g_object_unref); + } +} + +static void +create_link_redo_func (NautilusFileUndoData *action) +{ + GList *locations; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + locations = eaction->sources; + nautilus_file_operations_link (locations, NULL, + eaction->dest_dir, NULL, + undo_redo_done_transfer_callback, action); +} + +static void +set_permissions_redo_func (NautilusFileUndoData *action) +{ + NautilusFile *file; + NautilusFileUndoDataPermissions* eaction = (NautilusFileUndoDataPermissions*) action; + + file = nautilus_file_get (eaction->target_file); + nautilus_file_set_permissions (file, eaction->new_permissions, + undo_redo_done_rename_callback, action); + + nautilus_file_unref (file); +} + +static void +recursive_permissions_redo_func (NautilusFileUndoData *action) +{ + gchar *parent_uri; + NautilusFileUndoDataRecursivePermissions* eaction = (NautilusFileUndoDataRecursivePermissions*) action; + + parent_uri = g_file_get_uri (eaction->dest_dir); + nautilus_file_set_permissions_recursive (parent_uri, + eaction->file_permissions, + eaction->file_mask, + eaction->dir_permissions, + eaction->dir_mask, + undo_redo_op_callback, + action); + g_free (parent_uri); +} + +static void +change_group_redo_func (NautilusFileUndoData *action) +{ + NautilusFile *file; + NautilusFileUndoDataOwnership* eaction = (NautilusFileUndoDataOwnership*) action; + + file = nautilus_file_get (eaction->target_file); + + nautilus_file_set_group (file, + eaction->new_ownership, + undo_redo_done_rename_callback, + action); + + nautilus_file_unref (file); +} + +static void +change_owner_redo_func (NautilusFileUndoData *action) +{ + NautilusFile *file; + NautilusFileUndoDataOwnership* eaction = (NautilusFileUndoDataOwnership*) action; + + file = nautilus_file_get (eaction->target_file); + nautilus_file_set_owner (file, + eaction->new_ownership, + undo_redo_done_rename_callback, + action); + + nautilus_file_unref (file); +} + +/* description helpers */ + +static void +copy_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *destination; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + destination = g_file_get_path (eaction->dest_dir); + + if (count != 1) { + descriptions[0] = g_strdup_printf (_("Delete %d copied items"), count); + descriptions[1] = g_strdup_printf (_("Copy %d items to '%s'"), count, destination); + + labels[0] = g_strdup_printf (_("_Undo Copy %d items"), count); + labels[1] = g_strdup_printf (_("_Redo Copy %d items"), count); + } else { + gchar *name; + + name = get_first_target_short_name (eaction); + descriptions[0] = g_strdup_printf (_("Delete '%s'"), name); + descriptions[1] = g_strdup_printf (_("Copy '%s' to '%s'"), name, destination); + + labels[0] = g_strdup (_("_Undo Copy")); + labels[1] = g_strdup (_("_Redo Copy")); + + g_free (name); + } +} + +static void +duplicate_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *destination; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + destination = g_file_get_path (eaction->dest_dir); + + if (count != 1) { + descriptions[0] = g_strdup_printf (_("Delete %d duplicated items"), count); + descriptions[1] = g_strdup_printf (_("Duplicate of %d items in '%s'"), + count, destination); + + labels[0] = g_strdup_printf (_("_Undo Duplicate %d items"), count); + labels[1] = g_strdup_printf (_("_Redo Duplicate %d items"), count); + } else { + char *name; + + name = get_first_target_short_name (eaction); + descriptions[0] = g_strdup_printf (_("Delete '%s'"), name); + descriptions[1] = g_strdup_printf (_("Duplicate '%s' in '%s'"), + name, destination); + + labels[0] = g_strdup (_("_Undo Duplicate")); + labels[1] = g_strdup (_("_Redo Duplicate")); + + g_free (name); + } + +} + +static void +move_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *source, *destination; + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + source = g_file_get_path (eaction->src_dir); + destination = g_file_get_path (eaction->dest_dir); + + if (count != 1) { + descriptions[0] = g_strdup_printf (_("Move %d items back to '%s'"), count, source); + descriptions[1] = g_strdup_printf (_("Move %d items to '%s'"), count, destination); + + labels[0] = g_strdup_printf (_("_Undo Move %d items"), count); + labels[1] = g_strdup_printf (_("_Redo Move %d items"), count); + } else { + char *name; + + name = get_first_target_short_name (eaction); + descriptions[0] = g_strdup_printf (_("Move '%s' back to '%s'"), name, source); + descriptions[1] = g_strdup_printf (_("Move '%s' to '%s'"), name, destination); + + labels[0] = g_strdup (_("_Undo Move")); + labels[1] = g_strdup (_("_Redo Move")); + + g_free (name); + } +} + +static void +rename_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *new_name, *old_name; + NautilusFileUndoDataRename* eaction = (NautilusFileUndoDataRename*) action; + + new_name = g_file_get_parse_name (eaction->new_file); + old_name = g_file_get_parse_name (eaction->old_file); + + descriptions[0] = g_strdup_printf (_("Rename '%s' as '%s'"), new_name, old_name); + descriptions[1] = g_strdup_printf (_("Rename '%s' as '%s'"), old_name, new_name); + + labels[0] = g_strdup (_("_Undo Rename")); + labels[1] = g_strdup (_("_Redo Rename")); + + g_free (old_name); + g_free (new_name); +} + +static void +create_undo_common (NautilusFileUndoDataCreate *eaction, + guint count, + gchar **descriptions) +{ + char *name; + + name = g_file_get_parse_name (eaction->target_file); + descriptions[0] = g_strdup_printf (_("Delete '%s'"), name); + + g_free (name); +} + +static void +create_empty_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *name; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + create_undo_common (eaction, count, descriptions); + + name = g_file_get_parse_name (eaction->target_file); + descriptions[1] = g_strdup_printf (_("Create an empty file '%s'"), name); + + labels[0] = g_strdup (_("_Undo Create Empty File")); + labels[1] = g_strdup (_("_Redo Create Empty File")); + + g_free (name); +} + +static void +create_from_template_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + char *name; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + create_undo_common (eaction, count, descriptions); + + name = g_file_get_parse_name (eaction->target_file); + descriptions[1] = g_strdup_printf (_("Create new file '%s' from template "), name); + g_free (name); + + labels[0] = g_strdup (_("_Undo Create from Template")); + labels[1] = g_strdup (_("_Redo Create from Template")); +} + +static void +create_folder_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + char *name; + NautilusFileUndoDataCreate* eaction = (NautilusFileUndoDataCreate*) action; + + create_undo_common (eaction, count, descriptions); + + name = g_file_get_parse_name (eaction->target_file); + descriptions[1] = g_strdup_printf (_("Create a new folder '%s'"), name); + + labels[0] = g_strdup (_("_Undo Create Folder")); + labels[1] = g_strdup (_("_Redo Create Folder")); + + g_free (name); +} + +static void +trash_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + NautilusFileUndoDataTrash* eaction = (NautilusFileUndoDataTrash*) action; + count = g_hash_table_size (eaction->trashed); + + if (count != 1) { + descriptions[0] = g_strdup_printf (_("Restore %d items from trash"), count); + descriptions[1] = g_strdup_printf (_("Move %d items to trash"), count); + } else { + GList *keys; + char *name, *orig_path; + GFile *file; + + keys = g_hash_table_get_keys (eaction->trashed); + file = g_file_new_for_commandline_arg (keys->data); + name = g_file_get_basename (file); + orig_path = g_file_get_path (file); + descriptions[0] = g_strdup_printf (_("Restore '%s' to '%s'"), name, orig_path); + + g_free (name); + g_free (orig_path); + g_list_free (keys); + + name = g_file_get_parse_name (file); + descriptions[1] = g_strdup_printf (_("Move '%s' to trash"), name); + + g_free (name); + g_object_unref (file); + + labels[0] = g_strdup (_("_Undo Trash")); + labels[1] = g_strdup (_("_Redo Trash")); + } +} + +static void +restore_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + if (count != 1) { + descriptions[0] = g_strdup_printf (_("Move %d items back to trash"), count); + descriptions[1] = g_strdup_printf (_("Restore %d items from trash"), count); + } else { + char *name; + + name = get_first_target_short_name (eaction); + descriptions[0] = g_strdup_printf (_("Move '%s' back to trash"), name); + descriptions[1] = g_strdup_printf (_("Restore '%s' from trash"), name); + + g_free (name); + + labels[0] = g_strdup (_("_Undo Restore from Trash")); + labels[1] = g_strdup (_("_Redo Restore from Trash")); + } +} + +static void +create_link_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + NautilusFileUndoDataExt* eaction = (NautilusFileUndoDataExt*) action; + + if (count != 1) { + descriptions[0] = g_strdup_printf (_("Delete links to %d items"), count); + descriptions[1] = g_strdup_printf (_("Create links to %d items"), count); + } else { + char *name; + + name = get_first_target_short_name (eaction); + descriptions[0] = g_strdup_printf (_("Delete link to '%s'"), name); + descriptions[1] = g_strdup_printf (_("Create link to '%s'"), name); + + labels[0] = g_strdup (_("_Undo Create Link")); + labels[1] = g_strdup (_("_Redo Create Link")); + + g_free (name); + } +} + +static void +recursive_permissions_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + char *name; + NautilusFileUndoDataRecursivePermissions* eaction = (NautilusFileUndoDataRecursivePermissions*) action; + + name = g_file_get_path (eaction->dest_dir); + + descriptions[0] = g_strdup_printf (_("Restore original permissions of items enclosed in '%s'"), name); + descriptions[1] = g_strdup_printf (_("Set permissions of items enclosed in '%s'"), name); + + labels[0] = g_strdup (_("_Undo Change Permissions")); + labels[1] = g_strdup (_("_Redo Change Permissions")); + + g_free (name); +} + +static void +set_permissions_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + char *name; + NautilusFileUndoDataPermissions* eaction = (NautilusFileUndoDataPermissions*) action; + + name = g_file_get_parse_name (eaction->target_file); + descriptions[0] = g_strdup_printf (_("Restore original permissions of '%s'"), name); + descriptions[1] = g_strdup_printf (_("Set permissions of '%s'"), name); + + labels[0] = g_strdup (_("_Undo Change Permissions")); + labels[1] = g_strdup (_("_Redo Change Permissions")); + + g_free (name); +} + +static void +change_group_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *name; + NautilusFileUndoDataOwnership* eaction = (NautilusFileUndoDataOwnership*) action; + + name = g_file_get_parse_name (eaction->target_file); + descriptions[0] = g_strdup_printf (_("Restore group of '%s' to '%s'"), + name, eaction->original_ownership); + descriptions[1] = g_strdup_printf (_("Set group of '%s' to '%s'"), + name, eaction->new_ownership); + + labels[0] = g_strdup (_("_Undo Change Group")); + labels[1] = g_strdup (_("_Redo Change Group")); + + g_free (name); +} + +static void +change_owner_description_func (NautilusFileUndoData *action, + guint count, + gchar **labels, + gchar **descriptions) +{ + gchar *name; + NautilusFileUndoDataOwnership* eaction = (NautilusFileUndoDataOwnership*) action; + + name = g_file_get_parse_name (eaction->target_file); + descriptions[0] = g_strdup_printf (_("Restore owner of '%s' to '%s'"), + name, eaction->original_ownership); + descriptions[1] = g_strdup_printf (_("Set owner of '%s' to '%s'"), + name, eaction->new_ownership); + + labels[0] = g_strdup (_("_Undo Change Owner")); + labels[1] = g_strdup (_("_Redo Change Owner")); + + g_free (name); +} + +static void +finalize_undo_data_ext (NautilusFileUndoData* data) +{ + NautilusFileUndoDataExt* extdata = (NautilusFileUndoDataExt*) data; + if (extdata->sources) { + g_list_foreach (extdata->sources, (GFunc) g_free, NULL); + g_list_free (extdata->sources); + } + if (extdata->destinations) { + g_list_foreach (extdata->destinations, (GFunc) g_free, NULL); + g_list_free (extdata->destinations); + } + if (extdata->src_dir) { + g_object_unref (extdata->src_dir); + } + if (extdata->dest_dir) { + g_object_unref (extdata->dest_dir); + } + g_slice_free (NautilusFileUndoDataExt, extdata); +} + +static void +finalize_undo_data_rename (NautilusFileUndoData* data) +{ + NautilusFileUndoDataRename* extdata = (NautilusFileUndoDataRename*) data; + if (extdata->old_file) { + g_object_unref (extdata->old_file); + } + if (extdata->new_file) { + g_free (extdata->new_file); + } + g_slice_free (NautilusFileUndoDataRename, extdata); +} + +static void +finalize_undo_data_create (NautilusFileUndoData* data) +{ + NautilusFileUndoDataCreate* extdata = (NautilusFileUndoDataCreate*) data; + if (extdata->target_file) { + g_object_unref (extdata->target_file); + } + g_free (extdata->template); + g_slice_free (NautilusFileUndoDataCreate, extdata); +} + +static void +finalize_undo_data_trash (NautilusFileUndoData* data) +{ + NautilusFileUndoDataTrash* extdata = (NautilusFileUndoDataTrash*) data; + if (extdata->trashed) { + g_hash_table_destroy (extdata->trashed); + } + g_slice_free (NautilusFileUndoDataTrash, extdata); +} + +static void +finalize_undo_data_permissions (NautilusFileUndoData* data) +{ + NautilusFileUndoDataPermissions* extdata = (NautilusFileUndoDataPermissions*) data; + if (extdata->target_file) { + g_object_unref (extdata->target_file); + } + g_slice_free (NautilusFileUndoDataPermissions, extdata); +} + +static void +finalize_undo_data_recursivepermissions (NautilusFileUndoData* data) +{ + NautilusFileUndoDataRecursivePermissions* extdata = (NautilusFileUndoDataRecursivePermissions*) data; + if (extdata->original_permissions) { + g_hash_table_destroy (extdata->original_permissions); + } + if (extdata->dest_dir) { + g_object_unref (extdata->dest_dir); + } + g_slice_free (NautilusFileUndoDataRecursivePermissions, extdata); +} + +static void +finalize_undo_data_ownership (NautilusFileUndoData* data) +{ + NautilusFileUndoDataOwnership* extdata = (NautilusFileUndoDataOwnership*) data; + if (extdata->target_file) { + g_object_unref (extdata->target_file); + } + g_free (extdata->original_ownership); + g_free (extdata->new_ownership); + g_slice_free (NautilusFileUndoDataOwnership, extdata); +} + + +static NautilusFileUndoData * +create_from_type (NautilusFileUndoDataType type) +{ + struct { + void (* undo_func) (NautilusFileUndoData *data); + void (* redo_func) (NautilusFileUndoData *data); + void (* strings_func) (NautilusFileUndoData *data, + guint count, + gchar **labels, + gchar **descriptions); + void (* finalize_func) (NautilusFileUndoData *data); + gsize alloc_size; + } const mappings[NAUTILUS_FILE_UNDO_NUM_TYPES] = { + /* copy action */ + { copy_or_link_undo_func, copy_redo_func, + copy_description_func, finalize_undo_data_ext, + sizeof(NautilusFileUndoDataExt) }, + /* duplicate action */ + { copy_or_link_undo_func, duplicate_redo_func, + duplicate_description_func, finalize_undo_data_ext, + sizeof(NautilusFileUndoDataExt) }, + /* move action */ + { move_undo_func, move_restore_redo_func, + move_description_func, finalize_undo_data_ext, + sizeof(NautilusFileUndoDataExt) }, + /* rename action */ + { rename_undo_func, rename_redo_func, + rename_description_func, finalize_undo_data_rename, + sizeof(NautilusFileUndoDataRename) }, + /* create empty action */ + { create_undo_func, create_empty_redo_func, + create_empty_description_func, finalize_undo_data_create, + sizeof(NautilusFileUndoDataCreate) }, + /* create from template action */ + { create_undo_func, create_from_template_redo_func, + create_from_template_description_func, finalize_undo_data_create, + sizeof(NautilusFileUndoDataCreate) }, + /* create folder action */ + { create_undo_func, create_folder_redo_func, + create_folder_description_func, finalize_undo_data_create, + sizeof(NautilusFileUndoDataCreate) }, + /* move to trash action */ + { trash_undo_func, trash_redo_func, + trash_description_func, finalize_undo_data_trash, + sizeof(NautilusFileUndoDataTrash) }, + /* restore from trash action */ + { restore_undo_func, move_restore_redo_func, + restore_description_func, finalize_undo_data_ext, + sizeof(NautilusFileUndoDataExt) }, + /* create link action */ + { create_undo_func, create_link_redo_func, + create_link_description_func, finalize_undo_data_ext, + sizeof(NautilusFileUndoDataExt) }, + /* recursive permissions action */ + { recursive_permissions_undo_func, recursive_permissions_redo_func, + recursive_permissions_description_func, finalize_undo_data_recursivepermissions, + sizeof(NautilusFileUndoDataRecursivePermissions) }, + /* set permissions action */ + { set_permissions_undo_func, set_permissions_redo_func, + set_permissions_description_func , finalize_undo_data_permissions, + sizeof(NautilusFileUndoDataPermissions) }, + /* change group action */ + { change_group_undo_func, change_group_redo_func, + change_group_description_func, finalize_undo_data_ownership, + sizeof(NautilusFileUndoDataOwnership) }, + /* change owner action */ + { change_owner_undo_func, change_owner_redo_func, + change_owner_description_func, finalize_undo_data_ownership, + sizeof(NautilusFileUndoDataOwnership) }, + }; + + NautilusFileUndoData *retval; + + retval = g_slice_alloc0 (mappings[type].alloc_size); + retval->undo_func = mappings[type].undo_func; + retval->redo_func = mappings[type].redo_func; + retval->strings_func = mappings[type].strings_func; + retval->finalize_func = mappings[type].finalize_func; + + return retval; +} + +/* functions to manipulate the action data */ +NautilusFileUndoData * +nautilus_file_undo_data_new (NautilusFileUndoDataType type, + gint items_count) +{ + NautilusFileUndoData *data; + + data = create_from_type (type); + data->type = type; + data->count = items_count; + + return data; +} + +void +nautilus_file_undo_data_set_src_dir (NautilusFileUndoData *action_data, + GFile *src) +{ + NautilusFileUndoDataExt* eaction_data = (NautilusFileUndoDataExt*) action_data; + eaction_data->src_dir = g_object_ref (src); +} + +void +nautilus_file_undo_data_set_dest_dir (NautilusFileUndoData *action_data, + GFile *dest) +{ + NautilusFileUndoDataExt* eaction_data = (NautilusFileUndoDataExt*) action_data; + eaction_data->dest_dir = g_object_ref (dest); +} + +void +nautilus_file_undo_data_add_origin_target_pair (NautilusFileUndoData *action_data, + GFile *origin, + GFile *target) +{ + NautilusFileUndoDataExt* eaction_data = (NautilusFileUndoDataExt*) action_data; + eaction_data->sources = + g_list_append (eaction_data->sources, g_object_ref (origin)); + eaction_data->destinations = + g_list_append (eaction_data->destinations, g_object_ref (target)); + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_add_trashed_file (NautilusFileUndoData *action_data, + GFile *file, + guint64 mtime) +{ + guint64 *modification_time; + char *original_uri; + NautilusFileUndoDataTrash* eaction_data = (NautilusFileUndoDataTrash*) action_data; + + if (eaction_data->trashed == NULL) { + eaction_data->trashed = + g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + } + + modification_time = g_new (guint64, 1); + *modification_time = mtime; + + original_uri = g_file_get_uri (file); + + g_hash_table_insert (eaction_data->trashed, original_uri, modification_time); + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_add_file_permissions (NautilusFileUndoData *action_data, + GFile *file, + guint32 permission) +{ + guint32 *current_permissions; + char *original_uri; + NautilusFileUndoDataRecursivePermissions* eaction_data = (NautilusFileUndoDataRecursivePermissions*) action_data; + + if (eaction_data->original_permissions == NULL) { + eaction_data->original_permissions = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + } + + current_permissions = g_new (guint32, 1); + *current_permissions = permission; + + original_uri = g_file_get_uri (file); + + g_hash_table_insert (eaction_data->original_permissions, original_uri, current_permissions); + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_set_file_permissions (NautilusFileUndoData *action_data, + GFile *file, + guint32 current_permissions, + guint32 new_permissions) +{ + NautilusFileUndoDataPermissions* eaction_data = (NautilusFileUndoDataPermissions*) action_data; + eaction_data->target_file = g_object_ref (file); + eaction_data->current_permissions = current_permissions; + eaction_data->new_permissions = new_permissions; + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_set_owner_change_information (NautilusFileUndoData *action_data, + GFile *file, + const char *current_user, + const char *new_user) +{ + NautilusFileUndoDataOwnership* eaction_data = (NautilusFileUndoDataOwnership*) action_data; + eaction_data->target_file = g_object_ref (file); + eaction_data->original_ownership = g_strdup (current_user); + eaction_data->new_ownership = g_strdup (new_user); + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_set_group_change_information (NautilusFileUndoData *action_data, + GFile *file, + const char *current_group, + const char *new_group) +{ + NautilusFileUndoDataOwnership* eaction_data = (NautilusFileUndoDataOwnership*) action_data; + eaction_data->target_file = g_object_ref (file); + eaction_data->original_ownership = g_strdup (current_group); + eaction_data->new_ownership = g_strdup (new_group); + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_set_recursive_permissions (NautilusFileUndoData *action_data, + guint32 file_permissions, + guint32 file_mask, + guint32 dir_permissions, + guint32 dir_mask) +{ + NautilusFileUndoDataRecursivePermissions* eaction_data = (NautilusFileUndoDataRecursivePermissions*) action_data; + eaction_data->file_permissions = file_permissions; + eaction_data->file_mask = file_mask; + eaction_data->dir_permissions = dir_permissions; + eaction_data->dir_mask = dir_mask; + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_set_recursive_permissions_dest_dir (NautilusFileUndoData *action_data, + GFile *dest) +{ + NautilusFileUndoDataRecursivePermissions* eaction_data = (NautilusFileUndoDataRecursivePermissions*) action_data; + eaction_data->dest_dir = g_object_ref (dest); +} + +void +nautilus_file_undo_data_set_create_data (NautilusFileUndoData *action_data, + GFile *file, + const char *template) +{ + NautilusFileUndoDataCreate* eaction_data = (NautilusFileUndoDataCreate*) action_data; + eaction_data->target_file = g_object_ref (file); + eaction_data->template = g_strdup (template); + + action_data->is_valid = TRUE; +} + +void +nautilus_file_undo_data_set_rename_information (NautilusFileUndoData *action_data, + GFile *old_file, + GFile *new_file) +{ + NautilusFileUndoDataRename* eaction_data = (NautilusFileUndoDataRename*) action_data; + eaction_data->old_file = g_object_ref (old_file); + eaction_data->new_file = g_object_ref (new_file); + + action_data->is_valid = TRUE; +} |