[nautilus/undo-manager: 3/3] undostack-manager: move to a vfunc-based undo/redo actions



commit ad52d982d35860ae157b7b14cd7f343a4e632ef8
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Mon Nov 29 10:19:31 2010 +0100

    undostack-manager: move to a vfunc-based undo/redo actions
    
    Instead of having huge switch-case blocks, separate each undo/redo
    snippet in a separate vfunc.
    Add a vfunc to refresh action labels and descriptions.
    
    This makes the code more readable and maintainable, but there's still a
    bunch of work to do to make this work properly.

 libnautilus-private/nautilus-undostack-manager.c | 1861 +++++++++++----------
 libnautilus-private/nautilus-undostack-manager.h |   21 +-
 2 files changed, 985 insertions(+), 897 deletions(-)
---
diff --git a/libnautilus-private/nautilus-undostack-manager.c b/libnautilus-private/nautilus-undostack-manager.c
index b9038af..91c7012 100644
--- a/libnautilus-private/nautilus-undostack-manager.c
+++ b/libnautilus-private/nautilus-undostack-manager.c
@@ -2,6 +2,7 @@
 /* nautilus-undostack-manager.h - Manages undo/redo of file operations
  *
  * Copyright (C) 2007-2010 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
@@ -18,7 +19,9 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Author: Amos Brocco <amos brocco unifr ch>
+ * Authors: Amos Brocco <amos brocco unifr ch>
+ *          Cosimo Cecchi <cosimoc redhat com>
+ *
  */
 #include <config.h>
 
@@ -36,21 +39,31 @@
 /* Default depth of the undo/redo stack. */
 #define DEFAULT_UNDO_DEPTH 32
 
