/* nautilus-file-undo-operations.c - Manages undo/redo of file operations
*
* Copyright (C) 2007-2011 Amos Brocco
* Copyright (C) 2010, 2012 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, see .
*
* Authors: Amos Brocco
* Cosimo Cecchi
*
*/
#include
#include "nautilus-file-undo-operations.h"
#include
#include "nautilus-file-operations.h"
#include "nautilus-file.h"
#include "nautilus-file-undo-manager.h"
#include "nautilus-batch-rename-dialog.h"
#include "nautilus-batch-rename-utilities.h"
#include "nautilus-tag-manager.h"
/* Since we use g_get_current_time for setting "orig_trash_time" in the undo
* info, there are situations where the difference between this value and the
* real deletion time can differ enough to make the rounding a difference of 1
* second, failing the equality check. To make sure we avoid this, and to be
* preventive, use 2 seconds epsilon.
*/
#define TRASH_TIME_EPSILON 2
typedef struct
{
NautilusFileUndoOp op_type;
guint count; /* Number of items */
GTask *apply_async_task;
gchar *undo_label;
gchar *redo_label;
gchar *undo_description;
gchar *redo_description;
} NautilusFileUndoInfoPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (NautilusFileUndoInfo, nautilus_file_undo_info, G_TYPE_OBJECT)
enum
{
PROP_OP_TYPE = 1,
PROP_ITEM_COUNT,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
/* description helpers */
static void
nautilus_file_undo_info_init (NautilusFileUndoInfo *self)
{
NautilusFileUndoInfoPrivate *priv;
priv = nautilus_file_undo_info_get_instance_private (self);
priv->apply_async_task = NULL;
}
static void
nautilus_file_undo_info_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
NautilusFileUndoInfo *self;
NautilusFileUndoInfoPrivate *priv;
self = NAUTILUS_FILE_UNDO_INFO (object);
priv = nautilus_file_undo_info_get_instance_private (self);
switch (property_id)
{
case PROP_OP_TYPE:
{
g_value_set_int (value, priv->op_type);
}
break;
case PROP_ITEM_COUNT:
{
g_value_set_int (value, priv->count);
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
break;
}
}
static void
nautilus_file_undo_info_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusFileUndoInfo *self;
NautilusFileUndoInfoPrivate *priv;
self = NAUTILUS_FILE_UNDO_INFO (object);
priv = nautilus_file_undo_info_get_instance_private (self);
switch (property_id)
{
case PROP_OP_TYPE:
{
priv->op_type = g_value_get_int (value);
}
break;
case PROP_ITEM_COUNT:
{
priv->count = g_value_get_int (value);
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
break;
}
}
static void
nautilus_file_redo_info_warn_redo (NautilusFileUndoInfo *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
g_critical ("Object %p of type %s does not implement redo_func!!",
self, G_OBJECT_TYPE_NAME (self));
}
static void
nautilus_file_undo_info_warn_undo (NautilusFileUndoInfo *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
g_critical ("Object %p of type %s does not implement undo_func!!",
self, G_OBJECT_TYPE_NAME (self));
}
static void
nautilus_file_undo_info_strings_func (NautilusFileUndoInfo *self,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
if (undo_label != NULL)
{
*undo_label = g_strdup (_("Undo"));
}
if (undo_description != NULL)
{
*undo_description = g_strdup (_("Undo last action"));
}
if (redo_label != NULL)
{
*redo_label = g_strdup (_("Redo"));
}
if (redo_description != NULL)
{
*redo_description = g_strdup (_("Redo last undone action"));
}
}
static void
nautilus_file_undo_info_finalize (GObject *object)
{
NautilusFileUndoInfo *self;
NautilusFileUndoInfoPrivate *priv;
self = NAUTILUS_FILE_UNDO_INFO (object);
priv = nautilus_file_undo_info_get_instance_private (self);
g_clear_object (&priv->apply_async_task);
G_OBJECT_CLASS (nautilus_file_undo_info_parent_class)->finalize (object);
}
static void
nautilus_file_undo_info_class_init (NautilusFileUndoInfoClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_finalize;
oclass->get_property = nautilus_file_undo_info_get_property;
oclass->set_property = nautilus_file_undo_info_set_property;
klass->undo_func = nautilus_file_undo_info_warn_undo;
klass->redo_func = nautilus_file_redo_info_warn_redo;
klass->strings_func = nautilus_file_undo_info_strings_func;
properties[PROP_OP_TYPE] =
g_param_spec_int ("op-type",
"Undo info op type",
"Type of undo operation",
0, NAUTILUS_FILE_UNDO_OP_NUM_TYPES - 1, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
properties[PROP_ITEM_COUNT] =
g_param_spec_int ("item-count",
"Number of items",
"Number of items",
0, G_MAXINT, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (oclass, N_PROPERTIES, properties);
}
NautilusFileUndoOp
nautilus_file_undo_info_get_op_type (NautilusFileUndoInfo *self)
{
NautilusFileUndoInfoPrivate *priv;
g_return_val_if_fail (NAUTILUS_IS_FILE_UNDO_INFO (self), NAUTILUS_FILE_UNDO_OP_INVALID);
priv = nautilus_file_undo_info_get_instance_private (self);
return priv->op_type;
}
static gint
nautilus_file_undo_info_get_item_count (NautilusFileUndoInfo *self)
{
NautilusFileUndoInfoPrivate *priv;
priv = nautilus_file_undo_info_get_instance_private (self);
return priv->count;
}
void
nautilus_file_undo_info_apply_async (NautilusFileUndoInfo *self,
gboolean undo,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data,
GAsyncReadyCallback callback,
gpointer user_data)
{
NautilusFileUndoInfoPrivate *priv;
g_return_if_fail (NAUTILUS_IS_FILE_UNDO_INFO (self));
priv = nautilus_file_undo_info_get_instance_private (self);
g_assert (priv->apply_async_task == NULL);
priv->apply_async_task = g_task_new (G_OBJECT (self),
NULL,
callback,
user_data);
if (undo)
{
NAUTILUS_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->undo_func (self,
parent_window,
dbus_data);
}
else
{
NAUTILUS_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->redo_func (self,
parent_window,
dbus_data);
}
}
typedef struct
{
gboolean success;
gboolean user_cancel;
} FileUndoInfoOpRes;
static void
file_undo_info_op_res_free (gpointer data)
{
g_slice_free (FileUndoInfoOpRes, data);
}
gboolean
nautilus_file_undo_info_apply_finish (NautilusFileUndoInfo *self,
GAsyncResult *res,
gboolean *user_cancel,
GError **error)
{
FileUndoInfoOpRes *op_res;
gboolean success = FALSE;
op_res = g_task_propagate_pointer (G_TASK (res), error);
if (op_res != NULL)
{
*user_cancel = op_res->user_cancel;
success = op_res->success;
file_undo_info_op_res_free (op_res);
}
return success;
}
void
nautilus_file_undo_info_get_strings (NautilusFileUndoInfo *self,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NAUTILUS_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->strings_func (self,
undo_label, undo_description,
redo_label, redo_description);
}
static void
file_undo_info_complete_apply (NautilusFileUndoInfo *self,
gboolean success,
gboolean user_cancel)
{
NautilusFileUndoInfoPrivate *priv;
FileUndoInfoOpRes *op_res;
priv = nautilus_file_undo_info_get_instance_private (self);
op_res = g_slice_new0 (FileUndoInfoOpRes);
op_res->user_cancel = user_cancel;
op_res->success = success;
g_task_return_pointer (priv->apply_async_task, op_res,
file_undo_info_op_res_free);
g_clear_object (&priv->apply_async_task);
}
static void
file_undo_info_transfer_callback (GHashTable *debuting_uris,
gboolean success,
gpointer user_data)
{
NautilusFileUndoInfo *self = user_data;
/* TODO: we need to forward the cancelled state from
* the file operation to the file undo info object.
*/
file_undo_info_complete_apply (self, success, FALSE);
}
static void
file_undo_info_operation_callback (NautilusFile *file,
GFile *result_location,
GError *error,
gpointer user_data)
{
NautilusFileUndoInfo *self = user_data;
file_undo_info_complete_apply (self, (error == NULL),
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
}
static void
file_undo_info_delete_callback (GHashTable *debuting_uris,
gboolean user_cancel,
gpointer user_data)
{
NautilusFileUndoInfo *self = user_data;
file_undo_info_complete_apply (self,
!user_cancel,
user_cancel);
}
/* copy/move/duplicate/link/restore from trash */
struct _NautilusFileUndoInfoExt
{
NautilusFileUndoInfo parent_instance;
GFile *src_dir;
GFile *dest_dir;
GQueue *sources; /* Relative to src_dir */
GQueue *destinations; /* Relative to dest_dir */
};
G_DEFINE_TYPE (NautilusFileUndoInfoExt, nautilus_file_undo_info_ext, NAUTILUS_TYPE_FILE_UNDO_INFO)
static char *
ext_get_first_target_short_name (NautilusFileUndoInfoExt *self)
{
GList *targets_first;
char *file_name = NULL;
targets_first = g_queue_peek_head_link (self->destinations);
if (targets_first != NULL &&
targets_first->data != NULL)
{
file_name = g_file_get_basename (targets_first->data);
}
return file_name;
}
static void
ext_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (info);
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
gint count = nautilus_file_undo_info_get_item_count (info);
gchar *name = NULL, *source, *destination;
source = g_file_get_path (self->src_dir);
destination = g_file_get_path (self->dest_dir);
if (count <= 1)
{
name = ext_get_first_target_short_name (self);
}
if (op_type == NAUTILUS_FILE_UNDO_OP_MOVE)
{
if (count > 1)
{
*undo_description = g_strdup_printf (ngettext ("Move %d item back to “%s”",
"Move %d items back to “%s”", count),
count, source);
*redo_description = g_strdup_printf (ngettext ("Move %d item to “%s”",
"Move %d items to “%s”", count),
count, destination);
*undo_label = g_strdup_printf (ngettext ("_Undo Move %d item",
"_Undo Move %d items", count),
count);
*redo_label = g_strdup_printf (ngettext ("_Redo Move %d item",
"_Redo Move %d items", count),
count);
}
else
{
*undo_description = g_strdup_printf (_("Move “%s” back to “%s”"), name, source);
*redo_description = g_strdup_printf (_("Move “%s” to “%s”"), name, destination);
*undo_label = g_strdup (_("_Undo Move"));
*redo_label = g_strdup (_("_Redo Move"));
}
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH)
{
*undo_label = g_strdup (_("_Undo Restore from Trash"));
*redo_label = g_strdup (_("_Redo Restore from Trash"));
if (count > 1)
{
*undo_description = g_strdup_printf (ngettext ("Move %d item back to trash",
"Move %d items back to trash", count),
count);
*redo_description = g_strdup_printf (ngettext ("Restore %d item from trash",
"Restore %d items from trash", count),
count);
}
else
{
*undo_description = g_strdup_printf (_("Move “%s” back to trash"), name);
*redo_description = g_strdup_printf (_("Restore “%s” from trash"), name);
}
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_COPY)
{
if (count > 1)
{
*undo_description = g_strdup_printf (ngettext ("Delete %d copied item",
"Delete %d copied items", count),
count);
*redo_description = g_strdup_printf (ngettext ("Copy %d item to “%s”",
"Copy %d items to “%s”", count),
count, destination);
*undo_label = g_strdup_printf (ngettext ("_Undo Copy %d item",
"_Undo Copy %d items", count),
count);
*redo_label = g_strdup_printf (ngettext ("_Redo Copy %d item",
"_Redo Copy %d items", count),
count);
}
else
{
*undo_description = g_strdup_printf (_("Delete “%s”"), name);
*redo_description = g_strdup_printf (_("Copy “%s” to “%s”"), name, destination);
*undo_label = g_strdup (_("_Undo Copy"));
*redo_label = g_strdup (_("_Redo Copy"));
}
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_DUPLICATE)
{
if (count > 1)
{
*undo_description = g_strdup_printf (ngettext ("Delete %d duplicated item",
"Delete %d duplicated items", count),
count);
*redo_description = g_strdup_printf (ngettext ("Duplicate %d item in “%s”",
"Duplicate %d items in “%s”", count),
count, destination);
*undo_label = g_strdup_printf (ngettext ("_Undo Duplicate %d item",
"_Undo Duplicate %d items", count),
count);
*redo_label = g_strdup_printf (ngettext ("_Redo Duplicate %d item",
"_Redo Duplicate %d items", count),
count);
}
else
{
*undo_description = g_strdup_printf (_("Delete “%s”"), name);
*redo_description = g_strdup_printf (_("Duplicate “%s” in “%s”"),
name, destination);
*undo_label = g_strdup (_("_Undo Duplicate"));
*redo_label = g_strdup (_("_Redo Duplicate"));
}
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_LINK)
{
if (count > 1)
{
*undo_description = g_strdup_printf (ngettext ("Delete links to %d item",
"Delete links to %d items", count),
count);
*redo_description = g_strdup_printf (ngettext ("Create links to %d item",
"Create links to %d items", count),
count);
}
else
{
*undo_description = g_strdup_printf (_("Delete link to “%s”"), name);
*redo_description = g_strdup_printf (_("Create link to “%s”"), name);
*undo_label = g_strdup (_("_Undo Create Link"));
*redo_label = g_strdup (_("_Redo Create Link"));
}
}
else
{
g_assert_not_reached ();
}
g_free (name);
g_free (source);
g_free (destination);
}
static void
ext_create_link_redo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
nautilus_file_operations_link (g_queue_peek_head_link (self->sources),
self->dest_dir,
parent_window,
dbus_data,
file_undo_info_transfer_callback,
self);
}
static void
ext_duplicate_redo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
nautilus_file_operations_duplicate (g_queue_peek_head_link (self->sources),
parent_window,
dbus_data,
file_undo_info_transfer_callback,
self);
}
static void
ext_copy_redo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
nautilus_file_operations_copy_async (g_queue_peek_head_link (self->sources),
self->dest_dir,
parent_window,
dbus_data,
file_undo_info_transfer_callback,
self);
}
static void
ext_move_restore_redo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
nautilus_file_operations_move_async (g_queue_peek_head_link (self->sources),
self->dest_dir,
parent_window,
dbus_data,
file_undo_info_transfer_callback,
self);
}
static void
ext_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (info);
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
if (op_type == NAUTILUS_FILE_UNDO_OP_MOVE ||
op_type == NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH)
{
ext_move_restore_redo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_COPY)
{
ext_copy_redo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_DUPLICATE)
{
ext_duplicate_redo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_LINK)
{
ext_create_link_redo_func (self, parent_window, dbus_data);
}
else
{
g_assert_not_reached ();
}
}
static void
ext_restore_undo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
nautilus_file_operations_trash_or_delete_async (g_queue_peek_head_link (self->destinations),
parent_window,
dbus_data,
file_undo_info_delete_callback,
self);
}
static void
ext_move_undo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
nautilus_file_operations_move_async (g_queue_peek_head_link (self->destinations),
self->src_dir,
parent_window,
dbus_data,
file_undo_info_transfer_callback,
self);
}
static void
ext_copy_duplicate_undo_func (NautilusFileUndoInfoExt *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
GList *files;
files = g_list_copy (g_queue_peek_head_link (self->destinations));
files = g_list_reverse (files); /* Deleting must be done in reverse */
nautilus_file_operations_delete_async (files, parent_window,
dbus_data,
file_undo_info_delete_callback, self);
g_list_free (files);
}
static void
ext_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (info);
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
if (op_type == NAUTILUS_FILE_UNDO_OP_COPY ||
op_type == NAUTILUS_FILE_UNDO_OP_DUPLICATE ||
op_type == NAUTILUS_FILE_UNDO_OP_CREATE_LINK)
{
ext_copy_duplicate_undo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_MOVE)
{
ext_move_undo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH)
{
ext_restore_undo_func (self, parent_window, dbus_data);
}
else
{
g_assert_not_reached ();
}
}
static void
nautilus_file_undo_info_ext_init (NautilusFileUndoInfoExt *self)
{
}
static void
nautilus_file_undo_info_ext_finalize (GObject *obj)
{
NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (obj);
if (self->sources)
{
g_queue_free_full (self->sources, g_object_unref);
}
if (self->destinations)
{
g_queue_free_full (self->destinations, g_object_unref);
}
g_clear_object (&self->src_dir);
g_clear_object (&self->dest_dir);
G_OBJECT_CLASS (nautilus_file_undo_info_ext_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_ext_class_init (NautilusFileUndoInfoExtClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_ext_finalize;
iclass->undo_func = ext_undo_func;
iclass->redo_func = ext_redo_func;
iclass->strings_func = ext_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_ext_new (NautilusFileUndoOp op_type,
gint item_count,
GFile *src_dir,
GFile *target_dir)
{
NautilusFileUndoInfoExt *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_EXT,
"op-type", op_type,
"item-count", item_count,
NULL);
self->src_dir = g_object_ref (src_dir);
self->dest_dir = g_object_ref (target_dir);
self->sources = g_queue_new ();
self->destinations = g_queue_new ();
return NAUTILUS_FILE_UNDO_INFO (self);
}
void
nautilus_file_undo_info_ext_add_origin_target_pair (NautilusFileUndoInfoExt *self,
GFile *origin,
GFile *target)
{
g_queue_push_tail (self->sources, g_object_ref (origin));
g_queue_push_tail (self->destinations, g_object_ref (target));
}
/* create new file/folder */
struct _NautilusFileUndoInfoCreate
{
NautilusFileUndoInfo parent_instance;
char *template;
GFile *target_file;
gint length;
};
G_DEFINE_TYPE (NautilusFileUndoInfoCreate, nautilus_file_undo_info_create, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
create_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (info);
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
char *name;
name = g_file_get_parse_name (self->target_file);
*undo_description = g_strdup_printf (_("Delete “%s”"), name);
if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE)
{
*redo_description = g_strdup_printf (_("Create an empty file “%s”"), name);
*undo_label = g_strdup (_("_Undo Create Empty File"));
*redo_label = g_strdup (_("_Redo Create Empty File"));
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER)
{
*redo_description = g_strdup_printf (_("Create a new folder “%s”"), name);
*undo_label = g_strdup (_("_Undo Create Folder"));
*redo_label = g_strdup (_("_Redo Create Folder"));
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE)
{
*redo_description = g_strdup_printf (_("Create new file “%s” from template "), name);
*undo_label = g_strdup (_("_Undo Create from Template"));
*redo_label = g_strdup (_("_Redo Create from Template"));
}
else
{
g_assert_not_reached ();
}
g_free (name);
}
static void
create_callback (GFile *new_file,
gboolean success,
gpointer callback_data)
{
file_undo_info_transfer_callback (NULL, success, callback_data);
}
static void
create_from_template_redo_func (NautilusFileUndoInfoCreate *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
GFile *parent;
gchar *parent_uri, *new_name;
parent = g_file_get_parent (self->target_file);
parent_uri = g_file_get_uri (parent);
new_name = g_file_get_basename (self->target_file);
nautilus_file_operations_new_file_from_template (NULL,
parent_uri, new_name,
self->template,
create_callback, self);
g_free (parent_uri);
g_free (new_name);
g_object_unref (parent);
}
static void
create_folder_redo_func (NautilusFileUndoInfoCreate *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
GFile *parent;
gchar *parent_uri;
gchar *name;
name = g_file_get_basename (self->target_file);
parent = g_file_get_parent (self->target_file);
parent_uri = g_file_get_uri (parent);
nautilus_file_operations_new_folder (NULL,
dbus_data,
parent_uri, name,
create_callback, self);
g_free (name);
g_free (parent_uri);
g_object_unref (parent);
}
static void
create_empty_redo_func (NautilusFileUndoInfoCreate *self,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
GFile *parent;
gchar *parent_uri;
gchar *new_name;
parent = g_file_get_parent (self->target_file);
parent_uri = g_file_get_uri (parent);
new_name = g_file_get_parse_name (self->target_file);
nautilus_file_operations_new_file (NULL, parent_uri,
new_name,
self->template,
self->length,
create_callback, self);
g_free (parent_uri);
g_free (new_name);
g_object_unref (parent);
}
static void
create_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (info);
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE)
{
create_empty_redo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER)
{
create_folder_redo_func (self, parent_window, dbus_data);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE)
{
create_from_template_redo_func (self, parent_window, dbus_data);
}
else
{
g_assert_not_reached ();
}
}
static void
create_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (info);
GList *files = NULL;
files = g_list_append (files, g_object_ref (self->target_file));
nautilus_file_operations_delete_async (files, parent_window,
dbus_data,
file_undo_info_delete_callback, self);
g_list_free_full (files, g_object_unref);
}
static void
nautilus_file_undo_info_create_init (NautilusFileUndoInfoCreate *self)
{
}
static void
nautilus_file_undo_info_create_finalize (GObject *obj)
{
NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (obj);
g_clear_object (&self->target_file);
g_free (self->template);
G_OBJECT_CLASS (nautilus_file_undo_info_create_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_create_class_init (NautilusFileUndoInfoCreateClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_create_finalize;
iclass->undo_func = create_undo_func;
iclass->redo_func = create_redo_func;
iclass->strings_func = create_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_create_new (NautilusFileUndoOp op_type)
{
return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_CREATE,
"op-type", op_type,
"item-count", 1,
NULL);
}
void
nautilus_file_undo_info_create_set_data (NautilusFileUndoInfoCreate *self,
GFile *file,
const char *template,
gint length)
{
self->target_file = g_object_ref (file);
self->template = g_strdup (template);
self->length = length;
}
/* rename */
struct _NautilusFileUndoInfoRename
{
NautilusFileUndoInfo parent_instance;
GFile *old_file;
GFile *new_file;
gchar *old_display_name;
gchar *new_display_name;
};
G_DEFINE_TYPE (NautilusFileUndoInfoRename, nautilus_file_undo_info_rename, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
rename_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (info);
gchar *new_name, *old_name;
new_name = g_file_get_parse_name (self->new_file);
old_name = g_file_get_parse_name (self->old_file);
*undo_description = g_strdup_printf (_("Rename “%s” as “%s”"), new_name, old_name);
*redo_description = g_strdup_printf (_("Rename “%s” as “%s”"), old_name, new_name);
*undo_label = g_strdup (_("_Undo Rename"));
*redo_label = g_strdup (_("_Redo Rename"));
g_free (old_name);
g_free (new_name);
}
static void
rename_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (info);
NautilusFile *file;
file = nautilus_file_get (self->old_file);
nautilus_file_rename (file, self->new_display_name,
file_undo_info_operation_callback, self);
nautilus_file_unref (file);
}
static void
rename_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (info);
NautilusFile *file;
file = nautilus_file_get (self->new_file);
nautilus_file_rename (file, self->old_display_name,
file_undo_info_operation_callback, self);
nautilus_file_unref (file);
}
static void
nautilus_file_undo_info_rename_init (NautilusFileUndoInfoRename *self)
{
}
static void
nautilus_file_undo_info_rename_finalize (GObject *obj)
{
NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (obj);
g_clear_object (&self->old_file);
g_clear_object (&self->new_file);
g_free (self->old_display_name);
g_free (self->new_display_name);
G_OBJECT_CLASS (nautilus_file_undo_info_rename_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_rename_class_init (NautilusFileUndoInfoRenameClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_rename_finalize;
iclass->undo_func = rename_undo_func;
iclass->redo_func = rename_redo_func;
iclass->strings_func = rename_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_rename_new (void)
{
return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_RENAME,
"op-type", NAUTILUS_FILE_UNDO_OP_RENAME,
"item-count", 1,
NULL);
}
void
nautilus_file_undo_info_rename_set_data_pre (NautilusFileUndoInfoRename *self,
GFile *old_file,
gchar *old_display_name,
gchar *new_display_name)
{
self->old_file = g_object_ref (old_file);
self->old_display_name = g_strdup (old_display_name);
self->new_display_name = g_strdup (new_display_name);
}
void
nautilus_file_undo_info_rename_set_data_post (NautilusFileUndoInfoRename *self,
GFile *new_file)
{
self->new_file = g_object_ref (new_file);
}
/* batch rename */
struct _NautilusFileUndoInfoBatchRename
{
NautilusFileUndoInfo parent_instance;
GList *old_files;
GList *new_files;
GList *old_display_names;
GList *new_display_names;
};
G_DEFINE_TYPE (NautilusFileUndoInfoBatchRename, nautilus_file_undo_info_batch_rename, NAUTILUS_TYPE_FILE_UNDO_INFO);
static void
batch_rename_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
*undo_description = g_strdup_printf (ngettext ("Batch rename %d file",
"Batch rename %d files",
g_list_length (self->new_files)),
g_list_length (self->new_files));
*redo_description = g_strdup_printf (ngettext ("Batch rename %d file",
"Batch rename %d files",
g_list_length (self->new_files)),
g_list_length (self->new_files));
*undo_label = g_strdup (_("_Undo Batch Rename"));
*redo_label = g_strdup (_("_Redo Batch Rename"));
}
static void
batch_rename_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
GList *l, *files;
NautilusFile *file;
GFile *old_file;
files = NULL;
for (l = self->old_files; l != NULL; l = l->next)
{
old_file = l->data;
file = nautilus_file_get (old_file);
files = g_list_prepend (files, file);
}
files = g_list_reverse (files);
batch_rename_sort_lists_for_rename (&files,
&self->new_display_names,
&self->old_display_names,
&self->new_files,
&self->old_files,
TRUE);
nautilus_file_batch_rename (files, self->new_display_names, file_undo_info_operation_callback, self);
}
static void
batch_rename_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
GList *l, *files;
NautilusFile *file;
GFile *new_file;
files = NULL;
for (l = self->new_files; l != NULL; l = l->next)
{
new_file = l->data;
file = nautilus_file_get (new_file);
files = g_list_prepend (files, file);
}
files = g_list_reverse (files);
batch_rename_sort_lists_for_rename (&files,
&self->old_display_names,
&self->new_display_names,
&self->old_files,
&self->new_files,
TRUE);
nautilus_file_batch_rename (files, self->old_display_names, file_undo_info_operation_callback, self);
}
static void
nautilus_file_undo_info_batch_rename_init (NautilusFileUndoInfoBatchRename *self)
{
}
static void
nautilus_file_undo_info_batch_rename_finalize (GObject *obj)
{
GList *l;
GFile *file;
GString *string;
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (obj);
for (l = self->new_files; l != NULL; l = l->next)
{
file = l->data;
g_clear_object (&file);
}
for (l = self->old_files; l != NULL; l = l->next)
{
file = l->data;
g_clear_object (&file);
}
for (l = self->new_display_names; l != NULL; l = l->next)
{
string = l->data;
g_string_free (string, TRUE);
}
for (l = self->old_display_names; l != NULL; l = l->next)
{
string = l->data;
g_string_free (string, TRUE);
}
g_list_free (self->new_files);
g_list_free (self->old_files);
g_list_free (self->new_display_names);
g_list_free (self->old_display_names);
G_OBJECT_CLASS (nautilus_file_undo_info_batch_rename_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_batch_rename_class_init (NautilusFileUndoInfoBatchRenameClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_batch_rename_finalize;
iclass->undo_func = batch_rename_undo_func;
iclass->redo_func = batch_rename_redo_func;
iclass->strings_func = batch_rename_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_batch_rename_new (gint item_count)
{
return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME,
"op-type", NAUTILUS_FILE_UNDO_OP_BATCH_RENAME,
"item-count", item_count,
NULL);
}
void
nautilus_file_undo_info_batch_rename_set_data_pre (NautilusFileUndoInfoBatchRename *self,
GList *old_files)
{
GList *l;
GString *old_name;
GFile *file;
self->old_files = old_files;
self->old_display_names = NULL;
for (l = old_files; l != NULL; l = l->next)
{
file = l->data;
old_name = g_string_new (g_file_get_basename (file));
self->old_display_names = g_list_prepend (self->old_display_names, old_name);
}
self->old_display_names = g_list_reverse (self->old_display_names);
}
void
nautilus_file_undo_info_batch_rename_set_data_post (NautilusFileUndoInfoBatchRename *self,
GList *new_files)
{
GList *l;
GString *new_name;
GFile *file;
self->new_files = new_files;
self->new_display_names = NULL;
for (l = new_files; l != NULL; l = l->next)
{
file = l->data;
new_name = g_string_new (g_file_get_basename (file));
self->new_display_names = g_list_prepend (self->new_display_names, new_name);
}
self->new_display_names = g_list_reverse (self->new_display_names);
}
/* starred files */
struct _NautilusFileUndoInfoStarred
{
NautilusFileUndoInfo parent_instance;
GList *files;
/* Whether the action was starring or unstarring */
gboolean starred;
};
G_DEFINE_TYPE (NautilusFileUndoInfoStarred, nautilus_file_undo_info_starred, NAUTILUS_TYPE_FILE_UNDO_INFO);
enum
{
PROP_FILES = 1,
PROP_STARRED,
NUM_PROPERTIES
};
static void
starred_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (info);
if (self->starred)
{
*undo_description = g_strdup_printf (ngettext ("Unstar %d file",
"Unstar %d files",
g_list_length (self->files)),
g_list_length (self->files));
*redo_description = g_strdup_printf (ngettext ("Star %d file",
"Star %d files",
g_list_length (self->files)),
g_list_length (self->files));
*undo_label = g_strdup (_("_Undo Starring"));
*redo_label = g_strdup (_("_Redo Starring"));
}
else
{
*undo_description = g_strdup_printf (ngettext ("Star %d file",
"Star %d files",
g_list_length (self->files)),
g_list_length (self->files));
*redo_description = g_strdup_printf (ngettext ("Unstar %d file",
"Unstar %d files",
g_list_length (self->files)),
g_list_length (self->files));
*undo_label = g_strdup (_("_Undo Unstarring"));
*redo_label = g_strdup (_("_Redo Unstarring"));
}
}
static void
on_undo_starred_tags_updated (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GTask *task;
NautilusFileUndoInfo *undo_info;
undo_info = NAUTILUS_FILE_UNDO_INFO (object);
task = user_data;
g_clear_object (&task);
file_undo_info_operation_callback (NULL, NULL, NULL, undo_info);
}
static void
starred_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (info);
if (self->starred)
{
nautilus_tag_manager_star_files (nautilus_tag_manager_get (),
G_OBJECT (info),
self->files,
on_undo_starred_tags_updated,
NULL);
}
else
{
nautilus_tag_manager_unstar_files (nautilus_tag_manager_get (),
G_OBJECT (info),
self->files,
on_undo_starred_tags_updated,
NULL);
}
}
static void
starred_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (info);
if (self->starred)
{
nautilus_tag_manager_unstar_files (nautilus_tag_manager_get (),
G_OBJECT (info),
self->files,
on_undo_starred_tags_updated,
NULL);
}
else
{
nautilus_tag_manager_star_files (nautilus_tag_manager_get (),
G_OBJECT (info),
self->files,
on_undo_starred_tags_updated,
NULL);
}
}
static void
nautilus_file_undo_info_starred_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (object);
switch (prop_id)
{
case PROP_FILES:
{
self->files = nautilus_file_list_copy (g_value_get_pointer (value));
}
break;
case PROP_STARRED:
{
self->starred = g_value_get_boolean (value);
}
break;
default:
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
}
static void
nautilus_file_undo_info_starred_init (NautilusFileUndoInfoStarred *self)
{
}
static void
nautilus_file_undo_info_starred_finalize (GObject *obj)
{
NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (obj);
nautilus_file_list_free (self->files);
G_OBJECT_CLASS (nautilus_file_undo_info_starred_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_starred_class_init (NautilusFileUndoInfoStarredClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_starred_finalize;
oclass->set_property = nautilus_file_undo_info_starred_set_property;
iclass->undo_func = starred_undo_func;
iclass->redo_func = starred_redo_func;
iclass->strings_func = starred_strings_func;
g_object_class_install_property (oclass,
PROP_FILES,
g_param_spec_pointer ("files",
"files",
"The files for which to undo star/unstar",
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (oclass,
PROP_STARRED,
g_param_spec_boolean ("starred",
"starred",
"Whether the files were starred or unstarred",
FALSE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
}
GList *
nautilus_file_undo_info_starred_get_files (NautilusFileUndoInfoStarred *self)
{
return self->files;
}
gboolean
nautilus_file_undo_info_starred_is_starred (NautilusFileUndoInfoStarred *self)
{
return self->starred;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_starred_new (GList *files,
gboolean starred)
{
NautilusFileUndoInfoStarred *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_STARRED,
"op-type", NAUTILUS_FILE_UNDO_OP_STARRED,
"item-count", g_list_length (files),
"files", files,
"starred", starred,
NULL);
return NAUTILUS_FILE_UNDO_INFO (self);
}
/* trash */
struct _NautilusFileUndoInfoTrash
{
NautilusFileUndoInfo parent_instance;
GHashTable *trashed;
};
G_DEFINE_TYPE (NautilusFileUndoInfoTrash, nautilus_file_undo_info_trash, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
trash_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
gint count = g_hash_table_size (self->trashed);
if (count != 1)
{
*undo_description = g_strdup_printf (ngettext ("Restore %d item from trash",
"Restore %d items from trash", count),
count);
*redo_description = g_strdup_printf (ngettext ("Move %d item to trash",
"Move %d items to trash", count),
count);
}
else
{
GList *keys;
char *name, *orig_path;
GFile *file;
keys = g_hash_table_get_keys (self->trashed);
file = keys->data;
name = g_file_get_basename (file);
orig_path = g_file_get_path (file);
*undo_description = 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);
*redo_description = g_strdup_printf (_("Move “%s” to trash"), name);
g_free (name);
}
*undo_label = g_strdup (_("_Undo Trash"));
*redo_label = g_strdup (_("_Redo Trash"));
}
static void
trash_redo_func_callback (GHashTable *debuting_uris,
gboolean user_cancel,
gpointer user_data)
{
NautilusFileUndoInfoTrash *self = user_data;
GHashTable *new_trashed_files;
GTimeVal current_time;
gsize updated_trash_time;
GFile *file;
GList *keys, *l;
if (!user_cancel)
{
new_trashed_files =
g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
g_object_unref, NULL);
keys = g_hash_table_get_keys (self->trashed);
g_get_current_time (¤t_time);
updated_trash_time = current_time.tv_sec;
for (l = keys; l != NULL; l = l->next)
{
file = l->data;
g_hash_table_insert (new_trashed_files,
g_object_ref (file), GSIZE_TO_POINTER (updated_trash_time));
}
g_list_free (keys);
g_hash_table_destroy (self->trashed);
self->trashed = new_trashed_files;
}
file_undo_info_delete_callback (debuting_uris, user_cancel, user_data);
}
static void
trash_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
if (g_hash_table_size (self->trashed) > 0)
{
GList *locations;
locations = g_hash_table_get_keys (self->trashed);
nautilus_file_operations_trash_or_delete_async (locations, parent_window,
dbus_data,
trash_redo_func_callback, self);
g_list_free (locations);
}
}
static void
trash_retrieve_files_to_restore_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (source_object);
GFileEnumerator *enumerator;
GHashTable *to_restore;
GFile *trash;
GError *error = NULL;
to_restore = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
g_object_unref, g_object_unref);
trash = g_file_new_for_uri ("trash:///");
enumerator = g_file_enumerate_children (trash,
G_FILE_ATTRIBUTE_STANDARD_NAME ","
G_FILE_ATTRIBUTE_TRASH_DELETION_DATE ","
G_FILE_ATTRIBUTE_TRASH_ORIG_PATH,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL, &error);
if (enumerator)
{
GFileInfo *info;
gpointer lookupvalue;
GFile *item;
glong trash_time, orig_trash_time;
const char *origpath;
GFile *origfile;
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
{
/* Retrieve the original file uri */
origpath = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH);
origfile = g_file_new_for_path (origpath);
lookupvalue = g_hash_table_lookup (self->trashed, origfile);
if (lookupvalue)
{
GDateTime *date;
orig_trash_time = GPOINTER_TO_SIZE (lookupvalue);
trash_time = 0;
date = g_file_info_get_deletion_date (info);
if (date)
{
trash_time = g_date_time_to_unix (date);
g_date_time_unref (date);
}
if (ABS (orig_trash_time - trash_time) <= TRASH_TIME_EPSILON)
{
/* File in the trash */
item = g_file_get_child (trash, g_file_info_get_name (info));
g_hash_table_insert (to_restore, item, g_object_ref (origfile));
}
}
g_object_unref (origfile);
}
g_file_enumerator_close (enumerator, FALSE, NULL);
g_object_unref (enumerator);
}
g_object_unref (trash);
if (error != NULL)
{
g_task_return_error (task, error);
g_hash_table_destroy (to_restore);
}
else
{
g_task_return_pointer (task, to_restore, NULL);
}
}
static void
trash_retrieve_files_to_restore_async (NautilusFileUndoInfoTrash *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (G_OBJECT (self), NULL, callback, user_data);
g_task_run_in_thread (task, trash_retrieve_files_to_restore_thread);
g_object_unref (task);
}
static void
trash_retrieve_files_ready (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (source);
GHashTable *files_to_restore;
GError *error = NULL;
files_to_restore = g_task_propagate_pointer (G_TASK (res), &error);
if (error == NULL && g_hash_table_size (files_to_restore) > 0)
{
GList *gfiles_in_trash, *l;
GFile *item;
GFile *dest;
gfiles_in_trash = g_hash_table_get_keys (files_to_restore);
for (l = gfiles_in_trash; l != NULL; l = l->next)
{
item = l->data;
dest = g_hash_table_lookup (files_to_restore, item);
g_file_move (item, dest, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, NULL, NULL, NULL);
}
g_list_free (gfiles_in_trash);
/* Here we must do what's necessary for the callback */
file_undo_info_transfer_callback (NULL, (error == NULL), self);
}
else
{
file_undo_info_transfer_callback (NULL, FALSE, self);
}
if (files_to_restore != NULL)
{
g_hash_table_destroy (files_to_restore);
}
g_clear_error (&error);
}
static void
trash_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
trash_retrieve_files_to_restore_async (self, trash_retrieve_files_ready, NULL);
}
static void
nautilus_file_undo_info_trash_init (NautilusFileUndoInfoTrash *self)
{
self->trashed = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
g_object_unref, NULL);
}
static void
nautilus_file_undo_info_trash_finalize (GObject *obj)
{
NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (obj);
g_hash_table_destroy (self->trashed);
G_OBJECT_CLASS (nautilus_file_undo_info_trash_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_trash_class_init (NautilusFileUndoInfoTrashClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_trash_finalize;
iclass->undo_func = trash_undo_func;
iclass->redo_func = trash_redo_func;
iclass->strings_func = trash_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_trash_new (gint item_count)
{
return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH,
"op-type", NAUTILUS_FILE_UNDO_OP_MOVE_TO_TRASH,
"item-count", item_count,
NULL);
}
void
nautilus_file_undo_info_trash_add_file (NautilusFileUndoInfoTrash *self,
GFile *file)
{
GTimeVal current_time;
gsize orig_trash_time;
g_get_current_time (¤t_time);
orig_trash_time = current_time.tv_sec;
g_hash_table_insert (self->trashed, g_object_ref (file), GSIZE_TO_POINTER (orig_trash_time));
}
GList *
nautilus_file_undo_info_trash_get_files (NautilusFileUndoInfoTrash *self)
{
return g_hash_table_get_keys (self->trashed);
}
/* recursive permissions */
struct _NautilusFileUndoInfoRecPermissions
{
NautilusFileUndoInfo parent_instance;
GFile *dest_dir;
GHashTable *original_permissions;
guint32 dir_mask;
guint32 dir_permissions;
guint32 file_mask;
guint32 file_permissions;
};
G_DEFINE_TYPE (NautilusFileUndoInfoRecPermissions, nautilus_file_undo_info_rec_permissions, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
rec_permissions_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (info);
char *name;
name = g_file_get_path (self->dest_dir);
*undo_description = g_strdup_printf (_("Restore original permissions of items enclosed in “%s”"), name);
*redo_description = g_strdup_printf (_("Set permissions of items enclosed in “%s”"), name);
*undo_label = g_strdup (_("_Undo Change Permissions"));
*redo_label = g_strdup (_("_Redo Change Permissions"));
g_free (name);
}
static void
rec_permissions_callback (gboolean success,
gpointer callback_data)
{
file_undo_info_transfer_callback (NULL, success, callback_data);
}
static void
rec_permissions_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (info);
gchar *parent_uri;
parent_uri = g_file_get_uri (self->dest_dir);
nautilus_file_set_permissions_recursive (parent_uri,
self->file_permissions,
self->file_mask,
self->dir_permissions,
self->dir_mask,
rec_permissions_callback, self);
g_free (parent_uri);
}
static void
rec_permissions_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (info);
if (g_hash_table_size (self->original_permissions) > 0)
{
GList *gfiles_list;
guint32 perm;
GList *l;
GFile *dest;
char *item;
gfiles_list = g_hash_table_get_keys (self->original_permissions);
for (l = gfiles_list; l != NULL; l = l->next)
{
item = l->data;
perm = GPOINTER_TO_UINT (g_hash_table_lookup (self->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 */
file_undo_info_transfer_callback (NULL, TRUE, self);
}
}
static void
nautilus_file_undo_info_rec_permissions_init (NautilusFileUndoInfoRecPermissions *self)
{
self->original_permissions = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
}
static void
nautilus_file_undo_info_rec_permissions_finalize (GObject *obj)
{
NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (obj);
g_hash_table_destroy (self->original_permissions);
g_clear_object (&self->dest_dir);
G_OBJECT_CLASS (nautilus_file_undo_info_rec_permissions_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_rec_permissions_class_init (NautilusFileUndoInfoRecPermissionsClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_rec_permissions_finalize;
iclass->undo_func = rec_permissions_undo_func;
iclass->redo_func = rec_permissions_redo_func;
iclass->strings_func = rec_permissions_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_rec_permissions_new (GFile *dest,
guint32 file_permissions,
guint32 file_mask,
guint32 dir_permissions,
guint32 dir_mask)
{
NautilusFileUndoInfoRecPermissions *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS,
"op-type", NAUTILUS_FILE_UNDO_OP_RECURSIVE_SET_PERMISSIONS,
"item-count", 1,
NULL);
self->dest_dir = g_object_ref (dest);
self->file_permissions = file_permissions;
self->file_mask = file_mask;
self->dir_permissions = dir_permissions;
self->dir_mask = dir_mask;
return NAUTILUS_FILE_UNDO_INFO (self);
}
void
nautilus_file_undo_info_rec_permissions_add_file (NautilusFileUndoInfoRecPermissions *self,
GFile *file,
guint32 permission)
{
gchar *original_uri = g_file_get_uri (file);
g_hash_table_insert (self->original_permissions, original_uri, GUINT_TO_POINTER (permission));
}
/* single file change permissions */
struct _NautilusFileUndoInfoPermissions
{
NautilusFileUndoInfo parent_instance;
GFile *target_file;
guint32 current_permissions;
guint32 new_permissions;
};
G_DEFINE_TYPE (NautilusFileUndoInfoPermissions, nautilus_file_undo_info_permissions, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
permissions_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (info);
gchar *name;
name = g_file_get_parse_name (self->target_file);
*undo_description = g_strdup_printf (_("Restore original permissions of “%s”"), name);
*redo_description = g_strdup_printf (_("Set permissions of “%s”"), name);
*undo_label = g_strdup (_("_Undo Change Permissions"));
*redo_label = g_strdup (_("_Redo Change Permissions"));
g_free (name);
}
static void
permissions_real_func (NautilusFileUndoInfoPermissions *self,
guint32 permissions)
{
NautilusFile *file;
file = nautilus_file_get (self->target_file);
nautilus_file_set_permissions (file, permissions,
file_undo_info_operation_callback, self);
nautilus_file_unref (file);
}
static void
permissions_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (info);
permissions_real_func (self, self->new_permissions);
}
static void
permissions_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (info);
permissions_real_func (self, self->current_permissions);
}
static void
nautilus_file_undo_info_permissions_init (NautilusFileUndoInfoPermissions *self)
{
}
static void
nautilus_file_undo_info_permissions_finalize (GObject *obj)
{
NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (obj);
g_clear_object (&self->target_file);
G_OBJECT_CLASS (nautilus_file_undo_info_permissions_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_permissions_class_init (NautilusFileUndoInfoPermissionsClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_permissions_finalize;
iclass->undo_func = permissions_undo_func;
iclass->redo_func = permissions_redo_func;
iclass->strings_func = permissions_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_permissions_new (GFile *file,
guint32 current_permissions,
guint32 new_permissions)
{
NautilusFileUndoInfoPermissions *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_PERMISSIONS,
"op-type", NAUTILUS_FILE_UNDO_OP_SET_PERMISSIONS,
"item-count", 1,
NULL);
self->target_file = g_object_ref (file);
self->current_permissions = current_permissions;
self->new_permissions = new_permissions;
return NAUTILUS_FILE_UNDO_INFO (self);
}
/* group and owner change */
struct _NautilusFileUndoInfoOwnership
{
NautilusFileUndoInfo parent_instance;
GFile *target_file;
char *original_ownership;
char *new_ownership;
};
G_DEFINE_TYPE (NautilusFileUndoInfoOwnership, nautilus_file_undo_info_ownership, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
ownership_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (info);
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
gchar *name;
name = g_file_get_parse_name (self->target_file);
if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_OWNER)
{
*undo_description = g_strdup_printf (_("Restore group of “%s” to “%s”"),
name, self->original_ownership);
*redo_description = g_strdup_printf (_("Set group of “%s” to “%s”"),
name, self->new_ownership);
*undo_label = g_strdup (_("_Undo Change Group"));
*redo_label = g_strdup (_("_Redo Change Group"));
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_GROUP)
{
*undo_description = g_strdup_printf (_("Restore owner of “%s” to “%s”"),
name, self->original_ownership);
*redo_description = g_strdup_printf (_("Set owner of “%s” to “%s”"),
name, self->new_ownership);
*undo_label = g_strdup (_("_Undo Change Owner"));
*redo_label = g_strdup (_("_Redo Change Owner"));
}
g_free (name);
}
static void
ownership_real_func (NautilusFileUndoInfoOwnership *self,
const gchar *ownership)
{
NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (NAUTILUS_FILE_UNDO_INFO (self));
NautilusFile *file;
file = nautilus_file_get (self->target_file);
if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_OWNER)
{
nautilus_file_set_owner (file,
ownership,
file_undo_info_operation_callback, self);
}
else if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_GROUP)
{
nautilus_file_set_group (file,
ownership,
file_undo_info_operation_callback, self);
}
nautilus_file_unref (file);
}
static void
ownership_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (info);
ownership_real_func (self, self->new_ownership);
}
static void
ownership_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (info);
ownership_real_func (self, self->original_ownership);
}
static void
nautilus_file_undo_info_ownership_init (NautilusFileUndoInfoOwnership *self)
{
}
static void
nautilus_file_undo_info_ownership_finalize (GObject *obj)
{
NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (obj);
g_clear_object (&self->target_file);
g_free (self->original_ownership);
g_free (self->new_ownership);
G_OBJECT_CLASS (nautilus_file_undo_info_ownership_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_ownership_class_init (NautilusFileUndoInfoOwnershipClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_ownership_finalize;
iclass->undo_func = ownership_undo_func;
iclass->redo_func = ownership_redo_func;
iclass->strings_func = ownership_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_ownership_new (NautilusFileUndoOp op_type,
GFile *file,
const char *current_data,
const char *new_data)
{
NautilusFileUndoInfoOwnership *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_OWNERSHIP,
"item-count", 1,
"op-type", op_type,
NULL);
self->target_file = g_object_ref (file);
self->original_ownership = g_strdup (current_data);
self->new_ownership = g_strdup (new_data);
return NAUTILUS_FILE_UNDO_INFO (self);
}
/* extract */
struct _NautilusFileUndoInfoExtract
{
NautilusFileUndoInfo parent_instance;
GList *sources;
GFile *destination_directory;
GList *outputs;
};
G_DEFINE_TYPE (NautilusFileUndoInfoExtract, nautilus_file_undo_info_extract, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
extract_callback (GList *outputs,
gpointer callback_data)
{
NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (callback_data);
gboolean success;
nautilus_file_undo_info_extract_set_outputs (self, outputs);
success = self->outputs != NULL;
file_undo_info_transfer_callback (NULL, success, self);
}
static void
extract_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (info);
gint total_sources;
gint total_outputs;
*undo_label = g_strdup (_("_Undo Extract"));
*redo_label = g_strdup (_("_Redo Extract"));
total_sources = g_list_length (self->sources);
total_outputs = g_list_length (self->outputs);
if (total_outputs == 1)
{
GFile *output;
g_autofree gchar *name = NULL;
output = self->outputs->data;
name = g_file_get_parse_name (output);
*undo_description = g_strdup_printf (_("Delete “%s”"), name);
}
else
{
*undo_description = g_strdup_printf (ngettext ("Delete %d extracted file",
"Delete %d extracted files",
total_outputs),
total_outputs);
}
if (total_sources == 1)
{
GFile *source;
g_autofree gchar *name = NULL;
source = self->sources->data;
name = g_file_get_parse_name (source);
*redo_description = g_strdup_printf (_("Extract “%s”"), name);
}
else
{
*redo_description = g_strdup_printf (ngettext ("Extract %d file",
"Extract %d files",
total_sources),
total_sources);
}
}
static void
extract_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (info);
nautilus_file_operations_extract_files (self->sources,
self->destination_directory,
parent_window,
dbus_data,
extract_callback,
self);
}
static void
extract_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (info);
nautilus_file_operations_delete_async (self->outputs, parent_window,
dbus_data,
file_undo_info_delete_callback, self);
}
static void
nautilus_file_undo_info_extract_init (NautilusFileUndoInfoExtract *self)
{
}
static void
nautilus_file_undo_info_extract_finalize (GObject *obj)
{
NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (obj);
g_object_unref (self->destination_directory);
g_list_free_full (self->sources, g_object_unref);
if (self->outputs)
{
g_list_free_full (self->outputs, g_object_unref);
}
G_OBJECT_CLASS (nautilus_file_undo_info_extract_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_extract_class_init (NautilusFileUndoInfoExtractClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_extract_finalize;
iclass->undo_func = extract_undo_func;
iclass->redo_func = extract_redo_func;
iclass->strings_func = extract_strings_func;
}
void
nautilus_file_undo_info_extract_set_outputs (NautilusFileUndoInfoExtract *self,
GList *outputs)
{
if (self->outputs)
{
g_list_free_full (self->outputs, g_object_unref);
}
self->outputs = g_list_copy_deep (outputs,
(GCopyFunc) g_object_ref,
NULL);
}
NautilusFileUndoInfo *
nautilus_file_undo_info_extract_new (GList *sources,
GFile *destination_directory)
{
NautilusFileUndoInfoExtract *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_EXTRACT,
"item-count", 1,
"op-type", NAUTILUS_FILE_UNDO_OP_EXTRACT,
NULL);
self->sources = g_list_copy_deep (sources,
(GCopyFunc) g_object_ref,
NULL);
self->destination_directory = g_object_ref (destination_directory);
return NAUTILUS_FILE_UNDO_INFO (self);
}
/* compress */
struct _NautilusFileUndoInfoCompress
{
NautilusFileUndoInfo parent_instance;
GList *sources;
GFile *output;
AutoarFormat format;
AutoarFilter filter;
gchar *passphrase;
};
G_DEFINE_TYPE (NautilusFileUndoInfoCompress, nautilus_file_undo_info_compress, NAUTILUS_TYPE_FILE_UNDO_INFO)
static void
compress_callback (GFile *new_file,
gboolean success,
gpointer callback_data)
{
NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (callback_data);
if (success)
{
g_set_object (&self->output, new_file);
}
file_undo_info_transfer_callback (NULL, success, self);
}
static void
compress_strings_func (NautilusFileUndoInfo *info,
gchar **undo_label,
gchar **undo_description,
gchar **redo_label,
gchar **redo_description)
{
NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (info);
g_autofree gchar *output_name = NULL;
gint sources_count;
output_name = g_file_get_parse_name (self->output);
*undo_description = g_strdup_printf (_("Delete “%s”"), output_name);
sources_count = g_list_length (self->sources);
if (sources_count == 1)
{
GFile *source;
g_autofree gchar *source_name = NULL;
source = self->sources->data;
source_name = g_file_get_parse_name (source);
*redo_description = g_strdup_printf (_("Compress “%s”"), source_name);
}
else
{
*redo_description = g_strdup_printf (ngettext ("Compress %d file",
"Compress %d files",
sources_count),
sources_count);
}
*undo_label = g_strdup (_("_Undo Compress"));
*redo_label = g_strdup (_("_Redo Compress"));
}
static void
compress_redo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (info);
nautilus_file_operations_compress (self->sources,
self->output,
self->format,
self->filter,
self->passphrase,
parent_window,
dbus_data,
compress_callback,
self);
}
static void
compress_undo_func (NautilusFileUndoInfo *info,
GtkWindow *parent_window,
NautilusFileOperationsDBusData *dbus_data)
{
NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (info);
GList *files = NULL;
files = g_list_prepend (files, self->output);
nautilus_file_operations_delete_async (files, parent_window,
dbus_data,
file_undo_info_delete_callback, self);
g_list_free (files);
}
static void
nautilus_file_undo_info_compress_init (NautilusFileUndoInfoCompress *self)
{
}
static void
nautilus_file_undo_info_compress_finalize (GObject *obj)
{
NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (obj);
g_list_free_full (self->sources, g_object_unref);
g_clear_object (&self->output);
g_free (self->passphrase);
G_OBJECT_CLASS (nautilus_file_undo_info_compress_parent_class)->finalize (obj);
}
static void
nautilus_file_undo_info_compress_class_init (NautilusFileUndoInfoCompressClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS (klass);
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
oclass->finalize = nautilus_file_undo_info_compress_finalize;
iclass->undo_func = compress_undo_func;
iclass->redo_func = compress_redo_func;
iclass->strings_func = compress_strings_func;
}
NautilusFileUndoInfo *
nautilus_file_undo_info_compress_new (GList *sources,
GFile *output,
AutoarFormat format,
AutoarFilter filter,
const gchar *passphrase)
{
NautilusFileUndoInfoCompress *self;
self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_COMPRESS,
"item-count", 1,
"op-type", NAUTILUS_FILE_UNDO_OP_COMPRESS,
NULL);
self->sources = g_list_copy_deep (sources, (GCopyFunc) g_object_ref, NULL);
self->output = g_object_ref (output);
self->format = format;
self->filter = filter;
self->passphrase = g_strdup (passphrase);
return NAUTILUS_FILE_UNDO_INFO (self);
}