-struct _NautilusUndoStackActionData
-{
+struct _NautilusUndoStackActionData {
 	/* Common stuff */
 	NautilusUndoStackActionType type;
+
+	void (* undo_func) (NautilusUndoStackActionData *data);
+	void (* redo_func) (NautilusUndoStackActionData *data);
+
+	NautilusUndoStackFinishCallback callback;
+	gpointer callback_user_data;
+
 	NautilusUndoStackManager *manager;
 	eel_boolean_bit is_valid : 1;
 	eel_boolean_bit locked : 1;	/* True if the action is being undone/redone */
 	eel_boolean_bit freed : 1;	/* True if the action must be freed after undo/redo */
 	guint count;			/* Number of items */
 
-	/* Cached labels/descriptions */
-	char *undo_label;
-	char *undo_description;
-	char *redo_label;
-	char *redo_description;
+	void    (* strings_func) (NautilusUndoStackActionData *data,
+				  guint count,
+				  gchar **labels,
+				  gchar **descriptions);
+
+	gchar *undo_label;
+	gchar *redo_label;
+	gchar *undo_description;
+	gchar *redo_description;
 
 	/* Copy / Move stuff */
 	GFile *src_dir;
@@ -81,15 +94,12 @@ struct _NautilusUndoStackActionData
 	guint32 new_permissions;
 
 	/* Group */
-	char *original_group_name;
-	char *new_group_name;
-
-	/* Owner */
-	char *original_user_name;
-	char *new_user_name;
-
+	char *original_name;
+	char *new_name;
 };
 
+typedef struct _NautilusUndoStackActionData UndoData;
+
 struct _NautilusUndoStackManagerPrivate
 {
 	GQueue *stack;
@@ -99,9 +109,8 @@ struct _NautilusUndoStackManagerPrivate
 
 	guint undo_levels;
 	guint index;
-	eel_boolean_bit dispose_has_run : 1;
-	eel_boolean_bit undo_redo_flag : 1;
-	eel_boolean_bit confirm_delete : 1;
+	guint undo_redo_flag : 1;
+	guint confirm_delete : 1;
 };
 
 #define NAUTILUS_UNDO_STACK_MANAGER_GET_PRIVATE(o)	\
@@ -128,11 +137,6 @@ static NautilusUndoStackActionData * stack_scroll_right (NautilusUndoStackManage
 static NautilusUndoStackActionData * get_next_redo_action (NautilusUndoStackManagerPrivate *priv);
 static NautilusUndoStackActionData * get_next_undo_action (NautilusUndoStackManagerPrivate *priv);
 
-static char *get_undo_label (NautilusUndoStackActionData *action);
-static char *get_undo_description (NautilusUndoStackActionData *action);
-static char *get_redo_label (NautilusUndoStackActionData *action);
-static char *get_redo_description (NautilusUndoStackActionData *action);
-
 static void do_menu_update (NautilusUndoStackManager * manager);
 static void undo_redo_done_transfer_callback (GHashTable * debuting_uris, gpointer data);
 static void undo_redo_op_callback (gpointer callback_data);
@@ -161,13 +165,12 @@ nautilus_undo_stack_manager_init (NautilusUndoStackManager * self)
 	priv->stack = g_queue_new ();
 	priv->mutex = g_mutex_new ();
 	priv->index = 0;
-	priv->dispose_has_run = FALSE;
 	priv->undo_redo_flag = FALSE;
 	priv->confirm_delete = FALSE;
 }
 
 static void
-free_undo_stack_action_data (NautilusUndoStackActionData *action)
+undo_stack_action_data_free (NautilusUndoStackActionData *action)
 {
 	g_return_if_fail (action != NULL);
 
@@ -178,10 +181,8 @@ free_undo_stack_action_data (NautilusUndoStackActionData *action)
 	g_free (action->redo_label);
 	g_free (action->redo_description);
 
-	g_free (action->original_group_name);
-	g_free (action->original_user_name);
-	g_free (action->new_group_name);
-	g_free (action->new_user_name);
+	g_free (action->original_name);
+	g_free (action->new_name);
 
 	if (action->sources) {
 		g_list_free_full (action->sources, g_free);
@@ -217,7 +218,7 @@ nautilus_undo_stack_manager_finalize (GObject * object)
 
 	g_mutex_lock (priv->mutex);
 	
-	g_queue_foreach (priv->stack, (GFunc) free_undo_stack_action_data, NULL);
+	g_queue_foreach (priv->stack, (GFunc) undo_stack_action_data_free, NULL);
 	g_queue_free (priv->stack);
 
 	g_mutex_unlock (priv->mutex);
@@ -384,6 +385,71 @@ nautilus_undo_stack_manager_is_undo_redo (NautilusUndoStackManager *manager)
 	return FALSE;
 }
 
+static void
+refresh_strings (UndoData *action)
+{
+	gchar **descriptions;
+	gchar **labels;
+
+	descriptions = (gchar **) g_malloc0 (3 * sizeof (gchar *));
+	descriptions[2] = NULL;
+
+	labels = (gchar **) g_malloc0 (3 * sizeof (gchar *));
+	labels[2] = NULL;
+
+	action->strings_func (action, action->count,
+			      labels, descriptions);
+
+	action->undo_label = labels[0];
+	action->redo_label = labels[1];
+
+	action->undo_description = descriptions[0];
+	action->redo_description = descriptions[1];
+
+	g_free (descriptions);
+	g_free (labels);
+}
+
+static const gchar *
+get_redo_label (UndoData *action)
+{
+	if (action->redo_label == NULL) {
+		refresh_strings (action);
+	}
+
+	return action->redo_label;
+}
+
+static const gchar *
+get_undo_label (UndoData *action)
+{
+	if (action->undo_label == NULL) {
+		refresh_strings (action);
+	}
+
+	return action->undo_label;
+}
+
+static const char *
+get_undo_description (UndoData *action)
+{
+	if (action->undo_description == NULL) {
+		refresh_strings (action);
+	}
+
+	return action->undo_description;
+}
+
+static const char *
+get_redo_description (UndoData *action)
+{
+	if (action->redo_description == NULL) {
+		refresh_strings (action);
+	}
+
+	return action->redo_description;
+}
+
 /**
  * nautilus_undo_stack_manager_request_menu_update:
  * @manager:
@@ -396,329 +462,462 @@ nautilus_undo_stack_manager_request_menu_update (NautilusUndoStackManager *manag
 	do_menu_update (manager);
 }
 
-/**
- * nautilus_undo_stack_manager_redo:
- * @manager:
- * @cb:
- * @user_data:
- *
- * Redoes the last file operation.
- */
-void
-nautilus_undo_stack_manager_redo (NautilusUndoStackManager        *manager,
-                                  NautilusUndoStackFinishCallback  callback,
-                                  gpointer                         user_data)
+
+/* undo helpers */
+
+static void
+delete_uris (NautilusUndoStackManager *self,
+	     GList *uris,
+	     UndoData *action)
+{
+	if (self->priv->confirm_delete) {
+		nautilus_file_operations_delete (uris, NULL,
+						 undo_redo_done_delete_callback, action);
+	} else {
+		self->priv->undo_redo_flag = FALSE;
+
+		/* We skip the confirmation message */
+		GList *f;
+		for (f = uris; f != NULL; f = f->next) {
+			g_file_delete (f->data, NULL, NULL);
+		}
+
+		/* Here we must do what's necessary for the callback */
+		undo_redo_done_transfer_callback (NULL, action);
+	}
+}
+
+static void
+create_undo_func (UndoData *action)
 {
-	NautilusUndoStackManagerPrivate *priv;
-	NautilusUndoStackActionData *action;
-	NautilusFile *file;
 	GList *uris;
-	char *new_name;
-	char *parent_uri;
+	gchar *uri;
 
-	priv = manager->priv;
+	uri = g_file_get_uri (action->target_file);
+	uris = construct_gfile_list_from_uri (uri);
 
-	/* Update the menus invalidating undo/redo while an operation is already underway */
-	g_mutex_lock (priv->mutex);
-	action = stack_scroll_left (priv);
-	/* Action will be NULL if redo is not possible */
-	if (action != NULL) {
-		action->locked = TRUE;
+	delete_uris (action->manager, uris, action);
+
+	g_free (uri);
+	g_list_free_full (uris, g_object_unref);
+}
+
+static void
+copy_or_link_undo_func (UndoData *action)
+{
+	GList *uris;
+
+	uris = construct_gfile_list (action->destinations, action->dest_dir);
+	uris = g_list_reverse (uris); /* Deleting must be done in reverse */
+
+	delete_uris (action->manager, uris, action);
+
+	g_list_free_full (uris, g_object_unref);
+}
+
+static void
+restore_undo_func (UndoData *action)
+{
+	GList *uris;
+
+	uris = construct_gfile_list (action->destinations, action->dest_dir);
+	nautilus_file_operations_trash_or_delete (uris, NULL,
+						  undo_redo_done_delete_callback, action);
+
+	g_list_free_full (uris, g_object_unref);
+}
+
+static void
+trash_undo_func (UndoData *action)
+{
+	NautilusUndoStackManagerPrivate *priv = action->manager->priv;
+	GHashTable *files_to_restore;
+
+	/* Internally managed op, clear the undo_redo_flag.
+	 * Same as calling nautilus_undo_stack_manager_is_undo_redo()
+	 * minus the function call and unused return val.
+	 */
+
+	priv->undo_redo_flag = FALSE;
+	files_to_restore = retrieve_files_to_restore (action->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_mutex_unlock (priv->mutex);
-	do_menu_update (manager);
 
-	uris = NULL;
-	if (action != NULL) {
-		action->locked = TRUE; /* Remember to unlock when redo is finished */
-		priv->undo_redo_flag = TRUE;
-		switch (action->type) {
-			case NAUTILUS_UNDO_STACK_COPY:
-				uris = construct_gfile_list (action->sources, action->src_dir);
-				nautilus_file_operations_copy (uris, NULL, action->dest_dir, NULL, undo_redo_done_transfer_callback, action);
-				g_list_free_full (uris, g_object_unref);
-				break;
-			case NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE:
-			{
-				GFile *parent;
-				parent = g_file_get_parent (action->target_file);
-				parent_uri = g_file_get_uri (parent);
-				new_name = g_file_get_parse_name (action->target_file);
-				nautilus_file_operations_new_file_from_template (NULL,
-						NULL,
-						parent_uri,
-						new_name, action->template, undo_redo_done_create_callback, action);
-				g_free (parent_uri);
-				g_free (new_name);
-				g_object_unref (parent);
-			}
-				break;
-			case NAUTILUS_UNDO_STACK_DUPLICATE:
-				uris = construct_gfile_list (action->sources, action->src_dir);
-				nautilus_file_operations_duplicate (uris, NULL, NULL, undo_redo_done_transfer_callback, action);
-				g_list_free_full (uris, g_object_unref);
-				break;
-			case NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH:
-			case NAUTILUS_UNDO_STACK_MOVE:
-				uris = construct_gfile_list (action->sources, action->src_dir);
-				nautilus_file_operations_move (uris, NULL, action->dest_dir, NULL, undo_redo_done_transfer_callback, action);
-				g_list_free_full (uris, g_object_unref);
-				break;
-			case NAUTILUS_UNDO_STACK_RENAME:
-				new_name = g_file_get_basename (action->new_file);
-				file = nautilus_file_get (action->old_file);
-				nautilus_file_rename (file, new_name, undo_redo_done_rename_callback, action);
-				g_object_unref (file);
-				g_free (new_name);
-				break;
-			case NAUTILUS_UNDO_STACK_CREATE_EMPTY_FILE:
-			{
-				GFile *parent;
-				parent = g_file_get_parent (action->target_file);
-				parent_uri = g_file_get_uri (parent);
-				new_name = g_file_get_parse_name (action->target_file);
-				nautilus_file_operations_new_file (NULL, NULL, parent_uri,
-						new_name,
-						action->template,
-						action->count, undo_redo_done_create_callback, action);
-				g_free (parent_uri);
-				g_free (new_name);
-			}
-				break;
-			case NAUTILUS_UNDO_STACK_CREATE_FOLDER:
-			{
-				GFile *parent;
-				parent = g_file_get_parent (action->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);
-			}
-				break;
-			case NAUTILUS_UNDO_STACK_MOVE_TO_TRASH:
-				if (g_hash_table_size (action->trashed) > 0) {
-					GList *uri_to_trash;
-					uri_to_trash = g_hash_table_get_keys (action->trashed);
-					uris = uri_list_to_gfile_list (uri_to_trash);
-					nautilus_file_operations_trash_or_delete (uris, NULL, undo_redo_done_delete_callback, action);
-					g_list_free (uri_to_trash);
-					g_list_free_full (uris, g_object_unref);
-				}
-				break;
-			case NAUTILUS_UNDO_STACK_CREATE_LINK:
-				uris = construct_gfile_list (action->sources, action->src_dir);
-				nautilus_file_operations_link (uris, NULL, action->dest_dir, NULL, undo_redo_done_transfer_callback, action);
-				g_list_free_full (uris, g_object_unref);
-				break;
-			case NAUTILUS_UNDO_STACK_SET_PERMISSIONS:
-				file = nautilus_file_get (action->target_file);
-				nautilus_file_set_permissions (file, action->new_permissions, undo_redo_done_rename_callback, action);
-				g_object_unref (file);
-				break;
-			case NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS:
-				parent_uri = g_file_get_uri (action->dest_dir);
-				nautilus_file_set_permissions_recursive (parent_uri,
-						action->file_permissions,
-						action->file_mask,
-						action->dir_permissions,
-						action->dir_mask,
-						undo_redo_op_callback,
-						action);
-				g_free (parent_uri);
-				break;
-			case NAUTILUS_UNDO_STACK_CHANGE_GROUP:
-				file = nautilus_file_get (action->target_file);
-				nautilus_file_set_group (file,
-						action->new_group_name,
-						undo_redo_done_rename_callback,
-						action);
-				g_object_unref (file);
-				break;
-			case NAUTILUS_UNDO_STACK_CHANGE_OWNER:
-				file = nautilus_file_get (action->target_file);
-				nautilus_file_set_owner (file,
-						action->new_user_name,
-						undo_redo_done_rename_callback,
-						action);
-				g_object_unref (file);
-				break;
-			default:
-				priv->undo_redo_flag = FALSE;
-				break; /* We shouldn't be here */
+	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 (UndoData *action)
+{
+	GList *uris;
+
+	uris = construct_gfile_list (action->destinations, action->dest_dir);
+	nautilus_file_operations_move (uris, NULL,
+				       action->src_dir, NULL,
+				       undo_redo_done_transfer_callback, action);
+
+	g_list_free_full (uris, g_object_unref);
+}
+
+static void
+rename_undo_func (UndoData *action)
+{
+	gchar *new_name;
+	NautilusFile *file;
+
+	new_name = g_file_get_basename (action->old_file);
+	file = nautilus_file_get (action->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 (UndoData *action)
+{
+	NautilusFile *file;
+
+	file = nautilus_file_get (action->target_file);
+
+	nautilus_file_set_permissions (file,
+				       action->current_permissions,
+				       undo_redo_done_rename_callback, action);
+
+	nautilus_file_unref (file);
+}
+
+static void
+recursive_permissions_undo_func (UndoData *action)
+{
+	NautilusUndoStackManagerPrivate *priv = action->manager->priv;
+
+	/* Internally managed op, clear the undo_redo_flag. */
+	priv->undo_redo_flag = FALSE;
+
+	if (g_hash_table_size (action->original_permissions) > 0) {
+		GList *gfiles_list;
+		guint32 *perm;
+		GList *l;
+		GFile *dest;
+		char *item;
+
+		gfiles_list = g_hash_table_get_keys (action->original_permissions);
+		for (l = gfiles_list; l != NULL; l = l->next) {
+			item = l->data;
+			perm = g_hash_table_lookup (action->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);
 	}
+}
 
-	if (callback != NULL) {
-		callback (user_data);
+static void
+change_group_undo_func (UndoData *action)
+{
+	NautilusFile *file;
+
+	file = nautilus_file_get (action->target_file);
+
+	nautilus_file_set_group (file,
+				 action->original_name,
+				 undo_redo_done_rename_callback, action);
+
+	nautilus_file_unref (file);
+}
+
+static void
+change_owner_undo_func (UndoData *action)
+{
+	NautilusFile *file;
+
+	file = nautilus_file_get (action->target_file);
+
+	nautilus_file_set_owner (file,
+				 action->original_name,
+				 undo_redo_done_rename_callback, action);
+
+	nautilus_file_unref (file);
+}
+
+/* redo helpers */
+
+static void
+copy_redo_func (UndoData *action)
+{
+	GList *locations;
+
+	locations = construct_gfile_list (action->sources, action->src_dir);
+	nautilus_file_operations_copy (locations, NULL,
+				       action->dest_dir, NULL,
+				       undo_redo_done_transfer_callback, action);
+
+	g_list_free_full (locations, g_object_unref);
+}
+
+static void
+create_from_template_redo_func (UndoData *action)
+{
+	GFile *parent;
+	gchar *parent_uri, *new_name;
+
+	parent = g_file_get_parent (action->target_file);
+	parent_uri = g_file_get_uri (parent);
+	new_name = g_file_get_parse_name (action->target_file);
+	nautilus_file_operations_new_file_from_template (NULL, NULL,
+							 parent_uri, new_name,
+							 action->template,
+							 undo_redo_done_create_callback, action);
+
+	g_free (parent_uri);
+	g_free (new_name);
+	g_object_unref (parent);
+}
+
+static void
+duplicate_redo_func (UndoData *action)
+{
+	GList *locations;
+
+	locations = construct_gfile_list (action->sources, action->src_dir);
+	nautilus_file_operations_duplicate (locations, NULL, NULL,
+					    undo_redo_done_transfer_callback, action);
+
+	g_list_free_full (locations, g_object_unref);
+}
+
+static void
+move_restore_redo_func (UndoData *action)
+{
+	GList *locations;
+
+	locations = construct_gfile_list (action->sources, action->src_dir);
+	nautilus_file_operations_move (locations, NULL,
+				       action->dest_dir, NULL,
+				       undo_redo_done_transfer_callback, action);
+
+	g_list_free_full (locations, g_object_unref);
+}
+
+static void
+rename_redo_func (UndoData *action)
+{
+	gchar *new_name;
+	NautilusFile *file;
+
+	new_name = g_file_get_basename (action->new_file);
+	file = nautilus_file_get (action->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 (UndoData *action)
+{
+	GFile *parent;
+	gchar *parent_uri;
+	gchar *new_name;
+
+	parent = g_file_get_parent (action->target_file);
+	parent_uri = g_file_get_uri (parent);
+	new_name = g_file_get_parse_name (action->target_file);
+	nautilus_file_operations_new_file (NULL, NULL, parent_uri,
+					   new_name,
+					   action->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 (UndoData *action)
+{
+	GFile *parent;
+	gchar *parent_uri;
+
+	parent = g_file_get_parent (action->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 (UndoData *action)
+{
+	if (g_hash_table_size (action->trashed) > 0) {
+		GList *uri_to_trash, *locations;
+
+		uri_to_trash = g_hash_table_get_keys (action->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);
 	}
 }
 
-/**
- * nautilus_undo_stack_manager_undo:
- * @manager:
- * @user_data:
- * @callback:
- *
- * Undoes the operation on the top of the undo stack, if there is one.
- * When the operation is finished, @callback will be called with
- * @user_data.
- */
-void
-nautilus_undo_stack_manager_undo (NautilusUndoStackManager        *manager,
-				  NautilusUndoStackFinishCallback  callback,
-				  gpointer                         user_data)
+static void
+create_link_redo_func (UndoData *action)
+{
+	GList *locations;
+
+	locations = construct_gfile_list (action->sources, action->src_dir);
+	nautilus_file_operations_link (locations, NULL,
+				       action->dest_dir, NULL,
+				       undo_redo_done_transfer_callback, action);
+	g_list_free_full (locations, g_object_unref);
+}
+
+static void
+set_permissions_redo_func (UndoData *action)
 {
-	NautilusUndoStackManagerPrivate *priv;
-	NautilusUndoStackActionData *action;
 	NautilusFile *file;
-	GList *uris;
-	GHashTable *files_to_restore;
-	char *new_name;
 
-	priv = manager->priv;
+	file = nautilus_file_get (action->target_file);
+	nautilus_file_set_permissions (file, action->new_permissions,
+				       undo_redo_done_rename_callback, action);
+
+	nautilus_file_unref (file);
+}
+
+static void
+recursive_permissions_redo_func (UndoData *action)
+{
+	gchar *parent_uri;
+
+	parent_uri = g_file_get_uri (action->dest_dir);
+	nautilus_file_set_permissions_recursive (parent_uri,
+						 action->file_permissions,
+						 action->file_mask,
+						 action->dir_permissions,
+						 action->dir_mask,
+						 undo_redo_op_callback,
+						 action);
+	g_free (parent_uri);
+}
+
+static void
+change_group_redo_func (UndoData *action)
+{
+	NautilusFile *file;
+
+	file = nautilus_file_get (action->target_file);
+	nautilus_file_set_group (file,
+				 action->new_name,
+				 undo_redo_done_rename_callback,
+				 action);
+
+	nautilus_file_unref (file);
+}
+
+static void
+change_owner_redo_func (UndoData *action)
+{
+	NautilusFile *file;
+
+	file = nautilus_file_get (action->target_file);
+	nautilus_file_set_owner (file,
+				 action->new_name,
+				 undo_redo_done_rename_callback,
+				 action);
+
+	nautilus_file_unref (file);
+}
+
+static void
+do_undo_redo (NautilusUndoStackManager *self,
+	      gboolean undo,
+	      NautilusUndoStackFinishCallback callback,
+	      gpointer user_data)
+{
+	NautilusUndoStackManagerPrivate *priv = self->priv;
+	UndoData *action;
 
 	/* Update the menus invalidating undo/redo while an operation is already underway */
 	g_mutex_lock (priv->mutex);
-	action = stack_scroll_right (priv);
+
+	if (undo) {
+		action = stack_scroll_right (priv);
+	} else {
+		action = stack_scroll_left (priv);
+	}
+
+	/* Action will be NULL if redo is not possible */
 	if (action != NULL) {
-		action->locked = TRUE;
+		action->locked = TRUE;  /* Remember to unlock when finished */
 	}
+
 	g_mutex_unlock (priv->mutex);
-	do_menu_update (manager);
 
-	uris = NULL;
+	do_menu_update (self);
+
 	if (action != NULL) {
-		/* Note: Internal managed ops have to call nautilus_undo_stack_manager_is_undo_redo (manager);
-		 * TODO: AW - this is really awkward. */
 		priv->undo_redo_flag = TRUE;
-		switch (action->type) {
-			case NAUTILUS_UNDO_STACK_CREATE_EMPTY_FILE:
-			case NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE:
-			case NAUTILUS_UNDO_STACK_CREATE_FOLDER:
-				uris = construct_gfile_list_from_uri (g_file_get_uri (action->target_file));
-			case NAUTILUS_UNDO_STACK_COPY:
-			case NAUTILUS_UNDO_STACK_DUPLICATE:
-			case NAUTILUS_UNDO_STACK_CREATE_LINK:
-				if (!uris) {
-					uris = construct_gfile_list (action->destinations, action->dest_dir);
-					uris = g_list_reverse (uris); /* Deleting must be done in reverse */
-				}
-				if (priv->confirm_delete) {
-					nautilus_file_operations_delete (uris, NULL, undo_redo_done_delete_callback, action);
-					g_list_free_full (uris, g_object_unref);
-				} else {
-					priv->undo_redo_flag = FALSE;
-					/* We skip the confirmation message */
-					GList *f;
-					for (f = uris; f != NULL; f = f->next) {
-						g_file_delete (f->data, NULL, NULL);
-						g_object_unref (f->data);
-					}
-					g_list_free (uris);
-					/* Here we must do what's necessary for the callback */
-					undo_redo_done_transfer_callback (NULL, action);
-				}
-				break;
-			case NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH:
-				uris = construct_gfile_list (action->destinations, action->dest_dir);
-				nautilus_file_operations_trash_or_delete (uris, NULL, undo_redo_done_delete_callback, action);
-				g_list_free_full (uris, g_object_unref);
-				break;
-			case NAUTILUS_UNDO_STACK_MOVE_TO_TRASH:
-				/* Internally managed op, clear the undo_redo_flag.
-				 * Same as calling nautilus_undo_stack_manager_is_undo_redo()
-				 * minus the function call and unused return val.
-				 */
-				priv->undo_redo_flag = FALSE;
-				files_to_restore = retrieve_files_to_restore (action->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);
-				break;
-			case NAUTILUS_UNDO_STACK_MOVE:
-				uris = construct_gfile_list (action->destinations, action->dest_dir);
-				nautilus_file_operations_move (uris, NULL, action->src_dir, NULL, undo_redo_done_transfer_callback, action);
-				g_list_free_full (uris, g_object_unref);
-				break;
-			case NAUTILUS_UNDO_STACK_RENAME:
-				new_name = g_file_get_basename (action->old_file);
-				file = nautilus_file_get (action->new_file);
-				nautilus_file_rename (file, new_name, undo_redo_done_rename_callback, action);
-				nautilus_file_unref (file);
-				g_free (new_name);
-				break;
-			case NAUTILUS_UNDO_STACK_SET_PERMISSIONS:
-				file = nautilus_file_get (action->target_file);
-				nautilus_file_set_permissions (file,
-						action->current_permissions,
-						undo_redo_done_rename_callback, action);
-				nautilus_file_unref (file);
-				break;
-			case NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS:
-				/* Internally managed op, clear the undo_redo_flag. */
-				priv->undo_redo_flag = FALSE;
-				if (g_hash_table_size (action->original_permissions) > 0) {
-					GList *gfiles_list;
-					guint32 *perm;
-					GList *l;
-					GFile *dest;
-					char *item;
-
-					gfiles_list = g_hash_table_get_keys (action->original_permissions);
-					for (l = gfiles_list; l != NULL; l = l->next) {
-						item = l->data;
-						perm = g_hash_table_lookup (action->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);
-				}
-				break;
-			case NAUTILUS_UNDO_STACK_CHANGE_GROUP:
-				file = nautilus_file_get (action->target_file);
-				nautilus_file_set_group (file,
-						action->original_group_name,
-						undo_redo_done_rename_callback, action);
-				nautilus_file_unref (file);
-				break;
-			case NAUTILUS_UNDO_STACK_CHANGE_OWNER:
-				file = nautilus_file_get (action->target_file);
-				nautilus_file_set_owner (file,
-						action->original_user_name,
-						undo_redo_done_rename_callback, action);
-				nautilus_file_unref (file);
-				break;
-			default:
-				g_assert_not_reached ();
-				break;
+
+		if (undo) {
+			action->undo_func (action);
+		} else {
+			action->redo_func (action);
 		}
 	}
 
 	if (callback != NULL) {
 		callback (user_data);
 	}
+	
+}
+
+void
+nautilus_undo_stack_manager_redo (NautilusUndoStackManager        *manager,
+                                  NautilusUndoStackFinishCallback  callback,
+                                  gpointer                         user_data)
+{
+	do_undo_redo (manager, FALSE, callback, user_data);
+}
+
+void
+nautilus_undo_stack_manager_undo (NautilusUndoStackManager        *manager,
+				  NautilusUndoStackFinishCallback  callback,
+				  gpointer                         user_data)
+{
+	do_undo_redo (manager, TRUE, callback, user_data);
 }
 
 /**
@@ -734,13 +933,10 @@ nautilus_undo_stack_manager_add_action (NautilusUndoStackManager    *manager,
 {
 	NautilusUndoStackManagerPrivate *priv;
 
-	g_return_if_fail (manager != NULL);
-	g_return_if_fail (action != NULL);
-
 	priv = manager->priv;
 
 	if (!(action && action->is_valid)) {
-		free_undo_stack_action_data (action);
+		undo_stack_action_data_free (action);
 		return;
 	}
 
@@ -822,32 +1018,6 @@ nautilus_undo_stack_manager_get_file_modification_time (GFile * file)
 }
 
 /**
- * nautilus_undo_stack_action_data_new:
- * @manager:
- * @items_count:
- *
- * Returns: a new undo data container.
- */
-NautilusUndoStackActionData *
-nautilus_undo_stack_action_data_new (NautilusUndoStackActionType type,
-                                     gint                        items_count)
-{
-	NautilusUndoStackActionData *data;
-
-	data = g_slice_new0 (NautilusUndoStackActionData);
-	data->type = type;
-	data->count = items_count;
-
-	if (type == NAUTILUS_UNDO_STACK_MOVE_TO_TRASH) {
-		data->trashed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-	} else if (type == NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS) {
-		data->original_permissions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-	}
-
-	return data;
-}
-
-/**
  * nautilus_undo_stack_action_data_set_src_dir:
  * @action_data:
  * @src:
@@ -858,8 +1028,6 @@ void
 nautilus_undo_stack_action_data_set_src_dir (NautilusUndoStackActionData *action_data,
                                              GFile                       *src)
 {
-	g_return_if_fail (action_data != NULL);
-
 	action_data->src_dir = src;
 }
 
@@ -874,8 +1042,6 @@ void
 nautilus_undo_stack_action_data_set_dest_dir (NautilusUndoStackActionData *action_data,
                                               GFile                       *dest)
 {
-	g_return_if_fail (action_data != NULL);
-
 	action_data->dest_dir = dest;
 }
 
@@ -895,8 +1061,6 @@ nautilus_undo_stack_action_data_add_origin_target_pair (NautilusUndoStackActionD
 	char *src_relative;
 	char *dest_relative;
 
-	g_return_if_fail (action_data != NULL);
-
 	src_relative = g_file_get_relative_path (action_data->src_dir, origin);
 	action_data->sources = g_list_append (action_data->sources, src_relative);
 	dest_relative = g_file_get_relative_path (action_data->dest_dir, target);
@@ -921,7 +1085,11 @@ nautilus_undo_stack_action_data_add_trashed_file (NautilusUndoStackActionData *a
 	guint64 *modification_time;
 	char *original_uri;
 
-	g_return_if_fail (action_data != NULL);
+	if (action_data->trashed == NULL) {
+		action_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;
@@ -949,7 +1117,10 @@ nautilus_undo_stack_action_data_add_file_permissions (NautilusUndoStackActionDat
 	guint32 *current_permissions;
 	char *original_uri;
 
-	g_return_if_fail (action_data != NULL);
+	if (action_data->original_permissions == NULL) {
+		action_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;
@@ -976,9 +1147,6 @@ nautilus_undo_stack_action_data_set_file_permissions (NautilusUndoStackActionDat
                                                       guint32                      current_permissions,
                                                       guint32                      new_permissions)
 {
-	g_return_if_fail (action_data != NULL);
-	g_return_if_fail (G_IS_FILE (file));
-
 	action_data->target_file = g_object_ref (file);
 	action_data->current_permissions = current_permissions;
 	action_data->new_permissions = new_permissions;
@@ -1001,12 +1169,9 @@ nautilus_undo_stack_action_data_set_owner_change_information (NautilusUndoStackA
                                                               const char                  *current_user,
                                                               const char                  *new_user)
 {
-	g_return_if_fail (action_data != NULL);
-	g_return_if_fail (G_IS_FILE (file));
-
 	action_data->target_file = g_object_ref (file);
-	action_data->original_user_name = g_strdup (current_user);
-	action_data->new_user_name = g_strdup (new_user);
+	action_data->original_name = g_strdup (current_user);
+	action_data->new_name = g_strdup (new_user);
 
 	action_data->is_valid = TRUE;
 }
@@ -1026,12 +1191,9 @@ nautilus_undo_stack_action_data_set_group_change_information (NautilusUndoStackA
                                                               const char                  *current_group,
                                                               const char                  *new_group)
 {
-	g_return_if_fail (action_data != NULL);
-	g_return_if_fail (G_IS_FILE (file));
-
 	action_data->target_file = g_object_ref (file);
-	action_data->original_group_name = g_strdup (current_group);
-	action_data->new_group_name = g_strdup (new_group);
+	action_data->original_name = g_strdup (current_group);
+	action_data->new_name = g_strdup (new_group);
 
 	action_data->is_valid = TRUE;
 }
@@ -1053,8 +1215,6 @@ nautilus_undo_stack_action_data_set_recursive_permissions (NautilusUndoStackActi
                                                            guint32                      dir_permissions,
                                                            guint32                      dir_mask)
 {
-	g_return_if_fail (action_data != NULL);
-
 	action_data->file_permissions = file_permissions;
 	action_data->file_mask = file_mask;
 	action_data->dir_permissions = dir_permissions;
@@ -1076,9 +1236,6 @@ nautilus_undo_stack_action_data_set_create_data (NautilusUndoStackActionData *ac
                                                  GFile                       *file,
                                                  const char                  *template)
 {
-	g_return_if_fail (action_data != NULL);
-	g_return_if_fail (G_IS_FILE (file));
-
 	action_data->target_file = g_object_ref (file);
 	action_data->template = g_strdup (template);
 
@@ -1098,8 +1255,6 @@ nautilus_undo_stack_action_data_set_rename_information (NautilusUndoStackActionD
                                                         GFile                       *old_file,
                                                         GFile                       *new_file)
 {
-	g_return_if_fail (action_data != NULL);
-
 	action_data->old_file = g_object_ref (old_file);
 	action_data->new_file = g_object_ref (new_file);
 
@@ -1147,7 +1302,7 @@ stack_clear_n_oldest (GQueue * stack, guint n)
 		if (action->locked) {
 			action->freed = TRUE;
 		} else {
-			free_undo_stack_action_data (action);
+			undo_stack_action_data_free (action);
 		}
 	}
 }
@@ -1175,7 +1330,7 @@ clear_redo_actions (NautilusUndoStackManagerPrivate *priv)
 	while (priv->index > 0) {
 		NautilusUndoStackActionData *head;
 		head = (NautilusUndoStackActionData *)g_queue_pop_head (priv->stack);
-		free_undo_stack_action_data (head);
+		undo_stack_action_data_free (head);
 		priv->index--;
 	}
 }
@@ -1210,504 +1365,6 @@ get_first_target_short_name (NautilusUndoStackActionData *action)
 	return file_name;
 }
 
-static char *
-get_undo_description (NautilusUndoStackActionData *action)
-{
-	char *description;
-	char *source;
-	guint count;
-
-	g_return_val_if_fail (action != NULL, NULL);
-
-	description = NULL;
-	source = NULL;
-
-	if (action->undo_description != NULL)
-		return action->undo_description;
-
-	if (action->src_dir) {
-		source = g_file_get_path (action->src_dir);
-	}
-	count = action->count;
-	switch (action->type) {
-		case NAUTILUS_UNDO_STACK_COPY:
-			if (count != 1) {
-				description = g_strdup_printf (_("Delete %d copied items"), count);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Delete '%s'"), name);
-				g_free (name);
-			}
-			break;
-		case NAUTILUS_UNDO_STACK_DUPLICATE:
-			if (count != 1) {
-				description = g_strdup_printf (_("Delete %d duplicated items"), count);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Delete '%s'"), name);
-				g_free (name);
-			}
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE:
-			if (count != 1) {
-				description = g_strdup_printf (_("Move %d items back to '%s'"), count, source);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Move '%s' back to '%s'"), name, source);
-				g_free (name);
-			}
-			break;
-		case NAUTILUS_UNDO_STACK_RENAME:
-		{
-			char *from_name;
-			char *to_name;
-			from_name = g_file_get_parse_name (action->new_file);
-			to_name = g_file_get_parse_name (action->old_file);
-			description = g_strdup_printf (_("Rename '%s' as '%s'"), from_name, to_name);
-			g_free (from_name);
-			g_free (to_name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE:
-		case NAUTILUS_UNDO_STACK_CREATE_EMPTY_FILE:
-		case NAUTILUS_UNDO_STACK_CREATE_FOLDER:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Delete '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE_TO_TRASH:
-		{
-			count = g_hash_table_size (action->trashed);
-			if (count != 1) {
-				description = g_strdup_printf (_("Restore %d items from trash"), count);
-			} else {
-				GList *keys, *first;
-				char *item, *name, *orig_path;
-				GFile *file;
-
-				keys = g_hash_table_get_keys (action->trashed);
-				first = g_list_first (keys);
-				item = (char *) first->data;
-				file = g_file_new_for_commandline_arg (item);
-				name = g_file_get_basename (file);
-				orig_path = g_file_get_path (file);
-				description = g_strdup_printf (_("Restore '%s' to '%s'"), name, orig_path);
-				g_free (name);
-				g_free (orig_path);
-				g_list_free (keys);
-				g_object_unref (file);
-			}
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH:
-		{
-			if (count != 1) {
-				description = g_strdup_printf (_("Move %d items back to trash"), count);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Move '%s' back to trash"), name);
-				g_free (name);
-			}
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_LINK:
-		{
-			if (count != 1) {
-				description = g_strdup_printf (_("Delete links to %d items"), count);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Delete link to '%s'"), name);
-				g_free (name);
-			}
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS:
-		{
-			char *name;
-			name = g_file_get_path (action->dest_dir);
-			description = g_strdup_printf (_("Restore original permissions of items enclosed in '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_SET_PERMISSIONS:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Restore original permissions of '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_GROUP:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Restore group of '%s' to '%s'"),
-						       name, action->original_group_name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_OWNER:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Restore owner of '%s' to '%s'"),
-							name, action->original_user_name);
-			g_free (name);
-		}
-			break;
-		default:
-			break;
-	}
-	if (source) {
-		g_free (source);
-	}
-	action->undo_description = description;
-
-	return description;
-}
-
-static char *
-get_redo_description (NautilusUndoStackActionData *action)
-{
-	char *description;
-	char *destination;
-	guint count;
-
-	description = NULL;
-	destination = NULL;
-
-	g_return_val_if_fail (action != NULL, NULL);
-
-	if (action->redo_description != NULL) {
-		return action->redo_description;
-	}
-
-	if (action->dest_dir) {
-		destination = g_file_get_path (action->dest_dir);
-	}
-
-	count = action->count;
-	switch (action->type) {
-		case NAUTILUS_UNDO_STACK_COPY:
-			if (count != 1) {
-				description = g_strdup_printf (_("Copy %d items to '%s'"), count, destination);
-			} else {
-				char *name;
-				name= get_first_target_short_name (action);
-				description = g_strdup_printf (_("Copy '%s' to '%s'"), name, destination);
-				g_free (name);
-			}
-			break;
-		case NAUTILUS_UNDO_STACK_DUPLICATE:
-			if (count != 1) {
-				description = g_strdup_printf (_("Duplicate of %d items in '%s'"), count, destination);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Duplicate '%s' in '%s'"), name, destination);
-				g_free (name);
-			}
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE:
-			if (count != 1) {
-				description = g_strdup_printf (_("Move %d items to '%s'"), count, destination);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Move '%s' to '%s'"), name, destination);
-				g_free (name);
-			}
-			break;
-		case NAUTILUS_UNDO_STACK_RENAME:
-		{
-			char *from_name;
-			char *to_name;
-			from_name = g_file_get_parse_name (action->old_file);
-			to_name = g_file_get_parse_name (action->new_file);
-			description = g_strdup_printf (_("Rename '%s' as '%s'"), from_name, to_name);
-			g_free (from_name);
-			g_free (to_name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Create new file '%s' from template "), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_EMPTY_FILE:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Create an empty file '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FOLDER:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Create a new folder '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE_TO_TRASH:
-		{
-			count = g_hash_table_size (action->trashed);
-			if (count != 1) {
-				description = g_strdup_printf (_("Move %d items to trash"), count);
-			} else {
-				GList *keys;
-				GList *first;
-				char *item;
-				char *name;
-
-				keys = g_hash_table_get_keys (action->trashed);
-				first = g_list_first (keys);
-				item = (char *) first->data;
-				name = g_file_get_parse_name (action->target_file);
-				description = g_strdup_printf (_("Move '%s' to trash"), name);
-				g_free (name);
-				g_list_free (keys);
-			}
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH:
-		{
-			if (count != 1) {
-				description = g_strdup_printf (_("Restore %d items from trash"), count);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Restore '%s' from trash"), name);
-				g_free (name);
-			}
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_LINK:
-		{
-			if (count != 1) {
-				description = g_strdup_printf (_("Create links to %d items"), count);
-			} else {
-				char *name;
-				name = get_first_target_short_name (action);
-				description = g_strdup_printf (_("Create link to '%s'"), name);
-				g_free (name);
-			}
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS:
-		{
-			char *name;
-			name = g_file_get_path (action->dest_dir);
-			description = g_strdup_printf (_("Set permissions of items enclosed in '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_SET_PERMISSIONS:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Set permissions of '%s'"), name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_GROUP:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Set group of '%s' to '%s'"), name, action->new_group_name);
-			g_free (name);
-		}
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_OWNER:
-		{
-			char *name;
-			name = g_file_get_parse_name (action->target_file);
-			description = g_strdup_printf (_("Set owner of '%s' to '%s'"), name, action->new_user_name);
-			g_free (name);
-		}
-			break;
-		default:
-			break;
-	}
-
-	if (destination) {
-		g_free (destination);
-	}
-
-	action->redo_description = description;
-
-	return description;
-}
-
-static char *
-get_undo_label (NautilusUndoStackActionData *action)
-{
-	char *label;
-	guint count;
-
-	g_return_val_if_fail (action != NULL, NULL);
-
-	if (action->redo_label != NULL) {
-		return action->redo_label;
-	}
-
-	label = NULL;
-	count = action->count;
-	switch (action->type) {
-		case NAUTILUS_UNDO_STACK_COPY:
-			label = g_strdup_printf (ngettext ("_Undo copy of %d item",
-							   "_Undo copy of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_DUPLICATE:
-			label = g_strdup_printf (ngettext ("_Undo duplicate of %d item",
-							   "_Undo duplicate of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE:
-			label = g_strdup_printf (ngettext ("_Undo move of %d item",
-							   "_Undo move of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_RENAME:
-			label = g_strdup_printf (ngettext ("_Undo rename of %d item",
-							   "_Undo rename of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_EMPTY_FILE:
-			label = g_strdup_printf (_("_Undo creation of an empty file"));
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE:
-			label = g_strdup_printf (_("_Undo creation of a file from template"));
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FOLDER:
-			label = g_strdup_printf (ngettext ("_Undo creation of %d folder",
-							"_Undo creation of %d folders", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE_TO_TRASH:
-			label = g_strdup_printf (ngettext ("_Undo move to trash of %d item",
-							"_Undo move to trash of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH:
-			label = g_strdup_printf (ngettext ("_Undo restore from trash of %d item",
-							   "_Undo restore from trash of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_LINK:
-			label = g_strdup_printf (ngettext ("_Undo create link to %d item",
-							   "_Undo create link to %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS:
-			label = g_strdup_printf (ngettext ("Undo recursive change permissions of %d item",
-							   "Undo recursive change permissions of %d items",
-							   count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_SET_PERMISSIONS:
-			label = g_strdup_printf (ngettext ("Undo change permissions of %d item",
-							   "Undo change permissions of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_GROUP:
-			label = g_strdup_printf (ngettext ("Undo change group of %d item",
-							   "Undo change group of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_OWNER:
-			label = g_strdup_printf (ngettext ("Undo change owner of %d item",
-							   "Undo change owner of %d items", count), count);
-			break;
-		default:
-			break;
-	}
-	action->undo_label = label;
-
-	return label;
-}
-
-static char *
-get_redo_label (NautilusUndoStackActionData *action)
-{
-	char *label;
-	guint count;
-
-	g_return_val_if_fail (action != NULL, NULL);
-
-	if (action->redo_label != NULL) {
-		return action->redo_label;
-	}
-
-	label = NULL;
-	count = action->count;
-	switch (action->type) {
-		case NAUTILUS_UNDO_STACK_COPY:
-			label = g_strdup_printf (ngettext ("_Redo copy of %d item",
-							   "_Redo copy of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_DUPLICATE:
-			label = g_strdup_printf (ngettext ("_Redo duplicate of %d item",
-							   "_Redo duplicate of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE:
-			label = g_strdup_printf (ngettext ("_Redo move of %d item",
-							   "_Redo move of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_RENAME:
-			label = g_strdup_printf (ngettext ("_Redo rename of %d item",
-							   "_Redo rename of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_EMPTY_FILE:
-			label = g_strdup_printf (_("_Redo creation of an empty file"));
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE:
-			label = g_strdup_printf (_("_Redo creation of a file from template"));
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_FOLDER:
-			label = g_strdup_printf (ngettext ("_Redo creation of %d folder",
-							"_Redo creation of %d folders", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_MOVE_TO_TRASH:
-			label = g_strdup_printf (ngettext ("_Redo move to trash of %d item",
-							"_Redo move to trash of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH:
-			label = g_strdup_printf (ngettext ("_Redo restore from trash of %d item",
-							"_Redo restore from trash of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CREATE_LINK:
-			label = g_strdup_printf (ngettext ("_Redo create link to %d item",
-							   "_Redo create link to %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS:
-			label = g_strdup_printf (ngettext ("Redo recursive change permissions of %d item",
-							   "Redo recursive change permissions of %d items",
-							   count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_SET_PERMISSIONS:
-			label = g_strdup_printf (ngettext ("Redo change permissions of %d item",
-							   "Redo change permissions of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_GROUP:
-			label = g_strdup_printf (ngettext ("Redo change group of %d item",
-							   "Redo change group of %d items", count), count);
-			break;
-		case NAUTILUS_UNDO_STACK_CHANGE_OWNER:
-			label = g_strdup_printf (ngettext ("Redo change owner of %d item",
-							   "Redo change owner of %d items", count), count);
-			break;
-		default:
-			break;
-	}
-
-	action->redo_label = label;
-
-	return label;
-}
-
 static void
 undo_redo_done_transfer_callback (GHashTable * debuting_uris, gpointer data)
 {
@@ -1717,7 +1374,7 @@ undo_redo_done_transfer_callback (GHashTable * debuting_uris, gpointer data)
 
 	/* If the action needed to be freed but was locked, free now */
 	if (action->freed) {
-		free_undo_stack_action_data (action);
+		undo_stack_action_data_free (action);
 	} else {
 		action->locked = FALSE;
 	}
@@ -1825,12 +1482,18 @@ do_menu_update (NautilusUndoStackManager * manager)
 	g_mutex_lock (priv->mutex);
 
 	action = get_next_undo_action (priv);
-	data->undo_label = get_undo_label (action);
-	data->undo_description = get_undo_description (action);
+
+	if (action != NULL) {
+		data->undo_label = get_undo_label (action);
+		data->undo_description = get_undo_description (action);
+	}
 
 	action = get_next_redo_action (priv);
-	data->redo_label = get_redo_label (action);
-	data->redo_description = get_redo_description (action);
+
+	if (action != NULL) {
+		data->redo_label = get_redo_label (action);
+		data->redo_description = get_redo_description (action);
+	}
 
 	g_mutex_unlock (priv->mutex);
 
@@ -1944,3 +1607,429 @@ retrieve_files_to_restore (GHashTable * trashed)
 
 	return to_restore;
 }
+
+static void
+copy_description_func (UndoData *action,
+		       guint count,
+		       gchar **labels,
+		       gchar **descriptions)
+{
+	gchar *destination;
+
+	destination = g_file_get_path (action->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 (action);
+		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 (UndoData *action,
+			    guint count,
+			    gchar **labels,
+			    gchar **descriptions)
+{
+	gchar *destination;
+
+	destination = g_file_get_path (action->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 (action);
+		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 (UndoData *action,
+		       guint count,
+		       gchar **labels,
+		       gchar **descriptions)
+{
+	gchar *source, *destination;
+
+        source = g_file_get_path (action->src_dir);
+	destination = g_file_get_path (action->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 (action);
+		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 (UndoData *action,
+			 guint count,
+			 gchar **labels,
+			 gchar **descriptions)
+{
+	gchar *new_name, *old_name;
+
+	new_name = g_file_get_parse_name (action->new_file);
+	old_name = g_file_get_parse_name (action->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 (UndoData *action,
+		    guint count,
+		    gchar **descriptions)
+{
+            char *name;
+
+	    name = g_file_get_parse_name (action->target_file);
+	    descriptions[0] = g_strdup_printf (_("Delete '%s'"), name);
+
+	    g_free (name);
+}
+
+static void
+create_empty_description_func (UndoData *action,
+			       guint count,
+			       gchar **labels,
+			       gchar **descriptions)
+{
+	gchar *name;
+
+	/* undo */
+	create_undo_common (action, count, descriptions);
+
+	name = g_file_get_parse_name (action->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 (UndoData *action,
+				       guint count,
+				       gchar **labels,
+				       gchar **descriptions)
+{
+	char *name;
+
+	/* undo */
+	create_undo_common (action, count, descriptions);
+
+	name = g_file_get_parse_name (action->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 (UndoData *action,
+				guint count,
+				gchar **labels,
+				gchar **descriptions)
+{
+	char *name;
+
+	/* undo */
+	create_undo_common (action, count, descriptions);
+
+	name = g_file_get_parse_name (action->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 (UndoData *action,
+			guint count,
+			gchar **labels,
+			gchar **descriptions)
+{
+	count = g_hash_table_size (action->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 (action->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);
+		g_object_unref (file);
+
+		name = g_file_get_parse_name (action->target_file);
+		descriptions[1] = g_strdup_printf (_("Move '%s' to trash"), name);
+
+		g_free (name);
+
+		labels[0] = g_strdup (_("_Undo Trash"));
+		labels[1] = g_strdup (_("_Redo Trash"));
+	}
+}
+
+static void
+restore_description_func (UndoData *action,
+			  guint count,
+			  gchar **labels,
+			  gchar **descriptions)
+{
+	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 (action);
+		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 (UndoData *action,
+			      guint count,
+			      gchar **labels,
+			      gchar **descriptions)
+{
+	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 (action);
+		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 (UndoData *action,
+					guint count,
+					gchar **labels,
+					gchar **descriptions)
+{
+	char *name;
+
+	name = g_file_get_path (action->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 (UndoData *action,
+				  guint count,
+				  gchar **labels,
+				  gchar **descriptions)
+{
+	char *name;
+
+	name = g_file_get_parse_name (action->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 (UndoData *action,
+			       guint count,
+			       gchar **labels,
+			       gchar **descriptions)
+{
+	gchar *name;
+
+	name = g_file_get_parse_name (action->target_file);
+	descriptions[0] = g_strdup_printf (_("Restore group of '%s' to '%s'"),
+					   name, action->original_name);
+	descriptions[1] = g_strdup_printf (_("Set group of '%s' to '%s'"),
+					   name, action->new_name);
+
+	labels[0] = g_strdup (_("_Undo Change Group"));
+	labels[1] = g_strdup (_("_Redo Change Group"));
+
+	g_free (name);
+}
+
+static void
+change_owner_description_func (UndoData *action,
+			       guint count,
+			       gchar **labels,
+			       gchar **descriptions)
+{
+	gchar *name;
+
+	name = g_file_get_parse_name (action->target_file);
+	descriptions[0] = g_strdup_printf (_("Restore owner of '%s' to '%s'"),
+					   name, action->original_name);
+	descriptions[1] = g_strdup_printf (_("Set owner of '%s' to '%s'"),
+					   name, action->new_name);
+
+	labels[0] = g_strdup (_("_Undo Change Owner"));
+	labels[1] = g_strdup (_("_Redo Change Owner"));
+
+	g_free (name);
+}
+
+static UndoData *
+create_from_type (NautilusUndoStackActionType type)
+{
+	struct {
+		void (* undo_func)               (NautilusUndoStackActionData *data);
+		void (* redo_func)               (NautilusUndoStackActionData *data);
+		void (* strings_func)            (NautilusUndoStackActionData *data,
+						  guint count,
+						  gchar **labels,
+						  gchar **descriptions);
+
+	} const mappings[NAUTILUS_UNDO_STACK_NUM_TYPES] = {
+		/* copy action */
+		{ copy_or_link_undo_func, copy_redo_func,
+		  copy_description_func },
+		/* duplicate action */
+		{ copy_or_link_undo_func, duplicate_redo_func,
+		  duplicate_description_func },
+		/* move action */
+		{ move_undo_func, move_restore_redo_func,
+		  move_description_func },
+		/* rename action */
+		{ rename_undo_func, rename_redo_func,
+		  rename_description_func },
+		/* create empty action */
+		{ create_undo_func, create_empty_redo_func,
+		  create_empty_description_func },
+		/* create from template action */
+		{ create_undo_func, create_from_template_redo_func,
+		  create_from_template_description_func },
+		/* create folder action */
+		{ create_undo_func, create_folder_redo_func,
+		  create_folder_description_func },
+		/* move to trash action */
+		{ trash_undo_func, trash_redo_func,
+		  trash_description_func },
+		/* restore from trash action */
+		{ restore_undo_func, move_restore_redo_func,
+		  restore_description_func },
+		/* create link action */
+		{ create_undo_func, create_link_redo_func,
+		  create_link_description_func },
+		/* recursive permissions action */
+		{ recursive_permissions_undo_func, recursive_permissions_redo_func,
+		  recursive_permissions_description_func },
+		/* set permissions action */
+		{ set_permissions_undo_func, set_permissions_redo_func,
+		  set_permissions_description_func },
+		/* change group action */
+		{ change_group_undo_func, change_group_redo_func,
+		  change_group_description_func },
+		/* change owner action */
+		{ change_owner_undo_func, change_owner_redo_func,
+		  change_owner_description_func },
+	};
+
+	UndoData *retval;
+
+	retval = g_slice_new0 (UndoData);
+	retval->undo_func = mappings[type].undo_func;
+	retval->redo_func = mappings[type].redo_func;
+	retval->strings_func = mappings[type].strings_func;
+
+	return retval;
+}
+
+NautilusUndoStackActionData *
+nautilus_undo_stack_action_data_new (NautilusUndoStackActionType type,
+                                     gint                        items_count)
+{
+	NautilusUndoStackActionData *data;
+
+	data = create_from_type (type);
+	data->type = type;
+	data->count = items_count;
+
+	return data;
+}
diff --git a/libnautilus-private/nautilus-undostack-manager.h b/libnautilus-private/nautilus-undostack-manager.h
index 2bfa47a..b90498b 100644
--- a/libnautilus-private/nautilus-undostack-manager.h
+++ b/libnautilus-private/nautilus-undostack-manager.h
@@ -50,7 +50,6 @@ typedef struct _NautilusUndoStackManagerPrivate NautilusUndoStackManagerPrivate;
 				   NautilusUndoStackManagerClass))
 
 typedef enum {
-	NAUTILUS_UNDO_STACK_INVALID,
 	NAUTILUS_UNDO_STACK_COPY,
 	NAUTILUS_UNDO_STACK_DUPLICATE,
 	NAUTILUS_UNDO_STACK_MOVE,
@@ -59,23 +58,23 @@ typedef enum {
 	NAUTILUS_UNDO_STACK_CREATE_FILE_FROM_TEMPLATE,
 	NAUTILUS_UNDO_STACK_CREATE_FOLDER,
 	NAUTILUS_UNDO_STACK_MOVE_TO_TRASH,
-	NAUTILUS_UNDO_STACK_CREATE_LINK,
 	NAUTILUS_UNDO_STACK_RESTORE_FROM_TRASH,
-	NAUTILUS_UNDO_STACK_SET_PERMISSIONS,
+	NAUTILUS_UNDO_STACK_CREATE_LINK,
 	NAUTILUS_UNDO_STACK_RECURSIVE_SET_PERMISSIONS,
+	NAUTILUS_UNDO_STACK_SET_PERMISSIONS,
+	NAUTILUS_UNDO_STACK_CHANGE_GROUP,
 	NAUTILUS_UNDO_STACK_CHANGE_OWNER,
-	NAUTILUS_UNDO_STACK_CHANGE_GROUP
+	NAUTILUS_UNDO_STACK_NUM_TYPES,
 } NautilusUndoStackActionType;
 
 typedef struct _NautilusUndoStackActionData NautilusUndoStackActionData;
 
-typedef struct _NautilusUndoStackMenuData NautilusUndoStackMenuData;
-struct _NautilusUndoStackMenuData {
-	char *undo_label;
-	char *undo_description;
-	char *redo_label;
-	char *redo_description;
-};
+typedef struct {
+	const char *undo_label;
+	const char *undo_description;
+	const char *redo_label;
+	const char *redo_description;
+} NautilusUndoStackMenuData;
 
 typedef void (*NautilusUndoStackFinishCallback) (gpointer data);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]